IServiceLocator a step toward IoC container / Service locator detente

Today we launched an exciting project on CodePlex, namely the Common Service Locator library. What is it? It’s a shared interface that applications and frameworks can reference in order to leverage IoC containers / service location mechanisms without taking hard dependencies.


The dominoes all fell like this. It all started with Jeremy Miller’s post. This then spurred on Ayende to send an email to a bunch of folks including many of the leading IoC container authors including Chris Tavares who wrote Unity, and myself (no I haven’t written an IoC container yet :)) Next thing you know we’re all designing the new library over email over a period of several weeks.


You can read more on this at Chris’s post here.


If you download the library you’ll find the following interface.



namespace Microsoft.Practices.ServiceLocation
{
    public interface IServiceLocator : IServiceProvider
    {
        object GetInstance(Type serviceType);
        object GetInstance(Type serviceType, string key);
        IEnumerable<object> GetAllInstances(Type serviceType);
 
        TService GetInstance<TService>();
        TService GetInstance<TService>(string key);
        IEnumerable<TService> GetAllInstances<TService>();
    }
}

You’ll also find a static ServiceLocator class that exposes an ambient (current) container. This provides a convenient way for frameworks to grab access to the current locator. It allows you to provide a delegate which will get invoked to retrieve the current locator.



namespace Microsoft.Practices.ServiceLocation
{
    public static class ServiceLocator
    {
        private static ServiceLocatorProvider currentProvider;
 
        public static IServiceLocator Current
        {
            get { return currentProvider(); }
        }
 
        public static void SetLocatorProvider(ServiceLocatorProvider newProvider)
        {
            currentProvider = newProvider;
        }
    }
}

So how many people did it take to design such an API? Well let’s see eight (no this is not a bad joke). The beauty is that those people represent a collaborative design effort both within and external to Microsoft. Yes, we all reached an agreement!


In addition to the this interface, you’ll find several adapters for IoC containers available with more on the way. I’ll be adding one for MEF (which is a locator) to that list shortly.


Also you’ll find a suite of unit tests you can use to validate that an adapter meets the functional requirements of the locator interface. We can thank Oren for that contribution :)


Our hope is that this interface will encourage products and frameworks to start leveraging IoC / Service location now that we’re removing the need to depend hardly on a specific one. The community can make this hope a reality ;-)

