How is the Web API Controller's constructor called?
Asked Answered
M

3

19

According to this article, a Controller should have a constructor that gets the interface to be implemented passed in, a la:

public class DuckbillsController : ApiController
{
    IDuckbillRepository _platypiRepository;

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

But how is this constructor called? A reckon via a client calling a Web API method contained within this class, but how does it get passed the Interface type? Or does that not have to happen (constructor is not explicitly called by anyone/from anywhere)?

UPDATE

The canonical examples show "private readonly" prepended to the Interface declaration, but that is not necessary for it to compile. Is there a compiling, I mean compelling, reason, for me to prepend "private readonly"?

Marty answered 23/12, 2013 at 23:0 Comment(2)
In general, no code is written to explicitly call the constructor. You need to hook your DI container into the WebApi framework, and the container will use reflection to instantiate the controller. This article might help explain things.Temper
This is actually a perfectly reasonable question and the provided answer simply says "look at this (third party tool)". The sad fact of the matter is that Microsoft does a really poor job documenting this and unfortunately it falls to the community to answer these questions.Hornmad
O
8

The controller factory creates them for you... You need to have a look at Dependency Injection.

Try Autofac, it has a nice integration for MVC.

Outspoken answered 23/12, 2013 at 23:5 Comment(1)
This was added for DI; we are using Windsor Castle.Marty
H
19

Since there's no documentation on this anywhere (the official docs just discuss doing it with Unity). Here's how you do it.

The HttpConfiguration.DependencyResolver property is an instance of IDependecyResolver which is basically a service locator (you ask for an instance of type, and it knows how to create it). What I would like is to provide my own controller instantiation.

Use like so:

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

Implemented like so:

/// <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;
    }

}

The trick is that you actually have to implement IDependencyScope twice - once for IDependencyResolver and once for the scope it creates on each request.

Hornmad answered 14/6, 2016 at 15:47 Comment(2)
Thanks; if I hadn't already marked another as the answer, I would choose this one.Marty
You can always change it :) but no big deal. Just putting it here for posterityHornmad
O
8

The controller factory creates them for you... You need to have a look at Dependency Injection.

Try Autofac, it has a nice integration for MVC.

Outspoken answered 23/12, 2013 at 23:5 Comment(1)
This was added for DI; we are using Windsor Castle.Marty
M
6

You have to use a dependency injection ( structuremap, ninject) whatever. If you dont want to use DI then you have to provide an overload constructor as shown below

public DuckbillsController():this( new DuckbillRepository())
{
}
Multiparous answered 23/12, 2013 at 23:5 Comment(2)
This is supposed to be introducing DI into the class; that's why I added the constructor and its argument. So what else is necessary? We We are using Castle Windsor.Marty
Castle Windsor supports MVC docs.castleproject.org/…Multiparous

© 2022 - 2024 — McMap. All rights reserved.