32 votes

Résolveur de dépendance de Castle Windsor pour MVC 3

Depuis que le Cio/DI de la mise en œuvre dans MVC 3 est le plus susceptible dans sa forme définitive dans les RC, je suis à la recherche d'une mise à jour de la mise en œuvre de la DependencyResolver, IControllerActivator et IViewPageActivator utilisant le système de Caste de Windsor. Existe-il des exemples qui ont été mis à jour pour MVC 3 RC?

EDIT #1 Mise en œuvre d'un Windsor solveur de dépendances est en effet trivial, mais il y a toujours quelque chose qui manque. Contrairement à Jeff Putz est Ninject exemple (ci-dessous), il apparaît que ce n'est pas aussi simple que cela avec les Windsor. Après le réglage de la résolution de dépendances comme,

DependencyResolver.SetResolver(new WindsorDependencyResolver(container)); 

Windsor jette ComponentNotFoundException. J'ai besoin de fournir des implémentations pour IControllerFactory et IControllerActivator. Depuis le DefaultControllerFactory est DependencyResolver au courant, ce problème peut être résolu comme suit:

Component.For<IControllerFactory >().ImplementedBy<DefaultControllerFactory>()
Component.For<IControllerActivator >().ImplementedBy<WindsorControllerActivator>(),

WindsorControllerActivator est trivial ainsi. Cependant, cela conduit à un autre ComponentNotFoundException pour IViewPageActivator.

Cela me mène à croire que je suis en manque de quelque chose. Il n'y a aucun moyen que ce doit être plus compliqué qu'une mise en œuvre d'un contrôleur de l'usine et de l'appel de ControllerBuilder.Actuel.SetControllerFactory MVC 2.0 de style.

EDIT #2 J'ai raté la subtile mais détail important que la résolution de Dépendances doit retourner la valeur null lorsqu'un service ne peut pas être trouvé. La mise en œuvre est comme suit:

public class WindsorDependencyResolver : IDependencyResolver
{
    private readonly IWindsorContainer container;

    public WindsorDependencyResolver(IWindsorContainer container)
    {
        this.container = container;
    }

    public object GetService(Type serviceType)
    {
        return container.Kernel.HasComponent(serviceType) ? container.Resolve(serviceType) : null;
    }

  public IEnumerable<object> GetServices(Type serviceType)
    {
        return container.Kernel.HasComponent(serviceType) ? container.ResolveAll(serviceType).Cast<object>() : new object[]{};
    }
}

EDIT #3

Répondant à une question dans les commentaires. Si vous ne trouvez que vous avez besoin de votre propre IControllerActivator, ici une simple mise en œuvre de Windsor:

public class WindsorControllerActivator : IControllerActivator
{
    private readonly IWindsorContainer container;

    public WindsorControllerActivator(IWindsorContainer container)
    {
        this.container = container;
    }

    public IController Create(RequestContext requestContext, Type controllerType)
    {
        return (IController)container.GetService(controllerType);
    }
}

}

Encore une fois, ce n'est PAS nécessaire d'obtenir de base DI de travail avec les Windsor et de la MVC3 solveur de dépendances.

EDIT #4 Basé sur des recherches plus poussées et des commentaires, il semble qu'un traditionnel contrôleur de l'usine de mise en œuvre est la meilleure approche pour Windsor et MVC3. Le souci est que le IDependencyResolver interface manque d'une méthode de version, ce qui pourrait provoquer des fuites de mémoire avec les Windsor pas de l'élimination de ses composants. C'est probablement ne va pas être un problème si toutes les dépendances sont résolues avec la PerWebRequest du cycle de vie, mais c'est toujours mieux de ne pas prendre la chance. Voici une implémentation de base de Windsor contrôleur de l'usine pour MVC3.

public class WindsorControllerFactory : DefaultControllerFactory
{
    private readonly IWindsorContainer container;

    public WindsorControllerFactory(IWindsorContainer container)
    {
        this.container = container;
    }

    public override void ReleaseController(IController controller)
    {
        container.Kernel.ReleaseComponent(controller);
    }

    public override IController CreateController(RequestContext requestContext, string controllerName)
    {
        var controllerComponentName = controllerName + "Controller";
        return container.Kernel.Resolve<IController>(controllerComponentName);
    }
}

EDIT #5 Si vous êtes en utilisant MVC domaines, la mise en œuvre ne va pas travailler pour vous. Vous aurez besoin d'enregistrer chaque contrôleur en fonction de son nom, et remplacer GetControllerInstance au lieu de CreateController:

 protected override IController GetControllerInstance(RequestContext context, Type controllerType)
    {
        if (controllerType != null)
        {
            return (IController)container.Kernel.Resolve(controllerType);
        }
        return null;
    }

24voto

Mike Hadlow Points 3779

L'interface MVC3 IDependencyResolver a un gros problème: pas de méthode de publication. Cela signifie qu'il y a une fuite de mémoire potentielle si vous comptez l'utiliser avec Windsor. Voir mon article de blog à ce sujet ici:

http://mikehadlow.blogspot.com/2011/02/mvc-30-idependencyresolver-interface-is.html

10voto

Jeff Putz Points 3654

L'interface n'a pas changé depuis la version bêta, et donc toutes les implémentations de différents cadres doivent encore travailler. Et la vérité est, ce n'est pas compliqué d'une interface... vous devriez être en mesure de rouler sans trop de tracas. Par exemple, je l'ai fait un pour Ninject:

public class NinjectDependencyResolver : IDependencyResolver
{
    public NinjectDependencyResolver(IKernel kernel)
    {
        _kernel = kernel;
    }

    private readonly IKernel _kernel;

    public object GetService(Type serviceType)
    {
        return _kernel.TryGet(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return _kernel.GetAll(serviceType);
    }
}

Puis de fil en mondial.asax comme ceci:

    private static IKernel _kernel;
    public IKernel Kernel
    {
        get { return _kernel; }
    }

    public void Application_Start()
    {
        _kernel = new StandardKernel(new CoreInjectionModule());
        DependencyResolver.SetResolver(new NinjectDependencyResolver(Kernel));
        ...
    }

Rappelez-vous, vous avez toutes sortes de goodies pour libre à ce point, y compris les DI pour les contrôleurs, contrôleur des usines, des filtres d'actions et de visualiser les classes de base.

EDIT: Pour être clair, je ne suis pas sûr de ce que votre "activateurs", mais vous n'avez probablement pas besoin d'eux. Le IDependencyResolver interface gère le newing des contrôleurs et des vues automatiquement.

2voto

Mauricio Scheffer Points 70470

MVCContrib est actuellement la source faisant autorité pour l'intégration IoC-MVC. Actuellement, la branche MVC3 n'inclut que les implémentations d'usine de contrôleur et IDependencyResolver (et quelques autres choses). Je recommande de biffer le référentiel et d'implémenter les points d'extension manquants (cela ne devrait pas être trop difficile), puis d'envoyer une demande d'extraction à l'équipe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X