|Number of votes:||0|
Since I started to write this post Joel Abrahamsson has written a great introduction to what IoC is which rendered the beginning part of my post more or less redundant. So if you’re not familiar with terms like DI (dependency injection) and IoC (Inversion of Controll) I suggest you go there and read his post. Also I’m new to this so I may misuse some concepts and be slightly confused about others.
For this post lets assume we have this simple but oh so useless class:
Now some cool Alt.Net guy comes along and tells us that working directly against DataFactory is not a very good idea for many reasons. They will probably give you quite the talk about using HttpContext and working with WebForms too, but that’s beside the point.
Our friend new says that our class shouldn’t be responsible for finding it’s dependency to the DataFactory but rather being told about it. So let’s rewrite our class to do just that.
Our class now takes the class to use in its constructor (this is called constructor injection). The class can now be more easily be tested since we can either create our own class that implements the interface or simply mock it. Plus this loosely coupled code make you feel all warm on the inside.
Lets say that we want to call this class on our start page, like this:
That’s not too much of a hassle, but since we’re creating a whole site we discover that we want to send in that class every time we come across the IDataFactoryFacade interface, it gets a bit tedious. And if we ever wanted to change the concrete class we would have to find every usage of that class and change it which, while easy using a search and replace, feels kind of smelly.
StructureMap is an IoC (Inversion of Control) tool that solves this problem. Please note I’m using a slightly old version still (2.5.2) so the syntax (or rather the method names) has changed a bit in the newer versions.
We’re going to use StrucutreMap to configure our app to always EPiAbstractions.DataFactoryFacade.Instance whenever an interfaces of type EPiAbstractions.IDataFactoryFacade is requested. We’ll put this code in the Application_Start method in global.asax (after adding a reference to the StructureMap dll).
This code does exactly what it looks to do, it informs StructureMap to use EPiAbstractions.DataFactoryFacade.Instance whenever the type EPiAbstractions.IDataFactoryFacade is requested. So now we’re going to be asking StrucutreMap to give us the object we want and it will magically resolve all our dependencies for us.
Notice that we don’t have to inform the constructor of WriteChildrenToStartPageCountV2 which class to use for IDataFactoryFacade. What we’re doing here is using StructureMap and it’s ObjectFactory as a Service Locator to resolve the dependencies we might have.
Now if we ever wanted to change which concrete class to use we only have to change the code in one place.
While the above method works constantly calling ObjectFactory.GetInstance everytime we need IDataFactoryFacade is actually considered somewhat of an IoC anti-patterns. What you want is to have as few explicit calls to GetInstance as you can in your application.
Most (if not all) of the various IoC-containers have a concept of auto wiring, that is to figure out dependencies amongst classes. To exemplify this say that we have these classes
So SomeExecutor has a dependency to IValidator and the concrete class we’re using for that (setup using StrucutreMap config as above) has a dependency to the IRepository. What happens when we do a GetInstance<SomeExecutor> is that StructureMap will looking at the fattest constructor (as in most parameters) and notice that we want a class that implements IValidator. It checks it’s config and find that we want to use the class Validator. This class fattest constructor in its turn wants a IRepository and so on and so on. So even though we only ask for the class at the bottom of the dependency chain StrucutreMap resolves all the dependencies for us and that’s what auto wiring is all about.
If we had been using MVC instead of WebForms this would have been simple to use because you can control the creation of all controls using your own controller factory. WebForms unfortunately has no similar thing for controlling the creation of a System.Web.UI.Page so we have to use a little trick called Setter injections here. Bare with me.
First we create a simple front end interface that has a property of type IDataFactoryFacade. The class that implements the interface takes this dependency via constructor injection like this
We then create a class that inherits from EPiServers TemplatePage.
This class has a property of type IFrontEndService and on line 9 some magic happens. To understand what’s going on let’s take a look on how StructureMap is configured.
Line 3 – 7 is the same way of telling StructureMap which classes to use like we’ve seen above. Line 9 informs it that whenever it comes across a property of type Abstractions.IFrontEndService it should set it’s value. It will look in the config and see that it should set the property to the concrete class FrontEndService which in its turn has a dependency to IDataFactoryFacade. The ObjectFactory.BuildUp(this); (line 9 in the code for TemplatePage) is the line that will activate the setting of the properties setup using SetAllProperties.
Now let’s change our code on the start page to inherit from this TemplatePage instead of EPiServers. We now have access to a FrontEndService property which in turn has a property for our DataFactoryFacade.
As you notice here I’m still passing in the DataFactoryFacade property to the class WriteChildrenToStartPageCountV2. This is because this class isn’t automatically wired up because we haven’t told StructureMap how and where to do that. But I’m quite happy to pass the property from the FrontEndService to the class since that property in it self is only declared and setup in one place.
It would be quite possible to extract an IWriteChildrenToStartPageCount interface from our concrete class and use that instead of our front end service approach. But since I have a feeling that I’m going to be using the DataFactoryFacade all over the application it can be nice to have it setup on the page that all EPiServer pages inherit from. It’s also quite likely that we’ll be adding other dependencies that’s nice to have available, some ILogger for instance.
The next step is to remove the dependency to HttpContext (since this is null outside of a web-context) in the Write method of the WriteChildrenToStartPageCountV2 but this is left as an exercise for the reader. ^^