The magic of Castle Windsor!

By | February 24, 2011

A while ago I wrote a few articles on this site about exposing Castle Windsor to your application. For some reason that caught the attention of Krzysztof Koźmic and Mark Seemann. In short they felt I was doing it all wrong! Which led to a follow up article. Fair enough, I was new to the whole principle of Inversion of Control and Dependency Injection, so I assumed they were in the know and were probably correct in… correcting me!

Since then I’ve been fiddling around with it in my spare time, trying to set up an architecture that would allow me to use Castle Windsor as it was intended. Unfortunately, my spare time is a little limited, so it took me a few months in total to come up with something a little more structured and streamlined. However, this week I got to the point where I said to myself: “Wow, now that’s cool!”

I’m not quite sure where to start. Perhaps it’s best to give some background information first.

I was looking for a clean solution to implement a Model View Presenter architecture in my application. Ideally this would be coded into a framework that I could use for any other project in the future. In fact, I already posted about modular web applications back in April last year! It addressed the Composite Web Application Block that provided the solution that I was looking for. After playing around with it however, I found it was very cumbersome to work with. Although, with the power of hindsight, that could have been due to my lack of knowledge of IoC and DI.

I ended up building my own framework, heavily inspired by the ideas behind the Composite Web Application Block. At first I managed to get along just fine without any form of inversion of control or dependency injection. The further I got down the road, the more obvious it became that, while possible, the code became cluttered and no longer felt as clean as I wanted. At this point we decided in the office to continue down the road of using as little inversion of control and dependency injection as we could get away with. However, in my spare time I decided to research at home how to utilise the capabilities of Castle Windsor to achieve that clean, loosely coupled design that would make my life so easy!

It took a bit of experimenting, but I’m glad I’ve done so. I feel I have a much better understanding of the principles of Inversion of Control and Dependency Injection as well as how to use Castle Windsor to help me implement this.

Now that I’ve given a little introduction to the background information, it’s time to look at a little class diagram. I’ve simplified it for the sake of example. It clearly shows five distinctly separate ‘layers’.

(Click to enlarge)

Let’s quickly go over the things you see in this diagram.

  • Unit of work;
    This can be an NHibernate Session or an Entity Framework ObjectContext.
  • Repository<T>;
    The repositories do all the work of querying the context and return objects with data.
  • Controller;
    The controller communicates with repositories and performs validations if needed. The reason for adding a controller is to allow for extending the architecture with web services later. A web service doesn’t know anything about presenters and views and is only interested in data and validations.
  • Presenter;
    The presenter asks the controller to perform a task and prepares the data for the view.
  • View;
    The view presents the data on the screen (can be a web form, win form, etc).

This is the point where Castle Windsor starts to come in.

As the name suggests, WebFormView is a web form. Within Visual Studio you’d see it as WebFormView.aspx in the Solution Explorer. It’s just a normal web page. The only thing that differs from “normal” is that the code-behind implements the IView interface. The rest of the system is tied together by using one of the most fundamental principles of object oriented programming: composition.

All I need to do now is to tell Castle Windsor which concrete implementations should be injected in all those classes. This is done through configuration. My personal preference is using XML files to configure, but feel free to use whichever method you prefer. For example:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <components>
    <!-- entity framework object context -->
    <component
      id="context.ef4"
      type="WebClient.Data.ClientModelContainer, WebClient"
      lifestyle="PerWebRequest">
    </component>

    <!-- unit of work -->
    <component
      id="unitofwork.ef4"
      service="WebClient.UnitOfWork.IUnitOfWork, WebClient"
      type="WebClient.UnitOfWork.EFUnitOfWork, WebClient"
      lifestyle="PerWebRequest">
      <parameters>
        <context>${context.ef4}</context>
      </parameters>
    </component>

    <!-- repositories -->
    <component
      id="repositories.defaultdummy"
      service="WebClient.Repositories.IRepository, WebClient"
      type="WebClient.Repositories.DefaultDummyRepository, WebClient"
      lifestyle="PerWebRequest">
      <parameters>
        <unitOfWork>${unitofwork.ef4}</unitOfWork>
      </parameters>
    </component>
    <component
      id="repositories.otherdummy"
      service="WebClient.Repositories.IRepository, WebClient"
      type="WebClient.Repositories.OtherDummyRepository, WebClient"
      lifestyle="PerWebRequest">
      <parameters>
        <unitOfWork>${unitofwork.ef4}</unitOfWork>
      </parameters>
    </component>

    <!-- controllers -->
    <component
      id="controllers.default"
      service="WebClient.Controllers.IController, WebClient"
      type="WebClient.Controllers.DefaultController, WebClient"
      lifestyle="PerWebRequest">
      <parameters>
        <repositories>
          <array>
            <repository>${repositories.defaultdummy}</repository>
            <repository>${repositories.otherdummy}</repository>
          </array>
        </repositories>

      </parameters>
    </component>

    <!-- presenters -->
    <component
      id="presenters.default"
      service="WebClient.Presenters.IPresenter, WebClient"
      type="WebClient.Presenters.DefaultPresenter, WebClient"
      lifestyle="PerWebRequest">
      <parameters>
        <controller>${controllers.default}</controller>
      </parameters>
    </component>
  </components>
