Many enterprise-level applications try to use POCO classes for their entities to enable a clean separation of concerns between business logic and data access.  One of the challenges of this is when an object contains a collection of child objects which should be loaded only when required.

A traditional approach to this would be to check whether the collection needed to be loaded in the ‘getter’ for the property.

public class Order
{

    IList<OrderItems> _items;
    
    public IList<OrderItem> Items
    {
        get
        {
            if (_items == null)
            {
                //Load the order items collection here...
                //Something like OrderItemsRepository.Load(this.ID)...
            }
            return _items;
        }
    }

}

The issue with this approach is that the entity now has a direct dependency on the data access layer.  Suddenly our class isn’t so POCO!  The class is now much harder to test in isolation, as the data access methods will need to be mocked.

An alternative approach to this is to use an AOP technique to inject the data access methods at runtime.  The idea here, is that the OrderRepository returns a proxy Order object that knows how to load the OrderItems collection.  In this example I will use DynamicProxy from the Castle Project.

Step 1 - Remove the data access code from the Order object

Change your entity to remove any code that try’s to load the child objects.  Your final class should look something like:

public class Order
{

    IList<OrderItems> _items;
    
    public IList<OrderItem> Items
    {
        get
        {
            return _items;
        }
    }

}

Don’t worry that the _items field is never instantiated - that will be rectified later.

Step 2 - Modify the OrderRepository to use a proxy object

Somewhere in your repository a new Order object will be created and it’s properties set from the data store.  This will need to be changed to create a new proxied Order object instead.

This:

public Order LoadOrder(int id)
{
    Order o = new Order();
    //Load the order from the data store
    o.ID = ....;
    o.OrderDate = ....;
    //etc...
    return o;
}

Becomes this:

public Order LoadOrder(int id)
{
    //Create a proxy object instead of a standard Order object.
    Castle.DynamicProxy.ProxyGenerator a = new Castle.DynamicProxy.ProxyGenerator();
    Order o = a.CreateClassProxy(typeof(Order), new OrderInterceptor(), null);

    //Load the order from the data store
    o.ID = ....;
    o.OrderDate = ....;
    //etc...
    return o;
}

Important Note: In a real application, the ProxyGenerator object should only be created once per application instance - or you will rapidly run out of resources!  (Yes, I did learn that one from experience!).

The second parameter to CreateClassProxy specifies the class that will end up loading the OrderItems for us.  This will be covered in the next step.

Step 3 - Create the interceptor class

The interceptor class contains a method, Intercept(),  that will be called every time a method on the base class (in our case the Order class) is called.  Into this method will be passed all the details of the method that was called on the base class, and any parameters that were passed to it.  Using this information, we can hook into the getter of the Order.Items property and load the OrderItem collection at this point.

The implementation of our interceptor will be something like this:

public class OrderInterceptor : Castle.DynamicProxy.StandardInterceptor
{

    public override object Intercept(Castle.DynamicProxy.IInvocation invocation, params object[] args)
    {
        //Get the object on which the method was called
        Order o = invocation.InvocationTarget as Order;
        //Check the method name is one in which we are interested
        if (invocation.Method.Name == "get_Items")
        {            
            LoadOrderItems(o);
        }

        //At the end of the method, call the base implementation which will ensure the original 
        //method is invoked, by which point the _items field will have been loaded.
        base.Intercept(invocation, args);
    }

    private void LoadOrderItems(Order o)
    {
        //Get the _items field from the Order object
        IList<OrderItem> items = typeof(Order).GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(o);
        //Check if we have already loaded the items. If not, load them
        if (items == null)
        {
            items = Factory.OrderItemRepository.LoadOrderItemsByOrderId(o.ID);
            //Set the private field _items in the Order object
            IList<OrderItem> items = typeof(Order).GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(o, items);
        }
    }

}

You can now try running this and you should find that when your client code calls Order.Items, the collection is retrieved from the database and returned in the IListHowever, if you try this now you will get a null reference exception!  The next step explains what to do and why!

Step 4 - Make the methods we need to intercept virtual

This is a very easy step, the reason for me including it separately is that it is also an easy one to forget to do!

The reason for the null reference exception is that the interceptor we lovingly crafted earlier wasn’t even called!  Therefore the _items field will always remain null. Why wasn’t it called?  Well, the generated proxy Order object inherits from the real Order object and overrides all of it’s method to allow the interceptor to be called.  However, our Items collection could not be overridden as it was not virtual.  Adding the virtual keyword will make this example work as expected.

In a future post I will discuss using mixin’s for more advanced scenarios.

This post is really just to remind myself of a class that I always seem to forget!  System.Web.VirtualPathUtility is a static class that contains a multitude of methods to use on URLs.  Everything from the simple ‘AppendTrailingSlash’ to the more sophisticated ‘ToApRelative’.  It’s always worth a look at this class to see if a method you need already exists, but because I don’t need to mess with URL’s often, I forget it - hopefully this post will help keep it in my mind!!

As mentioned in my last post, I have upgraded my blog to the new version of SubText (v2).  It all went reasonably well except for a few files which are still in the source code repository, but are no longer included in the project.  Because of the way I copied the files across to my local copy, I accidentally included these old files in the project so I was getting a few build errors.  Once that was sorted it all went well.

Changes I like so far:

  • The admin site certainly looks a lot more professional.
  • The enhanced Windows Live Writer support is very good.

I’m sure that there is a lot more than that but I posting this 10 minutes after the upgrade has completed so I haven’t noticed yet!!

Just a few days after I finally moved my blog over to SubText 1.95, they released version 2.0!  Just typical!  In fairness, it looks like a straight forward upgrade so I’ll just get on and do it, but why couldn’t it have been released just BEFORE I started instead?!

If I run into any interesting problems upgrading I’m sure I’ll post about them here…

Hello and welcome to the re-launch of my blog site.  My previous blog was created using WordPress which, although a great blogging platform, is written in PHP.  I decided that I wanted more control over my blog, so I’ve decided to switch to using SubText which is written in .NET.  So far I’ve not had any need to modify anything though, I’ve just created a theme based on Andreas Viklund’s template, Andreas09.

This blog will contain mainly .NET related material, but I may post other random stuff if I think it’s interesting (to me, at least).  If you do find something useful, or you need further information, please leave a comment.

Thanks for visiting!

Ran into this problem with a website last week.  It slowed me down for a while so I’m posting about it here to help others (or more likely me, when I run into it again!).

The problem is caused by having an aspx page which has the same name as a System.Web.UI control.  The auto-generated class will try to reference the System.Web.UI control when it should be referencing your page class.  So, it happens for Login.aspx, ChangePassword.aspx etc.

The solution I found on the net is to simply to rename your page.  However, this isn’t ideal as it will obviously break any existing links to the page.  A better fix is to modify the code-behind class name instead.  e.g. Change this:

<%@ Page Language=”C#” AutoEventWireup=”true” CodeFile=”Login.aspx.cs” Inherits=”Login”  %>

To this:

<%@ Page Language=”C#” AutoEventWireup=”true” CodeFile=”Login.aspx.cs” Inherits=”LoginPage“  %>

Then you need to rename the class in your code behind file to LoginPage.  This means that the page will work again, and any existing links to Login.aspx will also still work!