佳佳的博客
Menu
首页
《.NET Core 实战》 [No.326~329] Web 主机配置
Posted by
佳佳
on 2020-04-07
IT
C#
.NET Core
《.NET Core 实战》
读书笔记
<!-- # 《.NET Core 实战》 [No.326~329] Web 主机配置 --> <!-- dotnet-core-web-host-config --> ## 默认配置 *ASP.NET Core Web 应用程序* 项目创建时,已经提供了一些默认配置。 随着版本的升级,创建 *WebHost* 的方式也一直在更新。 *.NET Core 1.1* 时默认的写法如下: ```csharp public static void Main(string[] args) { var host = new WebHostBuilder() .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup<Startup>() .UseApplicationInsights() .Build(); host.Run(); } ``` 在 *.NET Core 2.1* 中则改成了使用 `WebHost` 静态类封装了创建 `WebHostBuilder` 的过程。 ```csharp public static void Main(string[] args) { CreateWebHostBuilder(args).Build().Run(); } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>(); ``` *WebHost.CreateDefaultBuilder* 方法使用如下的默认配置来创建 Web 主机(摘自其方法的备注): > The following defaults are applied to the returned Microsoft.AspNetCore.Hosting.WebHostBuilder: > - use Kestrel as the web server and configure it using the application's configuration providers, > 使用内置的 Kestrel 服务器组件 > - set the Microsoft.AspNetCore.Hosting.IHostingEnvironment.ContentRootPath to the result of System.IO.Directory.GetCurrentDirectory, > 将应用程序的当前目录作为 Web 内容的根目录 > - load Microsoft.Extensions.Configuration.IConfiguration from 'appsettings.json' and 'appsettings.[Microsoft.AspNetCore.Hosting.IHostingEnvironment.EnvironmentName].json', > 从 *appsettings.json* 和 *appsettings.{启动环境}.json* 文件加载配置 > - load Microsoft.Extensions.Configuration.IConfiguration from User Secrets when Microsoft.AspNetCore.Hosting.IHostingEnvironment.EnvironmentName is 'Development' using the entry assembly, > 当启动环境为 *Development* 时从 *User Secrets*([用户机密][3]) 加载配置 > - load Microsoft.Extensions.Configuration.IConfiguration from environment variables, > 从环境变量加载配置 > - load Microsoft.Extensions.Configuration.IConfiguration from supplied command line args, > 从命令行参数加载配置 > - configures the Microsoft.Extensions.Logging.ILoggerFactory to log to the console and debug output, > 配置日志输出到命令行窗口和调试窗口 > - enables IIS integration, > 启用 IIS 交互(IIS 将作为反向代理端,将 HTTP 请求转发到 Web 应用程序) > - and enables the ability for frameworks to bind their options to their default configuration sections. 在 *.NET Core 3.1* 中则改成使用 `Host` 静态类来实现,其默认代码如下: ```csharp public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); ``` *Host.CreateDefaultBuilder* 方法使用如下的默认配置来创建 Web 主机(摘自其方法备注): > The following defaults are applied to the returned Microsoft.Extensions.Hosting.HostBuilder: > - set the Microsoft.Extensions.Hosting.IHostEnvironment.ContentRootPath to the result of System.IO.Directory.GetCurrentDirectory > - load host Microsoft.Extensions.Configuration.IConfiguration from "DOTNET_" prefixed environment variables > 从 *DOTNET_* 前缀的环境变量加载主机配置 > - load host Microsoft.Extensions.Configuration.IConfiguration from supplied command line args > - load app Microsoft.Extensions.Configuration.IConfiguration from 'appsettings.json' and 'appsettings.[Microsoft.Extensions.Hosting.IHostEnvironment.EnvironmentName].json' > - load app Microsoft.Extensions.Configuration.IConfiguration from User Secrets when Microsoft.Extensions.Hosting.IHostEnvironment.EnvironmentName is 'Development' using the entry assembly > - load app Microsoft.Extensions.Configuration.IConfiguration from environment variables > - load app Microsoft.Extensions.Configuration.IConfiguration from supplied command line args > - configure the Microsoft.Extensions.Logging.ILoggerFactory to log to the console, debug, and event source output > - enables scope validation on the dependency injection container when Microsoft.Extensions.Hosting.IHostEnvironment.EnvironmentName is 'Development' > 当启动环境为 *Development* 时在依赖注入容器上启用 [作用域验证][4] 相比 *.NET Core 2.1* 多了两项: - 从 *DOTNET_* 前缀的环境变量加载配置 ASP.NET Core Web 应用程序默认的环境变量是 *ASPNETCORE_* 前缀的,这两个前缀倒是不知道有什么区别。 - 当启动环境为 *Development* 时在依赖注入容器上启用 [作用域验证][4] 若在程序的启动过程中(如 *StartUp.Configure*)解析 *Scoped* 生命周期的服务,运行时就会报 *InvalidOperationException* 异常。 > System.InvalidOperationException:“Cannot resolve scoped service 'WebApplication1.ConcreteA' from root provider.” 之所以会引发上面的异常,原因在于使用 *Scoped* 生命周期时,正常的作用域是一次 HTTP 请求,请求结束时会释放掉实例。而在 启动过程 的 *root provider* 中解析服务时,其生命周期一般相当于整个 Application 的生命周期,这会造成资源的浪费,特别是当使用数据库链接等资源的时候。 一种解决方法是在启动时禁用 [作用域验证][4] : ```csharp public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseDefaultServiceProvider(options => options.ValidateScopes = false) .UseStartup<Startup>(); ``` 上面的方法并不好,只是不做验证,并没有解决资源占用问题。最好是手动指定一个 *Scope* ,在指定的 *Scope* 结束时释放资源(摘自 [StackOverflow][2])。 ```csharp // Create a new IServiceScope that can be used to resolve scoped services. using (var scope = app.ApplicationServices.CreateScope()) { // resolve the services within this scope ConcreteA A = scope.ServiceProvider.GetRequiredService<ConcreteA>(); //ConcreteA instance and injected ConcreteB are used in the same scope //do something A.Run(); } //both will be properly disposed of here when they both got out of scope. ``` ## 配置 URL 指定 URL 的方法有很多种,比较常用的有以下三种: 1. 调用 *UseUrls* 方法 *UseUrls* 方法支持多个参数。 ```csharp WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>() .UseUrls("http://localhost:6500", "http://localhost:7000", "http://*:7500") .Build() .Run(); ``` 在 *APS.NET Core 3.1* 中配置方法如下: ```csharp public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .UseDefaultServiceProvider(options => options.ValidateScopes = false) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); webBuilder.UseUrls("http://localhost:6500", "http://localhost:7000", "http://*:7500"); }); ``` 2. 调用 *UseSetting* 方法 监听多个端口时,使用半角分号 `;` 分隔。 ```csharp WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>() .UseSetting(WebHostDefaults.ServerUrlsKey, "http://localhost:8990;http://localhost:46133") .Build() .Run(); ``` 在 *APS.NET Core 3.1* 中配置方法如下: ```csharp public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .UseDefaultServiceProvider(options => options.ValidateScopes = false) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); webBuilder.UseSetting(WebHostDefaults.ServerUrlsKey, "http://localhost:8990;http://localhost:46133"); }); ``` 3. 通过配置文件 在 *ASP.NET Core 2.1* 中首先要添加 *json* 文件,假设名为 *host.json* 。 ```json { "urls": "http://localhost:3600;http://*:8080" } ``` 然后修改 *Main* 方法: ```csharp var builder = WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>(); var config = new ConfigurationBuilder().SetBasePath(builder.GetSetting(WebHostDefaults.ContentRootKey)) .AddJsonFile("host.json"); builder.UseConfiguration(config.Build()); builder.Build().Run(); ``` 这里我有个感觉比较疑惑的地方,上面的 *urls* 如果放在 *appsettings.json* 文件中并没有默认就被加载。按照上面一节中对 *WebHost.CreateDefaultBuilde* 方法的描述,*appsettings.json* 应该是会被默认加载的才对。 [StackOverflow][5] 上也有一个类似的问题,可惜回答中只有一个通过配置 *Kestrel* 来设置 URL 的方式,而且貌似只支持设置一个端口。 ```json "Kestrel": { "EndPoints": { "Http": { "Url": "http://localhost:5000" } } } ``` 对应的通过代码设置 *Kestrel* 的方式如下(摘自 [StackOverflow][6]): ```csharp WebHost.CreateDefaultBuilder(args) .UseKestrel(options => { options.Listen(IPAddress.Loopback, 5000); // http:localhost:5000 options.Listen(IPAddress.Any, 80); // http:*:80 options.Listen(IPAddress.Loopback, 443, listenOptions => { listenOptions.UseHttps("certificate.pfx", "password"); }); }) .UseStartup<Startup>() .Build(); ``` 在 *APS.NET Core 3.1* 中则不需要新增 *json* 文件,也不需要修改 *main* 方法,直接在 *appsettings.json* 文件中添加一个 *Urls* 就行了。 ```json { "Urls": "http://localhost:3600;http://*:8099", "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*" } ``` 再补充一个书中没有提到的方法:通过命令行参数。 ```bash dotnet run --urls "http://*:8090;http://localhost:9090" ``` 另外还可以通过环境变量(*ASPNETCORE_URLS*)配置 URL。 ## Kestrel *Kestrel* 是 *ASP.NET Core* 框架的默认 Web 服务器组件。*WebHost.CreateDefaultBuilder* 方法的默认配置中已经默认使用了 *Kestrel*,但若是自己编写代码来创建 Web 服务器,则可以通过 *UseKestrel* 扩展方法启用 *Kestrel* 。另外可以通过 *UseIISIntegration* 方法启用 IIS 集成功能,只有在使用 IIS 作为反向代理时才有效。 ```csharp new WebHostBuilder() .UseStartup<Startup>() .UseContentRoot(Directory.GetCurrentDirectory()) .UseKestrel() .UseIISIntegration() .Build() .Run(); ``` ## 配置调试方案 ASP.NET Core Web 项目自带两个调试方案: - 以 IIS Express 作为反向代理运行应用程序 - 用项目名称命名,独立运行项目(通过 dotnet 命令执行) 可以在 *项目属性 → 调试* 页面新增/修改/删除调试方案。配置完成后可以在 *Properties\launchSettings.json* 文件看到保存的配置内容。大致结构如下: ```json { "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:65132", "sslPort": 0 } }, "profiles": { "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "WebApplication2": { "commandName": "Project", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, "applicationUrl": "http://localhost:5000" } } } ``` *commandName* 一共有 4 个可选值 - *IIS Express*:以 *IIS Express* 作为反向代理进程 - *IIS*:以 *IIS* 服务(完整版 IIS)作为反向代理进程 - *Project*:使用 *dotnet* 命令直接运行应用程序 - *Executable*:自定义一个可执行文件,这种调试方案一般不常用 *environmentVariables* 是环境变量的键值对,名称以 *ASPNETCORE_* 为前缀,后跟环境变量名。 *Environment* 环境变量有 3 个预定义的值: - *Development*:开发环境 - *Staging*:预览环境 - *Production*:生产环境 <!-- 链接 --> [1]: https://stackoverflow.com/questions/57651750/disable-the-dependency-injection-scope-validation-feature-in-the-program-class (disable the dependency injection scope validation feature in the Program class?) [2]: https://stackoverflow.com/questions/57666457/outside-of-scope-when-use-a-service-in-configure-method (outside of scope when use a service in Configure method?) [3]: https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-3.1&tabs=windows (Safe storage of app secrets in development in ASP.NET Core) [4]: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/web-host?view=aspnetcore-3.1#scope-validation (Scope validation) [5]: https://stackoverflow.com/questions/44117840/can-i-set-listen-urls-in-appsettings-json-in-asp-net-core-2-0-preview (Can I set listen URLs in appsettings.json in ASP.net Core 2.0 Preview?) [6]: https://stackoverflow.com/questions/46621788/how-to-use-https-ssl-with-kestrel-in-asp-net-core-2-x (How to use HTTPS / SSL with Kestrel in ASP.NET Core 2.x?) [7]: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-2.2 (Kestrel web server implementation in ASP.NET Core) --- > 购买本书 => [《.NET Core实战:手把手教你掌握380个精彩案例》][10] -- *周家安* 著 --- [10]:https://union-click.jd.com/jdc?e=&p=AyIGZRhaEwAQBFUZXBIyEgRSEl0QCxc3EUQDS10iXhBeGlcJDBkNXg9JHU4YDk5ER1xOGRNLGEEcVV8BXURFUFdfC0RVU1JRUy1OVxUBFQ5THlIQMm1AEkRdb11GZyNTK0BBZwYIbylWcHILWStaJQITBlYbXB0LFQJlK1sSMkBpja3tzaejG4Gx1MCKhTdUK1sRCxQBVxtTEQIQBlwrXBULIloNXwZBXUReEStrJQEiN2UbaxYyUGlUG1kUBhcGUBILQgUXDlMeUkBVRlUBS10XBkIABhkJRzIQBlQfUg%3D%3D (《.NET Core实战:手把手教你掌握380个精彩案例》)
版权声明:原创文章,未经允许不得转载。
https://www.liujiajia.me/2020/4/7/dotnet-core-web-host-config
“Buy me a nongfu spring”
« 《.NET Core 实战》 [No.330~332] Startup
《.NET Core 实战》 [No.321~325] 加密算法 »
昵称
*
电子邮箱
*
回复内容
*
(回复审核后才会显示)
提交
目录
AUTHOR
刘佳佳
江苏 - 苏州
软件工程师