使用IConfigureOptions来配置注入的依赖项
本文关键字:依赖 注入 配置 IConfigureOptions 使用 | 更新日期: 2023-09-27 18:09:11
我已经创建了一个ASP。. NET Core 1.0.1 WebApi项目,我试图在我的控制器中使用它之前,用一些自定义选项初始化注入的依赖项。在网上搜索之后,我找到了一些文章(在这里,在这里和在这里),解释如何使用IConfigureServices来做到这一点。看起来很简单!不幸的是,我不能让它工作,我也不知道为什么,我敢肯定这一定是一个简单的疏忽。
我创建了一个简单的项目,并添加了以下类来说明最基本的场景:
public class Tester
{
public void Initialize(TestOptions options)
{
//do something with options.
}
}
public class TestConfigurator : IConfigureOptions<TestOptions>
{
private Tester _tester;
public TestConfigurator(Tester tester)
{
_tester = tester;
}
public void Configure(TestOptions options)
{
_tester.Initialize(options);
}
}
public class TestOptions
{
}
'Tester'类被注入到Controller类的构造函数中:
[Route("api/[controller]")]
public class ValuesController : Controller
{
public ValuesController(Tester tester)
{
//do something with tester..
}
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
最后,我在Startup类的ConfigureServices中添加了以下配置:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddOptions();
services.AddMvc();
services.AddSingleton<Tester, Tester>();
services.AddSingleton<IConfigureOptions<TestOptions>, TestConfigurator>();
}
当我运行项目并调用'api/values'调用时,Tester类被创建并注入到ValuesController中,但TestConfigurator类从未被构造,因此类从未被初始化与options类。我错过了什么?
更新下面的答案当然都适用于这个简化的例子。现在我意识到我有点过于简化了,因为我使用的依赖项(此处为Tester)来自第三方库,所以我没有构造函数可以使用。将第三方类包装在一个扩展类中可以达到这个目的,但是如果有人有在不修改构造函数的情况下操作它的替代建议,那么我仍然愿意接受建议,谢谢。
好了,现在我明白了,我觉得所有的编辑都很愚蠢。
你用错了IOptions
,这让我很困惑。
实现自定义IConfigurationOptions<>
使您能够从数据库配置选项,或者只是使用不同的类(而不是lambda)
你要做的,是实例化一个基于这些选项的Tester类,这很好-但它不是IConfigureOptions<>
的工作。
为了初始化基于TestOptions
的Tester
类,你应该在Tester
类上创建一个构造函数来接收它,就像这样
public class Tester
{
public Tester(IOptions<TestOptions> options)
{
//do something with options.
}
}
和你想做的事情将会起作用
摘自Asp。Net Core配置文档,并适应您的示例
假设
public class TestOptions {
public string SomeOption { get; set; }
}
选项可以使用
IOptions<TOptions>
访问服务。
您可以尝试抽象Tester
并将其注册到服务集合。
public interface ITester {
//tester contract
}
public class Tester : ITester {
public Tester(IOptions<TestOptions> options) {
//do something with test options.
}
}
要设置
IOptions<TOptions>
服务,请调用AddOptions
在ConfigureServices
方法中启动时使用扩展方法。使用Configure<TOptions>
扩展方法配置选项。您可以使用委托或绑定选项来配置选项配置:
public void ConfigureServices(IServiceCollection services) {
services.AddApplicationInsightsTelemetry(Configuration);
// Setup options with DI
services.AddOptions();
// Configure TestOptions using config by installing Microsoft.Extensions.Options.ConfigurationExtensions
services.Configure<TestOptions>(Configuration);
// Configure TestOptions using code
services.Configure<TestOptions>(testOptions => {
testOptions.SomeOption = "value1_from_action";
});
// Add framework services.
services.AddMvc();
// Add your services.
services.AddSingleton<ITester, Tester>();
}
最后重构控制器,使其依赖于抽象而不是具体。
[Route("api/[controller]")]
public class ValuesController : Controller {
public ValuesController(ITester tester) {
//do something with tester..
}
// GET api/values
[HttpGet]
public IEnumerable<string> Get() {
return new string[] { "value1", "value2" };
}
}
teststoptions应该来自哪里?您是否试图从设置文件中自动映射它?我认为你是过度思考这应该如何工作,除非有一些原因,你必须使用initialize
而不是构造函数注入。
你所要做的就是为测试人员提供一些选择,对吗?
如果是,只需使用基本的IOptions
功能-不需要使用IConfigureOptions
public class Tester
{
private TestOptions _options;
public Tester(IOptions<TestOptions> options)
{
_options = options.Value;
}
}
// don't need this anymore
/* public class TestConfigurator : IConfigureOptions<TestOptions>
{
private Tester _tester;
public TestConfigurator(Tester tester)
{
_tester = tester;
}
public void Configure(TestOptions options)
{
_tester.Initialize(options);
}
}
*/
public class TestOptions
{
}
然后使用下面两种方法中的一种来配置这些选项(取决于它是来自config还是必须手动构建)。
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddOptions();
services.AddMvc();
services.AddSingleton<Tester, Tester>();
// Configure TestOptions using config
services.Configure<TestOptions>(Configuration);
// Configure MyOptions using code
services.Configure<TestOptions>(testOptions =>
{
// initialize them here, e.g. testOptions.Foo = "Bar"
});
}