Валидаторы FluentValidation и простой инжектор, где валидаторы вводятся как массив

У меня возникли проблемы с работой моих валидаторов FluentValidation с Simple Injector.

У меня есть декоратор с конструктором:

public CommandHandlerValidationDecorator(
    IRequestHandler<TRequest, TRepsonse> innerHandler, 
    IValidator<TRequest>[] validators)
{
    _decoratedHandler = innerHandler;
    _validators = validators;
}

Проблема связана со вторым параметром, IValidator<TRequest>[] validators.

Руководствуясь сообщениями об ошибках, которые я получал, я выполнил настройку следующим образом:

container.Register(typeof(FluentValidation.IValidator<>), new[] { assembly });
container.RegisterCollection(typeof(FluentValidation.IValidator<>), new[] { assembly });
container.Register(typeof(IRequestHandler<,>),new [] { assembly });
container.RegisterDecorator(typeof(IRequestHandler<,>), 
    typeof(CommandHandlerValidationDecorator<,>));

Это работало нормально, пока я не изменил область действия для каждого веб-запроса:

container.Register(typeof(FluentValidation.IValidator<>), new[] { assembly }, 
    Lifestyle.Scoped);
container.RegisterCollection(typeof(FluentValidation.IValidator<>), new[] { assembly });
container.Register(typeof(IRequestHandler<,>),new [] { assembly }, Lifestyle.Scoped);
container.RegisterDecorator(typeof(IRequestHandler<,>), 
    typeof(CommandHandlerValidationDecorator<,>), Lifestyle.Scoped);

Похоже, что вы не можете использовать RegisterCollection для каждого веб-запроса, и это становится проблемой, потому что возникает исключение из-за несоответствия образа жизни:

Дополнительная информация: Обнаружено несоответствие образа жизни. CommandHandlerValidationDecorator (веб-запрос) зависит от IValidator[] (переходный). Несоответствие образа жизни может вызвать ошибки параллелизма в вашем приложении. См. https://simpleinjector.org/dialm, чтобы понять эту проблему и способы ее решения.

Возможно, я пытаюсь заставить что-то, что является плохой практикой?


person onefootswill    schedule 30.04.2016    source источник
comment
Измените аргумент конструктора на anIEnumarable<IValidator<TRequest>>, и все в порядке.   -  person Steven    schedule 01.05.2016
comment
@Steven Спасибо за быстрый и результативный ответ!   -  person onefootswill    schedule 01.05.2016


Ответы (1)


То, что вы видите, описано здесь в документации:

Simple Injector сохраняет образ жизни экземпляров, возвращаемых из внедренных экземпляров IEnumerable<T>, ICollection<T>, IList<T>, IReadOnlyCollection<T> и IReadOnlyList<T>. На самом деле вы не должны рассматривать внедренный IEnumerable<T> как набор экземпляров; вы должны рассматривать это как поток экземпляров. Simple Injector всегда будет вставлять ссылку на один и тот же поток (сам IEnumerable<T> или ICollection<T> является синглтоном), и каждый раз, когда вы повторяете IEnumerable<T>, для каждого отдельного компонента контейнеру предлагается разрешить экземпляр на основе образа жизни этого компонента.

Предупреждение. В отличие от абстракций коллекции, массив регистрируется как временный. Массив — это изменяемый тип; потребитель может изменить содержимое массива. Совместное использование массива (сделав его одноэлементным) может привести к сбою несвязанных частей ваших приложений из-за изменений в массиве. Поскольку массив является конкретным типом, он не может функционировать как поток, в результате чего элементы в массиве получают время жизни потребляющего компонента. Это могло привести к несоответствиям образа жизни, если массив не был зарегистрирован как временный.

Итак, у вас есть два варианта:

  1. Также сделайте потребителей массива переходными или
  2. Измените аргумент параметра с массива на IEnumerable<T>, ICollection<T>, IList<T>, IReadOnlyCollection<T> или IReadOnlyList<T>.
person Steven    schedule 01.05.2016
comment
Спасибо, Стивен. Я читал документ. Я пропустил этот момент. Спасибо, что объяснили это здесь. Это тоже хорошая документация. - person onefootswill; 01.05.2016