早在 .NET 6 时期发布 MAUI 时就已经对 C# 非常感兴趣,加上这几年对游戏开发的学习使得我重新关注这款语言平台
关联阅读:
如今 .NET 8 新增了各种能力:例如进一步对 wasm
的支持(Blazor 美如画),还有 NativeAOT
。再加上微软自从改变了路线开始尊重开源社区,并且先进技术跟得一次比一次快,让我又当场狗叫
「.NET is THE NEXT GENERATION」
总所周知 CloudFlare Workers 本来是一个服务托管平台,还是跟上一篇讲得差不多:它优先托管基于 NodeJS
的应用或者 FaaS。但是!它确实也进入了 WASI
的实验性支持
所以当我单方面狗叫「WebAssembly is FUTURE」之时,我已经在想:用 C# 狸猫换太子是不是有戏?
醉翁之意不在酒啊
在 .NET 8,WASI 创建相当丝滑
这个事情起源于 .NET 7,这个时候需要一个 SDK:SteveSandersonMS/dotnet-wasi-sdk: Packages for building .NET projects as standalone WASI-compliant modules
本质还是创建一个 ASP.NET
应用,但是将 ASP
关于网络部分重新以 WASI
实现
而 .NET 8 开始正经支持,并且提供了新的 workload(按照我们老微软正田字旗的说法叫:工作负载)
dotnet workload install wasi-experimental
接着,为了它的 Publish
或者是 AOT(?) 能正常实现,需要自行在环境中安装 wasi-sdk
.NET 在编译的时候会自行去找本地的 wasi-sdk
,但前提是这个终端环境中有 WASI_SDK_PATH
变量。所以还是记得先根据 wasi-sdk
的 Readme 中关于 Install
和 Use
部分先做好
然后就可以 Create 一个项目。当然如果使用的是 Jetbrain Rider 的话,新建项目列表已经将这个 workload 扫出来了
这个时候打开 csproj
文件搂一眼会发现,Runtime
不是 web
不是 console
而是 wasi-wasm
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>wasi-wasm</RuntimeIdentifier>
<OutputType>Exe</OutputType>
<PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
</Project>
这个时候如果什么都不做(反正也有个 hello world 能跑),直接编译,会按照经典 .NET 老配方运行 —— 代码将会编程一些中间代码(已经分门别类编译成 dll),最后让小 Runtime 就着 Wasm 环境来跑
显然我不要这个配方,我要的是单独一个 .wasm
文件以便 wasmedge 或者 wasmtime 直接执行起来,就像上一篇提到的一样
所以这个时候需要向 csproj
文件再杵一行进去
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>wasi-wasm</RuntimeIdentifier>
<OutputType>Exe</OutputType>
<PublishTrimmed>true</PublishTrimmed>
+ <WasmSingleFileBundle>true</WasmSingleFileBundle>
</PropertyGroup>
</Project>
再次编译就是单文件版本了
一般这个时候如果拿去 docker 运行,跑下来会大概 10MB 左右上上和下下,所以可以根据情况再对运行环境有些优化或者调整,例如
<EventSourceSupport>false</EventSourceSupport>
<UseSystemResourceKeys>true</UseSystemResourceKeys>
<EnableUnsafeUTF7Encoding>false</EnableUnsafeUTF7Encoding>
<HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
<DebuggerSupport>false</DebuggerSupport>
接着 wasm-opt
也可以用用(这在 rust
已经很常见,还是 wasm-pack
的内置优化项)
完事,根据 wrangler
的文档就可以把这个 wasm
文件送上去,过一小段时间之后就可以当成一个服务调用
关联阅读:
然而,.NET 8 的 WASI
转正,带来的却是暂时不直接支持 http
应用。即 system.net
并没有提供给 WASI
平台,要稳定支持且更多相关的功能还是得等到 .NET 9
或者还有一些路线
事实上,答案就在 rust version sdk 里
Cloudflare Workers 直接明牌写着:
Write in JS, Rust, C, and C++
又众所周知,CF Workers 实际上就是整了个 V8
在提供服务
由此可得,Rust
和 C++
的支持指腚有问题。于是我们可以先去看一眼 tutorial 学习一手
关联阅读:
结果,不仅代码上有明显的 wasm_bindgen,而且 rust 代码中各种要调用环境外扩展标记,证明 rust 确实是在 WebAssembly 中运行
并且 rustwasm-worker-template
的 README 还清晰的写下了这个:
workers-rs (the Rust SDK for Cloudflare Workers used in this template) is meant to be executed as compiled WebAssembly, and as such so must all the code you write and depend upon.
所以,C# 完整的在 worker 上跑起来不是不可能的。并且有另外一个托管平台 spin
就实现了相应的 SDK
但在我印象中,.NET 社区的活跃程度应该是离谱的高的,只是玩 .NET 的家人们应该还不屑于这种玩法,以致还没有相应的 NuGet 吧