问题
我已经有了一个命令处理框架,我试图使用Simple injector(3.3.2)将我现有的处理程序包装在Mediatr会理解的东西中。我的命令处理程序总是返回CommandResult
所以我的处理程序接口只有TCommand
作为Type变量,而处理程序接口Mediatr也需要TResult
。
所以我的ICommandHandler<TCommand>
和Mediatr需求为IRequestHandler<TRequest, TResult>
想到
我可以更改ICommandHandler<TCommand>
以实施IRequestHandler<TCommand, CommandResult>
,但我必须更改ICommand<TCommand>
以实施IRequest<TCommand, CommandResult>
。但是我不想改变现有的代码并将它紧密耦合。
我可以拦截SimpleInjector上的ResolveUnregisteredType
并返回Mediatr需要的任何内容(这将起作用)。但后来我需要的代码依赖于我的代码 AND Mediatr AND SimpleInjector 而且我想避免这种情况。 如果其他所有方法都失败了,那将是我的后备方案。
试过
我尝试了三种方法让注册工作,请参阅代码
代码
它有点,在我预计至少有一个通过的测试的顶部。然后是我现在拥有的接口和TestCommand
。在那三个地区之后,我尝试了这些东西。
顺便说一句
我没有在此问题上加上Mediatr
标记,因为它可以适用于任何框架。
using MediatR;
using NUnit.Framework;
using SimpleInjector;
using System;
namespace CommandHandlingTest
{
public class Tests
{
[Test]
public void Version_1()
{
var container = new Container();
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
container.Register(typeof(ICommandHandler<>), assemblies);
container.Register(typeof(IRequestHandler<,>), assemblies);
container.Verify();
var commandBus = new MediatorCommandBus_1(container.GetInstance, container.GetAllInstances);
var command = new TestCommand();
Assert.DoesNotThrow(() => commandBus.Send(command));
// Fails with Handler was not found for request of type CommandWrapped_1<TestCommand>
}
[Test]
public void Version_2()
{
var container = new Container();
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
container.Register(typeof(ICommandHandler<>), assemblies);
container.Register(typeof(IRequestHandler<,>), assemblies);
container.Verify();
var commandBus = new MediatorCommandBus_2(container.GetInstance, container.GetAllInstances);
var command = new TestCommand();
Assert.DoesNotThrow(() => commandBus.Send(command));
// Fails with Handler was not found for request of type CommandWrapped_2<TestCommand, CommandResult>.
}
[Test]
public void Version_3()
{
var container = new Container();
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
container.Register(typeof(ICommandHandler<>), assemblies);
container.Register(typeof(IRequestHandler<,>), assemblies);
container.Verify();
var commandBus = new MediatorCommandBus_3(container.GetInstance, container.GetAllInstances);
var command = new TestCommand();
Assert.DoesNotThrow(() => commandBus.Send(command));
// Fails with Handler was not found for request of type CommandWrapped_3<TestCommand, CommandResult>.
}
}
/* Should not change */
public interface ICommand { }
/* Should not change */
public interface ICommandBus
{
CommandResult Send<TCommand>(TCommand command) where TCommand : ICommand;
}
/* Should not change */
public interface ICommandHandler<in TCommand>
where TCommand : ICommand
{
CommandResult Handle(TCommand command);
}
/* Should not change */
public class TestCommand : ICommand { }
/* Should not change */
public class TestHandler : ICommandHandler<TestCommand>
{
public CommandResult Handle(TestCommand command)
{
return new CommandResult { IsValid = true };
}
}
/* Should not change */
public class CommandResult
{
public bool IsValid { get; set; }
}
#region Version 1
public class MediatorCommandBus_1 : ICommandBus
{
private readonly IMediator _mediator;
public MediatorCommandBus_1(SingleInstanceFactory singleInstanceFactory, MultiInstanceFactory multiInstanceFactory)
{
_mediator = new Mediator(singleInstanceFactory, multiInstanceFactory);
}
public CommandResult Send<TCommand>(TCommand command)
where TCommand : ICommand
{
return _mediator.Send(new CommandWrapped_1<TCommand>(command)).Result;
}
}
public class WrappedHandler_1<TCommand, TResult, TWrappedCommand> :
IRequestHandler<TWrappedCommand, TResult>
where TCommand : ICommand
where TWrappedCommand : CommandWrapped_1<TCommand>, IRequest<TResult>
where TResult : CommandResult
{
private readonly ICommandHandler<TCommand> _commandHandler;
public WrappedHandler_1(ICommandHandler<TCommand> commandHandler)
{
_commandHandler = commandHandler;
}
public TResult Handle(TWrappedCommand message)
{
var handle = _commandHandler.Handle(message.UnWrap());
return handle as TResult;
}
}
public class CommandWrapped_1<TCommand> : IRequest<CommandResult>
where TCommand : ICommand
{
private readonly TCommand _command;
public CommandWrapped_1(TCommand command)
{
_command = command;
}
public TCommand UnWrap() => _command;
}
#endregion
#region Version 2
public class MediatorCommandBus_2 : ICommandBus
{
private readonly IMediator _mediator;
public MediatorCommandBus_2(SingleInstanceFactory singleInstanceFactory, MultiInstanceFactory multiInstanceFactory)
{
_mediator = new Mediator(singleInstanceFactory, multiInstanceFactory);
}
public CommandResult Send<TCommand>(TCommand command)
where TCommand : ICommand
{
return _mediator.Send(new CommandWrapped_2<TCommand, CommandResult>(command)).Result;
}
}
public class WrappedHandler_2<TCommand, TResult> :
IRequestHandler<CommandWrapped_2<TCommand, TResult>, TResult>
where TCommand : ICommand
where TResult : CommandResult
{
private readonly ICommandHandler<TCommand> _commandHandler;
public WrappedHandler_2(ICommandHandler<TCommand> commandHandler)
{
_commandHandler = commandHandler;
}
public TResult Handle(CommandWrapped_2<TCommand, TResult> message)
{
var handle = _commandHandler.Handle(message.UnWrap());
return handle as TResult;
}
}
public class CommandWrapped_2<TCommand, TResult> : IRequest<TResult>
where TCommand : ICommand
where TResult : CommandResult
{
private readonly TCommand _command;
public CommandWrapped_2(TCommand command)
{
_command = command;
}
public TCommand UnWrap() => _command;
}
#endregion
#region Version 3
public class MediatorCommandBus_3 : ICommandBus
{
private readonly IMediator _mediator;
public MediatorCommandBus_3(SingleInstanceFactory singleInstanceFactory, MultiInstanceFactory multiInstanceFactory)
{
_mediator = new Mediator(singleInstanceFactory, multiInstanceFactory);
}
public CommandResult Send<TCommand>(TCommand command)
where TCommand : ICommand
{
return _mediator.Send(new CommandWrapped_3<TCommand, CommandResult>(command)).Result;
}
}
public class WrappedHandler_3<TCommand, TResult> :
IRequestHandler<ICommandWrapped_3<TCommand, TResult>, TResult>
where TCommand : ICommand
where TResult : CommandResult
{
private readonly ICommandHandler<TCommand> _commandHandler;
public WrappedHandler_3(ICommandHandler<TCommand> commandHandler)
{
_commandHandler = commandHandler;
}
public TResult Handle(ICommandWrapped_3<TCommand, TResult> message)
{
var handle = _commandHandler.Handle(message.UnWrap());
return handle as TResult;
}
}
public class CommandWrapped_3<TCommand, TResult> : ICommandWrapped_3<TCommand, TResult>
where TCommand : ICommand
where TResult : CommandResult
{
private readonly TCommand _command;
public CommandWrapped_3(TCommand command)
{
_command = command;
}
public TCommand UnWrap() => _command;
}
public interface ICommandWrapped_3<out TCommand, out TResult> : IRequest<TResult>
where TCommand : ICommand
{
TCommand UnWrap();
}
#endregion
}
答案 0 :(得分:1)
您应该替换以下行:
container.Register(typeof(IRequestHandler<,>), assemblies);
使用:
container.Register(typeof(IRequestHandler<,>), typeof(WrappedHandler_2<,>));
批量注册重载Register
,它接收程序集列表,默认情况下跳过通用注册(除非您另行指定),因为泛型类型通常需要特殊处理。在您的情况下,您实际上对批量注册不感兴趣,因为您只有一个您感兴趣的映射(这是包装的处理程序)。