autofac 解析所有 ICommandHandler<ICommand,IMessageResult>

autofac resolve all ICommandHandler<ICommand,IMessageResult>

您好,在 .Net 中的 MessageDispatch 场景中,我注册了我所有的命令处理程序,如下所示:

builder.RegisterAssemblyTypes(commandsAssemblies)
.AsClosedTypesOf(typeof(ICommandHandler<,>))
.InstancePerRequest();

在我的 messageDispatcher 的 OnActivating 方法中,我想像这样用 messageDispatcher 注册 commandHandlers。

builder.RegisterType<MessageDispatcher>()
.As<IMessageDispatcher>().InstancePerRequest()
.OnActivating(e =>

{
 var handlers = e.Context.Resolve(IEnumerable<ICommandHandler<ICommand,IMessageResult>>);
    foreach (var handler in handlers)
    {
        e.Instance.RegisterCommandHandler(handler);
    }
......

commandHandler 的实现方式如下:

public class ActivateCampaignHandler : CommandHandler<ActivateCampaign,MessageResult>   
{
    ....

我的问题是 Resolve 不起作用。我可以看到处理程序已注册,但它自己和 ICommandHandler 只有 2 个服务

如何解决我所有的命令处理程序?

我可以看到 3 个检索 IEnumerable<ICommandHandler<,>> 的解决方案。

最简单的方法是引入一个非通用的 ICommandHandler 接口:

    public interface ICommandHandler { }
    public interface ICommandHandler<TCommand, TMessageResult>
        : ICommandHandler
        where TCommand : ICommand
        where TMessageResult : IMessageResult
    { }

    // register it this way 
    builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
            .AsClosedTypesOf(typeof(ICommandHandler<,>))
            .As<ICommandHandler>();

这是我推荐的解决方案,因为使用非通用接口可能更容易。

第二种解决方案包括使您的接口协变(使用 out 修饰符)以允许从 TestCommandHandler 转换为 ICommandHandler<ICommand, IMessageResult> 并将您的类型注册为 ICommandHandler<ICommand, IMessageResult>

    public interface ICommandHandler<out TCommand, out TMessageResult>
        where TCommand : ICommand
        where TMessageResult : IMessageResult
    { }

    // register this way
    builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
            .AsClosedTypesOf(typeof(ICommandHandler<,>))
            .As<ICommandHandler<ICommand, IMessageResult>>();

    // resolve this ways
    var commandHandlers = container.Resolve<IEnumerable<ICommandHandler<ICommand, IMessageResult>>>();
    Console.WriteLine(commandHandlers.Count());

最新的解决方案是创建你自己的 IRegistrationSource 它需要更多的工作,但它会避免将你的类型注册为 ICommandHandler<ICommand, IMessageResult> 并允许你解决类似的问题 ICommandHandler<ISpecificCommand, IMessageResult> (如果你 IRegistrationSource 实现当然允许)。

您可以查看 ContravariantRegistrationSource 了解如何制作您的。