温莎登记通用命令/命令处理程序(Windsor registration for generic c

2019-10-21 00:58发布

这里是我的情况:

public static class DomainCommandProcessor
{
    public static void Dispatch<T>(T command) where T : IDomainCommand
    {
        var serviceLocator = ServiceLocator.Current;

        var handler = serviceLocator.GetInstance<IDomainCommandHandler<T>>();
        if (handler != null)
            handler.Handle(command);
    }
}

public class FakeGenericCommand<T1, T2> : IDomainCommand
{
    public FakeGenericCommand(T1 first, T2 second)
    {
        First = first;
        Second = second;
    }

    public T1 First { get; private set; }
    public T2 Second { get; private set; }
}

public class FakeGenericCommandHandler<T1, T2> : IDomainCommandHandler<FakeGenericCommand<T1, T2>>
{
    public void Handle(FakeGenericCommand<T1, T2> command)
    {
        // something interesting
    }
}

用法:

DomainCommandProcessor.Dispatch(new FakeGenericCommand<string, string>("hi", "there"))

我不能让温莎注册权。 非常适合我所有的非通用命令的以下工作:

container.Register(Classes.FromAssemblyNamed(namespaceName)
    .BasedOn(typeof(IDomainCommandHandler<>))
    .WithService.AllInterfaces()
    .LifestyleTransient());

如果我直接注册的每个可能的实现,它的工作原理,但显然是次优的:

container.Register(
    Component.For<IDomainCommandHandler<FakeGenericCommand<string, string>>>()
        .UsingFactoryMethod(input => new FakeGenericCommandHandler<string, string>())
        .LifestyleTransient());

建议?

Answer 1:

你在这里什么是需要一个的教科书案例类型化厂 :我回答 ,我描述了如何使用它的一个问题


这个答案在很大程度上受到启发这篇文章 。

注册您的所有处理器

container.Register(Classes.FromAssemblyInThisApplication()
    .BasedOn<IDomainCommandHandler>()
    .WithServiceAllInterfaces());

声明一个工厂接口,将返回的处理程序的命令

public interface IDomainCommandHandlerFactory
{
    IDomainCommandHandler[] GetHandlersForCommand(IDomainCommand command);
}

您需要在命令类型链接到处理程序,您可以用自定义选择做:

public class HandlerSelector:ITypedFactoryComponentSelector
{
    public TypedFactoryComponent SelectComponent(MethodInfo method, Type type, object[] arguments)
    {
        var message = arguments[0];
        var handlerType = typeof(IDomainCommandHandler<>).MakeGenericType(message.GetType());
        return new TypedFactoryComponentCollection(handlerType.MakeArrayType(), new Arguments(arguments));
    }
}

然后告诉温莎你想有一个工厂,将返回IDomainCommandHandler<T> 别代码,工厂什么。

container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<ITypedFactoryComponentSelector>().ImplementedBy<HandlerSelector>());
container.Register(Component.For<IDomainCommandHandlerProvider>().AsFactory());

现在,您可以使用工厂来检索您的处理程序的命令

var provider = container.Resolve<IDomainCommandHandlerFactory>();
var msg = new Type2Message();
var msgHandler = provider.GetHandlersForCommand(msg.MessageType);

请注意,本例中的处理程序没有运行对命令本身,但有一个Execute的功能。 如果你想返回封闭的通用对象,你需要解决后投他们,因为你不能从一个方法返回不同的类型。

我建议你阅读的原创文章,因为它也包含了有关生活方式的更多信息,释放组件和其他有趣的点。


在这里,我使用其中I指定请求和作为通用部件的响应请求选择器的一个例子

protected override Type GetComponentType(MethodInfo method, object[] arguments)
{
    var request = arguments[0].GetType();
    var response = arguments[1] as Type;
    var handlerType = typeof(IHandlerOf<,>).MakeGenericType(request, response);
    return handlerType;
}

这里是该呼叫到工厂的结果(T是请求,R的响应)

var handler = handlerFactory.GetHandler<T>(input, typeof(R));
var requestType = input.GetType();
var responseType = typeof(R);
var handlerType = typeof(IHandlerOf<,>).MakeGenericType(requestType, responseType);
r = (R)handlerType.GetMethod("Handle").Invoke(handler, new object[] { input });


文章来源: Windsor registration for generic commands/command handlers