Ответ 1
Контроллер factory создает их для вас... Вам нужно взглянуть на Injection Dependency.
Попробуйте Autofac, он имеет приятную интеграцию для MVC.
Согласно в этой статье, контроллер должен иметь конструктор, который получает реализованный интерфейс, a 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", добавленный к объявлению интерфейса, но это не обязательно для его компиляции. Есть ли компиляция, я имею в виду неотразимую причину для меня, чтобы добавить "личное чтение только"?
Контроллер factory создает их для вас... Вам нужно взглянуть на Injection Dependency.
Попробуйте Autofac, он имеет приятную интеграцию для MVC.
Поскольку там нигде нет документации (официальные документы просто обсуждают это с 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
и один раз для области, которую он создает для каждого запроса.
Вам нужно использовать инъекцию зависимостей (structuremap, ninject). Если вы не хотите использовать DI, вам необходимо предоставить конструктор перегрузки, как показано ниже.
public DuckbillsController():this( new DuckbillRepository())
{
}