ASP.NET Coreでの構成

12778 ワード

前言
我々の開発過程において、ASP.NETの構成はWeb.configにある.JSON、XML、データベースなどに配置することもできます(ただし、ASP.NETは対応するモジュールや方法を提供していません).
ASP.NET CoreのWeb.configは既に存在しません(ただしIISに管理されている場合はweb.configを使用してIISを構成できます)、
appsettingsでjsonとappsettings.(Development、Staging、Production).jsonプロファイル
(ASP.NETにおけるWeb.configとWeb.Release.configの関係と理解できる).
次にASPを見てみましょう.NET Coreでの構成
基本的な使い方HomeController.cs :
[ApiController]
public class HomeController : ControllerBase
{
    private readonly IConfiguration _configuration;
    public HomeController(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    [HttpGet("/")]
    public dynamic Index()
    {
        return JsonConvert.SerializeObject(new
        {
            ConnectionString = _configuration["ConnectionString"],
            Child1 = _configuration["Parent:Child1"],
            Grandchildren = _configuration["Parent:Child2:Grandchildren"]
        });
    }
}

結果を返します.
{
    "ConnectionString": "data source=.;initial catalog=TEST;user id=sa",
    "Child1": "child",
    "Grandchildren": "grandchildren"
}
appsettings.jsonの値に対応:
{
    "ConnectionString": "data source=.;initial catalog=TEST;user id=sa;password=123",
    "Parent": {
        "Child1": "child1",
        "Child2": "child2"
    }
}

次の点に注意してください.
  • キーは大文字と小文字を区別しません.たとえば、ConnectionsStringとconnectionstringは等価キーとみなされます.
  • キー名が同じ(すべてのロードされたプロファイルを含む)場合は、最後の値に準じます.したがって、appsettings.(Development、Staging、Production).jsonは、appsettings.jsonの構成情報を上書きする.
  • マルチレベルは:で分割するが、環境変数の場合、プラットフォーム間で問題が発生する詳細は
  • を参照する.
  • 上のような表記はキャッシュされていない、すなわち、appsettings.jsonが修正すると、取得した値は直ちに
  • に変更される.

    オブジェクトにバインドIOptions_configuration["Parent:Child2:Grandchildren"]の書き方はプログラマーにとって反感を持っているに違いありません.次に、プロファイルをオブジェクトにバインドします.
  • まずJSONオブジェクトをオブジェクト
    public class TestOptions
    {
        public string ConnectionString { get; set; }
        public Parent Parent { get; set; }
    }
    public class Parent
    {
        public string Child1 { get; set; }
        public Child2 Child2 { get; set; }
    }
    public class Child2
    {
        public string GrandChildren { get; set; }
    }
  • に変換する.
  • Startup.csConfigureServicesメソッドにコードを追加する:
    services.Configure(Configuration);
  • HomeController.cs:
    [ApiController]
    public class HomeController : ControllerBase
    {
        private readonly IOptions _options;
    
        public HomeController(IOptions options)
        {
            _options = options;
        }
    
