2013-10-15 91 views
2

我有一個使用MVC4構建的面向互聯網的網站,我偶爾會從漫遊器或好奇的用戶那裏獲取錯誤報告,這些用戶發送不完整的URL請求。忽略由於缺少控制器參數導致的異常

例如:

public class ProductController : Controller 
{ 
    [HttpGet] 
    public void View(int id) 
    { 
     // ... 
  • GET請求到/product/view/1是有效的。
  • 由於未指定參數,所以對/product/view的GET請求無效。

這種無效的請求,引發異常相似:

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

由於異常消息的狀態,我可以使id參數空,但操作方法內檢查,但我有許多控制器與許多行動。

我想返回一個BadRequest/NotFound對任何無法將參數綁定到操作參數的請求的響應,並在代碼中的一個位置指定此值以跨所有控制器應用。

這怎麼辦?

+0

在你定義控制器和動作和參數定義的路由配置中,你可以指定參數爲可空。 –

+0

@AnirudhAgarwal當嘗試將null轉換爲int時,可能會拋出int –

+0

@AirirhAgarwal,如果我爲'id'包含一個我不想做的默認值,那麼工作的唯一方法就是。如果在操作中定義了「id」並且它沒有提供,那麼客戶端犯了一個錯誤,我想給他們發送404。另外,我有各種不同的控制器,每個控制器都需要在我的路由配置中輸入。這裏的要點是,我不希望在我的操作和配置中進行自定義更改,以防萬一某個用戶/機器人發送無效請求 - 它們應該集中處理,並且不會引發導致我收到錯誤電子郵件的異常只需刪除。 –

回答

1

一種方法,所以纔會把它放在那裏。)

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

感覺有點不舒服要做到這一點,因爲它可以在框架的未來版本打破。但是,如果它確實發生中斷,那麼該網站將恢復爲500而不是400。

+0

您也可以重寫OnException方法以獲得相同的效果。不知道它是否重要,但我猜OnActionExecuted是爲每個調用的操作方法調用的,而OnException僅在發生異常時調用。只是一個想法。 – Doktorn

0

您可以使用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 
{ 
} 

如果你想你可以在應用程序啓動文件夾,將其添加到一個FilterConfig類的中央位置處理這個問題:

public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
{ 
    var error = new HandleErrorAttribute(); 
    error.ExceptionType = typeof (ArgumentException); 
    error.View = "MissingArgument"; 
    filters.Add(error); 
} 

的MissingArgument視圖應位於共享視圖文件夾。 如果要發送一個特定的HTTP錯誤代碼返回給客戶端,你可以把在視圖中:

,似乎工作是在控制器(我用的基本控制器覆蓋 OnActionExecuted
@{ 
    ViewBag.Title = "Error"; 
    Context.Response.StatusCode = (int) HttpStatusCode.BadRequest; 
} 

<h2>Not found</h2> 
+0

有趣的是,雖然這將處理所有'ArgumentException's,而我只希望那些與無法綁定操作參數相關的。另外,我想把這個過濾器放在一箇中央位置,而不是每個控制器上(我認爲這可以通過一些小的代碼修改來實現。) –

+0

如果你希望這個過濾器集中在FilterConfig中,我已經更新了我的回答來證明這一點。 – Doktorn

+0

感謝您的更新。最後,我在基礎控制器中重寫了'OnActionExecuted',並針對確切的錯誤,而不是所有的'ArgumentException'實例。我擔心的是,我會禁止在不同情況下拋出的合法參數異常的錯誤日誌記錄/電子郵件。 –

相關問題