39 votes

Comment implémenter une gestion correcte des erreurs HTTP dans .NET MVC 2?

J'ai été mal toute la journée pour mettre en œuvre la gestion des erreurs dans mon ASP.NET MVC 2 app. J'ai regardé une variété de techniques, mais aucun ne fonctionne correctement. Je suis l'aide de MVC2 et .NET 4.0 (commencé le projet avant de MVC3 a été publié; nous allons la mise à niveau après nous livrons notre version initiale).

À ce point, je serai heureux de traiter correctement les 404 et 500 erreurs -- 403 (autorisation requise) serait également suivi par plusieurs autres réponses spécifiques. Maintenant, soit je reçois tous d'une erreur 404, tous les 500s, tous les 302s avant la 404, ou tous les 302s avant la 500.

Voici mes exigences (qui devrait être assez proche de la configuration de base du protocole HTTP):

  • Si une ressource n'est pas trouvée, jeter une 404, et de les afficher sur une page 404-la page spécifique de l'URL demandée. NE PAS retourner une réponse intermédiaire d'un code comme 302. L'idéal est de conserver l'URL demandée, plutôt que de montrer une nouvelle URL /Error/NotFound -- mais si celui-ci s'affiche, assurez-vous que nous n'avons pas de retour une réponse de redirection pour l'obtenir.

  • Si une erreur interne du serveur s'est produite, jeter un 500, et d'afficher un 500-erreur spécifique avec une indication de ce qui s'est passé. Encore une fois, ne pas retourner une réponse intermédiaire de code, et, idéalement, ne pas modifier l'URL.

Voici ce que j'avais envisager une 404:

  1. Statique fichier non trouvé: /Content/non-existent-dir/non-existent-file.txt
  2. Contrôleur non trouvé: /non-existent-controller/Foo/666
  3. Contrôleur, mais l'Action non trouvé: /Home/non-existent-action/666
  4. Contrôleur et l'action trouvés, mais l'action ne peut pas trouver l'objet demandé: /Home/Login/non-existent-id

Voici ce que je voudrais examiner un 500:

  1. Post une mauvaise valeur: POST /User/New/new-user-name-too-long-for-db-column-constraint
  2. Non-données liées au problème, comme une terminaison de Service Web ne répond pas

Certains de ces problèmes doivent être identifiés par des contrôleurs spécifiques ou des modèles, puis les contrôleurs devraient jeter les appropriée HttpException. Le reste devrait être traitée de manière plus générale.

Pour les 404 cas #2, j'ai essayé d'utiliser un ControllerFactory de jeter une erreur 404 si le contrôleur ne peut pas être trouvé. Pour les 404 cas #3, j'ai essayé d'utiliser un contrôleur de base pour remplacer HandleUnknownAction et de le jeter sur une page 404.

Dans les deux cas, j'ai un 302 avant de la 404. Et, je n'ai jamais eu de 500 erreurs; si je modifie le Web.config pour mettre une faute de frappe dans mon terminaison de Service Web, je reçois toujours un 302, puis une 404 dire l'URL (contrôleur/action) qui utilise le Service Web ne peut pas être trouvé. J'ai également obtenir l'URL demandée en tant que(n indésirables) querystring param: /Error/NotFound?aspxerrorpath=/Home/non-existent-action

Ces deux techniques sont venus de http://www.niksmit.com/wp/?p=17 (Comment faire pour obtenir normale 404 (Page non trouvée) les pages d'erreur à l'aide de ASP.Net MVC), a souligné que, à partir de http://richarddingwall.name/2008/08/17/strategies-for-resource-based-404-errors-in-aspnet-mvc/

Si dans le Web.config j'ai <customErrors mode="On" defaultRedirect="~/Error/Unknown" redirectMode="ResponseRedirect" />,- je obtenir le code de la réponse approprié, mais mon Erreur contrôleur n'est jamais appelé. En prenant de l' redirectMode attribut me met le MVC erreur de point de vue, mais avec un intervenant 302 et un changement de l'URL -- et toujours le même contrôleur (Unknown = 500; si je la changer en NotFound tout ressemble à un 404).

Voici quelques autres choses que j'ai lu et essayé de mettre en place:

.. avec un tas de StackOverflow postes.

Me semble que ce genre d'erreur de manipulation est assez basic pour applications Web, et le framework MVC devrait par défaut à partir de la boîte, et de laisser les gens étendre à travailler autrement. Peut-être qu'ils vont le faire dans une version future. En attendant, quelqu'un peut-il me donner des détails complets sur la façon de mettre en œuvre correcte des réponses HTTP?

49voto

Darin Dimitrov Points 528142

Voici une technique que vous pouvez utiliser. Définissez un ErrorsController qui servira les pages d'erreur:

 public class ErrorsController : Controller
{
    public ActionResult Http404()
    {
        Response.StatusCode = 404;
        return Content("404", "text/plain");
    }

    public ActionResult Http500()
    {
        Response.StatusCode = 500;
        return Content("500", "text/plain");
    }

    public ActionResult Http403()
    {
        Response.StatusCode = 403;
        return Content("403", "text/plain");
    }
}
 

puis, en Global.asax vous pouvez vous abonner à l'événement Application_Error où vous pouvez enregistrer l'exception et exécuter l'action correspondante de ErrorsController :

 protected void Application_Error(object sender, EventArgs e)
{
    var app = (MvcApplication)sender;
    var context = app.Context;
    var ex = app.Server.GetLastError();
    context.Response.Clear();
    context.ClearError();
    var httpException = ex as HttpException;

    var routeData = new RouteData();
    routeData.Values["controller"] = "errors";
    routeData.Values["exception"] = ex;
    routeData.Values["action"] = "http500";
    if (httpException != null)
    {
        switch (httpException.GetHttpCode())
        {
            case 404:
                routeData.Values["action"] = "http404";
                break;
            case 403:
                routeData.Values["action"] = "http403";
                break;
            case 500:
                routeData.Values["action"] = "http500";
                break;
        }
    }
    IController controller = new ErrorsController();
    controller.Execute(new RequestContext(new HttpContextWrapper(context), routeData));
}
 

Et maintenant, il ne reste plus qu'à lancer les exceptions appropriées:

 public class HomeController : Controller
{
    public ActionResult Index()
    {
        throw new HttpException(404, "NotFound");
    }
}
 

4voto

Hector Correa Points 10408

Pour les erreurs HTTP 404 (sans redirections), jetez un œil à mon article de blog sur le sujet. Cela pourrait vous donner de bonnes idées:

http://hectorcorrea.com/Blog/Returning-HTTP-404-in-ASP.NET-MVC

0voto

JK. Points 5517

Cela ne répond pas à votre question, mais il est important de noter que le statut HTTP 500 indique que quelque chose s'est mal passé sur le serveur. Votre exemple:

 POST /User/New/new-user-name-too-long-for-db-column-constraint
 

N’est pas un motif valable pour lancer un 500, c’est un problème de validation des données et doit être traité par des annotations de données MVC ou un cadre de validation jQuery, etc. Il est préférable d’afficher un message d'erreur à côté de la zone de texte, indiquant "Nom d'utilisateur trop long".

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