Asp.net web api 如何在不调用setter注入的情况下丰富StructureMap中的对象组合?

Asp.net web api 如何在不调用setter注入的情况下丰富StructureMap中的对象组合?,asp.net-web-api,structuremap,Asp.net Web Api,Structuremap,我正试图为StructureMap构建一个IHttpControllerActivator接口的实现,这样我就可以解决控制器的依赖关系,它依赖于MVC Web API管道中正在处理的HttpRequestMessage 我的Create实现如下: public IHttpController Create( HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type con

我正试图为StructureMap构建一个
IHttpControllerActivator
接口的实现,这样我就可以解决控制器的依赖关系,它依赖于MVC Web API管道中正在处理的
HttpRequestMessage

我的
Create
实现如下:

public IHttpController Create(
    HttpRequestMessage request,
    HttpControllerDescriptor controllerDescriptor,
    Type controllerType)
{
    return (IHttpController)this.Container
        .With(request)
        .With(controllerDescriptor)
        .GetInstance(controllerType);
}
Container
属性是对StructureMap
IContainer
实例的引用,该实例在构造时传递给activator

我对控制器的注册使用反射来获得所有
ApiController
实现:

foreach(var controller in this.GetType().Assembly.GetTypes()
    .Where(type => typeof(ApiController).IsAssignableFrom(type)))
{
   this.For(controller).Use(controller);
}
使用调试器,我检查初始化控制器实例并传入它们的依赖项。但是,在控制器上调用
ExecuteAsync
方法时,会引发异常:

无法重用“ApicController”实例必须根据传入消息构造ApicController。检查您的自定义“IHttpControllerActivator”,确保它不会制造相同的实例

经过一些挖掘和实验后,我发现这是由于在
ExecuteAsync
开始时执行了一项检查,该检查检查
ApiController
Request
属性,以查看是否已为其赋值。如果属性具有非null值,则会推断控制器已用于处理请求并中止操作

除此之外,我还验证了StructureMap在编写控制器时试图使用其setter注入行为,并且负责
请求
具有非空值

在我的注册表中,我没有配置任何setter注入,所以我不明白为什么在这里调用它。对StructureMap API的研究并没有给出任何明显的答案,说明我如何改变所展示的行为


我是否错误地调用了StructureMap?是否有一个配置设置可以让我说“永远不要分配属性值”

我认为您的问题围绕着使用
StructureMap
设置控制器的方式。为了使其正常工作,最好的方法是通过创建自己的
IDependencyResolver
实现来连接WebAPI堆栈的依赖项注入堆栈。这里有一个很好的例子

不过,基本代码可能类似于:

IDependencyResolver

public class _DependencyResolver : _DependencyScope, IDependencyResolver {

    public _DependencyResolver(IContainer container) : base(container) { }

    public IDependencyScope BeginScope() {
        return new _DependencyScope(_container);
    }
}
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();
    }

}
IDependencyScope

public class _DependencyResolver : _DependencyScope, IDependencyResolver {

    public _DependencyResolver(IContainer container) : base(container) { }

    public IDependencyScope BeginScope() {
        return new _DependencyScope(_container);
    }
}
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();
    }

}
Global.asax
或您的
Bootstrapper
中,您可以添加以下内容:

ObjectFactory.Initialize(x => {
    x.Scan(scanner => scanner.AddAllTypesOf<ApiController>());
});
ObjectFactory.Initialize(x=>{
x、 扫描(scanner=>scanner.AddAllTypesOf());
});

这将设置您的
StructureMap
实现以使用堆栈的预先存在的注入结构-这将避免您遇到的问题。

您可以发布代码吗?您在StructureMapI中注册控制器的方式我已按要求添加了注册代码-这不是特别详细。您似乎错过了该部分其中,我依赖于
HttpRequestMessage
,该消息仅可通过
IHttpControllerActivator
接口进行合成。问题是如何在不调用setter注入的情况下,丰富StructureMap的对象组合以包含瞬态请求消息。