我们正在将一个项目从.Net Framework 4.6.2迁移到.Net Core 2.0。我遇到的情况是,一个接口由多个类实现,所有这些实现都必须注入到使用方的客户端中,并以某种顺序执行(这里的顺序和类名是在运行时从配置中选择的)。我正在注入IServiceProvider来解析使用类构造器中的这些实现,但是在构建对象时遇到了StackOverflowException。

需要说明的是,所有这些类都实现一个接口,并且它们的实例必须注入到使用类中。 .Net Core 2.0提供的默认DI容器不支持对实现相同接口的多个类进行named(类名)或typed(类类型)注入,这与其他DI选项(如Unity)(我们以前的容器)所支持的方式相同。

为了解决这个问题,我注入了IServiceProvider并将其包装在另一个类中,该类构建所有实例,然后根据类类型或类名称过滤所需的实例。

但是,当我尝试构建所有这些实例时,运行时将引发StackOverFlowException。

注意-所有类都已在Transient Scope中注册,并且不能为每个类创建单独的接口并注入它们。

我的IServiceProvider包装器-

public class TypedImplementationDependencyInjector
{
    private readonly IServiceProvider _serviceProvider = null;

    public TypedImplementationDependencyInjector(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public T ResolveImplementation<U, T>() where T : class, U
    {
        if (typeof(U).IsInterface)
        {
            var services = _serviceProvider.GetServices<U>();
            var typedImplementation = services.FirstOrDefault(o => o.GetType() == typeof(T)) as T;
            return typedImplementation;
        }

        return default(T);
    }

public T ResolveImplementation<T>(Type type)
    {
        if (type == null)
            throw new TypeLoadException("Supplied type was null or empty");

        if (typeof(T).IsInterface)
        {
            var services = _serviceProvider.GetServices<T>();
            var typedImplementation = services.FirstOrDefault(o => o.GetType() == type);
            return typedImplementation;
        }

        return default(T);
    }

    public T ResolveImplementation<T>(string assemblyName, string namespacename, string classname)
    {
        if (typeof(T).IsInterface)
        {
            Type type = Type.GetType($"{namespacename}.{classname}, {assemblyName}", true, true);
            return ResolveImplementation<T>(type);
        }

        return default(T);
    }
}


我正在实施的通用接口

public interface IEntityOperationCommand
{
    void Execute(EntityOperationModel operationModel);
}


我的消费类可以解决这些依赖关系-

public class EntityOperationProvider
{
    private readonly IEntityOperationCommand _TWCommandPrepare = null;
    private readonly IEntityOperationCommand _TWCommandCreateDetails = null;
    private readonly IEntityOperationCommand _TWCommandPostCreation = null;
    private readonly IEntityOperationCommand _TWCommandRaiseEvents = null;
    private readonly IEntityOperationCommand _TWCommandNotification = null;
    private readonly TypedImplementationDependencyInjector _implementationDependencyInjector = null;

    private const string assemblyName = "__assembly_name__";
    private const string namespaceName = "__namespace__";


    public EntityOperationProvider(TypedImplementationDependencyInjector implementationDependencyInjector)
    {
        _implementationDependencyInjector = implementationDependencyInjector;

        _TWCommandPrepare = _implementationDependencyInjector.ResolveImplementation<IEntityOperationCommand>(assemblyName, namespaceName, "PrepareEntity");
        _TWCommandCreateDetails = _implementationDependencyInjector.ResolveImplementation<IEntityOperationCommand>(assemblyName, namespaceName, "CreateDetails");
        _TWCommandPostCreation = _implementationDependencyInjector.ResolveImplementation<IEntityOperationCommand>(assemblyName, namespaceName, "PostCreation");
        _TWCommandRaiseEvents = _implementationDependencyInjector.ResolveImplementation<IEntityOperationCommand>(assemblyName, namespaceName, "RaiseEvents");
        _TWCommandNotification = _implementationDependencyInjector.ResolveImplementation<IEntityOperationCommand>(assemblyName, namespaceName, "SendNotification");
    }
}


注入EntityOperationProvider时,其构造函数尝试构建依赖关系并引发StackOVerflowException。

我希望可以创建和注入EntityOperationProvider对象。

注-我无法解决导致StackOverFlowException的问题,没有循环依赖项(例如,需要RaiseEvents对象的PrepareEntity类,反之亦然)或自身依赖项(例如,试图递归创建自己的对象的CreateDetails)。任何帮助将不胜感激。

同样,如果有任何优雅的方式来注入类型化的依赖项(例如Unity的Dependency属性)而不是注入IserviceProivder,那也将有所帮助。

最佳答案

如果必须注入IServiceProvider,则设计存在问题,因为这是代码异味。

Asp.Net Core DI允许注册一个接口的多个实现。因此,它还允许通过IEnumerable<IInterface>将该集合注入到依赖类中

例如

public EntityOperationProvider(IEnumerable<IEntityOperationCommand> commands) {
    //...
}


在内部使用IServiceProvider.GetServices<T>()扩展名

从那里只需提取所需的实现即可

public class EntityOperationProvider {
    private readonly IEntityOperationCommand _TWCommandPrepare = null;
    private readonly IEntityOperationCommand _TWCommandCreateDetails = null;
    private readonly IEntityOperationCommand _TWCommandPostCreation = null;
    private readonly IEntityOperationCommand _TWCommandRaiseEvents = null;
    private readonly IEntityOperationCommand _TWCommandNotification = null;


    public EntityOperationProvider(IEnumerable<IEntityOperationCommand> commands) {
        _TWCommandPrepare = commands.OfType<PrepareEntity>().FirstOrDefault();
        _TWCommandCreateDetails = commands.OfType<CreateDetails>().FirstOrDefault();
        _TWCommandPostCreation = commands.OfType<PostCreation>().FirstOrDefault();
        _TWCommandRaiseEvents = commands.OfType<RaiseEvents>().FirstOrDefault();
        _TWCommandNotification = commands.OfType<SendNotification>().FirstOrDefault();
    }

    //...
}

关于c# - 如何使用默认的ASP.NET Core DI容器在类中注入(inject)单个接口(interface)的多个服务类实现,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53880625/

10-16 15:09