1

我想为我的 Open Generic ICommandHandler 创建一个基于 T 的 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 时识别 CommandHandlers,并以某种方式识别 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();

但不是喜悦似乎不起作用。它可以编译,但现在没有注册 CommandHandlers,即使是那些继承自 ConsultantCommand 的。我认为我的语法都是错误的

4

2 回答 2

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>的所有服务注册为. 您必须使用基本类型,否则您将无法一次解析所有处理程序。没有任何方法可以“解析从该基类型派生的所有服务”。也没有办法解决开放泛型列表。TConsultantCommandICommandHandler<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像你使用单个服务一样工作。

于 2012-11-30T17:41:17.567 回答
1

你要:

builder.RegisterAssemblyTypes(assemblies)
       .AsClosedTypesOf(typeof(ICommandHandler<>))
       .AsSelf()
       .AsImplementedInterfaces()
       .InstancePerHttpRequest();
于 2012-11-30T14:12:48.987 回答