当无效参数传递到 ASP.NET MVC 控制器时,如何返回 404 状态?

发布于 2024-12-28 17:29:42 字数 2551 浏览 2 评论 0原文

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

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

那么如果遇到这样的 url,我想返回 404

/GetAccount
/GetAccount/notanumber

即我想捕获 ArgumentException 这是抛出。

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

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

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

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

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

但这似乎效果不佳。

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

在这个答案中,有一个摘要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
}

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

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

这在语义上正确吗?

I want to return a HTTP status 404 if invalid arguments are passed to my controller. For example if I have a controller that looks like:

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

Then I want to return a 404 if say urls such as these are encountered:

/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");
}

But that's pretty icky and repetitious.

I was hoping I could add this to my controllers where necessary:

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

But that doesn't appear to work well.

I saw this post and this answer which nearly solves my problem:

In that answer an abstract BaseController is created from which you derive all your other controllers from:

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
}

This works great at handling unknown actions with a 404 but doesn't allow me to handle invalid data as a 404.

Can I safely override Controller.OnException(ExceptionContext filterContext) like this:

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

On the surface it seems to work, but am I storing up any problems by doing this?

Is this semantically correct thing to do?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

打小就很酷 2025-01-04 17:29:42

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

为了真正避免可为空的方法参数,我建议您编写一个 Action方法选择器属性实际上仅在提供id时匹配您的操作方法。它不会说未提供参数,但它无法匹配给定请求的任何操作方法。

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

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

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

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

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

有一个应用程序代码!

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

Best way? Action method selector attribute!

To actually avoid nullable method arguments I suggest that you write an Action Method Selector attribute that will actually only match your action method when id is supplied. It won't say that argument wasn't supplied but that it couldn't match any action methods for the given request.

I would call this action selector RequireRouteValuesAttribute and would work this way:

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

Why is this the best solution for your problem?

If you look at your code you'd like to return a 404 on actions that match name but parameter binding failed (either because it wasn't supplied or any other reason). Your action so to speak requires particular action parameter otherwise a 404 is returned.

So when adding action selector attribute adds the requirement on the action so it has to match name (this is given by MVC) and also require particular action parameters. Whenever id is not supplied this action is not matched. If there's another action that does match is not the issue here because that particular action will get executed. The main thing is accomplished. Action doesn't match for invalid route request and a 404 is returned instead.

There's an app code for that!

Check my blog post that implements this kind of attribute that you can use out of the box. It does exactly what you're after: it won't match your action method if route data provided doesn't have all required values.

悲凉≈ 2025-01-04 17:29:42

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

对于示例中的网址,可以在单行中返回 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
);

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

Disclaimer: this does not cover all the cases

For urls in your examples, returning 404 can be done in single line. Just add route constraint for id parameter.

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
);

And that's all. Now any matching url that has no id or id is not numeric, autimatically triggers not found error (for which there are plenty of ways to handle, one in your example, another by using custom HandleErrorAttribute, etc). And you can use non-nullable int parameters on your actions.

相守太难 2025-01-04 17:29:42

我设法通过在所有路由的末尾添加此路由来实现此工作:

routes.MapRoute("CatchAllErrors", "{*url}",
    new { controller = "Error", action = "NotFound" }
);

注意:首先我遵循以下操作: 如何正确处理 404在 ASP.NET MVC 中?

I managed to get this working by adding this route at the end of all routes:

routes.MapRoute("CatchAllErrors", "{*url}",
    new { controller = "Error", action = "NotFound" }
);

Note: First I followed this: How can I properly handle 404 in ASP.NET MVC?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文