Showing posts with label Castle Windsor. Show all posts
Showing posts with label Castle Windsor. Show all posts

Monday, November 25, 2013

EasyNetQ’s Minimalist DI Container

I’ve been a long time fan of IoC (or DI) containers ever since I first discovered Castle Windsor back in 2007. I’ve used Windsor in every major project I’ve been involved in since then, and if you’d gone to a developer event in the late naughties, you may well have encountered me speaking about Windsor. Indeed, Seb Lambla had the cheek to call me ‘Windsor man’. I shall label him ‘Rest-a-man’ in revenge.

When I started working on EasyNetQ in 2011, I initially thought it would be a very simple lightweight wrapper around the RabbitMQ.Client library. The initial versions were very procedural, ‘just get it done’, script-ish code burps. But as it turned into a more serious library, I started to factor the different pieces into more SRPish classes using dependency injection. At this point I was doing poor-man’s dependency injection, with an initial piece of wire-up code in the RabbitHutch class.

As EasyNetQ started to gain some traction outside 15below, I began to get questions like, “how do I use a different serializer?” And “I don’t like your error handling strategy, how can I implement my own?” I was also starting to get quite bored of maintaining the ever-growing wire up code. The obvious solution was to introduce a DI container, but I was very reluctant to take a dependency on something like Windsor. Writing a library is a very different proposition than writing an application. Every dependency you introduce is a dependency that your user also has to take. Imagine you are a happily using AutoFac and suddenly Castle.Windsor appears in your code base, or even worse, you are an up-to-date Windsor user, but EasyNetQ insists on installing an old version of Windsor alongside. Nasty. Windsor is an amazing library, some of its capabilities are quite magical, but I didn’t need any of these advanced features in EasyNetQ. In fact I could be highly constrained in my DI container requirements:

  • I only needed singleton instances.
  • The lifetime of all DI provided components matches the lifetime of the main IBus interface.
  • I didn’t need the container to manage component disposal.
  • I didn’t need open generic type registration.
  • I was happy to explicitly register all my components, so I didn’t need convention based registration.
  • I only needed constructor injection.
  • I can guarantee that a component implementation will only have a single constructor.

With this highly simplified list of requirements, I realised that I could write a very simple DI container in just few lines of code (currently 113 as it turns out).

My super simple container only provides two registration methods. The first takes a service interface type and a instance creation function:

IServiceRegister Register<TService>(Func<IServiceProvider, TService> serviceCreator) where TService : class;

The second takes an instance type and an implementation type:

IServiceRegister Register<TService, TImplementation>()
where TService : class
where TImplementation : class, TService;

These are both defined in a IServiceRegister interface. There is also a single Resolve method in an IServiceProvider interface:

TService Resolve<TService>() where TService : class;

You can see all 113 lines of the implementation in the DefaultServiceProvider class. As you can see, it’s not at all complicated, just three dictionaries, one holding the list of service factories, another holding a list of registrations, and the last a list of instances. Each registration simply adds a record to the instances dictionary. When Resolve is called, a bit of reflection looks up the implementation type’s constructor and invokes it, recursively calling resolve for each constructor argument. If the service is provided by a service factory, it is invoked instead of the constructor.

I didn’t have any worries about performance. The registration and resolve code is only called once when a new instance of IBus is created. EasyNetQ is designed to be instantiated at application start-up and for that instance to last the lifetime of the application. For 90% of applications, you should only need a single IBus instance.

EasyNetQ’s component are registered in a ComponentRegistration class. This provides an opportunity for the user to register services ahead of the default registration, and since the first to register wins, it provides an easy path for users to replace default services implementations with their own. Here’s an example of replacing EasyNetQ’s default console logger with a custom logger:

var logger = new MyLogger();
var bus = RabbitHutch.CreateBus(connectionString, x => x.Register<IEasyNetQLogger>(_ => logger));

You can replace pretty much any of the internals of EasyNetQ in this way: the logger, the serializer, the error handling strategy, the dispatcher threading model … Check out the ComponentRegistration class to see the whole list.

Of course the magic of DI containers, the first rule of their use, and the thing that some people find extraordinarily hard to grok, is that I only need one call to Resolve in the entire EasyNetQ code base at line 146 in the RabbitHutch class:

return serviceProvider.Resolve<IBus>();

IoC/DI containers are often seen as very heavyweight beasts that only enterprise architecture astronauts could love, but nothing could be more wrong. A simple implementation only needs a few lines of code, but provides your application, or library, with considerable flexibility.

