I recently wanted to take on old MonoRail application and update it to use Windsor for dependency injection (DI). The application stated as a sort of prototype and slowing grew into a decent sized application. There's a couple of places that I want to add some unit tests and I could really benefit from DI. So I sat down to hook Windsor into the application.
There's already documentation on how to integrate Windsor into MonoRail. After all, they kind of "grew up" together. However, the documentation is a little old and MonoRail has gone through a number of changes (some breaking) and improvements. The "using MonoRail" site (a sort of wiki-like site) had some information on integrating Windsor into MonoRail which was more up-to-date than the Castle docs, but still left out an important section about ViewComponents. So I thought I'd bring everything I learned into a single blog post. I plan to take much of this and use it to update the Castle docs as well as the "using" site.
You'll need to reference a few extra assemblies in your MonoRail application:
The first thing is to create a sub-class of the Windsor container for your MonoRail application. This specialized version of the container will add the following capabilities:
- It will add a new facility which will automatically configure our Controllers for a transient lifestyle (one instance per request). Windsor's default lifestyle is Singleton (imagine having only a single instance for each controller – yikes!!).
- It will automatically register all of our controllers for us. This is optional as you can individually register each controller, but I find the automatic registration much easier.
- It will automatically register all of our ViewComponents. Like controllers, this could be done individually, but this is easier.
Our custom container is really quite simple. We'll create WebAppContainer.cs in our App_Code directory. Our constructor will call the base class constructor that will initialize the container from the config file (web.config):
Now let's work on our 3 items above. We'll plug all of this into our Init() method which we'll call later when we initialize our container.
First, we add a facility for MonoRail integration. This facility is part of MonoRail:
Next, we register all of our controllers (yes, in one statement). My controllers are in a separate assembly so this is how my registration looks:
If your controllers are directly in your web application, you can change "FromAssemblyNamed(…)" to "FromAssembly(Assembly.GetExecutingAssembly())".
Now we also need to register our ViewComponents. This registration will also make sure that the ViewComponents are set up with a transient lifestyle:
That's it for the container! Our complete, customized container looks like this:
Integrating Our Container
Now we need to hook this container into our web application. We need to plug this into our custom HttpApplication (usually, your GlobalApplication.cs). First, we need to add the IContainerAccessor interface:
Now add a static class variable to old our container:
Now we need to create the container when our application first starts and dispose of it when the application ends. This is easy by hooking into the Application_OnStart and Application_OnEnd events. The OnStart event is where we call the container's Init() method.
Finally, we need to implement the IContainerAccessor.Container property to return our custom container:
We're almost there!
Now that we're using Windsor, we need to configure our web.config. Add the following section handler declaration in the <configSections> node:
And add a "useWindsorIntegration" attribute to your existing <monorail> node, setting its value to "true":
Since you probably don't have any components to register (since you haven't been using Windsor until now), you can add an empty <castle> section. When you're ready to configure your components to enable DI and loose coupling, see the Windsor Configuration Reference at the Castle Project site.
You're done. We added a new, 33-line WebAppContainer.cs, added about 6-8 lines to GlobalApplication.cs and added a few lines to web.config. Now we've got the full power of Castle's dependency injection to allow us to build loosely-couple, easily testable controllers and view components.