Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

779
Visualizações
¿Cómo escribir reglas de validación fluidas dentro de IValidateOptions usando FluentValidation?

Para mi aplicación de servicio de trabajador .Net 5, quiero validar las opciones implementando la interfaz IValidateOptions pero no quiero escribir mis propios mensajes de error. Es por eso que quiero hacer uso del paquete FluentValidation.AspNetCore .

Dado el modelo

 namespace App.Models { public class MyOptions { public string Text { get; set; } } }

Agregué reglas de validación.

 namespace App.ModelValidators { public class MyOptionsValidator : AbstractValidator<MyOptions> { public MyOptionsValidator() { RuleFor(model => model.Text).NotEmpty(); } } }

A continuación, estoy usando este validador dentro de la validación.

 namespace App.OptionsValidators { public class MyOptionsValidator : IValidateOptions<MyOptions> { private readonly IValidator<MyOptions> _validator; public MyOptionsValidator(IValidator<MyOptions> validator) { _validator = validator; } public ValidateOptionsResult Validate(string name, MyOptions options) { var validationResult = _validator.Validate(options); if (validationResult.IsValid) { return ValidateOptionsResult.Success; } return ValidateOptionsResult.Fail(validationResult.Errors.Select(validationFailure => validationFailure.ErrorMessage)); } } }

Por último, configuré el contenedor DI

 services.AddTransient<IValidator<MyOptions>, ModelValidators.MyOptionsValidator>(); services.AddSingleton<IValidateOptions<MyOptions>, OptionsValidators.MyOptionsValidator>(); services.Configure<MyOptions>(configuration.GetSection("My"));

Quisiera saber si esto se puede simplificar.

¿Tal vez pueda implementar la interfaz IValidateOptions , evitar el AbstractValidator y escribir reglas fluidas dentro del método .Validate() ?

Ejemplo de código de lo que quiero lograr

 namespace App.OptionsValidators { public class MyOptionsValidator : IValidateOptions<MyOptions> { public ValidateOptionsResult Validate(string name, MyOptions options) { var validationResult = options.Text.Should.Not.Be.Empty(); if (validationResult.IsValid) { return ValidateOptionsResult.Success; } return ValidateOptionsResult.Fail(validationResult.ErrorMessage); } } }

así que ya no necesito AbstractValidator<MyOptions> .


Mi primer acercamiento no estoy seguro

En lugar de usar FluentValidation, estoy usando DataAnnotations.

  • Agregué el atributo [Required] a la propiedad Text
  • Eliminé por completo la clase MyOptionsValidator : AbstractValidator<MyOptions>
  • Solo registro esto en la configuración DI

.

 services.AddSingleton<IValidateOptions<MyOptions>, OptionsValidators.MyOptionsValidator>(); services.Configure<MyOptions>(configuration.GetSection("My"));

Dentro MyOptionsValidator valido las opciones así

 public ValidateOptionsResult Validate(string name, MyOptions options) { var validationResults = new List<ValidationResult>(); if (!Validator.TryValidateObject(options, new ValidationContext(options), validationResults, true)) { return ValidateOptionsResult.Fail(validationResults.Select(validationResult => validationResult.ErrorMessage)); } return ValidateOptionsResult.Success; }

pero tal vez todavía hay mejores maneras :)

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

Puedo simplificar usando System.ComponentModel.DataAnnotations

 public class MyOptions { [Required] public string Text { get; set; } }

luego puede personalizar su BadRequest a través de la canalización

 services.AddControllers() .ConfigureApiBehaviorOptions(opts => { opts.InvalidModelStateResponseFactory = context => { var problemDetails = new ViolationProblemDetails() { Instance = context.HttpContext.Request.Path, Status = StatusCodes.Status400BadRequest, Detail = "Please refer to the errors property for additional details." }; problemDetails.Violations = new List<Violation>(); foreach (var modelState in context.ModelState) { problemDetails.Violations.Add(new Violation() { Field = modelState.Key, Message = string.Join(",",modelState.Value.Errors.Select(a => a.ErrorMessage)) }); } return new BadRequestObjectResult(problemDetails); }; })

más información https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-5.0

over 4 years ago · Santiago Trujillo Relatório

0

Encontré el siguiente código en este artículo https://dejanstojanovic.net/aspnet/2020/april/validate-configurations-with-fluentvalidation-in-aspnet-core/

 public void ConfigureServices(IServiceCollection services) { services.Configure<EndpointsConfiguration>(Configuration.GetSection(nameof(EndpointsConfiguration))); services.AddSingleton<AbstractValidator<EndpointsConfiguration>, EndpointsConfigurationValidator>(); services.AddSingleton<EndpointsConfiguration>(container => { var config = container.GetService<IOptions<EndpointsConfiguration>>().Value; var validator = container.GetService<AbstractValidator<EndpointsConfiguration>>(); validator.Validate(config); return config; }); services.AddControllers(); }

