Asp.net MVC : SubControllers
Julien on nov 18th 2008
Grâce à MVC Contrib, un librairie open source couvrant certains aspects absents d'Asp.net MVC, il est possible d'utiliser des "SubControllers" afin de réutiliser des unités logiques au sein de plusieurs actions en minimisant la duplication de code. Matt Hinze, à l'origine du projet en explique le fonctionnement ici.
Pour récupérer les instances des sous contrôleurs, Matt utilise l'injection de paramètre au niveau des actions. Cette méthode à le mérite d'être simple et efficace mais je trouve qu'elle nuit aussi à la lisibilité du code, dans la mesure ou ce paramètre n'est pas réutilisé dans le corps de l'action. J'ai donc légèrement modifié la syntaxe en introduisant un attribut :
public ActionResult Index() { return View(); }
L'attribut prends 2 paramètres, le type du sous contrôleur à instancier et une chaine de caractère qui définit la clef du dictionnaire ViewData dans lequel on stockera l'instance à invoquer. J'utilise ici une constance, SubControllerKeys.ProductSearch mais on pourrait tout à fait la remplacer par "ProductSearch". L'invocation coté vue ressemblera alors à cela :
<% Html.ViewData.Get("ProductSearch").Invoke(); %>
Voici le code pour cet attribut :
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] public class SubControllerAttribute : ActionFilterAttribute { private Type _subControllerType; private string _viewDataKey; public Type SubControllerType { get { return _subControllerType; } set { Guard.AgainstNull(value, "value can't be null"); Require.That(typeof(ISubController).IsAssignableFrom(value), String.Format("The type '{0}' does not inherit from ISubController.", value.FullName)); _subControllerType = value; } } public string ViewDataKey { get { return _viewDataKey; } set { _viewDataKey = value; } } public SubControllerAttribute(Type subControllerType, string viewDataKey) { _subControllerType = subControllerType; _viewDataKey = viewDataKey; } public override void OnActionExecuting(ActionExecutingContext filterContext) { Guard.AgainstNullOrEmpty(_viewDataKey, "View data key is not set"); Guard.AgainstNull(_subControllerType, "Sub controller type is not set"); ISubController subController = (ISubController)ObjectFactory.GetInstance(_subControllerType); if (subController == null) { } filterContext.Controller.ViewData.Add(_viewDataKey, subController.GetResult(filterContext.Controller)); base.OnActionExecuting(filterContext); } }
Deux remarques (qui expliquent pourquoi je n'ai pas soumis de patch pour MVC Contrib) :
- J'utilise structure map pour construire mon instance du sous contrôleur (ligne 39). Idéalement il faudrait utilise une interface pour pouvoir plugger tout les outils d'injection de dépendances)
- J'utilise une mini libraire maison pour tester les pré-conditions (Guard.* et Require.*). Il faudra donc la remplacer par des if ou une librairie équivalente.
P.S : Je viens de me rendre compte que je ne pouvais pas coller du code contenant des commentaires en xml. Quelqu'un peut me conseiller un plugin wordpress qui gère cela?
Filed in Asp.net MVC | 3 responses so far


Rafael nov 19th 2008 at 03:22 1
Bonjour Julien,
J’ai lu tout les infos sur SubControllers, téléchargé le MVCContrib trunk et j’ai joué avec le projet de exemple, mais j’ai un doute: comment je peux exécuter un action différent qui la défaut dans un subcontroller? En plus, il y a quelque chose bizarre dans cette implémentation, mais je ne suis pas sur quoi. En tout cas, merci pour le lien, il m’a donné un bonne idée et je la montrerai bientôt.
Merci,
Rafael.
Julien nov 19th 2008 at 09:05 2
Tu ne peux pas dans la version actuelle. Les sous-contrôleurs sont des unités logiques très simples donc un sous-contrôleur = une action .
Rafael nov 19th 2008 at 11:09 3
D’accord, est dommage. Autre chose que je n’aime pas ce l’utilisation des strings pour exécuter les actions, ton idée de utiliser les enums est bonne, meilleur qui l’implémentation défaut. Depuis je l’enviera un implémentation différent que j’ai développé il y a quelque temps.
A bientôt