【问题标题】:How to use composite handler with nested open generic?如何使用具有嵌套开放泛型的复合处理程序?
【发布时间】:2014-05-22 15:09:39
【问题描述】:
public interface IMessage { }
public interface ICommand : IMessage { }
public interface IEvent : IMessage { }

public interface IMessageHandler<T> {
    void Handle(T message);
}

public class ItemCreatedEvent : IEvent {
    public string Name { get; set; }
}

public class ValidateMessageEnvelope<TMessage> {
    public TMessage Message { get; set; }
    public ValidateMessageEnvelope(TMessage message){
        Message = message;
    }
}

public class ValidateMessageEnvelopeHandler<TMessage> 
    : IMessageHandler<ValidateMessageEnvelope<TMessage>> {
    private readonly IMessageHandler<TMessage> _innerHandler;
    public ValidateMessageEnvelopeHandler(IMessageHandler<TMessage> innerHandler){
        _innerHandler = innerHandler;
    }
    public void Handle(ValidateMessageEnvelope<TMessage> message){
        _innerHandler.Handle(message.Message);
    }
}

public class SecureMessageEnvelope<TMessage> {
    public TMessage Message { get; set; }
    public string UserToken { get; set; }
    public SecureMessageEnvelope(TMessage message, string userToken){
        Message = message;
        UserToken = userToken;
    }
}

public class SecureMessageEnvelopeHandler<TMessage> 
    : IMessageHandler<SecureMessageEnvelope<TMessage>>
{
    private readonly IMessageHandler<TMessage> _innerHandler;
    public SecureMessageEnvelopeHandler(IMessageHandler<TMessage> innerHandler){
         _innerHandler = innerHandler;
    }
    public void Handle(SecureMessageEnvelope<TMessage> message){
         _innerHandler.Handle(message.Message);
    }
}

public class MessageLogDecorator<TMessage> : IMessageHandler<TMessage> 
    where TMessage : IEvent {
    private readonly IMessageHandler<TMessage> _messageHandler;
    public MessageLogDecorator(IMessageHandler<TMessage> messageHandler) {
        _messageHandler = messageHandler;
    }
    public void Handle(TMessage message){
        Console.WriteLine("Event Log: {0}",JsonConvert.SerializeObject(message));
        _messageHandler.Handle(message);
    }
}

public class CompositeMessageHandler<TMessage> : IMessageHandler<TMessage> {
    private readonly IEnumerable<IMessageHandler<TMessage>> _handlers;
    public CompositeMessageHandler(IEnumerable<IMessageHandler<TMessage>> handlers){
        _handlers = handlers;
    }
    public void Handle(TMessage message) {
        foreach (var messageHandler in _handlers) {
            messageHandler.Handle(message);
        }
    }
}

public class LogService :IMessageHandler<ItemCreatedEvent> {
    public void Handle(ItemCreatedEvent message) {}
}

public class ProjectionService: IMessageHandler<ItemCreatedEvent> {
    public void Handle(ItemCreatedEvent message) { }
}

public static class Extensions{
    public static SecureMessageEnvelope<TMessage> AsSecure<TMessage>(
        this TMessage message, string userToken){
        return new SecureMessageEnvelope<TMessage>(message, userToken);
    }
    public static ValidateMessageEnvelope<TMessage> AsValidatable<TMessage>(
        this TMessage message){
        return new ValidateMessageEnvelope<TMessage>(message);
    }
}

注册:

Container.RegisterManyForOpenGeneric(typeof (IMessageHandler<>),
    Container.RegisterAll,
    Assembly.GetExecutingAssembly());

// handle all ValidateMessageEnvelope<TMessage> messages
Container.RegisterOpenGeneric(typeof(IMessageHandler<>),
    typeof(ValidateMessageEnvelopeHandler<>)); 

// handle all SecureMessageEnvelope<TMessage> messages
Container.RegisterOpenGeneric(typeof(IMessageHandler<>),
    typeof(SecureMessageEnvelopeHandler<>));

// handle all IEvent messages
Container.RegisterDecorator(typeof(IMessageHandler<>), 
    typeof(MessageLogDecorator<>));

事件调用

var ev = new ItemCreatedEvent().AsSecure("token/1").AsValidatable();
    var handlerType = typeof(IMessageHandler<>).MakeGenericType(ev.GetType());
    foreach (dynamic handler in _container.GetAllInstances(handlerType)){
        handler.Handle((dynamic)ev);    
    }

return empty 但必须返回两个处理程序:

handler[0] = 
    new ValidateMessageEnvelopeHandler<SecureMessageEnvelope<ItemCreatedEvent>>(
        new SecureMessageEnvelopeHandler<ItemCreatedEvent>(
            new MessageLogDecorator<ItemCreatedEvent>(
                new LogService())));

handler[1] = 
    new ValidateMessageEnvelopeHandler<SecureMessageEnvelope<ItemCreatedEvent>>(
        new SecureMessageEnvelopeHandler<ItemCreatedEvent>(
            new MessageLogDecorator<ItemCreatedEvent>(
                new ProjectionService())));

虽然最好如下:

