10

我想用ASP.NET WebAPI设置Castle Windsor。ASP Web Api - IoC - 解决HttpRequestMessage

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

我正在关注Mark Seemann的这篇文章 - http://blog.ploeh.dk/2012/04/19/WiringHttpControllerContextWithCastleWindsor.aspx,但我发现虽然API运行,但是当我打电话给它时,请求只是挂起。没有错误信息。就好像它处于无限循环中一样。它挂在我的自定义ControllerActivator中解决的呼叫

我想我的一些城堡注册是错误的。如果我删除上面的文章中提到的那些,那么我可以成功地调用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<TypedFactoryFacility>(); 

     container.Register(
      Component.For<ValuesController>() 
       .Named("ValuesController") 
       .LifeStyle.PerWebRequest, 

      Component.For<IResourceLinker>() 
       .ImplementedBy<RouteLinker>() 
       .LifeStyle.PerWebRequest, 

      Component.For<IResourceModelBuilder>() 
       .ImplementedBy<ResourceModelBuilder>() 
       .LifeStyle.PerWebRequest, 

       Component.For<HttpRequestMessage>() 
       .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作为一个构造函数参数,结果发现:

这工作:

//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; 

即当不久对象有一个名为“请求”属性和构造函数控制器ARG被称为“请求”。它以某种方式使控制器认为它的请求属性为空。这是什么导致我看到的错误:

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

在System.Web.Http.ApiController.ExecuteAsync( controllerContext,的CancellationToken的CancellationToken HttpControllerContext)在 System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal(HttpRequestMessage 请求,的CancellationToken的CancellationToken)在 System.Web.Http .Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage 请求,的CancellationToken的CancellationToken)

具有此 How can I enrich object composition in StructureMap without invoking setter injection?

它解释了一个类似的情况。

当然,hyprlinkr对于HttpRequestMessage被称为“request”,因此我确实需要指定具有该属性名称的anon对象。

任何想法?

+3

连接到上面的帖子介绍如何使用温莎城堡与Web API的预览。由于预览和RTM版本之间发生了重大变化,因此这里描述的方法不再有效。请参考http://blog.ploeh.dk/2012/10/03/DependencyInjectionInASPNETWebAPIWithCastleWindsor.aspx对于如何使DI工作与温莎城堡中的Web API RTM的说明。 –

+0

谢谢 - 是的 - 我跟着那个。我只是不知道如何为hyprlinkr需要的HttpRequestMessage进行注册。你能为我指出正确的方向吗? – ChrisCa

+0

像这样:http://stackoverflow.com/q/10854701/126014 –

回答

12

这里有一个成分根为我的作品:

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<RouteLinker, IResourceLinker>() 
    .LifestyleTransient()); 

有一点需要注意的是ApiController基类有一个名为Request的HttpRequestMessage类型的公共属性。如my book的第10.4.3节所述,如果温莎具有匹配的组件,Windsor将尝试为每个可写属性赋值 - 并且该匹配不区分大小写。

当你通过一个名为request的解决方法的HttpRequestMessage,这正是发生什么事,所以你需要告诉温莎城堡,它应该放弃房产注射液ApiControllers。以下是我不要在基于约定登记:

container.Register(Classes 
    .FromThisAssembly() 
    .BasedOn<IHttpController>() 
    .ConfigureFor<ApiController>(c => c.Properties(pi => false)) 
    .LifestyleTransient()); 
+0

谢谢 - 你需要替换IHttpeControllerActivator? GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator),new WindsorCompositionRoot(container)); 如果我不这样做,我得到一个错误,我的控制器没有默认的构造函数 - 所以它显然不是由城堡构造的。 如果我添加上面的行,那么我得到和以前一样的错误。即不能重用'ApiController'实例。 你能告诉我你的控制器注册是什么样子吗?我有这个:container.Register(Component.For ()。LifestyleTransient()); – ChrisCa

+0

有关基础知识,请参阅http://blog.ploeh.dk/2012/10/03/DependencyInjectionInASPNETWebAPIWithCastleWindsor.aspx。您不需要(也不能)完全注册HttpRequestMessage,因为每次调用IHttpControllerActivator.Create都有一个新实例。 ValuesController的注册看起来很好......从目前可用的信息来看,我无法分辨出什么是错的。 –

+0

是的,这很奇怪。也许我有一个不同版本的web api给你?有什么办法可以告诉?另外 - 你可以确认你的版本是否替换默认的IHttpControllerActivator,即config.Services.Replace(typeof(IHttpControllerActivator),new WindsorCompositionRoot(container)); – ChrisCa

0

为什么不使用ASP中已有的内置机制。NET的Web API - 依赖解析器

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

在项目WebApiContrib有CastleWindsor解析器实现,但我已经与依赖解析器看到

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

而马克在评论说 - 一个的方式来实现IHttpControllerActivator

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

+0

我更关心如何解决HttpRequestMessage问题。在任何一种方法中...... – ChrisCa

+0

HttpRequestMessage已解决......嗯,为什么你需要它? – Regfor

+0

Hyprlinkr库有一个构造函数依赖于它,我需要满足 – ChrisCa