【问题标题】:How can I centralize modelstate validation in asp.net mvc using action filters?如何使用操作过滤器在 asp.net mvc 中集中模型状态验证?
【发布时间】:2014-03-06 10:53:40
【问题描述】:

我在好几个地方写了这段代码,并且总是重复这个逻辑:

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
        }
    }
}

有什么方法可以使用动作过滤器,不重复try-catch,询问模型是否有效,return Json(false)ActionResult

【问题讨论】:

  • 是的,绝对可以,您可以创建验证ActionFilterExceptionFilter 来捕获所有错误,但是您到底为什么要在这里尝试...捕获?从验证之类的东西中抛出异常是错误的。你期待什么样的错误?同样返回Json(true)Json(false) 也是错误的,这就是Http 状态码的用途。
  • 我可以回答,但您需要的所有内容都已在此处输入:lostechies.com/jimmybogard/2013/12/19/… 或者您可以观看技术视频viddler.com/v/b568679c
  • 是的,如果应该在try-catch之外,除了返回一个Json (true)是错误的,谢谢

标签: c# asp.net-mvc-4


【解决方案1】:

为了符合 REST,您应该返回 http bad request 400 以表明 请求格式错误(模型无效),而不是返回 Json(false)

asp.net official site 尝试这个属性用于 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);
        }
    }
}

asp.net mvc 的版本可能是这样的:

public class ValidateModelAttribute : ActionFilterAttribute
{
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
              if (!filterContext.Controller.ViewData.ModelState.IsValid)
              {
                   filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.BadRequest);  
              }
        }
}

【讨论】:

  • 查看这个答案stackoverflow.com/a/69648844/129269 以获得内置解决方案
  • @riezebosch 用于 .net 核心,用于 WebAPI 和 MVC
  • 感谢您指出这一点,对于使用核心或 5.0+ 找到此答案的人来说仍然很有价值。
  • @riezebosch 当然,如果您更新您的评论以反映这一点,那么我将删除我的 cmets(以消除一些噪音)
【解决方案2】:

这里是如何使用来自 Khanh TO 的代码(来自 asp.net official site):

要将此过滤器应用于所有 Web API 控制器,请在配置期间将过滤器的一个实例添加到 HttpConfiguration.Filters 集合:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Filters.Add(new ValidateModelAttribute());

        // ...
    }
}

另一种选择是将过滤器设置为单个控制器或控制器操作的属性:

public class ProductsController : ApiController
{
  [ValidateModel]
  public HttpResponseMessage Post(Product product)
  {
    // ...
  }
}

【讨论】:

    【解决方案3】:

    如果您想在 MVC6 或 Mvc Core 中执行此操作,并且没有在所有 Action 方法上指定您的属性,那么您就是这样做的。

    首先创建你的 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 );
        }
    }
    

    现在创建一个约定,您将在其中将此 ActionFilter 应用于所有控制器。

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

    最后一件事是在 MVC 中注册这个约定

        public void ConfigureServices( IServiceCollection services )
        {
          services.Configure<MvcOptions>( x => x.Conventions.Add( new ModelStateValidatorConvension() ) );
        }
    

    【讨论】:

    • 这是一个更完整的答案,因为它可以避免重复更多代码
    【解决方案4】:
    public class ValidateModelStateAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (!context.ModelState.IsValid)
            {              
                context.Result = new ViewResult();
            }
        }
    }
    

    【讨论】:

    • add对你的回答做一些解释
    【解决方案5】:

    从 ASP.Net Core 2.1 开始,[ApiController] 属性将触发自动模型验证:

    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase
    

    因此,动作方法或自定义ActionFilterAttribute中不需要以下代码:

    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    

    来源:https://docs.microsoft.com/en-us/aspnet/core/web-api/?view=aspnetcore-2.1#automatic-http-400-responses-1

    【讨论】:

    • 谢谢!不幸的是,我只有一张赞成票可以放弃。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-07
    相关资源
    最近更新 更多