        [HttpGet("options")]
        public string Options()
        {
            return JsonConvert.SerializeObject(_options);
        }
    }
    は、
    {
    "Value": {
        "ConnectionString": "data source=.;initial catalog=TEST;user id=sa",
            "Parent": {
            "Child1": "child",
                "Child2": {
                "GrandChildren": "grandchildren"
                }
            }
        }
    }
  • の結果を返します.
    検出
  • appsettings.jsonを変更してページをリフレッシュすると、値は
  • になる必要はありません.
  • ルートノードがValueであることを発見しました上の2つの問題に基づいてソースコードを見に行きます:まずこの文を見つけます:services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptions<>), typeof(OptionsManager<>))); OptionsManager方法を見に行きます:
    public class OptionsManager : IOptions, IOptionsSnapshot where TOptions : class, new()
    {
        private readonly IOptionsFactory _factory;
        //   : _cache   ConcurrentDictionary>()
        //              ,    Singleton   ,              
        private readonly OptionsCache _cache = new OptionsCache();
    
        public OptionsManager(IOptionsFactory factory)
        {
            _factory = factory;
        }
    
        /// 
        /// TOptions       
        ///            Value
        /// 
        public TOptions Value
        {
            get
            {
                return Get(Options.DefaultName);
            }
        }
    
        /// 
        ///      IOptionsSnapshot    
        /// 
        public virtual TOptions Get(string name)
        {
            name = name ?? Options.DefaultName;
    
            // Store the options in our instance cache
            return _cache.GetOrAdd(name, () => _factory.Create(name));
        }
    }
  • オブジェクトにバインドされたOptionsSnapshot
  • IOptionsの用法と同様に,注入に依存するライフサイクルがScopedであるためキャッシュされず,コードを直接見る:services.TryAdd(ServiceDescriptor.Scoped(typeof(IOptionsSnapshot<>), typeof(OptionsManager<>)));
  • .
  • IOptionsSnapshotはIOptionsよりも多くの方法TOptions Get(string name); Value属性が実際にこの方法を呼び出したが、nameOptions.DefaultName
  • である.
  • IOptionsSnapshotはIOptionsを継承しています(ここで疑問ですが、上のOptionsManagerIOptions, IOptionsSnapshotのインタフェースを継承しています.はっきりしているためかもしれません).

  • カスタムプロファイル(JSON)
    時々配置情報が多く、個別のファイルに配置したい、ASP.NET Coreは、INI、XML、JSONファイルシステムのロード構成方法を提供します.
  • まずProgram.csのCreateWebHostBuilderメソッドには、次のコードが追加されています.
    public static IWebHostBuilder CreateWebHostBuilder(string[] args)
     {
         return WebHost.CreateDefaultBuilder(args)
                     .ConfigureAppConfiguration((hostingContext, config) =>
                     {
                         //     ,     /Config     
                         //           `appsettings.json`
                         // config.SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), "Config"));
                         config.SetBasePath(Directory.GetCurrentDirectory());
                         //   setting.json     
                         //optional:       ,  false                 
                         //reloadOnChange:           
                         config.AddJsonFile("Config/setting.json", optional: false, reloadOnChange: false);
                     })
                     .UseStartup();
     }
    reloadOnChangeパラメータがどのようなことを処理しているかを見てみましょう.
    if (Source.ReloadOnChange && Source.FileProvider != null)
    {
        ChangeToken.OnChange(
            //             Load(true)   
            () => Source.FileProvider.Watch(Source.Path),
            () => {
                Thread.Sleep(Source.ReloadDelay);
                Load(reload: true);
            });
    }
  • settingを作成する.json:
    {
            "Rookie": {
                "Name": "DDD",
                "Age": 12,
                "Sex": " "
            }
    }
  • Controller:
     [Route("api/[controller]")]
     [ApiController]
     public class OptionsController : ControllerBase
     {
         private readonly IConfiguration _configuration;
         public OptionsController(IConfiguration configuration)
         {
             _configuration = configuration;
         }
         [HttpGet]
         public string Index()
         {
             return JsonConvert.SerializeObject(new
             {
                 Name = _configuration["Rookie:Name"],
                 Age = _configuration["Rookie:Age"],
                 Sex = _configuration["Rookie:Sex"]
             });
         }
     }
  • カスタムプロファイル(JSON)オブジェクトへのバインド
    上記の構成により、取得構成が_configuration["Name"]方式であることが判明し、次にオブジェクトにバインドする
  • コンフィギュレーションオブジェクトSettingsクラス
  • を定義する
  • はStartupです.csのConfigureServicesメソッド追加コード:services.Configure(Configuration.GetSection("Rookie")); GetSectionメソッド:指定キーを取得する構成サブセクション
  • .
  • 用法上同様
  • 何か見つけたか?jsonのプロファイルの情報も_に保存されます.configurationでは、ファイルが多くなるとノードが上書きされる可能性が高いので、書き方を変えます.
  • まずProgramを削除する.csにおけるCreateWebHostBuilderメソッドのコード:config.AddJsonFile("Config/setting.json", optional: false, reloadOnChange: true);
  • プロファイルsettingを変更する.json:
    {
       "Name": "DDD",
       "Age": 12,
       "Sex": " "
    }
  • 在中Startup.csのConfigureServicesメソッドに追加:
    var config = new ConfigurationBuilder()
                 .SetBasePath(Directory.GetCurrentDirectory())
                 .AddJsonFile("Config/setting.json", optional: false, reloadOnChange: true)
                 .Build();
     services.Configure(config);
  • これにより、グローバルな構成情報に影響を与えることはありません.
    その他の方法
  • 次の2つの方法を見てみましょう.
    [Route("[controller]")]
    [ApiController]
    public class HomeController : ControllerBase
    {
        private readonly IConfiguration _configuration;
        private readonly TestOptions _bindOptions = new TestOptions();
        private readonly Parent _parent = new Parent();
    
        public HomeController(IConfiguration configuration)
        {
            //    
            _configuration.Bind(_bindOptions);
            //    
            _configuration.GetSection("Parent").Bind(_parent);
        }
    
        [HttpGet("options")]
        public string Options()
        {
            return JsonConvert.SerializeObject(new
            {
                BindOptions = _bindOptions,
                Parent = _parent
            });
        }
    }
    人はこの方法が少し余計だと感じています(′□╰)
  • IOptionsMonitor、IOptionsFactory、IOptionsMonitor Cache方式:次のコード
    services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptions<>), typeof(OptionsManager<>)));
    services.TryAdd(ServiceDescriptor.Scoped(typeof(IOptionsSnapshot<>), typeof(OptionsManager<>)));
    services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptionsMonitor<>), typeof(OptionsMonitor<>)));
    services.TryAdd(ServiceDescriptor.Transient(typeof(IOptionsFactory<>), typeof(OptionsFactory<>)));
    services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptionsMonitorCache<>), typeof(OptionsCache<>)));
    を参照ここではIOptionsMonitor<>:
     [Route("[controller]")]
     [ApiController]
     public class HomeController : ControllerBase
     {
         private readonly IOptionsMonitor _optionsMonitor;
    
         public HomeController(IOptionsMonitor optionsMonitor
         , ILogger logger)
         {
             _optionsMonitor = optionsMonitor;
             _logger = logger;
         }
    
         [HttpGet("options")]
         public string Options()
         {
             //        
             _optionsMonitor.OnChange((options, name) =>
             {
                 var info = JsonConvert.SerializeObject(new
                 {
                     Options = options,
                     Name = name
                 });
                 _logger.LogInformation($"       :{info}");
             });
             return JsonConvert.SerializeObject(new
             {
                 OptionsMoitor = _optionsMonitor
             });
         }
    プロファイルを変更するとログ情報が表示されます:info:WebApiSample.Controllers.HomeController[0]構成情報が変更されました:{"Options":{"ConnectionString":{data source=.;initial catalog=TEST;user id=sa","Parent":{"Child 1":"child","Child 2":{"GrandChildren":"grandchildren"}},"Name":"TestOptions"}info:WebApiSample.Controllers.HomeController[0]構成情報が変更されました:{"Options":{"ConnectionString":{data source=.;initial catalog=TEST;user id=sa","Parent":{"Child 1":"child","Child 2":{"GrandChildren":"grandchildren"}},"Name":"TestOptions"}info:WebApiSample.Controllers.HomeController[0]構成情報が変更されました:{"Options":{"ConnectionString":{data source=.;initial catalog=TEST;user id=sa","Parent":{"Child 1":"child","Child 2":{"GrandChildren":"grandchildren"}},"Name":"TestOptions"}info:WebApiSample.Controllers.HomeController[0]構成情報が変更されました:{"Options":{"ConnectionString":{data source=.;initial catalog=TEST;user id=sa","Parent":{"Child 1":"child","Child 2":{"GrandChildren":"grandchildren"}}},"Name":"TestOptions"}なぜこんなに多くのログがあるのか分かりません...また、どのログファイルを変更しても、AddJsonFileが実行されたファイルであれば、このイベント
  • がトリガーされます.
    最後に書く
               ,               ,                ...
    
                ,         。
    
                    ,            !