Search code examples
c#asp.net-coreasp.net-core-webapiwebapi

Adding custom format class to WebPI Core feedback error


Visual Studio 2022 + all updates. WebAPI Core (.Net 6)

I have a simple Model class:

`    [Required(ErrorMEssage="NAme is required"]
     public string Name {get; set;}

 [Required(ErrorMessage = "Email is required"]
 [EmailAddress(ErrorMEssage="Enter a correct email address")]
 public string Email {get; set;}

 public string Address {get; set;}
 public int Age {get; set;}`

When i deliberately execute a Get action and leave the EmailAddress out i get an error from the model. If i leave the name out i also receive that error. Similar to

`{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-27be45d9cffab14698524a63120a4f88-6bfe2613f2328a42-00",
"errors": {
   // All errors here
    ]
}
}`

I then implemented this class

`public class ReformatValidationProblemAttribute : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext context)
    {
        if (context.Result is BadRequestObjectResult badRequestObjectResult)
            if (badRequestObjectResult.Value is ValidationProblemDetails)
            {
                // Introduced my custom class to provide the error
            }

        base.OnResultExecuting(context);
    }
}`

The issue i find is the error for the property is found under context.Result.Value (which is what i see when i debug) which isnt available when I add the same code in Visual Studio.

How could i get all the errors and pass them into my custom class so the end JSON is produced to my specification?

Please note i can build the class to my specification for the JSON but i just need to know how to pull the multiple errors out so i can display it accordingly.


Solution

  • You can try the following code
    MyModel.cs

        public class MyModel
        {
            [Required(ErrorMessage = "NAme is required")]
            public string Name { get; set; }
    
            [Required(ErrorMessage = "Email is required")]
            [EmailAddress(ErrorMessage = "Enter a correct email address")]
            public string Email { get; set; }
        }
    

    ValidationFilterAttribute.cs

        public class ValidationFilterAttribute : IActionFilter
        {
            public void OnActionExecuting(ActionExecutingContext context)
            {
                if (!context.ModelState.IsValid)
                {
                    var customErrorMessage=new Dictionary<string, string>();
                    foreach (var b in context.ModelState)
                    {
                        customErrorMessage.Add(b.Key, b.Value.Errors.FirstOrDefault().ErrorMessage);
                    }
                    context.Result = new ObjectResult(customErrorMessage);
                }
            }
            public void OnActionExecuted(ActionExecutedContext context) { }
        }
    

    Program.cs

    builder.Services.AddScoped<ValidationFilterAttribute>();
    builder.Services.Configure<ApiBehaviorOptions>(options
        => options.SuppressModelStateInvalidFilter = true);
    

    Controller

            [HttpPost("test")]
            [ServiceFilter(typeof(ValidationFilterAttribute))]
            public IActionResult test(MyModel myModel)
            {
                return Ok(myModel);
            }
    

    Test Input
    enter image description here
    Response
    enter image description here