ASP.NET MVC HandleError

110

Wie gehe ich mit dem [HandleError]Filter in asp.net MVC Preview 5 vor?
Ich habe die customErrors in meiner Web.config-Datei festgelegt

<customErrors mode="On" defaultRedirect="Error.aspx">
  <error statusCode="403" redirect="NoAccess.htm"/>
  <error statusCode="404" redirect="FileNotFound.htm"/>
</customErrors>

und setze [HandleError] wie folgt über meine Controller-Klasse:

[HandleError]
public class DSWebsiteController: Controller
{
    [snip]
    public ActionResult CrashTest()
    {
        throw new Exception("Oh Noes!");
    }
}

Dann lasse ich meine Controller von dieser Klasse erben und rufe CrashTest () auf. Visual Studio hält bei dem Fehler an und nachdem ich f5 gedrückt habe, um fortzufahren, werde ich zu Error.aspx? Aspxerrorpath = / sxi.mvc / CrashTest umgeleitet (wobei sxi der Name des verwendeten Controllers ist. Natürlich kann der Pfad nicht gefunden werden und ich erhalte "Serverfehler in '/' Anwendung." 404.

Diese Site wurde von Vorschau 3 auf 5 portiert. Bis auf die Fehlerbehandlung läuft alles (es war nicht so viel Arbeit zu portieren). Wenn ich ein komplett neues Projekt erstelle, scheint die Fehlerbehandlung zu funktionieren.

Ideen?

--Hinweis--
Da diese Frage jetzt mehr als 3K-Ansichten hat, hielt ich es für vorteilhaft, das einzugeben , was ich derzeit (ASP.NET MVC 1.0) verwende. Im mvc contrib-Projekt gibt es ein brillantes Attribut namens "RescueAttribute". Sie sollten es wahrscheinlich auch ausprobieren;)

Boris Callens
quelle
Link zur RescueAttributeQuelle: mvccontrib.codeplex.com/SourceControl/changeset/view/…
Peter

Antworten:

158
[HandleError]

Wenn Sie Ihrer Klasse (oder Ihrer Aktionsmethode) nur das Attribut HandleError zur Verfügung stellen, sucht MVC bei Auftreten einer nicht behandelten Ausnahme zuerst im Ansichtsordner des Controllers nach einer entsprechenden Ansicht mit dem Namen "Fehler". Wenn es dort nicht gefunden werden kann, wird im Ordner "Shared View" gesucht (der standardmäßig eine Error.aspx-Datei enthalten sollte).

[HandleError(ExceptionType = typeof(SqlException), View = "DatabaseError")]
[HandleError(ExceptionType = typeof(NullReferenceException), View = "LameErrorHandling")]

Sie können auch zusätzliche Attribute mit spezifischen Informationen über die Art der gesuchten Ausnahme stapeln. Zu diesem Zeitpunkt können Sie den Fehler auf eine andere Ansicht als die Standardansicht "Fehler" lenken.

Weitere Informationen finden Sie in Scott Guthries Blogbeitrag .

Elijah Manor
quelle
1
Vielen Dank für die erweiterten Informationen. Ich weiß nicht, was ich falsch gemacht habe, aber ich habe ein neues Projekt erstellt, alle vorhandenen Ansichten, Controller und Modelle darin portiert und jetzt funktioniert es. Ich wusste jedoch nichts über die selektiven Ansichten.
Boris Callens
Wenn die Protokollierung dieser Ausnahmen gewünscht wird, ist dies ein akzeptabler Ort, um der Ansicht einen Codebehind hinzuzufügen?
Peter J
6
Iconic, hier ist meine Antwort "Besser spät als nie" auf Ihren Kommentar: Sie können stattdessen das HandleErrorAttribute unterordnen und seine "OnException" -Methode überschreiben: Fügen Sie dann die gewünschten Protokollierungs- oder benutzerdefinierten Aktionen ein. Sie können dann entweder die Ausnahme vollständig behandeln (Kontext.ExceptionHandled auf true setzen) oder dafür auf die OnException-Methode der Basisklasse zurückgreifen. Hier ist ein ausgezeichneter Artikel, der dabei helfen kann: blog.dantup.me.uk/2009/04/…
Funka
Ich habe viele Controller , so kann ich diese innen behandeln global.asaxwie diese eine Nachricht an Benutzer zeigen?
Shaijut
@Was ist mit der Verwendung derselben Fehlerseite wie PartialView und deren Darstellung im modalen Dialogfeld, nachdem eine Ausnahme aufgetreten ist? Könnten Sie bitte ein Beispiel in Ihrer Antwort angeben? Was ich erreichen möchte, wurde in der globalen Fehlerbehandlung mit PartialView in MVC erläutert .
Jack
23

