asp.net - 当无效参数传递到 ASP.NET MVC Controller 时,如何返回 404 状态?

标签 asp.net asp.net-mvc asp.net-mvc-3 error-handling asp.net-mvc-routing

如果将无效参数传递给我的 Controller ,我想返回 HTTP 状态 404。例如,如果我有一个如下所示的 Controller :

public ActionResult GetAccount(int id)
{
   ...
}

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

/GetAccount
/GetAccount/notanumber

i.e. I want to trap the ArgumentException that is thrown.

I know I could use a nullable type:

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

但这非常令人讨厌且重复。

我希望我可以在必要时将其添加到我的 Controller 中:

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

但这似乎效果不佳。

我看到了this postthis answer这几乎解决了我的问题:

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

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
}

这非常适合使用 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);
  }
}

从表面上看,它似乎有效,但是我这样做是否会带来任何问题?

这在语义上正确吗?

最佳答案

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

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

我会将此操作选择器称为 RequireRouteValuesAttribute 并以这种方式工作:

[RequireRouteValues("id")]
public ActionResult GetAccount(int id)
{
    ...
}

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

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

因此,在添加操作选择器属性时,会添加对操作的要求,因此它必须与名称匹配(由 MVC 给出),并且还需要特定的操作参数。每当未提供 id 时,此操作就不匹配。如果有另一个匹配的操作不是这里的问题,因为该特定操作将被执行。主要的事情已经完成了。操作与无效路由请求不匹配,而是返回 404。

有一个应用程序代码!

检查my blog post它实现了您可以开箱即用的这种属性。它完全符合您的要求:如果提供的路线数据不包含所有必需的值,它将与您的操作方法不匹配。

关于asp.net - 当无效参数传递到 ASP.NET MVC Controller 时,如何返回 404 状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8981709/

相关文章:

asp.net-mvc - 如何从服务器下载文件到客户端?

javascript - MVC 操作方法和 JavaScript

asp.net-mvc-3 - 不同命名空间中的 Asp.Net MVC 3 Custom WebViewPage 会破坏 IntelliSense

c# - CTP5 EF代码第一题

asp.net - 传入字典的模型项是 type 的,但是该字典需要 type 的模型项

asp.net-mvc - foreach 中 switch 语句的正确 Razor 语法

asp.net-mvc - 第二次请求后 TempData 不会销毁

asp.net - MVC 6 asp-validation-summary 省略属性名称以验证隐藏输入

javascript - 如何在window.open方法中传递参数?

c# - 修复 global.asax 中的语法错误