欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

NetCore 启动地址配置详解

程序员文章站 2022-04-06 10:14:06
背景 程序在发布部署时候,设置环境 不生效,也没在代码里使用 ,启动一直是 .最后测试发现只有在 中配置 才生效,网上找了半天资料也没看到有什么问题。 最终翻看源代码,发现是在 中的 替换了全局 导致。 平时开发大体知道程序启动时候端口启用顺序是 环境变量 默认,具体是怎么确定使用哪个配置的,没找到 ......

背景

程序在发布部署时候,设置环境aspnetcore_urls不生效,也没在代码里使用useurls("xxxx"),启动一直是http://localhost:5000.最后测试发现只有在appsettings.json中配置urls才生效,网上找了半天资料也没看到有什么问题。

最终翻看源代码,发现是在startup中的configure替换了全局iconfiguration导致。

平时开发大体知道程序启动时候端口启用顺序是
useurls("xxx")> 环境变量 > 默认,具体是怎么确定使用哪个配置的,没找到资料,所有才有了本文。

启动地址配置的几种方式介绍
  1. 环境变量aspnetcore_urls
#windows 
set aspnetcore_urls=http://localhost:6000
#linux 
export aspnetcore_urls=http://localhost:6000
  1. useurls("http://localhost:6000")
  2. appsettings.json新增urls或者server.urls配置
{
    "urls":"http://localhost:6000;http://localhost:6001",
    "server.urls":"http://localhost:6000;http://localhost:6001"
}
  1. 使用系统默认
说明

程序启动过程中,一个配置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实例中,也就是hosticonfiguration实例。

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);,上面代码也有说明。所以iconfigurationurls如果有值,又会被覆盖掉。所以优先级最高的是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";
结论
  1. 启动端口设置优先级如下:
    useurls("xxxx") > 环境变量 > appsetting.json配置urls>默认地址
  2. 不要随意替换全局的iconfiguration,如果不手动加入环境变量解析的话,会丢失一部分配置数据。

作者:cgyqu
出处:
本站使用「署名 4.0 国际」创作共享协议,转载请在文章明显位置注明作者及出处。