# Tuesday, December 09, 2008

First of all let me say that I love IoC containers.  I love them not because they are trendy, or that they help testability, or that they allow me to use AOP. No, the real reason I love IoC containers is because they let me be lazy.

When I'm designing a class I don't need to worry about how I get can get a dependency.  The container allows me to worry about that later, by separating construction from logic.  Think about that for a second. Every time we use the new keyword we're explicitly creating a dependency between implementations.  Sometimes this isn't a big deal, but if we have a dependency that itself has 10 other dependencies this can get out of hand real quick.

Containers are smart, they know which implementations fulfill which contracts.  Somewhere on application startup we just tell the container what contracts and what implementations we have and it figures out the dependencies for us. If we have a FooService that requires an IBarRepository implementation, the container will automatically new up a class that implements IBarRepository and give it to FooService on creation.

Things get a bit less academic and a bit more troublesome when we try to implement a container with ASP.NET.  Normally we would want the container to new up our page instance and provide any dependencies it my have, but with ASP.NET we don't get the chance to have the container create the page instances with all of its required dependencies.  We could create our own page handler factory to do this, but that's a lot of work to do right.

Sprint.NET has its own page handler factory which works very well, but the last I checked, Spring.NET configuration is very verbose and requires that each page that needs the container to construct it be registered with the container. It works, but I prefer convention over configuration.

My favorite .NET container is Windsor because it allows me to do more with less work (configuration), but unfortunately there's no built in way to use Windsor in a truly IoC way with ASP.NET.  The only supported way is to get a reference to the container and ask the container to resolve an instance of something, which directly makes your page dependant upon the container, and generally just adds noise where its not needed; you would see calls like this all over:

IFooService service = Container.Resolve<IFooService>();

Rather than explicitly asking the container for a service instance, I would much rather have the container inject any required dependencies into my page instance when it gets constructed.  The problem is how do we do this with Windsor?

Windsor AspNetModule

The approach I've taken is to create an http module that will inject dependencies into a page just after instantiation using setter injection.  This means that the container will inject any dependencies that my page may have using public property setters.  Constructor injection would be better, but IMO its not worth the effort of having to create my own page handler factory, here we can rely on the tried and true ASP.NET infrastructure.  Perhaps someday I'll change my mind, but for now this is acceptable.

Since I plan on using this container with a large amount of legacy code that doesn't use dependency injection I want to make the use of the container somewhat explicit.  I don't want to waste cycles scanning over a page that doesn't need any dependencies injected.  To enforce this, I make the pages that require injection declare so using a class level attribute.  Here's a succinct example with one dependency:

[UsesInjection]
public partial class CustomerDetail : Page
{
    public ICustomerRepository CustomerRepository { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        customerGrid.DataSource = CustomerRepository.GetAll();
        customerGrid.DataBind();
    }
}

When the module sees the current handler with the UsesInjection attribute it scans the class for public setter properties and tries to resolve any dependencies by type. If an instance is registered with that type in the container, the module tries to set the property. Here an ICustomerRepository instance gets injected. All of this happens before the page lifecycle begins, so its safe to use these dependencies on page init or page load.

If more explicit control is required, we can change the module's behavior by changing the class level UsesInjection attribute.

[UsesInjection(For.ExplicitProperties)]
public partial class CustomerDetail : Page
{
    private ICustomerRepository customerRepository;

    [RequiredDependency]
    public ICustomerRepository CustomerRepository
    {
        get { return customerRepository; }
        set { customerRepository = value; }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        customerGrid.DataSource = CustomerRepository.GetAll();
        customerGrid.DataBind();
    }
}

The For.ExplicitProperties does two things:

  1. Optimizes the scanning process to only consider explicitly tagged properties (the default behavior considers all public settable properties).
  2. An exception will be thrown if a dependency couldn't be found in the container to inject. This makes is pretty evident if you forget to register a dependency with the container.

With the page level code in place we then need to setup our container and register our components. This is easily accomplished by implementing Castle.Windsor.IContainerAccessor in our global.asax and creating a static container with the registered components our web application needs to run.  Here we register to use an in memory customer repository implementation.

