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)
从表面上看它似乎有效,但我是否通过这样做存储任何问题?
这个语义是否正确?
为了实际避免可空的方法参数,我建议您编写一个Action Method Selector属性,该属性实际上只在id提供时与您的action方法匹配.它不会说没有提供参数,但它无法匹配给定请求的任何操作方法.
我会调用这个动作选择器RequireRouteValuesAttribute并以这种方式工作:
[RequireRouteValues("id")]
public ActionResult GetAccount(int id)
{
...
}
Run Code Online (Sandbox Code Playgroud)
如果查看代码,您希望在与名称匹配的操作上返回404,但参数绑定失败(因为它未提供或任何其他原因).您可以这么说的动作需要特定的动作参数,否则返回404.
因此,当添加操作选择器属性时,会对操作添加要求,因此必须匹配名称(这由MVC提供),并且还需要特定的操作参数.无论何时id未提供此操作都不匹配.如果有另一个匹配的操作不是问题,因为该特定操作将被执行.最重要的是完成了.操作与无效路径请求不匹配,而是返回404.
查看我的博客文章,它实现了您可以立即使用的这种属性.它完全符合您的要求:如果提供的路径数据没有所有必需值,它将与您的操作方法不匹配.
免责声明:这并不涵盖所有情况
对于示例中的 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)
就这样。现在,任何没有id或id不是数字的匹配网址都会自动触发未找到错误(对此有很多方法可以处理,一种是在您的示例中,另一种是使用 customHandleErrorAttribute等)。int您可以在操作中使用不可为空的参数。