NetCore 啓動地址配置詳解

背景

程序在發佈部署時候,設置環境ASPNETCORE_URLS不生效,也沒在代碼裏使用UseUrls("xxxx"),啓動一直是http://localhost:5000.最後測試發現只有在appsettings.json中配置urls才生效,網上找了半天資料也沒看到有什麼問題。html

最終翻看源代碼,發現是在StartUp中的Configure替換了全局IConfiguration致使。linux

平時開發大致知道程序啓動時候端口啓用順序是
UseUrls("xxx")> 環境變量 > 默認,具體是怎麼肯定使用哪一個配置的,沒找到資料,全部纔有了本文。git

啓動地址配置的幾種方式介紹
  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會重複使用,先放這裏github

//WebHostDefaults.ServerUrlsKey以下
public static readonly string ServerUrlsKey = "urls";
Web項目啓動地址配置說明

今天是介紹啓動方式,因此web啓動流程不是重點。直接進入正題。web

Web啓動最終是調用WebHost.StartAsync,源代碼在這WebHost。其中有個方法EnsureServer來獲取啓動地址json

private static readonly string DeprecatedServerUrlsKey = "server.urls";

//省略
var urls = _config[WebHostDefaults.ServerUrlsKey] ?? _config[DeprecatedServerUrlsKey];

是從全局IConfigration實例中獲取啓動地址。因此個人遇到問題這裏就解決了。但環境變量UseUrls是如何解析並記載進來的呢?下面就開今天講解。windows

環境變量配置詳解

通常Web程序啓動代碼以下:app

Host.CreateDefaultBuilder(args)
   .ConfigureWebHostDefaults(webBuilder =>
   {
       webBuilder.UseStartup<Startup>();
   }).Build().Run();

其中ConfigureWebHostDefaults的會用調用擴展方法ConfigureWebHostide

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
出處:http://www.javashuo.com/article/p-kqlxcvup-da.html 本站使用「署名 4.0 國際」創做共享協議,轉載請在文章明顯位置註明做者及出處。

相關文章
相關標籤/搜索