Các trang lỗi tùy chỉnh trên asp.net MVC3


144

Tôi đang phát triển một trang web cơ sở MVC3 và tôi đang tìm giải pháp xử lý lỗi và Hiển thị Chế độ xem tùy chỉnh cho từng loại lỗi. Vì vậy, hãy tưởng tượng rằng tôi có Bộ điều khiển "Lỗi" trong đó hành động chính của anh ta là "Chỉ mục" (trang lỗi chung) và bộ điều khiển này sẽ có thêm một số hành động cho các lỗi có thể xuất hiện cho người dùng như "Xử lý 500" hoặc "Xử lýActionNotFound".

Vì vậy, mọi lỗi có thể xảy ra trên trang web có thể được xử lý bởi Trình điều khiển "Lỗi" này (ví dụ: "Trình điều khiển" hoặc "Hành động" không tìm thấy, 500, 404, dbException, v.v.).

Tôi đang sử dụng tệp Sơ đồ trang web để xác định đường dẫn trang web (chứ không phải tuyến đường).

Câu hỏi này đã được trả lời, đây là câu trả lời cho Gweebz

Phương pháp applicaiton_error cuối cùng của tôi là như sau:

protected void Application_Error() {
//while my project is running in debug mode
if (HttpContext.Current.IsDebuggingEnabled && WebConfigurationManager.AppSettings["EnableCustomErrorPage"].Equals("false"))
{
    Log.Logger.Error("unhandled exception: ", Server.GetLastError());
}
else
{
    try
    {
        var exception = Server.GetLastError();

        Log.Logger.Error("unhandled exception: ", exception);

        Response.Clear();
        Server.ClearError();
        var routeData = new RouteData();
        routeData.Values["controller"] = "Errors";
        routeData.Values["action"] = "General";
        routeData.Values["exception"] = exception;

        IController errorsController = new ErrorsController();
        var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
        errorsController.Execute(rc);
    }
    catch (Exception e)
    {
        //if Error controller failed for same reason, we will display static HTML error page
        Log.Logger.Fatal("failed to display error page, fallback to HTML error: ", e);
        Response.TransmitFile("~/error.html");
    }
}
}

Các cài đặt nên có trong web.config để hỗ trợ điều này? Chắc chắn bạn sẽ không bao gồm bất kỳ cài đặt omeperrors?
philbird

forums.asp.net/p/1782402/4894514.aspx/... có một số lời khuyên tốt đẹp như IE sẽ không hiển thị trang báo lỗi của bạn nếu nó là dưới 512 byte
RickAndMSFT

Câu trả lời:


201

Đây là một ví dụ về cách tôi xử lý các lỗi tùy chỉnh. Tôi xác định một ErrorsControllerhành động xử lý các lỗi HTTP khác nhau:

public class ErrorsController : Controller
{
    public ActionResult General(Exception exception)
    {
        return Content("General failure", "text/plain");
    }

    public ActionResult Http404()
    {
        return Content("Not found", "text/plain");
    }

    public ActionResult Http403()
    {
        return Content("Forbidden", "text/plain");
    }
}

và sau đó tôi đăng ký Application_Errorvào Global.asaxvà gọi trình điều khiển này:

protected void Application_Error()
{
    var exception = Server.GetLastError();
    var httpException = exception as HttpException;
    Response.Clear();
    Server.ClearError();
    var routeData = new RouteData();
    routeData.Values["controller"] = "Errors";
    routeData.Values["action"] = "General";
    routeData.Values["exception"] = exception;
    Response.StatusCode = 500;
    if (httpException != null)
    {
        Response.StatusCode = httpException.GetHttpCode();
        switch (Response.StatusCode)
        {
            case 403:
                routeData.Values["action"] = "Http403";
                break;
            case 404:
                routeData.Values["action"] = "Http404";
                break;
        }
    }

    IController errorsController = new ErrorsController();
    var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
    errorsController.Execute(rc);
}

4
Chỉ cần một lưu ý nhỏ. Vì tôi muốn hiển thị Chế độ xem trong từng trường hợp (404, 500, v.v.) trên mỗi ActionResult, tôi đã trả lại Chế độ xem. Tuy nhiên, tôi đã thử bắt xung quanh nội dung Application_Error và tôi gặp trường hợp lỗi trang HTML tĩnh được trả lại. (Tôi có thể đăng mã nếu ai đó mong muốn)
John Louros

4
Tôi không thể có được lượt xem dao cạo để kết xuất bằng giải pháp này trên MVC3. return View (model) chẳng hạn chỉ có một màn hình trống.
Extrakun

2
Đã thêm TrySkipIisCustomErrors để sửa lỗi cho IIS7 tích hợp. Xem stackoverflow.com/questions/1706934/ từ
Pavel Savara

1
@ajbeaven, Executelà một phương thức được xác định trong IControllergiao diện. Điều này không thể được bảo vệ. Nhìn vào mã của tôi cẩn thận hơn: IController errorsController = new ErrorsController();và chú ý loại errorsControllerbiến mà tôi đang gọi Executephương thức. Đó là loại IControllervì vậy hoàn toàn không có gì ngăn cản bạn gọi phương thức này. Và nhân tiện, nó Executeđã được bảo vệ trong lớp Trình điều khiển cũng như trong MVC 3, vì vậy không có thay đổi nào về vấn đề này.
Darin Dimitrov

2
Đã sửa bằng cách chỉ định rõ ràng loại nội dung của phản hồi:Response.ContentType = "text/html";
ajbeaven


6

Bạn cũng có thể làm điều này trong Tệp Web.Config. Đây là một ví dụ hoạt động trong IIS 7.5.

     <system.webServer>
          <httpErrors errorMode="DetailedLocalOnly" defaultResponseMode="File">
                <remove statusCode="502" subStatusCode="-1" />
                <remove statusCode="501" subStatusCode="-1" />
                <remove statusCode="412" subStatusCode="-1" />
                <remove statusCode="406" subStatusCode="-1" />
                <remove statusCode="405" subStatusCode="-1" />
                <remove statusCode="404" subStatusCode="-1" />
                <remove statusCode="403" subStatusCode="-1" />
                <remove statusCode="401" subStatusCode="-1" />
                <remove statusCode="500" subStatusCode="-1" />
                <error statusCode="500" path="/notfound.html" responseMode="ExecuteURL" />
                <error statusCode="401" prefixLanguageFilePath="" path="/500.html" responseMode="ExecuteURL" />
                <error statusCode="403" prefixLanguageFilePath="" path="/403.html" responseMode="ExecuteURL" />
                <error statusCode="404" prefixLanguageFilePath="" path="/404.html" responseMode="ExecuteURL" />
                <error statusCode="405" prefixLanguageFilePath="" path="/405.html" responseMode="ExecuteURL" />
                <error statusCode="406" prefixLanguageFilePath="" path="/406.html" responseMode="ExecuteURL" />
                <error statusCode="412" prefixLanguageFilePath="" path="/412.html" responseMode="ExecuteURL" />
                <error statusCode="501" prefixLanguageFilePath="" path="/501.html" responseMode="ExecuteURL" />
                <error statusCode="502" prefixLanguageFilePath="" path="/genericerror.html" responseMode="ExecuteURL" />
           </httpErrors>
</system.webServer>

3

Tôi thấy bạn đã thêm một giá trị cấu hình cho EnableCustomErrorPagevà bạn cũng đang kiểm tra IsDebuggingEnabledđể xác định xem có nên chạy xử lý lỗi hay không.

Vì đã có <customErrors/>cấu hình trong ASP.NET (có nghĩa là chính xác cho mục đích này), thật dễ dàng để nói:

    protected void Application_Error()
    {
        if (HttpContext.Current == null) 
        {
                // errors in Application_Start will end up here                
        }
        else if (HttpContext.Current.IsCustomErrorEnabled)
        {
                // custom exception handling
        }
    }

Sau đó, trong cấu hình bạn đặt <customErrors mode="RemoteOnly" />an toàn để triển khai như vậy và khi bạn cần kiểm tra trang lỗi tùy chỉnh của mình, bạn sẽ đặt nó để <customErrors mode="On" />bạn có thể xác minh rằng nó hoạt động.

Lưu ý bạn cũng cần kiểm tra xem HttpContext.Currentcó phải không vì một ngoại lệ Application_Startsẽ vẫn là phương thức này mặc dù sẽ không có bối cảnh hoạt động.


2

Bạn có thể hiển thị trang lỗi thân thiện với người dùng với mã trạng thái http chính xác bằng cách triển khai mô-đun Xử lý ngoại lệ thân thiện với người dùng của Jeff Atwood với một sửa đổi nhỏ cho mã trạng thái http. Nó hoạt động mà không có bất kỳ chuyển hướng. Mặc dù mã là từ năm 2004 (!), Nhưng nó hoạt động tốt với MVC. Nó có thể được cấu hình hoàn toàn trong web.config của bạn, không có thay đổi mã nguồn dự án MVC nào cả.

Việc sửa đổi cần thiết để trả về trạng thái HTTP ban đầu thay vì 200trạng thái được mô tả trong bài đăng trên diễn đàn có liên quan này .

Về cơ bản, trong Handler.vb, bạn có thể thêm một cái gì đó như:

' In the header...
Private _exHttpEx As HttpException = Nothing

' At the top of Public Sub HandleException(ByVal ex As Exception)...
HttpContext.Current.Response.StatusCode = 500
If TypeOf ex Is HttpException Then
    _exHttpEx = CType(ex, HttpException)
    HttpContext.Current.Response.StatusCode = _exHttpEx.GetHttpCode()
End If

0

Tôi đang sử dụng MVC 4.5 và tôi gặp vấn đề với giải pháp của Darin. Lưu ý: Giải pháp của Darin là tuyệt vời và tôi đã sử dụng nó để đưa ra giải pháp của mình. Đây là giải pháp sửa đổi của tôi:

protected void Application_Error(object sender, EventArgs e)
{           
var exception = Server.GetLastError();
var httpException = exception as HttpException;
Response.StatusCode = httpException.GetHttpCode();

Response.Clear();
Server.ClearError();


if (httpException != null)
{
    var httpContext = HttpContext.Current;

    httpContext.RewritePath("/Errors/InternalError", false);

    // MVC 3 running on IIS 7+
    if (HttpRuntime.UsingIntegratedPipeline)
    {
        switch (Response.StatusCode)
        {
            case 403:
                httpContext.Server.TransferRequest("/Errors/Http403", true);
                break;
            case 404:
                httpContext.Server.TransferRequest("/Errors/Http404", true);
                break;
            default:
                httpContext.Server.TransferRequest("/Errors/InternalError", true);
                break;
        }
    }
    else
    {
        switch (Response.StatusCode)
        {
            case 403:
                httpContext.RewritePath(string.Format("/Errors/Http403", true));
                break;
            case 404:
                httpContext.RewritePath(string.Format("/Errors/Http404", true));
                break;
            default:
                httpContext.RewritePath(string.Format("/Errors/InternalError", true));
                break;
        }

        IHttpHandler httpHandler = new MvcHttpHandler();
        httpHandler.ProcessRequest(httpContext);
    }
}
}

2
Bạn gặp vấn đề gì với giải pháp của Darin?
Kenny Evitt

Bạn đã không mô tả vấn đề bạn gặp phải đã đưa ra một câu trả lời cạnh tranh.
ivanjonas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.