我正在尝试使用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<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);
}
}
EDIT *********** 附加信息****************
所以我设置了一个场景,控制器只将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'并确保它不会制造 相同的实例。
at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext) controllerContext,CancellationToken cancellationToken)at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal(HttpRequestMessage 请求,取消语音取消语言) System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage 请求,取消语音取消语言)
读一读 How can I enrich object composition in StructureMap without invoking setter injection?
它解释了类似的情况。
当然,hyprlinkr有一个名为“request”的HttpRequestMessage的ctor arg,所以我需要用该属性名指定anon对象。
有什么想法吗?
答案 0 :(得分: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基类有一个名为HttpRequestMessage类型的Request
的公共属性。正如my book的第10.4.3节所解释的那样,Windsor将尝试为每个可写属性分配一个值,如果它具有匹配的组件 - 并且该匹配不区分大小写。
当您将名为request
的HttpRequestMessage传递给Resolve方法时,这正是发生的情况,因此您需要告诉Castle Windsor它应该放弃ApiControllers的Property Injection。以下是我在基于会议的注册中的表达方式:
container.Register(Classes
.FromThisAssembly()
.BasedOn<IHttpController>()
.ConfigureFor<ApiController>(c => c.Properties(pi => false))
.LifestyleTransient());
答案 1 :(得分:0)
为什么不在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