在基于传统的.NET Framework的Asp.Net Mvc的时候,本地开发环境中可以在IIS中建立一个站点,可以直接把站点的目录指向asp.net mvc的项目的根目录。然后build一下就可以在浏览器里面刷新到最新的修改了,也可以附加到w3wp的进程进行调试。但是在开发基于.Net Core的Asp.Net Core项目的时候,这样的做法已经无法满足我们的需要了:
- 更改完代码build一下,无需部署即可在浏览器得到最新的更改。
- 附加到进程调试。
Asp.Net Core的项目需要先Pubilsh一下才能部署到IIS,而且中间需要一个AspNetCoreModule的模块来中转一下。这主要是因为Asp.Net Core的项目本质上来说是一个Console类型的项目,而且它自带了Kestrel组件来监听HTTP请求。这就使得IIS不再负责Asp.Net Core的运行了,而是作为一个反向代理来使用的,如下图所示:
那么如何优雅在满足上面提到的2点需要呢?本文源代码位于(https://github.com/linianhui/aspnetcore.example/tree/master/src/dotnet.watch.run)
dotnet watch
dotnet watch 属于dotnet cli tool里面的一部分功能,其用途在于扩充dotnet cli的命令,为它们添加一个监视的功能,即在使用cli运行dotnet core的项目的时候,当你修改了项目的源代码,那么save一下源码,即可刷新得到最新的更改。比如我们用 dotnet run 运行了我们的一个Asp.Net Core项目,想要修改的话就需要先停止运行,然后修改代码,再一次运行才能看到结果。而如果使用了 dotnet watch run 来运行的话则省去了停止运行的过程,直接修改保存即可。享受到这样的好处只需再你的csproj文件中增加一个引用即可。
<ItemGroup> <DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="2.0.0" /> </ItemGroup>
当我修改了ValuesController.cs文件的内容的时候,watch会自动退出当前正在运行的进程,然后再一次启动它。是不是很方便呢?
IIS中的 dotnet watch
如何把Asp.Net Core部署到IIS这里就不解释了,只贴一下我写的Cake部署脚本:
1 #addin "Cake.IIS" 2 #addin "Cake.Hosts" 3 #addin "Cake.Powershell" 4 5 var target = Argument("target", "default"); 6 7 var rootPath = "./"; 8 var solution = rootPath + "aspnetcore.example.sln"; 9 var srcProjectPath = rootPath + "src/"; 10 11 var websites = new []{ 12 new { 13 host = "dotnet.watch.run", 14 path = srcProjectPath + "dotnet.watch.run/", 15 } 16 }; 17 18 Task("deploy-iis") 19 .Description("部署到iis") 20 .DoesForEach(websites, (website) => 21 { 22 AddHostsRecord("127.0.0.1", website.host); 23 24 DeleteSite(website.host); 25 26 CreateWebsite(new WebsiteSettings 27 { 28 Name = website.host, 29 Binding = IISBindings.Http.SetHostName(website.host) 30 .SetIpAddress("*") 31 .SetPort(80), 32 ServerAutoStart = true, 33 PhysicalDirectory = website.path, 34 ApplicationPool = new ApplicationPoolSettings 35 { 36 Name = website.host, 37 IdentityType = IdentityType.LocalSystem, 38 MaxProcesses = 1, 39 ManagedRuntimeVersion = "v4.0" 40 } 41 }); 42 }); 43 44 Task("open-browser") 45 .Description("打开浏览器") 46 .Does(() => 47 { 48 StartPowershellScript("Start-Process", args => 49 { 50 var urls = ""; 51 foreach(var website in websites){ 52 urls += ",'http://" + website.host + "/'"; 53 } 54 55 args.Append("chrome.exe") 56 .Append("'-incognito'") 57 .Append(urls); 58 }); 59 }); 60 61 62 /// default task 63 Task("default") 64 .Description("默认操作") 65 .IsDependentOn("deploy-iis") 66 .IsDependentOn("open-browser"); 67 68 RunTarget(target);
由于我们要使用dotnet watch这个命令,所以在部署的时候并没有对Asp.Net Core的项目进行Build和Publish,而是直接指向了其源代码目录。那么在哪里让IIS执行dotnet watch呢?答案是web.config里面:
1 <?xml version="1.0" encoding="utf-8"?> 2 <configuration> 3 <system.webServer> 4 <handlers> 5 <remove name="aspNetCore" /> 6 <add name="aspNetCore" 7 path="*" 8 verb="*" 9 modules="AspNetCoreModule" 10 resourceType="Unspecified" /> 11 </handlers> 12 <aspNetCore processPath="dotnet" 13 arguments="watch run" 14 stdoutLogEnabled="true" 15 shutdownTimeLimit="2" 16 stdoutLogFile=".\" /> 17 </system.webServer> 18 </configuration>
其中重点在于aspnetcore节点的processPath="dotnet"和arguments="watch run"。这个配置节点是供AspNetCoreModule使用的,其详细的配置参数请移步这里:https://docs.microsoft.com/en-us/aspnet/core/hosting/aspnet-core-module。这样在IIS中访问的时候,AspNetCoreModule就会使用 dotnet watch run来运行我们的项目。就可以实现编辑代码->保存->在浏览器中刷新就可以直接看到结果了!。
使用附加到进程调试IIS中的Asp.Net Core
由于Asp.Net Core是单独运行的Console应用,所以调试部署在IIS中的Asp.Net Core的时候就不是像之前那样附加到w3wp进程了,而是运行项目的dotnet进程(由dotnet watch run运行起来的嘛)。
。。。。。。一下子有四个dotnet的进程,到底是哪一个呢?我也不知道,,,查了半天也没查出来原因,可以确定是受的arguments="watch run"影响:
- arguments="watch run":4个。
- arguments="run":2个。
- arguments=".\bin\debug\netcoreapp2.0\Dotnet.Watch.Run.dll":1个。
有了解这块的麻烦告知,谢谢!
参考
本文源代码:https://github.com/linianhui/aspnetcore.example/tree/master/src/dotnet.watch.run
AspNetCoreModule:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/aspnet-core-module?tabs=aspnetcore2x
AspNetCoreModule Config:https://docs.microsoft.com/en-us/aspnet/core/hosting/aspnet-core-module
Kertrel:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?tabs=aspnetcore2x
dotnet watch:https://docs.microsoft.com/en-us/aspnet/core/tutorials/dotnet-watch