webentwicklung-frage-antwort-db.com.de

IoC: Castle Windsor und WebAPI

Ich habe eine MVC4-Site, die Castle Windsor verwendet, zu der ich einige WebAPI-Aufrufe hinzufügen möchte. Daher fange ich an, ein wenig in den Interwebs zu suchen.

Jetzt kenne ich die Besonderheiten von IoC nicht. Ich habe ein Tutorial durchlaufen, wie Castle Windsor in meinem Projekt eingerichtet wird, und IUnitOfWorkFactory und IApplicationService als öffentliche Eigenschaften in einen Basiscontroller und einige andere Schnittstellen, wie sie in den Controller-Konstruktoren benötigt werden, eingefügt haben. Es funktioniert schwimmend, also musste ich nie mehr damit anfangen.

Überall, wo ich bei WebAPI nachlese, wird mir gesagt, dass DI mit Castle Windsor nicht so gut funktionieren wird und über Probleme mit der Variablen IDependencyResolver und IDependencyScope spricht. Es gibt mehrere Problemumgehungen und Implementierungen, wie man dieses Problem umgehen kann, aber mir ist nicht klar, was genau das Problem ist. Code-Snippets sind enthalten, aber es wird davon ausgegangen, dass Sie wissen, zu welcher Klasse sie gehören und wie sie aufgerufen werden, was ich leider nicht weiß. Darüber hinaus beziehen sich alle Beispiele, die ich online gesehen habe, auf ein exklusives WebAPI-Projekt und nicht auf ein MVC4-Projekt mit einem paar ApiControllers, das mit Bedacht ins Feld geworfen wurde. Ich weiß nicht, wie oder ob dies irgendetwas beeinflusst.

Warum funktioniert meine Arbeit mit meinen Standardcontrollern nicht mit einem API-Controller? Welche Art von Code-Akrobatik muss ausgeführt werden, damit WebAPI-Aufrufe und Standard-Webaufrufe in derselben Anwendung ausgeführt werden können?

19
Jeremy Holovacs

Um Windsor mit Webapi zu verwenden, folgen Sie http://blog.ploeh.dk/2012/10/03/DependencyInjectioninASP.NETWebAPIwithCastleWindsor/ (BEH: Fixed Link)

Lesen Sie auch Castle Windsor/DelegatingHandler/IPrincipal Dependency Injection (DI)/Inversion der Kontrolle (IoC) in ASP.NET Web API

Sie können Webapi- und MVC-Controller in derselben App verwenden (ich bevorzuge es, sie getrennt zu halten), aber das Routing und die Controller-Fabrik sind unterschiedlich, und Sie müssen zwei unterschiedliche Konfigurationen einrichten und Routing-Überlappungen handhaben. Für MVC & Windsor findest du toll 

12
Crixo

Bestehende Castle Windsor MVC-Konfiguration

Angenommen, Sie haben MVC und Castle Windsor ähnlich wie Castle Windsor MVC-Lernprogramm eingerichtet. Das Hinzufügen von IoC, damit Web-API-Controller die Abhängigkeitseinspritzung nutzen, ist mit Mark Seemanns Beitrag ( Beachten Sie, dass er erklärt, warum IDependencyResolver nicht verwendet wird.) .

Im Castle Windsor-Tutorial sollten Sie so etwas in Global.asax.cs haben.

    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;

Erforderliche Änderungen

Von Mark Seemanns Post aus müssen Sie über die Variable IHttpControllerActivatorname _ in den Einstiegspunkt (Composition Root) der Web-API gelangen. Hier ist seine Adapter-Implementierung, die Sie benötigen.

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();
        }
    }
}

Mit dem IHttpControllerActivator-Adapter und der MVC Castle Windsor-Containerimplementierung müssen Sie ihn nur im Global.asax.cs (oder in BootStrapper (falls verwendet)) konfigurieren. Es muss sich nach der MVC-Initialisierung befinden, da die MVC-Initialisierung über alle Installationsprogramme verfügt. 

    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));
    }

Endergebnis:

Die Web-API-Controller können Ihre injizierten Abhängigkeiten genauso verwenden wie Ihre MVC-Controller.

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

Das folgende Beispielprojekt gab mir die Antwort, die ich gesucht hatte. Es verwendet Castle Windsor für die Abhängigkeitsinjektion. Ich konnte MVC-Controller neben Web-API-Controllern in derselben Anwendung verwenden.

mirajavora/WebAPISample


Hier ist der Beitrag, der es ausführlich beschreibt:

Erste Schritte mit der ASP.NET-Web-API

6

Wie Iko bereits angedeutet hat, müssen Sie eine Klasse erstellen, die IHttpControllerActivator implementiert.

Fügen Sie dann in ContainerBootstrapper in Bootstrap() Folgendes hinzu: Ersetzen Sie den Standard durch den implementierten:

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

Zum Schluss wird hier nicht erwähnt und es funktionierte für mich nicht ohne, dass Sie Folgendes in Ihren implementierten IWindsorInstaller-Dienst in install() einfügen sollten:

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