Detailed explanation of NetCore startup address configuration

Posted by polson on Fri, 04 Mar 2022 18:34:52 +0100

background

When the program is released and deployed, set the environment ASPNETCORE_URLS does not take effect, and UseUrls("xxxx") is not used in the code. Startup is always http://localhost:5000. Finally, the test found that only in Appsettings The configuration of urls in JSON takes effect. I haven't seen any problems after looking for information on the Internet for a long time.

Finally, looking at the source code, it is found that the global IConfiguration is replaced by Configure in StartUp.

Usually, developers generally know the port enabling order when the program is started
Useurls ("XXX") > environment variables > default. Specifically, how to determine which configuration to use. No information is found, so this article is available.

Introduction to several ways of starting address configuration
  1. Environment variable ASPNETCORE_URLS
#windows 
set ASPNETCORE_URLS=http://localhost:6000
#linux 
export ASPNETCORE_URLS=http://localhost:6000
  1. UseUrls("http://localhost:6000")
  2. appsettings.json adds urls or server urls configuration
{
    "urls":"http://localhost:6000;http://localhost:6001",
    "server.urls":"http://localhost:6000;http://localhost:6001"
}
  1. Use system default
explain

During program startup, a configuration key will be reused and put here first

//WebHostDefaults.ServerUrlsKey is as follows
public static readonly string ServerUrlsKey = "urls";
Description of Web project startup address configuration

Today's web startup mode is not the key point. Go straight to the point.

Web startup is ultimately a call to webhost Startasync, the source code is here WebHost . There is a method, EnsureServer, to get the startup address

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

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

Is to obtain the startup address from the global IConfigration instance. So I solved the problem here. But how are environment variables and UseUrls parsed and recorded? Let's talk about today.

Detailed explanation of environment variable configuration

The general Web program startup code is as follows:

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

The of ConfigureWebHostDefaults will call the extension method ConfigureWebHost

public static IHostBuilder ConfigureWebHostDefaults(this IHostBuilder builder, Action<IWebHostBuilder> configure)
 {
     return builder.ConfigureWebHost(webHostBuilder =>
     {
         WebHost.ConfigureWebDefaults(webHostBuilder);

         configure(webHostBuilder);
     });
 }

The above codes are defined in Microsoft Extensions. Hosting.

Continue to look at the ConfigureWebHost code. This method is defined in Microsoft AspNetCore. Hosting assembly.

public static IHostBuilder ConfigureWebHost(this IHostBuilder builder, Action<IWebHostBuilder> configure)
{
    //Environment variables will be loaded here
    var webhostBuilder = new GenericWebHostBuilder(builder);
    //Extension methods such as UseUrls will be called here
    configure(webhostBuilder);
    builder.ConfigureServices((context, services) => services.AddHostedService<GenericWebHostService>());
    return builder;
}

In the GenericWebHostBuilder constructor, the following code is used to initialize the configuration and finally add it to the global
IConfiguration instance, that is, IConfiguration instance in Host.

builder. ConfigureServices((context, services) => services. AddHostedService()); This is the focus of web startup. Those who are interested can have a look

//Add environment variable configuration
_config = new ConfigurationBuilder()
           .AddEnvironmentVariables(prefix: "ASPNETCORE_")
           .Build();
//Load configuration into 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 the EnvironmentVariablesConfigurationProvider will eventually be used for environment variable resolution. If you are interested, please take a look at AddEnvironmentVariables source code , the EnvironmentVariablesConfigurationProvider resolves the environment as follows.

public override void Load()
{
    Load(Environment.GetEnvironmentVariables());
}

internal void Load(IDictionary envVariables)
{
    var data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
    //Here is the screening ASPNETCORE_ Environment variable at the beginning
    var filteredEnvVariables = envVariables
        .Cast<DictionaryEntry>()
        .SelectMany(AzureEnvToAppEnv)
        .Where(entry => ((string)entry.Key).StartsWith(_prefix, StringComparison.OrdinalIgnoreCase));

    foreach (var envVariable in filteredEnvVariables)
    {
        //The prefix will be removed and added to the configuration here
        var key = ((string)envVariable.Key).Substring(_prefix.Length);
        data[key] = (string)envVariable.Value;
    }

    Data = data;
}

The keys in IConfiguration are case insensitive. The final effect is to add a record with the key of urls in the global IConfiguration.
If you use the default host CreateDefaultBuilder()ļ¼Œappsettings. The configuration in JSON will be loaded first.
If in Appsettings If urls is configured in JSON, the environment variable is also defined and will be overwritten by the environment variable.

UseUrls parsing

UseUrls parsing will eventually call UseSetting in GenericWebHostBuilder

//The UseUrls code is as follows
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));
}

//UseSetting in GenericWebHostBuilder
public IWebHostBuilder UseSetting(string key, string value)
{
    _config[key] = value;
    return this;
}

Because this method is in the new GenericWebHostBuilder(builder);
After that, it is called configure(webhostBuilder); The above code also has instructions. Therefore, if urls in IConfiguration has a value, it will be overwritten. So the highest priority is UseUrls().

Default address

If there are none of the above three configurations, the address is empty, and the default policy will be used. Here is source code , here are the addresses used by the default policy

 /// <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";
conclusion
  1. The priority of startup port is set as follows:
    Useurls ("XXXX") > environment variables > appsetting JSON configuration URLs > Default Address
  2. Do not replace the global IConfiguration at will. If you do not manually add environment variable resolution, some configuration data will be lost.
  3. To inject your own configuration into the global, you can use the following methods, which will add the configuration to the global IConfiguration
 Host.CreateDefaultBuilder(args)
     .ConfigureWebHostDefaults(builder =>
     {
         builder.UseStartup<Startup>();
     }).ConfigureAppConfiguration(config =>
     {
         config.AddJsonFile("config.json", true, true);
     }).Build().Run();

Author: cgyqu
source: https://www.cnblogs.com/cgyqu/p/12169014.html
This site uses the creative sharing agreement of "signature 4.0 international". Please indicate the author and source in the obvious position of the article.