我们正在将一个项目从.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/