[英]Wrapping generic types with Simple Injector
问题
我已经有一个Command处理框架,并且尝试使用简单注入器(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>
。 但是我不想更改现有代码并将其紧密耦合在一起。
我可以在ResolveUnregisteredType
上拦截ResolveUnregisteredType并返回Mediatr需要的任何东西(这将起作用)。 但是然后我需要依赖于我的代码 , Mediatr 和 SimpleInjector的 代码 ,我想避免这种情况。 如果所有其他方法都失败了,那将是我的后备方案。
试过了
我尝试了三种方法来使注册生效,请参见代码
码
在最高的测试中,我期望至少有一个测试能够通过。 然后,我现在拥有的接口和一个TestCommand
。 在那三个区域之后,我尝试了。
BTW
我没有将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
}
您应该替换以下行:
container.Register(typeof(IRequestHandler<,>), assemblies);
带有:
container.Register(typeof(IRequestHandler<,>), typeof(WrappedHandler_2<,>));
接收程序集列表的Register
的批量注册重载,默认情况下会跳过通用注册(除非另行指定),因为通用类型通常需要特殊处理。 在您的情况下,您实际上对批量注册不感兴趣,因为只有一个您感兴趣的映射(这是包装的处理程序)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.