Wie heißt Error.cshtml in ASP.NET MVC?

77

Ich habe ein Dutzend ähnlicher Fragen zu StackOverflow gelesen, aber ich kann das anscheinend nicht verstehen. Wie wird die Error.cshtml in Bezug auf den benutzerdefinierten Fehlerknoten in der web.config und das HandleErrorAttribute jemals aufgerufen? Letztendlich kann die Antwort auf diese Frage die Antwort auf eine der mehreren Fragen sein, die es bereits zur ASP.NET MVC-Fehlerbehandlung gibt. Tatsache ist jedoch, dass ich nicht weiß, welche.

LJM
quelle

Antworten:

90

In Ihrer Global.asax haben Sie die folgende Methode:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
}

Dadurch wird das HandleErrorAttribute als globaler Aktionsfilter registriert. Dies bedeutet, dass dieser Handler automatisch auf alle Controller-Aktionen angewendet wird. Schauen wir uns nun anhand des Quellcodes an, wie dieses Attribut implementiert wird:

[SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "This attribute is AllowMultiple = true and users might want to override behavior.")]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class HandleErrorAttribute : FilterAttribute, IExceptionFilter {

    private const string _defaultView = "Error";

    private readonly object _typeId = new object();

    private Type _exceptionType = typeof(Exception);
    private string _master;
    private string _view;

    public Type ExceptionType {
        get {
            return _exceptionType;
        }
        set {
            if (value == null) {
                throw new ArgumentNullException("value");
            }
            if (!typeof(Exception).IsAssignableFrom(value)) {
                throw new ArgumentException(String.Format(CultureInfo.CurrentCulture,
                    MvcResources.ExceptionViewAttribute_NonExceptionType, value.FullName));
            }

            _exceptionType = value;
        }
    }

    public string Master {
        get {
            return _master ?? String.Empty;
        }
        set {
            _master = value;
        }
    }

    public override object TypeId {
        get {
            return _typeId;
        }
    }

    public string View {
        get {
            return (!String.IsNullOrEmpty(_view)) ? _view : _defaultView;
        }
        set {
            _view = value;
        }
    }

    public virtual void OnException(ExceptionContext filterContext) {
        if (filterContext == null) {
            throw new ArgumentNullException("filterContext");
        }
        if (filterContext.IsChildAction) {
            return;
        }

        // If custom errors are disabled, we need to let the normal ASP.NET exception handler
        // execute so that the user can see useful debugging information.
        if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled) {
            return;
        }

        Exception exception = filterContext.Exception;

        // If this is not an HTTP 500 (for example, if somebody throws an HTTP 404 from an action method),
        // ignore it.
        if (new HttpException(null, exception).GetHttpCode() != 500) {
            return;
        }

        if (!ExceptionType.IsInstanceOfType(exception)) {
            return;
        }

        string controllerName = (string)filterContext.RouteData.Values["controller"];
        string actionName = (string)filterContext.RouteData.Values["action"];
        HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
        filterContext.Result = new ViewResult {
            ViewName = View,
            MasterName = Master,
            ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
            TempData = filterContext.Controller.TempData
        };
        filterContext.ExceptionHandled = true;
        filterContext.HttpContext.Response.Clear();
        filterContext.HttpContext.Response.StatusCode = 500;

        // Certain versions of IIS will sometimes use their own error page when
        // they detect a server error. Setting this property indicates that we
        // want it to try to render ASP.NET MVC's error page instead.
        filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
    }
}

Der Quellcode enthält Kommentare und ist mehr als selbsterklärend. Als erstes wird überprüft, ob Sie benutzerdefinierte Fehler in Ihrer web.config (dh <customErrors mode="On">) aktiviert haben . Wenn Sie es nicht haben, tut es nichts => YSOD. Wenn Sie benutzerdefinierte Fehler aktiviert haben, wird in der Fehleransicht ein Modell übergeben, das die Ausnahmestapelspur und andere nützliche Informationen enthält.

Darin Dimitrov
quelle
Ich bin noch ziemlich neu in ASP.NET MVC, aber ich dachte, dass jede Ansicht der Aktion eines Controllers entsprechen muss. Was ist der Controller und die Aktion hier und woher weiß es, dass es für die Ansicht zu Shared geht? Es sieht so aus, als ob dieser Mechanismus hier ist, um die Fehleransicht zu unterbrechen und auszutauschen.
LJM
3
Ja, jede Ansicht muss einer Controller-Aktion entsprechen. Die Controller-Aktion ist in diesem Fall diejenige, die ausgeführt wird und eine Ausnahme auslöst. Könnte eine beliebige Controller-Aktion sein. Diese Ausnahme wird vom globalen Aktionsfilter (in diesem Fall ein Ausnahmefilter) abgefangen und rendert die Fehleransicht. Da die Ausnahme innerhalb der Controller-Aktion ausgelöst wird, die diese Aktion niemals zurückgibt, wird die Ausführung in dieser Phase einfach gestoppt und die Ausführung an den Fehlerbehandler übergeben, der wiederum die Ansicht rendert.
Darin Dimitrov
12
Hat sich dies in MVC 5.1 geändert? Für mich sieht es so aus, als ob HandleErrorAttribute standardmäßig registriert ist (ohne dass wir es der Filterliste in RegisterGlobalFilters hinzufügen müssen) und wir keine benutzerdefinierten Fehler mehr aktivieren müssen.
Johnny Oshika
1
Hat sich die Antwort in MVC 5 geändert? Ich erhalte die Fehlerseite nicht. Ich sehe nur die YSOD. Ich habe den <customError mode = "On">. Was fehlt noch?
Dan