【问题标题】:How can I enrich object composition in StructureMap without invoking setter injection?如何在不调用 setter 注入的情况下丰富 StructureMap 中的对象组合?
【发布时间】:2012-09-28 20:03:03
【问题描述】:

我正在尝试使用 StructureMap 构建 IHttpControllerActivator 接口的实现,以便我可以解决控制器的依赖关系,该依赖关系依赖于在 MVC Web API 管道中处理的 HttpRequestMessage

我对@9​​87654323@的实现如下:

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 开头执行的检查,它检查ApiControllerRequest 属性以查看它是否已被分配一个值。如果该属性具有非空值,则推断控制器已用于处理请求并中止操作。

除此之外,我还验证了 StructureMap 在组成控制器时尝试使用其设置器注入行为,并负责 Request 具有非空值。

在我的注册表中,我没有配置任何 setter-injection,所以我对为什么在这里调用它感到困惑。围绕 StructureMap API 进行的探讨并没有得出任何关于如何改变所表现出的行为的明显答案。

我是否错误地调用了 StructureMap?有没有我可以利用的配置设置说“从不分配属性值”?

【问题讨论】:

  • 能否贴出如何在 StructureMap 中注册控制器的代码
  • 我已经按要求添加了注册码-不是特别详细。

标签: asp.net-web-api structuremap


【解决方案1】:

我认为您的问题与您使用 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.asaxBootstrapper 中,您可以添加以下内容:

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

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

【讨论】:

  • 您似乎错过了我依赖HttpRequestMessage 的部分,它只能通过IHttpControllerActivator 接口进行组合。问题是如何丰富 StructureMap 的对象组合以包含瞬态请求消息,而不调用 setter 注入。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-09
  • 1970-01-01
  • 1970-01-01
  • 2012-05-22
  • 1970-01-01
  • 2023-03-17
  • 2014-05-23
相关资源
最近更新 更多