背景 程式在發佈部署時候,設置環境 不生效,也沒在代碼里使用 ,啟動一直是 .最後測試發現只有在 中配置 才生效,網上找了半天資料也沒看到有什麼問題。 最終翻看源代碼,發現是在 中的 替換了全局 導致。 平時開發大體知道程式啟動時候埠啟用順序是 環境變數 預設,具體是怎麼確定使用哪個配置的,沒找到 ...
背景
程式在發佈部署時候,設置環境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
出處:https://www.cnblogs.com/cgyqu/p/12169014.html
本站使用「署名 4.0 國際」創作共用協議,轉載請在文章明顯位置註明作者及出處。