What is .Net Core Web Api Model Validation error response Type?

Amir Shaikh 1 Reputation point
2021-11-09T12:57:43.197+00:00

Hi All,

I have made an .NET core web API endpoint that takes a model in parameter from body.
I have purposely generated this error
However, when model state is not valid it returns a response that's attached bellow based on the filters I have added on the Model.

User Model

public class User
{
    [Required]
    public string Firstname { get; set; }

    [Required]
    public string Lastname { get; set; }
}

If I post empty json object ( {} ) then I get bellow error.

{
  "errors": {
    "firstname": [
      "Firstname is required."
    ],
    "lastname": [
      "Lastname is required."
    ],
  },
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "00-3bb4c1b32731c4479dce567469a-bfc88e43393cc34e-00"
}

If I post blank body then I get the below error

{
  "errors": {
    "": [
      "A non-empty request body is required."
    ]
  },
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "00-3bb4c1b32731c4479dce567469a-bfc88e43393cc34e-00"
}

In both the cases the object inside "errors" changes dynamically based on the Model.
I need to serialize this response to a type on client.
Please help me to figure out the type of this schema should be.
Or this there more correct way or better way to handle EF Model validations

ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,129 questions
{count} votes

2 answers

Sort by: Most helpful
  1. Zhi Lv - MSFT 32,006 Reputation points Microsoft Vendor
    2021-11-11T10:11:00.033+00:00

    Hi @Amir Shaikh ,

    You could try to create a Custom validation Error model, and then use the action filter to handle the Validation failure error response. Check the following sample code:

    1. Create custom ValidationError model which contains the returned fields:
       public class ValidationError  
       {  
           [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
           public string Field { get; }  
      
           [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
           public int Code { get; set; }  
      
           public string Message { get; }  
      
           public ValidationError(string field,int code, string message)  
           {  
               Field = field != string.Empty ? field : null;  
               Code = code != 0 ? code : 55;  //set the default code to 55. you can remove it or change it to 400.  
               Message = message;  
           }  
       }  
      
       public class ValidationResultModel  
       {  
           public string Message { get; }  
      
           public List<ValidationError> Errors { get; }  
      
           public ValidationResultModel(ModelStateDictionary modelState)  
           {  
               Message = "Validation Failed";  
               Errors = modelState.Keys  
                       .SelectMany(key => modelState[key].Errors.Select(x => new ValidationError(key,0, x.ErrorMessage)))  
                       .ToList();  
           }  
       }  
      
    2. Create custom IActionResult. By default, when display the validation error, it will return BadRequestObjectResult and the HTTP status code is 400. Here we could change the Http Status code.
       public class ValidationFailedResult : ObjectResult  
       {  
           public ValidationFailedResult(ModelStateDictionary modelState)  
               : base(new ValidationResultModel(modelState))  
           {  
               StatusCode = StatusCodes.Status422UnprocessableEntity; //change the http status code to 422.  
           }  
       }  
      
    3. Create Custom Action Filter attribute:
       public class ValidateModelAttribute: ActionFilterAttribute  
       {   
           public override void OnActionExecuting(ActionExecutingContext context)  
           {  
               if (!context.ModelState.IsValid)  
               {  
                   context.Result = new ValidationFailedResult(context.ModelState);  
               }  
           }  
       }  
      
    4. Change the default response type to SerializableError in Startup.ConfigureServices:
           services.AddControllers().ConfigureApiBehaviorOptions(options =>  
           {  
               options.InvalidModelStateResponseFactory = context =>  
               {  
                   var result = new ValidationFailedResult(context.ModelState);  
      
                   // TODO: add `using System.Net.Mime;` to resolve MediaTypeNames  
                   result.ContentTypes.Add(MediaTypeNames.Application.Json);   
      
                   return result;  
               };  
           });  
      
    5. Add the custom action filter at the action method or controller.
       [HttpPost]  
       [ValidateModel]  
       public async Task<ActionResult<Student>> PostStudent(Student student)  
       {   
          ...  
       }  
      
    6. Create a Student model :
       public class Student  
       {  
           [Key]  
           public int Id { get; set; }  
      
           [Required(ErrorMessage = "Please enter Firstname")]   
           public string Firstname { get; set; }  
      
           [Required(ErrorMessage = "Please enter Lastname")]  
           public string Lastname { get; set; }  
      
       }   
      

    Then, if the request body is empty, the result like this:

    148369-image.png

    After get the response, you could deserialize it to the custom ValidationError model.

    Reference:

    Handle Validation failure errors in ASP.NET Core web APIs

    Handling validation responses for ASP.NET Core Web API


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,
    Dillion

    5 people found this answer helpful.

  2. Bradley Clouser 1 Reputation point
    2021-12-28T20:42:17.603+00:00

    I was trying to do exactly what you're asking, and there's no need to re-invent the wheel. You can use the built in .net5 classes to accomplish this...

    ControllerBase has a method you can return called ValidationProblem. This is what gets returned if there is a model validation error.

    ModelState.AddModelError(nameof(ChangePasswordArgs.CurrentPassword), "Password is not correct");
    return ValidationProblem(ModelState);
    
    0 comments No comments