当前位置: 欣欣网 > 码农

如何在浏览器中运行 .NET

2024-03-25码农


概述: 本文将讨论如何用最简单的术语在网站上运行 C# 代码。半技术讲座我使用了 wasm-tools-net7,这是一个基于 wasm-tools 的工作负载,没有包含任何额外的包。我的重点是简单性和主要主题。彻底了解该主题可提供完成所有其他任务所需的信息。如何工作?WebAssembly 工作原理:序列图创建演示创建项目我用的是net7,但这取决于你。Dotnet new console -o WASM_Demo cd WASM_Demo Dotnet workload install wasm-tools-net7此时,需要对 csproj 文件进行修改。Project Sdk=Mi

本文将讨论如何用最简单的术语在网站上运行 C# 代码。

半技术讲座

我使用了 wasm-tools-net7,这是一个基于 wasm-tools 的工作负载,没有包含任何额外的包。我的重点是简单性和主要主题。彻底了解该主题可提供完成所有其他任务所需的信息。

如何工作?

WebAssembly 工作原理:序列图

创建演示

创建项目

  • 我用的是net7,但这取决于你。

  • Dotnet new console -o WASM_Demo
    cd WASM_Demo
    Dotnet workload install wasm-tools-net7

    此时,需要对 csproj 文件进行修改。

    <Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
    <WasmMainJSPath>main.js</WasmMainJSPath>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    </PropertyGroup>
    <ItemGroup>
    <WasmExtraFilesToDeploy Include="index.html"/>
    <WasmExtraFilesToDeploy Include="main.js"/>
    </ItemGroup>
    </Project>


    我们添加了什么:

  • RuntimeIdentifier (wasm-tools 需要)

  • WasmMainJSPath (wasm-tools 需要)

  • AllowUnsafeBlocks(JSExportAttribute 需要不安全的代码)

  • ItemGroup (Include as resource)

  • 导入 index.html

  • 导入main.js

  • 返回到program.cs文件,需要考虑某些规则。

  • 类必须是公共的和部分的。

  • 函数必须是公共的和静态的,并且必须使用 [JSExport] 进行属性化。

  • 让我们举个例子。

    usingSystem.Runtime.InteropServices.JavaScript;
    namespaceWASM_Demo;
    publicpartial classProgram
    {
    staticvoidMain(string[] args) { }
    [JSExport]
    publicstaticstringResponse()
    {
    return"""
    <h1>
    Hello World
    </h1>
    """;
    }
    }

    没关系,但是我们如何在浏览器中运行此代码?

    运行这个程序的代码是dotnet.js的,它自带了wasm-tools,所以没有必要担心它。要使用此dotnet.js,我们只需使用一个名为 main.js 的文件。

    import { dotnet } from'./dotnet.js'
    const is_browser = typeof window != "undefined";
    if (!is_browser) thrownewError(`Expected to be running in a browser`);
    const { setModuleImports, getAssemblyExports, getConfig, runMainAndExit } = await dotnet
    .withDiagnosticTracing(false)
    .withApplicationArgumentsFromQuery()
    .create();
    const config = getConfig();
    const exports = awaitgetAssemblyExports(config.mainAssemblyName);
    const html =
    exports
    .WASM_Demo // Namespace
    .Program // class Name
    .Response(); // Function Name
    // Regular javascript code
    document.getElementById("app").innerHTML = `${html}`;
    awaitrunMainAndExit(config.mainAssemblyName, [] /* Console App Args */);




    index.html页面的模板已经准备完毕。

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <title>WASM Demo</title>
    <meta charset="UTF-8"/>
    <meta name="viewport"content="width=device-width, initial-scale=1.0"/>
    <link rel="modulepreload"href="./dotnet.js"/>
    </head>
    <body>
    <main id="app"></main>
    <script type="module"src="./main.js"></script>
    </body>
    </html>

    现在,让我们再看一遍这个过程,

  • HTTP 请求传入

  • WASM-Tools 处理此问题并发送index.html文件。

  • index.html文件请求dotnet.js和main.js文件,dotnet.js由 WASM-Tools 发送,main.js是我们的自定义代码。

  • 通过在 main.js 中使用 dotnet.js,我们可以进入 C# 代码中的 Program 类,调用 Response 函数并在 main.js 中进行我们想要的任何客户端更改。

  • 我们还有一件事要做,你需要打开一个名为 runtimeconfig.template.json 的文件,并将以下 JSON 数据放入其中。

    {
    "wasmHostProperties": {
    "perHostConfig": [
    {
    "name": "browser",
    "html-path": "index.html",
    "Host": "browser"
    }
    ]
    }
    }

    我们已经到了尽头,程序现在可以运行了。唯一需要的命令是:

    Dotnet run -c Release

    常见问题

    我可以托管所有文件而不是 wasm-tools 吗?又是如何做到的呢?

    当然,但它可能会变得有点复杂,你用 wasm-tools 制作的项目不能用于任何其他目的,即控制台应用程序不起作用,wasm-tools 可以工作。因为我们选择 browser-wasm 作为 RuntimeIdentifier,并且多个 RuntimeIdentifiers 在 .NET 中不可用。作为替代方法,您可以打开两个项目,将第一个项目设置为 WASM 项目,然后在第二个项目中将其设置为控制台应用程序,然后生成第一个项目并托管输出文件夹,所有 DLL 和文件都将在那里。

    这个演示只是索引文件,我可以做多页吗?又是如何做到的呢?

    当然,但这比你想象的要难得多,因为这样做的方法是一种叫做SPA(单页应用程序)的方法,用户总是在同一页面上,只是内容发生了变化。有多种方法可以做到这一点。所以它可以用你的创造力来完成。

    我可以像计数器一样做动态代码吗?又是如何做到的呢?

    _是的,我也这样做了,你可以一遍又一遍地调用 C# 函数,如果你只是将导出绑定到 window 对象,你可以从每个 JavaScript 代码中调用它。