2011-06-29 1 views
2

J'ai le code suivant:Injection Propriété sans attributs à l'aide Ninject dans un contrôleur de base abstraite dans MVC3

public abstract class BaseController : Controller 
{ 
    public IUserService UserService { get; set; } 
} 

Tous mes contrôleurs héritent de ce contrôleur de base. J'ai commencé par le configurer dans Ninject en utilisant le code suivant:

kernel.Bind<BaseController>() 
     .ToSelf() 
     .WithPropertyValue("UserService", x => x.Kernel.GetService(typeof(IUserService))); 

Cela n'a pas fonctionné. Je suppose que c'est parce que le BaseController est une classe abstraite (veuillez confirmer mon hypothèse). Donc, je suis passé à modifier la configuration pour:

kernel.Bind<HomeController>() 
     .ToSelf() 
     .WithPropertyValue("UserService", x => x.Kernel.GetService(typeof(IUserService))); 

Cela ne fonctionne pas. L'inconvénient mineur est que je dois maintenant configurer chaque contrôleur de la même manière.

Depuis que j'ai aussi la configuration DependencyResolver dans mon projet ASP.NET MVC 3 Je pourrais également supprimer la configuration ci-dessus Ninject et modifier mon contrôleur de base pour ressembler à:

public IUserService UserService 
    { 
     get 
     { 
      return DependencyResolver.Current.GetService<IUserService>(); 
     } 
    } 

Y at-il avantage à utiliser le fluent configuration par opposition à l'utilisation de l'approche DependencyResolver? Est-ce que l'un est meilleur que l'autre? Quelle approche serait considérée comme une meilleure pratique?

Il est à noter que je ne voulais pas faire d'injection de constructeur dans mon contrôleur de base.

+1

Cette question n'a-t-elle pas déjà été posée et a-t-elle reçu une réponse dans [Injection de propriété dans le contrôleur de base à l'aide de Ninject 2] (http://stackoverflow.com/questions/3154240/property-injection-in-base-controller-using-ninject -2 /), quoique sous une forme légèrement différente. – mrydengren

+0

Cette question implique le DependencyResolver dans MVC 3 que le précédent n'a pas. La question est aussi quelle est la meilleure approche par opposition à comment faites-vous cela. – Thomas

+0

MVC3/DependencyResolver ne change absolument rien –

Répondre

2

Une meilleure pratique dans MVC consiste à utiliser l'injection du constructeur plutôt que l'injection de propriété. Pourquoi as-tu fait ton choix comme ça?

En utilisant Constructor Injection vous précise que toutes les dépendances dans le constructeur sont nécessaires pour la classe pour faire son travail.

injection propriété signifie que les dépendances sont facultatives ou qu'il existe des implémentations de valeurs par défaut locales, de sorte que tous fonctionnera même si vous ne fournissez pas vous mises en œuvre nécessaires. Vous devriez vraiment savoir ce que vous faites en utilisant l'injection de propriété ou vous n'avez pas d'autre choix, donc l'approche la plus sûre est de compter sur l'injection du constructeur.

Maintenant, je vais vous donner mon point de vue. D'autres peuvent avoir d'autres opinions.

DependencyResolver a été introduit dans le MVC 3 pour l'emplacement de service « pratique » mais pour moi il est un localisateur de service régulier qui pour moi est aussi un anti-modèle http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx. Je ne l'utilise pas parce que je ne l'aime pas et il n'y a aucun avantage à l'utiliser. Je préfère utiliser mon usine de contrôleurs comme auparavant et transmettre les dépendances via le constructeur.

Plus le IDependencyResolver a des problèmes avec certains conteneurs IoC (je ne sais pas si c'est le cas avec Ninject). Vous pouvez en lire plus ici: http://mikehadlow.blogspot.com/2011/02/mvc-30-idependencyresolver-interface-is.html

0

Il existe de nombreuses façons de peler le chat qu'ils disent. Vous pouvez utiliser des liaisons basées sur des conventions avec .WithPropertyValue() ou avec .OnActivaction() (comme décrit here).

public class ControllerModule : NinjectModule 
{ 
    public override void Load() 
    { 
     // Get all controller types derived from the base controller. 
     IEnumerable<Type> controllerTypes = // ... 
     foreach (var controllerType in controllerTypes) 
     { 
      Bind(controllerType).ToSelf().InRequestScope() 
       .WithPropertyValue(...); 
     } 
    } 
} 

Vous pouvez créer votre propre implémentation personnalisée de l'interface IInjectionHeuristic comme décrit here ou votre propre implémentation personnalisée de l'interface IControllerActivator.

public class CustomNinjectControllerActivator : IControllerActivator 
{ 
    private readonly IKernel kernel; 

    public CustomNinjectControllerActivator(IKernel kernel) 
    { 
     this.kernel = kernel; 
    } 

    public IController Create(RequestContext context, Type controllerType) 
    { 
     var baseController = kernel.TryGet(controllerType) as BaseController; 
     if (baseController == null) 
     { 
      return null; 
     } 

     baseController.UserService = kernel.Get<IUserService>(); 
     return baseController; 
    } 
} 

Heck, vous pouvez même utiliser le modèle de localisateur de service si vous êtes à l'aise pour l'utiliser. Vous devez choisir la solution la plus facile à mettre en œuvre, à tester et à maintenir, et bien sûr fournir le comportement souhaité. Vous devez choisir la solution la plus simple à mettre en œuvre, à tester et à maintenir.

+0

Y a-t-il une approche considérée comme plus "correcte"? Je peux implémenter n'importe lequel d'entre eux et cela fonctionnera et fera ce qu'il doit faire mais lequel est le plus correct? – Thomas

+0

Je dirais que la bonne est celle qui fournit le moins d'effort. Dans ce cas, il s'agit probablement de l'activateur de contrôleur personnalisé ou du localisateur de service (le localisateur de dépendances). Mais comme @ Remo Gloor a souligné que vous pourriez vouloir rester à l'écart de ce type d'architecture tout à fait. – mrydengren

2

Si vous avez besoin de la même dépendance dans chaque contrôleur, il semble que quelque chose ne va pas dans votre conception. Très probablement, vous manipulez une sorte de préoccupation transversale dans votre contrôleur de base. Dans ce cas, l'injection de propriété consiste simplement à traiter les symptômes au lieu de guérir la maladie. Cela devrait plutôt être géré par un aspect (par exemple un filtre ou un intercepteur) afin que vous n'ayez pas à polluer votre contrôleur avec quelque chose qui ne lui appartient pas.

Questions connexes