我也使用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<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作为一个ctor参数,并发现:
这样做:
//controller
public class ValuesController : ApiController
{
private readonly HttpRequestMessage _httpReq;
public ValuesController(HttpRequestMessage httpReq)
{
_httpReq = httpReq;
}
//IHttpControllerActivator
public IHttpController Create(
HttpRequestMessage httpRequest,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,new { request = request });
return controller;
即当anon对象具有称为“请求”的属性,并且控制器ctor arg被称为“请求”时.它以某种方式使控制器认为它的请求属性为null.这是什么原因导致我看到的错误:
Cannot reuse an ‘ApiController’ instance. ‘ApiController’ has to be
constructed per incoming message. Check your custom
‘IHttpControllerActivator’ and make sure that it will not manufacture
the same instance.at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext
controllerContext,CancellationToken cancellationToken) at
System.Web.Http.dispatcher.HttpControllerdispatcher.SendAsyncInternal(HttpRequestMessage
request,CancellationToken cancellationToken) at
System.Web.Http.dispatcher.HttpControllerdispatcher.SendAsync(HttpRequestMessage
request,CancellationToken cancellationToken)
读了这个
How can I enrich object composition in StructureMap without invoking setter injection?
它解释了类似的情况.
当然,hyprlinkr具有称为“request”的HttpRequestMessage的ctor参数,因此我需要使用该属性名称指定anon对象.
有任何想法吗?
解决方法
public class WindsorCompositionRoot : IHttpControllerActivator
{
private readonly IWindsorContainer container;
public WindsorCompositionRoot(IWindsorContainer container)
{
this.container = container;
}
public IHttpController Create(
HttpRequestMessage request,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 DefaultComponentInstaller())
.Install(new MyWindsorInstaller());
这里是InlineDependenciesPropagatingDependencyResolver:
public class InlineDependenciesPropagatingDependencyResolver :
DefaultDependencyResolver
{
protected override CreationContext RebuildContextForParameter(
CreationContext current,true);
}
}
最后,我如何注册RouteLinker:
container.Register(Component
.For<RouteLinker,IResourceLinker>()
.LifestyleTransient());
需要注意的一点是,ApiController基类有一个名为Request of HttpRequestMessage类型的公共属性.如my book节第10.4.3节所述,Windsor将尝试为每个可写属性分配一个值(如果它具有匹配的组件),并且匹配不区分大小写.
当您将HttpRequestMessage命名请求传递给Resolve方法时,这正是发生的情况,因此您需要告诉Castle Windsor它应该放弃ApiControllers的属性注入.以下是我在公约注册中如何使用:
container.Register(Classes
.FromThisAssembly()
.BasedOn<IHttpController>()
.ConfigureFor<ApiController>(c => c.Properties(pi => false))
.LifestyleTransient());