【发布时间】:2017-01-15 21:03:54
【问题描述】:
问题
我已经有一个命令处理框架,我正在尝试使用简单注入器 (3.3.2) 将我现有的处理程序包装在 Mediatr 可以理解的东西中。我的命令处理程序总是返回一个CommandResult,所以我的处理程序接口只有TCommand 作为类型变量,而 Mediatr 提供的处理程序接口也需要一个TResult。
所以我有一个ICommandHandler<TCommand> 和 Mediatr 需要 IRequestHandler<TRequest, TResult>
想过
我可以将ICommandHandler<TCommand> 更改为也实现IRequestHandler<TCommand, CommandResult>,但随后我必须更改ICommand<TCommand> 以实现IRequest<TCommand, CommandResult>。但我不想更改现有代码并将其耦合得如此紧密。
我可以拦截 SimpleInjector 上的 ResolveUnregisteredType 并返回 Mediatr 需要的任何内容(这将起作用)。但是我需要依赖于 My Code 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
}
【问题讨论】:
-
问题中缺少的是解释您实际使用 MediatR 的原因。您已经有了处理命令的特定于应用程序的抽象;还有外部(不兼容)接口有什么用?
-
好问题。我拥有的抽象是对我有用的最简单的。 MediatR 是一个广泛使用的库,所以我选择首先使用它。我不确定最终解决方案中是否会使用其他选项,但其他实现可能会出现类似的问题。
-
如果我理解正确,您在此处遇到的实际 only 问题是从 MediatR 映射到您自己的界面并返回。从等式中删除 MediatR 即可解决问题。
-
是的,但我必须用另一个实现来替换它。我不想自己写。也许我会使用远程总线或进程间通信。无论哪种方式,问题可能都是一样的。我也很好奇如何解决这个问题以及为什么它不起作用。
-
MediatR 为您解决了什么问题?
标签: c# dependency-injection simple-injector