Click here to Skip to main content
15,867,328 members
Articles / Web Development / ASP.NET / ASP.NET Core
Tip/Trick

ASP.NET Core Global Model Validation

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
1 Aug 2017MIT 9.7K   5  
In this article, you will learn about ASP.NET Core global model validation

Introduction

Have you ever been writing these codes all the time:

C#
[HttpPost]
public IActionResult Create(Movie movie)
{
    if (ModelState.IsValid)
    {
        // Do something
        // ...
        return Json(..your data...);
    }
    return Json(..error...);
}

But if we can do something much better like:

C#
[HttpPost]
public IActionResult Create(Movie movie)
{
    // Do something
    // ...
    return Json(..your data...);
}

Using the Code

When creating ASP.NET Core (.NET Core/.NET Framework) project, we choose Web API project template.

Image 1

To implement global model validation, we implement these classes/interfaces:

  • ActionFilterAttribute: Check ModelState.IsValid and throw exception if there is any error
  • ModelStateDictionary: Read all model errors
  • IExceptionFilter: To handle global error

For the full source code, refer to my GitHub.

Implementing ActionFilterAttribute:

C#
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
    public class ValidateModelStateAttribute : ActionFilterAttribute
    {
        public ValidateModelStateAttribute()
        {
        }

        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (!context.ModelState.IsValid)
            {
                // When ModelState is not valid, we throw exception
                throw new ValidationException(context.ModelState.GetErrors());
            }
        }
    }

Implementing ModelStateDictionary:

C#
public static class ModelStateExtensions
{
    public static List GetErrors(this ModelStateDictionary modelState)
    {
        var validationErrors = new List();

        foreach (var state in modelState)
        {
            validationErrors.AddRange(state.Value.Errors
                .Select(error => error.ErrorMessage)
                .ToList());
        }

        return validationErrors;
    }
}

Implementing IExceptionFilter:

C#
public class HttpGlobalExceptionFilter : IExceptionFilter
{
    public HttpGlobalExceptionFilter()
    {
    }

    public void OnException(ExceptionContext context)
    {
        var exception = context.Exception;
        var code = HttpStatusCode.InternalServerError;
        var ajaxResponse = new AjaxResponse
        {
            IsSuccess = false
        };

        if (exception is ValidationException)
        {
            code = HttpStatusCode.BadRequest;
            ajaxResponse.Message = "Bad request";
            // We can serialize exception message here instead of throwing Bad request message
        }
        else
        {
            ajaxResponse.Message = "Internal Server Error";
        }

        context.Result = new JsonResult(ajaxResponse);
        context.HttpContext.Response.StatusCode = (int)code;
        context.ExceptionHandled = true;
    }
}

Modifying ConfigureServices method in Startup.cs file:

C#
public void ConfigureServices(IServiceCollection services)
{
    services
        .AddMvc(options =>
        {
            options.Filters.Add(new ValidateModelStateAttribute());
            options.Filters.Add(typeof(HttpGlobalExceptionFilter));
        })
        .AddJsonOptions(options =>
        {
            options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        });
}

Result

Now when methods are executed in controller classes, the validation process will be triggered and we can remove Model.IsValid checking.

C#
[Route("api/[controller]")]
public class MoviesController : Controller
{
    // POST api/movies
    [HttpPost]
    public IActionResult Create([FromBody]Movie value)
    {
        return Json("OK");
    }
}

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Architect FPT Software Hochiminh
Vietnam Vietnam
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --