简体   繁体   English

有没有办法在 asp.net 核心 2 依赖注入中注册和加载实现上一层接口的类?

[英]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派生的IExpirableAIExpirableB 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM