web-dev-qa-db-fra.com

Pages d'erreur personnalisées sur asp.net MVC3

Je développe un site Web de base MVC3 et je recherche une solution pour la gestion des erreurs et un rendu personnalisé des vues pour chaque type d'erreur. Imaginez donc que j’ai un contrôleur "Erreur" dont l’action principale est "Index" (page d’erreur générique) et que ce contrôleur aura plusieurs actions supplémentaires pour les erreurs pouvant apparaître à l’utilisateur, telles que "Handle500" ou "HandleActionNotFound".

Ainsi, chaque erreur pouvant survenir sur le site Web peut être gérée par ce contrôleur "Erreur" (exemples: "Contrôleur" ou "Action" non trouvé, 500, 404, dbException, etc.).

J'utilise le fichier Sitemap pour définir les chemins d'accès aux sites Web (et non les itinéraires).

Cette question a déjà été répondue, ceci est une réponse à Gweebz

Ma dernière méthode applicaiton_error est la suivante:

protected void Application_Error() {
//while my project is running in debug mode
if (HttpContext.Current.IsDebuggingEnabled && WebConfigurationManager.AppSettings["EnableCustomErrorPage"].Equals("false"))
{
    Log.Logger.Error("unhandled exception: ", Server.GetLastError());
}
else
{
    try
    {
        var exception = Server.GetLastError();

        Log.Logger.Error("unhandled exception: ", exception);

        Response.Clear();
        Server.ClearError();
        var routeData = new RouteData();
        routeData.Values["controller"] = "Errors";
        routeData.Values["action"] = "General";
        routeData.Values["exception"] = exception;

        IController errorsController = new ErrorsController();
        var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
        errorsController.Execute(rc);
    }
    catch (Exception e)
    {
        //if Error controller failed for same reason, we will display static HTML error page
        Log.Logger.Fatal("failed to display error page, fallback to HTML error: ", e);
        Response.TransmitFile("~/error.html");
    }
}
}
144
John Louros

Voici un exemple de la façon dont je gère les erreurs personnalisées. Je définis un ErrorsController avec des actions traitant différentes erreurs HTTP:

public class ErrorsController : Controller
{
    public ActionResult General(Exception exception)
    {
        return Content("General failure", "text/plain");
    }

    public ActionResult Http404()
    {
        return Content("Not found", "text/plain");
    }

    public ActionResult Http403()
    {
        return Content("Forbidden", "text/plain");
    }
}

et puis je m'inscris pour le Application_Error dans Global.asax et appelez ce contrôleur:

protected void Application_Error()
{
    var exception = Server.GetLastError();
    var httpException = exception as HttpException;
    Response.Clear();
    Server.ClearError();
    var routeData = new RouteData();
    routeData.Values["controller"] = "Errors";
    routeData.Values["action"] = "General";
    routeData.Values["exception"] = exception;
    Response.StatusCode = 500;
    if (httpException != null)
    {
        Response.StatusCode = httpException.GetHttpCode();
        switch (Response.StatusCode)
        {
            case 403:
                routeData.Values["action"] = "Http403";
                break;
            case 404:
                routeData.Values["action"] = "Http404";
                break;
        }
    }

    IController errorsController = new ErrorsController();
    var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
    errorsController.Execute(rc);
}
201
Darin Dimitrov

Voici d'autres articles Comment créer des pages d'erreur personnalisées avec MVC http://kitsula.com/Article/MVC-Custom-Error-Pages .

18
Shaman

Vous pouvez également le faire dans le fichier Web.Config. Voici un exemple qui fonctionne dans IIS 7.5.

     <system.webServer>
          <httpErrors errorMode="DetailedLocalOnly" defaultResponseMode="File">
                <remove statusCode="502" subStatusCode="-1" />
                <remove statusCode="501" subStatusCode="-1" />
                <remove statusCode="412" subStatusCode="-1" />
                <remove statusCode="406" subStatusCode="-1" />
                <remove statusCode="405" subStatusCode="-1" />
                <remove statusCode="404" subStatusCode="-1" />
                <remove statusCode="403" subStatusCode="-1" />
                <remove statusCode="401" subStatusCode="-1" />
                <remove statusCode="500" subStatusCode="-1" />
                <error statusCode="500" path="/notfound.html" responseMode="ExecuteURL" />
                <error statusCode="401" prefixLanguageFilePath="" path="/500.html" responseMode="ExecuteURL" />
                <error statusCode="403" prefixLanguageFilePath="" path="/403.html" responseMode="ExecuteURL" />
                <error statusCode="404" prefixLanguageFilePath="" path="/404.html" responseMode="ExecuteURL" />
                <error statusCode="405" prefixLanguageFilePath="" path="/405.html" responseMode="ExecuteURL" />
                <error statusCode="406" prefixLanguageFilePath="" path="/406.html" responseMode="ExecuteURL" />
                <error statusCode="412" prefixLanguageFilePath="" path="/412.html" responseMode="ExecuteURL" />
                <error statusCode="501" prefixLanguageFilePath="" path="/501.html" responseMode="ExecuteURL" />
                <error statusCode="502" prefixLanguageFilePath="" path="/genericerror.html" responseMode="ExecuteURL" />
           </httpErrors>
</system.webServer>
6
Brett Allred

Je vois que vous avez ajouté une valeur de configuration pour EnableCustomErrorPage et que vous vérifiez également IsDebuggingEnabled pour déterminer si vous souhaitez ou non exécuter le traitement des erreurs.

Puisqu'il y a déjà un <customErrors/> configuration dans ASP.NET (ce qui est exactement prévu à cet effet), il est plus simple de simplement dire:

    protected void Application_Error()
    {
        if (HttpContext.Current == null) 
        {
                // errors in Application_Start will end up here                
        }
        else if (HttpContext.Current.IsCustomErrorEnabled)
        {
                // custom exception handling
        }
    }

Ensuite, dans la configuration, vous mettriez <customErrors mode="RemoteOnly" /> qui peut être déployé en toute sécurité, et lorsque vous devez tester votre page d’erreurs personnalisée, définissez-la sur <customErrors mode="On" /> afin que vous puissiez vérifier que cela fonctionne.

Notez que vous devez également vérifier si HttpContext.Current est null car une exception dans Application_Start continuera à utiliser cette méthode bien qu’il n’y ait pas de contexte actif.

3
Simon_Weaver

Vous pouvez afficher une page d'erreur conviviale avec le code de statut http correct en implémentant le module User Friendly Exception Handling de Jeff Atwood avec une légère modification du statut http. code. Cela fonctionne sans aucune redirection. Bien que le code date de 2004 (!), Cela fonctionne bien avec MVC. Il peut être entièrement configuré dans votre web.config, sans aucune modification du code source du projet MVC.

La modification requise pour renvoyer le statut HTTP d'origine plutôt qu'un 200 Le statut est décrit dans cet article de forum lié .

En gros, dans Handler.vb, vous pouvez ajouter quelque chose comme:

' In the header...
Private _exHttpEx As HttpException = Nothing

' At the top of Public Sub HandleException(ByVal ex As Exception)...
HttpContext.Current.Response.StatusCode = 500
If TypeOf ex Is HttpException Then
    _exHttpEx = CType(ex, HttpException)
    HttpContext.Current.Response.StatusCode = _exHttpEx.GetHttpCode()
End If
2
Martin_ATS

J'utilise MVC 4.5 et j'avais des problèmes avec la solution de Darin. Remarque: la solution de Darin est excellente et je l’ai utilisée pour trouver ma solution. Voici ma solution modifiée:

protected void Application_Error(object sender, EventArgs e)
{           
var exception = Server.GetLastError();
var httpException = exception as HttpException;
Response.StatusCode = httpException.GetHttpCode();

Response.Clear();
Server.ClearError();


if (httpException != null)
{
    var httpContext = HttpContext.Current;

    httpContext.RewritePath("/Errors/InternalError", false);

    // MVC 3 running on IIS 7+
    if (HttpRuntime.UsingIntegratedPipeline)
    {
        switch (Response.StatusCode)
        {
            case 403:
                httpContext.Server.TransferRequest("/Errors/Http403", true);
                break;
            case 404:
                httpContext.Server.TransferRequest("/Errors/Http404", true);
                break;
            default:
                httpContext.Server.TransferRequest("/Errors/InternalError", true);
                break;
        }
    }
    else
    {
        switch (Response.StatusCode)
        {
            case 403:
                httpContext.RewritePath(string.Format("/Errors/Http403", true));
                break;
            case 404:
                httpContext.RewritePath(string.Format("/Errors/Http404", true));
                break;
            default:
                httpContext.RewritePath(string.Format("/Errors/InternalError", true));
                break;
        }

        IHttpHandler httpHandler = new MvcHttpHandler();
        httpHandler.ProcessRequest(httpContext);
    }
}
}
0
MVCdragon