Implémentation de Castle Windsor ApiController Factory pour API Web ASP.NET

Je sais qu’il est possible d’utiliser DependancyResolver et d’enregistrer Castle Windsor auprès de MVC, mais en raison des problèmes décrits dans https://stackoverflow.com/a/4889222/139392, nous nous sums tenus à la méthode de mise en œuvre de WindsorControllerFactory sur nos projets MVC.

Cependant, il semble que les ApiControllers utilisent un autre type d’usine, car Castle Windsor est incapable d’injecter les dépendances.

Quelqu’un a-t-il compris comment utiliser Castle Windsor avec les API Web ASP.NET et MVC sans utiliser DependencyResolver?

Grâce au message de Critiano et à quelques recherches en ligne, j’ai réussi à le faire fonctionner. Voici le code pour tous ceux qui ont ce problème. Je me suis habitué à travailler avec MVC3 et ASP.NET Web Api Beta, mais je pense que la même solution devrait fonctionner pour MVC4.

Tout d’abord, j’ai créé une WindsorHttpControllerFactory car les ApiControllers utilisent une usine différente de celle de MVC.

public class WindsorHttpControllerFactory : IHttpControllerFactory { private readonly IKernel kernel; private readonly HttpConfiguration configuration; public WindsorHttpControllerFactory(IKernel kernel, HttpConfiguration configuration) { this.kernel = kernel; this.configuration = configuration; } public IHttpController CreateController(HttpControllerContext controllerContext, ssortingng controllerName) { if (controllerName == null) { throw new HttpException(404, ssortingng.Format("The controller for path '{0}' could not be found.", controllerContext.Request.RequestUri.AbsolutePath)); } var controller = kernel.Resolve(controllerName); controllerContext.Controller = controller; controllerContext.ControllerDescriptor = new HttpControllerDescriptor(configuration, controllerName, controller.GetType()); return controllerContext.Controller; } public void ReleaseController(IHttpController controller) { kernel.ReleaseComponent(controller); } } 

La partie la plus délicate était l’enregistrement, cela semblait impliquer l’enregistrement de tout un tas d’autres choses. C’est ce que j’ai fini avec.

 container.Register(Component.For().ImplementedBy().LifeStyle.Singleton); container.Register(Component.For().ImplementedBy().LifeStyle.Singleton); container.Register(Component.For().ImplementedBy().LifeStyle.Singleton); container.Register(Component.For().ImplementedBy().LifeStyle.Transient); container.Register(Component.For().ImplementedBy().LifeStyle.Transient); container.Register(Component.For().ImplementedBy().LifeStyle.Transient); container.Register(Component.For().ImplementedBy().LifeStyle.Transient); container.Register(Component.For().ImplementedBy().LifeStyle.Transient); container.Register(Component.For().Instance(configuration)); //Register all api controllers container.Register(AllTypes.FromAssembly(assemblyToRegister) .BasedOn() .Configure(registration => registration.Named(registration.ServiceType.Name.ToLower().Replace("controller", "")).LifeStyle.Transient)); //Register WindsorHttpControllerFactory with Service resolver GlobalConfiguration.Configuration.ServiceResolver.SetService(typeof(IHttpControllerFactory), container.Resolve()); 

Je devais créer ma propre implémentation d’un ILogger, vous pouvez utiliser une version de stub comme ci-dessous.

 public class MyLogger : System.Web.Http.Common.ILogger { public void LogException(ssortingng category, TraceLevel level, Exception exception) { // Do some logging here eg. you could use log4net } public void Log(ssortingng category, TraceLevel level, Func messageCallback) { // Do some logging here eg. you could use log4net } } 

J’ai également fait face à ce problème il y a deux jours et ce post m’a aidé. Et n’oubliez pas d’append des contrôleurs WebAPI dans votre bootstrap Windsor.

 container.Register(AllTypes.FromThisAssembly().BasedOn().LifestyleTransient()); 

UPDATE pour ASP.NET MVC 4 RC: Cet article utile vous explique comment utiliser Windsor avec WebAPI, il fonctionne à merveille.

Regardez ce post

Je ne suis pas encore passé à mvc 4 beta, y compris web.api (j’utilise toujours Web api de la WCF, Prev6), mais ce qui a été souligné dans le fil semble être la voie à suivre.

J’ai écrit un post sur comment faire cela et le twigr à RavenDB que vous pourriez trouver utile ici

J’ai réussi à résoudre mon conteneur windsor en utilisant GlobalConfiguration.Configuration.ServiceResolver.SetResolver comme indiqué ici .

Exemple de code Windsor

 private void BootStrapWindsorContainer() { _container = new WindsorContainer() .Install(FromAssembly.This()); var controllerFactory = new WindsorControllerFactory(_container.Kernel); ControllerBuilder.Current.SetControllerFactory(controllerFactory); ServiceLocator.SetLocatorProvider(() => new WindsorServiceLocator(_container)); GlobalConfiguration.Configuration.ServiceResolver.SetResolver( t => { try { return _container.Resolve(t); } catch { return null; } }, t => { try { return _container.ResolveAll(t).OfType(); } catch { return new List(); } }); } 

Le renvoi de null lorsque vous ne pouvez pas résoudre les types fonctionne et il semble que MVC créera de nouvelles dépendances.

Edit: Assurez-vous de disposer d’un programme d’installation pour IHttpController

 public class WindsorHttpControllerFactory : IHttpControllerActivator { readonly IWindsorContainer _container; public WindsorHttpControllerFactory(IWindsorContainer container) { _container = container; } public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) { var controller = (IHttpController)_container.Resolve(controllerType); request.RegisterForDispose(new Release(() => _container.Release(controller))); return controller; } class Release : IDisposable { readonly Action _release; public Release(Action release) { _release = release; } public void Dispose() { _release(); } } }