【发布时间】:2012-06-06 22:56:23
【问题描述】:
在ASP.NET Web API中,HttpControllerContext实例提供了很多关于当前环境的信息,包括当前请求的URI。
如果服务依赖于此类信息(例如请求 URI),则应该可以将该信息注入到服务中。
使用Poor Man's DI 很容易做到这一点:只需implement a custom IHttpControllerActivator。
但是,有了温莎城堡,这突然变得非常困难。之前I've described a very convoluted way 解决了这个问题,但是它依赖于 PerWebRequest 生活方式,事实证明这种生活方式在自托管场景中不起作用,因为 HttpContext.Current 是空的。
到目前为止,我已经能够通过将所需信息作为内联参数从自定义 IHttpControllerActivator 传递给 Resolve 方法来完成这项工作:
public IHttpController Create(
HttpControllerContext controllerContext,
Type controllerType)
{
var baseUri = new Uri(
controllerContext
.Request
.RequestUri
.GetLeftPart(UriPartial.Authority));
return (IHttpController)this.container.Resolve(
controllerType,
new { baseUri = baseUri });
}
但是,默认情况下,这仅在立即请求的类型依赖于参数时才有效(即,如果请求的控制器本身依赖于baseUri)。如果对baseUri 的依赖在依赖层次结构中被隐藏得更深,则默认情况下它不起作用,因为内联参数不会传播到更深层。
可以使用自定义 IDependencyResolver(Castle Windsor IDependencyResolver,而不是 ASP.NET Web API IDependencyResolver)更改此行为:
public class InlineDependenciesPropagatingDependencyResolver :
DefaultDependencyResolver
{
protected override CreationContext RebuildContextForParameter(
CreationContext current, Type parameterType)
{
if (parameterType.ContainsGenericParameters)
{
return current;
}
return new CreationContext(parameterType, current, true);
}
}
注意true 是作为propagateInlineDependencies 构造函数参数而不是false 传递的,这是默认实现。
为了将容器实例与 InlineDependenciesPropagatingDependencyResolver 类连接起来,它必须以这种方式构造:
this.container =
new WindsorContainer(
new DefaultKernel(
new InlineDependenciesPropagatingDependencyResolver(),
new DefaultProxyFactory()),
new DefaultComponentInstaller());
我想知道这是否是解决此问题的最佳解决方案,或者是否有更好/更简单的方法?
【问题讨论】:
-
为什么要这样做?如果是用于单元测试,那么我很长一段时间都没有遇到同样的问题,最后只对依赖于在上下文中使用信息的控制器进行了集成测试。
-
问题中的链接提供了这样做的理由。 blog.ploeh.dk/2012/04/17/…
-
@MarkSeemann 嗨,马克,除了您在此处的博客文章之外,您是否能够为这个问题提出更好的解决方案:blog.ploeh.dk/2012/04/19/…
-
@Xerxes 不,但这些天我专门做Pure DI,所以我现在使用的是纯 DI 方法。以下是使用 Pure DI 连接 Web API 的正确方法:blog.ploeh.dk/2012/09/28/…
-
@MarkSeemann 谢谢你的链接和你的博客,它是一个宝库:)
标签: dependency-injection castle-windsor asp.net-web-api self-hosting