自1.0版之前,ASP.NET Core已使用“ 选项”模式配置强类型设置对象。从那时起,该功能获得了更多功能。例如,引入了ASP.NET Core 1.1 IOptionsSnapshot,它允许在基础IConfigurationRoot更改时(例如,在更改appsettings.json文件时)更新强类型选项。

在本文中,我将讨论您要在依赖项注入容器中注册强类型设置对象的多个实例时的选项。特别是,我展示了如何使用命名选项以不同的名称注册每个已配置的对象。

我将首先回顾一下您通常如何将选项模式与强类型设置,IOptions<T>界面和IOptionsSnapshot<T>界面一起使用。然后,我将探讨三种可能的方式来在DI容器中注册多个强类型设置的实例。

使用强类型设置

选项模式通过将POCO对象绑定到对象来允许使用强类型设置IConfiguration。我在最近的文章中介绍了此过程,因此在这里我会相对简短。

我们将从一个强类型的设置对象开始,您可以将其绑定到配置并注入到您的服务中:

public class SlackApiSettings
{
public string WebhookUrl { get; set; }
public string DisplayName { get; set; }
}

您可以绑定,要在配置部分Startup.ConfigureServices使用Configure<T>()

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

Configure方法将您的配置(从appsettings.json加载,环境变量,用户密码等)绑定到该SlackApiSettings对象。您还可以配置一个IOptions<>使用过载的对象Configure()接受一个Action<>,而不是一个配置部分,所以你可以在代码,例如使用配置

public void ConfigureServices(IServiceCollection services)
{
services.Configure<SlackApiSettings>(x => x.DisplayName = "My Slack Bot");
}

您可以SlackApiSettings通过将IOptions<SlackApiSettings>接口注入服务中来访问配置的对象:

public class SlackNotificationService
{
private readonly SlackApiSettings _settings;
public SlackNotificationService(IOptions<SlackApiSettings> options)
{
_settings = options.Value
} public void SendNotification(string message)
{
// use the settings to send a message
}
}

该属性上提供了已配置的强类型设置对象IOptions<T>.Value。另外,您也可以注入一个IOptionsSnapshot<T>

处理配置更改 IOptionsSnapshot<T>

到目前为止,我展示的示例可能是最典型的用法(尽管避免对IOptions<T>服务的依赖也很常见)。使用IOptions<T>强类型配置假定你的配置是固定的应用程序的生命周期。配置值被计算并绑定到您的POCO对象一次;例如,如果您以后更改appsettings.json文件,则更改不会显示在您的应用中。

就个人而言,我发现几乎所有我的应用程序都可以。但是,如果您确实需要支持配置的重新加载,则可以通过该IOptionsSnapshot<T>界面进行。该接口与该接口同时配置IOptions<T>,因此您无需执行任何其他操作即可在您的应用程序中使用它。只需将其注入您的服务中,然后访问该IOptionsSnapshot<T>.Value属性上配置的设置对象:

public class SlackNotificationService
{
private readonly SlackApiSettings _settings;
public SlackNotificationService(IOptionsSnapshot<SlackApiSettings> options)
{
_settings = options.Value
}
}

如果以后更改配置的值(例如,通过编辑appsettings.json文件),IOptionsSnapshot<T>则会在下一个请求时更新强类型的配置,您将看到新的值。请注意,配置值本质上具有“作用域”生存期-您将IOptionsSnapshot<T>在请求的生存期内看到相同的配置值。

并非所有配置提供程序都支持配置重载。例如,基于文件的提供程序都可以,但是环境变量提供程序则不可以。

重新加载配置在某些情况下可能很有用,但IOptionsSnapshot<T>还有另外一个窍门-名为options。我们将尽快与他们联系,但首先我们将探讨一个问题,您可能偶尔会遇到需要设置对象的多个实例的情况。

使用强类型设置对象的多个实例

我看到的典型用例IOptions<T>是细粒度的强类型设置。绑定系统使您可以轻松地为每个特定服务注入小型,集中的POCO对象。

但是,如果要配置多个具有相同属性的对象该怎么办。例如,考虑SlackApiSettings我到目前为止使用过的。要将消息发布到Slack,您需要一个WebHook URL和一个显示名称。在SlackNotificationService使用这些值将消息发送到特定的频道在农闲时调用SendNotification(message)

