it-swarm.com.de

Funktionsweise benutzerdefinierter Fehlerseiten in ASP.NET MVC 4

Ich möchte, dass eine benutzerdefinierte Fehlerseite für 500, 404 und 403 angezeigt wird.

  1. Aktivierte benutzerdefinierte Fehler in der web.config wie folgt:

    <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. Registrieren Sie HandleErrorAttribute wie folgt als globalen Aktionsfilter in der Klasse FilterConfig:

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new CustomHandleErrorAttribute());
        filters.Add(new AuthorizeAttribute());
    }
    
  3. Erstellt eine benutzerdefinierte Fehlerseite für jede der oben genannten Meldungen. Die Standardeinstellung für 500 war bereits im Auslieferungszustand verfügbar.

  4. In jeder benutzerdefinierten Fehlerseitenansicht wurde deklariert, dass das Modell für die Seite System.Web.Mvc.HandleErrorInfo ist.

Für 500 wird die benutzerdefinierte Fehlerseite angezeigt. Für andere ist das nicht der Fall.

Fehlt mir etwas?

Es sieht so aus, als ob dies nicht alles ist, was zum Anzeigen benutzerdefinierter Fehler erforderlich ist, wenn ich den Code in der OnException -Methode der HandleErrorAttribute -Klasse durchlese, und sie verarbeitet nur 500.

Was muss ich tun, um andere Fehler zu behandeln?

236
Water Cooler v2

Mein aktuelles Setup (auf MVC3, aber ich denke, es gilt immer noch) basiert auf einem ErrorController, daher verwende ich:

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

Und der Controller enthält Folgendes:

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

Und die Ansichten genau so, wie Sie sie implementieren. Ich neige dazu, ein bisschen Logik hinzuzufügen, um die Stack-Trace- und Fehlerinformationen anzuzeigen, wenn sich die Anwendung im Debug-Modus befindet. Error.cshtml sieht also ungefähr so ​​aus:

@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>
343
Pablo Romeo

Ich habe Pablo-Lösung gemacht und ich hatte immer den Fehler (MVC4)

Die Ansicht 'Fehler' oder ihr Master wurde nicht gefunden oder keine Ansichts-Engine unterstützt den gesuchten Ort.

Um dies loszuwerden, entfernen Sie die Zeile

 filters.Add(new HandleErrorAttribute());

in FilterConfig.cs

39
Machinegon

Ich mache etwas, das weniger Programmierung erfordert als die anderen Lösungen, die veröffentlicht werden.

Erstens habe ich in meiner web.config Folgendes:

<customErrors mode="On" defaultRedirect="~/ErrorPage/Oops">
   <error redirect="~/ErrorPage/Oops/404" statusCode="404" />
   <error redirect="~/ErrorPage/Oops/500" statusCode="500" />
</customErrors>

Der Controller (/Controllers/ErrorPageController.cs) enthält Folgendes:

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

        return View();
    }
}

Und schließlich enthält die Ansicht Folgendes (der Einfachheit halber abgespeckt, kann aber Folgendes enthalten:

@{ 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>

So einfach ist das. Es könnte leicht erweitert werden, um detailliertere Fehlerinformationen anzubieten, aber ELMAH erledigt das für mich und der statusCode & statusDescription ist alles, was ich normalerweise brauche.

20
coderpro

Ich würde empfehlen, die Datei Global.asax.cs zu verwenden.

 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
maxspan

Hier scheint eine Reihe von Schritten zusammengewürfelt zu sein. Ich werde vorbringen, was ich von Grund auf getan habe.

  1. Erstellen Sie den Controller ErrorPage

    public class ErrorPageController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }
    
        public ActionResult Oops(int id)
        {
            Response.StatusCode = id;
            return View();
        }
    }
    
  2. Fügen Sie Ansichten für diese beiden Aktionen hinzu (Rechtsklick -> Ansicht hinzufügen). Diese sollten in einem Ordner mit dem Namen ErrorPage angezeigt werden.

  3. In App_Start öffne FilterConfig.cs und kommentiere den Fehlerbehandlungsfilter aus.

    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. Fügen Sie in web.config die folgenden <customerErrors> Einträge unter System.Web hinzu

    <customErrors mode="On" defaultRedirect="~/ErrorPage/Oops">
        <error redirect="~/ErrorPage/Oops/404" statusCode="404" />
        <error redirect="~/ErrorPage/Oops/500" statusCode="500" />
    </customErrors>
    
  5. Test (natürlich). Lösen Sie eine nicht behandelte Ausnahme in Ihrem Code aus, und rufen Sie die Seite mit der ID 500 auf. Verwenden Sie anschließend eine URL zu einer Seite, die nicht vorhanden ist, um 404 anzuzeigen.

