激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - ASP.NET教程 - asp.net core配置文件加載過程的深入了解

asp.net core配置文件加載過程的深入了解

2020-06-05 16:27Ron.liang ASP.NET教程

這篇文章主要給大家介紹了關(guān)于asp.net core配置文件加載過程的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧

前言

配置文件中程序運行中,擔當著不可或缺的角色;通常情況下,使用 visual studio 進行創(chuàng)建項目過程中,項目配置文件會自動生成在項目根目錄下,如 appsettings.json,或者是被大家廣泛使用的 appsettings.{env.EnvironmentName}.json;配置文件

作為一個入口,可以讓我們在不更新代碼的情況,對程序進行干預(yù)和調(diào)整,那么對其加載過程的全面了解就顯得非常必要。

何時加載了默認的配置文件

在 Program.cs 文件中,查看以下代碼

?
1
2
3
4
5
6
7
8
9
10
11
public class Program
{
 public static void Main(string[] args)
 {
  CreateWebHostBuilder(args).Build().Run();
 }
 
 public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
  WebHost.CreateDefaultBuilder(args)
   .UseStartup<Startup>();
}

WebHost.CreateDefaultBuilder 位于程序集 Microsoft.AspNetCore.dll 內(nèi),當程序執(zhí)行 WebHost.CreateDefaultBuilder(args) 的時候,在 CreateDefaultBuilder 方法內(nèi)部加載了默認的配置文件

代碼如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
public static IWebHostBuilder CreateDefaultBuilder(string[] args)
  {
   var builder = new WebHostBuilder();
 
   if (string.IsNullOrEmpty(builder.GetSetting(WebHostDefaults.ContentRootKey)))
   {
    builder.UseContentRoot(Directory.GetCurrentDirectory());
   }
   if (args != null)
   {
    builder.UseConfiguration(new ConfigurationBuilder().AddCommandLine(args).Build());
   }
 
   builder.UseKestrel((builderContext, options) =>
    {
     options.Configure(builderContext.Configuration.GetSection("Kestrel"));
    })
    .ConfigureAppConfiguration((hostingContext, config) =>
    {
     var env = hostingContext.HostingEnvironment;
 
     config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
       .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
 
     if (env.IsDevelopment())
     {
      var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
      if (appAssembly != null)
      {
       config.AddUserSecrets(appAssembly, optional: true);
      }
     }
 
     config.AddEnvironmentVariables();
 
     if (args != null)
     {
      config.AddCommandLine(args);
     }
    })
    .ConfigureLogging((hostingContext, logging) =>
    {
     logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
     logging.AddConsole();
     logging.AddDebug();
     logging.AddEventSourceLogger();
    })
    .ConfigureServices((hostingContext, services) =>
    {
     // Fallback
     services.PostConfigure<HostFilteringOptions>(options =>
     {
      if (options.AllowedHosts == null || options.AllowedHosts.Count == 0)
      {
       // "AllowedHosts": "localhost;127.0.0.1;[::1]"
       var hosts = hostingContext.Configuration["AllowedHosts"]?.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
       // Fall back to "*" to disable.
       options.AllowedHosts = (hosts?.Length > 0 ? hosts : new[] { "*" });
      }
     });
     // Change notification
     services.AddSingleton<IOptionsChangeTokenSource<HostFilteringOptions>>(
      new ConfigurationChangeTokenSource<HostFilteringOptions>(hostingContext.Configuration));
 
     services.AddTransient<IStartupFilter, HostFilteringStartupFilter>();
    })
    .UseIIS()
    .UseIISIntegration()
    .UseDefaultServiceProvider((context, options) =>
    {
     options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
    });
 
   return builder;
  }