如果您想更新,SlackNotificationService以允许您将消息发送到多个渠道怎么办。例如:

public class SlackNotificationService
{
public void SendNotificationToDevChannel(string message) { }
public void SendNotificationToGeneralChannel(string message) { }
public void SendNotificationToPublicChannel(string message) { }
}

我添加方法这里三个不同的渠道DevGeneralPublic。问题是,我们如何为每个通道配置WebHook URL和显示名称?为了提供一些上下文,我假设我们将配置绑定到一个看起来像这样的单个appsettings.json文件:

{
"SlackApi": {
"DevChannel" : {
"WebhookUrl": "https://hooks.slack.com/T1/B1/111111",
"DisplayName": "c0mp4ny 5l4ck b07"
},
"GeneralChannel" : {
"WebhookUrl": "https://hooks.slack.com/T2/B2/222222",
"DisplayName": "Company Slack Bot"
},
"PublicChannel" : {
"WebhookUrl": "https://hooks.slack.com/T3/B3/333333",
"DisplayName": "Professional Looking name"
}
}

我们如何配置SlackNotificationService; 的设置有一些可用选项;我将在下面逐步介绍其中的三个。

1.创建一个父设置对象

提供每个通道设置的一种方法是扩展SlackApiSettings对象以包括每个通道设置的属性。例如:

public class SlackApiSettings
{
public ChannelSettings DevChannel { get; set; }
public ChannelSettings GeneralChannel { get; set; }
public ChannelSettings PublicChannel { get; set; } public class ChannelSettings
{
public string WebhookUrl { get; set; }
public string DisplayName { get; set; }
}
}

我创建了一个嵌套ChannelSettings对象,并为每个通道使用了一个单独的实例,并在顶层为每个通道使用了一个属性SlackApiSettings。配置这些设置很简单,因为我小心地匹配了appsettings.jsonSlackApiSettings层次结构:

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

在中,SlackNotificationService我们继续像以前一样注入单个设置对象:

public class SlackNotificationService
{
private readonly SlackApiSettings _settings;
public SlackNotificationService(IOptions<SlackApiSettings> options)
{
_settings = options.Value
}
}

这种方法的优点是易于理解正在发生的事情,并且它提供对每个通道设置的强类型访问。不利的一面是,增加对另一个频道的支持涉及到编辑SlackApiSettings类,在某些情况下这可能是不可能的(或不希望的)。

2.为每个通道创建单独的类

另一种方法是将每个通道的设置视为独立的。我们将分别配置和注册每个通道设置对象,然后将它们全部注入SlackNotificationService。例如,我们可以从一个抽象ChannelSettings类开始:

public abstract class ChannelSettings
{
public string WebhookUrl { get; set; }
public string DisplayName { get; set; }
}

并由此导出我们的各个频道设置:

public class DevChannelSettings: ChannelSettings { }
public class GeneralChannelSettings: ChannelSettings { }
public class PublicChannelSettings: ChannelSettings { }

要配置我们的选项,我们需要调用Configure<T>每个通道,传入要绑定的部分:

public void ConfigureServices(IServiceCollection services)
{
services.Configure<DevChannelSettings>(Configuration.GetSection("SlackApi:DevChannel"));
services.Configure<GeneralChannelSettings>(Configuration.GetSection("SlackApi:GeneralChannel"));
services.Configure<PublicChannelSettings>(Configuration.GetSection("SlackApi:PublicChannel"));
}

由于每个通道都有不同的设置对象,因此需要将它们分别注入SlackNotificationService

public class SlackNotificationService
{
private readonly DevChannelSettings _devSettings;
private readonly GeneralChannelSettings _generalSettings;
private readonly PublicChannelSettings _publicSettings; public SlackNotificationService(
IOptions<DevChannelSettings> devOptions
IOptions<GeneralChannelSettings> generalOptions
IOptions<PublicChannelSettings> publicOptions)
{
_devSettings = devOptions;
_generalSettings = generalOptions;
_publicSettings = publicOptions;
}
}

这种方法的优点是它允许您添加其他内容ChannelSettings而无需编辑现有类。如果需要的话,还可以注入一部分通道设置。但是,这也会使配置和使用起来变得更加复杂,每个新通道都需要一个新的options对象,一个新的调用Configure()以及修改的构造函数SlackNotificationService

3.使用命名选项

这将我们带到此后命名选项的焦点。命名选项听起来很像-它们是具有唯一名称的强类型配置选项。这样,您就可以在需要使用它们时按名称检索它们。

使用命名选项,您可以拥有多个独立配置的强类型设置实例。这意味着我们可以继续使用SlackApiSettings在文章开头定义的原始对象:

public class SlackApiSettings
{
public string WebhookUrl { get; set; }
public string DisplayName { get; set; }
}

区别在于我们如何配置它:

public void ConfigureServices(IServiceCollection services)
{
services.Configure<SlackApiSettings>("Dev", Configuration.GetSection("SlackApi:DevChannel"));
services.Configure<SlackApiSettings>("General", Configuration.GetSection("SlackApi:GeneralChannel"));
services.Configure<SlackApiSettings>("Public", Configuration.GetSection("SlackApi:PublicChannel"));
}

我们使用适当的配置部分(例如"SlackApi:DevChannel")分别配置每个通道,但我们也提供名称作为Configure<T>调用的第一个参数。此名称使我们能够从使用服务中检索特定配置。

要使用这些命名的选项,你必须注入IOptionsSnapshot<T>不能 IOptions<T>进入SlackNotificationService。这使您可以访问该IOptionsSnapshot<T>.Get(name)方法,可用来检索各个选项。

public class SlackNotificationService
{
private readonly SlackApiSettings _devSettings;
private readonly SlackApiSettings _generalSettings;
private readonly SlackApiSettings _publicSettings; public SlackNotificationService(IOptionsSnapshot<SlackApiSettings> options)
{
_devSettings = options.Get("Dev");
_generalSettings = options.Get("General");
_publicSettings = options.Get("Public");
}
}

这种方法的最大优点是,您无需创建任何新的类或方法来添加新的通道,只需配置一个新的命名SlackApiSettings选项对象。的构造函数SlackNotifictionService也保持不变。在缺点方面,它不是从明确SlackNotificationService的构造完全相同,其设置的对象是依赖。而且,您现在真正依赖于作用域IOptionsSnapshot<T>接口,因此,正如我之前所描述的那样,没有一种简单的方法来删除IOptions<>依赖关系

哪种方法最适合您,将取决于您的要求和总体偏好。选项1在许多方面都是最简单的,如果您不希望添加选项对象的任何额外实例,那么它可能是一个不错的选择。如果以后可能会添加其他实例,则选项2很方便,但是您可以控制它们的添加时间(因此可以根据需要更新使用者服务)。当您无法控制何时添加新选项时,选项3特别有用。例如,ASP.NET Core框架本身使用命名选项作为身份验证选项,其中可以使用核心框架不了解的新身份验证处理程序。

摘要

在这篇文章中,我概述了如何在ASP.NET Core中的选项模式下使用强类型设置。然后,我讨论了在ASP.NET Core DI容器中注册多个强类型设置实例的要求。我描述了实现此目的的三种可能方法:创建父设置对象,为每个设置创建单独的派生类或使用命名选项。命名的选项可以使用IOptionsSnapshot<T>接口使用Get(name)方法来检索。

转发自:https://andrewlock.net/using-multiple-instances-of-strongly-typed-settings-with-named-options-in-net-core-2-x/

[转]在.NET Core 2.x中将多个强类型设置实例与命名选项一起使用的更多相关文章

  1. C# 当前 .NET SDK 不支持将 .NET Core 2.1 设置为目标。请将 .NET Core 2.0 或更低版本设置为目标,或使用支持 .NET Core 2.1 的 .NET SDK 版本。

    报错信息: 严重性 代码 说明 项目 文件 行 禁止显示状态 错误 NETSDK1045 当前 .NET SDK 不支持将 .NET Core 2.2 设置为目标.请将 .NET Core 2.1 或 ...

  2. .NET Core 2.x中使用Named Options处理多个强类型配置实例

    来源: Using multiple instances of strongly-typed settings with named options in .NET Core 2.x 作者: Andr ...

  3. ASP.NET Core 请求/查询/响应参数格式转换(下划线命名)

    业务场景: 在 ASP.NET Core 项目中,所有的代码都是骆驼命名,比如userName, UserName,但对于 WebApi 项目来说,因为业务需要,一些请求.查询和响应参数的格式需要转换 ...

  4. .Net Core实战教程(二):设置Kestrel的IP与端口的几种方法

    .Net Core实战教程(二):设置Kestrel的IP与端口的几种方法 1.直接写在代码方式 Program.cs代码如下: using System; using System.Collecti ...

  5. 在.NET Core控制台应用程序中使用强类型配置

    想象一下,你写一个控制台应用程序,你想要从配置文件中以强类型方式读取配置. .NET Core 可以帮助我们解决. 通常我会在ASP.NET Core MVC中演示,但简单起见,只在控制台应用程序中演 ...

  6. ASP.NET Core轻松入门Bind读取配置文件到C#实例

    首先新建一个ASP.NET Core空项目,命名为BindReader 然后 向项目中添加一个名为appsettings.json的json文件,为什么叫appsettings呢?  打开Progra ...

  7. 当前 .NET SDK 不支持将 .NET Core 2.2 设置为目标。请将 .NET Core 2.1 或更低版本设置

    场景重现 Windows 10 操作系统 (64-bit) 已经安装 .NET Core SDKs 如下: C:\Users\taadis>dotnet --list-sdks 2.1.202 ...

  8. 关于.net core 在docker中监听地址设置踩坑记

    1.今天在做docker容器的时候发现如果将.net core 内部监听地址设置为localhost:8888. 2.在docker build -p 6444:8888 运行容器后,外部通过6444 ...

  9. .net core 3.0 Signalr - 02 使用强类型的Hub

    ## 强类型的优缺点 - 优点 强类型的Hub可以避免魔法函数名,相比弱类型更容易维护和发现问题,直接上代码 - 缺点 特么的得多些好几行代码 ## 代码 ### 接口定义 ``` C# /// // ...

随机推荐

  1. HttpClient发起Http/Https请求工具类

    <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcl ...

  2. TKinter当Label绑定bind事件时传参方法

    记录下tkinter的 当在label绑定bind事件时,遇到需要传参时的解决方法(因为有event存在 所以不能直接传参) https://www.cnblogs.com/liyuanhong/ar ...

  3. koa2跨域模块koa2-cors

    之前写了一个api在小程序里调用,但是我不想每次都打开小程序,所以想写一个简单的网页,但是遇到CORB的问题: 经尝试,jsonp等都没起作用,由于我后台是koa写的,发现koa2-cors库可以解决 ...

  4. FreeRTOS操作系统教程发布,支持F103,F407和F429,配套145个例子,1200页教程

    前言说明:1. 首先感谢大家对我们安富莱电子的支持. 2. FreeRTOS最大的优势就是开源免费,商业使用的话不需要用户公开源代码,也不存在任何版权问题,是当前小型嵌入式操作系统   市场使用率最高 ...

  5. Jrebel实现tomcat热部署,遇到的问题以及解决办法,详解

    我的安装的详细过程: 下载Jrebel:  https://github.com/ilanyu/ReverseProxy/releases/tag/v1.4 我的是winx64,所以选择如下的: 下载 ...

  6. JavaScript定时器方法

    一.setTimeout() 延迟性操作 window.setTimeout(function(){ console.log('派大星');//延迟了4秒 },4000); console.log(' ...

  7. 织女星开发板调试器升级为Jlink固件

    前言 为了能使用板载的FreeLink调试器来调试RISC-V内核,我们需要把默认的CMSIC-DAP固件,升级为JLink固件,固件升级之后,通过选择使用不同的驱动程序,来支持ARM内核还是RISC ...

  8. vuex动态引入store modules

    主要解决的问题每次建一个module需要自己去主index.js里面去注册 为了偷懒,也为了避免团队开发时同时对index.js 进行修改引发冲突 所以在index.js中 动态的对子目录和模块进行注 ...

  9. aop分层模型——aop是元编程的一种

    织入应用层—->待织入的附加功能 应用层 织入管理层—->使用元语和织入的功能进行编程 语言层 aop元语层---〉aop机制提供的高阶抽象概念. 解释层 aop引擎层—->维护的实 ...

  10. 保护模式中的PDE与PTE

    Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html 保护模式中的PDE与PTE 1. PDE与PTE的认知 我们在上一 ...