ASP Web Api – IoC – 解析HttpRequestMessage

我正在尝试使用ASP.NET WebAPI设置Castle Windsor。

我也在使用Hyprlinkr包( https://github.com/ploeh/Hyprlinkr ),因此需要将HttpRequestMessage的实例注入到我的控制器的一个依赖项中。

我正在关注Mark Seemann的这篇文章 – http://blog.ploeh.dk/2012/04/19/WiringHttpControllerContextWithCastleWindsor.aspx ,但我发现尽管API运行,但当我调用它时,请求只是挂起。 没有错误消息。 就像它处于一个无限循环中一样。 它停留在我的Custom ControllerActivator调用Resolve上

我想我的一些城堡注册错了。 如果我删除上面文章中提到的那些,那么我可以成功调用API(虽然没有我需要解决的依赖项)

有任何想法吗?

代码如下

//Global.asax public class WebApiApplication : HttpApplication { private readonly IWindsorContainer container; public WebApiApplication() { container = new WindsorContainer( new DefaultKernel( new InlineDependenciesPropagatingDependencyResolver(), new DefaultProxyFactory()), new DefaultComponentInstaller()); container.Install(new DependencyInstaller()); } protected void Application_Start() { GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new WindsorCompositionRoot(this.container)); } // installer public class DependencyInstaller : IWindsorInstaller { public void Install(IWindsorContainer container, IConfigurationStore store) { container.AddFacility(); container.Register( Component.For() .Named("ValuesController") .LifeStyle.PerWebRequest, Component.For() .ImplementedBy() .LifeStyle.PerWebRequest, Component.For() .ImplementedBy() .LifeStyle.PerWebRequest, Component.For() .Named("HttpRequestMessage") .LifeStyle.PerWebRequest ); } } //Activator 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, new { request = request }); request.RegisterForDispose( new Release( () => this.container.Release(controller))); return controller; } // DependencyResolver public class InlineDependenciesPropagatingDependencyResolver : DefaultDependencyResolver { protected override CreationContext RebuildContextForParameter(CreationContext current, Type parameterType) { if (parameterType.ContainsGenericParameters) { return current; } return new CreationContext(parameterType, current, true); } } 

编辑***********附加信息****************

所以我设置了一个场景,控制器只需要将HttpRequestMessage作为ctor参数,然后找到:

这有效:

 //controller public class ValuesController : ApiController { private readonly HttpRequestMessage _httpReq; public ValuesController(HttpRequestMessage httpReq) { _httpReq = httpReq; } //IHttpControllerActivator public IHttpController Create( HttpRequestMessage httpRequest, HttpControllerDescriptor controllerDescriptor, Type controllerType) { var controller = (IHttpController)this.container.Resolve( controllerType, new { httpReq = httpRequest }); return controller; 

但是,这不。

 //controller public class ValuesController : ApiController { private readonly HttpRequestMessage _httpReq; public ValuesController(HttpRequestMessage request) { _httpReq = request; } //IHttpControllerActivator public IHttpController Create( HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) { var controller = (IHttpController)this.container.Resolve( controllerType, new { request = request }); return controller; 

即,当anon对象具有称为“request”的属性并且控制器ctor arg被称为“request”时。 它以某种方式使控制器认为它的请求属性为空。 这是导致我看到错误的原因:

无法重用’ApiController’实例。 每个传入消息必须构造’ApiController’。 检查您的自定义’IHttpControllerActivator’并确保它不会生成相同的实例。

System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage)上System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal(HttpRequestMessage请求,CancellationToken cancellationToken)的System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext,CancellationToken cancellationToken)处于System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext,CancellationToken cancellationToken)请求,取消语音取消语句)

阅读本文如何在不调用setter注入的情况下丰富StructureMap中的对象组合?

它解释了类似的情况。

当然,hyprlinkr有一个名为“request”的HttpRequestMessage的ctor arg,所以我确实需要用该属性名指定anon对象。

有任何想法吗?

这是一个适合我的组合根:

 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, new { request = request }); 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(); } } } 

这是我创建容器的方式:

 this.container = new WindsorContainer( new DefaultKernel( new InlineDependenciesPropagatingDependencyResolver(), new DefaultProxyFactory()), new DefaultComponentInstaller()) .Install(new MyWindsorInstaller()); 

这是InlineDependenciesPropagatingDependencyResolver:

 public class InlineDependenciesPropagatingDependencyResolver : DefaultDependencyResolver { protected override CreationContext RebuildContextForParameter( CreationContext current, Type parameterType) { if (parameterType.ContainsGenericParameters) { return current; } return new CreationContext(parameterType, current, true); } } 

最后,这是我如何注册RouteLinker:

 container.Register(Component .For() .LifestyleTransient()); 

需要注意的一点是,ApiController基类有一个名为Request of HttpRequestMessage类型的公共属性。 正如我的本书 10.4.3节所解释的那样,Windsor将尝试为每个可写属性分配一个值,如果它具有匹配的组件 – 并且该匹配不区分大小写。

当您将HttpRequestMessage命名request传递给Resolve方法时,这正是发生的情况,因此您需要告诉Castle Windsor它应该放弃ApiControllers的Property Injection。 以下是我在基于会议的注册中的表达方式:

 container.Register(Classes .FromThisAssembly() .BasedOn() .ConfigureFor(c => c.Properties(pi => false)) .LifestyleTransient()); 

为什么不在ASP.NET Web API中使用已经内置的机制 – 依赖性解析器

http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver

在项目WebApiContrib中有CastleWindsor解析器实现,但正如我在Dependency解析器中看到的那样

https://github.com/WebApiContrib/WebApiContrib.IoC.CastleWindsor

正如Mark在评论中所说 – 实现IHttpControllerActivator的方法之一

http://blog.ploeh.dk/2012/10/03/DependencyInjectionInASPNETWebAPIWithCastleWindsor.aspx