ASP.NET Core + IIS 502.5错误码0x8007010b的解决方法

ASP.NET Core是跨平台的Web技术,像Spring Boot一样使用内置Kestrel的方式就能够作为一个进程自己跑起来承担Web应用服务器的功能。

但是Kestrel强项在于处理动态请求,作为Web服务器的能力稍弱,对于静态文件支持、请求缓存等Web服务器功能支持都不算强,并且不建议使用一个控制台进程的方式把Kestrel直接用于生产。

使用Windows平台,通常使用IIS作为Kestrel的反向代理运行起来。使用Linux,我们可以选择使用NginX作为反向代理。

但是在Visual Studio调试中直接使用IIS调试会非常顺利,碰不到实际上线部署所碰到的问题,例如在低版本Windows里面所出现的部署不成功问题。

现在按照开发人员常见的部署IIS步骤,排除一些里面会出现的问题。

一、首先,把一个ASP.NET Core Web程序发布,以下使用默认发布方式

这是最常见的发布方式。

二、在Win10 IIS里面随便一个站点,创建一个应用程序

三、在确认IIS是否能成功跑起来之前,先用命令行的方式确认直接跑Kestrel能否跑起来

Ketrel端口默认是5000,建议不要占用它,方便随时使用默认的形式调试。命令行使用

1
$ dotnet ****.dll

的方式运行,这个是成功的。

四、IIS跑起来的时候报500.19

如图:

因为我们之前已经确认过Kestrel运行asp.net core站点是正常的,那么到底是什么原因呢?

其实是开发人员在ASP.NET上过于经验丰富,没看说明就跑起来了。

看一下微软的官方指导,如何用IIS Host ASP.NET Core(由于公众号的限制,直接贴网址,网址可能随着版本变,搜索一下就可以了):

https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/?view=aspnetcore-2.1&tabs=aspnetcore2x

因为ASP.NET Core的运行方式和原来的ASP.NET有所不同,所以不是安装一个.NET Framework就搞定的,需要安装各种组件适配各种情况。.NET Core的Prerequisite就要求C++ 2015 Redistribution,这个在类似于Windows 2008 R2(Win7)这样的老系统上,一般是没有的。而开发人员如果使用Win7来开发,不会出现这个问题,是因为安装Visual Studio的时候会把Microsoft Visual C++ 2015 Redistribution装上,所以本机根本不会有这个问题。

如果没有安装C++ 2015 Redistribution,是会爆“丢失api-ms-win-crt-runtime-l1-1-0.dll”的:

.NET Core Hosting Bundle就更加不用说了,用VS调试IIS根本不会报问题,因为VS不是使用web.config文件启动ASP.NET Core程序,是有一套自己的启动方式。

五、安装.NET Core Hosting Bundle

但是我们如果没有安装VS,要单独部署ASP.NET Core的话,需要安装.NET Core Hosting Bundle。网上查的资料通常较旧,都是.NET Core 1.x时代的,那个时代.NET Core Hosting Bundle可能还是单独下载的。而到了ASP.NET Core 2.x,则是通过下载这个:

下载一个.NET Core Runtime,在.NET Core SDK的下载页直接就可以看到了。但笔者真的有点奇怪,为什么Runtime不可以直接包含在SDK里面?SDK应该是基于Runtime提供更多的开发支持,而不是用不同的runtime,所以逻辑上应该是可以合二为一的,至于是不是微软某些技术兼容的考虑就不得而知了。

六:真正的问题来了——运行的时候爆IIS 502.5

笔者找这个问题的答案最为费劲,网上什么解答方式都试过,主要都是说安装.NET Core Hosting Bundle就能解决,另外就是看一下Windows日志,看一下报错的问题是什么:

这个问题是从Windows Event Logs里面找到的。错误码0x8007010b。Google一下网上的说法基本上一样,就是安装.NET Core Hosting Bundle,然后针对这条日志记录,看一下web.config文件指示的文件位置是否正确、dotnet命令是否正确等。

实际上我们一开始就已经Kestrel验证过,直接运行“dotnet ***.dll [参数] ”是可行的。那么我们继续排查。

七、尝试解决依赖的部署方式

进程无法启动,意味着不是代码的问题,是IIS运行方式的问题。

我们尝试另一种部署方式:考虑解决所有dll依赖的问题,因为DLL依赖不通过,也是没办法启动起来的,而这通常还无法输出日志。所以我们用SelfContained的发布方式,尽量.NET Runtime启动的时候不报异常:

这个东西是平台相关的,所以如果要跑在Linux等底下就需要另外编译了,有点烦,但是为了先解决问题,暂时不考虑这个。

这样会编译出来很多平台相关的、本来该在.net Core SDK里面的DLL。还有一堆的Nuget引用的DLL都被编译生成出来了,跟原来的.NET程序类似,一个小小的ASP.NET Demo项目就会大概100MB左右。

