Friday, December 4, 2009

Putting it together series – Part 2: IoC Container (Castle.Windsor and Fluent Castle)

Introduction

Whenever I need to put even a simple application together there’s always a whole bunch of infrastructure I need to put in place. For a WPF application this can include:

  • IoC Container
  • Testing Framework
  • MVP / MVVM Framework
  • Logging
  • ORM

This was recently the case when putting together the PDC downloader.  So I’m going to put a quick post around each of these areas. Besides the UI Framework everything else should convert over to ASP.NET without too much difficulty.

There is going no be no real example as I don’t want to complicate the solutions. Each solution will contain the minimum code to get the relevant area up and running, with the smallest example I can give. Once you have things going, Google will provide more advanced help.

Part 2: IoC Container

So we have our testing framework in place, the next step is to put in our IoC Container so we can dependency inject domain services in our business objects, or UI services into our UI objects. If you want to know more about what IoC and DI is there is a host of information explaining the technology and how to use it. This guide will be around setting up one of my preferred containers and integrating it with the tests we already have.

The container in question is Castle.Windsor which IMO is one of the more powerful and configurable containers available. It has good performance and is easily extensible offering some powerful extension points. It is also one of the more popular containers offering great documentation (both on the official site and by 3rd party bloggers), as well as lots of adaptors to plug it into various other frameworks.

So let’s get started, we really want to use the latest code and the easiest place to get it is here:

http://hornget.net/

Clicking on IoC gives us access to the latest build of the Castle.Windsor trunk, exactly what we need! We’ll need to set up the following referenced assemblies in our solution:

image

Now we already have an entity from the last example called SillyPoco, and a service which its dependent on called ISillyService. So what we want to do is create a concrete SillyServiceImpl and inject that into our SillyPoco object.

We’ll start with a test:

[TestMethod]
public void ShouldInjectSillyServiceIntoMyObject()
{
SillyPoco sillyPOCO = null;
bool result = false;

Story.WithScenario("a plain old nbehave spec")
.Given("an object we are going to test",
() => sillyPOCO = FrameworkHelper.New<SillyPoco>())
.When("we call a method on the object",
() => result = sillyPOCO.TalkToService())
.Then("the service should have been called",
() => Assert.IsTrue(result));
}

So we’ve made the service contract return a boolean, and we are checking that it should return true. We’ve also got a static helped method called FrameworkHelper.New<T> which will create our object that needs to have dependencies injected. Here’s how it looks:

public static T New<T>()
{
return Container.Resolve<T>();
}

That looks good, this is how we will ask the container for instances of our dependency injected objects. This is a simple implementation of the ServiceLocator, for something more advanced I would recommend: CommonServiceLocator which Castle.Windsor is compatible with.

So we have a method to get our objects, let’s setup the container. Since we are in a test project we should probably refactor the setup into a test base class to be shared throughout the tests.

protected override void Establish_context()
{
base.Establish_context();

WindsorContainer windsorContainer = new WindsorContainer();
windsorContainer.Register(
Component.For<ISillyService>().ImplementedBy<SillyService>(),
Component.For<SillyPoco>().ImplementedBy<SillyPoco>());

FrameworkHelper.Initialize(windsorContainer);
}

We've now set up our container. Essentially what we’ve told it is:

  • If anyone asks you for a ISillyService, return a new instance of SillyService
  • If anyone asks you for a SillyPoco, return a new SillyPoco and insert a new instance of ISillyService into it.

So now when we run our test it goes green! Now we have our container set up, it will start getting much easier to put our application together!

You can find the code for the examples at the bitbucket repo:

http://bitbucket.org/naeem.khedarun/projectpit/overview/

The samples for this part are under a tag called parttwo. Simply get the repository and update to that tag.

No comments:

Post a Comment