如何返回404状态,其中无效参数传递给我的ASP.NET MVC控制器?

Kev*_*Kev 16 asp.net error-handling asp.net-mvc asp.net-mvc-routing asp.net-mvc-3

404如果将无效参数传递给我的控制器,我想返回HTTP状态.例如,如果我有一个看起来像这样的控制器:

public ActionResult GetAccount(int id)
{
   ...
}
Run Code Online (Sandbox Code Playgroud)

然后我想返回404如果遇到这样的网址:

/GetAccount
/GetAccount/notanumber

即我想陷阱ArgumentException被抛出.

我知道我可以使用可以为空的类型:

public ActionResult GetAccount(int? id)
{
  if(id == null) throw new HttpException(404, "Not found");
}
Run Code Online (Sandbox Code Playgroud)

但那非常狡猾和重复.

我希望我可以在必要时将它添加到我的控制器:

[HandleError(View="Error404", ExceptionType = typeof(ArgumentException))]
public class AccountsController : Controller
{
  public ActionResult GetAccount(int id)
  {
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

但这似乎并不奏效.

我看到这篇文章这个答案几乎解决了我的问题:

在该答案中,创建了一个抽象的BaseController,您可以从中派生所有其他控制器:

public abstract class MyController : Controller
{
    #region Http404 handling

    protected override void HandleUnknownAction(string actionName)
    {
        // If controller is ErrorController dont 'nest' exceptions
        if (this.GetType() != typeof(ErrorController))
            this.InvokeHttp404(HttpContext);
    }

    public ActionResult InvokeHttp404(HttpContextBase httpContext)
    {
        IController errorController = ObjectFactory.GetInstance<ErrorController>();
        var errorRoute = new RouteData();
        errorRoute.Values.Add("controller", "Error");
        errorRoute.Values.Add("action", "Http404");
        errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
        errorController.Execute(new RequestContext(
             httpContext, errorRoute));

        return new EmptyResult();
    }

    #endregion
}
Run Code Online (Sandbox Code Playgroud)

这非常适合处理未知操作,404但不允许我处理无效数据404.

我可以安全地覆盖Controller.OnException(ExceptionContext filterContext)这样:

protected override void OnException(ExceptionContext filterContext)
{
  if(filterContext.Exception.GetType() == typeof(ArgumentException))
  {
    filterContext.ExceptionHandled = true;
    this.InvokeHttp404(filterContext.HttpContext);
  }
  else
  {
    base.OnException(filterContext);
  }
}
Run Code Online (Sandbox Code Playgroud)

从表面上看它似乎有效,但我是否通过这样做存储任何问题?

这个语义是否正确?

Rob*_*nik 6

最好的办法?动作方法选择器属性!

为了实际避免可空的方法参数,我建议您编写一个Action Method Selector属性,该属性实际上只在id提供时与您的action方法匹配.它不会说没有提供参数,但它无法匹配给定请求的任何操作方法.

我会调用这个动作选择器RequireRouteValuesAttribute并以这种方式工作:

[RequireRouteValues("id")]
public ActionResult GetAccount(int id)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

为什么这是您问题的最佳解决方案?

如果查看代码,您希望在与名称匹配的操作上返回404,但参数绑定失败(因为它未提供或任何其他原因).您可以这么说的动作需要特定的动作参数,否则返回404.

因此,当添加操作选择器属性时,会对操作添加要求,因此必须匹配名称(这由MVC提供),并且还需要特定的操作参数.无论何时id未提供此操作都不匹配.如果有另一个匹配的操作不是问题,因为该特定操作将被执行.最重要的是完成了.操作与无效路径请求不匹配,而是返回404.

一个应用程序代码!

查看我的博客文章,它实现了您可以立即使用的这种属性.它完全符合您的要求:如果提供的路径数据没有所有必需值,它将与您的操作方法不匹配.


arc*_*hil 1

免责声明:这并不涵盖所有情况

对于示例中的 url,返回 404 可以在单行中完成。只需为参数添加路由约束即可id

routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    new { controller = "Home", action = "Index" }, // Parameter defaults
    new { id = @"\d+" } // restrict id to be required and numeric
);
Run Code Online (Sandbox Code Playgroud)

就这样。现在,任何没有idid不是数字的匹配网址都会自动触发未找到错误(对此有很多方法可以处理,一种是在您的示例中,另一种是使用 customHandleErrorAttribute等)。int您可以在操作中使用不可为空的参数。

  • 但是...他可能不需要所有控制器和操作来提供 ID...这只是某些边缘情况的部分解决方案。 (4认同)