我在应用程序中使用Autofac来管理依赖项。我有一个接口和许多接口的实现。实际的实现在容器中注册为键控服务。
我想要做的是解决使用特定键类型注册的每个服务(因此IEnumerable)的实例(因此键入的注册)。
如果我直接使用容器,它可以工作:
container.ResolveKeyed<IEnumerable<IService>>(MyServiceGroups.Group1);
// This returns the a list of IService implementor objects, that were previously registered with the given key
但是,如果我在构造函数中使用[KeyFilter]
属性来解析依赖关系,它就没有效果,我得到所有已注册服务的列表,无论键控注册使用的值是什么。
public class MyBigService([KeyFilter(MyServiceGroups.Group1)] services)
{
// here services contains one from every type, not just the ones registered with that particular key
}
我做错了什么?有没有办法让这项工作?我可能可以组合Func和IEnumerable类型并手动解决容器(因为它可行),但我想保留这个结构。
修改 代码的具体示例:
public class SubserviceModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<SubServiceA>().As<ISubService>().Keyed<ISubService>(ServiceType.TypeX);
builder.RegisterType<SubServiceB>().As<ISubService>().Keyed<ISubService>(ServiceType.TypeX);
builder.RegisterType<SubServiceC>().As<ISubService>().Keyed<ISubService>(ServiceType.TypeY);
builder.RegisterType<SubServiceD>().As<ISubService>().Keyed<ISubService>(ServiceType.TypeY);
}
}
public class ServiceModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<Service1>();
builder.RegisterType<Service2>();
}
}
public abstract class ServiceBase
{
public ServiceBase(IEnumerable<ISubService> subServices) {/*...*/}
}
public class Service1
{
public ServiceA([KeyFilter(ServiceGroup.ServiceTypeX)] IEnumerable<ISubService> subServices)
: base(subServices) { /* ... */ }
}
public class Service2
{
public ServiceB([KeyFilter(ServiceGroup.ServiceTypeY)] IEnumerable<ISubService> subServices)
: base(subServices) { /* ... */ }
}
答案 0 :(得分:0)
好吧,我现在想出了一个答案。我基本上做了我期望Autofac会做的事情:遍历所有参数,并使用当前的解析上下文来解决它。我自己检查参数属性,如果它在那里,我解析为一个键控服务,否则,我只是解决。我还创建了一个很好的小扩展方法来隐藏这个注册的复杂性:
public static class AutofacExtensions
{
public static IRegistrationBuilder<TService, SimpleActivatorData, SingleRegistrationStyle> RegisterModulePageViewModel<TService>(this ContainerBuilder builder) where TService : ServiceBase
{
return builder.Register(ctx => CreateInstance<TService>(ctx));
}
private static TService CreateInstance<TService>(IComponentContext ctx)
{
var ctor = typeof(TService).GetConstructors().Single();
List<object> parameters = new List<object>();
foreach (var param in ctor.GetParameters())
{
var keyAttribute = param.GetCustomAttribute<KeyFilterAttribute>();
if (keyAttribute != null)
{
parameters.Add(ctx.ResolveKeyed(keyAttribute.Key, param.ParameterType));
}
else
{
parameters.Add(ctx.Resolve(param.ParameterType));
}
}
return (TService)ctor.Invoke(parameters.ToArray());
}
}