【发布时间】:2012-10-10 06:34:57
【问题描述】:
我正在尝试使用 ASP.NET WebAPI 设置 Castle Windsor。
我也在使用 Hyprlinkr 包 (https://github.com/ploeh/Hyprlinkr),因此需要将 HttpRequestMessage 实例注入到我的控制器的依赖项之一中。
我正在关注 Mark Seemann 的这篇文章 - http://blog.ploeh.dk/2012/04/19/WiringHttpControllerContextWithCastleWindsor.aspx,但我发现虽然 API 运行,但当我调用它时,请求只是挂起。没有错误信息。就好像它处于一个无限循环中。它挂在我的自定义 ControllerActivator 中对 Resolve 的调用
我认为我的某些 Castle 注册有误。如果我删除了上面文章中提到的那些,那么我可以成功调用 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,
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 对象具有称为“请求”的属性并且控制器 ctor arg 称为“请求”时。它以某种方式使控制器认为它的请求属性为空。这是导致我看到的错误的原因:
无法重用“ApiController”实例。 'ApiController' 必须是 每个传入消息构造。检查您的自定义 'IHttpControllerActivator' 并确保它不会制造 同一个实例。
在 System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext 控制器上下文,CancellationToken 取消令牌)在 System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal(HttpRequestMessage 请求,CancellationToken 取消令牌)在 System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage 请求,CancellationToken 取消令牌)
阅读本文 How can I enrich object composition in StructureMap without invoking setter injection?
它解释了一个类似的场景。
当然,hyprlinkr 的 HttpRequestMessage 的 ctor arg 称为“request”,所以我确实需要使用该属性名称指定 anon 对象。
有什么想法吗?
【问题讨论】:
-
上面链接的帖子描述了如何使用 Castle Windsor 和 Web API 的预览。由于预览版和 RTM 版本之间存在重大更改,因此此处描述的方法不再有效。请参阅blog.ploeh.dk/2012/10/03/…,了解如何在 Web API RTM 中使 DI 与 Castle Windsor 一起使用。
-
谢谢 - 是的 - 我已经遵循了。我只是不知道如何为 hyprlinkr 需要的 HttpRequestMessage 进行注册。你能指出我正确的方向吗?
-
再次感谢 - 我现在收到一条错误消息!所以有些进展。 “不能重用 'ApiController' 实例。必须为每个传入消息构建 'ApiController'。检查您的自定义 'IHttpControllerActivator' 并确保它不会制造相同的实例。”。我已经用我现在使用的代码更新了上面的问题。你能看出有什么明显的错误吗?听起来好像认为控制器注册为Singleton,但肯定是PerWebRequest。有什么想法吗?
-
您不能将
PerWebRequest与 Web API 一起使用。PerWebRequest依赖于环境上下文HttpContext.Current,这在 Web API 中为空。尝试使用Transient,或编写您自己的定制Castel Windsor 生活方式——我的书解释了如何做到这一点:affiliate.manning.com/idevaffiliate.php?id=1150_236
标签: c# asp.net-web-api inversion-of-control castle-windsor hyprlinkr