9
VictorySaber

Aufbauend auf der Antwort von maxspan habe ich ein minimales Beispielprojekt auf GitHub zusammengestellt, das alle funktionierenden Teile zeigt.

Grundsätzlich fügen wir eine Application_Error -Methode zu global.asax.cs hinzu, um die Ausnahme abzufangen und uns die Möglichkeit zu geben, umzuleiten (oder mehr) richtig, transfer request ) zu einer benutzerdefinierten Fehlerseite.

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

    }

Fehlercontroller:

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

}

Fehlerseitenansicht:

<!DOCTYPE html>

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

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

Es handelt sich nur um das Deaktivieren/Entfernen von filters.Add(new HandleErrorAttribute()) in FilterConfig.cs .

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

Obwohl sehr einfach zu implementieren, ist der einzige Nachteil, den ich bei diesem Ansatz sehe, die Verwendung von Querystring, um Ausnahmeinformationen an die Zielfehlerseite zu liefern.

6
user3380909

Ich hatte alles eingerichtet, konnte aber immer noch keine richtigen Fehlerseiten für den Statuscode 500 auf unserem Staging-Server sehen, obwohl auf lokalen Entwicklungsservern alles einwandfrei funktionierte.

Ich habe diesen Blog-Beitrag von Rick Strahl gefunden, der mir geholfen hat.

Ich musste meinem benutzerdefinierten Fehlerbehandlungscode Response.TrySkipIisCustomErrors = true; hinzufügen.

2
DCShannon

Hier ist meine Lösung. Die Verwendung von [ExportModelStateToTempData]/[ImportModelStateFromTempData] ist meiner Meinung nach unangenehm.

~/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>

~/Controller/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);
    }
}

~/Controller/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.");
        }
    }
}

Ich wünsche Ihnen erfolgreiche Projekte ;-)

2
ADM-IT

Sie können dazu führen, dass Fehler korrekt funktionieren, ohne global.cs zu hacken, mit HandleErrorAttribute in Konflikt zu geraten, Response.TrySkipIisCustomErrors auszuführen, Application_Error anzuhängen oder was auch immer:

In system.web (nur das Übliche, ein/aus)

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

und in system.webServer

<httpErrors existingResponse="PassThrough" />

Jetzt sollten sich die Dinge wie erwartet verhalten und Sie können Ihren ErrorController verwenden, um alles anzuzeigen, was Sie benötigen.

1
Robert Hoffmann

Es sieht so aus, als wäre ich zu spät zur Party gekommen, aber das solltest du dir auch mal ansehen.

Also in system.web für das Zwischenspeichern von Ausnahmen in der Anwendung, z. B. return HttpNotFound ()

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

und in system.webServer für das Auffinden von Fehlern, die von IIS abgefangen wurden und nicht in das asp.net-Framework gelangt sind

 <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>

Wenn Sie sich im letzten Fall Gedanken über die Clientantwort machen, ändern Sie den responseMode="Redirect" in responseMode="File" und stellen Sie eine statische HTML-Datei bereit, da auf dieser Seite eine Seite mit einem 200-Antwortcode angezeigt wird.

0
OrElse

Fügen Sie dies in der Datei web.config unter dem Tag system.webserver wie folgt hinzu:

<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>

und fügen Sie einen Controller hinzu als,

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

und fügen Sie ihre respektierten Ansichten hinzu, das wird auf jeden Fall funktionieren, denke ich für alle.

Diese Lösung habe ich gefunden von: Neptune Century

0
Dpk-Kumar