Es sollte auch beachtet werden, dass Fehler, die den http-Fehlercode nicht auf 500 setzen

(zB UnauthorizedAccessException)

wird vom HandleError-Filter nicht behandelt.

Corin Blaikie
quelle
1
Stimmt, aber sehen Sie sich das RescueAttribute in MVC Contrib (Link in OP) an
Boris Callens
14

Lösung für http-Fehlercode bis 500 Dies ist ein Attribut namens [ERROR], das eine Aktion ausführt

public class Error: System.Web.Mvc.HandleErrorAttribute
{
    public override void OnException(System.Web.Mvc.ExceptionContext filterContext)
    {

            if (filterContext.HttpContext.IsCustomErrorEnabled)
            {
                filterContext.ExceptionHandled = true;

            }
            base.OnException(filterContext);
            //OVERRIDE THE 500 ERROR  
           filterContext.HttpContext.Response.StatusCode = 200;
    }

    private static void RaiseErrorSignal(Exception e)
    {
        var context = HttpContext.Current;
      // using.Elmah.ErrorSignal.FromContext(context).Raise(e, context);
    } 

}

//BEISPIEL:

[Error]
[HandleError]
[PopulateSiteMap(SiteMapName="Mifel1", ViewDataKey="Mifel1")]
public class ApplicationController : Controller
{
}
Raul
quelle
12

Attribute in MVC sind sehr nützlich bei der Fehlerbehandlung bei der get- und post- Methode und verfolgen auch den Ajax-Aufruf .

Erstellen Sie einen Basis-Controller in Ihrer Anwendung und erben Sie ihn in Ihrem Haupt-Controller (EmployeeController).

öffentliche Klasse EmployeeController: BaseController

Fügen Sie den folgenden Code im Basis-Controller hinzu.

/// <summary>
/// Base Controller
/// </summary>
public class BaseController : Controller
{       
    protected override void OnException(ExceptionContext filterContext)
    {
        Exception ex = filterContext.Exception;

        //Save error log in file
        if (ConfigurationManager.AppSettings["SaveErrorLog"].ToString().Trim().ToUpper() == "TRUE")
        {
            SaveErrorLog(ex, filterContext);
        }

        // if the request is AJAX return JSON else view.
        if (IsAjax(filterContext))
        {
            //Because its a exception raised after ajax invocation
            //Lets return Json
            filterContext.Result = new JsonResult()
            {
                Data = Convert.ToString(filterContext.Exception),
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };
        }
        else
        {
            filterContext.ExceptionHandled = true;
            filterContext.HttpContext.Response.Clear();

            filterContext.Result = new ViewResult()
            {
                //Error page to load
                ViewName = "Error",
                ViewData = new ViewDataDictionary()
            };

            base.OnException(filterContext);
        }
    }

    /// <summary>
    /// Determines whether the specified filter context is ajax.
    /// </summary>
    /// <param name="filterContext">The filter context.</param>
    private bool IsAjax(ExceptionContext filterContext)
    {
        return filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest";
    }

