我正在尝试使用StructureMap构建IHttpControllerActivator
接口的实现,以便我可以解析控制器的依赖关系,该控制器依赖于MVC中正在处理的HttpRequestMessage
Web API管道。
我对Create
的实施如下:
public IHttpController Create(
HttpRequestMessage request,
HttpControllerDescriptor controllerDescriptor,
Type controllerType)
{
return (IHttpController)this.Container
.With(request)
.With(controllerDescriptor)
.GetInstance(controllerType);
}
Container
属性是对构造时传递给激活器的StructureMap IContainer
实例的引用。
我对控制器的注册使用反射来获取所有ApiController
实现:
foreach(var controller in this.GetType().Assembly.GetTypes()
.Where(type => typeof(ApiController).IsAssignableFrom(type)))
{
this.For(controller).Use(controller);
}
使用调试器,我检查了初始化控制器实例并传入其依赖项。但是,在控制器上调用ExecuteAsync
方法时,会抛出异常:
无法重用'ApiController'实例。每个传入消息都必须构造'ApiController'。检查您的自定义'IHttpControllerActivator'并确保它不会生成相同的实例。
经过一些挖掘和实验后,我发现这是由于在ExecuteAsync
开始时执行的检查,它检查Request
的{{1}}属性,看它是否已被分配了值。如果属性具有非null值,则表示控制器已用于处理请求并中止操作。
除此之外,我还验证了StructureMap在编写控制器时尝试使用其setter-injection行为,并负责ApiController
具有非null值。
在我的注册表中,我没有配置任何setter-injection,所以我很困惑为什么在这里调用它。对于如何改变所展示的行为,围绕StructureMap API进行了一次探讨并没有得出任何明显的答案。
我是否错误地调用了StructureMap?我是否可以使用配置设置来说“永远不会分配属性值”?
答案 0 :(得分:0)
我认为您的问题围绕着使用StructureMap
设置控制器的方式。为了使其正常工作,最好的方法是通过创建自己的IDependencyResolver
实现来挂钩WebAPI堆栈的依赖注入堆栈。在http://craigsdevspace.wordpress.com/2012/02/26/using-structuremap-with-web-api/
但基本代码可能类似于:
<强>的IDependencyResolver 强>:
public class _DependencyResolver : _DependencyScope, IDependencyResolver {
public _DependencyResolver(IContainer container) : base(container) { }
public IDependencyScope BeginScope() {
return new _DependencyScope(_container);
}
}
<强> IDependencyScope 强>:
public class _DependencyScope : ServiceLocatorImplBase, IDependencyScope {
protected readonly IContainer _container;
public _DependencyScope(IContainer container) {
if (container == null)
throw new ArgumentNullException("container");
_container = container;
}
public override object GetService(Type serviceType) {
if (serviceType == null)
return null;
try {
return (serviceType.IsAbstract || serviceType.IsInterface)
? _container.TryGetInstance(serviceType)
: _container.GetInstance(serviceType);
} catch {
return null;
}
}
protected override object DoGetInstance(Type serviceType, string key) {
if (string.IsNullOrEmpty(key))
return _container.TryGetInstance(serviceType);
return _container.TryGetInstance(serviceType, key);
}
protected override IEnumerable<object> DoGetAllInstances(Type serviceType) {
return _container.GetAllInstances<object>().Where(s => s.GetType() == serviceType);
}
public IEnumerable<object> GetServices(Type serviceType) {
return _container.GetAllInstances<object>().Where(s => s.GetType() == serviceType);
}
public void Dispose() {
//_container.Dispose();
}
}
要将这些类挂钩到WebAPI,您需要将以下内容添加到Global.asax
:
GlobalConfiguration.Configuration.DependencyResolver =
new _DependencyResolver(ObjectFactory.Container);
在Global.asax
或Bootstrapper
中,您可以添加以下内容:
ObjectFactory.Initialize(x => {
x.Scan(scanner => scanner.AddAllTypesOf<ApiController>());
});
这会设置您的StructureMap
实现以使用堆栈的预先存在的注入结构 - 这应该可以避免您遇到的问题。