当无效参数传递到 ASP.NET MVC 控制器时,如何返回 404 状态?
如果将无效参数传递给我的控制器,我想返回 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
最好的办法?动作方法选择器属性!
为了真正避免可为空的方法参数,我建议您编写一个 Action方法选择器属性实际上仅在提供
id
时匹配您的操作方法。它不会说未提供参数,但它无法匹配给定请求的任何操作方法。我会将此操作选择器称为
RequireRouteValuesAttribute
并以这种方式工作:为什么这是解决您问题的最佳解决方案?
如果您查看代码,您希望在与名称匹配但参数绑定失败的操作上返回 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: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 appcode 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.
免责声明:这并不能涵盖所有情况
对于示例中的网址,可以在单行中返回 404。只需为
id
参数添加路由约束即可。仅此而已。现在,任何没有
id
或id
的匹配网址都不是数字,会自动触发未找到错误(对此有很多方法可以处理,在您的示例中是一种,另一种是通过使用自定义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.And that's all. Now any matching url that has no
id
orid
is not numeric, autimatically triggers not found error (for which there are plenty of ways to handle, one in your example, another by using customHandleErrorAttribute
, etc). And you can use non-nullableint
parameters on your actions.我设法通过在所有路由的末尾添加此路由来实现此工作:
注意:首先我遵循以下操作: 如何正确处理 404在 ASP.NET MVC 中?
I managed to get this working by adding this route at the end of all routes:
Note: First I followed this: How can I properly handle 404 in ASP.NET MVC?