NetCore 啟動地址配置詳解


背景

程序在發布部署時候,設置環境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,如果不手動加入環境變量解析的話,會丟失一部分配置數據。
  3. 將自己的配置注入的全局,可以使用以下方式,這樣就會把配置追加到全局的IConfiguration
 Host.CreateDefaultBuilder(args)
     .ConfigureWebHostDefaults(builder =>
     {
         builder.UseStartup<Startup>();
     }).ConfigureAppConfiguration(config =>
     {
         config.AddJsonFile("config.json", true, true);
     }).Build().Run();

作者:cgyqu
出處:https://www.cnblogs.com/cgyqu/p/12169014.html
本站使用「署名 4.0 國際」創作共享協議,轉載請在文章明顯位置注明作者及出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM