Спеціальні сторінки помилок на asp.net MVC3


144

Я розробляю базовий веб-сайт MVC3 і шукаю рішення для обробки помилок та відображення користувальницьких поглядів для кожного виду помилок. Тож уявіть, що у мене є контролер "Помилка", де його основною дією є "Індекс" (загальна сторінка помилок), і цей контролер матиме ще пару дій щодо помилок, які можуть з’явитися користувачеві на кшталт "Handle500" або "HandleActionNotFound".

Отже, будь-яка помилка, яка може статися на веб-сайті, може оброблятися цим контролером "Помилка" (приклади: "Контролер" або "Дія" не знайдено, 500, 404, dbException тощо).

Я використовую файл Sitemap для визначення шляхів веб-сайту (а не маршруту).

На це запитання вже відповіли, це відповідь Gweebz

Мій остаточний метод applicaiton_error такий:

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

Які параметри повинні бути в web.config для підтримки цього? Ви, ймовірно, не включили жодні налаштування https?
philbird

forums.asp.net/p/1782402/4894514.aspx/… має кілька приємних підказок, як IE не показуватиме вашу сторінку помилок, якщо вона знаходиться під 512 байтами
RickAndMSFT

Відповіді:


201

Ось приклад того, як я обробляю власні помилки. Я визначаю ErrorsControllerдії з обробкою різних помилок HTTP:

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

а потім я приєднуюся до Application_Errorв Global.asaxі викликати цей контролер:

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
Лише невелика записка. Оскільки я хотів надати перегляд у кожному випадку (404, 500 тощо) для кожного ActionResult, я повернув перегляд. Однак я спробував наздогнати вміст Application_Error, і в разі відмови статична HTML-сторінка повертається. (Я можу розмістити код, якщо хтось захоче)
Джон Лурос

4
Я не можу отримати вигляд бритви для відображення за допомогою цього рішення на MVC3. наприклад, повернення View (модель) отримує лише порожній екран.
Екстракун

2
Додано TrySkipIisCustomErrors, щоб виправити це для інтегрованого IIS7. Дивіться stackoverflow.com/questions/1706934/…
Павло Савара

1
@ajbeaven, Executeце метод, визначений в IControllerінтерфейсі. Це неможливо захистити. Погляньте на мій код уважніше: IController errorsController = new ErrorsController();і помітьте тип errorsControllerзмінної, на яку я викликаю Executeметод. Він типу, IControllerтому абсолютно нічого не заважає вам закликати цей метод. І, до речі, Executeбув захищений і в класі Controller, і в MVC 3, тому змін у цьому плані немає.
Дарин Димитров

2
Виправлено шляхом явного вказівки типу вмісту відповіді:Response.ContentType = "text/html";
ajbeaven


6

Ви також можете це зробити у файлі Web.Config. Ось приклад, який працює в 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

Я бачу, що ви додали значення конфігурації для, EnableCustomErrorPageі ви також перевіряєте, IsDebuggingEnabledчи потрібно запускати обробку помилок чи ні.

Оскільки <customErrors/>в ASP.NET вже є конфігурація (яка призначена саме для цієї мети), найпростіше просто сказати:

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

Потім у налаштованому вами конфігурації, <customErrors mode="RemoteOnly" />який безпечно розгортати таким чином, і коли вам потрібно перевірити вашу власну сторінку помилок, ви встановите її <customErrors mode="On" />так, щоб ви могли переконатися, що вона працює.

Зауважте, вам також потрібно перевірити, чи HttpContext.Currentнедійсний, оскільки виняток у Application_Startцьому методі все ще буде, хоча активного контексту не буде.


2

Ви можете відобразити зручну сторінку помилок із правильним кодом статусу http, застосувавши модуль поводження з дружнім користувачем Jeff Atwood з незначною зміною коду статусу http. Він працює без перенаправлень. Хоча код з 2004 року (!), Він добре працює з MVC. Він може бути налаштований повністю у вашій web.config, без зміни вихідного коду проекту MVC.

Модифікація, необхідна для повернення початкового статусу HTTP, а не 200стану, описана в цьому відповідному дописі на форумі .

В основному в Handler.vb ви можете додати щось на кшталт:

' 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

Я використовую MVC 4.5, і у мене виникли проблеми з рішенням Даріна. Примітка: Рішення Даріна відмінне, і я використовував його, щоб придумати своє рішення. Ось моє модифіковане рішення:

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
Які проблеми у вас виникли з рішенням Даріна?
Кенні Евітт

Ви не описували проблему, яку ви відчули, що спонукало відповідати.
ivanjonas
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.