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

asp.net core 系列 12 选项 TOptions

程序员文章站 2022-12-17 13:39:07
一.概述 本章讲的选项模式是对Configuration配置的功能扩展。 讲这篇时有个专用名词叫“选项类(TOptions)” 。该选项类作用是指:把选项类中的属性与配置来源中的键关联起来。举个例,假设json文件有个Option1键,选项类中也有个叫Option1的属性名,经过选项配置,这样就能把 ......

一.概述

  本章讲的选项模式是对configuration配置的功能扩展。 讲这篇时有个专用名词叫“选项类(toptions)” 。该选项类作用是指:把选项类中的属性与配置来源中的键关联起来。举个例,假设json文件有个option1键,选项类中也有个叫option1的属性名,经过选项配置,这样就能把json中的键的值映射到选项类属性值中。也可以理解在项目应用中,把一个json文件序列化到.net类。

 

  1.1选项接口介绍

    在官方文档中选项接口有很多,这里列举了这些选项接口。所有选项接口基本都继承了toptions接口。

asp.net core 系列 12 选项 TOptions
    // used for notifications when toptions instances change
    public interface ioptionsmonitor<out toptions>
    {
        //
        // 摘要:
        //     returns the current toptions instance with the microsoft.extensions.options.options.defaultname.
        toptions currentvalue { get; }
        //...
    }


    // used to create toptions instances
    public interface ioptionsfactory<toptions> where toptions : class, new()
    {
        //
        // 摘要:
        //     returns a configured toptions instance with the given name.
        toptions create(string name);
    }


    // represents something that configures the toptions type. note: these are run before all 
    public interface iconfigureoptions<in toptions> where toptions : class
    {
        //
        // 摘要:
        //     invoked to configure a toptions instance.
        //
        // 参数:
        //   options:
        //     the options instance to configure.
        void configure(toptions options);
    }


    public interface ipostconfigureoptions<in toptions> where toptions : class
    {
        //
        // 摘要:
        //     invoked to configure a toptions instance.
        //
        // 参数:
        //   name:
        //     the name of the options instance being configured.
        //
        //   options:
        //     the options instance to configured.
        void postconfigure(string name, toptions options);
    }


    public interface iconfigurenamedoptions<in toptions> : iconfigureoptions<toptions> where toptions : class
    {
        //
        // 摘要:
        //     invoked to configure a toptions instance.
        //
        // 参数:
        //   name:
        //     the name of the options instance being configured.
        //
        //   options:
        //     the options instance to configure.
        void configure(string name, toptions options);
    }


    // used by ioptionsmonitor<toptions> to cache toptions instances.
    public interface ioptionsmonitorcache<toptions> where toptions : class
    {
        //
        // 摘要:
        //     clears all options instances from the cache.
        void clear();
        //
        // 摘要:
        //     gets a named options instance, or adds a new instance created with createoptions.
        //
        // 参数:
        //   name:
        //     the name of the options instance.
        //
        //   createoptions:
        //     the func used to create the new instance.
        //
        // 返回结果:
        //     the options instance.
        toptions getoradd(string name, func<toptions> createoptions);
        //
        // 摘要:
        //     tries to adds a new option to the cache, will return false if the name already
        //     exists.
        //
        // 参数:
        //   name:
        //     the name of the options instance.
        //
        //   options:
        //     the options instance.
        //
        // 返回结果:
        //     whether anything was added.
        bool tryadd(string name, toptions options);
        //
        // 摘要:
        //     try to remove an options instance.
        //
        // 参数:
        //   name:
        //     the name of the options instance.
        //
        // 返回结果:
        //     whether anything was removed.
        bool tryremove(string name);
    }


    // used to access the value of toptions for the lifetime of a request
    public interface ioptionssnapshot<out toptions> : ioptions<toptions> where toptions : class, new()
    {
        //
        // 摘要:
        //     returns a configured toptions instance with the given name.
        toptions get(string name);
    }

    //used to retrieve configured toptions instances
    public interface ioptions<out toptions> where toptions : class, new()
    {
        //
        // 摘要:
        //     the default configured toptions instance
        toptions value { get; }
    }
