C# 如何在ConfigureServices内解析IOptions实例?
是否可以解析C# 如何在ConfigureServices内解析IOptions实例?,c#,asp.net-core,inversion-of-control,asp.net-core-mvc,C#,Asp.net Core,Inversion Of Control,Asp.net Core Mvc,是否可以解析IOptions的实例: 不要在Startup.ConfigureServices中使用IOptions或ioptionmonitor。由于服务注册的顺序,可能存在不一致的选项状态 您可以使用serviceCollection.BuildServiceProvider()手动创建服务提供程序,但这会导致警告: 从应用程序代码调用“BuildServiceProvider”会导致创建一个额外的单例服务副本。考虑诸如依赖注入服务之类的选项来“配置”参数。 我怎样才能做到这一点 publi
IOptions的实例:
不要在Startup.ConfigureServices中使用IOptions
或ioptionmonitor
。
由于服务注册的顺序,可能存在不一致的选项状态
您可以使用serviceCollection.BuildServiceProvider()
手动创建服务提供程序,但这会导致警告:
从应用程序代码调用“BuildServiceProvider”会导致创建一个额外的单例服务副本。考虑诸如依赖注入服务之类的选项来“配置”参数。
我怎样才能做到这一点
public void ConfigureServices(IServiceCollection services)
{
services.Configure<AppSettings>(
configuration.GetConfigurationSection(nameof(AppSettings)));
// How can I resolve IOptions<AppSettings> here?
}
public void配置服务(IServiceCollection服务)
{
服务。配置(
GetConfigurationSection(nameof(AppSettings));
//我如何解决这里的问题?
}
您是否正在寻找以下内容?您可以在代码中查看我的注释:
// this call would new-up `AppSettings` type
services.Configure<AppSettings>(appSettings =>
{
// bind the newed-up type with the data from the configuration section
ConfigurationBinder.Bind(appSettings, Configuration.GetConfigurationSection(nameof(AppSettings)));
// modify these settings if you want to
});
// your updated app settings should be available through DI now
//此调用将更新'AppSettings'类型
配置(appSettings=>
{
//用配置部分的数据绑定新的up类型
Bind(appSettings,Configuration.GetConfigurationSection(nameof(appSettings)));
//如果需要,请修改这些设置
});
//您更新的应用程序设置现在应该可以通过DI获得
如果您需要使用服务提供商手动解析服务,您可以使用此AddSingleton/AddScoped/AddTransient
重载:
// Works for AddScoped and AddTransient as well
services.AddSingleton<IBarService>(sp =>
{
var fooService = sp.GetRequiredService<IFooService>();
return new BarService(fooService);
}
为此,您需要Microsoft.Extensions.DependencyInjection
包
但是请注意,这会导致多个服务提供商实例,而这又可能导致多个单例实例
如果只需要绑定
ConfigureServices
中的一些选项,也可以使用bind
方法:
var appSettings = new AppSettings();
configuration.GetSection(nameof(AppSettings)).Bind(appSettings);
此功能可通过Microsoft.Extensions.Configuration.Binder软件包获得。实例化依赖于其他服务的类的最佳方法是使用添加XXX重载,该重载为您提供IServiceProvider。这样,您就不需要实例化中间服务提供者 以下示例显示如何在AddSingleton/AddTransient方法中使用此重载
services.AddSingleton(serviceProvider =>
{
var options = serviceProvider.GetService<IOptions<AppSettings>>();
var foo = new Foo(options);
return foo ;
});
services.AddTransient(serviceProvider =>
{
var options = serviceProvider.GetService<IOptions<AppSettings>>();
var bar = new Bar(options);
return bar;
});
services.AddSingleton(serviceProvider=>
{
var options=serviceProvider.GetService();
var foo=新foo(选项);
返回foo;
});
services.AddTransient(serviceProvider=>
{
var options=serviceProvider.GetService();
var bar=新的条形图(选项);
返回杆;
});
想帮助其他看起来一样但也使用Autofac的人
如果您想获取ILifetimeScope(即当前作用域的容器),则需要调用Configure(IAApplicationBuilder app)
中的app.ApplicationServices.GetAutofacRoot()
方法,这将返回可用于解析服务的ILifetimeScope实例
public void Configure(IApplicationBuilder app)
{
//app middleware registrations
//...
//
ILifetimeScope autofacRoot = app.ApplicationServices.GetAutofacRoot();
var repository = autofacRoot.Resolve<IRepository>();
}
public void配置(IApplicationBuilder应用程序)
{
//应用程序中间件注册
//...
//
ILifetimeScope autofacRoot=app.ApplicationServices.GetAutofacRoot();
var repository=autofacRoot.Resolve();
}
所有其他告诉您手动构建iSeries Provider
以获取IOptions
实例的答案都是危险的,因为它们是错误的(至少从ASP.NET Core 3.0开始)!事实上,如果您今天使用这些答案,您将得到以下编译器警告:
从应用程序代码调用“BuildServiceProvider”会导致创建一个额外的单例服务副本。考虑诸如依赖注入服务之类的选项来“配置”参数。
正确的方法是实现这一点,在ASP.NET Core的所有版本中都能安全可靠地工作,它是实现自.NET Core 1.0以来就存在的接口-但似乎知道的人太少了
例如,您希望添加一个自定义模型验证器,该验证器依赖于应用程序的其他服务之一。起初这似乎是不可能的-无法解决IMyServiceDependency
,因为您无法访问iSeries Provider
:
public class MyModelValidatorProvider : IModelValidatorProvider
{
public MyModelValidatorProvider(IMyServiceDependency dependency)
{
...
}
}
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
{
options.ModelValidatorProviders.Add(new MyModelValidatorProvider(??????));
});
}
但是IConfigureOptions
的“魔力”让它变得如此简单:
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>();
}
公共类配置MVCOPIONS:IConfigureOptions
{
私有IMyServiceDependency_dependency;
公共mymvcopions(IMyServiceDependency)
=>_dependency=dependency;
公共无效配置(MVCOPIONS选项)
=>options.ModelValidatorProviders.Add(新的MyModelValidatorProvider(_依赖项));
}
public void配置服务(IServiceCollection服务)
{
services.AddControllers();
...
//或范围化或暂时性,视服务需要而定
services.AddSingleton();
}
本质上,您在ConfigureServices
中的Add***(***选项)
委托中所做的任何设置现在都被移动到IConfigureOptions
类的Configure
方法中。然后,您注册选项的方式与注册任何其他服务的方式相同,然后就可以开始了
有关更多详细信息以及如何在后台工作的信息,请参见。如果需要在应用程序的另一部分中解决此服务,该怎么办?我确信这不是全部在ConfigureServices()中完成的,对吗?@Ray然后您可以使用默认的依赖项注入机制,例如构造函数注入。这个问题特别是关于在
ConfigureServices
方法中解析服务的问题。@pcdev这样做时会得到NULL,然后尝试解析实例。您必须首先添加服务,但在添加服务的方法没有
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>();
}