NetCore 启动地址配置详解
背景
程序在发布部署时候,设置环境aspnetcore_urls
不生效,也没在代码里使用useurls("xxxx")
,启动一直是http://localhost:5000
.最后测试发现只有在appsettings.json
中配置urls
才生效,网上找了半天资料也没看到有什么问题。
最终翻看源代码,发现是在startup
中的configure
替换了全局iconfiguration
导致。
平时开发大体知道程序启动时候端口启用顺序是useurls("xxx")
> 环境变量 > 默认,具体是怎么确定使用哪个配置的,没找到资料,所有才有了本文。
启动地址配置的几种方式介绍
- 环境变量
aspnetcore_urls
#windows set aspnetcore_urls=http://localhost:6000 #linux export aspnetcore_urls=http://localhost:6000
useurls("http://localhost:6000")
-
appsettings.json
新增urls
或者server.urls
配置
{ "urls":"http://localhost:6000;http://localhost:6001", "server.urls":"http://localhost:6000;http://localhost:6001" }
- 使用系统默认
说明
程序启动过程中,一个配置key会重复使用,先放这里
//webhostdefaults.serverurlskey如下 public static readonly string serverurlskey = "urls";
web项目启动地址配置说明
今天是介绍启动方式,所以web启动流程不是重点。直接进入正题。
web启动最终是调用webhost.startasync
,源代码在这webhost
。其中有个方法ensureserver
来获取启动地址
private static readonly string deprecatedserverurlskey = "server.urls"; //省略 var urls = _config[webhostdefaults.serverurlskey] ?? _config[deprecatedserverurlskey];
是从全局iconfigration
实例中获取启动地址。所以我的遇到问题这里就解决了。但环境变量和useurls
是如何解析并记载进来的呢?下面就开今天讲解。
环境变量配置详解
一般web程序启动代码如下:
host.createdefaultbuilder(args) .configurewebhostdefaults(webbuilder => { webbuilder.usestartup<startup>(); }).build().run();
其中configurewebhostdefaults
的会用调用扩展方法configurewebhost
public static ihostbuilder configurewebhostdefaults(this ihostbuilder builder, action<iwebhostbuilder> configure) { return builder.configurewebhost(webhostbuilder => { webhost.configurewebdefaults(webhostbuilder); configure(webhostbuilder); }); }
以上代码都是定义在microsoft.extensions.hosting
中。
继续看configurewebhost
代码,这个方法就定义在microsoft.aspnetcore.hosting
程序集中了。
public static ihostbuilder configurewebhost(this ihostbuilder builder, action<iwebhostbuilder> configure) { //这里会加载环境变量 var webhostbuilder = new genericwebhostbuilder(builder); //这里会调用useurls等扩展方法 configure(webhostbuilder); builder.configureservices((context, services) => services.addhostedservice<genericwebhostservice>()); return builder; }
在genericwebhostbuilder
构造函数里有如下代码,用来初始化配置,最终添加到全局iconfiguration
实例中,也就是host
中iconfiguration
实例。
builder.configureservices((context, services) => services.addhostedservice
());这个是web启动重点,有兴趣的可以看下
//加入环境变量配置 _config = new configurationbuilder() .addenvironmentvariables(prefix: "aspnetcore_") .build(); //把配置加载到host _builder.configurehostconfiguration(config => { config.addconfiguration(_config); // we do this super early but still late enough that we can process the configuration // wired up by calls to usesetting executehostingstartups(); })
addenvironmentvariables
环境变量解析最终会使用environmentvariablesconfigurationprovider
,有兴趣的可以看下addenvironmentvariables
源代码,environmentvariablesconfigurationprovider
解析环境的方法如下。
public override void load() { load(environment.getenvironmentvariables()); } internal void load(idictionary envvariables) { var data = new dictionary<string, string>(stringcomparer.ordinalignorecase); //这里是筛选aspnetcore_开头的环境变量 var filteredenvvariables = envvariables .cast<dictionaryentry>() .selectmany(azureenvtoappenv) .where(entry => ((string)entry.key).startswith(_prefix, stringcomparison.ordinalignorecase)); foreach (var envvariable in filteredenvvariables) { //这里会把前缀去掉加到配置里 var key = ((string)envvariable.key).substring(_prefix.length); data[key] = (string)envvariable.value; } data = data; }
iconfiguration
中的key是不区分大小写的,所有最终的效是在全局iconfiguration
中新增一条key为urls的记录。
而如果使用默认host.createdefaultbuilder()
,appsettings.json
中的配置会先加载。
如果在appsettings.json中配置urls
的话,环境变量也定义了,就会被环境变量的覆盖掉。
useurls解析
useurls解析
最终会调用genericwebhostbuilder
中的usesetting
//useurls代码如下 public static iwebhostbuilder useurls(this iwebhostbuilder hostbuilder, params string[] urls) { if (urls == null) { throw new argumentnullexception(nameof(urls)); } return hostbuilder.usesetting(webhostdefaults.serverurlskey, string.join(serverurlsseparator, urls)); } //genericwebhostbuilder中的usesetting public iwebhostbuilder usesetting(string key, string value) { _config[key] = value; return this; }
由于这个方法是在 new genericwebhostbuilder(builder);
之后调用,就是 configure(webhostbuilder);
,上面代码也有说明。所以iconfiguration
中urls如果有值,又会被覆盖掉。所以优先级最高的是useurls()
。
默认地址
假如以上3种配置都没有,就是地址为空,会使用默认策略。这里是源代码,下面是默认策略使用的地址
/// <summary> /// the endpoint kestrel will bind to if nothing else is specified. /// </summary> public static readonly string defaultserveraddress = "http://localhost:5000"; /// <summary> /// the endpoint kestrel will bind to if nothing else is specified and a default certificate is available. /// </summary> public static readonly string defaultserverhttpsaddress = "https://localhost:5001";
结论
- 启动端口设置优先级如下:
useurls("xxxx")
> 环境变量 >appsetting.json
配置urls
>默认地址 - 不要随意替换全局的
iconfiguration
,如果不手动加入环境变量解析的话,会丢失一部分配置数据。
作者:cgyqu
出处:
本站使用「署名 4.0 国际」创作共享协议,转载请在文章明显位置注明作者及出处。
上一篇: 【DDD】持久化领域对象的方法实践
下一篇: 【Asp.net】 七大内置对象