DEV Community

Cover image for .NET WebCIL Container Meets WebForms Core 2.1
Elanat Framework
Elanat Framework

Posted on

.NET WebCIL Container Meets WebForms Core 2.1

What is WebForms Core?

WebForms Core is a modern multi-platform web technology from Elanat designed to build interactive web applications without requiring traditional client-side business logic.

WebForms Core uses a server-centric architecture in which the server defines UI behavior through commands, while a lightweight client engine executes those commands in the browser.

With the upcoming WebForms Core 2.1 (WFC), this architecture is being extended with another interesting capability: C# code running inside a .NET WebAssembly environment can use WebForms Core itself to generate UI commands.

This makes it possible to combine:

  • C#
  • .NET WebAssembly
  • WebForms Core
  • WebForms Core's declarative UI commands

inside the same WebAssembly application.


.NET WebCIL Container

One of the new possibilities demonstrated with WFC 2.1 is the use of a .NET WebCIL Container.

Instead of compiling C# into a standalone native-style WASM function such as:

add(10000, 3)
Enter fullscreen mode Exit fullscreen mode

the application can load the .NET WebAssembly runtime and execute exported C# methods through dotnet.js.

For example:

using System.Runtime.InteropServices.JavaScript;
using WebFormsCore;

public partial class MyClass
{
    [JSExport]
    public static int Add(int a, int b)
    {
        return a + b;
    }

    [JSExport]
    public static string SetData(string inputPlace, string text, string backgroundColor, string fontSize)
    {
        WebForms form = new WebForms();

        form.SetText(inputPlace, text);
        form.SetBackgroundColor("-", backgroundColor);
        form.SetFontSize("-", fontSize);

        return form.Response();
    }

    [JSExport]
    public static string GetHtml()
    {
        return "<marquee>Tag From Wasm!</marquee>";
    }
}

public class Program
{
    public static void Main()
    {
    }
}
Enter fullscreen mode Exit fullscreen mode

The important part is that WebForms.cs from WebForms Core is included in the WebAssembly project.

Therefore, C# code running inside the WebAssembly environment can directly create WebForms Core commands.


Creating the .NET WebCIL Project

Create a new .NET 10 WebAssembly console project:

dotnet new wasmconsole -n NativeWasmModule -f net10.0
Enter fullscreen mode Exit fullscreen mode

Then enter the project:

cd NativeWasmModule
Enter fullscreen mode Exit fullscreen mode

The project can use the following configuration:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <WasmEnableExceptionHandling>false</WasmEnableExceptionHandling>
    <RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
    <OutputType>Exe</OutputType>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <WasmMainJSPath>main.mjs</WasmMainJSPath>
  </PropertyGroup>

</Project>
Enter fullscreen mode Exit fullscreen mode

The project targets:

<TargetFramework>net10.0</TargetFramework>
Enter fullscreen mode Exit fullscreen mode

and uses:

<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
Enter fullscreen mode Exit fullscreen mode

The main.mjs file is specified as the JavaScript entry point:

<WasmMainJSPath>main.mjs</WasmMainJSPath>
Enter fullscreen mode Exit fullscreen mode

Adding WebForms Core

The WebForms.cs class from WebForms Core is added to this project.

This is important because the WebAssembly C# code is now capable of using WebForms Core's API.

For example:

WebForms form = new WebForms();

form.SetText(inputPlace, text);
form.SetBackgroundColor("-", backgroundColor);
form.SetFontSize("-", fontSize);

return form.Response();
Enter fullscreen mode Exit fullscreen mode

The C# method doesn't directly manipulate the browser DOM.

Instead, it generates a WebForms Core response.

This keeps the same philosophy used throughout WebForms Core.


Exporting C# Methods

Methods that should be accessible from JavaScript are marked with:

[JSExport]
Enter fullscreen mode Exit fullscreen mode

For example:

[JSExport]
public static int Add(int a, int b)
{
    return a + b;
}
Enter fullscreen mode Exit fullscreen mode

The method can then be accessed through the .NET WebAssembly runtime.

A method can also return a WebForms Core response:

[JSExport]
public static string SetData(string inputPlace, string text, string backgroundColor, string fontSize)
{
    WebForms form = new WebForms();

    form.SetText(inputPlace, text);
    form.SetBackgroundColor("-", backgroundColor);
    form.SetFontSize("-", fontSize);

    return form.Response();
}
Enter fullscreen mode Exit fullscreen mode

