Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I centralize modelstate validation in asp.net mvc using action filters?

I write this code in several places and always repeat this logic:

public ActionResult MyMethod(MyModel collection)
{
    if (!ModelState.IsValid)
    {
        return Json(false);//to read it from javascript, it's always equal
    }
    else
    {
        try
        {
            //logic here
            return Json(true);//or Json(false);
        }
        catch
        {
            return Json(false);//to read it from javascript, it's always equal
        }
    }
}

Is there any way using action filters, not to be repeating the try-catch, ask if the model is valid and return Json(false) as ActionResult?

like image 830
MaicolBen Avatar asked Feb 09 '14 02:02

MaicolBen


2 Answers

To conform with REST, you should return http bad request 400 to indicate that the request is malformed (model is invalid) instead of returning Json(false).

Try this attribute from asp.net official site for web api:

public class ValidateModelAttribute : ActionFilterAttribute
{
     public override void OnActionExecuting(HttpActionContext actionContext)
     {
        if (!actionContext.ModelState.IsValid)
        {
            actionContext.Response = actionContext.Request.CreateErrorResponse(
                HttpStatusCode.BadRequest, actionContext.ModelState);
        }
    }
}

A version for asp.net mvc could be like this:

public class ValidateModelAttribute : ActionFilterAttribute
{
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
              if (!filterContext.Controller.ViewData.ModelState.IsValid)
              {
                   filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.BadRequest);  
              }
        }
}
like image 165
Khanh TO Avatar answered Oct 11 '22 05:10

Khanh TO


If you want to do this in MVC6 or Mvc Core and without specifying your attribute on all of your Action methods then this is how you do it.

First create your ActionFilter

public class ModelStateValidationFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting( ActionExecutingContext context )
    {
        if ( context.HttpContext.Request.Method == "POST" && !context.ModelState.IsValid )
            context.Result = new BadRequestObjectResult( context.ModelState );
    }
}

Now create a convention in which you will apply this ActionFilter to all of your controllers.

    public class ModelStateValidatorConvension : IApplicationModelConvention
    {
        public void Apply( ApplicationModel application )
        {
            foreach ( var controllerModel in application.Controllers )
            {
                controllerModel.Filters.Add( new ModelStateValidationFilterAttribute() );
            }
        }
    }

And the last thing is to register this convention in MVC

    public void ConfigureServices( IServiceCollection services )
    {
      services.Configure<MvcOptions>( x => x.Conventions.Add( new ModelStateValidatorConvension() ) );
    }
like image 13
adeel41 Avatar answered Oct 11 '22 05:10

adeel41