关键词:
KestrelServer最大的优势体现在它的跨平台的能力,如果ASP.NET CORE应用只需要部署在Windows环境下,IIS也是不错的选择。ASP.NET CORE应用针对IIS具有两种部署模式,它们都依赖于一个IIS针对ASP.NET CORE Core的扩展模块。本文提供的示例演示已经同步到《ASP.NET Core 6框架揭秘-实例演示版》)
一、ASP.NET CORE Core Module
二、 In-Process部署模式
三、Out-of-Process部署模式
四、<aspnetcore>配置
一、ASP.NET CORE Core Module
IIS其实也是按照管道的方式来处理请求的,但是IIS管道和ASP.NET CORE中间件管道有本质的不同。对于部署在IIS中的Web应用来说,从最初接收到请求到最终将响应发出去,这段处理流程被细分为一系列固定的步骤,每个都具有一个或者两个(前置+后置)对应的事件或者回调。我们可以利用自定义的Module注册相应的事件或回调在适当的时机接管请求,并按照自己希望的方式对它进行处理。
IIS提供了一系列原生(Native)的Module,我们也可以使用任意.NET语言编写托管的Module,整合IIS和ASP.NET CORE 的这个ASP.NET CORE Core Module就是一个原生的Module。它利用注册的事件将请求从IIS管道中拦截下来,并转发给ASP.NET CORE管道进行处理。相应的安装包可以从https://dotnet.microsoft.com/permalink/dotnetcore-current-windows-runtime-bundle-installer下载。
二、 In-Process部署模式
ASP.NET CORE在IIS下有In-Process和Out-of-Process两种部署模式。In-Process模式下的ASP.NET CORE应用运行在IIS的工作进程w3wp.exe中(如果采用IIS Express,工作进程为iisexpress.exe)。如图18-7所示,ASP.NET CORE应用在这种模式下使用的服务器类型是IISHttpServer,上述的ASP.NET CORE Core Module会将原始的请求转发给这个服务器,并将后者生成响应转交给IIS服务器进行回复。
图1 In-Process部署模式
In-Process是默认采用的部署模式,所以我们不需要为此做任何设置,接下来我们就来演示一下具体的部署方式。我们在IIS的默认站点(Defaut Web Site)创建一个名为WebApp的应用,并将映射的物理路径设置为“C:\\App”。然后我们创建一个空的ASP.NET CORE程序,并编写了如下这个将当前进程名称作为响应内容的演示程序。
using System.Diagnostics;
var app = WebApplication.Create(args);
app.Run(context => context.Response.WriteAsync(Process.GetCurrentProcess().ProcessName));
app.Run();
然后我们在Visual Studio的解决方案视图右键选择该项目,在弹出的菜单中选择“发布(Publish)”选项,创建一个指向“C:\\App”的Publish Profile,然后执行这个Profile完成发布工作。应用发布也可以执行命令行“dotnet public”来完成。应用部署好之后,我们利用浏览器采用地址“http://localhost/webapp”访问部署好的应用,从图2所示的输出结果可以看出ASP.NET CORE应用实际上就运行在IIS的工作进程中。
图2 In-Process模式下的进程名称
如果我查看此时的部署目录(“C:\\App”),会发现生成的程序集和配置文件。应用既然部署在IIS中,那么具体的配置自然定义在web.config中,如下所示的就是这个文件的内容。我们会发现所有的请求(path="*" verb="*")都被映射到“AspNetCoreModuleV2”这个Module上,这就是上面介绍的ASP.NET CORE Core Module。至于这个Module如果启动ASP.NET CORE管道并与之交互,则由后面的<aspNetCore>配置节来控制,可以看到它将表示部署模式的hostingModel属性设置为“inprocess”。
<?xml version="1.0" encoding="utf-8"?> <configuration> <location path="." inheritInChildApplications="false"> <system.webServer> <handlers> <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" /> </handlers> <aspNetCore processPath="dotnet" arguments=".\\App.dll" stdoutLogEnabled="false" stdoutLogFile=".\\logs\\stdout" hostingModel="inprocess" /> </system.webServer> </location> </configuration> <!--ProjectGuid: 243DF55D-2E11-481F-AA7A-141C2A75792D-->
In-Process模式会注册如下这个IISHttpServer,对应的配置选项定义在IISServerOptions中。如果具有同步读写请求和响应主体内容的需要,我们需要将AllowSynchronousIO属性(默认为False)设置为True。如果将AutomaticAuthentication属性返回True(默认值),认证用户将自动赋值给HttpContext上下文的User属性。我们可以利用MaxRequestBodyBufferSize(默认为1,048,576)和MaxRequestBodySize属性(默认为30,000,000)设置接收请求主体的缓冲区的容量,和最大请求主体的字节数。
internal class IISHttpServer : IServer, IDisposable public IFeatureCollection Features get; public IISHttpServer( IISNativeApplication nativeApplication, IHostApplicationLifetime applicationLifetime, IAuthenticationSchemeProvider authentication, IOptions<IISServerOptions> options, ILogger<IISHttpServer> logger); public unsafe Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken); public Task StopAsync(CancellationToken cancellationToken);
public class IISServerOptions public bool AllowSynchronousIO get; set; public bool AutomaticAuthentication get; set; public string? AuthenticationDisplayName get; set; public int MaxRequestBodyBufferSize get; set; public long? MaxRequestBodySize get; set;
针对IISHttpServer的注册实现在IWebHostBuilder接口如下这个UseIIS扩展方法中。由于这个方法并没有提供一个Action<IISServerOptions>委托参数对IISServerOptions配置选项进行设置,所以我们不得不采用原始的对它进行设置。由于IHostBuider接口ConfigureWebHostDefaults扩展方法内部会调用这个方法, 我们并不需要为此做额外的工作。
public static class WebHostBuilderIISExtensions public static IWebHostBuilder UseIIS(this IWebHostBuilder hostBuilder);
三、Out-of-Process部署模式
ASP.NET CORE应用在IIS中还可以采用Out-of -Process模式进行部署。如图3所示,在这种部署下,采用KestrelServer的ASP.NET CORE应用运行在独立的dotnet.exe进程中。当IIS接受到针对目标应用的请求时,如果目标应用所在的进程并未启动,ASP.NET CORE Core Module还负责执行dotnet命令激活此进程,相当于充当了WAS(Windows Activation Service)的作用。
图3 Out-of-Process部署模式
在激活ASP.NET CORE承载进程之前,ASP.NET CORE Core Module会选择一个可用的端口号,该端口号和当前应用的路径(该路径将作用ASP.NET CORE应用的PathBase)被写入环境变量,对应的环境变量名称分别为“ASPNETCORE_PORT”和“ASPNETCORE_APPL_PATH”。以Out-of-Process模式部署的ASP.NET CORE应用只会接收IIS转发给它的请求,为了能够过滤其它来源的请求,ASP.NET CORE Core Module会生成一个Token并写入环境变量“ASPNETCORE_TOKEN”。后续转发的请求会利用一个报头“MS-ASPNETCORE-TOKEN”传递此Token,ASP.NET CORE应用会校验是否与之前生成的Token匹配。
ASP.NET CORE Core Module还会利用环境变量传递其他一些设置,认证方案会写入环境变量“ASPNETCORE_IIS_HTTPAUTH”,另一个“ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED”环境变量用来设置针对Web Socket的支持状态。由于这些环境变量名称的前缀都是“ASPNETCORE_”,所以它们会作为默认配置源。KestrelServer最终会绑定到基于该端口的本地终结点(“localhost”)进行监听。由于监听地址是由ASP.NET CORE Core Module控制的,所以它只需要将请求往该地址进行转发,最终将接收到响应交给IIS返回即可。由于这里涉及本地回环网络(Loopback)的访问,其性能自然不如In-Process部署模式。
<?xml version="1.0" encoding="utf-8"?> <configuration> <location path="." inheritInChildApplications="false"> <system.webServer> <handlers> <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2"resourceType="Unspecified" /> </handlers> <aspNetCore processPath="dotnet" arguments=".\\App.dll" stdoutLogEnabled="false" stdoutLogFile=".\\logs\\stdout" hostingModel="outofprocess" /> </system.webServer> </location> </configuration>
我们在上面演示了In-Process的部署方式,现在我们直接修改配置文件web.config,按照上面的方式将<aspNetCore>配置节的hostingModel属性设置为“outofprocess”,部署的应用就自动切换到Out-of-Process。此时再次以相同的方式访问部署的应用,我们会发现浏览器上显示的进程名称变成了“dotnet”。
图4 Out-of-Process模式下的进程名称
部署模式可以直接定义在项目文件中,如果按照如下的方式将AspNetCoreHostingModel属性设置为“OutOfProcess”,那么发布后生成的web.config中针对部署模式的设置将随之改变。该属性默认值为“InProcess”,我们也可以显式进行设置。
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> <NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile> <AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel> </PropertyGroup> </Project>
为了进一步验证上述的这一系列环境变量是否存在,如下所示的演示程序会将以“ASPNETCORE_”为前缀的环境变量作为响应内容输出来。除此之外,作为响应输出的还有进程名称、请求的PathBase和“MS-ASPNETCORE-TOKEN”报头。
using System.Diagnostics; using System.Text; var app = WebApplication.Create(args); app.Run(HandleAsync); app.Run(); Task HandleAsync(HttpContext httpContext) var request = httpContext.Request; var configuration = httpContext.RequestServices.GetRequiredService<IConfiguration>(); var builder = new StringBuilder(); builder.AppendLine($"Process: Process.GetCurrentProcess().ProcessName"); builder.AppendLine($"MS-ASPNETCORE-TOKEN: request.Headers["MS-ASPNETCORE-TOKEN"]"); builder.AppendLine($"PathBase: request.PathBase"); builder.AppendLine("Environment Variables"); foreach (string key in Environment.GetEnvironmentVariables().Keys) if (key.StartsWith("ASPNETCORE_")) builder.AppendLine($"\\tkey=Environment.GetEnvironmentVariable(key)"); return httpContext.Response.WriteAsync(builder.ToString());
应用重新发布之后,再次利用浏览器访问后回得到如图5所示的结果。我们可以从这里找到上述的环境变量,请求携带的“MS-ASPNETCORE-TOKEN”报头正好与对应环境变量的值一致,应用在IIS中的虚拟目录作为了应用路径被写入环境变量并成为请求的PathBase。如果站点提供了HTTPS终结点,其端口还会写入“SPNETCORE_ANCM_HTTPS_PORT”这个环境变量,这是为了实现针对HTTPS终结点的重定向而设计的。
Out-of-Process部署的大部分实现都是由如下这个IISMiddleware中间件来完成的,IISOptions为对应的配置选项。IISMiddleware中间件完成了针对“配对Token”的验证过滤非IIS转发的请求。如果IISOptions配置选项的ForwardClientCertificate属性返回True(默认值),此中间件会从请求报头“MS-ASPNETCORE-CLIENTCERT”中提取客户端证书,并将它保存到ITlsConnectionFeature特性中。该中间件还会将当前Windows账号对应的WindowsPrincipal对象附加到HttpContext上下文的特性集合中,如果IISOptions配置选项的AutomaticAuthentication属性返回True(默认值),该对象会直接赋值给HttpContext上下文的User属性。
public class IISMiddleware public IISMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, IOptions<IISOptions> options, string pairingToken, IAuthenticationSchemeProvider authentication, IHostApplicationLifetime applicationLifetime); public IISMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, IOptions<IISOptions> options, string pairingToken, bool isWebsocketsSupported, IAuthenticationSchemeProvider authentication, IHostApplicationLifetime applicationLifetime); public Task Invoke(HttpContext httpContext); public Task Invoke(HttpContext httpContext)
public class IISOptions public bool AutomaticAuthentication get; set; public string? AuthenticationDisplayName get; set; public bool ForwardClientCertificate get; set;
IIS利用WAS根据请求激活工作进程w3wp.exe。如果站点长时间未曾访问,它还会自动关闭工作进程。如果工作进程都关闭了,承载ASP.NET CORE应用的dotnet.exe进程自然也应该关闭。为了关闭应用承载进程,ASP.NET CORE Core Module会发送一个特殊的请求,该请求携带一个值为“shutdown”的“MS-ASPNETCORE-EVENT”报头,IISMiddleware中间件在接收到该请求时会利用注入的IHostApplicationLifetime对象关闭当前应用。如果不支持WebSocket,该中间件还会将代表“可升级到双向通信”的IHttpUpgradeFeature特性删除。将应用路径设置为请求的PathBase也是由这个中间件完成的。由于IISMiddleware中间件所作的实际上是对HttpContext上下文进行初始化的工作,所以它必须优先执行才有意义,为了将此中间件置于管道的前端,如下这个IISSetupFilter被定义出来完成对该中间件的注册。
internal class IISSetupFilter : IStartupFilter internal IISSetupFilter(string pairingToken, PathString pathBase, bool isWebsocketsSupported); public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next);
IISSetupFilter最终是通过IWebHostBuilder接口如下这个UseIISIntegration扩展方法进行注册的。这个方法还负责从当前配置和环境变量提取端口号,并完成监听地址的注册。由于KestrelServer默认会选择注册到服务器上的终结点,所以该方法会利用配置将IServerAddressesFeature特性的PreferHostingUrls属性设置为True,这里设置的监听地址才会生效。这个方法还会根据当前IIS站点的设置对IISOptions作相应设置。由于IHostBuider接口ConfigureWebHostDefaults扩展方法内部也会调用这个方法,我们并不需要为此做额外的工作。
public static class WebHostBuilderIISExtensions public static IWebHostBuilder UseIISIntegration(this IWebHostBuilder hostBuilder);
四、<aspnetcore>配置
不论是采用何种部署模式,相关的配置都定义在部署目录下的web.config配置文件,它提供的针对ASP.NET CORE Core Module的映射使我们能够将ASP.NET CORE应用部署在IIS中。在web.config中,与ASP.NET CORE应用部署相关的配置定义在<aspNetCore>配置节中。
<aspNetCore processPath = "dotnet" arguments = ".\\App.dll" stdoutLogEnabled = "false" stdoutLogFile = ".\\logs\\stdout" hostingModel = "outofprocess" forwardWindowsAuthToken = "true" processesPerApplication = "10" rapidFailsPerMinute = "5" requestTimeout = "00:02:00" shutdownTimeLimit = "60" startupRetryCount = "3" startupTimeLimit = "60"> <environmentVariables> <environmentVariable name = "ASPNETCORE_ENVIRONMENT" value = "Development"/> </environmentVariables> <handlerSettings> <handlerSetting name = "stackSize" value = "2097152" /> <handlerSetting name = "debugFile" value = ".\\logs\\aspnetcore-debug.log" /> <handlerSetting name = "debugLevel" value = "FILE,TRACE" /> </handlerSettings> </aspNetCore>
上面这段XML片段包含了完整的<aspNetCore>配置属性,下表对这些配置进行了简单的说明。设置的文件可以采用绝对路径和相对于部署目录(通过 “.”表示)的相对路径。
属性 | 含 义 |
processPath | ASP.NET CORE应用启动命令所在路径,必需。 |
arguments | ASP.NET CORE应用启动传入的参数,可选。 |
stdoutLogEnabled | 是否将stdout 和stderr输出到 stdoutLogFile属性指定的文件,默认为False。 |
stdoutLogFile | 作为stdout 和stderr输出的日志文件,默认为“ aspnetcore-stdout”。 |
hostingModel | 部署模式,“inprocess/InProcess”或者“outofprocess/OutOfProcess”(默认值)。 |
forwardWindowsAuthToken | 是否转发Windows认证令牌,默认为True。 |
processesPerApplication | 承载ASP.NET CORE应用的进程( processPath)数,默认为1。该配置对In-Process模式无效。 |
rapidFailsPerMinute | ASP.NET CORE应用承载进程( processPath)每分钟允许崩溃的次数,默认为10,超过此数量将不再试图重新启动它。 |
requestTimeout | 请求处理超时时间,默认为2分钟。 |
startupRetryCount | ASP.NET CORE应用承载进程启动重试次数,默认为2次。 |
startupTimeLimit | ASP.NET CORE应用承载进程启动超时时间(单位为秒),默认为120秒。 |
environmentVariables | 设置环境变量。 |
handlerSettings | 为ASP.NET CORE Core Module提供额外的配置。 |
asp.netcore部署系列一:发布到iis上
前言: 当构建一个ASP.NETCore应用程序并且计划将其运行在IIS中时,你会发现Core应用程序和之前版本的ASP.NET程序在IIS中的运行方式是完全不一样的。与ASP.NET时代不同,ASP.NETCore不再是由IIS工作进程(w3wp.exe)托管,而是使用自... 查看详情
又一篇centos7下的asp.netcore部署教程(代码片段)
原文:又一篇Centos7下的asp.netcore部署教程历程2个多月的学习,我终于从PHP转.Net开发了。虽然网上已经有很多关于asp.netcore在linux下的部署教程了,但我还是想写一篇,主要增强我自己的记忆。搭建的环境为Centos7+.netcore +nginx+mys... 查看详情
.netcore项目在iis中部署
本文实例环境及版本Win10、.NetCore3.1一、概述与ASP.NET时代不同,ASP.NETCore不再是由IIS工作进程(w3wp.exe)托管,而是使用自托管Web服务器(Kestrel)运行,IIS则是作为反向代理的角色转发请求到Kestrel不同端口的ASP.NETCore程序中... 查看详情
asp.netcore--.netcore3.1部署到iis
环境:win10.netcore3.1restfulapi1、下载运行时https://dotnet.microsoft.com/download/dotnet-core/current/runtime下载右手边这个,左边是桌面程序,右边是web,大家应该能看懂,下载完毕正常安装就行 查看详情
用nssm把.netcore部署至windows服务
为什么部署至WindowsServices在很多情况下,很少会把.NetCore项目部署至Windows服务中,特别是Asp.netCore就更少了。一般情况下,Asp.netCore会部署至linux服务器,或者部署至Windows的IIS中。但也不排除会有Asp.netCore部署至Windows服务中的情... 查看详情
无法在 ASP.NET Core 5.0 下的 IIS 中托管 CoreWcf
】无法在ASP.NETCore5.0下的IIS中托管CoreWcf【英文标题】:CannothostCoreWcfinIISunderASP.NETCore5.0【发布时间】:2021-09-1606:02:15【问题描述】:我尝试将我的WCFWeb服务从.NetFramework4.7.1迁移到.Net5.0。我使用nuggetCoreWcf并尝试在IIS上运行它。阅... 查看详情
asp.netcore部署手册:3.windows篇
“don'tworry”,部署ASP.NETCore应用可以和原来部署.NETFramework的ASP.NET应用一样的简单,还是“熟悉的配方,熟悉的味道”,甚至提供了更加便捷的Kestrel部署方式,下面主要介绍在windows平台下两种常用部署方式:方式一:Kestrel部... 查看详情
linux中以单容器部署nginx+asp.netcore
...转发请求到KestrelHttp服务器,本文将会实践将Nginx--->ASP.NETCore部署架构容器化的过程。 Nginx->ASP.NETCoe部署架构容器化 在Docker中部署Nginx--->ASP.NETCore有两种选择,第一种是在单容器内部署Nginx+ASP.NETCore,这是本文着 查看详情
asp.netcore部署手册:2.hyper-v虚拟机
为什么要把虚拟机纳入到ASP.NETCore部署手册中?在.NETFramework时期,我们只用将应用程序部署到Windows操作系统中,甚至是在测试阶段或演示阶段我们可以把应用程序部署在本机的IIS中即可。而如今对于跨平台的.NETCore而言,我们的... 查看详情
解决asp.netcore部署到iis,更新项目时"文件夹正在使用"错误
解决ASP.NETCore部署到IIS,更新项目时"文件夹正在使用"错误 查看详情
部署在 IIS 上的 ASP.NET Core 对长时间运行的请求返回 502 错误
】部署在IIS上的ASP.NETCore对长时间运行的请求返回502错误【英文标题】:ASP.NETCoredeployedonIISreturns502Errorforlongrunningrequests【发布时间】:2018-02-1915:41:28【问题描述】:我有一个ASP.NETCore2Web应用程序,它托管在WindowsServer2012上的IIS10... 查看详情
解决asp.netcore部署到iis,更新项目"另一个程序正在使用此文件,进程无法访问"(代码片段)
问题:部署到IIS上的ASP.NETCore项目,在更新的时候会进程占用的错误 初步解决方案:1,关闭应用程序池2,关闭网站3,更新项目缺点:网站没法访问,部署项目停的时间过长 查询官方文档后,官方给出的方案: 结合... 查看详情
先定一个小目标asp.netcore在iis上的托管运行
1.安装.NETCoreFramework 下载.netcore地址:官网地址2.InstallIIS在控制面板->程序与功能-》InternetInfomationServices3.站点部署 实例: https://github.com/aspnet/mvc 在IIS管理器,新建站点->物理路径Path:为项目的根目录。 网站绑... 查看详情
小5聊asp.netcore2.1基础之部署在iis上接口请求超时解决方法(代码片段)
由于项目业务需求,对于调用和请求接口A可能需要比较长的时候,比如10分钟,那么对于core默认2分钟的请求时间就不够用了 1、Core默认请求时间默认请求时间是2分钟2、Core在发布后自动生成web.config配置文件web.config... 查看详情
总结:利用asp.netcore日志进行生产环境下的错误排查(asp.netcoreversion2.2,用iis做服务器)(代码片段)
概述调试asp.netcore程序时,在输出窗口中,在输出来源选择“调试”或“xxx-ASP.NETCoreWeb服务器”时,可以看到类似“info:Microsoft.AspNetCore.Hosting.Internal.WebHost[2] Requestfinishedin285.6ms200text/css”这样的内容,这就是... 查看详情
解决asp.netcore部署到iis,更新项目"另一个程序正在使用此文件,进程无法访问"...
问题部署到IIS上的ASP.NETCore项目,在更新的时候会进程占用的错误解决思路初步解决方案:1,关闭应用程序池2,关闭网站3,更新项目缺点:网站没法访问,部署项目停的时间过长答案查询官方文档后... 查看详情
解决asp.netcore部署到iis,更新项目"另一个程序正在使用此文件,进程无法访问"...
问题部署到IIS上的ASP.NETCore项目,在更新的时候会进程占用的错误解决思路初步解决方案:1,关闭应用程序池2,关闭网站3,更新项目缺点:网站没法访问,部署项目停的时间过长答案查询官方文档后... 查看详情
解决asp.netcore部署到iis,更新项目"另一个程序正在使用此文件,进程无法访问"...
问题部署到IIS上的ASP.NETCore项目,在更新的时候会进程占用的错误解决思路初步解决方案:1,关闭应用程序池2,关闭网站3,更新项目缺点:网站没法访问,部署项目停的时间过长答案查询官方文档后... 查看详情