ASP.NET MVC HandleError


110

Come si esegue il [HandleError]filtro in asp.net MVC Preview 5?
Ho impostato customErrors nel mio file Web.config

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

e metti [HandleError] sopra la mia classe Controller in questo modo:

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

Quindi ho lasciato che i miei controller ereditassero da questa classe e li chiamassero CrashTest (). Visual Studio si ferma all'errore e dopo aver premuto f5 per continuare, vengo reindirizzato a Error.aspx? Aspxerrorpath = / sxi.mvc / CrashTest (dove sxi è il nome del controller utilizzato. Ovviamente il percorso non può essere trovato e ottengo "Errore del server nell'applicazione" / "." 404.

Questo sito è stato portato dall'anteprima 3 alla 5. Tutto viene eseguito (non è stato molto lavoro da portare) tranne la gestione degli errori. Quando creo un nuovo progetto completo, la gestione degli errori sembra funzionare.

Idee?

- Nota--
Poiché questa domanda ha oltre 3K visualizzazioni ora, ho pensato che sarebbe stato utile inserire ciò che sto attualmente utilizzando (ASP.NET MVC 1.0). Nel progetto mvc contrib c'è un brillante attributo chiamato "RescueAttribute" Probabilmente dovresti controllarlo anche tu;)


Risposte:


158
[HandleError]

Quando fornisci solo l'attributo HandleError alla tua classe (o al tuo metodo di azione per quella materia), quando si verifica un'eccezione non gestita, MVC cercherà prima una vista corrispondente denominata "Errore" nella cartella Visualizza del controller. Se non riesce a trovarlo lì, procederà a cercare nella cartella Visualizzazione condivisa (che dovrebbe contenere un file Error.aspx per impostazione predefinita)

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

Puoi anche accumulare attributi aggiuntivi con informazioni specifiche sul tipo di eccezione che stai cercando. A quel punto, puoi indirizzare l'errore a una visualizzazione specifica diversa dalla visualizzazione predefinita "Errore".

Per ulteriori informazioni, dai un'occhiata al post sul blog di Scott Guthrie a riguardo.


1
Grazie per le informazioni estese. Non so cosa ho sbagliato, ma ho creato un nuovo progetto, ho portato tutte le viste, i controller e i modelli esistenti e ora funziona. Tuttavia, non conoscevo le visualizzazioni selettive.
Boris Callens

Se si desidera la registrazione di queste eccezioni, questo sarebbe un posto accettabile per aggiungere un codebehind alla vista?
Peter J

6
Iconico, ecco la mia risposta "meglio tardi che mai" al tuo commento: puoi invece sottoclassare HandleErrorAttribute e sovrascrivere il suo metodo "OnException": Quindi, inserisci qualsiasi registrazione o azione personalizzata che desideri. È quindi possibile gestire completamente l'eccezione (impostando context.ExceptionHandled su true) o rimandare al metodo OnException della classe base per questo. Ecco un ottimo articolo che può aiutare con questo: blog.dantup.me.uk/2009/04/…
Funka

Ho sacco di controllori in modo posso gestire questo dentro global.asaxcome questo per mostrare un messaggio per gli utenti?
shaijut

@ Che ne dici di usare la stessa pagina di errore di PartialView e renderla nella finestra di dialogo modale dopo che si verifica un'eccezione? Potresti fornire un esempio nella tua risposta? Quello che voglio ottenere è stato spiegato sulla gestione degli errori globali utilizzando PartialView in MVC .
Jack

23

Va anche notato che gli errori che non impostano il codice di errore http su 500

(ad es. UnauthorizedAccessException)

non sarà gestito dal filtro HandleError.


1
Vero, ma controlla RescueAttribute in MVC contrib (link in OP)
Boris Callens

14

Soluzione per il codice di errore http su 500, questo è un attributo chiamato [ERROR] inseriscilo in un'azione

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

}

//ESEMPIO:

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

12

Gli attributi in MVC sono molto utili nella gestione degli errori nel metodo get e post , inoltre tengono traccia delle chiamate ajax .

Crea un controller di base nella tua applicazione ed ereditalo nel controller principale (EmployeeController).

classe pubblica EmployeeController: BaseController

Aggiungi sotto il codice nel controller di base.

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

}

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

Trova la directory: Root / App_Start / FilterConfig.cs

Aggiungi sotto il codice:

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

Traccia errore AJAX:

Chiama la funzione CheckAJAXError nel caricamento della pagina di layout.

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

Stai perdendo dettagli sulle eccezioni sulle richieste AJAX, non lo vuoi sempre. Il tuo codice di registrazione non è thread-safe. Stai presumendo che ci sia una visualizzazione Error e restituendola, senza alterare il codice di risposta. Quindi vai a controllare alcune stringhe di errore in JavaScript (che dire della localizzazione?). Fondamentalmente stai ripetendo ciò che una risposta esistente dice già: "Sostituisci OnExceptionper gestire le eccezioni" , ma mostrando un'implementazione piuttosto negativa.
CodeCaster

Cos'è il parametro @ School.Resource.Messages.ReferanceExist?
Jack

@CodeCaster Conosci un modo migliore per utilizzare questo tipo di metodo di gestione degli errori con AJAX in ASP.NET MVC? Qualche aiuto per favore?
Jack

Restituisce 400 o 500, come previsto da HTTP. Non cercare stringhe specifiche nel corpo della risposta.
CodeCaster

@CodeCaster Potresti dare un'occhiata alla gestione degli errori globali utilizzando PartialView in MVC riguardo a questo problema?
Jack

4

Ti manca Error.aspx :) Nell'anteprima 5, si trova nella cartella Views / Shared. Basta copiarlo da un nuovo progetto Preview 5.


Grazie per la risposta, ma ho già copiato la pagina Error.aspx. Potrebbe davvero essere qualcosa che normalmente dimenticherei, ma non questa volta. : 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();
    }

}

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.