Changing registered services at runtime in EPiServer 7.5
The new Inversion of Control pattern introduced with EPiServer 7 is, in my opinion, one of the best new features of EPiServer CMS. Anywhere in your application you can simply call the ServiceLocator and GetInstance <ISomeInterface>() and it will return the concrete implementation of your choosing of that interface.
However, in the EPiServer world this is still kind of new and I’ve seen several epi-projects where the concept of IoC is still largely misunderstood. But this is not a post about IoC as such, but if you’re interested here’s an introduction to StructureMap, it’s a pretty old post but still interesting.
I was working in a project recently where we created a couple of concrete implementations for cache handling. A CacheManager and a NullCacheManager, the CacheManager utilized the HttpRuntime.Cache in the background, the NullCacheManager simply cached nothing as one would expect. They both implement the ICacheManager interface, shown highly simplified below.
This was all good and we could now easily decouple our design using code looking something like this.
This is great and gives us a very loosely coupled design. We could easily create a new concrete type of ICacheManager such as SqlCacheManager or FileSystemCacheManager and switch between the implementations using a ConfigureableModule, something like this:
We could also have different concrete implementations for different environments by using profiles, like this:
But wouldn’t it be pretty cool if we could switch the implementation at runtime? Turns out it’s not too difficult to achieve… Lets create an admin plugin where an administrator can choose which implementation of ICacheManager should currently be used by the site.
We start out by creating a simple plugin:
Remember that we need to add this nonsense to the episerver.shell part of our web.config as well for our module to be picked up:
Also please note that I’ve added an authorization attribute to the controller to make sure noone but an administrator stumbles upon it.
Add an empty index.cshtml view for now and type something awesome in it. Compile and run and make sure your plugin appears in the admin config menu.
Allright, next lets create a model for our view.
Simple, all our plugin will need is a list of the available cachemanagers and a string representing the currently selected one. Ok, lets flesh out our view next.
Now we have a model and a view, all that’s left is to add some code to our controller:
There are a few interesting points in the code above. Lets first consider GetViewModel() method. We simply get the currently active concrete implementation and then loop through all instances of ICacheManager that is currently registered in our IoC container. This brings us to an important point, allimplementations of ICacheManager must have been registered in our container or they wont be returned by the GetAllInstances method. This could be done in simple fashion by using the AddAllTypesOf<ICacheManager> when we configure our container. Something like this:
Next lets have a look at the post method. This method looks kinda peculiar, what’s all this ejecting and removing stuff? It turns out that we can’t really just change which configured cachemanager to use with For.Use because that would add another instance of the same type and not replace the existing one, and that’s why we first need to eject the model of the selected type and then re-configure it.
And that should be it! We now have a working admin plugin that lets us change fundamental inner workings of our application at runtime. We could substitute ICacheManager for IContentRepository and radically change how we fetch our content, we could substitute it for IContentRenderer and add functionality such a detailed logging to the rendering of our content… There’s no end to the possibilities!
But, as we’ve learned from modern classics such as the bible and the amazing spiderman: