我有一个通用服务,我注册如下:
serviceProvider.AddSingleton(typeof(IMyService<>), typeof(MyService<>));
效果很好。它使用 T = 被注入的类来注入服务。到目前为止一切顺利。
public class MyService<T> : IMyService<T>
{
public MyService(string myParameter)
{
// do something with T and myParameter.
}
}
现在我想在注册时向构造函数传递一个参数。
如何将参数传递给通用服务?
是否存在类似下面的代码?
serviceProvider.AddSingleton(typeof(IMyService<>), typeof(MyService<>), "SomeStringValue");
如果不是,最好的解决办法是什么?
诸如字符串和整数之类的原始值不能轻易地注册到容器中,因为它们的含义是不明确的。以下内容实际上不起作用:
// Would not really work
services.AddSingleton("SomeStringValue");
services.AddSingleton(typeof(IMyService<>), typeof(MyService<>));
但是你也不能使用开放泛型类型注册委托:
// Would certainly not really work
services.AddSingleton(typeof(IMyService<>), sp => new MyService<???("SomeStringValue"));
因此,您可以单独注册每个封闭类型:
services.AddSingleton<IMyService<A>>(new MyService<A>("SomeStringValue"));
services.AddSingleton<IMyService<B>>(new MyService<B>("SomeStringValue"));
但这可能不太方便,特别是当您有许多不同的封闭版本,或者定期添加新版本时。
在我看来,这种情况下最好的解决方案是消除字符串引起的歧义,并将该字符串包装在可以注册的包装类中:
services.AddSingleton(new MyServiceSettings("SomeStringValue"));
services.AddSingleton(typeof(IMyService<>), typeof(MyService<>));
这需要您更改
MyService<T>
的构造函数以接受 MyServiceSettings
而不是 string
:
public class MyService<T> : IMyService<T>
{
private readonly MyServiceSettings settings;
public MyService(MyServiceSettings settings)
{
this.settings = settings;
}
// use settings.SomeStringValue in the class
}
除了直接注入
MyServiceSettings
之外,ASP.NET Core 还允许您向构造函数提供 IOption<MyServiceSettings>
。这就是@Ralf 在评论中提到的内容。然而,正如我所见,这只会导致额外的复杂性,因为在这种情况下,您将注入一个允许访问 MyServiceSettings
参数对象的接口。这只是一个额外的间接级别,在大多数情况下是不需要的。不过,很高兴知道这个选项的存在。最好了解这些选项并了解它们的优点、缺点和后果。