Customizing a Model Validation Response which results in an HTTP 400 Error Code

What is Model Validation?

 
Model validation adds checks for any model state errors and produces a BadRequestResult if the model state is invalid. Some common validations are present in system.data.componentModel.DataAnnotations. One can write custom validation attributes to address specific validation scenarios. 
 

What is the need for Customizing the response

 
In specific scenarios, we might need to include more details in our response so that user can interpret it well and correct the request easily. There may be several other reasons behind customizing the response due to model validation.
 

How to achieve this in .Net Core 2.2

 
ConfigureApiBehaviorOptions is an extension method of IMvcbulder interface. ApiBehaviorOptions class has the property of Func delegate InvalidModelStateResponseFactory, which gives developers the control to write custom responses. 
 
Let's have a look at ConfigureServices method present in startup class and then examine it line by line. All explanations are given inline as comments so that they can be quickly understood.
  1. public void ConfigureServices(IServiceCollection services) {  
  2.   
  3.  services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)  
  4.   // ConfigureApiBehaviorOptions is an extention method of IMvcbuilder  
  5.   // interface and is used to configure ApiBehaviorOptions.                                    
  6.   //In a nutshell, ApiBehaviorOptions is shipped with .Net Core 2.1 and facilitates  
  7.   // automatic model state validation, automatic parameter binding    
  8.   //and much more usefull features.    
  9.   .ConfigureApiBehaviorOptions(options => {  
  10.    //InvalidModelStateResponseFactory is a Func delegate  
  11.    // and used to customize the error response.    
  12.    //It is exposed as property of ApiBehaviorOptions class  
  13.    // that is used to configure api behaviour.    
  14.    options.InvalidModelStateResponseFactory = actionContext => {  
  15.     //CustomErrorResponse is method that gets model validation errors     
  16.     //using ActionContext creates customized response,  
  17.     // and converts invalid model state dictionary    
  18.   
  19.     return CustomErrorResponse(actionContext);  
  20.    };  
  21.   });  
  22. }  
Here is a code snippet for the CustomErrorResponse method and the custom Error class:
  1. // Below method extracts model state errors and assigns to the properties of Custom class.    
  2. private BadRequestObjectResult CustomErrorResponse(ActionContext actionContext) {  
  3.  //BadRequestObjectResult is class found Microsoft.AspNetCore.Mvc and is inherited from ObjectResult.    
  4.  //Rest code is linq.    
  5.  return new BadRequestObjectResult(actionContext.ModelState  
  6.   .Where(modelError => modelError.Value.Errors.Count > 0)  
  7.   .Select(modelError => new Error {  
  8.    ErrorField = modelError.Key,  
  9.     ErrorDescription = modelError.Value.Errors.FirstOrDefault().ErrorMessage  
  10.   }).ToList());  
  11. } 
  1. //Custom class to create custom response. 
  2. //Developer can add or remove properties as per requirement.    
  3. public class Error    
  4. {    
  5.     public string ErrorField { getset; }    
  6.     public string ErrorDescription { getset; }    
  7. }    
Please be advised that this article is a quick reference and not a complete guide on configuring ApiBehaviourOptions. Any suggestions to help make the article more concise are welcome.