c# - IoC: Castle Windsor y WebAPI
asp.net-mvc asp.net-mvc-4 (4)
Configuración existente de Castle Windsor MVC
Suponiendo que tiene MVC y la configuración de Castle Windsor de manera similar al tutorial de Castle Windsor MVC , agregar IoC para que los controladores de API web utilicen la inyección de dependencia es muy simple con http://blog.ploeh.dk/2012/10/03/DependencyInjectioninASP.NETWebAPIwithCastleWindsor/ (tenga en cuenta que explica por qué no usar IDependencyResolver) .
Desde el tutorial de Castle Windsor debería tener algo como esto en 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()
IWindsorContainer container = new WindsorContainer()
.Install(
new LoggerInstaller()
//...,
, new ControllersInstaller()
);
var controllerFactory = new WindsorControllerFactory(container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
return container;
Cambios requeridos
Desde la publicación de Mark Seemann, debe ingresar al punto de entrada de la API web (Raíz de composición) a través del IHttpControllerActivator
. Aquí está su implementación de adaptador que necesita.
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();
}
}
}
Con el adaptador IHttpControllerActivator y la implementación del contenedor MVC Castle Windsor, solo necesita configurarlo en Global.asax.cs
(o en BootStrapper si lo usó). Tiene que ser después de la inicialización de MVC, ya que la inicialización de MVC tiene todos los instaladores.
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));
}
Resultado final:
Los controladores de API web pueden usar sus dependencias inyectadas de la misma manera que sus controladores 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" };
}
}
Tengo un sitio MVC4 con Castle Windsor al que quiero agregar algunas llamadas de WebAPI, así que empiezo a investigar un poco en las interwebs.
Ahora no sé los entresijos de la IoC; Seguí un tutorial sobre cómo configurar Castle Windsor en mi proyecto, inyectando el IUnitOfWorkFactory
y el IApplicationService
como propiedades públicas en un controlador base, y algunas otras interfaces según sea necesario en los constructores del controlador. Funciona a la perfección, así que nunca tuve que hacer más con eso.
En todas partes que estoy leyendo en WebAPI, me dicen que DI no funcionará tan bien usando Castle Windsor, hablando sobre problemas con IDependencyResolver
e IDependencyScope
. Existen varias soluciones e implementaciones para solucionar este problema, pero lo que no me queda claro es cuál es exactamente el problema. Se incluyen fragmentos de código, pero se supone que usted sabe a qué clase pertenecen y cómo se invocan, lo que desafortunadamente no lo hago. Además, todos los ejemplos que he visto en línea se refieren a un proyecto exclusivo de WebAPI, y no a un proyecto MVC4 con un par de ApiController
s juiciosamente lanzados. No sé cómo, o si esto afecta algo.
¿Por qué no funciona lo que tengo trabajando con mis controladores estándar con un controlador API? ¿Qué tipo de código deben hacer las acrobacias para que las llamadas WebAPI y las llamadas web estándar funcionen en la misma aplicación?
El siguiente proyecto de muestra me dio la respuesta que estaba buscando. Utiliza el castillo de Windsor para inyección de dependencia. Pude usar los controladores MVC junto con los controladores de API web en la misma aplicación.
Aquí está el post que lo detalla:
Para utilizar Windsor con webapi siga http://blog.ploeh.dk/2012/10/03/DependencyInjectioninASP.NETWebAPIwithCastleWindsor/ (BEH: enlace fijo)
Puede usar webapi y los controladores MVC en la misma aplicación (prefiero mantenerlos separados) pero la fábrica de enrutadores y controladores son diferentes y usted tiene que configurar dos configuraciones diferentes y manejar las superposiciones de enrutamiento ... Para MVC y Windsor puede encontrar una genial
Primero, cuando Iko declaró que necesita crear una clase que implemente IHttpControllerActivator
.
Luego, en ContainerBootstrapper
en Bootstrap()
agregue lo siguiente Reemplace el valor predeterminado con el implementado:
//This will help in creating Web api with Dependency injection
GlobalConfiguration.Configuration.Services.Replace(
typeof(IHttpControllerActivator),
new WindsorCompositionRoot(container));
Por último, lo que no se menciona aquí y no me funcionó sin él, debería agregar lo siguiente en la implementación del servicio IWindsorInstaller
en install()
:
container.Register(
Classes.FromThisAssembly()
.BasedOn<ApiController>()
.LifestyleTransient()
);