2010-11-10 34 views
1

Je viens de mettre à jour mon projet MVC2 vers MVC3 et j'ai utilisé la référence du paquet de la bibliothèque NuGet pour installer ninject. Cela a créé une classe appstart et j'ai utilisé le code suivant pour injecter ma classe IMembershipService.Objet Ninject ne liant pas dans BaseController dans MVC3

public static void RegisterServices(IKernel kernel) { 
     kernel.Bind<IMembershipService>().To<AccountMembershipService>(); 
    } 

Cela fonctionne très bien avec mon HomeController, par exemple. Cependant, j'utilise un BaseController. Presque le même code dans la classe de base ne fonctionne plus.

public class BaseController : Controller 
{ 
    public IMembershipService MembershipService { get; set; } 
    public UserService UserService { get; set; } 

    public BaseController() : this(null, null) { } 

    public BaseController(IMembershipService service, UserService userService) 
    { 
     MembershipService = service; 
     UserService = userService ?? new UserService(); 
    } 

Si je casse le constructeur du contrôleur de base, le service est juste NULL. Je n'ai jamais utilisé Ninject pour IOC, alors peut-être que la réponse est évidente, mais pourquoi n'injectera-t-il pas mon AccountMembershipController dans la classe de base comme je le veux? Je ne vois pas ce qui est différent, bien que je me rende compte que le niveau supplémentaire d'héritage peut être en train de jouer avec Ninject en quelque sorte.

Répondre

1

J'ai moi-même rencontré ce même problème. En supposant que votre code ressemble à ceci:

public HomeController : BaseController 
{ 

} 

public BaseController : Controller 
{ 
    public IMembershipService MembershipService { get; set; } 

    public MembershipService() { } 

    public MembershipService(IMembershipService service) 
    { 
     MembershipService = service; 
    } 
} 

Pour une raison quelconque, Ninject pense que HomeController a un seul constructeur, l'un sans paramètre par défaut. Lorsque vous mettez tout dans HomeController, il peut trouver le constructeur injectable, mais le factoriser dans une classe de base et pour une raison quelconque, il ne cherchera pas dans la classe de base pour voir s'il y a des constructeurs surchargés. Il existe deux correctifs pour cela:

  1. Supprimez le constructeur par défaut. C'est ma solution préférée car elle oblige le constructeur à être injecté (comme lorsque vous créez le contrôleur manuellement lors des tests unitaires), mais l'inconvénient est que vous devez implémenter le constructeur dans toutes vos sous-classes.
  2. Gardez le constructeur par défaut, mais ajouter l'[Inject] attribut à toutes vos propriétés injectables:

    public BaseController : Controller 
    { 
        [Inject] public IMembershipService MembershipService { get;set; } 
        // rest is the same 
    } 
    

Ninject injectera les propriétés correctement cette façon, mais il faut savoir que Ninject appellera le constructeur parameterless .

+0

Donc, vous faites essentiellement cela dans chaque sous-classe? public HomeController (service IMembershipService): base (service) {} –

+0

Oui, juste comme ça. –

+0

Intéressant, qui peut être un peu bâclé si vous avez beaucoup de services et de contrôleurs, je peux simplement mettre hors tension le Ninject pour l'instant, ou utiliser un conteneur différent. Merci. –

5

Votre contrôleur HomeController est-il commandé par Controller et non par BaseController? En outre, vous avez un constructeur par défaut pour BaseController qui définit les choses comme nulles. Pourquoi avez-vous cela du tout? Je commencerais par me débarrasser de ces constructeurs par défaut. Vous ne devriez pas avoir besoin de constructeurs par défaut.

+0

J'ai eu les constructeurs par défaut simplement parce que le projet de test unitaire par défaut se brisait sans eux. Mais j'ai essayé avec et sans et cela n'a pas semblé faire la différence. HomeController dérive de BaseController après avoir déplacé le service d'appartenance à la classe de base. C'est quand ça casse. –

+0

En fait, plus correctement, le sous-contrôleur demande un constructeur par défaut dans le contrôleur de base. Il ne compilera pas sans cela. (Bien que les tests unitaires intégrés veulent constructeur par défaut dans HomeController.) BTW votre conversation PDC est ce qui m'a mis dans ce gâchis. (plaisante ... belle présentation, m'a définitivement convaincu de faire la mise à niveau.) –