起因
对于刚刚有意向和已经行动将Asp.Net项目迁移到Linux服务器的小伙们,会碰到各种打击,常说的一句就是,我的项目在IIS运行的没问题呀,但放到Linux怎么就不行了呢!这是为什么呢?大体上是因为部分历史原因的元素,大多数问题还是因为我们没有跨平台的意识,在不经意间在使用了Windows系统的特性(等下详细说).
Asp.Net可以跨平台不是个新鲜的事情,只是我们不了解而已,最早接触Asp.Net跨平台是在13年,那会将Asp.Net WebForm运行在Linux还是有些麻烦,很多人都说玩玩就行了,你还指望上项目呀!那会还不知道Jexus是神马,第一次尝试的时候,Mono安装是必备的,当然全世界都知道的,其次就是安装Apache(没错),然后安装Httpd,最后安装xsp,麻烦吧!相对于现在是很麻烦了,最终还是很好的运行了.
现在要想将Asp.Net在Linux运行,大体上分两种老项目用Jexus来运行和新项目用Asp.Net Core开发用Kestrel Server运行.
Jexus是国内牛人宇内流云所写,使用CSharp基于Linux的epoll I/O复用,又针对Linux做了大量的优化,Jexus性能比Xsp好很多,且使用简单,操作方便,最贴心的是使用独立版的话,Jexus已经内置Mono,真是做到了开箱即用.
Kestrel Server是微软出品.在著名Libuv事件库上,用CSharp进行封装,很好的继承Libuv的特性,跨平台,如果不知道Libuv,那么可能听说过NodeJs,其实NodeJs底层也是Libuv.所以Kestrel Server在性能上是完全没问题.但只能运行Asp.Net Core项目.
TinyFox也是宇内流云所写,同样也是基于Libuv,但宇大重新封装了线程池,TinyFox主要运行基于Owin协议的项目(Jexus也支持基于Owin项目),如果你不知道的话,那要好好的百度一下,这里面有很多的事情.同时也是可以支持传统的Web项目(Asp.Net WebForm/MVC),是以适配器组件将Http请求信息(Owin的请求)转换为Asp.Net WebForm的请求信息进行运行.还有一个很大的优点是支持Socket,方便客户端进行通信.
不掰扯了,想要跨平台,都要摒弃使用系统独有的特性.假如说你使用Windows的特性,即使是Java项目中也不能好好的部署到Linux服务器.
Jexus开箱即用,使用也很简单,这里就不多说证书如何使用了,具体参考Jexus的readme文件,有中文介绍.
不依赖Windows特性
在项目引用的程序集,没有使用Windows系统独有的系统函数调用,如调用的kernel32.dll中系统函数.
进入正题,新建一个WebForm项目,当然MVC项目也可以的.
该项目是使用VS2022所建,当然VS2022应该相差不大.使用VS WebForm模板,看看项目中的文件.
asp.net webform项目 VS默认模板
如果看项目引用,简直是头皮发麻呀!我就想建一个项目,至于那么多引用吗?微软真是太贴心了,以至于这些成为我们项目跨平台的罪魁祸首.
将项目编译后,将生成的文件放到Linux(这里使用Jexus运行)先看看FileNotFoundException
asp.net. webform/mvc 发布到Linux遇到FileNotFoundException信息
Mono 5.0开始支持csc编译了,还没有运行在Mono 5.0测试过的,碰到这个问题,就在NuGet管理器中卸载
Microsoft.CodeDomviders.DotNetCompilerPlatform和Microsoft.Netpilers.
来看看卸载前后的对比:
VS的WebForm模板有些引用造成无法在Linux运行的主要原因
说说模板中引用Microsoft.Web.Infrastructure.dll
在VS中发布的
Microsoft.Web.Infrastructure.dll文件是不能跨平台的,是因为该库文件使用Windows的特性注册表,在KillBitHelper类中.所以在发布之后,要先把该文件删除掉,没事的,因为Mono很贴心给我们准备一个跨平台的
Microsoft.Web.Infrastructure.dll.
Microsoft.Web.Infrastructure.dll这个模板引用的是无法在Linux运行的
Mono下有同名对应的动态库的,在将该程序集排除后,将剩下的程序集拷贝到Linux上就可以了.
WebForm项目中文件名问题
Linux系统对文件名大小写是区分的,如index.html和Index.html这两个文件名在Linux系统中是两个文件,这一点和Windows是完全不一样的.不管迁移老项目和新项目,最后对文件名进行统一,个人建议文件名统一小写处理.
早期Mono有一个配置MONO_IOMAP是可以在Linux不区分文件名大小写的,这是需要以性能为代价实现,是通过多次打开文件来实现的.
在Jexus配置也有MONO_IOMAP,随着Mono移除该配置,Jexus也不支持区分文件名大小写.
最后追加
文章主要内容是在2022年7月7日所写,那时Kestrel Server和TingyFox都是基于Libuv,现在Kestrel Server都不支持Libuv了,TinyFox是基于对应系统的Socket和IO复用(Windows IOCP/Linux Epoll)
项目需要迁移到Linux,又特别需要高性能的话,可以将在需要性能的地方,拆分为基于Owin的项目,