Showing posts with label Dependency Injection. Show all posts
Showing posts with label Dependency Injection. Show all posts

Sunday, 13 April 2008

A basic IoC container for Silverlight

All the recent User Interfaces I have built have been developed using some kind of MVC approach - be it the good old MVP (Model/View/Presenter) pattern for WebForms applications, or the recently devised MVVM (Model/View/ViewModel) pattern for WPF.

Well I recently started work on a small "pet project" using Silverlight (let's just assume for those who know me that the aforementioned pet is a Horse) and some of my development seems to have been spent building shared components which could be used in other projects. For example, I have previously blogged about my Command Implementation for Silverlight which I am using in this project.

When building MVC applications, a key piece of the developer's strategy is the ability to abstract a class's dependencies into an external component which will resolve those dependencies at runtime into what is required by the application. This allows (for one thing) the developer to build each class without worrying too much about where that class obtains its dependencies from. Note that classes which resolve other class's dependencies at runtime (a technique known as Dependency Injection) are commonly known as Inversion of Control containers. I won't get into much more detail about this here and recommend reading this excellent MSDN article.

So, despite previous attempts to cross-compile the excellent Ninject IoC framework into Silverlight (see this blog post and comments) I failed to get it to run. The problem is that Silverlight implements a new security model, in which lots of framework methods (such as some of System.Reflection.Emit, and System.Threading.StackTrace) are not allowed to be executed from application code. Essentially, if you look in Reflector at the Silverlight libraries, anything marked with a [SecurityCritical] attribute will be inaccessible to any code you write. If you are interested, you can get more information about Silverlight's new security model here. Personally, I think it's a little overzealous, and I hope the restriction will be lifted somewhat as Silverlight's deployment mechanism matures - I'm not sure how it would work but I'd like to see shared libraries being built which are able to call into some of the code deemed critical. I guess that's not my call though!

Anyway, given that no container I could find out there would run on Silverlight, I set about writing my own IoC container to "free myself" from my dependencies, so to speak. I pushed my code into a small library I have named Silverstone. You can download the DLL here.

The container is implemented as a very simple static class - Silverstone.DI.IocContainer. What I am currently doing is just registering all my dependencies in the Startup method of my App.xaml.cs, as follows:

using Silverstone.DI;

public partial class App : Application
{
  public void Application_Startup(object sender, StartupEventArgs e)
  {
    // Register an instance of a concrete type MyClass against interface IMyInterface.
    // The instance will be passed to all constructors with parameter of type
    // IMyInterface and all settable properties of type IMyInterface.
    IocContainer.RegisterInstance<IMyInterface>(new MyClass());

    // Register a concrete type against an abstract type.  This means that a new
    // instance of the concrete type will be created every time the abstract type is
    // requested by either a constructor with parameter of type IMyInterface or a
    // settable property of type IMyInterface.
    IocContainer.RegisterForCreation<MyClass, IMyInterface>();
  }
}

That's pretty simple really! Note that you can only register the same abstract type (IMyInterface in this example) once.

When you wish to retrieve the implementation of any abstract type, it's just a simple call to Get<>();

  IocContainer.Get<IMyInterface>();

Assuming that MyClass had been registered against IMyInterface in the container, the above call would actually return an instance of MyClass. Otherwise it will return null.

That's all there is to it really! Of course, the container is iterative and will walk the tree of constructors and properties on all objects as it goes. So, for example, if MyClass has a constructor with a parameter of type IMyOtherInterface, that will be requested from the container when creating the instance of MyClass. This is where the power of a container comes in - when you don't have think about all the dependencies of the dependencies of your dependencies, you can think a lot more clearly!

If anyone starts using this stuff and has any feedback, please let me know. Alternatively you can take a look at the source code which is available on the Google Code site for the project.

Have a great day

Neil