Как зарегистрировать необязательный декоратор или декоратор с необязательными параметрами, используя structmap asp.net mvc?

Я реализовал подход CQRS в своем приложении под сильным влиянием этой фантастической статьи: https://cuttingedge.it/blogs/steven/pivot/entry.php?id=9. Мой код для команд и обработчиков настроен идентично статье, и эта часть работает хорошо. Моя проблема возникает, когда я пытаюсь реализовать класс декоратора для обработки проверки команды. Простые интерфейсы обработки команд выглядят так:

public interface ICommand
{
}

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

Тогда для валидации декоратора у меня есть:

public class ValidationCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand> where TCommand : CommandBase
{
    private readonly ICommandHandler<TCommand> _decoratedCommandHandler;
    private readonly ICommandValidator<TCommand> _commandValidator;

    public ValidationCommandHandlerDecorator(ICommandHandler<TCommand> decoratedCommandHandler, ICommandValidator<TCommand> commandValidator)
    {
        _decoratedCommandHandler = decoratedCommandHandler;
        _commandValidator = commandValidator;
    }

    public void Handle(TCommand command)
    {
        if (_commandValidator != null)
        {
            var validationResult = _commandValidator.Validate(command);

            if (validationResult != null)
            {
                command.Success = false;
                command.Errors = validationResult;
                return;
            }
        }

        _decoratedCommandHandler.Handle(command);
        command.Success = true;
    }
}    

Который использует интерфейс для определения валидаторов:

public interface ICommandValidator<TCommand>
{
    IEnumerable<string> Validate(TCommand command);
}

А также CommandBase это простой базовый класс, который позволяет мне хранить информацию об успехе или неудаче команды и об ошибках, которые произошли в случае неудачи. Я предпочитаю этот метод в качестве альтернативы выбрасыванию исключения. Все команды будут наследовать этот базовый класс.

public abstract class CommandBase : ICommand
{
    public bool Success { get; set; }
    public IEnumerable<string> Errors { get; set; }
}

И все это связано с контейнером IoC в реестре структурной карты:

public class CommandRegistry : Registry
{
    public CommandRegistry()
    {
        Scan(s =>
        {
            s.AssemblyContainingType<CommandBase>();
            s.ConnectImplementationsToTypesClosing(typeof(ICommandHandler<>));
            s.ConnectImplementationsToTypesClosing(typeof(ICommandValidator<>));
            s.WithDefaultConventions();

            For(typeof(ICommandHandler<>)).DecorateAllWith(typeof(ValidationCommandHandlerDecorator<>));
        });
    }
}

Теперь, поскольку я регистрирую этот декоратор для каждого ICommandHandler, если у меня когда-либо будет команда, которая не нуждается в валидаторе и не определяет его, ICommandValidator<TCommand> _commandValidator частное поле ValidationCommandHandlerDecorator<TCommand> класс не может быть найден, потому что он, конечно, не существует и всегда будет выдавать ошибку структурной карты:

"Экземпляр по умолчанию не зарегистрирован и не может быть автоматически определен для типа" ICommandValidator ". Конфигурация для ICommandValidator не указана"

Есть ли способ в структуре карты, чтобы определить, как ValidationCommandHandlerDecorator создается так, что он использует некоторый тип валидатора по умолчанию, когда он не существует, без необходимости брать зависимость от контейнера в классе или создавать IValidateableCommandHandler<TCommand> интерфейс для обработки команд с валидаторами?

Спасибо.

1 ответ

Решение

На случай, если кто-нибудь столкнется с этим позже, я решил добавить класс DefaultCommandValidator в качестве класса шаблона Null Object:

public class DefaultCommandValidator<TCommand> : ICommandValidator<TCommand> where TCommand : CommandBase
{
    public IEnumerable<string> Validate(TCommand command)
    {
        return Enumerable.Empty<string>();
    }
}

А затем добавьте эту строку в реестр карт структуры:

For(typeof(ICommandValidator<>)).Use(typeof(DefaultCommandValidator<>));

Я не знал, что этот синтаксис структурной карты будет на самом деле использовать экземпляр по умолчанию ТОЛЬКО, если он не может найти конкретную реализацию ICommandValidator<TCommand>, Теперь, если у меня нет валидатора, я просто не добавляю DefaultCommandValidator<TCommand> Экземпляр используется для возврата пустой / успешной проверки.

Другие вопросы по тегам