IOC seems to be a bit of a buzzword again recently with frameworks like Asp.Net MVC popping up allowing the possibility of plugging custom Controller Factory objects directly in.
That's great, but sometimes you just don't want the baggage of a Container hanging around, especially if you are writing a small-ish solution. I faced that scenario today and stumbled upon what I think is a really elegant solution!
The problem... I want to inject dependencies into Controller classes, but don't want to use a container.
The solution... OK, bear with me it's easy!
In the global application_onstart method I have the opportunity to construct a custom ControllerFactory and pass it to Asp.Net. I won't cover that. Try here for more information.
My initial thought was to have a ControllerFactory expose a Register<T>(string name) where T:Controller method. That would let me register a Controller against a name, and then do an Activator.CreateInstance to create it. But of course in the real world the whole point of IoC is that the Controller will have dependencies it needs satisfying so this approach is kind of lacking!
One option I thought of was to have a Builder class for each Controller which would know how to create its Controller. I could RegisterBuilder<T>(Builder<T> builder) where T:Controller. Now my ControllerFactory can grab the appropriate builder and just ask it to Build(). The builder would be specific to a Controller so can create it concretely. It works, but it could lead to an explosion of Builder classes.
Then I remembered my old friend Func<>. It's nothing new really and is just a concrete implementation of a Delegate we could have written in .Net 2.0 - delegate T Func<T>() I think is the signature- don't have Reflector to hand. It allows me to do something like this:
ControllerFactory.Register<T>(Func<T> buildController) where T:Controller.
My global.asax can now look something like this
var provider = new DbConnectionProvider(Configuration.ConnectionStrings[....]);
var customerRepository = new CustomerRepository(provider);
var controllerFactory = new ControllerFactory();
controllerFactory.Register<HomeController>(() => new HomeController(customerRepository));
When a request comes in to the ControllerFactory it can say something like:
Dictionary<Type, Func<Controller> _controllerDictionary;
The syntax might look a bit weird, but essentially the dictionary contains functions which build a particular type. So when we grab something from the dictionary we just have to execute it hence the () call.
No container, no builder classes. Just everything wired up ready to go in my application start-up.
That might pose an architectural question of 'What do you mean by wiring up your application at start-up?' To answer than let me link you to Misko Hevery's blog - a google guy with some awesome posts on writing testable applications.