Home > Net >  Async Action Filter not working. ASP.NET Core Web Api
Async Action Filter not working. ASP.NET Core Web Api

Time:07-18

I have created custom 'ValidationFilter' in order to validate request before it reaches controller, there it is:

ValidationFilter class

using Contracts.ViewModels;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace Middleware.Filters
{
    public class ValidationFilter : IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            if (!context.ModelState.IsValid)
            {
#pragma warning disable CS8602 // Dereference of a possibly null reference.
                var errorsInModelState = context.ModelState
                    .Where(o => o.Value.Errors.Count > 0)
                    .ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Errors.Select(o => o.ErrorMessage)).ToArray();
#pragma warning restore CS8602 // Dereference of a possibly null reference.

                var errorResponse = new ErrorResponse();

                foreach(var error in errorsInModelState)
                {
                    foreach(var subError in error.Value)
                    {
                        var errorModel = new ErrorModel
                        {
                            FieldName = error.Key,
                            Message = subError
                        };

                        errorResponse.Errors.Add(errorModel);
                    }
                }

                context.Result = new BadRequestObjectResult(errorResponse);
                return;
            }

            await next();
        }
    }
}

There is simple Validator for request:

using Contracts;
using FluentValidation;

namespace Middleware.Validators
{
    public class AddressingDtoValidator : AbstractValidator<AddressingDto>
    {
        public AddressingDtoValidator()
        {
            RuleFor(x => x.District)
                .NotNull()
                .NotEmpty()
                .Matches("^[a-zA-Z0-9 ]*$");
            RuleFor(x => x.Mr)
                .NotNull()
                .NotEmpty()
                .Matches("^[a-zA-Z0-9 ]*$");
            RuleFor(x => x.Quarter)
                .NotNull()
                .NotEmpty()
                .Matches("^[a-zA-Z0-9 ]*$");
            RuleFor(x => x.Street)
                .NotNull()
                .NotEmpty()
                .Matches("^[a-zA-Z0-9 ]*$");
            RuleFor(x => x.Building)
                .NotNull()
                .NotEmpty()
                .Matches("^[a-zA-Z0-9 ]*$");
            RuleFor(x => x.Corpus)
                .NotNull()
                .NotEmpty()
                .Matches("^[a-zA-Z0-9 ]*$");
            RuleFor(x => x.Building)
                .NotNull()
                .NotEmpty()
                .Matches("^[a-zA-Z0-9 ]*$");
            RuleFor(x => x.InstitutionName)
                .NotNull()
                .NotEmpty()
                .Matches("^[a-zA-Z0-9 ]*$");
        }
    }
}

I have also "ErrorModel" and "ErrorResponse" classes which you can see below and my goal is to display error using this class but somemwhy it doesn't work:

ErrorModel

namespace Contracts.ViewModels
{
    public class ErrorModel
    {
        public string? FieldName { get; set; }
        public string? Message { get; set; }
    }
}

ErrorResponse class

namespace Contracts.ViewModels
{
    public class ErrorResponse
    {
        public List<ErrorModel> Errors { get; set; } = new List<ErrorModel>();
    }
}

I want the error to be displayed like this:

{
   "errors": [
     {
        "fieldname": "....",
        "message": "...."
     }
   ]
}

but instead, i get something like that:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "00-b9157268dc1f793004182694c1acf1a7-67fd063ebec5cbc3-00",
  "errors": {
    "Quarter": [
      "'Quarter' must not be empty."
    ]
  }
}

I mean this type of error is understandable and okay to read but i am practicing with action filters and something is not working.

There is also Program.cs class where i inject this validator in pipeline:

builder.Services.AddControllers(options =>
{
    options.Filters.Add<ValidationFilter>();
})
    .AddFluentValidation(configuration => configuration.RegisterValidatorsFromAssemblyContaining<AddressingDtoValidator>());

So what could be the problem, am i missing something?

CodePudding user response:

To disable the default model state handling, you need to add the below setting in Program.cs.

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

enter image description here

  • Related