使用 Simple Injector 将开放通用类型注册为回退

Register open generic type as fallback with Simple Injector

设置

我是 运行 .NET4.0 上的 Web 应用程序,使用 the almighty SimpleInjector3. I'm using the Command-/QueryHandler architecture described here 进行连接,我在为命令处理程序配置依赖项时遇到问题。

示例代码

这里是 class 结构的细分:

interface ICommandHandler<T> 
{
    void Handle(T command);
}

enum LoggingState { Success, Failed }

interface ICommandLogger<T>
{
    void Log(LoggingState state, T command);
}

class NullCommandLogger<T> : ICommandLogger<T>
{
    void Log(LoggingState state, T command)
    {
        // Intentionally left blank
    }
}

装饰者:

/// <summary>
/// The logging command handler that gets wrapped around every
/// command handlers.
/// </summary>
class LoggingCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand>
{
    private readonly ICommandHandler<TCommand> decorated;
    private readonly ICommandLogger<TCommand> logger;

    public LoggingCommandHandlerDecorator(
        ICommandHandler<TCommand> decorated,
        ICommandLogger<TCommand> logger)
    {
        this.decorated = decorated;
        this.logger = logger;
    }

    public void Handle(TCommand command)
    {
        try
        {
            this.decorated.Handle(command);
        }
        catch (Exception)
        {
            this.logger.Log(LoggingState.Failed, command);
            throw;
        }

        this.logger.Log(LoggingState.Success, command);
    }
}

在我的 CompositionRoot 中,我这样配置:

var assembly = /* Get the assembly where the handlers are located */

// Register all explicitly defined loggers
container.Register(typeof(ICommandLogger<>), assembly);

// Register null objects for everything else
container.RegisterConditional(
    typeof(ICommandLogger<>),
    typeof(NullCommandLogger<>),
    ctx => !ctx.Handled);

// Wrap all command handlers with the logging
container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(LoggingCommandHandlerDecorator<>));

这对于像这样的非通用记录器非常有效:

class WorkingLogger : ICommandLogger<SomeCommand> { /* ... */ }

问题

现在我有一组实现标记接口的命令,这样我就可以为所有这些使用一个记录器——但这不会被 SimpleInjector 拾取:

class NotWorkingLogger<T> : ICommandLogger<T>
    where T : IMarkerInterface { /* ... */ }

我知道这不应该是差异问题,但我尝试使用 variance extensions 只是为了确定但无济于事。

有没有办法配置这个场景?

您只需按如下方式明确添加 NotWorkingLogger<T> 的注册:

container.Register(typeof(ICommandLogger<>), assembly);

// It's added between the two other registrations
container.RegisterConditional(
    typeof(ICommandLogger<>),
    typeof(NotWorkingLogger<>),
    ctx => !ctx.Handled);

container.RegisterConditional(
    typeof(ICommandLogger<>),
    typeof(NullCommandLogger<>),
    ctx => !ctx.Handled);