具有IEnumerable关系类型

时间:2017-10-20 15:23:10

标签: c# .net dependency-injection autofac

我在应用程序中使用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) { /* ... */ }
}

1 个答案:

答案 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());
    }
}