Blazor WASM w/ FiveM

Hello. Anyone know if it is possible to use Blazor inside of FiveM? I’ve tried figuring out how to publish it so it doesn’t need to be hosted with dotnet run but I have not been able to figure out if it is possible. If anyone has any information and would like to share that would be great :slight_smile:

If you do

dotnet publish -c Release

Then in /bin/Release/netwhatever/publish/wwwroot are your published files

Yeah I figured that out a bit after making the post. Was struggling to actually get it to load in game though. I tried this in the fxmanifest

file("Diamond.UserInterface/bin/" + appEnvironment + "/net5/publish/wwwroot/**/*");
ui_page("Diamond.UserInterface/bin/" + appEnvironment + "/net5/publish/wwwroot/index.html");

Hey, this is really interesting.

Can you share more info on benefits of using Blazor?
I’ve given up on C# inside FiveM but Blazor looks useful for certain types of NUI, if that’s what you’re going after.

Cheers!

I’ve got actually rendering blazor working so far. Currently trying to get NUI callbacks and what not to work but I’m having some issues :(. I’ll post more information after its finished.

The only benefit Blazor has for me is that i hate javascript with a passion. I’m remaking ESX in C# and making it not shit, it will be used for basically all of my UI.

Alright, I have figured it out. Here’s a quick tutorial.

Of course you need to make a project, to do that type.
> dotnet new blazorwasm -f net5 -o ProjectName.UserInterface

After creating the project, publish the project.
> dotnet publish -c Release

After the project is published, this will give you the wasm files you need to run the site.

Include these files in the fxmanifest by adding

file("./ProjectName.UserInterface/bin/Release/net5.0/publish/wwwroot/*");
ui_page("./ProjectName.UserInterface/bin/Release/net5.0/publish/wwwroot/index.html");

Next there’s some stuff I added for making communication easier between your client and nui.

First, open wwwroot/index.html. Next find the script referencing _framework/blazor.webassembly.js, it should be at the bottom of the body tag.

Add autostart="false". Ex

<script src="_framework/blazor.webassembly.js" autostart="false"></script>

Below that script, we’re going to create a new script. This script will listen for events and send them to C#. This will also let C# know of the resource name, in case it ever changes.

<script>
	window.addEventListener("message", e =>
	{
		if (!e.data || !e.data.name) return;
		DotNet.invokeMethod("ProjectName.UserInterface", "OnNuiEvent", e.data.name JSON.stringify(e.data));
	}

	Blazor.start({ }).then(_ => DotNet.invokeMethod("ProjectName.UserInterface", "SetParentResourceName", GetParentResourceName());
</script>

At the top of the file, also be sure to remove the base href.

That’s all we need to add to the JavaScript side of things, now for C#.

After setting up the JS method to send data to C#, it’s not very hard to add functionality to this in C#. Create a new class, I called mine Communicator. Labeling the methods with JSInvokable allows them to be called with DotNet.invokeMethod() in JavaScript.

public static class Communicator
{
	private static string ParentResourceName = string.Empty;
		
	[JSInvokable("OnNuiEvent")]
	public static void OnNuiEvent(string name, string data)
	{
		// Do stuff with the data
	}
	
	[JSInvokable("SetParentResourceName")]
	public static void SetParentResourceName(string name) =>
		ParentResourceName = name;
}

I would defiantly recommend setting up some sort of attribute so you can easily set up event handlers.

Now you will be able to receive events. Sending them is pretty easy too. Add another method to your class called something like TriggerNuiCallback. For this I am using the NuGet libraries Newtonsoft.Json and RestSharp.

public static string TriggerNuiCallback(string name, dynamic data)
{
	var client = new RestClient("https://{ParentResourceName}/{name}");
	client.AddDefaultHeader("content-type", "application/json");

	var request = new RestRequest(Method.POST)
	{ Body = JsonConvert.SerializeObject(data) };

	var response = client.Execute(request);
	return response.Content;
}

Once everything is setup, you will be able to handle events just like any other NUI resource. See this for more information.

Important

Be sure to type > dotnet publish -c Release every time you update your user interface! I would recommend using the dotnet cli command because when I tried using the publish button in Rider, the web page did not load properly.

2 Likes

Good luck with your project!

1 Like

uh ok so i ended up changing a lot of this but i finally actually got it working. I’m going to make a separate thread with an actual tutorial to get it working once i get home.

Unfortunately i can’t make the solution not a solution anymore, which is unfortunate because i don’t think that actually works.

Good evening @Samplee,

did you create a tutorial for it in the end? Unfortunately I can’t find it, if it exists. I would be very interested in such a tutorial.

I’m probably going to make a tutorial for this soon, also going to make a nice library to trigger NUI callbacks and handle NUI messages. Everything is working for me, except message handling, It’s such a pain because you literally get no information from exceptions. It also seems like you can’t await any async calls in async JS Invokables, weirdly. A workaround for this is using Task.Factory.StartNew(async() => { // });. If I made a tutorial or a project template, I’ll let it know here.

i did but its pretty shit so i never posted ab it. Sample's Epic Blog if you wanna see an example check out GitHub - Sampleeeee/Diamond-Framework