view code

 

    (1)  ioptionsmonitor<toptions>

      ioptionsmonitor<toptions>用于toptions实例更改时的通知,用于管理 toptions选项类 。该ioptionsmonitor<toptions>支持以下方案:

      (1) 更改通知。当配置文件发生修改时,会监听同步到选项类。

      (2) 命名选项。iconfigurenamedoptions支持命名选项。接口继续关系 iconfigurenamedoptions:iconfigureoptions

      (3) 重新加载配置。通过 ioptionssnapshot 重新加载配置数据,ioptionsmonitor也支持该功能。 接口继续关系ioptionssnapshot :ioptions

      (4) 选择性选项失效 (ioptionsmonitorcache<toptions>)。

    (2)  其它接口

      ioptionsfactory<toptions> 负责产生toptions选项实例,它具有单个 create 方法。

      默认实现采用所有已注册 iconfigureoptions<toptions> 和 ipostconfigureoptions<toptions> 并首先运行所有配置(所有的来源配置),

      然后才进行选项后期配置ipostconfigureoptions<toptions> 。

      ioptionsmonitorcache<toptions>用于缓存toptions实例。

      

  1.2 常规选项配置

    toptions选项类必须为包含公共无参数构造函数的非抽象类。下面示例中选项类myoptions具有两种属性:option1 和 option2。 设置默认值为可选,但以下示例中的类构造函数设置了 option1 的默认值。 option2 具有通过直接初始化属性设置的默认值。

     public class myoptions
      {
          public myoptions()
          {
              // set default value.
              option1 = "value1_from_ctor";
          }

          public string option1 { get; set; }
          public int option2 { get; set; } = 5;
      }
       //将myoptions类已通过configure添加到服务容器,并绑定到配置iconfiguration上
       //registers a configuration instance which toptions will bind against.
       services.configure<myoptions>(configuration);
        private readonly myoptions _options;
     //otherpages/page1 public page1model( ioptionsmonitor<myoptions> optionsaccessor) { _options = optionsaccessor.currentvalue; } public void onget() { var option1 = _options.option1; var option2 = _options.option2; var simpleoptions = $"option1 = {option1}, option2 = {option2}"; }
    // 此时simpleoptions值:"option1 = value1_from_ctor, option2 = 5"
      //下面在appsettings.json 文件添加 option1 和 option2 的值。
        "option1": "value1_from_json",
        "option2": -1,

    当配置文件appsettings.json中option1和option2键的值改变后,myoptions 选项类中的属性option1和option2的值也会改变。 下面再次运行otherpages/page1

      //此时simpleoptions的值为:"option1 = value1_from_json, option2 = -1"

    为什么myoptions类中option1,option2会取到appsettings.json文件中的值呢?因为myoptions选项类注入到iconfiguration服务后与appsettings.json文件中键相同,形成了映射。

 

  1.3 通过委托配置简单选项

     使用委托设置选项值。 此示例应用使用 myoptionswithdelegateconfig 类 ,这里仍然是使用相同的键option1,option2。 它通过 myoptionswithdelegateconfig 使用委托来配置绑定。

      public class myoptionswithdelegateconfig
    {
        public myoptionswithdelegateconfig()
        {
            // set default value.
            option1 = "value1_from_ctor";
        }
    
         public string option1 { get; set; }
         public int option2 { get; set; } = 5;
    }
         services.configure<myoptions>(configuration);
         //第二个注入服务
         services.configure<myoptionswithdelegateconfig>(myoptions =>
         {
         // 在page1model构造方法中生成myoptionswithdelegateconfig实例时调用 myoptions.option1 = "value1_configured_by_delegate"; myoptions.option2 = 500; });

    

    public page1model(
            iconfiguration configuration,
            ioptionsmonitor<myoptionswithdelegateconfig> optionsaccessorwithdelegateconfig,
            ioptionsmonitor<myoptions> optionsaccessor
          )
        {
        
            _optionswithdelegateconfig = optionsaccessorwithdelegateconfig.currentvalue;
            _options = optionsaccessor.currentvalue;
            configuration = configuration;
        }

        public iconfiguration configuration { get; }
        private readonly myoptions _options;
        private readonly myoptionswithdelegateconfig _optionswithdelegateconfig;

        public string bindguidmsg { get; set; }

        public void onget()
        {
            bindguidmsg = $"option1 = {_options.option1}, option2 = {_options.option2}";

            bindguidmsg += "</br>";

            bindguidmsg += $"delegate_option1 = {_optionswithdelegateconfig.option1}, " +
                           $"delegate_option2 = {_optionswithdelegateconfig.option2}";
        }

    每次调用 configure 都会将 iconfigureoptions<toptions> 服务添加到服务容器。 在前面的示例中,option1 和 option2 的值同时在 appsettings.json 中指定,但 option1 和 option2 的值被配置的委托替代。

    当启用多个配置服务时,指定的最后一个配置源优于其他源,由其设置配置值。 运行应用时,页面模型的 onget 方法返回显示选项类值的字符串:

    // myoptions实例取值如下:
    simpleoptions:option1 = -1,option2 = 5 
    // myoptionswithdelegateconfig实例取值如下:
    delegate_option1 = value1_configured_by_delegate,delegate_option2 = 500

 

   1.4 子选项配置

     当配置文件中的子节点需要与选项类进行关联映射时,可以通过服务注入bind到指定的configuration节点。在以下代码中,已向服务容器添加第三个 iconfigureoptions<toptions> 服务。 它将 mysuboptions 绑定到 appsettings.json 文件的 subsection 部分:

      "option1": "value1_from_json",
      "option2": -1,
      "subsection": {
         "suboption1": "subvalue1_from_json",
         "suboption2": 200
      }
     public class mysuboptions
      {
          public mysuboptions()
          {
              // set default values.
              suboption1 = "value1_from_ctor";
              suboption2 = 5;
          }

          public string suboption1 { get; set; }
          public int suboption2 { get; set; }
      }
//第三个iconfigureoptions<toptions>注入服务
         services.configure<mysuboptions>(configuration.getsection("subsection"));
    //otherpages/page1              
     public page1model(
            iconfiguration configuration,
            ioptionsmonitor<myoptionswithdelegateconfig> optionsaccessorwithdelegateconfig,
            ioptionsmonitor<myoptions> optionsaccessor,
            ioptionsmonitor<mysuboptions> suboptionsaccessor
          )
        {
        
            _optionswithdelegateconfig = optionsaccessorwithdelegateconfig.currentvalue;
            _options = optionsaccessor.currentvalue;
            _suboptions = suboptionsaccessor.currentvalue;
            configuration = configuration;
        }

        public iconfiguration configuration { get; }
        private readonly myoptions _options;
        private readonly myoptionswithdelegateconfig _optionswithdelegateconfig;
        private readonly mysuboptions _suboptions;
       // onget方法
      suboptions = $"suboption1 = {_suboptions.suboption1}, suboption2 = {_suboptions.suboption2}"
      //运行应用时,onget 方法返回显示子选项类值的字符串:
      // mysuboptions实例取值如下:
      suboption1 = subvalue1_from_json,suboption2 = 200

    

  1.5 iconfigurenamedoptions选项命名

    iconfigurenamedoptions:是用于对选项类在注入服务时,进行命名。下面是把myoptions选项类注入到服务,并取了别名named_options_1。 如下所示:

      services.configure<myoptions>("named_options_1", configuration);
    //在要使用的页面,如下所示:
    private readonly myoptions _named_options_1;
    public indexmodel(
        ioptionssnapshot<myoptions> namedoptionsaccessor)
    {
        _named_options_1 = namedoptionsaccessor.get("named_options_1");
    }
     // ioptionssnapshot源码
      public interface ioptionssnapshot<out toptions> : ioptions<toptions> where toptions : class, new()
      {
          //
          // 摘要:
          //     returns a configured toptions instance with the given name.
          toptions get(string name);
      }

 

  1.6 configureall 

    上面介绍的选项类,在注入服务时都是使用的services.configure,它是针对选项类的当前实例,例如:在page1和page2都使用了实例myoptions( private readonly myoptions _options)但它们属于不同的实例。 

      //使用 configureall 方法配置所有选项实例
            services.configureall<myoptions>(myoptions =>
            {
                //所有myoptions实例配置 option1的值
                myoptions.option1 = "configureall replacement value";
            });
      //添加代码后运行示例应用将产生以下结果:
      named_options_1: option1 = configureall replacement value, option2 = -1
      named_options_2: option1 = configureall replacement value, option2 = 5

 

  总结:

         选项模式是对configuration配置的功能扩展,主要用于把json文件序列化到.net类(选项类)。通过注入services. configure或services.configureall把选项类注入到服务并绑定到configuration上。 选项这篇还有其它功能如:选项后期配置( ipostconfigureoptions), 启动期间访问选项, 选项验证等,详细了解查看官网

 

参考文献

官方资料: