【问题标题】:How is the Web API Controller's constructor called?Web API Controller 的构造函数是如何调用的?
【发布时间】:2014-01-12 04:48:01
【问题描述】:

根据this article,一个Controller应该有一个构造函数来获取要实现的接口,一个la:

public class DuckbillsController : ApiController
{
    IDuckbillRepository _platypiRepository;

    public DuckbillsController(IDuckbillRepository platypiRepository)
    {
        if (platypiRepository == null)
        {
            throw new ArgumentNullException("platypiRepository is null");
        }
        _platypiRepository = platypiRepository;
    }
}

但是这个构造函数是怎么调用的呢?通过客户端调用包含在此类中的 Web API 方法进行估算,但它如何传递接口类型?或者这不是必须发生的(构造函数没有被任何人/从任何地方显式调用)?

更新

规范示例显示接口声明前附加“私有只读”,但这不是编译所必需的。是否有编译(我的意思是令人信服的)理由让我在前面加上“private readonly”?

【问题讨论】:

  • 一般情况下,不会编写任何代码来显式调用构造函数。您需要将您的 DI 容器挂接到 WebApi 框架中,该容器将使用反射来实例化控制器。 This article 可能有助于解释事情。
  • 这实际上是一个非常合理的问题,并且提供的答案只是说“看看这个(第三方工具)”。可悲的事实是,微软在记录这一点方面做得非常糟糕,不幸的是,社区要回答这些问题。

标签: c# asp.net-web-api controller ioc-container constructor-injection


【解决方案1】:

因为在任何地方都没有这方面的文档(官方文档只是讨论了用 Unity 做这件事)。这是你如何做到的。

HttpConfiguration.DependencyResolver 属性是IDependecyResolver 的一个实例,它基本上是一个服务定位器(您要求一个类型的实例,它知道如何创建它)。我想要的是提供我自己的控制器实例化。

这样使用:

config.DependencyResolver = 
   new OverriddenWebApiDependencyResolver(config.DependencyResolver)
   .Add(typeof(ScoreboardController), () => 
                                    new ScoreboardController(Messages) 
   ); 

这样实现:

/// <summary>
/// The standard web api dependency resolver cannot inject dependencies into a controller 
/// use this as a simple makeshift IoC
/// </summary>
public class OverriddenWebApiDependencyResolver : WebApiOverrideDependency<IDependencyResolver >, IDependencyResolver {
    public OverriddenWebApiDependencyResolver Add(Type serviceType, Func<object> initializer) {
        provided.Add(serviceType, initializer);
        return this;
    }
    public IDependencyScope BeginScope() => new Scope(inner.BeginScope(), provided);
    public OverriddenWebApiDependencyResolver(IDependencyResolver inner) : base(inner, new Dictionary<Type, Func<object>>()) { }
    public class Scope : WebApiOverrideDependency<IDependencyScope>, IDependencyScope {
        public Scope(IDependencyScope inner, IDictionary<Type, Func<object>> provided) : base(inner, provided) { }
    }
}
public abstract class WebApiOverrideDependency<T> : IDependencyScope where T : IDependencyScope {
    public void Dispose() => inner.Dispose();
    public Object GetService(Type serviceType) {
        Func<Object> res;
        return provided.TryGetValue(serviceType, out res) ? res() : inner.GetService(serviceType);
    }

    public IEnumerable<Object> GetServices(Type serviceType) {
        Func<Object> res;
        return inner.GetServices(serviceType).Concat(provided.TryGetValue(serviceType, out res) ? new[] { res()} : Enumerable.Empty<object>());
    }
    protected readonly T inner;
    protected readonly IDictionary<Type, Func<object>> provided;
    public WebApiOverrideDependency(T inner, IDictionary<Type, Func<object>> provided) {
        this.inner = inner;
        this.provided = provided;
    }

}

诀窍是您实际上必须实现IDependencyScope 两次 - 一次用于IDependencyResolver,一次用于它在每个请求上创建的范围。

【讨论】:

  • 谢谢;如果我还没有将另一个标记为答案,我会选择这个。
  • 您可以随时更改它:) 但没什么大不了的。只是为了后代放在这里
【解决方案2】:

控制器工厂为你创建它们...你需要看看依赖注入。

试试 Autofac,它对 MVC 有很好的集成。

【讨论】:

  • 这是为 DI 添加的;我们正在使用温莎城堡。
【解决方案3】:

你必须使用依赖注入(结构映射,ninject)。如果您不想使用 DI,则必须提供如下所示的重载构造函数

public DuckbillsController():this( new DuckbillRepository())
{
}

【讨论】:

  • 这个应该是在类中引入DI;这就是我添加构造函数及其参数的原因。那么还有什么必要的呢?我们正在使用温莎城堡。
  • 温莎城堡支持 MVC docs.castleproject.org/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-25
  • 1970-01-01
  • 2015-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-08
相关资源
最近更新 更多