可以看到,CreateDefaultBuilder 內(nèi)部還是使用了 IConfigurationBuilder 的實現(xiàn),且寫死了默認配置文件的名字

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
public static IWebHostBuilder CreateDefaultBuilder(string[] args)
  {
   var builder = new WebHostBuilder();
 
   if (string.IsNullOrEmpty(builder.GetSetting(WebHostDefaults.ContentRootKey)))
   {
    builder.UseContentRoot(Directory.GetCurrentDirectory());
   }
   if (args != null)
   {
    builder.UseConfiguration(new ConfigurationBuilder().AddCommandLine(args).Build());
   }
 
   builder.UseKestrel((builderContext, options) =>
    {
     options.Configure(builderContext.Configuration.GetSection("Kestrel"));
    })
    .ConfigureAppConfiguration((hostingContext, config) =>
    {
     var env = hostingContext.HostingEnvironment;
 
     config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
       .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
 
     if (env.IsDevelopment())
     {
      var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
      if (appAssembly != null)
      {
       config.AddUserSecrets(appAssembly, optional: true);
      }
     }
 
     config.AddEnvironmentVariables();
 
     if (args != null)
     {
      config.AddCommandLine(args);
     }
    })
    .ConfigureLogging((hostingContext, logging) =>
    {
     logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
     logging.AddConsole();
     logging.AddDebug();
     logging.AddEventSourceLogger();
    })
    .ConfigureServices((hostingContext, services) =>
    {
     // Fallback
     services.PostConfigure<HostFilteringOptions>(options =>
     {
      if (options.AllowedHosts == null || options.AllowedHosts.Count == 0)
      {
       // "AllowedHosts": "localhost;127.0.0.1;[::1]"
       var hosts = hostingContext.Configuration["AllowedHosts"]?.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
       // Fall back to "*" to disable.
       options.AllowedHosts = (hosts?.Length > 0 ? hosts : new[] { "*" });
      }
     });
     // Change notification
     services.AddSingleton<IOptionsChangeTokenSource<HostFilteringOptions>>(
      new ConfigurationChangeTokenSource<HostFilteringOptions>(hostingContext.Configuration));
 
     services.AddTransient<IStartupFilter, HostFilteringStartupFilter>();
    })
    .UseIIS()
    .UseIISIntegration()
    .UseDefaultServiceProvider((context, options) =>
    {
     options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
    });
 
   return builder;
  }

由于以上代碼,我們可以在應(yīng)用程序根目錄下使用 appsettings.json appsettings.{env.EnvironmentName}.json 這種形式的默認配置文件名稱

并且,由于 Main 方法默認對配置文件進行了 Build 方法的調(diào)用操作

?
1
2
3
4
public static void Main(string[] args)
 {
  CreateWebHostBuilder(args).Build().Run();
 }

我們可以在 Startup.cs 中使用注入的方式獲得默認的配置文件對象 IConfigurationRoot/IConfiguration,代碼片段

?
1
2
3
4
5
6
public class Startup
{
 public Startup(IConfiguration configuration)
 {
  Configuration = configuration;
 }

這是為什么呢,因為在 執(zhí)行 Build 方法的時候,方法內(nèi)部已經(jīng)將默認配置文件對象加入了 ServiceCollection 中,代碼片段

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var services = new ServiceCollection();
services.AddSingleton(_options);
services.AddSingleton<IHostingEnvironment>(_hostingEnvironment);
services.AddSingleton<Extensions.Hosting.IHostingEnvironment>(_hostingEnvironment);
services.AddSingleton(_context);
 
var builder = new ConfigurationBuilder()
   .SetBasePath(_hostingEnvironment.ContentRootPath)
   .AddConfiguration(_config);
 
_configureAppConfigurationBuilder?.Invoke(_context, builder);
 
var configuration = builder.Build();
services.AddSingleton<IConfiguration>(configuration);
_context.Configuration = configuration;

以上這段代碼非常熟悉,因為在 Startup.cs 文件中,我們也許會使用過 ServiceCollection 對象將業(yè)務(wù)系統(tǒng)的自定義對象加入服務(wù)上下文中,以方便后續(xù)接口注入使用。

AddJsonFile 方法的使用

通常情況下,我們都會使用默認的配置文件進行開發(fā),或者使用 appsettings.{env.EnvironmentName}.json 的文件名稱方式來區(qū)分 開發(fā)/測試/產(chǎn)品 環(huán)境,根據(jù)環(huán)境變量加載不同的配置文件;可是這樣一來帶來了另外一個管理上的問題,產(chǎn)品環(huán)境的配置參數(shù)和開發(fā)環(huán)境

是不同的,如果使用環(huán)境變量的方式控制配置文件的加載,則可能導(dǎo)致密碼泄露等風(fēng)險;誠然,可以手工在產(chǎn)品環(huán)境創(chuàng)建此文件,但是這樣一來,發(fā)布流程將會變得非常繁瑣,稍有錯漏文件便會被覆蓋。

我們推薦使用 AddJsonFile 加載產(chǎn)品環(huán)境配置,代碼如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public Startup(IConfiguration configuration, IHostingEnvironment env)
 {
  Configuration = AddCustomizedJsonFile(env).Build();
 
 }
 