public class Global : System.Web.HttpApplication, IContainerAccessor
{
    private readonly IWindsorContainer container = new WindsorContainer();

    public Global()
    {
        container.Register(
            Component.For<ICustomerRepository>()
                .ImplementedBy<InMemoryCustomerRepository>());
    }

    public IWindsorContainer Container
    {
        get { return container; }
    }
}

We do this in the global.asax because we share the container between all requests, and thus only want one instance of it. Also, the IContainerAcessor is used as a service locator which is required by the AspNetWindsor http module to find your container instance which it will use to resolve dependencies.

The very last thing we need to do is register the AspNetWindsor http module in our web.config, just like any other module.

<add name="WindsorModule" type="Sneal.AspNetWindsorIntegration.AspNetDependencyBuilderModule, Sneal.AspNetWindsorIntegration"/>

From here on out, all ASP.NET requests get intercepted by this module and "enriched" by the container as long as they are tagged with the UsesInjection page level attribute.

The code is available under the Apache 2 license in my SVN repository here on Google Code.  A compiled binary is also available for download.

.NET | IoC
Tuesday, December 09, 2008 7:26:26 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Friday, April 13, 2007
I really don't understand why Spring and thus Spring.NET chose to default all objects or beans to singleton scoping.  I mean why?  In my experience singletons are rare magical beasts that usually only exist because they act as a sort of service locator.  When I use any plain old C# object I have to use the new keyword.  I'm comfortable with the new keyword, and would seriously miss it if all my classes were forced to be singletons right out of the box.  You can think of the code that you write as the blueprints for constructing a new instance at runtime, well I think that should apply to the XML you use to wire objects up in Spring with - blueprints for new objects, not singletons!  Instead the designers of Spring chose to default to singleton prototyping so that every object I declare in my XML config only ever exists once.  This is a serious scoping mismatch especially when writing something stateless like a web application where you want new instances for each request.

Why am I ranting about this anyway?  I ran into a very subtle state bug where I forgot to set singleton="true" on one of my ASP.NET controller objects, so each request was using the same controller class instance.  This may explain another error that the testers were getting at times: Request is not available in this context.

IoC
Friday, April 13, 2007 9:45:39 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [1]  | 
# Saturday, March 17, 2007

To get my WatiN tests working in predictable and repeatable manner I ended up integrating Spring.NET into my application so that I could swap out the data service implementation through configuration.  When running under WatiN the stubbed data service is used instead of the production web service.  Having a predictable set of test data is critically important, especially since some of my test assertions are looking for specific data values in the rendered HTML, which would be impossible if I was hitting the actual web service for data.