This is where the combination becomes particularly interesting.

The WASM code isn't merely calculating a value.

It can generate WebForms Core UI behavior.


Using C# WebAssembly from WebForms Core

A WebForms Core controller can invoke the C# WebAssembly runtime:

using CodeBehind;

public partial class CsharpMediatorWasmController : CodeBehindController
{
    public void PageLoad(HttpContext context)
    {
        string WasmPath = "/web-assembly/csharp-publish/_framework/dotnet.js";

        WebForms form = new WebForms();

        form.AddText("<b>", Fetch.WasmMethod(WasmLanguage.CSharpMediator, WasmPath, "MyClass.Add", [10000, 3]));

        form.SetWasmEvent("WasmEvent", HtmlEvent.OnClick, WasmLanguage.CSharpMediator, WasmPath, "MyClass.SetData", ["h3Tag", "Text From Wasm", "lightgreen", "30px"]);

        form.SetWasmEvent("WasmEventWithOutput", HtmlEvent.OnClick, WasmLanguage.CSharpMediator, WasmPath, "MyClass.GetHtml", [], "WasmHtmlOutput");

        Write(form.ExportToHtmlComment());
    }
}
Enter fullscreen mode Exit fullscreen mode

Notice the method names:

MyClass.Add
MyClass.SetData
MyClass.GetHtml
Enter fullscreen mode Exit fullscreen mode

The class name can be specified before the method name.

This makes it possible to address exported methods belonging to different C# types.


HTML

The HTML remains simple:

@page
@controller CsharpMediatorWasmController
@layout "/layout.aspx"

@{
    ViewData.Add("title", "C# Mediator Wasm");
}

<h3>.NET WebCIL Container</h3>

<b>C# Mediator WASM Result: </b>

<br>

<button id="WasmEvent">
    Wasm Event
</button>

<br>

<h3 id="h3Tag">
    Wasm Tag Changing!
</h3>

<button id="WasmEventWithOutput">
    Wasm Event With Output
</button>

<p id="WasmHtmlOutput">
    Wasm Html Output
</p>
Enter fullscreen mode Exit fullscreen mode

There is no custom WebAssembly element.

There is no special DOM component.

There is no C# component syntax.

The HTML remains standard HTML.


The Interesting Part

Consider this:

form.SetWasmEvent("WasmEvent", HtmlEvent.OnClick, WasmLanguage.CSharpMediator, WasmPath, "MyClass.SetData", ["h3Tag", "Text From Wasm", "lightgreen", "30px"]);
Enter fullscreen mode Exit fullscreen mode

The server declares:

When this button is clicked, execute MyClass.SetData inside the C# WebAssembly runtime.

The method executes:

WebForms form = new WebForms();

form.SetText(inputPlace, text);
form.SetBackgroundColor("-", backgroundColor);
form.SetFontSize("-", fontSize);

return form.Response();
Enter fullscreen mode Exit fullscreen mode

The result is then handled by WebForms Core.

The C# WebAssembly method therefore becomes another source of WebForms Core commands.


WASM Event With Output

The same mechanism can return HTML:

[JSExport]
public static string GetHtml()
{
    return "<marquee>Tag From Wasm!</marquee>";
}
Enter fullscreen mode Exit fullscreen mode

and:

form.SetWasmEvent("WasmEventWithOutput", HtmlEvent.OnClick, WasmLanguage.CSharpMediator, WasmPath, "MyClass.GetHtml", [], "WasmHtmlOutput");
Enter fullscreen mode Exit fullscreen mode

The returned value is placed into:

<p id="WasmHtmlOutput"></p>
Enter fullscreen mode Exit fullscreen mode

This demonstrates that the WASM method can be used not only for calculations, but also as a source of dynamic UI output.


The screenshot below shows the HTML page after clicking the buttons.

WASM in WebForms Core


What Makes This Different?

This is not simply:

"Run C# in the browser."

That capability already exists.

The interesting part is the combination of C# WebAssembly and WebForms Core.

A C# method running inside WebAssembly can use:

WebForms
Enter fullscreen mode Exit fullscreen mode

and produce WebForms Core commands.

That creates a pipeline like this:

C# WebAssembly
      ↓
  WebForms.cs
      ↓
WebForms Core Response
      ↓
WebForms Core Client Engine
      ↓
     DOM
Enter fullscreen mode Exit fullscreen mode

The WebAssembly code does not need to know how the browser DOM is implemented.

