web-dev-qa-db-fra.com

IoC: Château Windsor et WebAPI

J'ai un site MVC4 utilisant Castle Windsor auquel je veux ajouter des appels WebAPI, alors je commence à fouiller un peu sur les interwebs.

Maintenant, je ne connais pas les tenants et les aboutissants d'IoC; J'ai suivi un didacticiel expliquant comment configurer Castle Windsor sur mon projet, en injectant IUnitOfWorkFactory et IApplicationService en tant que propriétés publiques dans un contrôleur de base, ainsi que quelques autres interfaces nécessaires dans les constructeurs de contrôleur. Cela fonctionne à merveille, alors je n'ai jamais eu à en faire plus.

Partout où je lis sur WebAPI, on me dit que DI ne marchera pas si bien avec Castle Windsor, en parlant de problèmes avec IDependencyResolver et IDependencyScope. Il existe plusieurs solutions de contournement et mises en œuvre pour contourner ce problème, mais ce que je ne comprends pas bien, c'est en quoi consiste exactement le problème. Les extraits de code sont inclus, mais l’hypothèse est que vous savez à quelle classe ils appartiennent et comment ils sont invoqués, ce que malheureusement je n’ai pas. En outre, tous les exemples que j'ai vus en ligne font référence à un projet WebAPI exclusif et non à un projet MVC4 avec un couple ApiController jeté judicieusement. Je ne sais pas comment, ou si, cela affecte quoi que ce soit.

Pourquoi ce que j'ai avec mes contrôleurs standard ne fonctionne-t-il pas avec un contrôleur API? Quel type de code doit être acrobatique pour que les appels WebAPI et les appels Web standard fonctionnent dans la même application?

19
Jeremy Holovacs

Pour utiliser Windsor avec webapi, suivez http://blog.ploeh.dk/2012/10/03/DependencyInjectioninASP.NETWebAPIwithCastleWindsor/ (BEH: lien fixe)

Lire aussi Castle Windsor/DelegatingHandler/Injection de dépendance IPrincipale (DI)/Inversion de contrôle (IoC) dans l’API Web ASP.NET

Vous pouvez utiliser les contrôleurs webapi et MVC dans la même application (je préfère la garder séparée), mais le routage et l'usine de contrôleurs sont différents et vous devez configurer deux configurations différentes et gérer les chevauchements de routage ... Pour MVC & Windsor vous pouvez trouver un grand 

12
Crixo

Configuration existante du Castle Windsor MVC

En supposant que MVC et Castle Windsor soient configurés de manière similaire au tutoriel Castle Windsor MVC , ajouter IoC pour permettre aux contrôleurs de l'API Web d'utiliser l'injection de dépendance est très simple avec publication de Mark Seemann } _ ( notez qu'il explique pourquoi ne pas utiliser IDependencyResolver) .

Dans le didacticiel de Castle Windsor, vous devriez avoir quelque chose comme ceci dans Global.asax.cs.

    private static IWindsorContainer container;

    protected void Application_Start()
    {
        //... MVC / Web API routing etc.
        BootStrapper bs = new BootStrapper();
        container = bs.ConfigureCastleWindsorMVC();
    }

BootStrapper.ConfigureCastleWindsorMVC() snip

        IWindsorContainer container = new WindsorContainer()
            .Install(
                new LoggerInstaller()
                //...,
                , new ControllersInstaller()
            );

        var controllerFactory = new WindsorControllerFactory(container.Kernel);
        ControllerBuilder.Current.SetControllerFactory(controllerFactory);
        return container;

Changements requis

Dans le message de Mark Seemann, vous devez entrer dans les points d’entrée (Composition Root) } de la Web API par la IHttpControllerActivator. Voici son implémentation d'adaptateur dont vous avez besoin.

public class WindsorCompositionRoot : IHttpControllerActivator
{
    private readonly IWindsorContainer container;

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

    public IHttpController Create(HttpRequestMessage request,
        HttpControllerDescriptor controllerDescriptor, Type controllerType)
    {
        var controller =
            (IHttpController)this.container.Resolve(controllerType);

        request.RegisterForDispose(
            new Release(() => this.container.Release(controller)));

        return controller;
    }

    private class Release : IDisposable
    {
        private readonly Action release;

        public Release(Action release) { this.release = release; }

        public void Dispose()
        {
            this.release();
        }
    }
}

Avec l'adaptateur IHttpControllerActivator et l'implémentation du conteneur MVC Castle Windsor, il vous suffit de le configurer dans le Global.asax.cs (ou dans BootStrapper si vous l'avez utilisé). Cela doit être après l'initialisation de MVC, car tous les programmes d'installation sont présents. 

    private static IWindsorContainer container;

    protected void Application_Start()
    {
        // MVC / Web API routing etc.
        BootStrapper bs = new BootStrapper();
        container = bs.ConfigureCastleWindsorMVC();
        // Web API Castle Windsor ++ ADD THIS ++
        GlobalConfiguration.Configuration.Services.Replace(
            typeof(IHttpControllerActivator),
            new WindsorCompositionRoot(container));
    }

Résultat final:

Les contrôleurs API Web peuvent utiliser vos dépendances injectées de la même manière que vos contrôleurs MVC.

public class TestController : ApiController
{
    private readonly ITestService TestService;

    public TestController(ITestService testService)
    {
        this.TestService = testService;
    }

    // GET api/<controller>
    public IEnumerable<string> Get()
    {
        return TestService.GetSomething();
        //return new string[] { "value1", "value2" };
    }
}
10
lko

Le projet exemple suivant m'a donné la réponse que je cherchais. Il utilise Castle Windsor pour l'injection de dépendance. J'ai pu utiliser les contrôleurs MVC avec les contrôleurs API Web sur la même application.

mirajavora/WebAPISample


Voici le message détaillant:

Mise en route de l'API Web ASP.NET

6
Leniel Maccaferri

Tout d'abord, comme Iko l'a indiqué, vous devez créer une classe qui implémente IHttpControllerActivator.

Puis, dans ContainerBootstrapper, dans Bootstrap(), ajoutez ce qui suit Remplacez la valeur par défaut par celle implémentée:

 //This will help in creating Web api with Dependency injection
 GlobalConfiguration.Configuration.Services.Replace(
 typeof(IHttpControllerActivator),
 new WindsorCompositionRoot(container));

Enfin, ce qui n’est pas mentionné ici et qui ne fonctionnait pas pour moi sans cela, vous devez ajouter ce qui suit dans le service IWindsorInstaller mis en œuvre dans install():

container.Register(
    Classes.FromThisAssembly()
    .BasedOn<ApiController>()
    .LifestyleTransient()    
);
0
Ali Ezzat Odeh