前言

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;
        }