• ASP.NET Core 选项模式源码学习Options Configure(一)


    前言

    ASP.NET Core 后我们的配置变得更加轻量级了,在ASP.NET Core中,配置模型得到了显著的扩展和增强,应用程序配置可以存储在多环境变量配置中,appsettings.json用户机密等 并可以通过应用程序中的相同界面轻松访问,除此之外,ASP.NET中的新配置系统允许使用Options的强类型设置。

    强类型Options

    在ASP.NET Core中没有AppSettings["Key"]默认方法,那么推荐的是创建强类型的配置类,去绑定配置项。

    
        public class MyOptions
        {
            public string Name { get; set; }
    
            public string Url { get; set; }
        }
    
    

    然后我们在appsettings.json中添加如下内容:

    
    {
      "MyOptions": 
        {
          "Name": "TestName",
          "Url": "TestUrl"
        }
    }
    
    

    配置绑定到类

    ConfigureServices方法进行配置以绑定到类

            public void ConfigureServices(IServiceCollection services)
            {
    
                services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
                services.AddControllers();
    
            }
    
    

    MyOptions只需将IOptions<>类的实例注入控制器中,然后通过Value属性获取Myoptions:

    
        public class WeatherForecastController : ControllerBase
        {
            private readonly MyOptions _options;
            public WeatherForecastController(IOptions<MyOptions> options)
            {
                _options = options.Value;
            }
    
            [HttpGet]
            public OkObjectResult Get() {
                return Ok(string.Format("Name:{0},Url:{1}", _options.Name,_options.Url));
            }
        }
    
    

    Configure

    委托配置
    
                //基础注册方式
                services.Configure<MyOptions>(o => { o.Url = "MyOptions"; o.Name = "Name111"; });
                //指定具体名称
                services.Configure<MyOptions>("Option", o => { o.Url = "MyOptions"; o.Name = "Name111"; }) ;
                //配置所有实例
                services.ConfigureAll<MyOptions>(options =>{ options.Name = "Name1";  options.Url = "Url1";});
    
    
    
    通过配置文件配置
    
               // 使用配置文件来注册实例
                services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
                // 指定具体名称
                services.Configure<MyOptions>("Option", Configuration.GetSection("MyOptions"));
    
    
    PostConfigure

    PostConfigure会在Configure注册完之后再进行注册

    
         services.PostConfigure<MyOptions>(o => o.Name = "Name1");
                services.PostConfigure<MyOptions>("Option", o => o.Name = "Name1");
                services.PostConfigureAll<MyOptions>(o => o.Name = "Name1");
    
    

    源码解析

    IConfigureOptions接口

    
        public interface IConfigureOptions<in TOptions> where TOptions : class
        {
            
            void Configure(TOptions options);
        }
    
    
    

    Configure为方便使用IConfigureOptions注册单例ConfigureNamedOptions

    
         public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string name, Action<TOptions> configureOptions)
                where TOptions : class
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                if (configureOptions == null)
                {
                    throw new ArgumentNullException(nameof(configureOptions));
                }
    
                services.AddOptions();
                services.AddSingleton<IConfigureOptions<TOptions>>(new ConfigureNamedOptions<TOptions>(name, configureOptions));
                return services;
            }
    
    
    
    

    上面代码IConfigureOptions实现了ConfigureNamedOptions,那我们再来看看内部源码
    ConfigureNamedOptions 其实就是把我们注册的Action包装成统一的Configure方法,以方便后续创建Options实例时,进行初始化。

    
        public class ConfigureNamedOptions<TOptions> : IConfigureNamedOptions<TOptions> where TOptions : class
        {
            
            public ConfigureNamedOptions(string name, Action<TOptions> action)
            {
                Name = name;
                Action = action;
            }
    
           
            public string Name { get; }
    
          
            public Action<TOptions> Action { get; }
    
          
            public virtual void Configure(string name, TOptions options)
            {
                if (options == null)
                {
                    throw new ArgumentNullException(nameof(options));
                }
    
                // Null name is used to configure all named options.
                if (Name == null || name == Name)
                {
                    Action?.Invoke(options);
                }
            }
            public void Configure(TOptions options) => Configure(Options.DefaultName, options);
        }
    
    

    services.Configure(Configuration.GetSection("MyOptions")); 我们不指定具体名称的时候默认是如下代码片段

    
            public virtual void Configure(string name, TOptions options)
            {
                if (options == null)
                {
                    throw new ArgumentNullException(nameof(options));
                }
    
                // Null name is used to configure all named options.
                if (Name == null || name == Name)
                {
                    Action?.Invoke(options);
                }
            }
            public void Configure(TOptions options) => Configure(Options.DefaultName, options);
    
    

    默认使用的是Options.DefaultName

    AddOptions默认方法默认为我们注册了一些核心的类

    
         public static IServiceCollection AddOptions(this IServiceCollection services)
            {
                if (services == null)
                {
                    throw new ArgumentNullException(nameof(services));
                }
    
                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<>)));
                return services;
            }
            
    
  • 相关阅读:
    关于线程间通信的条件变量
    vim学习相关链接
    CString与输入输出流对象问题。
    CRect类 的介绍
    在vs中char类型的实参与LPCWSTR类型的形参类型不兼容怎么解决?
    ADO Recordset 对象链接
    FIND_IN_SET的简单使用
    html meta标签作用
    github新建托管项目及上传项目
    Javascript编码规范
  • 原文地址:https://www.cnblogs.com/yyfh/p/12020522.html
Copyright © 2020-2023  润新知