Feeds:
Posts
Comments

Archive for February, 2008

Unity Project

Speaking about DI/IoC, Microsoft Patterns & Practices has just released an MSPL licensed DI container in the project Unity.  I must say, I’m disappointed.

Here’s a list of things I think Unity did wrong.

  1. It’s a P&P project, and not part of the BCL.  I’m not sure we need a full DI container in the BCL, but I do believe a lot of the interfaces should be there.
  2. They call this a "lightweight" container, but it contains two assemblies.  Doesn’t sound too light weight to me.  I haven’t fully looked into this yet, and it’s possible one of the assemblies provides optional features layered on a basic container, in which case I’d have to retract what I just said in this point ;).
  3. The interfaces are designed incorrectly.  There’s basically one interface, IUnityContainer, that’s the driving interface.  Like mentioned, I’d prefer this in the BCL, with a more generic name, such as IObjectContainer.  Further, this should be split into two interfaces: the APIs to resolve instances should be separated from the APIs to configure a container, such as is done with IServiceProvider and IContainer in the BCL.
  4. Types are resolved through reflection.  At the basic level the container should be operating on "factory delegates" registered with the container.  This is the most flexible design, and also provides the best performance.  The reflective stuff can be built on top of this.  I’d layer it, so if you don’t need it you don’t have to include it, but I wouldn’t argue to strongly if the container (and interfaces) provided both out of the box.  The fact that the factory delegate isn’t present in the API at all, though, is a mistake.  Just as an example, this container doesn’t provide support for per-thread scope, you only have Singleton (in two varieties… one where the user creates the instance and one where the container creates the instance) and per-call.  There’s absolutely no way to change this, short of changing the container implementation.  If we had delegate factory registration, you wouldn’t have this problem.
  5. There’s still a lot of complexity here.  I want a lighter weight solution.

Over all, it’s not a bad library, but it doesn’t deliver what I believe we need.

Read Full Post »

OK, in my last post I promised to show you how to use the ServiceContainer.  I’m going to steal code from the Autofac home page, and rewrite it using ServiceContainer.

IServiceContainer container = new ServiceContainer();

container.AddService(typeof(IEngine),
   (c, t) => new Straight6TwinTurbo());

container.AddService(typeof(ICar),
   (c, t) => new Skyline(c.GetService(typeof(IEngine)), Color.Black));

ICar car = container.GetService(typeof(ICar));
car.DriveTo("Byron Bay");

Pretty darn similar.  Autofac uses a ContainerBuilder and a declarative coding style, but other than this they are very equivalent.  However, most containers allow you to specify the "scope", while the BCL ServiceContainer only provides Singleton scope, even when you supply a ServiceCreatorCallback, which is unfortunate.  So, although I’ll be using IServiceProvider, I won’t be able to use ServiceContainer, and may consider extending both IServiceProvider and IServiceContainer to account for generics and keyed access.

Read Full Post »

I recently wrote a rant on here about Dependency Injection and Inversion of Control containers.  This might leave you to believe I’m totally against IoC.  In fact, I’m not.  There is a time and a place for this pattern, I just feel that it’s overused, especially in designs where the only purpose it’s serving is to allow for unit testing.

However, right now I’ve got a use for it.  The details about why aren’t that relevant, so I’m not going to discuss it here.  However, my needs are isolated and still want to take a pragmatic approach to the usage.  I don’t expect to need runtime configuration, though I don’t want to strictly rule it out, either.  So, I’ve been researching the available IoC containers for the CLR.  Most of them seem to be sledgehammer solutions, when I need a claw hammer.  The one that seemed to come the closest to what I’d want is Autofac, but there’s a lot of features there that I don’t necessarily need either.  What I’d really like is to code to an extremely light weight interface, and provide a really simple default implementation, allowing for the ability to use any of the other containers if and/or when my needs grow.

Did you know the BCL contains such an interface?  More importantly, it provides a very simple container as well.  If you’ve done much in WPF, you’ve actually probably used the interface already.  What am I talking about?

IServiceProvider.

This simple interface provides a single method: object GetService(Type serviceType).  That’s it.  And that’s all you need to get services from an IoC container.  Oh, I also mentioned that the BCL provides a container as well.  There’s both an IServiceContainer interface and a ServiceContainer class.  This container also happens to be very similar to the container in Autofac, utilizing delegate callbacks as the mechanism for specifying how service instances should be retrieved.  This is very light weight, very fast, and very flexible.  I’ll give some examples on how to use this in a bit.  First, though, I’d like to discuss some "short comings" of these interfaces.

Jeremy Miller had a post recently, where he ask "Is it time to make IoC/DI tooling part of the BCL?"  Jeremy is a very sharp guy.  He created StructureMap, another one of the IoC containers available on the CLR.  I know he has to be familiar with these APIs, so it’s not readily obvious from the post what he thinks is actually lacking in the BCL.  However, some of the comments to this post do point out some of the problems I do see with the existing APIs.  First, these APIs were created prior to Generics, and as such they are not as typesafe as one would hope.  Second, they can retrieve services only by a Type key, while most of the other containers also allow you to use a key string in addition.  There’s a nice suggestion in the comments to extend the IServiceProvider interface with something along the lines of:

public interface IServiceLocator : IServiceProvider
{
   T GetService<T>();
   T GetService<T>(string key);
}

The problem with this is that IServiceContainer extends IServiceProvider, and you can’t change it.  Worse, ServiceContainer can’t be changed.  You could provide your own container APIs based on the IServiceLocator, but then at best we’re back into the Name Game (TM) for what to call them, so they don’t collide with the current ones.

Another possibility for the generic APIs would be to use an extension method.

public static class ServiceProviderExtensions
{
   public T GetService<T>(this IServiceProvider self)
   {
      return (T)self.GetService(typeof(T));
   }
}

This works, though I’d like to point out that FxCop/CodeAnalysis will generate a warning about using a method signature that requires an explicit type parameter (CA1004).  The MSDN documentation suggests you should never suppress this warning.  I’m not sure I can agree fully with the reasoning the documentation gives, i.e. the API is more complicated when you have to specify an explicit type parameter, especially in a circumstance like this.  So, I’d be tempted to suppress this and move on. However, I will point out that there is a consideration if you’re rolling your own APIs and you only provide an generic method like this:  utilizing the API using reflection is several magnitudes more difficult.  In this case, this is just an alternative API that simplifies code.  The non-generic API still exists, and can be used in those cases where the generic API is too complicated (i.e. in reflection).

However, no attempts to extend the interface is going to allow you to provide the GetService that takes a key.  If you simply must have that, then you must provide extended interfaces and your own container.  I’d actually consider doing that in what I’m working on, but I’d have to come up with names.

Well, I rambled enough that I’d better save the "how to use" discussion for another post.

Read Full Post »