У меня похожая проблема. Однако вы мне помогли.
То, что я сделал по-другому / сделал бы по-другому. вместо Create или Update вы можете использовать RuleSets, в зависимости от имени, которое будет выполнять различные RuleSets, это позволит вам идентифицировать операцию при ее проверке: https://fluentvalidation.net/start#rulesets. Вы не должны вводить что-либо зависимое на результат во время выполнения в этот момент такая индикация, если это создание или обновление.
Отвечая на ваши вопросы:
Вопрос 1. Кажется, я указал на одну ошибку выше. В противном случае выглядит хорошо для меня. Нет необходимости создавать оболочку для модульного тестирования вашей проверки, вы можете просто сделать это, как в этом примере:
[Test]
public void Should_have_error_when_val_is_zero()
{
validator = new TestModelValidator();
TestModel testRequest = new TestModel();
//populate with dummy data
var result = validator.Validate(testRequest);
Assert.That(result.Errors.Any(o => o.PropertyName== "ParentVal"));
}
Вопрос 2: Я бы внедрил в валидатор всего одну scopedFactory и позволил бы ей самостоятельно разрешать свои зависимости, а не вводить все, что ему нужно. Однако что вы делаете внутри new CompanyValidator(_unitOfWork, databaseOperation)
? Мне кажется странным вводить что-либо в Validator, поскольку на самом деле это не то, что вы вводите, чтобы разрешить правило. Я не уверен, в чем ваша причина, но в противном случае, как я уже сказал, для этого нужно добавить scopedFactory или класс Nested.
Вопрос 3: Мне кажется, я уже ответил на этот вопрос.
Вопрос 4: Я бы попытался создать обобщенную инъекцию зависимостей или внедрить Массив валидаторов в какую-то фабрику, которая будет разрешаться в зависимости от типа.
services.AddScoped (typeof (IValidationFactory <>), typeof (ValidationFactory <>));
Что решит, какой валидатор мне нужен на основе типа.
Надеюсь, это имеет смысл.
UPDATE
Таким образом, внутри CreateMethod передайте имя RuleSet методу validate, чтобы он мог решить, является ли это Create или Update. О заводе с ограниченной ответственностью https://csharp.hotexamples.com/examples/-/IServiceScopeFactory/-/php-iservicescopefactory-class-examples.html
Например:
Вместо этого:
ValidationResult validationResult = ожидание проверки. ValidateAsync (пользователь);
Вы можете сделать это:
validator.Validate(person, ruleSet: "Create");
Также вы можете разрешить зависимости и ввести необходимый валидатор, например, вот так (я решаю по типу запроса, вы можете использовать строковый ключ, если необходимо):
services.AddSingleton<IValidator, Validator1>();
services.AddSingleton<IValidator, Validator2>();
services.AddSingleton<IValidator, Validator3>();
services.AddScoped<Func<Type, IValidator>>(serviceProvider => typeKey =>
{
if (typeKey == typeof(Validator1))
{
return serviceProvider.GetService<Validator1>();
}
if (typeKey == typeof(Validator2))
{
return serviceProvider.GetService<Validator2>();
}
if (typeKey == typeof(Validator3))
{
return serviceProvider.GetService<Validator3>();
}
return null;
});
А это пример использования:
public GenericValidator(Func<Type, IValidator> validatorFactory)
{
_validatorFactory = validatorFactory ?? throw new ArgumentNullException(nameof(validatorFactory));
}
public async Task<IEnumerable<string>> ValidateAsync<T, TK>(TK objectToValidate) where TK : class
{
var validator = _validatorFactory(typeof(T));
if (validator == null)
{
throw new ValidationException($"Failed to get validator for type: {typeof(T)}");
}
var validationResult = await validator.ValidateAsync(objectToValidate);
return validationResult.Errors.Select(x => x.ErrorMessage);
}
И введите: IServiceScopeFactory serviceScopeFactory
в ваш валидатор, который поможет разрешить любые внешние зависимости. Вы можете найти примеры здесь: https://csharp.hotexamples.com/examples/-/IServiceScopeFactory/-/php-iservicescopefactory-class-examples.html