C# 忽略因缺少控制器参数而导致的异常
我有一个面向互联网的网站,它是使用MVC4构建的,我偶尔会收到来自机器人或好奇的用户的错误报告,这些用户发送不完整URL的请求 例如:C# 忽略因缺少控制器参数而导致的异常,c#,.net,asp.net-mvc,asp.net-mvc-4,C#,.net,Asp.net Mvc,Asp.net Mvc 4,我有一个面向互联网的网站,它是使用MVC4构建的,我偶尔会收到来自机器人或好奇的用户的错误报告,这些用户发送不完整URL的请求 例如: public class ProductController : Controller { [HttpGet] public void View(int id) { // ... 对/product/view/1的GET请求有效 对/product/view的GET请求无效,因为未指定参数 此类无效请求会引发类似以下
public class ProductController : Controller
{
[HttpGet]
public void View(int id)
{
// ...
- 对
的GET请求有效/product/view/1
- 对
的GET请求无效,因为未指定参数/product/view
System.ArgumentException: The parameters dictionary contains a null entry
for parameter 'id' of non-nullable type 'System.Int32' for method
'System.Web.Mvc.ActionResult View(Int32)' in 'Foo.ProductController'. An
optional parameter must be a reference type, a nullable type, or be declared
as an optional parameter.
Parameter name: parameters
at System.Web.Mvc.ActionDescriptor.ExtractParameterFromDictionary(ParameterInfo parameterInfo, IDictionary`2 parameters, MethodInfo methodInfo)
at System.Web.Mvc.ReflectedActionDescriptor.<>c__DisplayClass1.<Execute>b__0(ParameterInfo parameterInfo)
...
System.ArgumentException:参数字典包含空条目
对于方法的“System.Int32”不可为空类型的参数“id”
“Foo.ProductController”中的“System.Web.Mvc.ActionResult视图(Int32)”。一
可选参数必须是引用类型、可为null的类型或已声明的类型
作为可选参数。
参数名称:参数
位于System.Web.Mvc.ActionDescriptor.ExtractParameterFromDictionary(ParameterInfo ParameterInfo,IDictionary`2参数,MethodInfo MethodInfo)
在System.Web.Mvc.ReflectedActionDescriptor.c\uuu DisplayClass1.b\uu0(ParameterInfo ParameterInfo)
...
正如异常消息所述,我可以使id
参数为空,并在action方法中进行检查,但是我有许多控制器,它们具有许多操作
对于无法将参数绑定到操作参数的任何请求,我想返回一个BadRequest
/NotFound
响应,并在代码中的单个位置指定该响应,以应用于所有控制器
如何做到这一点?您可以使用HandleError属性来处理应用程序中的错误。HandleError属性可以在控制器级别和方法级别指定。我以前用过类似的方法:
[HandleError(ExceptionType = typeof(ArgumentException), View = "MissingArgument")]
public ActionResult Test(int id)
{
return View();
}
如果您不想在每个方法的基础上捕获异常,可以将该属性放在类级别:
[HandleError(ExceptionType = typeof(ArgumentException), View = "MissingArgument")]
public class HomeController : Controller
{
}
如果要在中心位置处理此问题,可以将其添加到App Start文件夹中的FilterConfig类:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
var error = new HandleErrorAttribute();
error.ExceptionType = typeof (ArgumentException);
error.View = "MissingArgument";
filters.Add(error);
}
MissingArgument视图应位于共享视图文件夹中。
如果要将特定HTTP错误代码发送回客户端,可以将其放在视图中:
@{
ViewBag.Title = "Error";
Context.Response.StatusCode = (int) HttpStatusCode.BadRequest;
}
<h2>Not found</h2>
@{
ViewBag.Title=“错误”;
Context.Response.StatusCode=(int)HttpStatusCode.BadRequest;
}
找不到
一种似乎有效的方法是覆盖控制器中执行的操作(我使用基本控制器,因此将其放在那里)
这样做感觉有点不舒服,因为它可能会在框架的未来版本中中断。但是,如果它确实中断,则站点将恢复为返回500而不是400。在路由配置中,您可以在其中定义控制器、操作和参数定义,您可以将参数指定为可为null。@AnirudhAgarwal,在尝试将null转换为int@AnirudhAgarwal,唯一可行的方法是,如果我为
id
包含一个默认值,而我不想这样做。如果在操作中定义了id
,但没有提供,则客户机出错,我想向他们发送404。此外,我有各种不同的控制器,每个控制器都需要在我的路由配置中输入。这里的要点是,我不想在我的操作和配置中进行自定义更改,以防某些用户/机器人发送无效的请求——它们应该集中处理,而不是引发异常,导致我收到错误电子邮件,而我只是删除了这些邮件。我认为问题来自于路由中有可选id和不匹配行动。有了一致的设计,你就不必做任何事情。有趣的可能重复,尽管这将处理所有ArgumentException
s,而我只想要那些与无法绑定动作参数相关的。另外,我想把这个过滤器放在一个中心位置,而不是每个控制器上(我认为通过一些小的代码更改是可能的。)如果你想把它集中化,就把它放在FilterConfig中。我已经更新了我的答案来显示这一点。谢谢更新。最后,我在我的基本控制器中覆盖了OnActionExecuted
,并瞄准了确切的错误,而不是所有ArgumentException
实例。我担心的是,我会禁止在不同情况下引发的合法参数异常的错误日志记录/电子邮件发送。您也可以覆盖OneException方法以获得相同的效果。我不知道这是否重要,但我猜每个调用的操作方法都会调用OnActionExecuted,而OneException只在异常情况下调用。只是一个想法。
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Exception == null)
return;
// Avoid 'action parameter missing' exceptions by simply returning an error response
if (filterContext.Exception.TargetSite.DeclaringType == typeof(ActionDescriptor) &&
filterContext.Exception.TargetSite.Name == "ExtractParameterFromDictionary")
{
filterContext.ExceptionHandled = true;
filterContext.Result = new HttpStatusCodeResult((int)HttpStatusCode.BadRequest);
}
}