[英]is there a way to register and load classes implementing an interface one level up in asp.net core 2 dependency injection?
I have the following:我有以下内容:
interface IExpirable{
Expire(int id);
}
interface IExpirableA : IExpirable {
MethodA();
}
interface IExpirableB : IExpirable {
MethodB();
}
public class A : IExpirableA {//implement both methods Expire, and MethodA}
public class B : IExpirableB {//implement both methods Expire, and MethodB}
//in Startup.cs
services.AddScoped<IExpirableA , A>();
services.AddScoped<IExpirableB , B>();
//in HomeController.cs
private readonly IEnumerable<IExpirable> _expirables;
public HomeController(IEnumerable<IExpirable> expirables){
expirables = _expirables;
//here expirables is an empty array, however I would like it to contain instances of both A and B because
// A -> IExpirableA -> Expirable and likewise for B.
//is this something that can be accomplished without separately
//registering A and B with IExpirable each?
}
You could use factory methods to inject the same instance against multiple interfaces.您可以使用工厂方法针对多个接口注入相同的实例。
services.AddScoped<IExpirableA, A>();
services.AddScoped<IExpirableB, B>();
services.AddScoped<IExpirable>(p => p.GetService<IExpirableA>());
services.AddScoped<IExpirable>(p => p.GetService<IExpirableB>());
And you could write an extension method that uses reflection to discover and register all implemented interfaces.你可以编写一个扩展方法,使用反射来发现和注册所有实现的接口。
Just register those services by using its super interface IExpirable would work只需使用其超级接口IExpirable注册这些服务即可
services.AddScoped<IExpirable, A>();
services.AddScoped<IExpirable, B>();
However, be careful of this constructor但是,要小心这个构造函数
public HomeController(
IEnumerable<IExpirable> expirables,
IExpirableA expirableA,
IExpirableB expirableB)
{
}
If you don't want to get exceptions like this如果你不想得到这样的异常
InvalidOperationException: Unable to resolve service for type 'IExpirableA' while attempting to activate 'HomeController'.
You probably can enhance by this way您可能可以通过这种方式增强
services.AddScoped<IExpirable, A>();
services.AddScoped<IExpirable, B>();
services.AddDerivedExpirables(ServiceLifetime.Scoped);
with a IServiceCollection extension带有IServiceCollection扩展
public static class ServiceCollectionExtension
{
public static IServiceCollection AddDerivedExpirables(this IServiceCollection services, ServiceLifetime lifetime)
{
var scanAssemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
var interfaceTypes = scanAssemblies.SelectMany(o => o.DefinedTypes
.Where(x => x.IsInterface)
.Where(x => x != typeof(IExpirable)) // exclude super interface
.Where(x => typeof(IExpirable).IsAssignableFrom(x))
);
foreach (var interfaceType in interfaceTypes)
{
var types = scanAssemblies.SelectMany(o => o.DefinedTypes
.Where(x => x.IsClass)
.Where(x => interfaceType.IsAssignableFrom(x))
);
foreach (var type in types)
{
services.TryAdd(new ServiceDescriptor(interfaceType, type, lifetime));
}
}
return services;
}
}
This extension automatically registers all the other interfaces like IExpirableA
or IExpirableB
deriveds from super interface IExpirable .此扩展自动注册所有其他接口,例如从超级接口IExpirable派生的
IExpirableA
或IExpirableB
。 Try switch to your needs.尝试切换到您的需求。
There is an example in OptionsServiceCollectionExtensions.cs to show how AddOptions() works. OptionsServiceCollectionExtensions.cs 中有一个示例来展示AddOptions ()的工作原理。 Mayble helpful.
可能有帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.