It can describe the desired UI behavior through WebForms Core.


Native WASM and .NET WebCIL Are Different

WebForms Core can work with different types of WebAssembly environments.

For example, a native WASM module may expose a function such as:

add
Enter fullscreen mode Exit fullscreen mode

and can be loaded directly as a .wasm module.

The .NET approach is different.

With the .NET WebCIL environment, the entry point is:

dotnet.js
Enter fullscreen mode Exit fullscreen mode

and the .NET runtime loads the necessary WebAssembly components.

Therefore:

Native WASM
     ↓
module.wasm
     ↓
WebAssembly.instantiate()
Enter fullscreen mode Exit fullscreen mode

is conceptually different from:

.NET WebAssembly
     ↓
dotnet.js
     ↓
.NET runtime
     ↓
C# exported method
Enter fullscreen mode Exit fullscreen mode

WebForms Core can provide an abstraction over these different execution models.


No JavaScript Business Logic

One of the most interesting properties of this example is that the application does not require custom JavaScript business logic.

The C# code contains:

public static string SetData(...)
{
    WebForms form = new WebForms();

    form.SetText(...);
    form.SetBackgroundColor(...);
    form.SetFontSize(...);

    return form.Response();
}
Enter fullscreen mode Exit fullscreen mode

The HTML contains:

<button id="WasmEvent">
    Wasm Event
</button>
Enter fullscreen mode Exit fullscreen mode

And the WebForms Core server code connects them:

form.SetWasmEvent("WasmEvent", HtmlEvent.OnClick, WasmLanguage.CSharpMediator, WasmPath, "MyClass.SetData", [...]);
Enter fullscreen mode Exit fullscreen mode

The application logic remains in C#.


WebForms Core 2.1

WebForms Core 2.1, or simply WFC, is coming soon.

This release expands the possibilities of WebForms Core by allowing WebAssembly methods to participate more deeply in the WebForms Core execution model.

The .NET WebCIL scenario is particularly interesting because developers can write C# methods such as:

[JSExport]
public static string SetData(...)
Enter fullscreen mode Exit fullscreen mode

and use the existing WebForms Core API inside those methods.

This means that the same WebForms Core command model can be used from:

  • Server-side C#
  • C# WebAssembly
  • Native WebAssembly modules
  • Other WASM-capable languages

while the browser continues to use the WebForms Core client engine (WebFormsJS).


Final Result

This example demonstrates a new direction for WebForms Core:

C# WebAssembly can become an execution layer for WebForms Core rather than simply a replacement for JavaScript.

The architecture can be summarized as:

              WebForms Core
                    │
        ┌───────────┴───────────┐
        │                       │
     Server                 WebAssembly
        │                       │
   WebForms.cs               C# / WASM
        │                       │
        └───────────┬───────────┘
                    ↓
          WebForms Core Commands
                    ↓
               Browser DOM
Enter fullscreen mode Exit fullscreen mode

And perhaps the most interesting point is this:

WebAssembly does not have to replace the WebForms Core model. It can become another execution environment for it.

That opens the door to using high-performance compiled languages and .NET WebAssembly together with the declarative command architecture of WebForms Core.

WebForms Core 2.1 is coming soon!

WebForms Core vs Blazor WebAssembly

Compared with Blazor WebAssembly, this approach in WebForms Core is not intended to run a complete .NET application in the browser. Instead, it can invoke a specific C# method as a WASM capability and return its result to WebForms Core. In the example above, MyClass.Add, MyClass.SetData, and MyClass.GetHtml are executed only when they are actually needed. Therefore, the architecture is much closer to a WASM Function Runtime than to a WASM-based SPA. Furthermore, by using WebForms within the C# code, even UI modification logic can be defined directly inside the C# method, with its output then passed to the WebForms Core engine.

In contrast, Blazor WASM provides a complete programming model for building .NET user interfaces in the browser, with a significant portion of the application logic and required runtime running on the client. WebForms Core can take a different approach: HTML remains standard HTML, WebForms Core manages UI behavior, and WASM is used only when specific capabilities need to be executed. Therefore, the two are not necessarily direct competitors. Blazor WASM primarily focuses on running .NET applications in the browser through WebAssembly, whereas WebForms Core is not limited to WebAssembly and provides a broader architecture for developing and executing web behavior.

Related links

WebForms Core in GitHub:
https://github.com/webforms-core

Top comments (0)