[英]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.