c# - 在 Startup.ConfigureServices 方法期间访问依赖注入对象
问题描述
我有一个 ASP.NET Core 3 应用程序,并且正在使用 AzureAD 进行身份验证。我的 Startup.ConfigureSerivces 方法中有以下几行,其目的是在附加 cookie 时执行一些业务规则。
services.Configure<CookiePolicyOptions>(options => {
options.CheckConsentNeeded = ctx => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
options.OnAppendCookie = ctx => {
var svc = ctx.Context.RequestServices.GetRequiredService<IUserInformationService>();
// do something with svc
};
});
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => {
Configuration.Bind("AzureAd", options);
});
这很好用,我得到了方法IUserInformationService
中预期的注入对象,OnAppendCookie
AzureAD 信息取自 appsettings.json。
然而,最近,有关 AzureAD 租户的信息不能驻留在 appsettings.json 中,而我现在必须查阅数据库。我有一个已经查询数据库并获取 AD 设置的服务。就像是:
public interface IAzureADConfiguration {
void Configure(AzureADOptions options);
}
但是,在调用AddAzureAD
. 我想要的是这样的:
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => {
var svc = ???
svc.Configure(options);
Configuration.Bind("AzureAd", options);
});
因为我无法像HttpContext
在. 有没有办法在这个阶段获得注入的对象?我不想对实例进行硬编码,因为此要求将来可能会发生变化(即添加另一种方法来配置我获取 Azure 广告设置的位置)。提前致谢!AddAzureAD
OnAppendCookie
解决方案
选项 1:配置回调
感谢@Nkosi 指出相关文档:使用 DI 服务配置选项
他们的回答让我开始走上正轨,但提供的代码示例对我不起作用,因为它没有考虑命名选项(AzureAD 配置使用的选项)。在弄清楚这一点并简化一点之后,我最终得到了以下内容......
对于AzureADOptions
,最好的选择似乎是在提供给AddAzureAD
. 两个回调将传递相同的AzureADOptions
实例,因此现有回调可以保持原样加载“基本”值,并且配置后回调可以根据需要覆盖它们。
// Configure Azure AD to load settings from the app config.
// This is unchanged (apart from syntax) from the original question.
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
// Add a post-configure callback to augment the app config-provided values
// with service-provided values.
services.AddOptions<AzureADOptions>(AzureADDefaults.AuthenticationScheme)
.PostConfigure<IAzureADConfiguration>((options, service) =>
service.Configure(options));
如果您不想从应用配置中加载基值,只需替换Configuration.Bind("AzureAD", options)
为空块 ( { }
)。
AddAzureAD
使用命名选项实例,因此请确保将相同的名称传递给PostConfigure
和AddAuthentication
。如果两个地方没有使用相同的名称,则配置后回调将不会配置正确的选项实例(或根本不会运行)。
注意:如果有人想使用这个答案来配置 Azure AD 以外的东西......当没有注册现有的选项实例或回调时,您应该使用Configure
方法而不是PostConfigure
,并且您可能不需要提供名称。
services.AddOptions<MyOptionsType>()
.Configure<IMyConfigurationService>((options, service) =>
service.Configure(options));
选项 2:自定义配置提供程序
虽然这不是您问题的直接答案,但它可能是激发您提出问题的问题的可行解决方案。
您可以实现自定义配置提供程序来从数据库加载设置,而不是编写配置服务。然后,您应该可以AddAzureAD
使用Configuration.Bind
.
文档中的示例new
创建了一个 EF 数据上下文,而不是由 DI 容器提供。这违背了 DI 的本能,但我认为在这种情况下很好。示例提供程序是一个小型且包含完善的子系统。它的数据库配置仍然是注入的(尽管不是通过 DI 容器),并且它仍然可以通过注入 EF 内存数据库的配置来进行单元测试。它没有任何其他依赖项可以换出。DI 容器不会增加太多价值——系统已经拥有它需要的所有依赖注入。
推荐阅读
- firebase - Firebase 设置了集合,但当我从颤动中引用它时没有检索并看到它
- amazon-web-services - 不同AZ中每个Web服务器的本地缓存-缓存复制/驱逐-Redis还是其他?
- reactjs - React UseState 在渲染后解析当前值
- html - 将 HTML 元素转换为 PDF(支持 utf-8)
- neo4j - Neo4j - 使用其他列表更新列表的问题
- assembly - Cortex M0+ MSP/PSP 上下文切换
- javascript - 如果选择了选择标签中的选项,如何创建元素
- python - Flask 无法捕获 404 错误,由于某种原因,它在尝试处理时返回 500 错误
- node.js - curl 无法与使用 Nodejs v14.16.0 tls.createSecureContext 创建的 https 服务器握手
- javascript - 我应该使用哪个组件或函数?