MvcTurbine.Laziness, and Leveraging a CSL

MvcTurbineLazy-loading, or waiting to instantiate your object or execute a query until the very moment where it’s required, is pretty important for a well-performing application.  By waiting until the last possible moment to execute a command, you give yourself the freedom to alter, limit, or eliminate all-together code that would have otherwise been executed.

This goes double for applications built on SOLID principles, especially the Single Responsibility Principle and Dependency Inversion Principle.  These types of applications tend to have many small classes that do one thing and that are isolated from the code in other classes.  It’s very possible for one class to return results and another class determine whether those results are necessary.  It’s also possible for a class to have a dependency on another class that is expensive to instantiate.  Without an idea like lazy-loading, these situations could force you to couple bits of code that would normally be kept apart.

I was in one of these situations recently in an ASP.Net MVC application with MVC Turbine.  I had a route with a route constraint that had a dependency on a repository.  If a specific part of the URL matched an item in the repository, the route was considered valid.  The issue I had was that the routes were being built before my caching “blade” was run, so the route constraint was instantiated with a repository tied to my database instead of a repository tied to the cache.  What should I do?  Bring in my IoC container as a dependency to the route constraint?  Should I alter MVC Turbine to make my caching blade to run before the routing blade?  Should I write a special lazy loader for this situation?

In every time I’ve been in this situation, I’ve gone with the last option.  It’s pretty easy:

public class RepositoryLazyLoader {

   private IServiceLocator locator;

   public RepositoryLazyLoader(IServiceLocator locator){
      this.locator = locator;
   }

   public IRepository GetRepository() {
      return locator.Resolve<IRepository>();
   }

}

This lazy loader is basically a wrapper around my IoC container.  It seems like I’ve had to write one or two of these in every project, so I had an idea:  Why not write this one more time and never write it again?

MvcTurbine.Laziness

Since I use MVC Turbine on every ASP.Net MVC application I write, I decided to write a “blade” (which is essentially a module you can plug into your MVC app) that would handle creating lazy loaders.  Instead of writing a lazy loader when I need one, I can just instantiate an ILazy<T> from my IoC container.  The ILazy<T> has one property, Value, that will return the value from the IoC container.  The value will *not* be instantiated until then, so I can change a constructor like this:

public SuperConstraint(IRepository repository) { // IRepository will be instantiated right NOW

to:

public SuperConstraint(ILazy<IRepository> lazyRepository) { // IRepository will be instantiated LATER

In order to use this, here’s what you have to do:

1.) Use MVC Turbine.
1.) Add a reference to MvcTurbine.Laziness.dll .
2.) Add a reference to MvcTurbine.Laziness.X.dll, where X is either Unity, StructureMap, Ninject, or Windsor.

That’s all. Just by adding references to these dlls, MVC Turbine will suck them into the application startup and add a registration for ILazy<> to your IoC. The only work I’ve done is to figure out how to register ILazy<> into each of those containers (which can be seen here for Unity,StructureMapNinject, or Windsor).  Not much there.

Leveraging a CSL

MVC Turbine comes with a common service locator that serves as an abstraction on top of all of the IoC containers.  It’s similar to the Common Service Locator you can find on Codeplex, except that MVC Turbine adds the ability to register mappings as well as resolve them.  If you stick with the standard features that MVC Turbine’s service provider offers, you can actually swap your IoC container without any impact on your MVC application.  Let me repeat that:  You can swap your IoC container without any impact on your MVC application. So with one line of code, you can swap Unity with StructureMap, or StructureMap with Unity, or with Ninject, or with Castle Windsor.  Wow, right?

“Big deal,” you say?  You know how to use your IoC-container-of-choice and you’ll never want to switch?  That’s how I felt a while ago.  I cut my DI teeth on Unity.  I know it.  I know how to handle configuration, lifetime management, interception, or anything else I could imagine wanting out of an IoC container.  All of my projects had direct references to Unity, everything worked, and I thought I was cool.  Then I hit an issue or two with Unity, including a memory leak in the disposal of child containers.  The issues were all worked out in time, but when I was in the middle of them it was pretty scary.  I wrote a huge application that was glued to my IoC container, to the point where I was literally stuck with it.  What if the issues couldn’t get worked out?  What if I *had* to replace Unity?  I could do it, but it definitely wouldn’t be a one-line change.

“But Unity is stinky and my IoC container issue works just fine, I’ll never have to swap it out.”  That’s great, but I think it’s still a bad practice to tie any third-party library directly into your application.  Your classes should depend on abstractions, not implementations, and this is true even with the class that’s responsible for mapping your abstractions to your implementations.  I’ve found, through much experience and pain, that when you tie yourself to anybody else, you’ll go down with them.  Adding one simple layer of abstraction will protect you and will keep your code focused on what you want instead of what they give you.  That’s what a CSL like the that comes with MVC Turbine will provide you.

Think about it this way:  I wanted to provide this ILazy<T> feature in my application.  If I were touching my IoC container directly, this is the point where I’d sink even deeper into it.  I’d write code that could only work with my IoC container, making yet another dependency on a third-party.  The next feature I write will probably be the same, as will the next.  I’m definitely on the wrong path.  But if I write a solution that’s meant to be IoC-agnostic, I’m covered and I’m on the right path.

If you want a better example of this, look at the MVC Turbine framework itself.  It lets you inject IoC into your ASP.NET MVC and MVC2 app, yet it doesn’t tie you to a specific IoC container.  This makes it possible to add this ILazy<T> feature, a Fluent Validation plugin, or any number of things (I’m working on some new ideas) that couldn’t be done if MVC Turbine picked one IoC container.

One Final Point

I know that bringing in an ILazy<T> as a dependency might be the wrong place to implement the “laziness.”  However, sometimes we’re put in less-than-ideal situations (like this routing example), and in those places I want to go with the simplest, testable solution.  I’ll strongly recommend that you NOT throw ILazy<T> dependencies all over your application.

Get MvcTurbine.Laziness here.

Tags: , ,

Leave a Reply