سؤال

It seems to me that somewhere a rabbit is being pulled out of a hat when it comes to DI in Web API Controllers.

I grok that: 0) The Controller in a Web API project can be called with various classes to be instantiated, all of which implement the interface on which the Controller depends. e.g., with this Controller code:

private readonly IDepartmentRepository _deptsRepository;

public DepartmentsController(IDepartmentRepository deptsRepository)
{
    if (deptsRepository == null)
    {
        throw new ArgumentNullException("deptsRepository is null");
    }
    _deptsRepository = deptsRepository;
}

..."deptsRepository" can be a class that implements IDepartmentRepository and retrieves test data, OR it can be a class that implements IDepartmentRepository and retrieves production data, OR (etc.)

1) Web API decides which Controller is called based on the URI the client calls, and that Web API decides which method in that Controller is called based on what type (GET, POST) etc. it is and what args, if any, are passed with it.

2) Castle Windsor intercepts this automatic control of Controllers with its own replacement routing engine.

What I don't grok is just where the developer injects the concrete class that implements the interface expected by the Controller. IOW, if I want to run the class that pulls from test data, where do I add code to specify that? I would think it would be somewhere in Global.asax.cs, something like (pseudocode):

// Use test data for now
DeptsControllerClass = TestDataClass;
//DeptsControllerClass = ProductionDataClass;

IOW, where does one specify, "This time, I want you to inject THIS concrete class which implements the required interface"?

هل كانت مفيدة؟

المحلول

As you wrote at point 1, Routing and IoC are two different things.

Once the routing engine figures out which controller has to be invoked, a "controller factory" will be invoked.

WebApi framework allows to plug your own factory as following:

GlobalConfiguration.Configuration.Services.Replace(
    typeof(IHttpControllerActivator),
    new WindsorCompositionRoot(this.container));

Read more on Mark Seemann post about webapi&windsor plumbing.

Which concrete will be used to satisfy a given interface dependency, that's up to the ioc you choose to use within your factory as above. Using Windsor you may/should link interfce&concrete in the Installers.

Let me try to recap the whole process 1) Set up the routing in order to link url vs controller 2) create the container and register all components using installers 3) replace default controller factory w/ a factory working w/ your favorite ioc container(Windsor, I presume :-) ) 4) Enjoy the magic.

All those steps happend in the Application_start within the Global.asax

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top