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", произошла ошибка:
При регистрации открытого типа IMessageHandler произошла ошибка. Не удалось создать регистрацию для типа ValidateMessageEnvelopeHandler>. При регистрации открытого типа IMessageHandler произошла ошибка. Не удалось создать регистрацию для типа SecureMessageEnvelopeHandler. Конструктор типа SecureMessageEnvelopeHandler содержит параметр типа IMessageHandler с именем "innerHandler", который не зарегистрирован. Убедитесь, что IMessageHandler зарегистрирован в контейнере или изменил конструктор SecureMessageEnvelopeHandler.
Когда я регистрирую CompositeHandler(), у меня есть ошибка. (Container.RegisterOpenGeneric(typeof (IMessageHandler <>), typeof (CompositeMessageHandler <>));)
При регистрации открытого типа IMessageHandler произошла ошибка. Не удалось создать регистрацию для типа ValidateMessageEnvelopeHandler>. Несколько наблюдателей события ResolveUnregisteredType регистрируют делегат для одного и того же типа сервиса: IMessageHandler>. Убедитесь, что только один из зарегистрированных обработчиков вызывает метод ResolveUnregisteredType.Register для данного типа службы.
Как я могу это исправить?
Ваша конфигурация не работает, потому что вы делаете две вещи неправильно:
CompositeMessageHandler<T>
GetAllInstances
вместо GetInstance
. Когда вы вызываете GetAllInstances
вы получаете только коллекцию обработчиков, которые зарегистрированы с помощью RegisterManyForOpenGeneric
, но в вашем примере вы запрашиваете IMessageHandler<ValidateMessageEnvelope<SecureMessageEnvelope<ItemCreatedEvent>>>
, но вы никогда не регистрировали IMessageHandler<ValidateMessageEnvelope<T>>
как коллекция; ValidateMessageEnvelopeHandler
зарегистрирован как регистрация "одного элемента".
Регистрирование для CompositeMessageHandler<T>
немного более развито, потому что вы не хотите, чтобы композит возвращался для всех регистраций IMessageHandler<T>
. Вы не хотите этого, потому что если сообщение является ValidateMessageEnvelope<T>
, вы хотите вернуть ValidateMessageEnvelopeHandler<T>
и если это сообщение SecureMessageEnvelope<T>
, вы хотите вернуть SecureMessageEnvelopeHandler<T>
.
Поэтому вам необходимо добавить следующую регистрацию ПОСЛЕ регистрации для ValidateMessageEnvelope<T>
и SecureMessageEnvelopeHandler<T>
:
container.RegisterOpenGeneric(
typeof(IMessageHandler<>),
typeof(CompositeMessageHandler<>),
Lifestyle.Singleton,
context => !context.Handled);
Предоставляя context => !context.Handled
, вы убедитесь, что CompositeMessageHandler<T>
применяется только в том случае, если вначале не была применена другая регистрация. Без этого предиката Simple Injector обнаружит, что две открытые регистрации применяются к одной и той же абстракции, а Simple Injector генерирует исключение.
Вместо вызова GetAllInstances
вы должны просто вызвать GetInstance
. Например:
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<T>
будет не только применяться к LogService
и ProjectionService
, но и к классу CompositeMessageHandler<T>
. Возможно, это не то, что вы хотите. Возможно, вам захочется - обернуть CompositeMessageHandler<T>
, или, возможно, вы хотите обернуть -everything but- CompositeMessageHandler<T>
. В последнем случае вы можете изменить регистрацию MessageLogDecorator<T>
на следующее:
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);
В этом случае декоратор будет только обернут вокруг не общих реализаций.