EasyNetQ is open source under the (very flexible) MIT licence. Feel free to cut-n-paste my DefaultServiceProvider class for your own use.

Wednesday, October 15, 2008

Using ServiceLocator in an MVC Framework application

A couple of weeks ago I blogged about the common service locator that had just been announced by the Microsoft Patterns and Practices team. I've just updated our current application to use it. Here is what you need to do:

First, download the the binaries from codeplex. You can also get the code and build it yourself. You then need to add the Microsoft.Practices.ServiceLocation assembly to your project.

ServiceLocation

If, like me, you're using Castle Windsor you should download the code for the Castle Windsor Adaptor. This includes a file called WindsorServiceLocator.cs that you can add to your project. If you are using another IoC container, check the main page of the common service locator codeplex project for the relevant adaptor.

In your application startup code (Global.asax.cs Application_Start() for examle), register the WindsorServiceLocator with the ServiceLocator:

ServiceLocator.SetLocatorProvider(() => new WindsorServiceLocator(container));

You can now grab components from any place in your application using the ServiceLocator static Current property:

var contextService = ServiceLocator.Current.GetInstance<IContextService>();

And there's no direct dependency on Windsor so you can swap in StructureMap, AutoFac, Unity or whatever when the mood takes you.

Now there's a big big caveat with this. You should really only use the static service locator when dependency injection (DI) is not an option. In an MVC Framework application you will typically provide a ControllerFactory that gets controller instances from the IoC container. Every further dependency in the object graph that handles the request should be provided by DI. Even when you need to defer service location, the abstract factory pattern is a better choice than ServiceLocator.

The next thing that needs to happen is for ServiceLocator to be fully leveraged by the MVC Framework code. At the moment you have to use the MvcContrib WindsorControllerFactory, or write your own controller factory. It would be very nice if simply calling SetLocationProvider did the same thing.

Sunday, October 05, 2008

Learn to use Castle Windsor: Skills Matter, London October 23rd

I’m going to be giving a talk on Castle Windsor with Gojko Adzic at Skills Matter on October 23rd. It’s free, but you should register here if you plan to come.

I’ll be kicking off the two hour session with an hour introducing Dependency Injection, how you can use it to build component oriented applications and how an IoC container such as Castle Windsor ties it all together. I’ll be showing some design patterns that fit nicely with Dependency Injection and some tricks that Castle Windsor can do to make your life easier.

Gojko will be talking about more advanced topics such as extending Windsor with your own facilities, remoting and implementing AOP-style functionality.

Friday, August 01, 2008

Last night's ALT.NET evening

I really enjoyed my 15 minutes of fame at last night's ALT.NET meeting. It was great to meet everyone, and I'm only sorry that I couldn't hang around for the after show drinks. Such is the cost of provincialism.

All the talks were good, but I especially enjoyed Seb Lambla's Open Rasta presentation, a very interesting RESTfull approach to ASP.NET. David De Florinier's talk on NServiceBus was also interesting since it's a tool I haven't had a chance to look at.

My talk was on Castle Windsor. You can download the slides here:

Powerpoint 2007

http://static.mikehadlow.com/The Castle Windsor Inversion of Control Container.pptx

Powerpoint 2003

http://static.mikehadlow.com/The Castle Windsor Inversion of Control Container_2003.ppt

Wednesday, June 04, 2008

More Windsor Love: Using log4net integration

Adopting an IoC container has been a software revelation for me. It just keeps on getting better. I just added logging to Suteki Shop simply by doing the following steps (thanks to Sean Chambers for the details)

1. Add a reference to the following Castle Project dlls:

Castle.Facilities.Logging.dll
Castle.Services.Logging.Log4netIntegration.dll

2. Configure the LoggingFacility:

<facilities>
  <facility
    id="loggingfacility"
    configfile="log4net.config"
    loggingapi="log4net"
    type="Castle.Facilities.Logging.LoggingFacility, Castle.Facilities.Logging" />
</facilities>

3. Add the log4net config file to the root of the web application:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<log4net>

  <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
    <file value="sutekishop.log" />
    <appendToFile value="true" />
    <maximumFileSize value="100KB" />
    <maxSizeRollBackups value="2" />

    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%level %thread %logger - %message%newline" />
    </layout>
  </appender>

  <root>
    <level value="DEBUG" />
    <appender-ref ref="RollingFile" />
  </root>
</log4net>
</configuration>

And that's all. Isn't that cool, now I can simply add a dependcy for ILogger to any service in my application and log to my heart's content.