I integrated Spring.NET into the ASP.NET 1.1* application I'm working on and so far I'm very happy with it.  What I like about it:

  • XML configuration almost exactly the same as Spring in Java (which I've been using pretty heavily for the last 3 months).
  • Tight ASP.NET integration, so I have no code dependencies on any of the Spring namespaces in my code.  None.  Zero.
  • There are data validation libraries and other features which may be useful in the future.
  • It just works.

So check it, here's my code behind for the Search.ascx, notice how the controller instance is set via the Controller property by Spring.  Then the view instance (the Search user control instance itself) is set into the controller in the Initialize method call on page load.  The one other thing that might seem strange is that I'm creating the SearchCriteria instance directly from the user control's Request collection rather than using declared ASP.Net controls; sometimes straight HTML controls are just what we need.

public class Search : ControlBase, ISearchView
{
   protected System.Web.UI.WebControls.LinkButton m_btnSearch;
   protected System.Web.UI.WebControls.DataGrid m_resultsGrid;
   private SearchController m_controller;

   private void Page_Load(object sender, System.EventArgs e)
   {
      Controller.Initialize(this, !Page.IsPostBack);
   }

   public void SortSearchResults(object sender, DataGridSortCommandEventArgs e)
   {
      Controller.Sort(e.SortExpression);
   }

   public void SearchClick(object sender, EventArgs e)
   {
      Controller.Search(Criteria);
   }

   public SearchCriteria Criteria
   {
      get
      {
         SearchCriteria criteria = new SearchCriteria();
         criteria.BorrowerId     = Request.Form["txtBorrowerId"];
         criteria.BorrowerName   = Request.Form["txtBorrowerName"];
         criteria.BusinessLine   = Request.Form["txtBusinessLine"];
         criteria.LoanNumber     = Request.Form["txtLoanNumber"];
         criteria.UnderwriterUid = Request.Form["txtUnderwriterUid"];

         return criteria;
      }
   }

   /// <summary>
   /// Injected by Spring.NET.
   /// </summary>
   public SearchController Controller
   {
      get { return m_controller; }
      set { m_controller = value; }
   }

   #region ISearchView Members

   public void setResults(IList results)
   {
      m_resultsGrid.DataSource = results;
      m_resultsGrid.DataBind();
   }

   #endregion

}

And here's the Spring.NET specific configuration for the Search page, this does all the wiring via configuration of the different objects.

<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">

    <object type="Search.ascx">
        <property name="Controller" ref="SearchController" />
    </object>

    <object id="SearchController" type="CRR.Web.Controllers.SearchController, CRR.Web">
        <constructor-arg name="dataService" ref="DataService" />
        <constructor-arg name="stateProvider" ref="SessionStateProviderAdapter" />
    </object>
   
    <object id="SessionStateProviderAdapter"
            type="CRR.Web.Controllers.SessionStateProviderAdapter, CRR.Web"/>


    <!-- Production data service implmentation -->
    <!-- <object id="DataService" type="CRR.Domain.DataService, CRR.Domain"/> -->
   
    <!-- Stubbed data service implmentation for testing -->

    <object id="DataService" type="CRR.Domain.DataServiceStub, CRR.Domain"/>   
   
</objects>

There is also a Spring provided HttpHandler and an HttpModule for Spring in the web.config.  This is the important part.  By registering Spring web as the http handler for aspx pages, I'm now telling Spring to construct my aspx (and thus ascx) page instances rather than ASP.NET.  With Spring now constructing my pages, its now possible to inject dependencies directly into my pages upon construction.

<httpModules>
   <add name="Spring" type="Spring.Context.Support.WebSupportModule, Spring.Web"/>
</httpModules>
<httpHandlers>
   <add verb="*" path="*.aspx" type="Spring.Web.Support.PageHandlerFactory, Spring.Web"/>
   <add verb="*" path="*.asmx" type="Spring.Web.Services.WebServiceHandlerFactory, Spring.Web"/>
   <add verb="*" path="ContextMonitor.ashx" type="Spring.Web.Support.ContextMonitor, Spring.Web"/>
</httpHandlers>

The search controller uses a state service, specifically ASP.NET session state via a custom session state adapter, and a data service which are injected into the controller by Spring - the view (code behind page) has NO knowledge of the services being injected into the controller, as the controller instance itself is injected into the view.

Here's the relevant parts of the controller used for wiring, the constructor and Initialize().  Note that the constructor is called by Spring and that the Initialize method is called by the search view.

/// <summary>
/// Controller logic for search view.
/// </summary>
public class SearchController
{
   public static readonly string ResultsKey = "SearchController.ResultsKey";

   private ISearchView m_view;
   private IDataService m_dataService;
   private IStateProvider m_stateProvider;

   public SearchController(IDataService dataService, IStateProvider stateProvider)
   {
      m_dataService = dataService;
      m_stateProvider = stateProvider;
   }

   public SearchController Initialize(ISearchView view, bool firstTime)
   {
      m_view = view;

      if (firstTime)
         DefaultSearchForCurrentUser();

      return this;

   }
   // snip //
}

The plan is to have two different Spring configurations.  One for production and integration testing and the other one used for WatiN tests.  That way when WatiN drives Internet Explorer to verify the UI is working, it does so without ever touching the data service, only testing specific stubs are being used for the data service.  This is partly for speed but also because our data service implementation is not yet complete.

*I know… very sad.  My last ASP.NET project was using .NET 2.0, and that was a year and a half ago when that was started.

ASP.NET | IoC
Saturday, March 17, 2007 5:29:16 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  |