我可以根据Open Generic的类型为AutoFac创建一个键控服务

时间:2012-11-29 23:11:03

标签: dependency-injection inversion-of-control decorator autofac command-pattern

我想基于T为我的Open Generic ICommandHandler创建一个keyedService。当ICommandHandler有一个继承自ConsultantCommand的T时,我想注册一个ConsultatCommandHanlder键控服务

知道怎么做吗?或者如果有可能的话?我是AutoFac的新手并且正在努力。

我目前正在注册CommandHandler:

        //Register All Command Handlers
        builder.RegisterAssemblyTypes(assemblies)
          .As(
              t =>
              t.GetInterfaces()
               .Where(a => a.IsClosedTypeOf(typeof (ICommandHandler<>)))
               .Select(a => new KeyedService("commandHandler", a))).InstancePerHttpRequest();

如果可能,我猜我必须在获得Closed Type时识别CommandHandler,并以某种方式识别Command实现ConsultantCommand的那些。

我试过了:

        builder.RegisterAssemblyTypes(assemblies)
               .As(
                 t =>
                   t.GetInterfaces()
                    .Where(a => a.IsClosedTypeOf(typeof(ICommandHandler<>)) &&
                        a.GetGenericArguments()[0].IsSubclassOf(typeof(ConsultantCommand)))
                    .Select(a => new KeyedService("ConsultantCommandHandler", a))).InstancePerHttpRequest();

但是,快乐似乎并不起作用。它编译但现在没有注册CommandHandler甚至那些从ConsultantCommand继承的命令。我认为我的语法都错了

2 个答案:

答案 0 :(得分:1)

你想:

builder.RegisterAssemblyTypes(assemblies)
       .AsClosedTypesOf(typeof(ICommandHandler<>))
       .AsSelf()
       .AsImplementedInterfaces()
       .InstancePerHttpRequest();

答案 1 :(得分:1)

首先,您需要确保宣布您的ICommandHandler<T>支持协方差:

public interface ICommandHandler<out T> { }

out很重要,否则您将无法立即解决所有ConsultantCommand个处理程序。您还将获得Autofac例外。

接下来,使用Named扩展方法注册您的命名服务,而不是自己动手。语法如下所示:

builder.RegisterAssemblyTypes(assemblies)
       .Where(t =>
                t.IsClosedTypeOf(typeof(ICommandHandler<>)) &&
                t.GetInterfaces()[0]
                 .GetGenericArguments()[0]
                 .IsAssignableTo<ConsultantCommand>())
       .Named("name", typeof(ICommandHandler<ConsultantCommand>))
       .InstancePerHttpRequest();

它将ICommandHandler<T> T从[{1}}派生的所有服务ConsultantCommand注册为ICommandHandler<ConsultantCommand>。您必须使用基本类型,或者,您将无法一次解析所有处理程序。没有任何方法可以“解析从此基本类型派生的所有服务”。也无法解决开放式泛型列表。

解决处理程序列表后,您需要解析名为IEnumerable<T>的内容:

using(var scope = container.BeginLifetimeScope())
{
  var x =
    scope.ResolveNamed<IEnumerable<ICommandHandler<ConsultantCommand>>>("name");
}

当然,您正在使用InstancePerHttpRequest,所以它更像是:

var x =
  AutofacDependencyResolver
    .Current
    .RequestLifetimeScope
    .ResolveNamed<IEnumerable<ICommandHandler<ConsultantCommand>>>("name");

如上所述,您必须注册为封闭式通用,因为这不起作用:

// WON'T WORK:
scope.ResolveNamed<IEnumerable<ICommandHandler<>>>("name");

您可以根据需要修改注册。其余的注册扩展应该照常工作 - 如果你想将事情注册为已实现的接口或其他任何东西,它应该与RegisterAssemblyTypes一起工作,就像你使用单个服务一样。