 public ConfigurationBuilder AddCustomizedJsonFile(IHostingEnvironment env)
 {
  var build = new ConfigurationBuilder();
  build.SetBasePath(env.ContentRootPath).AddJsonFile("appsettings.json", true, true);
  if (env.IsProduction())
  {
   build.AddJsonFile(Path.Combine("/data/sites/config", "appsettings.json"), true, true);
  }
  return build;
 }

通過 AddCustomizedJsonFile 方法去創(chuàng)建一個 ConfigurationBuilder 對象,并覆蓋系統(tǒng)默認的 ConfigurationBuilder 對象,在方法內(nèi)部,默認加載開發(fā)環(huán)境的配置文件,在產(chǎn)品模式下,額外加載目錄 /data/sites/config/appsettings.json 文件,

不同擔心配置文件沖突問題,相同鍵值的內(nèi)容將由后加入的配置文件所覆蓋。

配置文件的變動

在調(diào)用 AddJsonFile 時,我們看到該方法共有 5 個重載的方法

其中一個方法包含了 4 個參數(shù),代碼如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange)
 {
  if (builder == null)
  {
   throw new ArgumentNullException(nameof(builder));
  }
  if (string.IsNullOrEmpty(path))
  {
   throw new ArgumentException(Resources.Error_InvalidFilePath, nameof(path));
  }
 
  return builder.AddJsonFile(s =>
  {
   s.FileProvider = provider;
   s.Path = path;
   s.Optional = optional;
   s.ReloadOnChange = reloadOnChange;
   s.ResolveFileProvider();
  });
 }

在此方法中,有一個參數(shù) bool reloadOnChange,從參數(shù)描述可知,該值指示在文件變動的時候是否重新加載,默認值為:false;一般在手動加載配置文件,即調(diào)用 AddJsonFile 方法時,建議將該參數(shù)值設(shè)置為 true。

那么 .netcore 是如果通過該參數(shù) reloadOnChange 是來監(jiān)控文件變動,以及何時進行重新加載的操作呢,看下面代碼

?
1
2
3
4
5
6
7
8
9
10
public IConfigurationRoot Build()
{
 var providers = new List<IConfigurationProvider>();
 foreach (var source in Sources)
 {
  var provider = source.Build(this);
  providers.Add(provider);
 }
 return new ConfigurationRoot(providers);
}

在我們執(zhí)行 .Build 方法的時候,方法內(nèi)部最后一行代碼給我們利用 AddJsonFile 方法的參數(shù)創(chuàng)建并返回了一個 ConfigurationRoot 對象

在 ConfigurationRoot 的構(gòu)造方法中

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public ConfigurationRoot(IList<IConfigurationProvider> providers)
{
 if (providers == null)
 {
  throw new ArgumentNullException(nameof(providers));
 }
 
 _providers = providers;
 foreach (var p in providers)
 {
  p.Load();
  ChangeToken.OnChange(() => p.GetReloadToken(), () => RaiseChanged());
 }
}

我們看到,方法內(nèi)部一次讀取了通過 AddJsonFile 方法加入的配置文件,并為每個配置文件單獨分配了一個監(jiān)聽器 ChangeToken,并綁定當前文件讀取對象 IConfigurationProvider.GetReloadToken 方法到監(jiān)聽器中