然后我们再部署到没有VS的干净的环境里,这样就可以了么?

Too young, naive呀

八、NuGet安装Microsoft.AspNetCore.Server.IISIntegration,设置UseIISIntegration()

看上面给过的微软官方的IIS Host指导,我们还有一项没有做,就是这个:

ASP.NET Core模板生成的默认代码里面是Program.cs文件的这里:

但ASP.NET Core都喜欢使用extensions的方法,到底有没有用,是需要看有没有实现的对象对框架进行依赖注入的。而使用IIS集成的依赖注入,就是在NuGet中安装Microsoft.AspNetCore.Server.IISIntegration。

NuGet如何安装这个的就不在这个文章里面细说了。

这些都做完,在Windows 2008 R2上面重启IIS之后,基本上就OK了。来到这里,其实已经基本上解决了ASP.NET Core + IIS 502.5错误码0x8007010b这个问题。

但是如果IIS Host ASP.NET Core在没有安装VS调试过IIS的Win10上面,事情就还没有完,还是IIS 502.5错误码0x8007010b,What the fuck?

后面发现,这个主要的原因,是我们使用服务器跟使用Win10等非服务器系统的不同。

九、设置Windows用户IIS Application Pool对文件访问的权限

通常使用Windows服务器的人都比较懒,直接使用Administrator(或者Administrators用户组,以下不强调了)进行操作,那么很多文件访问的事情都会变得非常方便,因为权限够高。

而通过Administrator登录,安装IIS、创建IIS站点的时候所创建的Application Pool,是继承了拥有足够高的读写权限的。于是Application Pool能够访问除了必须Administrators或者SYSTEM组权限的目录,那么IIS以IIS或者某个IIS Application Pool用户跑Kestrel的时候都能够成功。

而使用Win10等默认给个人使用的操作系统,则可能不会成功,因为我们通常工作在非管理员用户底下,典型的非管理员用户就是使用了Microsoft ID登录Win10,一直没有使用Administrator(从某个时间段开始,微软的操作系统Administrator自动隐藏了,需要net user Administrator /active:yes 才能见到并激活使用)。我们在Win10安装IIS、创建一个新的站点自动创建一个对应的IIS Application Pool用户,其实权限并没有那么高,哪怕安装IIS过程中中间需要弹窗让我们授权。

在Linux底下,需要root权限的命令都需要先sudo,那么补偿的操作,首先不是用Administrator解决所有问题,而是分配一下权限:

在你需要运行ASP.NET Core的目录右键->属性->安全,通过“编辑……”增加一个你所使用的Application Pool对应的用户的权限来解决。

用户名通常是这种格式:IIS AppPool<myappoolname>

例如上面的是Wp2Self,在查找用户的时候则输入“IIS AppPool\Wp2Self”查找就出来了。

具体添加的步骤也不细说,估计大部分的读者没太多经验也都有Google的能力。

这次就应该真的解决了。然而这样还没够。既然Windows使用IIS做反向代理到Kestrel这么麻烦,我们试试Linux使用NginX反向代理如何?

十、安装NginX并设置反向代理

安装Nginx也不说了,网上资料非常多,先测试运行一下保证NginX安装成功:

这次别自作聪明,当个小白,直接看微软的官方指导文档:

https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-2.1&tabs=aspnetcore2x

如果不加这个Http Header Forward,则反向代理就不带信息过来了。

然后在/etc/nginx/conf.d/nginx.conf(没有这个文件就创建一个)配置NginX反向代理:

来到这里可能需要注意,NginX反向代理并没有像IIS那样还负责把Kestrel跑起来。所以这里的proxy_pass所指向的http://localhost:5000是需要我们自己通过“dotnet ****.dll”跑起来的。

配置好NginX和跑起Kestrel,sudo nginx -s reload 之后测试一下:

我们的服务器的确是变成了NginX了。但是在Linux平台下Kestrel的稳定性,还是需要像SpringBoot直接自己跑Web应用一样,仔细考虑一下稳定性的。

写在最后

其实真的挺累,部署个ASP.NET Core Hello World 都这么困难。除了要解决环境问题,还要解决可靠性问题。

其实如果条件允许,真没必要去花精力在这些上面,直接使用Azure WebApp一键部署:

不但不用关心基础设施,一步就部署成功,而且Azure WebApp保证运行在里面的程序很高的可用性,还能自动根据负载缩放程序运行的实例等等功能。

我是不会告诉你这是一个一站式解决的方案的。

但是使用Azure WebApp也是有需要注意的地方的。

那就是Azure WebApp未必支持最新的.NET Core,所以需要在控制台里面找Kudu看一下:

部署在Azure WebApp程序的ASP.NET Core的版本,一定要不高于这个版本才行。

推荐文章