Common Sevice Locator
One of the nice things about Dependency Injection is that it can really help write a more flexible, modular application. These days, it seems that there is no shortage of choice in the .NET community when it comes to IoC frameworks:
- StructureMap
- Castle Windsor
- Ninject
- Autofac
- Unity
- Spring.NET
- And probably others that I'm missing.
1: public class DefaultStructureMapRegistry: Registry
2: {
3: public DefaultStructureMapRegistry()
4: {
5: ForRequestedType<IDb4oConfiguration>()
6: .TheDefaultIsConcreteType<SimpleDb4oConfiguration>();
7: }
8: }In a nutshell this says that every time StructureMap is asked to provided an object of type IDb4oConfiguration, it should instantiate a SimpleDb4oConfiguration object and return that. So, to get an instance of IDb4oConfiguration with StructureMap, I would do something like this:
1: var db4oConfig = ObjectFactory.GetInstance<IDb4oConfiguration>();Pretty simple, but it does kind of tightly couples me to StructureMap. If I need/feel like/am forced at gunpoint to change my IoC container to something that is Not StructureMap, you can bet that there will be much wailing and gnashing of teeth on my part as I hunt through my code to make these changes. Now enter the Common Service Locator. First, let's take a peek at some interfaces for CSL. First an interface:
1: namespace Microsoft.Practices.ServiceLocation
2: {
3: public interface IServiceLocator : IServiceProvider
4: {
5: object GetInstance(Type serviceType);
6: object GetInstance(Type serviceType, string key);
7: IEnumerable<object> GetAllInstances(Type serviceType);
8: TService GetInstance<TService>();
9: TService GetInstance<TService>(string key);
10: IEnumerable<TService> GetAllInstances<TService>();
11: }
12: }The IServiceLocator is an interface that your application will use when it requests something from your IoC container. Another thing that CSL provides is a static class that your application would use to use a current IServiceLocator to request services. That static class looks something like:
1: namespace Microsoft.Practices.ServiceLocation
2: {
3: public static class ServiceLocator
4: {
5: public static IServiceLocator Current { get; }
6: public static void SetLocatorProvider(ServiceLocatorProvider newProvider) {};
7: }
8: }So, now lets see how we would request the default implementation of the IDb4oConfiguration service using CSL. First, we would initialize CSL:
1: var registry = new DefaultStructureMapRegistry();
2: var container = new global::StructureMap.Container(registry);
3: var smServiceLocator = new StructureMapServiceLocator(container);
4: ServiceLocator.SetLocatorProvider(() => smServiceLocator );What is going on here? Allow me to provide a quick line by line explanation: Line 1 we instantiate a new StructureMap registry. We then feed that registry to a StructureMap container in line 2. With line 3, we see that StructureMap container is then fed to the StructureMapServiceLocator, which is the SM adapter for the Common Service Locator. Finally, with line 4 we provide a lambda that CSL will use to fulfill future requests for services. Now when our application wants to get an instance of IDb4oConfiguration it just politely asks CSL:
1: var db4oConfig = ServiceLocator.Current.GetService<IDb4oConfiguration>();Pretty simple and clean, eh? Now, when radical group the Foundation for Unity as the Dominate IoC Container sneaks into your cube and forces you at the point of a nerf gun to switch to Unity, you can do so with minimal disruption to your application. With a properly layered application, it would be as simple as coding a new UnityConfiguration layer and then using that instead of your StructureMapConfiguration layer on application startup. Now, granted this is pretty trivialized example. There are other ways to solve this problem, but CSL does seem to take are of the grunt work for you so that you can just get going with things.