18

我在我的web.config以下:在ASP.NET MVC中,在我看來,最好的顯示未處理的異常是什麼?

<customErrors mode="On" defaultRedirect="Error"> 
    <error statusCode="404" redirect="Error/NotFound" /> 
</customErrors> 

我有一個

[HandleError] 

在我HomeController類的頂部。爲了測試,我創建了一個只會拋出異常的操作。 。並重定向到我

ErrorController/Index 

方法,但是當它到達我的觀點,其結合HandleErrorInfo我的模型爲空,所以我莫名其妙地失去了參考錯誤。

我確定它與在重定向中迷路的錯誤有關,所以我想看看我是否錯過了一些東西,如果有人有建議,我可以有一個顯示Stacktrace和錯誤消息的視圖。

+0

customError失去對錯誤的所有引用。 – 2013-05-01 04:09:55

+0

可能的重複[如何處理ASP.NET MVC 3應用程序中未捕獲的異常?](http://stackoverflow.com/questions/6596648/how-do-i-handle-uncaught-exceptions-in-an- asp-net-mvc-3-application) – 2013-05-01 04:11:35

+0

雖然customError重定向,但它正在創建一個新的http請求,因此丟失了所有以前的響應數據。你需要的是將redirectMode設置爲ResponseRewrite,這樣你就不會發出新的請求。 – 2013-05-01 04:12:59

回答

22

我可以看到這種誤解。您想要執行MVC事情和redirect控制器操作。

但是defaultRedirect本身是一個Web Form約定,從而受到限制。您重定向到另一個控制器的那一刻,你將失去你HttpContext,從而失去你HandleErrorInfo對象

[HandleError]屬性需要View指導其錯誤消息。按照上面的例子,我假設你有一個Views/Error文件夾,用於你的ErrorController,並且你有一個Index視圖。如果你想你的過濾器上下文爲HandleErrorInfo對象發送到該視圖,

試試這個語法:

[HandleError(View="~/Views/Error/Index")] 
Public class HomeController : Controller 

但對於記錄?!?!?

我懷疑你的意圖是不僅僅是顯示錯誤堆棧給用戶更多。事實上,我懷疑你根本沒有這種意圖。我懷疑你的真正目的是記錄你的錯誤(可能是db),並向用戶顯示一些平淡的信息。

我到目前爲止解釋的是「什麼是最好的[顯示未處理的異常的方式,我認爲]」。 [HandleError]屬性對此很有幫助。

但是,當你要移動到下一個步驟(記錄錯誤),你有幾種選擇:

1)Override your base controller's On Exception method;創建自己的繼承自MVC Controller類的Controller,但覆蓋On Exception Method。此方法可與[HandleError]屬性結合使用

2)Create a custom exception handler創建您自己的記錄錯誤的異常處理程序。您的異常處理程序然後可以調用選擇的視圖,或者可以與[HandleError(order=2)]一起使用,因爲篩選器屬性可以採用應用優先級的順序參數。


尼廷張以芳要求的錯誤觀點是什麼樣子。

@model System.Web.Mvc.HandleErrorInfo 
<h2>Exception details</h2> 
<p> Controller: @Model.ControllerName </p> 
<p> Action: @Model.ActionName </p> 
<p> Exception: @Model.Exception </p> 
+0

你可以發佈'〜/ Views/Error/Index'的內容嗎? – 2015-02-11 08:15:37

+1

@NitinSawant,我希望這有助於 – 2015-02-12 16:30:17

1

我已經使用這一小段代碼來顯示用戶處理錯誤頁面。是否找不到頁面或發生了其他一些錯誤。

