如何返回无效参数传递给ASP.NETMVC控制器的404状态?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (120)

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

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

然后,我想返回一个404如果说这样的URL如遇到:

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

表面上它似乎工作,但我通过这样做存储任何问题?

这是在语义上正确的事情吗?

提问于
用户回答回答于

免责声明:这并不包括所有的情况

对于示例中的网址,返回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不是数字的匹配url,会自动触发未发现的错误(有很多方法可以处理,一个在你的例子中,另一个在使用自定义HandleErrorAttribute等)。可以int在操作中使用不可空的参数。

用户回答回答于

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

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

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

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

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

如果你看看你的代码,你想返回一个404匹配名称但参数绑定失败的动作(无论是因为它没有提供或任何其他原因)。可以这么说你的动作需要特定的动作参数,否则返回404。

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

代码!

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

扫码关注云+社区