简介:面向C#开发者的WebApi服务示例,重点演示如何通过自托管模式构建不依赖IIS的服务,解决跨平台部署与微服务扩展中的环境依赖问题。压缩包共188个文件、约5.92MB,除cs源文件与csproj工程文件外,还包括较多dll动态库、xml文档、nupkg依赖包、pdb调试符号、config配置文件,以及项目依赖与运行环境配置等,覆盖编译、运行、调试与文档所需的主要工程素材。目前已有747人学习下载,适合希望摆脱Windows自带IIS束缚、尝试跨平台发布WebApi服务的.NET开发者。借助完整Demo,读者可深入理解自托管WebApi服务的启动、停止与生命周期管理,学习基于客户端-服务器模式的通信方案、RESTful接口设计、HTTP标准方法与JSON数据交换方式;同时可参考项目中轻量级Web服务器(如HttpListener或Kestrel)的集成思路,补全安全通信、身份验证与授权控制等扩展设计,为容器化部署或微服务架构落地提供可改造蓝本。整个资源目录从工程配置到核心代码排列清晰,既适合初学者对照学习,也方便开发者进行二次拓展。 我们搞.NET开发的,前几年一提WebApi,脑子里默认就是建个ASP.NET项目,然后右键发布到IIS上,接着去IIS管理器里建站点、配应用池,一套流程固定得很。但最近这几年,越来越多的项目开始把WebApi从IIS里抽出来,用自宿主(Self-Host)的方式跑,再让IIS在前面做一层反向代理。这个思路就是我们常说的“C#构建与IIS解耦的WebApi服务Demo”。
这篇东西我打算讲得细一点,把为什么解耦、解耦之后架构怎么变、Kestrel在里边扮演什么角色、以及IIS反向代理怎么配,全部串一遍。不管你是被领导要求把老项目迁出去,还是做上位机开发时想给Vue前端提供接口但不想装IIS,这篇都适合你。我会附上完整的Demo工程思路和部署步骤,保证你看完能直接照着落地。
1. 为什么要把WebApi从IIS里解耦出来
1.1 传统IIS托管模式到底有什么痛点
先聊痛点。IIS托管WebApi,最常见的问题是进程回收。IIS的应用池默认空闲超时是20分钟,超过这个时间没有请求,工作进程直接给你回收掉。等到下一个请求进来,IIS重新拉起进程,这个过程中所有的静态变量、内存缓存、后台定时任务,全部归零。
做硬件对接、上位机通信这类项目时,这个特性非常致命。比如我用C#写了一个扫码枪服务,扫码枪通过串口或网口持续报送数据,服务端在内存里缓存了最近收到的数据包。IIS一回收,缓存清空,上位机那边的一个简单的“查询当前批次数据”请求,拿到的却是空结果,排查半天才发现是进程被回收了。
另外一个痛点就是部署环境。早些年IIS只支持Windows,想部署到Linux服务器上根本没门。虽然现在.NET Framework也支持Windows Container了,但那种灵活性和裸金属Linux上跑一个Kestrel进程比起来,还是差了很多。
还有一点,是IIS作为托管宿主的时候,应用程序和服务器环境是强耦合的。IIS管理器里几十个配置项,什么应用程序池、管道模式、身份验证、URL重写,任何一个配置错了,服务就起不来。出了问题,还得一边查Windows事件日志,一边查IIS日志,两边来回折腾。
1.2 解耦之后的服务架构长什么样
解耦之后的架构,核心思想就是把“Web服务器”和“应用程序”彻底分开。应用程序自己充当一个独立的进程,监听端口,处理HTTP请求,这就是自宿主模式。
在ASP.NET Core时代,这个自宿主进程默认就是Kestrel。Kestrel是一个跨平台的、基于libuv(后来换成了自研的Socket基础设施)的HTTP服务器,它内嵌在应用程序里。发布出来的程序,本质上就是一个控制台程序,跑起来之后开始监听端口,跟IIS毫无关系。
这个架构下,我通常这样部署:
- WebApi服务(Kestrel自宿主):监听一个内网端口,比如5000。
- IIS:只扮演反向代理,把公网或局域网进来的请求转发到5000端口。
- 前端(Vue等):请求直接走IIS的80/443端口,通过反向代理转发到后端的5000。
这样一拆,好处非常明显。IIS那边再出什么应用池回收、站点重启的问题,后端服务完全不受影响。反过来,后端服务需要更新版本,只要把DLL拷贝进去,然后重启进程就行,IIS连动都不用动。
2. 硬核拆解:Kestrel和IIS在这套架构里的分工
2.1 Kestrel自宿主的技术原理
很多从.NET Framework时代过来的人,第一次接触Kestrel会觉得有点懵。这里我打个比方。
传统的IIS托管模式,就好像你租了一个商场的柜台。商场(IIS)负责开门关门、打扫卫生、安保巡逻。你的柜台(WebApi)只管卖东西,其他一律不用操心。但问题在于,商场一旦说“我要关门改造20分钟”,你这个柜台也得跟着停业。
而Kestrel自宿主呢,就相当于你自己租了个临街店铺,自己拉电闸、自己装门锁、自己做安保。你的生存完全自理,商场管不着你。代价就是你得自己处理很多之前由IIS承担的杂事。
Kestrel在做这个“临街店铺”的时候,有几个技术点是必须清楚的。
第一个是端口监听。Kestrel通过UseUrls或者配置文件里的applicationUrl参数来设置监听地址。比如我要监听本机的5000端口,就设置http://0.0.0.0:5000。0.0.0.0是必须的,表示监听所有网络接口,不然外部机器根本访问不到。
第二个是请求处理管道。ASP.NET Core的中间件管道(Middleware Pipeline)是完全由Kestrel来驱动的。请求到达Kestrel之后,按照你在Startup.cs(或者.NET 6+的Program.cs)里注册的中间件顺序依次处理。这个管道模型和IIS的管道模型不一样,但逻辑上更清晰——从静态文件到认证授权,所有的事情都在应用程序进程内解决,不需要经过IIS的那些模块。
第三个是进程生命周期管理。Kestrel进程是一个独立进程,所以你需要一个守护方案。Windows下可以用Windows Service,Linux下可以用systemd,或者用Docker方式跑。这个比IIS省心的是,你的服务进程完全在你的掌控范围内,你不需要去理解IIS那一大套工作进程和回收机制。
2.2 IIS在这里的新角色:反向代理
解耦之后IIS变成一个反向代理,但很多人其实没弄清这里的关键。我一直跟同事讲,反向代理的核心工作是“转发”,而不是“托管”。在IIS的世界里,做反向代理需要两个模块配合,缺一不可。
第一个是Application Request Routing(ARR)。这个模块主要提供代理能力,它能把请求转发到指定的后端服务器地址。ARR的安装包可以直接从微软官网下载,装好之后在IIS管理器的根节点会多出一个“Server Farm”图标。
第二个是URL Rewrite。这个模块负责做地址重写,它的作用是把进来的请求URL按照规则重写。比如说前端请求的是http://www.example.com/api/login,URL Rewrite把路径里的/api提取出来,重写成http://localhost:5000/api/login,然后交给ARR去转发。
这两个模块的工作顺序是这样的:请求先进入IIS网站的主机头,到达URL Rewrite模块,URL Rewrite规则判断这个URL是不是需要代理;如果需要,就重写URL并把这个请求交给ARR;ARR根据服务器场的配置,把请求转发到后端的Kestrel进程。
这套反向代理模式的好处在于,IIS仍然可以处理静态文件、HTTPS证书、域名绑定这些“边缘”事务,动态逻辑则在Kestrel进程里处理。换句话说,IIS变成了一个端口守卫和证书管家,业务进程的负担被完全解放了。
3. 实操落地:一步步搭建解耦的WebApi服务
3.1 创建ASP.NET Core WebApi项目(手把手)
这部分我假设你用的是Visual Studio 2022,或者直接用命令行。
用命令行创建项目是最快的。打开终端,执行:
dotnet new webapi -n DecoupledWebApi cd DecoupledWebApi这里-n参数指定项目名。dotnet new webapi模板生成的时候是空壳子,带一个默认的天气接口,我们直接改造成自己的。
如果你坚持用VS2022,操作路径是这样的:新建项目 -> 选择“ASP.NET Core Web API”模板 -> 项目名称填DecoupledWebApi-> 框架选.NET 8.0(或者.NET 6.0,看你的环境),然后“身份验证类型”选“无”,把“配置HTTPS”勾选去掉——因为这个Demo跑在内网,用HTTP就够了。
项目创建好之后,打开Program.cs,你会看到:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); var app = builder.Build(); app.UseAuthorization(); app.MapControllers(); app.Run();这是一个非常精简的纯Kestrel宿主管道。我们在这个基础上加两个接口——一个上传文件接口、一个下载文件接口。
新建一个FileController.cs文件,代码如下:
using Microsoft.AspNetCore.Mvc; [ApiController] [Route("api/[controller]")] public class FileController : ControllerBase { private readonly IWebHostEnvironment _env; public FileController(IWebHostEnvironment env) { _env = env; } [HttpPost("upload")] public async Task<IActionResult> Upload(IFormFile file) { if (file == null || file.Length == 0) { return BadRequest("文件不能为空"); } var uploadPath = Path.Combine(_env.ContentRootPath, "Uploads"); if (!Directory.Exists(uploadPath)) { Directory.CreateDirectory(uploadPath); } var filePath = Path.Combine(uploadPath, file.FileName); using (var stream = new FileStream(filePath, FileMode.Create)) { await file.CopyToAsync(stream); } return Ok(new { fileName = file.FileName, size = file.Length }); } [HttpGet("download/{fileName}")] public async Task<IActionResult> Download(string fileName) { var filePath = Path.Combine(_env.ContentRootPath, "Uploads", fileName); if (!System.IO.File.Exists(filePath)) { return NotFound("文件不存在"); } var bytes = await System.IO.File.ReadAllBytesAsync(filePath); return File(bytes, "application/octet-stream", fileName); } }这个接口在后面的前后端联调中很有用,特别是“如何保持文件名不变”这件事,我们用return File(bytes, "application/octet-stream", fileName)返回,fileName参数直接指定下载文件名,浏览器会严格按照这个名字来做,不会出现把blob当文件名的情况。
3.2 修改监听端口和启动设置
Kestrel默认端口是5000,但我习惯在开发环境用5200、生产环境用5300,这样区分度比较高。
在appsettings.json里加一个节点:
{ "Urls": "http://0.0.0.0:5200", "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" }如果你用的是.NET 6及以上版本,Kestrel会自动读取Urls这个配置节点。用0.0.0.0而不是localhost或者127.0.0.1,原因很简单——localhost只监听本机回环地址,外部设备(比如手机、另一台电脑)是访问不到你的服务的。
注意:
AllowedHosts设置为*表示允许任何Host请求进入,开发环境无所谓,生产环境如果域名固定,建议改成你的域名,避免被扫描器用IP地址直接访问。
另外,如果你项目中有Properties/launchSettings.json,这里面的applicationUrl优先级比较高。它是给开发调试用的,VS按F5启动时读的是这个文件。所以你也需要同步修改这个文件里的applicationUrl为http://0.0.0.0:5200。
3.3 发布与直接运行
发布命令很简单:
dotnet publish -c Release -o ./publish发布完成之后,进入publish文件夹,你会看到一堆DLL文件、一个decoupledwebapi.dll、一个web.config。这个web.config是给IIS做反向代理用的(后面细说)。
现在直接在终端里运行:
dotnet DecoupledWebApi.dll你会发现它就是一个控制台程序,打印出监听地址之后,服务就起来了。你可以用浏览器访问http://localhost:5200/api/file/download/test.txt试试,Kestrel全程自己处理,没有IIS参与。
4. IIS反向代理配置:让IIS做一道门卫
4.1 安装ARR和URL Rewrite模块
IIS要配置反向代理,首先必须安装ARR(Application Request Routing)和URL Rewrite这两个模块。IIS默认是不带这两个的,得单独下载。
下载地址我直接给两条路,避免你走弯路:
- URL Rewrite:在IIS管理器左边的连接树里点根节点(服务器级别),找到“管理”分组下的“功能视图”,如果没有URL Rewrite,进入微软官网搜索“IIS URL Rewrite Module”下载。
- ARR:同样在IIS根节点,如果你没有看到“服务器场”图标,说明ARR未安装。微软官网搜索“IIS Application Request Routing”下载安装。
安装顺序没有要求,两个都装上就行。装完之后如果你看到IIS根节点下多了“服务器场”和“URL重写”这两个图标,说明模块已经就位。
4.2 创建网站和配置服务器场
首先给这个反代创建一个独立的站点。
打开IIS管理器,右键“网站”->“添加网站”。站点名称填DecoupledWebApiProxy,物理路径随便指一个空文件夹(比如C:\WebSites\DecoupledWebApiProxy),绑定端口填8080——你可以用80端口,但容易跟其他站点冲突,开发环境用8080更稳当。
然后到IIS根节点,点击“服务器场”,右键“创建服务器场”。名称填DecoupledServerFarm,然后在“可用服务器”里添加:服务器地址填localhost或者127.0.0.1,端口填5200,HTTP等设置不用动,按照向导完成。
创建完成后,ARR会弹出提示问你要不要创建一个URL重写规则,它默认会生成一条“把所有请求都转发到服务器场”的规则。这里的规则我们需要自定义,所以暂时不要选“创建规则”,后面手动配。
4.3 编写URL Rewrite规则(关键中的关键)
现在进入到“URL重写”配置页面。找到你刚才创建的那个站点(比如DecoupledWebApiProxy),然后双击“URL重写”。
在右侧操作面板,点击“添加规则”,选“空白规则”。填入以下配置。
规则名称填ProxyToKestrel。
匹配URL部分:
- “请求的 URL”选择“与模式匹配”
- “使用”选“正则表达式”
- “模式”填
(.*)
条件部分:这个规则默认是所有请求都匹配,不需要额外添加条件。注意,如果你想限制只有/api路径的请求做代理,可以设置模式为^api/(.*)$。
服务器变量:不需要设置。
操作部分:
- “操作类型”选“重写”
- “重写为”填
http://DecoupledServerFarm/{R:1} - “停止规则重写”勾选“是”
配好之后点“应用”,规则立即生效。
这里的原理是:当请求地址是http://localhost:8080/api/file/upload时,正则表达式(.*)捕获整个路径api/file/upload,然后重写到http://DecoupledServerFarm/api/file/upload。DecoupledServerFarm是之前建的服务器场名称,ARR会自动在这个服务器场的所有服务器之间做负载均衡(这里只有一台,就转发到localhost:5200)。
注意:
重写为字段里的DecoupledServerFarm不要加端口号,这是引用服务器场的名字。如果你不想用服务器场,也可以直接写http://localhost:5200/{R:1},效果一样,走的是URL Rewrite模块直接转发,但用服务器场的好处是可以配置健康检查、会话保持等高级功能。
配置完之后,在浏览器访问http://localhost:8080/api/file/upload,你看到的不再是IIS的欢迎页,而是Kestrel返回的404(因为GET请求不支持上传),说明IIS已经把请求转发到Kestrel了。
4.4 通过web.config直接配置反代(备选方案)
有时候你不想配服务器场,觉得有点重。那可以直接在站点的web.config里写规则。其实IIS的“URL重写”界面配置最终也是落到web.config文件里的,所以你完全可以手动编辑。
在站点物理路径下新建一个web.config文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?> <configuration> <system.webServer> <rewrite> <rules> <rule name="ProxyToKestrel" stopProcessing="true"> <match url="(.*)" /> <action type="Rewrite" url="http://localhost:5200/{R:1}" /> </rule> </rules> </rewrite> </system.webServer> </configuration>这个配置的意思是:所有匹配(.*)的URL,全部重写到http://localhost:5200/路径下。{R:1}是正则表达式第一个捕获组的引用,也就是原始请求的完整路径。
提示:如果你要代理的站点和Kestrel监听的端口在同一个机器上,用
localhost就行。如果Kestrel跑在另一台服务器上,把localhost:5200改成那台服务器的IP和端口。这里要注意跨服务器的防火墙设置,确保反向代理服务器(IIS所在机器)能访问后端Kestrel所在机器的5200端口。
5. 和上位机联动的实战经验:扫码枪、文件下载与Vue对接
5.1 扫码枪和C#的配合
这个Demo虽然是一个WebApi服务,但它的实际场景往往不是单纯的互联网应用,更多是给上位机提供服务接口。比如你有个C#写的上位机程序,需要把扫码枪扫描到的数据通过HTTP请求提交到WebApi服务,怎么做?
我们的做法是在上位机侧写一个扫码枪事件处理器。扫码枪通过串口或者USB模拟键盘输入,当有扫码事件发生时,C#程序捕获到完整的扫码字符串,然后构造一个POST请求,发到WebApi的接口。
这里的关键点在于,扫码枪的输入是有分隔符的。如果你用串口接收,你需要在代码里判断帧头和帧尾,把完整的一包数据拼出来。如果你用USB模拟键盘模式,那么直接用一个全局键盘钩子捕获即可,但要注意扫描速度,很多扫码枪一次扫描会触发多个键盘事件,你需要把所有字符收集起来直到遇到回车键。
上位机收集到扫码数据后,调用我们Demo里的接口,类似POST http://localhost:8080/api/scan/receive,传一个JSON字符串,WebApi接收到之后,把数据写入数据库或者内存队列。因为WebApi已经在Kestrel进程里独立运行,不依赖IIS,上位机的请求即使再频繁,也不会触发IIS进程回收导致数据丢失。
5.2 Vue前端与后端接口联调
做Vue前端联调的时候,解耦架构的好处更明显。前端开发人员只需要知道WebApi的地址是http://localhost:8080,然后所有请求都走这个域名就行。代理规则由IIS统一管理,后端服务的内部地址(http://localhost:5200)完全对前端透明。
前端上传文件的代码,需要注意FormData的传参名要和后端[FromForm]的参数名字一致。举个例子:
const formData = new FormData(); formData.append('file', file); axios.post('/api/file/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' } });这里append的第一个参数file,必须和后端接口的参数名IFormFile file对应上,否则后端收到的是null。
前端下载文件时,也有一个经典问题——文件名保持。很多人在请求下载接口时直接用axios,然后拿到一个blob,用URL.createObjectURL创建地址下载,但发现下载下来的文件是一个随机字符串。解决方法是,从后端返回的响应头里拿Content-Disposition字段,解析出filename,然后手动指定:
const disposition = response.headers['content-disposition']; let fileName = 'download.txt'; if (disposition) { const match = disposition.match(/filename="?([^"]+)"?/); if (match) fileName = match[1]; } const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement('a'); link.href = url; link.setAttribute('download', fileName); document.body.appendChild(link); link.click();这个方法百试百灵,关键是后端的return File(bytes, "application/octet-stream", fileName)已经设置了正确的响应头,前端解析Content-Disposition就能保证文件名不变。
5.3 隐藏IIS响应头的小技巧
解耦部署之后,前端通过IIS代理访问,响应头里会带有Server: Microsoft-IIS/10.0这样的服务器版本信息。做硬件对接时,很多客户对安全扫描很敏感,这个版本信息暴露在外网怎么看都不太舒服,最好去掉。
去掉IIS响应头的方法是,在IIS的web.config里加上:
<system.webServer> <httpProtocol> <customHeaders> <remove name="X-Powered-By" /> </customHeaders> </httpProtocol> <security> <requestFiltering removeServerHeader="true" /> </security> </system.webServer>其中customHeaders里的<remove name="X-Powered-By" />可以去掉ASP.NET默认添加的X-Powered-By响应头。而requestFiltering removeServerHeader="true"可以让IIS不发送Server响应头。
注意:
removeServerHeader属性需要IIS 7.5及以上版本才支持。如果你还在用IIS 7.0,这个属性不生效,得用URL Rewrite的serverVariables去手动删除。
6. 常见问题与排查技巧实录
6.1 访问站点提示503 Service Unavailable
这是最常见的坑。IIS代理模式下,ARR转发目标不可用时会报503。先确认Kestrel进程是否在监听5200端口。
排查方法:在IIS所在的机器上打开浏览器访问http://localhost:5200/api/file/download/test.txt,如果能正常返回,说明后端是通的;如果不能,说明Kestrel没起来或者防火墙拦截了。
如果localhost能访问但通过IIS代理之后报503,那大概率是ARR到服务器场的转发问题。在IIS根节点点开“服务器场”,选中DecoupledServerFarm,双击“代理”,检查“HTTP端口”是不是填写的5200,还可在右侧面板点“重启”应用健康检查。
6.2 响应头里出现两条Server信息
那多半是你还保留了旧版本的静态文件服务器。注意一个细节:解耦之后IIS和Kestrel都在处理HTTP请求,如果Kestrel也开启了Server头,而IIS没来得及移除,响应头就会叠加。解决方法是同时关掉Kestrel和IIS的Server头。
Kestrel关闭Server头的方法是在Program.cs里配置:
var builder = WebApplication.CreateBuilder(args); builder.WebHost.ConfigureKestrel(options => { options.AddServerHeader = false; });然后IIS侧按5.3的方法移除自己的Server头,这样两层都干净了。
6.3 上传大文件失败
默认情况下Kestrel的请求体大小限制是30MB左右,IIS的也有限制。做上位机上传日志、相机拍照图片的场景,很容易就超出这个限制。
Kestrel侧修改限制,在Program.cs里:
builder.Services.Configure<FormOptions>(options => { options.ValueLengthLimit = int.MaxValue; options.MultipartBodyLengthLimit = int.MaxValue; });IIS侧的限制在web.config里设置:
<system.webServer> <security> <requestFiltering> <requestLimits maxAllowedContentLength="524288000" /> </requestFiltering> </security> </system.webServer>这里面maxAllowedContentLength的单位是字节,524288000就是500MB。两边的限制都要改,否则哪一个先拦截都会导致上传失败。
特别说一句,MultipartBodyLengthLimit默认是128MB,这个值经常被忽略。很多人在IIS那边改了限制,发现大文件还是传不上去,其实就是Kestrel这边卡住了。
6.4 前端请求跨域(CORS)问题
解耦模式下,IIS代理的域名和Kestrel自宿主的域名不一样,如果前端直接用axios请求Kestrel的5200端口,必然触发跨域。虽然在我们的方案里前端都走IIS的8080端口,但在开发阶段,很多前端工程师习惯直连后端。
为了解决联调阶段的跨域问题,后端需要启用CORS。在Program.cs里加上:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddCors(options => { options.AddPolicy("AllowAll", policy => { policy.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader(); }); }); // ... app.UseCors("AllowAll");注意:生产环境不建议用
AllowAnyOrigin,这等于允许任意网站调用你的接口。如果接口只在内部用,建议配置为WithOrigins("http://localhost:8080", "http://192.168.1.100")等具体的来源地址。
6.5 发布之后配置文件没生效
不少人会把appsettings.json遗忘在发布目录之外。dotnet publish命令默认会把appsettings.json复制到输出目录,但如果你改了文件内容却没重新发布,运行的时候读的还是旧的配置。
判断方法:在运行目录下打开DecoupledWebApi.dll旁边的appsettings.json,看里面的Urls配置是不是想要的端口;如果不对,手动改一下再重启服务就行——这是自宿主模式一个特有的便利,不用重新编译,改完配置文件直接重启进程就生效了。
7. 实际操作中的几点体会
写到这里,关于这个方案我想再做几点补充。
在硬件测试、上位机开发这个圈子里,解耦WebApi的思路越来越流行。我们之前一套设备机箱里的工控机,运行着C#写的上位机软件,同时又跑着一个WebApi给MES系统上报数据。以前这个WebApi部署在IIS里,用户改完配置,点了一下“回收应用程序池”,整个MES通信中断了十几秒,产线报警。后来改成Kestrel自宿主+Windows服务注册,重启时间和MES断线问题就再也没出现过了。
第二个体会是关于部署工具的选型。如果你面向的生产环境是Windows Server,我特别推荐用Windows Service方式注册Kestrel。在发布目录里执行一行命令就能注册:
sc create DecoupledWebApi binPath= "C:\path\to\publish\DecoupledWebApi.exe" start= auto这样开机自启、异常重启都由Windows服务控制,控制台程序挂掉还能自动恢复,运维省心太多了。
第三个体会是日志。自宿主模式的日志默认打到哪里,很多人搞不清。Kestrel默认是写到控制台的,如果你注册成了Windows服务跑,控制台窗口根本不存在,日志就丢了。我们实际项目里都是接Serilog,输出到文件或者数据库,这样出了问题才能有据可查。这个点放在最后说,是因为我见过太多人解耦之后说“服务挂了我都不知道为什么”,其实就是日志没配好。
以上就是我从传统IIS托管模式迁移到Kestrel自宿主+反向代理模式的全过程。这套架构不是银弹,但确实解决了很多实际的部署和维护问题。如果你也在做C#相关的服务端开发,手里有硬件设备要对接,强烈建议花一天时间,照着Demo把流程跑一遍,你会对“解耦”这两个字的体会完全不一样。
本文还有配套的精品资源,点击获取