new ValidateMessageEnvelopeHandler<SecureMessageEnvelope<ItemCreatedEvent>>(
    new SecureMessageEnvelopeHandler<ItemCreatedEvent>(
        new CompositeHandler(
            new MessageLogDecorator<ItemCreatedEvent>(
                new LogService()),
            new MessageLogDecorator<ItemCreatedEvent>(
                new ProjectionService()))));

如果我调用“_container.GetInstance(handlerType)”而不是“GetAllInstances”,则会发生错误:

注册开放泛型类型时出错 消息处理程序。未能为类型建立注册 ValidateMessageEnvelopeHandler>。 注册开放泛型类型时出错 消息处理程序。未能为类型建立注册 SecureMessageEnvelopeHandler。的构造函数 SecureMessageEnvelopeHandler 类型包含 带有名称的 IMessageHandler 类型的参数 未注册的“innerHandler”。请确保 IMessageHandler 在容器中注册,或者 改变构造函数 SecureMessageEnvelopeHandler。

当我注册 CompositeHandler () 时出现错误。 ( Container.RegisterOpenGeneric(typeof(IMessageHandler), typeof(CompositeMessageHandler));)

注册开放泛型类型时出错 消息处理程序。未能为类型建立注册 ValidateMessageEnvelopeHandler>。 ResolveUnregisteredType 事件的多个观察者是 为相同的服务类型注册一个委托: 消息处理程序>。确保 只有一个注册的处理程序调用 给定服务类型的 ResolveUnregisteredType.Register 方法。

我该如何解决这个问题?

【问题讨论】:

    标签: c# dependency-injection simple-injector open-generics


    【解决方案1】:

    您的配置不起作用,因为您做错了两件事:

    1. 您没有注册CompositeMessageHandler&lt;T&gt;
    2. 您拨打的是GetAllInstances 而不是GetInstance

    当您调用GetAllInstances 时,您只会获得使用RegisterManyForOpenGeneric 注册的处理程序集合,但在您的示例中,您请求的是IMessageHandler&lt;ValidateMessageEnvelope&lt;SecureMessageEnvelope&lt;ItemCreatedEvent&gt;&gt;&gt;,但您从未将IMessageHandler&lt;ValidateMessageEnvelope&lt;T&gt;&gt; 注册为集合; ValidateMessageEnvelopeHandler 注册为“单项”注册。

    CompositeMessageHandler&lt;T&gt; 的注册更加完善,因为您不希望为所有 IMessageHandler&lt;T&gt; 注册返回组合。你不希望这样,因为如果消息是ValidateMessageEnvelope&lt;T&gt;,你想返回ValidateMessageEnvelopeHandler&lt;T&gt;,如果消息是SecureMessageEnvelope&lt;T&gt;,你想返回SecureMessageEnvelopeHandler&lt;T&gt;

    所以您需要在ValidateMessageEnvelope&lt;T&gt;SecureMessageEnvelopeHandler&lt;T&gt; 的注册之后添加以下注册:

    container.RegisterOpenGeneric(
        typeof(IMessageHandler<>), 
        typeof(CompositeMessageHandler<>),
        Lifestyle.Singleton, 
        context => !context.Handled);
    

    通过提供context =&gt; !context.Handled,您可以确保CompositeMessageHandler&lt;T&gt; 只有在没有首先应用其他注册的情况下才会被应用。如果没有这个谓词,Simple Injector 将检测到两个开放通用注册应用于同一个抽象,Simple Injector 将抛出异常。

    您应该直接调用GetInstance,而不是调用GetAllInstances。例如:

    var ev = new ItemCreatedEvent().AsSecure("token/1").AsValidatable();
    var handlerType = typeof(IMessageHandler<>).MakeGenericType(ev.GetType());
    
    dynamic handler = container.GetInstance(handlerType);
    
    handler.Handle((dynamic)ev);
    

    请注意,您的MessageLogDecorator&lt;T&gt; 不仅会应用于LogServiceProjectionService 类,还会应用于CompositeMessageHandler&lt;T&gt; 类。这可能不是你想要的。您可能只想-包装CompositeMessageHandler&lt;T&gt;,或者您可能想包装-除了-CompositeMessageHandler&lt;T&gt;之外的所有东西。最后一种情况,可以将MessageLogDecorator&lt;T&gt;的注册改成如下:

    container.RegisterDecorator(typeof(IMessageHandler<>),
        typeof(MessageLogDecorator<>), context =>
        {
            var type = context.ImplementationType;
            return !type.IsGenericType ||
                type.GetGenericTypeDefinition() != typeof(CompositeMessageHandler<>));
        });
    

    或者您甚至可以将其简化为以下内容:

    container.RegisterDecorator(typeof(IMessageHandler<>),
        typeof(MessageLogDecorator<>), 
        context => !context.ImplementationType.IsGenericType);
    

    在这种情况下,装饰器只会被非泛型实现包裹。

    【讨论】:

    • 感谢您的回复,它的作品。顺便说一句,我需要 CompositeMessageHandler 吗?
    • @oguzh4n:复合模式阻止应用程序代码知道背后有多个实现的事实。使用信封处理程序进行设计时,您显然需要这样做,因为在您的情况下,有时您会注入单个实例,而有时您会注入复合材料。信封处理程序和“消息执行调解员”都不知道什么时候会出现这种情况(他们也不需要知道)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多