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使用相关推荐
- 使用Apache TVM将机器学习编译为WASM和WebGPU
使用Apache TVM将机器学习编译为WASM和WebGPU TLDR 在Apache TVM深度学习编译器中引入了对WASM和WebGPU的支持.实验表明,在将模型部署到Web时,TVM的WebG ...
- DOTNET防止反编译
DOTNET防止反编译 目录 第一部分 相关理论 一 防止反编译概述 二 DOTNET编译原理简介 三 被反编译的后果 四 保护方案分类 第二部分 实践 一 Net强名称工具SN.EXE 二 使用Do ...
- 如何使用LLVM将C语言编译为WASM
LLVM 在10之后都支持了wasm,但是这是一个实验性的功能,默认是不打开的,另外,在windows上,llvm是不带LLVM静态编译器的,也就是llc,但是Linux倒是自带了llvm的llc,但 ...
- 把两个C++项目编译成wasm
[应用场景说明] C++动态库在不同的平台需要编译成不同的形式,widows下应用时需要编译成dll文件,linux下应用时需要编译成so文件,mac下应用时需要编译成dylib.每升级一次库文件,都 ...
- js中立即执行函数会预编译吗_作为前端你了解JavaScript运行机制吗?
作为前端工程师,大家都知道js是前端一开始就要学会的知识点,js的代码你会写了,那js的运行机制你了解吗?只有了解了js的运行机制,才能在工作中如鱼得水,今天就跟随珠峰的老师一起来了解下js的运行机制 ...
- 图解DotNet框架之一:编译与执行引擎(上)
众所周知,DotNet框架是非常庞大的,光项目创建时的种类就有WPF,WCF,WF这三种最新的技术,还有以前的Web,WinForm,Service,Mobile等等. 这么复杂和庞大的框架,用文字来 ...
- node 简繁体转换_编译了wasm版本的OpenCC,在浏览器上直接转换简繁体
wasm-opencc开放中文转换OpenCC的wasm版本. 这个项目对OpenCC进行了添加修改修改,并利用Emscripten进行编译,在OpenCC进行中文简繁体转换的能力上具有以下特性:可在 ...
- 编译原理中的前端和后端
划分依据:与机器的相关性. 前端工作与源语言有关而与机器无关.后端工作与机器有关. 可以理解为:前端工作把(不同类型的)源语言转换为中间代码,后端工作是将中间代码适用于(不同类型的)机器上.实际应用中 ...
- BIM轻量化和Web的应用
大家好,我是小张同学,一个接触BIM有一段时间的人了,一直混迹在各大论坛学习的潜水党,收获众多.也很感慨与各种前辈们的无私奉献,在此也想分享一点自己一直以来的学习过程.如有理解不足或错误 ...
最新文章
- 企业开发与社交开发相辅相成
- 推荐:.Net 5开源免费的内容管理系统
- 基于Masstransit实现Eventbus的功能
- Unity4.3 遮挡剔除:基本知识
- nologging mysql_oraclenologgingoperation
- 计算机毕业设计springboot家政管理系统
- Dlink ?一款交互式FlinkSQL开发平台
- python实现网页表单填写_python在网页中自动填充表单
- WC-Write Combining 合并写技术
- HALO博客配置华为云OSS上传附件
- Mac 上 git 命令出现 xcode-select: error: tool ‘xcodebuild‘ requires Xcode, but active developer direc 错误
- mysql 集群搭建(Centos7) for Galera
- Redis做接口限流
- Linux下常用的工具软件
- SQL Server 利用WITH AS递归获取层级关系数据
- NopCommerce Alipay 支付插件
- Mac 定时提醒应用 stretchly 配置
- 智能网卡OVS卸载设计
- 【slam十四讲第二版】【课本例题代码向】【第七讲~视觉里程计Ⅱ】【使用LK光流(cv)】【高斯牛顿法实现单层光流和多层光流】【实现单层直接法和多层直接法】
- Flink教程(31)- Flink网络流控及反压