Gestion des exceptions dans le contrôleur (ASP.NET MVC)

Lorsqu’une exception est générée par votre propre code appelé à partir d’une action dans un contrôleur, comment doit-elle être gérée? Je vois beaucoup d’exemples de meilleures pratiques pour lesquelles il n’y a pas de déclarations try-catch. Par exemple, accéder à des données depuis un référentiel:

public ViewResult Index() { IList customModels = _customModelRepository.GetAll(); return View(customModels); } 

Il est clair que ce code peut générer une exception si l’appel est adressé à une firebase database à laquelle elle ne peut accéder et si nous utilisons un ORM comme Entity Framework, par exemple.

Cependant, tout ce que je peux voir, c’est que l’exception bouillonne et affiche un message d’erreur désagréable à l’intention de l’utilisateur.

Je connais l’atsortingbut HandleError mais je comprends qu’il est principalement utilisé pour vous redirect vers une page d’erreur si une exception non gérée se produit.

Bien sûr, ce code pourrait être encapsulé dans un try-catch mais ne se sépare pas bien, surtout si vous avez plus de logique:

 public ViewResult Index() { if (ValidationCheck()) { IList customModels = new List(); try { customModels = _customModelRepository.GetAll(); } catch (SqlException ex) { // Handle exception } if (CustomModelsAreValid(customModels)) // Do something else // Do something else } return View(); } 

Auparavant, j’avais extrait tout le code susceptible de générer des exceptions, telles que les appels de firebase database, dans une classe DataProvider qui traite les erreurs et renvoie les messages permettant d’afficher des messages à l’utilisateur.

Je me demandais quelle était la meilleure façon de gérer cela? Je ne veux pas toujours revenir à une page d’erreur car certaines exceptions ne devraient pas le faire. Au lieu de cela, un message d’erreur à l’utilisateur devrait être affiché avec une vue normale. Ma méthode précédente était-elle correcte ou existe-t-il une meilleure solution?

Je fais trois choses pour afficher des messages plus conviviaux:

  1. Tirez parti du gestionnaire d’exception global. Dans le cas de MVC: Application_Error dans Global.asax. Découvrez comment l’utiliser ici: http://msdn.microsoft.com/en-us/library/24395wz3(v=vs.100).aspx
  2. Je sous-classe Exception dans une UserFriendlyException. Je fais de mon mieux, dans toutes mes classes de service sous-jacentes, pour lancer cette exception UserFriendlyException au lieu d’une ancienne exception. J’essaie toujours de mettre des messages utiles pour l’utilisateur dans ces exceptions personnalisées. L’objective principal est de pouvoir effectuer une vérification de type sur l’exception dans la méthode Application_Error. Pour les exceptions UserFriendlyExceptions, j’utilise simplement le message convivial que j’ai défini au plus profond de mes services, comme “Hé! 91 degrés n’est pas une valeur de latitude valide!”. Si c’est une exception normale, alors c’est un cas que je n’ai pas traité, alors j’affiche un message d’erreur plus générique, du type “Oups, quelque chose s’est mal passé! Nous ferons de notre mieux pour le résoudre!”.
  3. Je crée également un ErrorController responsable du rendu de vues conviviales ou JSON. C’est le contrôleur dont les méthodes seront appelées à partir de la méthode Application_Error.

EDIT: Je pensais mentionner l’API Web ASP.NET car elle est étroitement liée. Étant donné que le consommateur de points de terminaison API Web ne sera pas nécessairement un navigateur, j’aime traiter les erreurs un peu différemment. J’utilise toujours “FriendlyException” (n ° 2 ci-dessus), mais au lieu de redirect vers un ErrorController, je laisse simplement tous mes points de terminaison renvoyer un type de type de base contenant une propriété Error. Ainsi, si une exception remonte jusqu’aux contrôleurs de l’API Web, je m’assure de coller cette erreur dans la propriété Error de la réponse de l’API. Ce message d’erreur sera soit le message convivial des classes sur lesquelles le contrôleur d’API s’appuie, soit un message générique si le type d’exception n’est pas une exception FriendlyException. Ainsi, le client consommateur peut simplement vérifier si la propriété Error de la réponse de l’API est vide ou non. Afficher un message si l’erreur est présente, procéder comme d’habitude sinon. La bonne chose est que, en raison du concept de message convivial, le message peut être beaucoup plus significatif pour l’utilisateur qu’un message d’erreur générique “Erreur!” message. J’utilise cette stratégie lorsque j’écris des applications mobiles avec Xamarin, où je peux partager mes types C # entre mes services Web et mon application iOS / Android.

Avec Asp.Net MVC, vous pouvez également remplacer la méthode OnException pour votre contrôleur.

 protected override void OnException(ExceptionContext filterContext) { if (filterContext.ExceptionHandled) { return; } filterContext.Result = new ViewResult { ViewName = ... }; filterContext.ExceptionHandled = true; } 

Cela vous permet de redirect vers une page d’erreur personnalisée avec un message faisant référence à l’exception si vous le souhaitez.

J’ai utilisé une substitution OnException car plusieurs projets font référence à un projet avec un contrôleur qui gère les erreurs:

Sécurité / HandleErrorsController.cs

 protected override void OnException(ExceptionContext filterContext) { MyLogger.Error(filterContext.Exception); //method for log in EventViewer if (filterContext.ExceptionHandled) return; filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError; filterContext.Result = new JsonResult { Data = new { Success = false, Error = "Please report to admin.", ErrorText = filterContext.Exception.Message, Stack = filterContext.Exception.StackTrace }, JsonRequestBehavior = JsonRequestBehavior.AllowGet }; filterContext.ExceptionHandled = true; } 

Toutes les questions de ce type ne sont pas très constructives, car la réponse est toujours “cela dépend”, car il existe de nombreuses manières de traiter le traitement des erreurs.

Beaucoup de gens aiment utiliser la méthode HandleError, car toute exception est fondamentalement non récupérable. Je veux dire, qu’allez-vous faire si vous ne pouvez pas retourner les objects? Vous allez leur montrer une erreur de toute façon, non?

La question est de savoir comment vous voulez leur montrer l’erreur. Si leur montrer une page d’erreur est acceptable, HandleError fonctionne correctement et fournit un emplacement facile pour consigner l’erreur. Si vous utilisez Ajax ou voulez quelque chose de plus sophistiqué, vous devez développer un moyen de le faire.

Vous parlez d’une classe DataProvider. C’est fondamentalement ce que votre référentiel est. Pourquoi ne pas intégrer cela dans votre référentiel?