Lifetime Management

Dec 4, 2009 at 5:44 PM

Is it possible to use different lifetime managers?  I don't see any methods off of IServiceLocator that allow me to set one, which I'm used to doing in Unity:

myContainer.RegisterType<IMyObject, MySingletonObject>(new ContainerControlledLifetimeManager());

Am I missing something?

Coordinator
Dec 14, 2009 at 6:20 PM

Since Turbine is IoC container agnostic and each IoC container does things differently when it comes to type registration, this feature is not included.  However, you can create your own IoC container and pass it to the SL facade which Turbine uses.

 

private static IUnityContainer CreateContainer(){
   var container = new UnityContainer();

   // Add your own type registration for your "domain" services

  return container;
}


static MvcApplication(){
  var mainContainer = CreateContainer();
 
  // Set the container with all the custom stuff here 
  ServiceLocatorManager.SetLocatorProvider(
     () => new UnityServiceLocator(mainContainer));
}

 

 

Sep 13, 2010 at 6:06 PM

Or I guess you can cast the IServiceLocator as your favorite IoC container (i.e. IKernel in Ninject).

@jglozano: Would it work?
I know it kind of defeats the purpose (well not completely), but knowing the limitations of MVC Turbine I don't mind tying myself (i.e. inside auto-registrations or blades) to a specific container implementation to gain some of its more advanced features.
There's just so much more to benefit from MVC Turbine as a smart layer between my app and my container.

I sometimes get an impression that people value "container agnosticism" (is this the right word?) too much because it is immediately visible in projects like MVC Turbine. However I'd bet that this was never a primary design goal but simply result of common sense to make the project usable for more people.

Coordinator
Sep 13, 2010 at 6:27 PM

@thoughtcriminal -- you're 100% correct! The sole reason why Turbine is 'container agnostic' is because of adoption; heck even some containers add that syntactic sugar to themselves by tying themselves to an HttpContext (indirectly).  It was never the intent for Turbine to replace your IoC container or get in your way from using it.  The features there are for you to leverage based on your context, and as we all know that varies :)

For 'best' practices on using your favorite container with turbine you can do the following:

1) Initialize the container manually and 'wire up' pieces it cares to know about -- for example, if you use Ninject use modules to wire up all the pieces you care about the most, then add those modules to the container and pass that to Turbine.

Note: the whole purpose of blades and IServiceRegistration is to allow you to have components that are reusable, not to do all the wiring up for you -- although it provides that functionality, you can can scale up (more regs to underlying container) or down (keep all registrations as is) based on your needs.

2) I've created a simple extension method for IServiceLocator called GetUnderlyingContainer<TContainer>() that provides casting for the underlying container that is used under IServiceLocator. So, again, if you're using Ninject you can do this:

// Get Ninject container
var kernel = locator.GetUnderlyingContainer<IKernel>();

// now we can use it
kernel.Bind<IFoo>.ImplementedBy<Foo>();

Sep 13, 2010 at 6:28 PM
Edited Sep 13, 2010 at 6:33 PM

You may not mind tying yourself to a specific container implementation, but once you cross that IoC-agnostic line line you force anybody who might want to use your work into your IoC choice.  Forcing someone to take on *your* preferred IoC container as a dependency in order to use your work is a pretty hefty price that nobody is going to want to pay.

I think the decision to go container-specific depends on the situation.  I see two:

1.)  Projects that are specific to a solution.  For example, the actual MVC application or any sub-projects associated with it.  Since I have to go container-specific there by telling MVC Turbine which container I want to use, I don't have a problem with sticking with that choice throughout the entire project.  I'll avoid container-specific code if I can, but for examples above like Unity's lifetime managers, I won't fight it.

2.)  Projects that are generic to any solution.  For example, projects like MvcTurbine.FluentValidation, which hooks up a standard FluentValidation factory to the model validation.  Since the target of that library is potentially *all* MVC users, no matter what IoC container they use, it would be ridiculous for me to say "I like StructureMap, so if you have to use StructureMap in order to incorporate this functionality."  That's where things like the service locator abstraction really become powerful.  I can create functionality for any MVC application, no matter what IoC container you want to use, and all you have to do is add a reference to my dll."

Given (2), I don't think people value "container agnosticism" enough.  

 

 

Sep 13, 2010 at 6:58 PM

@darrencauthon:
I completely agree with you, I just did not make myself clear. What I had in mind was exactly what you described in 1).

I thought of the top level project (MVC, WCF,  WinForms, not libraries) of your solution which typically should be the only place where your container is "visible" and immediately pushed down as a founding block of your app. After all container is just a glue (and btw. MVC Turbine makes a pretty good job of hiding it :)

 

Sep 13, 2010 at 7:03 PM

@jglozano:
Thanks for reply and pointing out the extension method.
Can you please explain why you are using PropertyInfo instead of using the as operator. I'm sure I'm missing something here :)

Coordinator
Sep 13, 2010 at 8:08 PM

@thoughtcriminal -

An IServiceLocator implementation is not necessarily the container, it is a facade for the calls to the underlying methods to the container. I opted to go with this pattern instead of creating a sub-type and then implementing the interface because of:

  1. Most CSL implementations out there are done this way -- I didn't want to confuse people :)
  2. Since each DI container does things differently, I figured it would make most sense to keep the mapping concern (turbine -> container, container -> turbine) in a simple (poco) class

Each CSL implementation has a Container property which is the underlying (specific) container (ie IKernel, IWindsorContainer, etc.), so using reflection on the  prop and returning the value was the easiest way to go about it without adding that method to IServiceLocator directly.

Does that make sense?

Sep 14, 2010 at 8:34 AM

@jglozano:

Oh yeah, this makes total sense, I must have confused things. Now that I looked again it is clear since the NinjectServiceLocator constructor stores the container in Container property.
Also it looks like a convention you made since it's not enforced.

 

Coordinator
Sep 14, 2010 at 3:22 PM

Yes, that's an indirect convention I applied to the containers -- trying to make things easier on implementers.