De esta manera, puede tener toda su validación en la implementación de AbstractValidator y será más simple que su implementación actual. Al usar esto, no es necesario implementar IOptionsValidator , supongo. El artículo tiene una buena explicación, así que consulte para obtener más información.

over 4 years ago · Santiago Trujillo Relatório

0

Tengo una fuerte preferencia por utilizar el mismo enfoque para la validación en toda la pila y, en mi caso, esto es a través de FluentValidation. El siguiente sería mi enfoque.

Cree un nuevo validador base para sus validadores de opciones/configuraciones:

 public abstract class AbstractOptionsValidator<T> : AbstractValidator<T>, IValidateOptions<T> where T : class { public virtual ValidateOptionsResult Validate(string name, T options) { var validateResult = this.Validate(options); return validateResult.IsValid ? ValidateOptionsResult.Success : ValidateOptionsResult.Fail(validateResult.Errors.Select(x => x.ErrorMessage)); } }

Esto amplía FluentValidation AbstractValidator<T> para admitir IValidateOptions<T> . Ahora tiene una base que puede usar para todos sus validadores de opciones/configuraciones. Para los siguientes ajustes:

 public class FooSettings { public string Bar { get; set; } }

terminas con un validador típico:

 public class FooSettingsValidator : AbstractOptionsValidator<FooSettings>, IFooSettingsValidator { public FooSettingsValidator() { RuleFor(x => x.Bar).NotEmpty(); } }

Hágale saber al contenedor DI:

 serviceCollection.AddSingleton<IValidateOptions<FooSettings>, FooSettingsValidator>();

Si no hay nada incorporado para hacer lo anterior, miraría a Scrutor para convertir esto en un proceso automático.

Todo lo anterior me brinda todos los beneficios de usar FluentValidation, mientras utilizo el soporte de validación de opciones de primera clase que Microsoft nos ha brindado.

Ejemplo de trabajo de LINQPad:

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

 using static FluentAssertions.FluentActions; void Main() { var fixture = new Fixture(); var validator = new FooSettingsValidator(); validator.Validate(fixture.Build<FooSettings>().Without(x => x.Bar).Create()).Errors.Select(x => x.ErrorMessage).Should().BeEquivalentTo(new string[] { "'Bar' must not be empty." }); validator.Validate(fixture.Build<FooSettings>().Create()).Errors.Select(x => x.ErrorMessage).Should().BeEquivalentTo(new string[] { }); using (var scope = ServiceProvider.Create(bar: null).CreateScope()) { Invoking(() => scope.ServiceProvider.GetRequiredService<IOptionsSnapshot<FooSettings>>().Value).Should().Throw<OptionsValidationException>(); } using (var scope = ServiceProvider.Create(bar: "asdf").CreateScope()) { scope.ServiceProvider.GetRequiredService<IOptionsSnapshot<FooSettings>>().Value.Bar.Should().Be("asdf"); } } // You can define other methods, fields, classes and namespaces here public class FooSettings { public string Bar { get; set; } } public interface IFooSettingsValidator : IValidator { } public class FooSettingsValidator : AbstractOptionsValidator<FooSettings>, IFooSettingsValidator { public FooSettingsValidator() { RuleFor(x => x.Bar).NotEmpty(); } } public abstract class AbstractOptionsValidator<T> : AbstractValidator<T>, IValidateOptions<T> where T : class { public virtual ValidateOptionsResult Validate(string name, T options) { var validateResult = this.Validate(options); return validateResult.IsValid ? ValidateOptionsResult.Success : ValidateOptionsResult.Fail(validateResult.Errors.Select(x => x.ErrorMessage)); } } public class ServiceProvider { public static IServiceProvider Create(string bar) { var serviceCollection = new ServiceCollection(); var config = new ConfigurationBuilder() .AddInMemoryCollection( new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("Foo:Bar", bar) }) .Build(); serviceCollection.AddSingleton<IConfiguration>(config); serviceCollection.AddOptions(); //serviceCollection.Configure<FooSettings>(config.GetSection("Foo")); serviceCollection.AddOptions<FooSettings>() .Bind(config.GetSection("Foo")); serviceCollection.AddSingleton<IValidateOptions<FooSettings>, FooSettingsValidator>(); serviceCollection.AddSingleton<IFooSettingsValidator, FooSettingsValidator>(); return serviceCollection.BuildServiceProvider(); } }
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda