告诉您手动构建IServiceProvider 以获取IOptions<T> 实例的所有其他答案都是危险,因为它们是错误(至少在 ASP .NET Core 3.0)!实际上,如果您今天使用这些答案,您将收到以下编译器警告:
从应用程序代码调用“BuildServiceProvider”会导致创建一个额外的单例服务副本。考虑将依赖注入服务等替代方案作为“配置”的参数。
正确的方法是实现这一点,在所有版本的 ASP.NET Core 中都安全可靠地工作,是实现自 .NET Core 1.0 以来就存在的 IConfigureOptions<TOptions> 接口 - 但它似乎很少有人知道how it makes things Just Work™。
例如,您想要添加一个自定义模型验证器,该验证器依赖于您的应用程序的其他服务之一。最初这似乎是不可能的 - 没有办法解决 IMyServiceDependency 因为您无权访问 IServiceProvider:
public class MyModelValidatorProvider : IModelValidatorProvider
{
public MyModelValidatorProvider(IMyServiceDependency dependency)
{
...
}
}
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
{
options.ModelValidatorProviders.Add(new MyModelValidatorProvider(??????));
});
}
但是IConfigureOptions<TOptions> 的“魔力”让它变得如此简单:
public class ConfigureMvcOptions : IConfigureOptions<MvcOptions>
{
private IMyServiceDependency _dependency;
public MyMvcOptions(IMyServiceDependency dependency)
=> _dependency = dependency;
public void Configure(MvcOptions options)
=> options.ModelValidatorProviders.Add(new MyModelValidatorProvider(_dependency));
}
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
...
// or scoped, or transient, as necessary for your service
services.AddSingleton<IConfigureOptions<MvcOptions>, ConfigureMvcOptions>();
}
基本上,您在ConfigureServices 中的Add***(***Options) 代表中所做的任何设置现在都移至您的IConfigureOptions<TOptions> 类的Configure 方法。然后,您以与注册任何其他服务相同的方式注册选项,然后离开!
如需更多详细信息,以及有关其在幕后如何运作的信息,请I refer you to the always-excellent Andrew Lock。