void Application_Error(object sender, EventArgs e) 
    { 
     // this value can be fetched from config or depend on DEBUG smybol 
     if (!handleErrors) 
      return; 

     var error = Server.GetLastError(); 
     var code = (error is HttpException) ? (error as HttpException).GetHttpCode() : 500; 

     if (code == 404) 
     { 
      // do something if page was not found. log for instance 
     } 
     else 
     { 
      // collect request info and log exception 
     } 

     // pass exception to ErrorsController 
     Request.RequestContext.RouteData.Values["ex"] = error; 

     // execute controller action 
     IController errorController = new ErrorsController(); 
     errorController.Execute(new RequestContext(new HttpContextWrapper(Context), Request.RequestContext.RouteData)); 
    } 

而錯誤控制器看起來像這樣。如果您需要詳細的例外,它是通過的RouteData

public class ErrorsController : Controller 
{ 
    /// <summary> 
    /// Page not found 
    /// </summary> 
    /// <returns></returns> 
    public ActionResult Http404() 
    { 
     return View(); 
    } 

    /// <summary> 
    /// All other errors 
    /// </summary> 
    /// <param name="actionName"></param> 
    protected override void HandleUnknownAction(string actionName) 
    { 
     // in case detailed exception is required. 
     var ex = (Exception) RouteData.Values["ex"]; 
     return View(); 
    } 
} 

訪問您可以爲每個HTTP代碼添加不同的看法。只是實施行動Http {Code}

6

我做了類似maxlego處理所有錯誤(不只是那些發生在與HandleError屬性的控制器中)。

我MvcApplication類(在的global.asax.cs)具有這樣的:

public class MvcApplication : HttpApplication 
{ 
    // usual stuff here... 

    protected void Application_Error(object sender, EventArgs e) 
    { 
     Server.HandleError(((MvcApplication)sender).Context); 
    } 
} 

上面的代碼使用擴展方法從有用的東西我的MVC庫。有了這個,我不需要任何錯誤處理屬性,customErrors配置或自定義過濾器。相反,擴展方法將記錄錯誤的詳細信息,然後調用相應的視圖,或者:

  • 存取遭拒
  • NOTFOUND
  • InternalServerError

擴展方法的代碼,使這項工作是:

public static class HttpServerUtilityExtensions 
{ 
    private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); 

    public static void HandleError(this HttpServerUtility server, HttpContext httpContext) 
    { 
     var currentController = " "; 
     var currentAction = " "; 
     var currentRouteData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext)); 

     if (currentRouteData != null) 
     { 
      if (currentRouteData.Values["controller"] != null && !String.IsNullOrEmpty(currentRouteData.Values["controller"].ToString())) 
       currentController = currentRouteData.Values["controller"].ToString(); 

      if (currentRouteData.Values["action"] != null && !String.IsNullOrEmpty(currentRouteData.Values["action"].ToString())) 
       currentAction = currentRouteData.Values["action"].ToString(); 
     } 

     var exception = server.GetLastError(); 
     Logger.ErrorException(exception.Message, exception); 

     var controller = DependencyResolver.Current.GetService<ErrorController>(); 
     var routeData = new RouteData(); 
     var action = "InternalServerError"; 

     if (exception is HttpException) 
     { 
      var httpEx = exception as HttpException; 

      switch (httpEx.GetHttpCode()) 
      { 
       case 404: 
        action = "NotFound"; 
        break; 

       case 401: 
        action = "AccessDenied"; 
        break; 
      } 
     } 

     httpContext.ClearError(); 
     httpContext.Response.Clear(); 
     httpContext.Response.StatusCode = exception is HttpException ? ((HttpException)exception).GetHttpCode() : 500; 
     httpContext.Response.TrySkipIisCustomErrors = true; 

     routeData.Values["controller"] = "Error"; 
     routeData.Values["action"] = action; 

     controller.ViewData.Model = new HandleErrorInfo(exception, currentController, currentAction); 
     ((IController)controller).Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData)); 
    } 
} 

請注意,上面使用NLog記錄錯誤細節,但可能易於只需改變以支持別的東西。 另外,這個方法在解析ErrorController時會考慮你的IoC容器。

相關問題