Les actions results n’existent pas juste pour faire beau. En fait c’est une fonctionnalité puissante si elle est utilisée correctement. Dans les contrôleurs ASP.NET MVC je vois souvent ce type de code, qui de plus se répète à plusieurs endroits :

   1:  public virtual ActionResult Index() 
   2:  { 
   3:        if (!HttpContext.User.Identity.IsAuthenticated) 
   4:        { 
   5:              FormsAuthentication.RedirectToLoginPage();
   6:              return new EmptyResult(); 
   7:        }
   8:   
   9:        return View(); 
  10:  }

Personnellement j’ai quelques problèmes avec ça:

  1. Le code similaire est présent à plusieurs endroits. Ce n’est certainement pas le respect du principe DRY.
  2. L’utilisation de HttpContext. Bien que c’est une propriété du contrôleur du type System.Web.HttpContextBase qui est parfaitement mockable, il vaut mieux limiter son utilisation pour que les tests des contrôleurs soient plus faciles à réaliser.
  3. L’utilisation directe de FormsAuthentication qui n’est pas mockable donc pas de tests unitaires pour les actions qui l’utilisent.

Ce que j’aimerais, c’est, d’une, pouvoir tester mon action du contrôleur, et d’autre ne pas dupliquer ce code où j’en ai besoin. J’aimerais faire quelque chose comme cela :

   1: public virtual ActionResult Index()        
   2: {            
   3:     var view = View();            
   4:     return new LoginActionResult(view);        
   5: }
Ce possible en créant notre propre action result. Ce que j’aimerais c’est que si l’utilisateur n’est pas identifié alors je redirige vers la page de login, sinon je retourne la vue demandée. Regardons le code ci dessous :
   1: public class LoginActionResult : ViewResult    
   2: {       
   3:     public ViewResult ViewAfterSuccessfulLogin { get; private set; }         
   4:     
   5:     public LoginActionResult(ViewResult viewAfterSuccessfulLogin)        
   6:     {            
   7:         if (viewAfterSuccessfulLogin == null)                
   8:             throw new ArgumentNullException("viewAfterSuccessfulLogin", "Can't be null");                        
   9:         
  10:         ViewAfterSuccessfulLogin = viewAfterSuccessfulLogin;
  11:     }         
  12:  
  13:     public override void ExecuteResult(ControllerContext context)
  14:     {            
  15:         if (!context.HttpContext.User.Identity.IsAuthenticated)
  16:         {                
  17:             FormsAuthentication.RedirectToLoginPage();            
  18:         }             
  19:  
  20:         ViewAfterSuccessfulLogin.ExecuteResult(context);        
  21:     }    
  22: }

Rien de transcendent. Une petite clarification :

  1. Ligne 1 : On dérive notre classe de ViewResult, car ce qu’on veut exécuter c’est le traitement de la vue si l’utilisateur est identifié.
  2. Ligne 5 : On passe en constructeur la vue qu’on aimerais afficher si l’utilisateur est identifié. Je stocke sa valeur dans la propriété ViewAfterSucessfulLogin pour réutiliser plus tard.
  3. Ligne 13 : On override la méthode ExecuteResult ce qui permet à notre classe de traiter le résultat d’une action. Dans notre cas c’est l’affichage d’une vue.
  4. Lignes 15 : Vérification si l’utilisateur courant est identifié. Si oui, la vue passée en constructeur est traitée (ligne 20). Sinon, on est redirigé vers la page de login (ligne 17).

Voilà. Une petite amélioration de rien du tout mais qui clarifie le code des actions. De plus les tests unitaires sont plus faciles à réaliser. On peut tester que LoginActionResult est retourné ou de tester RedirectToRouteResult pour s’assurer que la redirection est correctement réalisée.

D’autres posts vont suivre sur l’ASP.NET MVC 3. Résolution 2011, se remettre à écrire plus de posts. On va voir combien de temps je vais la tenir Clignement d'œil

A+