</configuration>

If you have studied the XML configuration for a moment, you will notice that I am not specifying a view parameter in the configuration for the presenter component. However, the class diagram clearly shows we need to have a view! This is because it will be detected dynamically on run-time which view needs to be given as a parameter.

I can feel you already wondering how this works. But, before I can tell you, I will have to add a few more tidbits of information to glue everything together.

The view is the absolute starting point. When sending a request to the server to load WebFormView.aspx   (or any other web page), I need to figure out which presenter to resolve. To prevent having to write the same code on each and every page, I’ve adopted a naming convention strategy that allows me to figure this out “on the fly” in a base page class:

The Id of the component within the Castle Windsor configuration should be able to be deducted from the root application path of the web page that has been requested.

Here’s a few examples to show what I mean:

url: http://localhost/default.aspx
id: presenters.default

url: http://localhost/subfolder/default.aspx
id: presenters.subfolder.default

url: http://localhost/MyAppRoot/default.aspx
id: presenters.default

url: http://localhost/MyAppRoot/subfolder/default.aspx
id: presenters.subfolder.default

Once I figured out that I could resolve presenters based on a naming convention, the code was pretty easy to write:

public class Page : System.Web.UI.Page, IView
{
    protected IPresenter presenter;

    /// <summary>
    /// Initializes the page. In this case it resolves our presenter class
    /// through Castle Windsor.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected virtual void Page_Init(object sender, EventArgs e)
    {
        string windsorKey = "";

        try
        {
            // Determine which presenter to resolve.
            int rootPathIndex = Request.Path.IndexOf(Request.ApplicationPath);
            int dotAspxIndex = Request.Path.IndexOf(".aspx");

            windsorKey = Request.Path
                .Remove(dotAspxIndex, 5)                                // strip .aspx
                .Remove(rootPathIndex, Request.ApplicationPath.Length)  // strip the root
                .Replace("/", ".")                                      // replace slash
                .ToLower();                                             // to lowercase

            // Finally create the proper windsor key.
            windsorKey = (windsorKey.StartsWith("."))
                ? String.Format("presenters{0}", windsorKey)
                : String.Format("presenters.{0}", windsorKey);

            // Let the presenter factory take care of creating the presenter.
            // Castle Windsor will make sure all dependencies will be resolved.
            this.presenter = HttpApplication.PresenterFactory.Create(windsorKey, this);
        }
        catch (Exception ex)
        {
            string message = String.Format(
                "Error trying to resolve presenter: {0}. See InnerException for details",
                windsorKey);

            throw new FrameworkException(message, ex);
        }
    }
}

Pretty neat, huh? But, wait! There’s something new in this code! Have you spotted it? I’ll highlight it for you, just in case:

// Let the presenter factory take care of creating the presenter.
// Castle Windsor will make sure all dependencies will be resolved.
this.presenter = HttpApplication.PresenterFactory.Create(windsorKey, this);

Up until now I’ve not spoken about the presenter factory yet. One of the things that I had a truly hard time to understand when trying to figure this out was the so-called Three Calls Pattern. When I read through that page for the very first time, I got a proper ‘what the fuck’ feeling! Once I figured it out, it was actually fairly straight forward. The mistake I made earlier was exposing the container to the application to resolve objects. In fact, if the system is designed properly, I found I don’t really need access to the container at all.

In short it means: make sure to call Install() on the container just once when the application starts, resolve one object that resolves everything else through dependency injection (hint: remember how the XML configuration looks) and finally release the object to free up memory. In my own situation it means that I install the container and resolve the PresenterFactory during Application_Start in the HttpApplication of my framework.

public class HttpApplication : System.Web.HttpApplication
{
    public static IPresenterFactory PresenterFactory;

