欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-05-18 15:36:16
前言 ASP.NET Core 后我们的配置变得更加轻量级了,在ASP.NET Core中,配置模型得到了显著的扩展和增强,应用程序配置可以存储在多环境变量配置中,appsettings.json用户机密等 并可以通过应用程序中的相同界面轻松访问,除此之外,ASP.NET中的新配置系统允许使用Opt ......

前言

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