Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use custom validation responses with fluent validation

Hello I am trying to get custom validation response for my webApi using .NET Core.

Here I want to have response model like

[{
  ErrorCode:
  ErrorField:
  ErrorMsg:
}]

I have a validator class and currently we just check ModalState.IsValid for validation Error and pass on the modelstate object as BadRequest.

But new requirement wants us to have ErrorCodes for each validation failure.

My sample Validator Class

public class TestModelValidator :  AbstractValidator<TestModel>{

public TestModelValidator {
   RuleFor(x=> x.Name).NotEmpty().WithErrorCode("1001");
   RuleFor(x=> x.Age).NotEmpty().WithErrorCode("1002");
  }
}

I can use something similar in my actions to get validation result

Opt1:

 var validator = new TestModelValidator();
    var result = validator.Validate(inputObj);
    var errorList = result.Error;

and manipulate ValidationResult to my customn Response object. or
Opt2:

I can use [CustomizeValidator] attribute and maybe an Interceptors.

but for Opt2 I don't know how to retrieve ValidationResult from interceptor to controller action.

All I want is to write a common method so that I avoid calling Opt1 in every controller action method for validation.

Request to point me to correct resource.

like image 518
RajGan Avatar asked Aug 18 '17 13:08

RajGan


People also ask

Should I use fluent validation?

Summary. FluentValidation provides a great alternative to Data Annotations in order to validate models. It gives better control of validation rules and makes validation rules easy to read, easy to test, and enable great separation of concerns.

How does fluent validation work?

Fluent Validation is a free to use . NET validation library that helps you make your validations clean, easy to create, and maintain. It even works on external models that you don't have access to, with ease. With this library, you can separate the model classes from the validation logic like it is supposed to be.

Is fluent validation client side?

FluentValidation is a server-side library and does not provide any client-side validation directly. However, it can provide metadata which can be applied to the generated HTML elements for use with a client-side framework such as jQuery Validate in the same way that ASP. NET's default validation attributes work.


2 Answers

As for me, it's better to use the following code in ASP.NET Core project

  services.AddMvc().ConfigureApiBehaviorOptions(options =>
  {
    options.InvalidModelStateResponseFactory = c =>
    {
      var errors = string.Join('\n', c.ModelState.Values.Where(v => v.Errors.Count > 0)
        .SelectMany(v => v.Errors)
        .Select(v => v.ErrorMessage));

      return new BadRequestObjectResult(new
      {
        ErrorCode = "Your validation error code",
        Message = errors
      });
    };
  });

Also take into account that instead of anonymous object you can use your concrete type. For example,

     new BadRequestObjectResult(new ValidationErrorViewModel
      {
        ErrorCode = "Your validation error code",
        Message = errors
      });
like image 37
Alexander Avatar answered Oct 20 '22 01:10

Alexander


try with this:

services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressModelStateInvalidFilter = true;
});

I validate the model with fluentvalidation, after build the BadResquest response in a ActionFilter class:

public class ValidateModelStateAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.ModelState.IsValid)
        {
            var errors = context.ModelState.Values.Where(v => v.Errors.Count > 0)
                    .SelectMany(v => v.Errors)
                    .Select(v => v.ErrorMessage)
                    .ToList();

            var responseObj = new
            {
                Message = "Bad Request",
                Errors = errors                    
            };

            context.Result = new JsonResult(responseObj)
            {
                StatusCode = 400
            };
        }
    }
}

In StartUp.cs:

        services.AddMvc(options =>
        {
            options.Filters.Add(typeof(ValidateModelStateAttribute));
        })
        .AddFluentValidation(fvc => fvc.RegisterValidatorsFromAssemblyContaining<Startup>());

        services.Configure<ApiBehaviorOptions>(options =>
        {
            options.SuppressModelStateInvalidFilter = true;
        });

And it works fine. I hope you find it useful

like image 165
asd Avatar answered Oct 20 '22 02:10

asd