    protected virtual void Application_Start(object sender, EventArgs e)
    {
        // Retrieve modules from (web) application configuration.
        ModuleSection moduleConfigSection = (ModuleSection)
            ConfigurationManager.GetSection("moduleSettings/modules");

        if (moduleConfigSection == null)
        {
            // Config secion not found, throw detailed exception message.
            throw new FrameworkException(
                "Please add module configuration to the application configuration "
                + "file: \n\r\n\r"
                + "<sectionGroup name=\"moduleSettings\">\n\r"
                + "     <section \n\r"
                + "         name=\"modules\" \n\r"
                + "         type=\"Framework.Configuration.ModuleSection, "
                + "                   Framework\" \n\r"
                + "         allowDefinition=\"Everywhere\" \n\r"
                + "         allowLocation=\"true\"/>\n\r"
                + "</sectionGroup>"
            );
        }

        // Initialize the required/ specified modules.
        ModuleInitializer.Initialize(moduleConfigSection.Modules);

        // Module initialization will have registered all necessary
        // windsor components, it should be safe to call Install()
        Windsor.Install();

        // Windsor installed, resolve the presenter factory.
        PresenterFactory = Windsor.Resolve<IPresenterFactory>();
    }
}

Castle Windsor has a feature called typed factory facilities. This is actually pretty cool. I can use this to create a PresenterFactory interface through which I can resolve a presenter. Castle Windsor is smart enough to figure out all the nitty gritty details for me. I only specify the interface and tell the configuration to use the typed facility factory and that’s it!

public interface IPresenterFactory
{
    IPresenter Create(string name, IView view);
}

To create a presenter, I need to specify two parameters: the name of the presenter to resolve and the view object to inject. This is exactly what you saw me do earlier, when calling the PresenterFactory from the Page_Init! However, there is a small downside… this doesn’t work out of the box. Castle Windsor will have to understand these parameters. This can be done by writing a custom component selector:

public class PresenterTypedFactoryComponentSelector : DefaultTypedFactoryComponentSelector
{
    protected override string GetComponentName(MethodInfo method, object[] arguments)
    {
        if (method.Name == "Create"
            && arguments.Length == 2
            && arguments[0] is string)
        {
            return (string)arguments[0];
        }

        return base.GetComponentName(method, arguments);
    }
}

It looks a little intimidating, but all this does is override Windsor’s method to get the component. It checks if the calling method name equals Create and if the method was called using two parameters and the first parameter needs to be a string. I could have done some additional checks, such as checking if the second parameter is of the type IView, but I didn’t think this was too big of an issue.

Now that all the missing pieces have been assembled, it’s time to let Castle Windsor know that we’d like to use a typed factory facility with our own home-made custom component selector. Simply open up the configuration file and insert at the top:

<!-- typed factory facilities -->
<facilities>
  <facility
    id="facilities.typedfactory"
    type="Castle.Facilities.TypedFactory.TypedFactoryFacility, Castle.Windsor">
    <factories>
      <factory
        id="facilities.typedfactory.presenters"
        interface="WebClient.IPresenterFactory, WebClient"
        selector="${components.selectors.presenter}" />
    </factories>
  </facility>
</facilities>

<components>
  <!-- custom selectors -->
  <component
    id="components.selectors.presenter"
    service="Castle.Facilities.TypedFactory.ITypedFactoryComponentSelector, Castle.Windsor"
    type="WebClient.PresenterTypedFactoryComponentSelector, WebClient">
  </component>
</components>

At this point everything is done! Let me summarize what I’ve achieved with all this code and configuration:

Using the Three Calls Pattern to automatically resolve a presenter through the PresenterFactory by looking at the URL of the requested web page. Not only the presenter is resolved, its controllers, repositories and unit of work are automatically resolved and injected. Even better, the unit of work has a parameter to resolve the object context of the entity framework! There’s never a need to look back to instantiate things myself (slight detail: remember to implement IDisposable in the unit of work to dispose of the context when the unit of work gets disposed)!

Let’s see if we can sum up the advantages of using this approach:

  • Flexible due to configuration;
  • Easy to add new functionalities because the system is loosely coupled and isn’t dependant on concrete implementations;
  • Allows the use of the MVP design pattern to create a web forms application;
  • Allows for injecting mock classes to help unit testing;

I can easily see that one of the biggest disadvantages of this approach is that it might be hard to understand for developers who aren’t familiar yet with inversion of control and dependency injection and who have never worked with IoC containers such as Castle Windsor.


Leave Your Comment

Your email will not be published or shared. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>