18

Tôi có sau trong web.config của tôi:Trong ASP.NET MVC những gì là hiển thị tốt nhất unhandled ngoại lệ trong quan điểm của tôi?

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

Tôi có một

[HandleError] 

ở phía trên cùng của lớp HomeController tôi. Để kiểm tra, tôi tạo và hành động đơn giản ném một ngoại lệ. . và nó chuyển hướng đến phương pháp

ErrorController/Index 

của tôi, nhưng khi nó được cho quan điểm của tôi mà liên kết với HandleErrorInfo mô hình của tôi là null vì vậy tôi bằng cách nào đó đã mất đi sự ám chỉ đến lỗi.

Tôi chắc chắn rằng nó có liên quan đến Lỗi bị mất trong chuyển hướng vì vậy tôi muốn xem liệu tôi có thiếu thứ gì không và có ai có đề xuất nơi tôi có thể có chế độ xem hiển thị Stacktrace và thông báo lỗi không.

+0

customError mất tất cả tham chiếu đến lỗi. –

+0

bản sao có thể có của [Làm cách nào để xử lý các ngoại lệ không bị bắt trong ứng dụng ASP.NET MVC 3?] (Http://stackoverflow.com/questions/6596648/how-do-i-handle-uncaught-exceptions-in-an- asp-net-mvc-3-application) –

+0

Trong khi customError chuyển hướng nó đang thực hiện một yêu cầu http mới để mất tất cả dữ liệu trả lời trước đó. Những gì bạn cần là đặt redirectMode thành ResponseRewrite để bạn không thực hiện yêu cầu mới. –

Trả lời

22

Tôi có thể thấy quan niệm sai lầm. Bạn muốn thực hiện các điều MVCredirect cho một hành động điều khiển.

Nhưng defaultRedirect chính nó là quy ước Web Form và do đó bị giới hạn. Thời điểm bạn chuyển hướng đến controller khác, bạn sẽ mất HttpContext của bạn, và do đó mất HandleErrorInfo Object của bạn

[HandleError] Thuộc tính của bạn đòi hỏi một View chỉ đạo thông báo lỗi của nó đến. Theo ví dụ của bạn ở trên, tôi giả sử rằng bạn có một Thư mục Views/Error cho số ErrorController của mình và trong đó bạn có Chế độ xem Index. Nếu bạn muốn lọc Bối cảnh của bạn để gửi một đối tượng HandleErrorInfo đến quan điểm cho rằng,

Hãy thử cú pháp sau:

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

Nhưng những gì về Logging?!?!?

tôi nghi ngờ ý định của bạn là hơn hơn là chỉ hiển thị đống lỗi cho người dùng. Trong thực tế, tôi nghi ngờ bạn không có ý định như vậy cả. Tôi nghi ngờ mục đích thực sự của bạn là để đăng nhập lỗi của bạn (có thể là db) và để hiển thị một số thông điệp nhạt nhẽo cho người dùng của bạn.

Điều tôi đã giải thích cho đến thời điểm này là "cách tốt nhất [cách] hiển thị ngoại lệ không được xử lý trong chế độ xem của tôi". Thuộc tính [HandleError] là tốt cho điều đó.

Nhưng khi bạn muốn di chuyển sang bước tiếp theo (đăng nhập lỗi), bạn có một vài lựa chọn:

1) Override your base controller's On Exception method; tạo riêng của bạn Controller kế thừa từ lớp MVC Controller nhưng ghi đè lên On Exception Method. Có thể sử dụng phương pháp này cùng với thuộc tính [HandleError]

2) Create a custom exception handler Tạo Trình xử lý ngoại lệ của riêng bạn để ghi lại lỗi. Người xử lý ngoại lệ của bạn sau đó có thể gọi Chế độ xem lựa chọn hoặc có thể hoạt động cùng với [HandleError(order=2)] vì thuộc tính bộ lọc có thể lấy đối số đơn đặt hàng ưu tiên.


Nitin Sawant hỏi những gì một cái nhìn lỗi sẽ trông như thế nào.

@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

bạn có thể đăng nội dung của '~/Views/Error/Index' không? –

+1

@NitinSawant, tôi hy vọng điều này sẽ hữu ích –

1

Tôi đã sử dụng đoạn mã nhỏ này để hiển thị trang lỗi do người dùng xử lý. Không tìm thấy trang hoặc một số lỗi khác xảy ra.

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

Và bộ điều khiển lỗi trông giống như thế này. Nếu bạn cần ngoại lệ chi tiết, bạn có thể truy cập ngoại lệ qua 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(); 
    } 
} 

Bạn có thể thêm chế độ xem khác nhau cho mỗi mã http. Chỉ cần thực hiện hành động Http {Code}

6

Tôi làm điều gì đó tương tự như maxlego xử lý tất cả các lỗi (không chỉ những lỗi xảy ra trong bộ điều khiển với thuộc tính HandleError).

Lớp học của tôi MvcApplication (trong global.asax.cs) có này:

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

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

Đoạn mã trên sử dụng một phương pháp khuyến nông từ thư viện MVC của tôi về công cụ hữu ích. Với điều này tại chỗ tôi không cần bất kỳ lỗi xử lý các thuộc tính, cấu hình customErrors hoặc các bộ lọc tùy chỉnh. Thay vào đó, phương pháp khuyến nông sẽ ghi lại các chi tiết lỗi sau đó gọi một cái nhìn thích hợp, hoặc là:

  • AccessDenied
  • notfound
  • InternalServerError

Mã phương pháp khuyến nông để làm cho công việc này là:

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

Lưu ý, ở trên sử dụng NLog để ghi nhật ký chi tiết lỗi nhưng có thể easi ly được thay đổi để hỗ trợ cái gì khác. Ngoài ra, phương pháp này tôn trọng container IoC của bạn khi giải quyết ErrorController.