• 【ASP.NET Core】选项类的依赖注入


    咱们继续上一个话题。先简单复习一下,根据老周前面文章的介绍,选项类体系的基本套路是通过 IOptionsFactory 来创建选项类实例的。而我们在服务容器(IServiceCollection)上是用Configure、PostConfigure 等扩展方法去配置选项类的(设置属性的值)。配置代码并不是立即执行,而是通过委托来让写代码的人自己设定属性值,最后向服务容器添加 IConfigureOptions、 IPostConfigureOptions、IValidateOptions 等关联服务。IOptionsFactory 通过依赖注入获得上述服务,并使用它们来设置选项类。

    本文重点说一下选项类的依赖注入——如何注入到其他类型中。这个当然是依靠构造函数(使用 Invoke 约定的中间件类除外)了(GetService、GetRequiredService 等方法也可以)。选项类自身不是直接添加到服务容器中,所以不能用于依赖注入。

    我们还得回过头去看一下 AddOptions 扩展方法的源代码。

       services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptions<>), typeof(UnnamedOptionsManager<>)));
       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<>)));

    其他的忽略不谈,我们一般用得多的是这三个:

    IOptions:单例模式,全场只创建一个实例。这个适用于只想读选项类信息的情形。

    IOptionsSnapshot:作用域模式,生命周期和一次HTTP请求相同。这个适用于选项有分组命名的情况,就是同一个选项类有多组设置时。

    IOptionsMonitor:这个也是单实例模式。既可用于单组选项类也可用于多组选项类。当与选项类绑定的配置(通常是配置文件,如 appsettings.json)更新时会自动产生通知。此时不用重启应用程序,刷新一下页面就能获取到新的信息。

     

    接下来就是实战阶段,咱们先准备一个选项类。

        public class DemoOptions
        {
            public string? AppTitle { get; set; }
            public uint MaxInstance { get; set; }
            public bool Locked { get; set; }
        }

    这个选项类仅用于演示,我是随便写的,没特殊含义,请不要恶意猜测其实际用途。

    接下来就很简单了。在应用程序初始化时咱们配置一下。

    复制代码
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddControllers();   // MVC无V
    // 配置选项类
    builder.Services.Configure(opt =>
    {
        opt.AppTitle = "山高皇帝远,坏事干翻天";
        opt.MaxInstance = 12;
        opt.Locked = false;
    });
    var app = builder.Build();
    // 添加 MVC 路由
    app.MapControllerRoute("Lily", "{controller=Main}/{action=Work}");
    
    app.Run();
    复制代码

    随后,咱们定义个控制器类,就可以用了。

    复制代码
        public class MainController : Controller
        {
            // 字段
            readonly IOptions _myOpt;
    
            // 构造函数接收赏赐
            public MainController(IOptions o)
            {
                _myOpt = o;
            }
    
            // 操作方法
            public ActionResult Work()
            {
                DemoOptions theOption = _myOpt.Value;
                string s = "App Title: " + theOption.AppTitle +
                           $"\nMax Instance: {theOption.MaxInstance}\n" +
                           $"Locked: {theOption.Locked}";
                return Content(s);
            }
        }
    复制代码

    运行后,如果看到以下内容,说明你的代码没写错。

     

     

    如果,选项有不同的分组。比如叫 g1 和 g2。

    复制代码
    builder.Services.Configure("g1", opt =>
    {
        opt.AppTitle = "鸭梨山小";
        opt.MaxInstance = 5;
        opt.Locked = true;
    });
    builder.Services.Configure("g2", opt =>
    {
        opt.AppTitle = "无头公鸡";
        opt.MaxInstance = 15;
        opt.Locked = false;
    });
    复制代码

    其实,未分组的选项类也是有一个默认组名的,叫空白字符串(string.Empty),可从 Options.DefaultName 字段获取。

    选项分组后,同一个选项类就拥有不同的配置方案。

    接下来的使用也不复杂。

    复制代码
        public class GpOptController : Controller
        {
            // 字段
            IOptionsSnapshot _myOpt;
            // 构造函数接受封赏
            public GpOptController(IOptionsSnapshot opt)
            {
                _myOpt = opt;
            }
    
            // 操作方法
            // g 是分组名称
            public ActionResult GetInfo(string g)
            {
                DemoOptions opt = _myOpt.Get(g);
                return Content(
                        $"App Title: {opt.AppTitle}\n" +
                        $"Max Instance: {opt.MaxInstance}\n" +
                        $"Locked: {opt.Locked}"
                    );
            }
        }
    复制代码

    注意 GetInfo 方法有个参数 g,用来筛选显示哪个分组的选项类(g1?g2?)。

    假如要显示 g1 的选项信息,就请求 http://SBHost:7337/gpopt/getinfo?g=g1。得到结果如下。

     

     同理,g2 的访问URL:https://BugHost/gpopt/getinfo?g=g2。结果如下。

     

     不要访问什么 g3、g4 的,因为没有这些分组,将得到一个带默认属性值的 DemoOptions 实例。

     

    最后,我们来看看 IOptionsMonitor。要想让 IOptionsMonitor 在关联的配置更改时获得更新通知,还需要实现 IOptionsChangeTokenSource,然后将其添加到服务容器中。内部默认实现的类是 ConfigurationChangeTokenSource。当配置文件被更改后会让 IOptionsMonitor 得到通知。实现 IOptionsChangeTokenSource 接口似乎有些复杂,一般我们不需要这样做。

    接下来我们把前面的代码改一下,在应用程序初始化时,用 appsettings.json 文件中的内容去配置选项类。

    builder.Services.Configure(builder.Configuration.GetSection("test"));

    配置 DemoOptions 类的节点名为“test”。打开 appsettings.json 文件,加上这个节点。

    复制代码
    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "AllowedHosts": "*",
      "test": {
        "appTitle": "纸糊的飞机",
        "maxInstance": 16,
        "locked": true
      }
    }
    复制代码

    定义一个控制器类,用于获取选项类信息。

    复制代码
        public class WKController : Controller
        {
            // 字段
            readonly IOptionsMonitor _mntOpt;
            // 构造函数接受册封
            public WKController(IOptionsMonitor o)
            {
                _mntOpt = o;
            }
    
            // 操作方法
            public ActionResult Do()
            {
                DemoOptions opt = _mntOpt.CurrentValue;
                return Content(
                        $"App Title: {opt.AppTitle}\n" +
                        $"Max Instance: {opt.MaxInstance}\n" +
                        $"Locked: {opt.Locked}"
                    );
            }
        }
    复制代码

    运行应用程序,定位到URL:https://localhost/wk/do,得到如下结果。

     

    不用关闭应用程序,打开 appsettings.json 文件,把它改一下。

      "test": {
        "appTitle": "茶叶青",
        "maxInstance": 36,
        "locked": true
      }

    然后保存文件,回面 web 页面,刷新一下,就能看到新的配置了。

     

    应用程序在不重启的情况下加载最新的选项配置。 

     

    今天的水文到此就结束了,咱们下次再聊。

     

  • 相关阅读:
    unity UnityWebRequest application/x-www-form-urlencoded上传字符对
    http请求与响应,同步异步请求以及异步请求axios的配置
    微信小程序渲染的富文本里面除了img标签外什么都没有,该如何设置img的大小
    Java 框架的一些文件配置
    iTOP3A5000_7A2000开发板龙芯全国产处理器LoongArch架构核心主板
    VoLTE基础自学系列 | 什么是SIP和IMS中的Forking
    Flutter高仿微信-第29篇-单聊
    Nest.js项目小结1
    订单超时自动取消订单实现策略
    ArcGIS绘制地球
  • 原文地址:https://www.cnblogs.com/tcjiaan/p/16534361.html