64 votes

Gestion des erreurs dans ASP.NET MVC

Comment puis-je gérer correctement les exceptions levées de contrôleurs ASP.NET MVC? L' HandleError attribut semble de ne traiter les exceptions levées par le MVC de l'infrastructure et de ne pas les exceptions levées par mon propre code.

L'utilisation de ce site.config

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

avec le code suivant

namespace MvcApplication1.Controllers
{
    [HandleError]
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            // Force a 401 exception for testing
            throw new HttpException(401, "Unauthorized");
        }
    }
}

n'entraîne pas de ce que j'espérais. Au lieu de cela je obtenir le générique ASP.NET page d'erreur me disant de me modifier mon site web.config pour voir les informations d'erreur. Cependant, si au lieu de lancer une exception-je retourner une défaillance de Vue, j'ai l' /Shared/Vues/Erreurs.page aspx:

return View("DoesNotExist");

De lever des exceptions au sein d'un contrôleur comme je l'ai fait ci-dessus semble ignorer tous les de la HandleError fonctionnalités, alors quelle est la bonne façon de créer des pages d'erreur et comment puis-je jouer à nice avec le MVC de l'infrastructure?

63voto

Will Points 76760

Controller.OnException(ExceptionContext context) . Le remplacer.

 protected override void OnException(ExceptionContext filterContext)
{
    // Bail if we can't do anything; app will crash.
    if (filterContext == null)
        return;
        // since we're handling this, log to elmah

    var ex = filterContext.Exception ?? new Exception("No further information exists.");
    LogException(ex);

    filterContext.ExceptionHandled = true;
    var data = new ErrorPresentation
        {
            ErrorMessage = HttpUtility.HtmlEncode(ex.Message),
            TheException = ex,
            ShowMessage = !(filterContext.Exception == null),
            ShowLink = false
        };
    filterContext.Result = View("ErrorPage", data);
}
 

21voto

Adrian Anttila Points 915

Grâce à kazimanzurrashaid, voici ce que j'ai fini par faire dans Global.asax.cs:

 protected void Application_Error()
{
    Exception unhandledException = Server.GetLastError();
    HttpException httpException = unhandledException as HttpException;
    if (httpException == null)
    {
        Exception innerException = unhandledException.InnerException;
        httpException = innerException as HttpException;
    }

    if (httpException != null)
    {
        int httpCode = httpException.GetHttpCode();
        switch (httpCode)
        {
            case (int) HttpStatusCode.Unauthorized:
                Response.Redirect("/Http/Error401");
                break;
        }
    }
}
 

Je serai en mesure d'ajouter plus de pages au HttpContoller en fonction des codes d'erreur HTTP supplémentaires que je dois prendre en charge.

13voto

Craig Stuntz Points 95965

Le HandleError attribut semble de ne traiter les exceptions levées par le MVC de l'infrastructure et de ne pas les exceptions levées par mon propre code.

C'est tout simplement faux. En effet, HandleError ne "processus" exceptions soit jeté dans votre propre code ou code appelé par votre propre code. En d'autres termes, les seules exceptions où votre action est dans la pile d'appel.

La véritable explication pour le comportement que vous voyez est l'exception que vous lancez. HandleError se comporte différemment avec un HttpException. À partir du code source:

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

6voto

kazimanzurrashid Points 1400

Je ne pense pas que vous pourrez afficher une page d'erreur spécifique en fonction du HttpCode avec l'attribut HandleError et je préférerais utiliser un HttpModule à cette fin. En supposant que le dossier "ErrorPages" contient une page différente pour chaque erreur spécifique et que le mappage soit spécifié dans le fichier web.config, de la même manière que l'application de formulaire Web standard. Et voici le code utilisé pour afficher la page d'erreur:

 public class ErrorHandler : BaseHttpModule{

public override void OnError(HttpContextBase context)
{
    Exception e = context.Server.GetLastError().GetBaseException();
    HttpException httpException = e as HttpException;
    int statusCode = (int) HttpStatusCode.InternalServerError;

    // Skip Page Not Found and Service not unavailable from logging
    if (httpException != null)
    {
        statusCode = httpException.GetHttpCode();

        if ((statusCode != (int) HttpStatusCode.NotFound) && (statusCode != (int) HttpStatusCode.ServiceUnavailable))
        {
            Log.Exception(e);
        }
    }

    string redirectUrl = null;

    if (context.IsCustomErrorEnabled)
    {
        CustomErrorsSection section = IoC.Resolve<IConfigurationManager>().GetSection<CustomErrorsSection>("system.web/customErrors");

        if (section != null)
        {
            redirectUrl = section.DefaultRedirect;

            if (httpException != null)
            {
                if (section.Errors.Count > 0)
                {
                    CustomError item = section.Errors[statusCode.ToString(Constants.CurrentCulture)];

                    if (item != null)
                    {
                        redirectUrl = item.Redirect;
                    }
                }
            }
        }
    }

    context.Response.Clear();
    context.Response.StatusCode = statusCode;
    context.Response.TrySkipIisCustomErrors = true;

    context.ClearError();

    if (!string.IsNullOrEmpty(redirectUrl))
    {
        context.Server.Transfer(redirectUrl);
    }
}
 

}

3voto

Simon_Weaver Points 31141

Une autre possibilité (pas vrai dans votre cas) que la lecture, cela peut être l'expérience, c'est que votre page d'erreur est de lancer une erreur elle-même, ou n'est pas mise en œuvre :

 System.Web.Mvc.ViewPage<System.Web.Mvc.HandleErrorInfo>

Si c'est le cas, alors vous obtiendrez la page d'erreur par défaut (sinon vous obtiendrez une boucle infinie car elle permettrait de continuer à essayer de s'envoyer lui-même à votre page d'erreur personnalisée). Ce n'était pas immédiatement évident pour moi.

Ce modèle est le modèle envoyé vers la page d'erreur. Si votre page d'erreur utilise le même gabarit comme le reste de votre site et exige que toute autre information de modèle, alors vous aurez besoin pour créer votre propre [HandleError] type de l'attribut ou de la remplacer OnException ou quelque chose.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X