    /// <summary>
    /// Saves the error log.
    /// </summary>
    /// <param name="ex">The ex.</param>
    /// <param name="filterContext">The filter context.</param>
    void SaveErrorLog(Exception ex, ExceptionContext filterContext)
    {
        string logMessage = ex.ToString();

        string logDirectory = Server.MapPath(Url.Content("~/ErrorLog/"));

        DateTime currentDateTime = DateTime.Now;
        string currentDateTimeString = currentDateTime.ToString();
        CheckCreateLogDirectory(logDirectory);
        string logLine = BuildLogLine(currentDateTime, logMessage, filterContext);
        logDirectory = (logDirectory + "\\Log_" + LogFileName(DateTime.Now) + ".txt");

        StreamWriter streamWriter = null;
        try
        {
            streamWriter = new StreamWriter(logDirectory, true);
            streamWriter.WriteLine(logLine);
        }
        catch
        {
        }
        finally
        {
            if (streamWriter != null)
            {
                streamWriter.Close();
            }
        }
    }

    /// <summary>
    /// Checks the create log directory.
    /// </summary>
    /// <param name="logPath">The log path.</param>
    bool CheckCreateLogDirectory(string logPath)
    {
        bool loggingDirectoryExists = false;
        DirectoryInfo directoryInfo = new DirectoryInfo(logPath);
        if (directoryInfo.Exists)
        {
            loggingDirectoryExists = true;
        }
        else
        {
            try
            {
                Directory.CreateDirectory(logPath);
                loggingDirectoryExists = true;
            }
            catch
            {
            }
        }

        return loggingDirectoryExists;
    }

    /// <summary>
    /// Builds the log line.
    /// </summary>
    /// <param name="currentDateTime">The current date time.</param>
    /// <param name="logMessage">The log message.</param>
    /// <param name="filterContext">The filter context.</param>       
    string BuildLogLine(DateTime currentDateTime, string logMessage, ExceptionContext filterContext)
    {
        string controllerName = filterContext.RouteData.Values["Controller"].ToString();
        string actionName = filterContext.RouteData.Values["Action"].ToString();

        RouteValueDictionary paramList = ((System.Web.Routing.Route)(filterContext.RouteData.Route)).Defaults;
        if (paramList != null)
        {
            paramList.Remove("Controller");
            paramList.Remove("Action");
        }

        StringBuilder loglineStringBuilder = new StringBuilder();

        loglineStringBuilder.Append("Log Time : ");
        loglineStringBuilder.Append(LogFileEntryDateTime(currentDateTime));
        loglineStringBuilder.Append(System.Environment.NewLine);

        loglineStringBuilder.Append("Username : ");
        loglineStringBuilder.Append(Session["LogedInUserName"]);
        loglineStringBuilder.Append(System.Environment.NewLine);

        loglineStringBuilder.Append("ControllerName : ");
        loglineStringBuilder.Append(controllerName);
        loglineStringBuilder.Append(System.Environment.NewLine);

        loglineStringBuilder.Append("ActionName : ");
        loglineStringBuilder.Append(actionName);
        loglineStringBuilder.Append(System.Environment.NewLine);

        loglineStringBuilder.Append("----------------------------------------------------------------------------------------------------------");
        loglineStringBuilder.Append(System.Environment.NewLine);

        loglineStringBuilder.Append(logMessage);
        loglineStringBuilder.Append(System.Environment.NewLine);
        loglineStringBuilder.Append("==========================================================================================================");

        return loglineStringBuilder.ToString();
    }

    /// <summary>
    /// Logs the file entry date time.
    /// </summary>
    /// <param name="currentDateTime">The current date time.</param>
    string LogFileEntryDateTime(DateTime currentDateTime)
    {
        return currentDateTime.ToString("dd-MMM-yyyy HH:mm:ss");
    }

    /// <summary>
    /// Logs the name of the file.
    /// </summary>
    /// <param name="currentDateTime">The current date time.</param>
    string LogFileName(DateTime currentDateTime)
    {
        return currentDateTime.ToString("dd_MMM_yyyy");
    }

}

===============================================

Findet das Verzeichnis: Root / App_Start / FilterConfig.cs

Fügen Sie den folgenden Code hinzu:

/// <summary>
/// Filter Config
/// </summary>
public class FilterConfig
{
    /// <summary>
    /// Registers the global filters.
    /// </summary>
    /// <param name="filters">The filters.</param>
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    }
}

AJAX-Fehler verfolgen:

Rufen Sie die CheckAJAXError-Funktion beim Laden der Layoutseite auf.

function CheckAJAXError() {
    $(document).ajaxError(function (event, jqXHR, ajaxSettings, thrownError) {

        var ex;
        if (String(thrownError).toUpperCase() == "LOGIN") {
            var url = '@Url.Action("Login", "Login")';
            window.location = url;
        }
        else if (String(jqXHR.responseText).toUpperCase().indexOf("THE DELETE STATEMENT CONFLICTED WITH THE REFERENCE CONSTRAINT") >= 0) {

            toastr.error('ReferanceExistMessage');
        }
        else if (String(thrownError).toUpperCase() == "INTERNAL SERVER ERROR") {
            ex = ajaxSettings.url;
            //var url = '@Url.Action("ErrorLog", "Home")?exurl=' + ex;
            var url = '@Url.Action("ErrorLog", "Home")';
            window.location = url;
        }
    });
};
Sandip - Full Stack Entwickler
quelle
Sie geben Ausnahmedetails für AJAX-Anfragen preis, das möchten Sie nicht immer. Ihr Protokollierungscode ist nicht threadsicher. Sie gehen davon aus, dass es eine Fehleransicht gibt, und geben diese zurück, ohne den Antwortcode zu ändern. Dann suchen Sie in JavaScript nach bestimmten Fehlerzeichenfolgen (was ist mit der Lokalisierung?). Grundsätzlich wiederholen Sie, was eine vorhandene Antwort bereits sagt: "Überschreiben OnException, um Ausnahmen zu behandeln" , zeigen aber eine ziemlich schlechte Implementierung.
CodeCaster
Was ist der Parameter @ School.Resource.Messages.ReferanceExist?
Jack
@CodeCaster Kennen Sie eine bessere Möglichkeit, eine solche Fehlerbehandlungsmethode mit AJAX in ASP.NET MVC zu verwenden? Hilfe bitte?
Jack
Geben Sie 400 oder 500 zurück, wie HTTP vorgesehen ist. Suchen Sie nicht nach bestimmten Zeichenfolgen im Antworttext.
CodeCaster
@CodeCaster Könnten Sie sich bitte die globale Fehlerbehandlung mit PartialView in MVC in Bezug auf dieses Problem ansehen ?
Jack
4

Sie vermissen Error.aspx :) In Vorschau 5 befindet sich diese in Ihrem Ordner Views / Shared. Kopieren Sie es einfach aus einem neuen Preview 5-Projekt.

Ricky
quelle
Vielen Dank für die Antwort, aber ich habe die Seite Error.aspx bereits kopiert. Könnte tatsächlich etwas gewesen sein, das ich normalerweise vergessen würde, aber diesmal nicht. : P
Boris Callens
-1
    [HandleError]
    public class ErrorController : Controller
    {        
        [AcceptVerbs(HttpVerbs.Get)]
        public ViewResult NotAuthorized()
        {
            //401
            Response.StatusCode = (int)HttpStatusCode.Unauthorized;

        return View();
    }

    [AcceptVerbs(HttpVerbs.Get)]
    public ViewResult Forbidden()
    {
        //403
        Response.StatusCode = (int)HttpStatusCode.Forbidden;

        return View();
    }

    [AcceptVerbs(HttpVerbs.Get)]
    public ViewResult NotFound()
    {
        //404
        Response.StatusCode = (int)HttpStatusCode.NotFound;
        return View();
    }

    public ViewResult ServerError()
    {
        //500
        Response.StatusCode = (int)HttpStatusCode.NotFound;
        return View();
    }

}}

Jack
quelle