Jak zrobić niestandardowe strony błędów działają w ASP.NET MVC 4

Chcę, aby Wyświetlono niestandardową stronę błędu dla 500, 404 i 403. Oto co zrobiłem:

  1. Włączone błędy niestandardowe w sieci.config w następujący sposób:

    <customErrors mode="On" 
                  defaultRedirect="~/Views/Shared/Error.cshtml">
    
        <error statusCode="403" 
               redirect="~/Views/Shared/UnauthorizedAccess.cshtml" />
    
        <error statusCode="404" 
               redirect="~/Views/Shared/FileNotFound.cshtml" />
    
    </customErrors>
    
  2. Zarejestrowany HandleErrorAttribute jako globalny filtr akcji w klasie FilterConfig w następujący sposób:

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new CustomHandleErrorAttribute());
        filters.Add(new AuthorizeAttribute());
    }
    
  3. Utworzono niestandardową stronę błędu dla każdego z powyższych komunikatów. Domyślny dla 500 był już dostępny po wyjęciu z pudełka.

  4. Deklarowane w każdym widoku strony błędu niestandardowego, że model dla strony jest System.Web.Mvc.HandleErrorInfo

Dla 500 pokazuje niestandardową stronę błędu. Dla innych nie.

Czy coś mi umyka?

Wygląda na to, że to nie wszystko, co jest do wyświetlania niestandardowych błędów, ponieważ czytam kod w metodzie OnException klasy HandleErrorAttribute i obsługuje tylko 500.

Co muszę zrobić, aby poradzić sobie z innymi błędami?

Author: H. Pauwelyn, 2012-12-17

11 answers

Moja obecna konfiguracja (na MVC3, ale myślę, że nadal obowiązuje) polega na posiadaniu ErrorController, więc używam:

<system.web>
    <customErrors mode="On" defaultRedirect="~/Error">
      <error redirect="~/Error/NotFound" statusCode="404" />
    </customErrors>
</system.web>

I kontroler zawiera:

public class ErrorController : Controller
{
    public ViewResult Index()
    {
        return View("Error");
    }
    public ViewResult NotFound()
    {
        Response.StatusCode = 404;  //you may want to set this to 200
        return View("NotFound");
    }
}

I widoki dokładnie tak, jak je realizujesz. Mam tendencję do dodawania trochę logiki jednak, aby pokazać ślad stosu i informacje o błędach, jeśli aplikacja jest w trybie debugowania. Więc Błąd.cshtml wygląda mniej więcej tak:

@model System.Web.Mvc.HandleErrorInfo
@{
    Layout = "_Layout.cshtml";
    ViewBag.Title = "Error";
}
<div class="list-header clearfix">
    <span>Error</span>
</div>
<div class="list-sfs-holder">
    <div class="alert alert-error">
        An unexpected error has occurred. Please contact the system administrator.
    </div>
    @if (Model != null && HttpContext.Current.IsDebuggingEnabled)
    {
        <div>
            <p>
                <b>Exception:</b> @Model.Exception.Message<br />
                <b>Controller:</b> @Model.ControllerName<br />
                <b>Action:</b> @Model.ActionName
            </p>
            <div style="overflow:scroll">
                <pre>
                    @Model.Exception.StackTrace
                </pre>
            </div>
        </div>
    }
</div>
 320
Author: Pablo Romeo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-23 13:26:20

Zrobiłem rozwiązanie pablo i zawsze miałem błąd (MVC4)

Widok 'Error' lub jego master nie został znaleziony lub żaden silnik widoku nie obsługuje wyszukiwanej lokalizacji.

Aby się tego pozbyć, usuń linię

 filters.Add(new HandleErrorAttribute());

W FilterConfig.cs

 34
Author: Machinegon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-07 18:18:51

Robię coś, co wymaga mniej kodowania niż inne opublikowane rozwiązania.

Najpierw w mojej sieci.config, mam następujące:
<customErrors mode="On" defaultRedirect="~/ErrorPage/Oops">
   <error redirect="~/ErrorPage/Oops/404" statusCode="404" />
   <error redirect="~/ErrorPage/Oops/500" statusCode="500" />
</customErrors>

Oraz controller (/Controllers / ErrorPageController.cs) zawiera:

public class ErrorPageController : Controller
{
    public ActionResult Oops(int id)
    {
        Response.StatusCode = id;

        return View();
    }
}

I wreszcie, Widok zawiera następujące (rozebrany dla uproszczenia, ale może być conta:

@{ ViewBag.Title = "Oops! Error Encountered"; }

<section id="Page">
  <div class="col-xs-12 well">
    <table cellspacing="5" cellpadding="3" style="background-color:#fff;width:100%;" class="table-responsive">
      <tbody>
        <tr>
          <td valign="top" align="left" id="tableProps">
            <img width="25" height="33" src="~/Images/PageError.gif" id="pagerrorImg">
          </td>
          <td width="360" valign="middle" align="left" id="tableProps2">
            <h1 style="COLOR: black; FONT: 13pt/15pt verdana" id="errortype"><span id="errorText">@Response.Status</span></h1>
          </td>
        </tr>
        <tr>
          <td width="400" colspan="2" id="tablePropsWidth"><font style="COLOR: black; FONT: 8pt/11pt verdana">Possible causes:</font>
          </td>
        </tr>
        <tr>
          <td width="400" colspan="2" id="tablePropsWidth2">
            <font style="COLOR: black; FONT: 8pt/11pt verdana" id="LID1">
                            <hr>
                            <ul>
                                <li id="list1">
                                    <span class="infotext">
                                        <strong>Baptist explanation: </strong>There
                                        must be sin in your life. Everyone else opened it fine.<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Presbyterian explanation: </strong>It's
                                        not God's will for you to open this link.<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong> Word of Faith explanation:</strong>
                                        You lack the faith to open this link. Your negative words have prevented
                                        you from realizing this link's fulfillment.<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Charismatic explanation: </strong>Thou
                                        art loosed! Be commanded to OPEN!<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Unitarian explanation:</strong> All
                                        links are equal, so if this link doesn't work for you, feel free to
                                        experiment with other links that might bring you joy and fulfillment.<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Buddhist explanation:</strong> .........................<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Episcopalian explanation:</strong>
                                        Are you saying you have something against homosexuals?<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Christian Science explanation: </strong>There
                                        really is no link.<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Atheist explanation: </strong>The only
                                        reason you think this link exists is because you needed to invent it.<br>
                                    </span>
                                </li>
                                <li>
                                    <span class="infotext">
                                        <strong>Church counselor's explanation:</strong>
                                        And what did you feel when the link would not open?
                                    </span>
                                </li>
                            </ul>
                            <p>
                                <br>
                            </p>
                            <h2 style="font:8pt/11pt verdana; color:black" id="ietext">
                                <img width="16" height="16" align="top" src="~/Images/Search.gif">
                                HTTP @Response.StatusCode - @Response.StatusDescription <br>
                            </h2>
                        </font>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</section>
To takie proste. Można go łatwo rozszerzyć, aby oferować bardziej szczegółowe informacje o błędach, ale ELMAH obsługuje to dla mnie & statusCode & statusDescription jest wszystkim, czego zwykle potrzebuję.
 19
Author: coderpros,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-15 11:41:44

Polecam użycie Global.asax.plik cs.

 protected void Application_Error(Object sender, EventArgs e)
{
    var exception = Server.GetLastError();
    if (exception is HttpUnhandledException)
    {
        Server.Transfer("~/Error.aspx");
    }
    if (exception != null)
    {
        Server.Transfer("~/Error.aspx");
    }
    try
    {
        // This is to stop a problem where we were seeing "gibberish" in the
        // chrome and firefox browsers
        HttpApplication app = sender as HttpApplication;
        app.Response.Filter = null;
    }
    catch
    {
    }
}
 12
Author: maxspan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-11 04:47:01

Wydaje się, że jest tu kilka kroków pomieszanych ze sobą. Przedstawię to, co zrobiłem od podstaw.

  1. Tworzenie kontrolera ErrorPage

    public class ErrorPageController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }
    
        public ActionResult Oops(int id)
        {
            Response.StatusCode = id;
            return View();
        }
    }
    
  2. Dodaj widoki dla tych dwóch działań (kliknij prawym przyciskiem myszy - > Dodaj Widok). Powinny one pojawić się w folderze o nazwie ErrorPage.

  3. Wewnątrz App_Start Otwórz FilterConfig.cs i skomentuj filtr obsługi błędów.

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        // Remove this filter because we want to handle errors ourselves via the ErrorPage controller
        //filters.Add(new HandleErrorAttribute());
    }
    
  4. Wewnątrz sieci.config dodaj następujące wpisy <customerErrors>, pod System.Web

    <customErrors mode="On" defaultRedirect="~/ErrorPage/Oops">
        <error redirect="~/ErrorPage/Oops/404" statusCode="404" />
        <error redirect="~/ErrorPage/Oops/500" statusCode="500" />
    </customErrors>
    
  5. Test (oczywiście). Wrzuć nieobsługiwany wyjątek w kodzie i zobacz, jak przechodzi do strony o id 500, a następnie użyj adresu URL do strony, która nie istnieje, aby zobaczyć 404.

 8
Author: VictorySaber,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-08 19:31:22

Bazując na odpowiedzi zamieszczonej przez maxspan, stworzyłem minimal przykładowy projekt na GitHub pokazujący wszystkie działające części.

Zasadniczo dodajemy metodę Application_Error do globalnej.asax.cs aby przechwycić wyjątek i dać nam możliwość przekierowania (lub bardziej poprawnie, żądania przeniesienia ) na niestandardową stronę błędu.

    protected void Application_Error(Object sender, EventArgs e)
    {
        // See http://stackoverflow.com/questions/13905164/how-to-make-custom-error-pages-work-in-asp-net-mvc-4
        // for additional context on use of this technique

        var exception = Server.GetLastError();
        if (exception != null)
        {
            // This would be a good place to log any relevant details about the exception.
            // Since we are going to pass exception information to our error page via querystring,
            // it will only be practical to issue a short message. Further detail would have to be logged somewhere.

            // This will invoke our error page, passing the exception message via querystring parameter
            // Note that we chose to use Server.TransferRequest, which is only supported in IIS 7 and above.
            // As an alternative, Response.Redirect could be used instead.
            // Server.Transfer does not work (see https://support.microsoft.com/en-us/kb/320439 )
            Server.TransferRequest("~/Error?Message=" + exception.Message);
        }

    }

Kontroler Błędów:

/// <summary>
/// This controller exists to provide the error page
/// </summary>
public class ErrorController : Controller
{
    /// <summary>
    /// This action represents the error page
    /// </summary>
    /// <param name="Message">Error message to be displayed (provided via querystring parameter - a design choice)</param>
    /// <returns></returns>
    public ActionResult Index(string Message)
    {
        // We choose to use the ViewBag to communicate the error message to the view
        ViewBag.Message = Message;
        return View();
    }

}

Widok strony błędu:

<!DOCTYPE html>

<html>
<head>
    <title>Error</title>
</head>
<body>

    <h2>My Error</h2>
    <p>@ViewBag.Message</p>
</body>
</html>

Nic innego nie jest w to zamieszane, poza wyłączanie / usuwanie filters.Add(new HandleErrorAttribute()) W FilterConfig.cs

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        //filters.Add(new HandleErrorAttribute()); // <== disable/remove
    }
}

Choć bardzo prosty w implementacji, jedyną wadą, którą widzę w tym podejściu, jest użycie querystring do dostarczania informacji o wyjątkach do docelowej strony błędu.

 6
Author: user3380909,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-23 17:02:02

Oto moje rozwiązanie. Użycie [ExportModelStateToTempData] / [ImportModelStateFromTempData] jest moim zdaniem niewygodne.

~ / Views / Home / Error.cshtml:

@{
    ViewBag.Title = "Error";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Error</h2>
<hr/>

<div style="min-height: 400px;">

    @Html.ValidationMessage("Error")

    <br />
    <br />

    <button onclick="Error_goBack()" class="k-button">Go Back</button>
    <script>
        function Error_goBack() {
            window.history.back()
        }
    </script>

</div>

~ / Controllers / HomeController. sc:

public class HomeController : BaseController
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult Error()
    {
        return this.View();
    }

    ...
}

~ / Controllers / BaseController. sc:

public class BaseController : Controller
{
    public BaseController() { }

    protected override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Result is ViewResult)
        {
            if (filterContext.Controller.TempData.ContainsKey("Error"))
            {
                var modelState = filterContext.Controller.TempData["Error"] as ModelState;
                filterContext.Controller.ViewData.ModelState.Merge(new ModelStateDictionary() { new KeyValuePair<string, ModelState>("Error", modelState) });
                filterContext.Controller.TempData.Remove("Error");
            }
        }
        if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
        {
            if (filterContext.Controller.ViewData.ModelState.ContainsKey("Error"))
            {
                filterContext.Controller.TempData["Error"] = filterContext.Controller.ViewData.ModelState["Error"];
            }
        }

        base.OnActionExecuted(filterContext);
    }
}

~ / Controllers / MyController. sc:

public class MyController : BaseController
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult Details(int id)
    {
        if (id != 5)
        {
            ModelState.AddModelError("Error", "Specified row does not exist.");
            return RedirectToAction("Error", "Home");
        }
        else
        {
            return View("Specified row exists.");
        }
    }
}

Życzę udanych projektów; -)

 2
Author: ADM-IT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-05 19:35:41

Błędy mogą działać poprawnie bez hackowania global.cs, mieszanie z HandleErrorAttribute, Robienie odpowiedzi.TrySkipIisCustomErrors, hooking up Application_Error, or whatever:

W systemie.web (tylko zwykły, on / off)

<customErrors mode="On">
  <error redirect="/error/401" statusCode="401" />
  <error redirect="/error/500" statusCode="500" />
</customErrors>

I w systemie.webServer

<httpErrors existingResponse="PassThrough" />

Teraz rzeczy powinny zachowywać się zgodnie z oczekiwaniami i możesz użyć kontrolera błędów, aby wyświetlić wszystko, czego potrzebujesz.

 2
Author: Robert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-14 12:45:42

Miałem wszystko skonfigurowane, ale nadal nie mogłem zobaczyć poprawnych stron błędów dla kodu stanu 500 na naszym serwerze testowym, pomimo faktu, że wszystko działało dobrze na lokalnych serwerach deweloperskich.

Znalazłemten wpis na blogu od Ricka Strahla, który mi pomógł.

Musiałem dodać Response.TrySkipIisCustomErrors = true; do mojego niestandardowego kodu obsługi błędów.

 0
Author: DCShannon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-08 01:57:19

Wygląda na to, że spóźniłem się na imprezę, ale lepiej Zobacz też to.

Więc w {[2] } do buforowania WYJĄTKÓW wewnątrz aplikacji, takich jak return HttpNotFound ()

  <system.web>
    <customErrors mode="RemoteOnly">
      <error statusCode="404" redirect="/page-not-found" />
      <error statusCode="500" redirect="/internal-server-error" />
    </customErrors>
  </system.web>

I w system.webServer za nadrabianie błędów, które zostały złapane przez IIS i nie dotarły do asp.net framework

 <system.webServer>
    <httpErrors errorMode="DetailedLocalOnly">
      <remove statusCode="404"/>
      <error statusCode="404" path="/page-not-found" responseMode="Redirect"/>
      <remove statusCode="500"/>
      <error statusCode="500" path="/internal-server-error" responseMode="Redirect"/>
  </system.webServer>

W ostatnim, jeśli martwisz się o odpowiedź klienta, Zmień responseMode="Redirect" na responseMode="File" i podaj statyczny plik html, ponieważ ten wyświetli przyjazną stronę z kod odpowiedzi 200.

 0
Author: OrElse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-11 16:52:44

W sieci.config dodaj to pod system.webserver tag jak poniżej,

<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
  <remove statusCode="404"/>
  <remove statusCode="500"/>
  <error statusCode="404" responseMode="ExecuteURL" path="/Error/NotFound"/>
  <error statusCode="500" responseMode="ExecuteURL"path="/Error/ErrorPage"/>
</httpErrors>

I dodaj kontroler jako,

public class ErrorController : Controller
{
    //
    // GET: /Error/
    [GET("/Error/NotFound")]
    public ActionResult NotFound()
    {
        Response.StatusCode = 404;

        return View();
    }

    [GET("/Error/ErrorPage")]
    public ActionResult ErrorPage()
    {
        Response.StatusCode = 500;

        return View();
    }
}

I dodać ich szanowane poglądy, to będzie działać na pewno, myślę, że dla wszystkich.

To rozwiązanie znalazłem z: Neptun Century

 0
Author: Dpk-Kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-30 08:06:55