This entry was posted in Common Service Locator, IOC. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Steve

    Great news. Can I make a request already? :)

    Please provide a good fluent API for programmatically adding objects/assemblies to the service locator.

  • Gavin

    What design consideration led to the development of yet another IoC? I really like castle Windsor … If you had to argue the differences in an MTV Style ‘Death Match’ what makes this one the best?

  • http://twitter.org/VirtueMe Benny Thomas

    aaaah, delegate, I have to learn to read the text and not only the code before commenting. :D

    I suggest that the name of currentProvider should be currentProviderDelegate to provide som intent of the member role in the code.

  • http://twitter.org/VirtueMe Benny Thomas

    It may be my lack of understandig. But isn’t currentProvider a static member and not a method?

    The () at the end of return currentProvider(); seems faulty to me.

  • http://siliconbea.ch Bruce Boughton

    At present ServiceLocator.Current throws a NullReferenceException if no service locator provider is set, which is a bit counter-intuitive. I couldn’t find any mention of this on the codeplex site.

  • http://www.codebetter.com/blogs/glenn.block/ Glenn Block

    @Bruce

    That was the reason we did it. Glad it is making more sense.

  • http://siliconbea.ch Bruce Boughton

    Glenn, the more I think about it, the more I’m coming round to the delegate :) Like Chris says it allows you to tell the ServiceLocator how to find the current container, rather than what the current container is. Useful.

  • http://www.codebetter.com/blogs/glenn.block/ Glenn Block

    @wekempf not sure that will meet the goals. Having a settable property means someone has to actively do it. The someone depends on different contexts like thread, etc. Having it be a delegate allows custom code to make the determination of what is needed at the time. It also removes threading contention that occurs if multiple try to update the prop at the same time.

  • http://adameb.blogspot.com/2008/10/decouple-your-service-locator-from-its.html Adam B

    Decouple your Service Locator from its IoC Container with IServiceLocator

  • http://www.tavaresstudios.com Chris Tavares

    The interface uses overloads instead of extension methods because, believe it or not, there are people still using VS 2005 and .NET 2.0.

    As for the delegate to retrieve the current container, the idea is that the “current container” may vary depending on the environment. You may have one per thread, one per asp.net request, etc. With a single settable property, you’re stuck. With a delegate, the application author can define what “current container” means with a lot more flexibility.

  • http://wekempf.spaces.live.com wekempf

    The third option would have been to just make the Current settable. Simpler design, with some interesting trade-offs.

    I’m also curious why the interface must have generic variants? Why not use extension methods? That just seems cleaner to me.

  • http://www.codebetter.com/blogs/glenn.block/ Glenn Block

    On the clunkiness…..we are open to suggestions. Just go vote…..

  • http://www.codebetter.com/blogs/glenn.block/ Glenn Block

    Benny, what specifically is the faultiness? The fact that it is a static dependency?

    We debated over whether or not to support the “Current” container idea. In the end if was decided we need it, beause ultmately apps that depend on this library, need a clear-cut thing they can depend on to give them the container.

  • http://www.codebetter.com/blogs/glenn.block/ Glenn Block

    Rob, good idea, go post it to the workitems. In this case we provide a base impl that calls all the overloads for you. It essentially accomplishes the same thing as when you implement your adapter, you have very few methods to override.

  • http://www.codebetter.com/blogs/glenn.block/ Glenn Block

    Casey, this library is intended for people who use IoC today, and people that don’t today, but will use it in the future.

    As far as using the container in more than one place, it depends on the complexity of the app. For example imagine I am using an IoC container in an order entry app. I might use the container at the top level to get me bunch of services, but then within the guts, I might need to instantiate an order screen that has it’s transient dependencies injected.

    Regardless even if it is in a single place, that single place would depend on a specific implementation, and with this library it doesn’t have to.

    Where it gets interesting is if I have a framework that uses a container, and my app uses a container. Instead of having 2 containers, I could now potentially have one that the app and framework can both talk to.

  • http://www.codebetter.com/blogs/glenn.block/ Glenn Block

    Bruce, the idea of the delegate was a simple way to plug in code which returns the ambient / current locator. The other way we could have done it was to have a specialized class with a single method that returns the locator.

    Is that what you would have preferred?

  • Ed McPadden

    This looks very close to the way services are located in CAB/SCSF through the workitem. I think this interface makes a lot of sense without excess complexity.

    Has any thought been given to chaining service locators together in a parent/child relationship (similar to what CAB does inside workitems). That way services could be specified at different levels and would allow services to be overridden at various points in the chain. In CAB/SCSF this allows default service implementations to be specified and then overridden in higher level modules and workitems.

    In any case, its great to see this kind of collaboration amongst the thought leaders in this area…THANKS!

    …Ed (@emcpadden)

  • http://www.bluespire.com Rob

    I’d like to make one suggestion. The following methods can all be made into extension methods:

    TService GetInstance();
    TService GetInstance
    (string key);
    IEnumerable
    GetAllInstances();

    Thus, the core interface will be smaller, but you will still be able to access the functionality just as easily as before.

  • http://siliconbea.ch Bruce Boughton

    Excellent! I have recently been working on an OAuth library which uses IoC to locate components (http://lab.madgex.com/oauth-net/). At the moment it is bound to Castle Windsor but I’m sure people will want to use their IoC of choice. Hopefully, this initiative will allow this.

    What is the thought behind registering service locators using delegates? That seems like a clunky syntax to have to expose to my library users.

  • http://devlicio.us/blogs/casey Casey

    A very interesting idea … I wonder how it will play out … how many apps using IoC have more than a single location with a concrete dependency on the container anyway?

    Some real world usage example of why this helps would be nice

    On the collaboration front – good going!!!!!

  • http://twitter.org/VirtueMe Benny Thomas

    public static IServiceLocator Current { get { return currentProvider(); } }

    Seems a bit faulty ;)