當文件產(chǎn)生變動的時候,監(jiān)聽器會收到一個通知,同時,對該文件執(zhí)行原子操作

?
1
2
3
4
5
private void RaiseChanged()
 {
  var previousToken = Interlocked.Exchange(ref _changeToken, new ConfigurationReloadToken());
  previousToken.OnReload();
 }

由于 AddJsonFile 方法內(nèi)部使用了 JsonConfigurationSource ,而 Build 的重載方法構(gòu)造了一個 JsonConfigurationProvider 讀取對象,查看代碼

?
1
2
3
4
5
public override IConfigurationProvider Build(IConfigurationBuilder builder)
{
 EnsureDefaults(builder);
 return new JsonConfigurationProvider(this);
}

在 JsonConfigurationProvider 繼承自 FileConfigurationProvider 類,該類位于程序集 Microsoft.Extensions.Configuration.Json.dll 內(nèi)

在 FileConfigurationProvider 的構(gòu)造方法中實現(xiàn)了監(jiān)聽器重新加載配置文件的過程

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public FileConfigurationProvider(FileConfigurationSource source)
{
 if (source == null)
 {
  throw new ArgumentNullException(nameof(source));
 }
 Source = source;
 
 if (Source.ReloadOnChange && Source.FileProvider != null)
 {
  ChangeToken.OnChange(
   () => Source.FileProvider.Watch(Source.Path),
   () => {
    Thread.Sleep(Source.ReloadDelay);
    Load(reload: true);
   });
 }
}

值得注意的是,該監(jiān)聽器不是在得到文件變動通知后第一時間去重新加載配置文件,方法內(nèi)部可以看到,這里有一個 Thread.Sleep(Source.ReloadDelay) ,而 ReloadDelay 的默認值為:250ms,該屬性的描述為

  • 獲取或者設(shè)置重新加載將等待的毫秒數(shù), 然后調(diào)用 "Load" 方法。 這有助于避免在完全寫入文件之前觸發(fā)重新加載。默認值為250
  • 讓人欣慰的是,我們可以自定義該值,如果業(yè)務(wù)對文件變動需求不是特別迫切,您可以將該值設(shè)置為一個很大的時間,通常情況下,我們不建議那么做

結(jié)語

以上就是 asp.netcore 中配置文件加載的內(nèi)部執(zhí)行過程,從中我們認識到,默認配置文件是如何加載,并將默認配置文件如何注入到系統(tǒng)中的,還學(xué)習(xí)到了如果在不同的環(huán)境下,選擇加載自定義配置文件的過程;但配置文件變動的時候,系統(tǒng)內(nèi)部又是如何去把配置文件重新加載到內(nèi)存中去的。

原文鏈接:https://www.cnblogs.com/viter/p/9967936.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 369看片你懂的小视频在线观看 | 久久久久91视频 | 成人午夜视屏 | 最新午夜综合福利视频 | 欧美成人黄色片 | 日本在线免费观看视频 | 斗罗破苍穹在线观看免费完整观看 | 国产精品亚洲一区二区三区在线观看 | 天天草夜夜爽 | 亚洲国产超高清a毛毛片 | 色视频91 | 夏目友人帐第七季第一集 | 夜间福利视频 | 精品国产乱码一区二区三区四区 | 91精品国| 亚洲网站免费看 | 成人18网站| 国产色视频一区 | 成熟女人特级毛片www免费 | 午夜视频在线免费观看 | 中国a级黄色片 | 黄色片免费看网站 | 久久久久99一区二区三区 | 福利在线国产 | 久久精品亚洲精品国产欧美kt∨ | av视屏 | 成人在线视频精品 | 久久在线 | 色污视频在线观看 | 欧美在线成人影院 | 日本在线观看视频网站 | 国产三级国产精品国产普男人 | 嫩草影院在线观看网站成人 | 久久噜噜噜精品国产亚洲综合 | 国产麻豆交换夫妇 | 色在线观看视频 | 91社影院在线观看 | 免费看毛片网站 | 日韩精品中文字幕一区二区 | 午夜精品在线视频 | 一级黄色免费 |