200 Page Manual on Inversion of Control, Part 2
I’ve received a ton of email with questions about
my IoC post the other day, so I thought I’d take a minute (or 60) and write up a followup. In this post I’ll try to put some pieces together and explain a bit more as to *why* you might want to use DI/IoC and how it won’t turn your application into the Mars Rover.
Sunday, October 11, 2009
I’ve received a ton of email with questions about
my IoC post the other day, so I thought I’d take a minute (or 60) and write up a followup. In this post I’ll try to put some pieces together and explain a bit more as to *why* you might want to use DI/IoC and how it won’t turn your application into the Mars Rover.
Quick Review
In the last 2 posts I’ve covered 4 “Cool Kid” patterns and tools:
- Dependency Injection: wiring a class to take its dependencies via constructor
- The Repository Pattern: formalizing your data access into a class with explicit methods (IPostRepository)
- Inversion of Control: using a special container to instantiate your objects for you, rather than explicitly declaring them yourself.
- Mocking: a groovy testing tool/trick to orchestrate your tests at a higher level.
These concepts are a lot of fun to read, but many people say “yah so what” – and
that’s the focus of this post: to tie the strings together.
Our App So Far
I’ve been using my blog project (building my own blog) as the basis for my examples, and I’ll keep doing that for this post. Here’s what we have so far (I’m using ASP.NET MVC):
IPostRepository repo;
public PostController(IPostRepository postRepository){
repo=postRepository;
}
public ActionResult Index(){
var posts=repo.GetPosts();
return View(posts);
}
and I’ve wired up IoC using StructureMap to inject my IPostRepository for me:
public class BlogRegistry : Registry {
protected override void configure() {
ForRequestedType<IPostRepository>()
.TheDefaultIsConcreteType<SQLPostRepository>();
}
}
Many people have asked me: “I don’t see how you’re using IoC here – you’re not calling for the Container anywhere” – and that’s true. I left that part out as I didn’t want to derail the point on the innards of ASP.NET MVC. But I will address it here.
Wiring IoC to MVC
What you’re about to see is why so many people like ASP.NET MVC: it’s modular and clean in terms of its parts. Yes you can do this with Web Forms – most likely by using inheritance with System.Web.Page – but there are issues with doing it this way since inheritance is another form of coupling (tying your classes to an architecture or implementation).
What would be much better is to “shiv” something in – use some Code Fu to work in this change without a lot of pain. And you can do just this with a thing called a ControllerFactory – which is a core piece of ASP.NET MVC. They have a single responsibility which is to find and create the Controller that your route is asking for.
If a user comes to my app and requests “http://myblog/post/index” – routing will dissect this and see that I want to use the PostController and execute the Index action – all good. It’s all magic and “just works” – but the good news is that Phil and team have left back doors in the framework just about everywhere, so we can shimmy-shake it as we need to (another reason why ASP.NET MVC is fun).
What I really need to do is to intercept the process – right where the Controller is created – and have my IoC create the Controller instead of the core bits. Doing this will allow me to set all kinds of fun injection rules and have at my Controllers as I feel.
To do this, I need to create my own ControllerFactory – the thing that creates the Controllers to service the request – and design the process myself:
public class HanaControllerFactory:DefaultControllerFactory {
protected override IController GetControllerInstance(Type controllerType) {
IController result = null;
if (controllerType != null) {
result = StructureMap.ObjectFactory.GetInstance(controllerType)
as Controller;
}
return result;
}
}
That’s all there is to it :). You might have been expecting a lot more here – but as I mention above: Phil and team gave the ControllerFactory a Single Reponsibility (following some principle that I can’t recall the name of) – making it easy to implement/override (love you Phil!).
Now that I have my ControllerFactory created, I crack open the Global.asax and wire it up:
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
StructureMapConfiguration.AddRegistry(new BlogRegistry());
ControllerBuilder.Current.
SetControllerFactory(new HanaControllerFactory());
}
That’s all there is to it. Now all of my Controllers are “wired” with Inversion of Control, and I can use it from this point on.
Greasing The Wheels With IoC
In the first part of my IoC post I had a comment from Dan A:
In this simplified example above you switched from 3 lines of easily understandable code to something that requires code in the global.asax, another couple classes, and an interface. The end result contains an extra line or two of code, but now the whole thing is “reusable” and can be unit tested. I happen to agree with Joel’s quote which you openly mocked… it *is* more convoluted. It *is* harder to read and grok. And this was an overly simple example… I’m sure it gets more convoluted with large projects.
Fair enough – reading the StructureMap stuff isn’t so easy – but please consider that as far as my application goes, I’ve added 1 dll and about 18 lines of code. What has it bought me? Check it out…
Let’s focus on a very real scenario – growth of the application via shifting business needs. Let’s say that I’m building this blog app for my work and so far it’s working as intended – it adds posts, displays posts, etc. My boss comes in and tells me that they want to move to a more CMS-type of system with version control and some rules around publishing. They also want to have the notion of pages as well as posts.
Normally you might throw up your hands and say “REWRITE!” – buy you don’t need to. Breaking the requests down, what’s needed is a more formalized way of working with the data – a business layer if you will. In there we’ll do all kinds of fun things like version our posts and so on:
public class CMSService(IPostRepository repo): ICMSService{
public IList<Post> GetPosts(){
//...
}
public void SavePost(Post post){
//..
}
//other stuff
}
(You’ll have to use your imagination a bit here for more “CMS-y” stuff… and yes I recognize that you’d probably have a few more classes than this. Work with me here people…)
Since I want to test my CMSService class I’ve used the Dependency Injection Pattern once again (passing IPostRepository in the constructor), and I’ve also created an interface called ICMSService so I can mock this thing as required.
Now I need to refactor my PostController to use the CMSService:
ICMSService _service;
public PostController(ICMSService service){
_service=service;
}
public ActionResult Index(){
var posts=_service.GetPosts();
return View(posts);
}
… and I have to deal with the Container stuff.
You might think “aha! THIS is where Conery eats his hat – this is going to be FUGLY”! Keep in mind that all I’ve done to this point is a bit of refactoring to my application – I haven’t touched the IoC stuff at all.
Hold on to your hats…
public class BlogRegistry : Registry {
protected override void configure() {
ForRequestedType<IPostRepository>()
.TheDefaultIsConcreteType<SQLPostRepository>();
ForRequestedType<ICMSService>()
.TheDefaultIsConcreteType<CMSService>();
}
}
Yes – that would be one line (well, one line broken in half to keep my page from getting too wide). And that one line does 2 things:
- It tells StructureMap “whenever you see ICMSService in a constructor – use CMSService” and
- It deals with injecting CMSService with IPostRepository *and* injecting the PostController with ICMSService.
That is why IoC is Good Time Fun – as your app grows, shuffling, refactoring, and tweaking your application is an order of magnitude easier.
More Examples
As the application grows I’ll doubtless have to add many things to it – Logging, ValidationEngine, EmailServices, AuthenticationServices – etc. Being a good Cool Kid, I make sure to interface each of them so I don’t take on coupling, and I add them to my IoC registry:
public class BlogRegistry : Registry {
protected override void configure() {
ForRequestedType<IPostRepository>()
.TheDefaultIsConcreteType<SQLPostRepository>();
ForRequestedType<ICMSService>()
.TheDefaultIsConcreteType<CMSService>();
ForRequestedType<IILogger>()
.TheDefaultIsConcreteType<NLogLogger>();
ForRequestedType<IEmailService>()
.TheDefaultIsConcreteType<SynchroEmailService>();
ForRequestedType<IAuthenticationService>()
.TheDefaultIsConcreteType<MSMembershipService>();
ForRequestedType<IValidationEngine>()
.TheDefaultIsConcreteType<XMLValidator>();
}
}
Now when I need any one of these things – I just ask for them where I need them - even in my Controller:
ICMSService _service;
ILogger _logger;
public PostController(ICMSService service, ILogger logger){
_service=service;
_logger=logger
}
public ActionResult Index(){
var posts=_service.GetPosts();
//log the posts
_logger.Info("IoC Rocks...");
return View(posts);
}
One thing to note: the IoC container handles the instantiation completely, so when I alter the constructor as I’ve done here, I don’t need to change the calling code anywhere else (except for tests).
I haven’t really even touched on the best parts yet :). Typically you’d want to have some level of logging in every part of your application – such as your AuthenticationService as well as your EmailService. Once again you don’t want to take dependencies in there (especially on a particular logging engine!) because you very well may reuse them later, or you may change your mind. I have an AuthenticationService and EmailService I use in just about every app I create – it’s what we do – we’re pack rats.
Can you imagine what my PostController would look like if I had to inject the logger into it, as well as into my services (that are also passed to the same constructor)? I’d offer a code sample but it makes my brain hurt just thinking about it. This is “Constructors Gone Wild” and it’s really, really ugly.
Instead – I’ve opted for IoC – which will inject “stuff” wherever it’s “injectable” – as long as it’s responsible for creating the object in the first place. Since I made my own ControllerFactory – everything else is buttah and IoC “knits” it all together.
Even More Examples
My project has been a success and my manager actually kissed me because I came in under budget and ahead of schedule (his beard is scratchy…). Now he throws me a curve ball and says “hey you know our site’s slowing down a bit – but only when people leave comments. I think we have an issue with sending out emails. With all of our users – that’s a lot of email all at once.”
Taking a look at my EmailService I see that “DOH!” – it’s the SynchroEmailService and YES – it’s trying to send emails synchronously (inline) to
n people when a page is submitted. Yikes! That should be asynchronous and put behind a “chron” – or a scheduled job.
I spend 3 hours writing up/testing another mailer (“AsynchroEmailService”) – one that sends the email messages to a queue and logs them using my ILogger. And now I have to implement this – how would you do it?
I get to do it in one line with IoC:
ForRequestedType<IEmailService>()
.TheDefaultIsConcreteType<ASynchroEmailService>();
It just doesn’t get easier than that.
But Wait, There’s More!
My boss and the lead engineer are looking over the code I wrote for the AsynchroEmailService and they like it, but the Lead Engineer has been reading his pattern books again and says
Can we do something with a little less memory pressure here?
Memory Pressure? ORLY? I try to convey that the cost of instantiation here is incredibly minimal – almost at the atomic level – but he insists on doing it right and “Can I use a Singleton”. Rather than argue – I say sure (have you ever had this discussion by chance?).
Have you ever tried to code a Singleton? It’s not very fun – in fact I’d say that most of us (me especially) are “doin it wrong”. Locks, threading, ick. Once again – IoC’s got my back:
ForRequestedType<IEmailService>()
.TheDefaultIsConcreteType<ASynchroEmailService>()
.CacheBy((InstanceScope.Singleton));
Not sure that could be any easier. I could also choose to cache by HttpContext, PerRequest, ThreadLocal, and “Hybrid” (which means, basically, the same as PerRequest but works better for testing). For now I choose “Singleton” to keep my Lead Engineer happy.
Summary
You can do most of these tricks with WebForms as well – but to be honest I’m not sure what the best way is. I’m fairly certain you could do it with inheriting a base class from your Page and then explicitly working with properties (read only):
public class MyPage:System.Web.Page{
public ICMSService CMSservice{
get{
return StructureMap.ObjectFactory.GetInstance<ICMSService>();
}
}
}
It’s a lot more manual, as you can see, but this *should* work (warning: I’ve never tried it).
I’m hoping that you’re beginning to see (if you haven’t already) that IoC *can be* a complicated thing, to be sure, but hey you work on computers and you’re already ahead of the curve :). If you think your application will grow (which most do), IoC can really become your best friend.
Really enjoying the posts, something to note - when you create your own ControllerFactory
"public class HanaControllerFactory:DefaultControllerFactory {" it's called HanaControllerFactory then when you hook it up you've called it "KonaControllerFactory()".
Just a little thing but might be confusing, especially since we're on the subject of IoC ;).
Cheers,
ChrisNTR
With regards to using containers with webforms, a better pattern is to use a presenter and request the presenter from the container in the base page, that way you only have to explicitly request one dependency in your page rather than deal with many. e.g.
public class PresenterBasePage : Page where T : IPresenter
{
private T _presenter;
public T Presenter
{
get
{
if( _presenter == null )
{
StructureMap.ObjectFactory.GetInstance();
}
return _presenter;
}
}
}
This can then be used via:
public class CreatePost : PresenterBasePage
{
...
}
public class PresenterBasePage[T] : Page where T : IPresenter
{
private T _presenter;
public T Presenter
{
get
{
if( _presenter == null )
{
StructureMap.ObjectFactory.GetInstance[T]();
}
return _presenter;
}
}
}
This can then be used via:
public class CreatePost : PresenterBasePage[ICreatePostPresenter]
{
…
}
1.) Automatically register all interfaces with their implementations when they are named the same (for example, IAccountRepository and AccountRepository), or
2.) Automatically register all interfaces with their implementations when there's only one implementation.
So when the application starts, it scans your references according to these rules, wires up your IoC container automatically, and you use your classes without any thought about setup! You just create your class, extract an interface, and it appears magically in your IoC container. No config.
Once you understand the patterns, everything Rob says about the benefits is, to my experience, correct, and moreover, it allows you to eliminate 80+% of the time normally spent using a debugger and/or launching the application. From a productivity standpoint, this is a key benefit for knowing how to use DI/IOC/Repository, etc.
The difficulty is getting to that understanding. It isn't really a matter of intelligence, but experience.
Unless I'm being thick (very possible - it is a Monday morning)...
public class CMSService(IPostRepository repo): ICMSRepository{
should read
public class CMSService(IPostRepository repo): ICMSService{
and this sentence needs changing to?
"Since I want to test my CMSService class I’ve used the Dependency Injection Pattern once again (passing IPostRepository in the constructor), and I’ve also created an interface called ICMSRepository so I can mock this thing as required."
Its very comforting as a junior developer to read articles published on blogs, find the bits that you understand and reassure yourself that you do understand what "everyone else" is doing. However a lot of these posts are potentially damaging if they are viewed as fact and "this is how you should do things".
You can see how bad practice (or even less good practice ;-)) can perpetuate, and and fill the hole left by lack of experience.
Then the people who have learnt (often the hard way, from their own experiences) and have seen real tangible benefits in certain approaches/methods, come on forums/blogs and sound a little bit like they're religious zealots who have "seen the light" and been converted.
This put people's backs up and back we go again around and around in a big vicious circle.
More at http://go.microsoft.com/fwlink/?LinkID=157066.
public class MySiteRegistry : Registry
{
public MySiteRegistry()
{
Scan(x =>
{
x.TheCallingAssembly();
x.WithDefaultConventions();
});
}
}
In an Action/Method, instead of creating a new instance of a class, you can just call the one that already exists as a field, leading to less code in each method.
So when you come back to maintain the application and look at a given Method, you don't have to read a whole load of instantiations, you can just see that something called "logger" or "postRepository" is being asked to do something.
If it's relevant at that point to dig deeper into how those objects actually perform their functions you can, if however you're only interested in the flow of that Method (or the logic contained within that Method) you can ignore the inner workings of the "logger" or the "postRepository". In fact, another member of your team entirely could write the implementation for "postRepository" and you might never need to understand how it works.
So I guess your concern is not about passing dependencies into the object via the constructor, but the idea of using a framework like Structuremap to do the injection for you?
You as the lead programmer are in a great spot to show them some good things.
As far as readability goes: Green Eggs and Ham. Just try it try it and you will see :). Seriously - just like your Controllers it really doesn't matter what object is passed in - it's an interface.
It seems like the DI part is more to your dislike am I right? Either way - give it a whirl and I promise you'll dig it :). So will your team - and always challenge others to broaden their reach.
public class CMSService:ICMSService {
public CMSService(IPostRepository) { ...
Any pros/cons using code vs config to wire up the registry?
I did however run into a few issues (that were fairly easy to resolve):
I used the default AccountController and all of a sudden I had to wire up default types to be instantiated for these because of the constructors. Your example
ForRequestedType().TheDefaultIsConcreteType();
ForRequestedType().TheDefaultIsConcreteType();
ForRequestedType().TheDefault.Is.Object(Membership.Provider);
It seems your examples are based on an earlier version of StructureMap because StructureMapConfiguration is now obsolete.
I wouldn't mind though, keep them coming!