2

Another Way to Run C# in a Web Page

 1 year ago
source link: https://medium.com/young-coder/another-way-to-run-c-in-a-web-page-ba0f39101f38
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Another Way to Run C# in a Web Page

.NET 7 gives you JavaScript interop without Blazor

1*fyod4VY5m_CFy3i7fkUvlQ.png

If you’ve been a .NET programmer for a few years, you’ve seen some remarkable changes. ASP.NET became modular and modern. C# absorbed new techniques from functional programming. And the entire .NET platform reinvented itself as a cross-platform, open source project. But few developments have been as dramatic as the introduction of Blazor, Microsoft’s WebAssembly-powered solution for running C# code in a browser, no plugin required.

Blazor works some serious magic to smuggle an entire slimmed-down .NET runtime into the browser sandbox. Compatibility is flawless, download sizes are light, and performance is excellent — if you ignore the potential first-request latency. But Blazor also comes with its own way of doing things, including a page and component model that follows some of the conventions of server-side Razor pages. Most of the time, this is what you need to get things done without reinventing the wheel. But for some use cases, it can be overwhelming. It’s a little like wanting to write a snippet of vanilla JavaScript and having someone hand you React.

In .NET 7, the story changes with a new set of JavaScript interop features.

The key ingredients

The magic happens courtesy of a new namespace named System.Runtime.InteropServices.JavaScript. It holds two basic building blocks:

  • The JSExport attribute. Use this to expose a C# method to the JavaScript in a web page.
  • The JSImport attribute. Use this to give C# access to a JavaScript function in the web page.

There are a few more ingredients you’ll use eventually, like JSException (which wraps JavaScript exceptions so they can bubble up to your C# code) and JSMarshalAsAttribute<T> (to control type conversions).

Here’s a 10,000 foot view of how the interop attributes work:

1*-_M6ci1IWA8jjz3wbCBR0w.png

Getting started

Let’s say you have some C# utility function that JavaScript needs to use. First, make sure it’s a static function (that’s a requirement). Then decorate it with JSExport, like this:

public class StoreUtility
{
[JSExport]
public static string GetProductUrl()
{
...
} ...
}

This indicates that you want to create a JavaScript wrapper around the GetProductUrl() method. To actually register the method and create the wrapper, .NET uses some boilerplate like this:

import { dotnet } from './dotnet.js'
...const config = getConfig();
const exports = await getAssemblyExports(config.mainAssemblyName);

Once that’s done, you can easily call the C# method from your JavaScript:

const url = exports.StoreUtility.GetProductUrl();
console.log(url);

The reverse operation is almost as easy. First, you create a partial static method that uses the JSImport attribute:

public class StoreUtility
{
... [JSImport("storeData", "./view.js")]
public static partial void storeData(string data);
}

This method matches the signature of the JavaScript function you want to use, but it doesn’t contain any code. In this example, that means the C# storeData() method is meant to call a JavaScript method of the same name, which requires one parameter and has no return value. The C# storeData() method is just a placeholder. .NET will generate the wrapper that calls the JavaScript function and merge that code with your partial C# method.

Notice that JSImport requires two arguments: the name of the function you’re calling, and a unique name that identifies the module where the function is located.

To actually create the wrapper code, you need to register the underlying JavaScript functions. The preferred convention for doing that is still evolving, but you have the choice of using setModuleImports (a JavaScript method provided by the all-powerful dotnet.js library) or calling the JSHost.ImportAsync() helper method from the System.Runtime.InteropServices.JavaScript namespace.

await JSHost.ImportAsync("view.js", "./view.js");

Once you’ve registered your functions (exposing C# functions to the JavaScript universe, and JavaScript functions to C#), all the gruntwork happens behind the scenes. The browser grabs the WebAssembly libraries that power the browser-hosted version of .NET in the background, and everything works just as seamlessly as in Blazor. You can check it out in the Network tab of the Chrome developer tools, where you’ll see that all the .NET assemblies are quietly loaded.

1*CagZYMzoQ2PTaLajtzdbkw.png

Trying it out yourself

The project support for JavaScript interop is still considered experimental. But you can try it out right now, provided you aren’t expecting niceties like designer support and hot reload.

First, install the .NET 7 SDK.

Next, open a terminal window and install these two packages:

dotnet workload install wasm-tools
dotnet workload install wasm-experimental

Now you’re ready to create a new web project that’s configured with JavaScript interop. Use this command to get started:

dotnet new wasmbrowser 

This creates a one-page working demo that has a single JavaScript-to-C# import and a single C#-to-JavaScript export. You can then use a simple dotnet build and dotnet run command to launch the application live with a localhost URL.

1*H6K54IMwffZXUOfCsXpQfg.png

To go deeper, you can look through a more ambitious example. Download Pavel Šavara’s Todo app from GitHub (or try it live).

Wrapping up

If your dream is to call a C# function from a web page with a minimum of fuss, the new JavaScript interop features are very promising. But there are a few obvious limitations:

  • The design-time experience is still evolving.
  • Your C# code doesn’t have access to browser objects or UI, so you either needs to handle that in your JavaScript code (and keep the C# for your business logic), or write the whole application in C# but use interop to expose all the JavaScript details it needs. Building a complex application this way could get messy.
  • We’re still waiting for standardization to lock down the boilerplate, so you have a consistent way to scaffold a whole application without Blazor.

But even with these caveats, the new interop features are an exciting addition to the C#-WebAssembly-JavaScript story — and my favorite new feature in .NET 7.

To follow Young Coder’s news about .NET 7 and beyond, sign up for the monthly newsletter.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK