dotnet 将C#编译为wasm让前端html使用
其實 dotnet 是全棧的首選,原因是因為可以開發的方向太多,比如大本營PC端,以及后臺。還有移動端,包括 IOS 和安卓端。現在還能用來寫前端,本文就來告訴大家如何在前端使用現有的C#代碼,通過 WebAssembly 使用 C# 的代碼支持完全靜態的網頁,也就是不需要任何后臺的存在。同時使用 C# 編寫的 WebAssembly 可以省去 js 編譯時間,同時使用二進制的本地指令,運行效率也有極大的提升。兼顧了開發的友好以及更高的性能
這需要搜 WebAssembly 就可以找到超級多的贊揚的文章,我這里也就不需要多說了。接下來告訴大家使用一個超級簡單的代碼入門
使用 WebAssmebly 的方式不會影響原有的任何業務,也就是我在已經寫了幾年的頁面里面,可以直接加入 WebAssmembly 的特性,就像多添加一個 js 引用一樣。不需要對現有的頁面做任何的改動
此時在 C# 里面用的代碼都是虛的,不再本文關注的范圍內,所以通過?dotnet new console -o YadernawcoLofeleabe創建一個控制臺項目
在控制臺項目添加一個類,這個類添加靜態方法,這個靜態方法就是讓前端調用的入口方法,給這個字符串添加字符串參數,方便傳入
using System;namespace YadernawcoLofeleabe {class Program{static void Main(string[] args){Console.WriteLine("Hello World!");}}public class Example{public static string Hello(string yourName){return $"Hello {yourName}";}} }這里的代碼不是重點,大概就是從 Hello 拿到輸入,然后修改輸入然后輸出
接下來就是重點了,如何將 C# 代碼編譯為 WebAssmebly 了
這里的 C# 需要通過 mono 的輔助用于將 IL 轉換為 WebAssembly 的代碼,所以需要在Mono官網下載最新的 Mono 的 SDK 安裝
點擊下載
默認的 Mono 將會安裝到?c:\Program Files\Mono\bin\?文件夾,如果是下載 x86 的就會安裝到?c:\Program Files(x86)\Mono\bin\?文件夾
然后下載 mono 在 wasm 的運行時,請?點擊下載?將下載的 zip 文件夾解壓縮到本地的文件夾,同時記住這個文件夾,如我將 zip 文件夾解壓縮到?f:/lindexi/mono?文件夾
此時準備環境工作就完成了,下一步就是命令行編譯了。當然這些步驟都是最基礎的步驟,也有封裝好的命令,也就是dotnet wasm xx.csproj?完成編譯,不過這一步需要先安裝工具(注意這個工具還沒正式發布)
通過 csc 命令將 C# 代碼編譯為 IL 文件。打開 VisualStudio 開發者命令行工具,進入到剛才創建的 Program.cs 所在文件夾
csc /target:library -out:Example.dll /noconfig /nostdlib /r:f:/lindexi/mono/wasm-bcl/wasm/mscorlib.dll /r:f:/lindexi/mono/wasm-bcl/wasm/System.dll /r:f:/lindexi/mono/wasm-bcl/wasm/System.Core.dll /r:f:/lindexi/mono/wasm-bcl/wasm/Facades/netstandard.dll /r:f:/lindexi/mono/wasm-bcl/wasm/System.Net.Http.dll /r:f:/lindexi/mono/framework/WebAssembly.Bindings.dll /r:f:/lindexi/mono/framework/WebAssembly.Net.Http.dll Program.cs注意將?f:/lindexi/mono?文件夾替換為你剛才解壓縮的 mono 運行時所在的文件夾
上面的代碼通過引用 mono 運行時的庫,將 Program.cs 文件編譯為 Example.dll 文件
當然這里的 Example.dll 文件現在還是 IL 文件,還需要通過 mono 再次編譯為 wasm 文件。注意這里說的編譯為 wasm 并不是真的將 IL 編譯 wasm 文件,而是編譯為運行在 wasm 的 .NET 運行時可解析的文件。上面這句話已經過時,只是我逗比看文檔理解不對,其實上面這一步編譯的 IL 文件已經可以在 wasm 執行了。原因是在 wasm 會先運行一個 .NET 的運行時,由 .NET 運行時執行這個 IL 文件單獨一個 Example.dll 文件是不能直接運行的,如上面所說,需要添加一個.NET運行時。但是一個 .NET 運行時是超級大的,難道要用戶每次打開網頁都下載一個這么大的運行時?此時就需要用到?packager.exe?工具,通過這個工具,可以只添加引用的同時支持在 wasm 運行的庫
"c:\Program Files\Mono\bin\mono" "f:/lindexi/mono/packager.exe" --copy=always --out=./publish Example.dll注意上面的路徑,如果安裝的是 x86 的 mono 那么需要修改路徑為?c:\Program Files(x86)\Mono\bin\mono?此外需要將?f:/lindexi/mono/packager.exe?替換為你解壓縮的 mono 運行時文件夾
執行上面命令如果看到下面輸出,那么就是運行成功
cp: Always - f:\temp\WpfApp1\YadernawcoLofeleabe\Example.dll -> ./publish\managed\Example.dll cp: Always - f:\lindexi\mono\wasm-bcl\wasm\mscorlib.dll -> ./publish\managed\mscorlib.dll cp: Always - f:\lindexi\mono\framework\WebAssembly.Bindings.dll -> ./publish\managed\WebAssembly.Bindings.dll cp: Always - f:\lindexi\mono\wasm-bcl\wasm\Facades\netstandard.dll -> ./publish\managed\netstandard.dll cp: Always - f:\lindexi\mono\wasm-bcl\wasm\System.dll -> ./publish\managed\System.dll cp: Always - f:\lindexi\mono\wasm-bcl\wasm\Mono.Security.dll -> ./publish\managed\Mono.Security.dll cp: Always - f:\lindexi\mono\wasm-bcl\wasm\System.Xml.dll -> ./publish\managed\System.Xml.dll cp: Always - f:\lindexi\mono\wasm-bcl\wasm\System.Numerics.dll -> ./publish\managed\System.Numerics.dll cp: Always - f:\lindexi\mono\wasm-bcl\wasm\System.Core.dll -> ./publish\managed\System.Core.dll cp: Always - f:\lindexi\mono\framework\WebAssembly.Net.WebSockets.dll -> ./publish\managed\WebAssembly.Net.WebSockets.dll cp: Always - f:\lindexi\mono\wasm-bcl\wasm\Facades\System.Memory.dll -> ./publish\managed\System.Memory.dll cp: Always - f:\lindexi\mono\wasm-bcl\wasm\System.Data.dll -> ./publish\managed\System.Data.dll cp: Always - f:\lindexi\mono\wasm-bcl\wasm\System.Transactions.dll -> ./publish\managed\System.Transactions.dll cp: Always - f:\lindexi\mono\wasm-bcl\wasm\System.Data.DataSetExtensions.dll -> ./publish\managed\System.Data.DataSetExtensions.dll cp: Always - f:\lindexi\mono\wasm-bcl\wasm\Facades\System.Drawing.Common.dll -> ./publish\managed\System.Drawing.Common.dll cp: Always - f:\lindexi\mono\wasm-bcl\wasm\System.IO.Compression.dll -> ./publish\managed\System.IO.Compression.dll cp: Always - f:\lindexi\mono\wasm-bcl\wasm\System.IO.Compression.FileSystem.dll -> ./publish\managed\System.IO.Compression.FileSystem.dll cp: Always - f:\lindexi\mono\wasm-bcl\wasm\System.ComponentModel.Composition.dll -> ./publish\managed\System.ComponentModel.Composition.dll cp: Always - f:\lindexi\mono\wasm-bcl\wasm\System.Net.Http.dll -> ./publish\managed\System.Net.Http.dll cp: Always - f:\lindexi\mono\framework\WebAssembly.Net.Http.dll -> ./publish\managed\WebAssembly.Net.Http.dll cp: Always - f:\lindexi\mono\wasm-bcl\wasm\System.Runtime.Serialization.dll -> ./publish\managed\System.Runtime.Serialization.dll cp: Always - f:\lindexi\mono\wasm-bcl\wasm\System.ServiceModel.Internals.dll -> ./publish\managed\System.ServiceModel.Internals.dll cp: Always - f:\lindexi\mono\wasm-bcl\wasm\System.Xml.Linq.dll -> ./publish\managed\System.Xml.Linq.dll此時打開 Program.cs 所在的文件夾,可以看到文件夾包含了 publish 文件夾,這個文件夾里面的內容就是 wasm 使用的文件了,而剛才編譯的 Example.dll 就放在 managed 文件夾里面
下一步就是如何在 html 中使用剛才編譯出來的 Excample.dll 文件了,這部分感謝前端的小智的協助
需要在 html 中引用 publish 文件夾下的?mono-config.js?和?runtime.js?和?dotnet.js?文件夾
<script type="text/javascript" src="./mono-config.js"></script><script type="text/javascript" src="./runtime.js"></script><script async type="text/javascript" src="./dotnet.js"></script>接下來就是如何在 js 代碼調用 C# 編譯的 dll 了
通過?Module.mono_bind_static_method?可以將 js 的一個方法綁定到一個靜態的方法里面
Module.mono_bind_static_method("[Example] YadernawcoLofeleabe.Example:Hello");使用格式是?Module.mono_bind_static_method("[dll文件名] 命名空間.類名:靜態方法");?如上面代碼
嘗試復制下面代碼放在 html 里面
<script type="text/javascript">let that = this;var App = {onClick: function () {that.output.value = "Please wait";that.output.value = that.execute("Ali");},init: function () {that.execute = Module.mono_bind_static_method("[Example] YadernawcoLofeleabe.Example:Hello");that.output = document.getElementById("output");that.button = document.getElementById("button");that.button.disabled = false;}}; </script>如果你的 dll 命名和命名空間和我不相同,那么請自己修改
接下來就是添加簡單的界面了
<!DOCTYPE doctype html> <html lang="en"><head><!-- Required meta tags --><meta charset="utf-8"><meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport"><!-- Bootstrap CSS --><link crossorigin="anonymous" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.0/css/bootstrap.min.css" integrity="sha384-SI27wrMjH3ZZ89r4o+fGIJtnzkAnFs3E4qz9DIYioCQ5l9Rd/7UAa8DHcaL8jkWt" rel="stylesheet"><title>Hello, Mono WASM!</title></link></meta></meta></head><body><div class="container"><h1>Hello, world!</h1><form><div class="form-group"><label for="output">Output from C#:</label><textarea class="form-control" id="output" rows="10"></textarea></div><div class="form-group"><button class="btn btn-primary" id="button" onclick="App.onClick" type="button">Run WASM, Run!</button></div></form></div><script type="text/javascript">let that = this;var App = {onClick: function () {that.output.value = "Please wait";that.output.value = that.execute("Ali");},init: function () {that.execute = Module.mono_bind_static_method("[Example] YadernawcoLofeleabe.Example:Hello");that.output = document.getElementById("output");that.button = document.getElementById("button");that.button.disabled = false;}}; document.getElementById("button").addEventListener("click", App.onClick);document.body.addEventListener("load", App.init);</script><script src="./mono-config.js" type="text/javascript"></script><script src="./runtime.js" type="text/javascript"></script><script async="" src="./dotnet.js" type="text/javascript"></script></body> </html>嘗試開啟一個靜態的 HTTP 服務器,然后在瀏覽器訪問這個 html 文件,注意將 dll 文件設置用戶可下載,這樣就完成了。例子可以訪問https://0x414c49.github.io/wasm-example/index.html?這里有所有的文件
其實我在入門翻了車,多謝下面大佬的博客,本文大部分代碼都是抄下面博客
Run C# natively in the browser through the web assembly via mono-wasm:?https://medium.com/m/global-identity?redirectUrl=https%3A%2F%2Fitnext.io%2Frun-c-natively-in-the-browser-through-the-web-assembly-via-mono-wasm-60f3d55dd05a?
看到這里小伙伴想到了什么?沒錯,微軟 Blazor 就是用這個原理,用 C# 寫前端
總結
以上是生活随笔為你收集整理的dotnet 将C#编译为wasm让前端html使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: asp.net core 实现支持多语言
- 下一篇: 【实战 Ids4】小技巧篇:自定义登录页