Castle DynamicProxy tutorial part I: Introduction

I’ve been exper­i­ment­ing lately quite a lot with Cas­tle Dynamic Proxy, cre­at­ing pro­to­type for a project I work on at work and I even imple­mented a small fea­ture that was miss­ing from it. Gen­er­ally, Dynamic Proxy (DP from now on) is a great, light­weight frame­work, but it’s great­est down­side is lack of doc­u­men­ta­tion. It’s sur­pris­ingly log­i­cal a easy to use, but since there are almost no resources on the web, that could help you get started with it, I decided to give it a go, and start a small tuto­r­ial series of posts, that will intro­duce var­i­ous fea­tures of DP while work­ing on a sim­ple sam­ple project.

The project is to add abil­ity to freeze objects, so that from the point in time where object has been frozen, it’s state can not change. AFAIK there’s such fea­ture in WPF, but since my knowl­edge of WPF is very lim­ited, I don’t know how that works. The project itself is not impor­tant (nor the use­ful­ness of its imple­men­ta­tion). It’s only pur­pose is to serve as didac­ti­cal exam­ple. I am also aware that the state of the project shown here is far from how good code should look like. We will evolve the imple­men­ta­tion in forth­com­ing parts of the tuto­r­ial, as we intro­duce other con­cepts and fea­tures of DP.

Basi­cally here’s what we want to achieve:

  • Be able to use non-frozen freez­able object just like any other object
  • Be able to check if the object is freezable
  • Be able to check if the object is frozen
  • be able to freeze freez­able object
  • NOT be able to change state of the object after it has been frozen

How do we do that? Well, DP cre­ates a trans­par­ent proxy for the real objet at run­time for as, and we can inter­cept the calls to it, and add logic to the objects. This is a very pow­er­ful capa­bil­ity and pos­si­bil­i­ties of using it, are vir­tu­ally endless.

To spec­ify our require­ments, we use tests, using xUnit framework:

[Fact]
public void IsFreezable_should_be_false_for_objects_created_with_ctor()
{
    var nonFreezablePet = new Pet();
    Assert.False(Freezable.IsFreezable(nonFreezablePet));
}

[Fact]
public void IsFreezable_should_be_true_for_objects_created_with_MakeFreezable()
{
    var freezablePet = Freezable.MakeFreezable<pet>();
    Assert.True(Freezable.IsFreezable(freezablePet));
}

[Fact]
public void Freezable_should_work_normally()
{
    var pet = Freezable.MakeFreezable</pet><pet>();
    pet.Age = 3;
    pet.Deceased = true;
    pet.Name = "Rex";
    pet.Age += pet.Name.Length;
    pet.ToString();
}

[Fact]
public void Frozen_object_should_throw_ObjectFrozenException_when_trying_to_set_a_property()
{
    var pet = Freezable.MakeFreezable</pet><pet>();
    pet.Age = 3;

    Freezable.Freeze(pet);

    Assert.Throws<objectfrozenexception>(delegate { pet.Name = "This should throw"; });
}

[Fact]
public void Frozen_object_should_not_throw_when_trying_to_read_it()
{
    var pet = Freezable.MakeFreezable<pet>();
    pet.Age = 3;

    Freezable.Freeze(pet);

    Assert.DoesNotThrow(delegate { int age = pet.Age; });
    Assert.DoesNotThrow(delegate { string name = pet.Name; });
    Assert.DoesNotThrow(delegate { bool deceased = pet.Deceased; });
    Assert.DoesNotThrow(delegate { string str = pet.ToString(); });
}

[Fact]
public void Freeze_nonFreezable_object_should_throw_NotFreezableObjectException()
{
    var rex = new Pet();
    Assert.Throws<notfreezableobjectexception>(() => Freezable.Freeze(rex));
}

We use sta­tic class  Freez­able to cre­ate freez­able objects, and to query their state. This allows us to have really sim­ple API (and imple­men­ta­tion), and encap­su­late all (well, not all — yet) freez­able logic in one place. This imple­men­ta­tion has one short­com­ing that you may have spot­ted – the class we want to make freez­able instance of, has to have default, para­me­ter­less constructor.

This is not a DP lim­i­ta­tion how­ever, and fur­ther along the way, we will remove it.

The way DP works, is by sub­class­ing given class and over­rid­ing it’s meth­ods. This approach has few limitations:

  • you obvi­ously can’t proxy sealed class, since it can’t be inher­ited from
  • you can only over­ride vir­tual meth­ods, so for non-virtual meth­ods there’s noth­ing you can gain

Ok, so how do we go about imple­ment­ing the whole thing?

First we need some way of track­ing which objects are freez­able and  their freez­abil­ity state. For that we cre­ate an interface:

internal interface IFreezable
{
    bool IsFrozen { get; }
    void Freeze();
}

It will help us by pro­vid­ing all the infor­ma­tion we need.

Then, in our Freez­able sta­tic class we cre­ate a dic­tio­nary, that will map objects, to their freez­abil­ity state:

private static readonly IDictionary<object, IFreezable> _freezables = new Dictionary<object, IFreezable>();

With that, imple­men­ta­tion of Freez­able meth­ods should be really straightforward:

public static bool IsFreezable(object obj)
{
    return obj != null && _freezables.ContainsKey(obj);
}

public static void Freeze(object freezable)
{
    if (!IsFreezable(freezable))
    {
        throw new NotFreezableObjectException(freezable);
    }
    _freezables[freezable].Freeze();
}

public static bool IsFrozen(object freezable)
{
    return IsFreezable(freezable) && _freezables[freezable].IsFrozen;
}

Still how­ever, no word about DP, and we have imple­men­ta­tion of Make­Freez­able miss­ing. Also, a reader may point out, that by virtue of keep­ing some map­ping from objects to inter­face, objects won’t mag­i­cally gain behavior.

That is true, with a lit­tle bit of work how­ever, they will.

What we need to do, is to mon­i­tor calls to prop­erty set­ters, and if object is indeed frozen call­ing a set­ter should raise an excep­tion, as shown in the test. To do that we need to actu­ally inter­cept the call, and for that, we have IIn­ter­cep­tor interface.

IIn­ter­cep­tor has only one method:

Castle.Core.Interceptor.IInterceptor.Intercept(Castle.Core.Interceptor.IInvocation);

The IIn­vo­ca­tion is another inter­face that holds all the infor­ma­tion about the call.

dptutorial_1_iinvocation

We can query its Method prop­erty to get Method­Info object point­ing to the called method, Pro­ceed method, that invokes the method on tar­get object and few other meth­ods and prop­er­ties that we will exam­ine in forth­com­ing parts of the tuto­r­ial. With that, we have all we need to actu­ally imple­ment our freez­able logic:

internal class FreezableInterceptor : IInterceptor, IFreezable
{
    private bool _isFrozen;

    public void Freeze()
    {
        _isFrozen = true;
    }

    public bool IsFrozen
    {
        get { return _isFrozen; }
    }

    public void Intercept(IInvocation invocation)
    {
        if (_isFrozen && invocation.Method.Name.StartsWith("set_", StringComparison.OrdinalIgnoreCase))
        {
            throw new ObjectFrozenException();
        }

        invocation.Proceed();
    }
}

Our inter­cep­tor holds the freez­abil­ity state of the object. Since we cre­ate one inter­cep­tor per object, it will work. In the Inter­cept method, inter­cep­tor checks if the object is frozen, and if called method’s name starts with “set_”, as is the case for all prop­erty set­ters. If indeed that’s the case, it means that we’re try­ing to set a prop­erty of a frozen object, so a Object­FrozenEx­cep­tion is thrown. Oth­er­wise, we can pro­ceed with the call.

Now, it’s really easy to imple­ment Freezable.MakeFreezable method. we know how to inter­cept calls. The only piece miss­ing is – how do we actu­ally cre­ate the prox­ies. For that, we use the Prox­y­Gen­er­a­tor class. We only need one instance, so we may keep it as a sta­tic field in the Freez­able class

private static readonly ProxyGenerator _generator = new ProxyGenerator();

Prox­y­Gen­er­a­tor class is the heart of the DP library. It has numer­ous meth­ods for cre­at­ing dif­fer­ent kinds of prox­ies, but for now, we will only use one: Cre­ate­ClassProxy, that cre­ates a proxy for a class.

public static TFreezable MakeFreezable<TFreezable>() where TFreezable : class, new()
{
    var freezableInterceptor = new FreezableInterceptor();
    var proxy = _generator.CreateClassProxy<TFreezable>(new CallLoggingInterceptor(), freezableInterceptor);
    _freezables.Add(proxy, freezableInterceptor);
    return proxy;
}

We cre­ate a Freez­ableIn­ter­cep­tor to inter­cept the calls, ver­ify freez­abil­ity state of the con­nected object, and throw if nec­es­sary, then we cre­ate the actual proxy, add it along with its freez­ableIn­ter­cep­tor to the dic­tio­nary, and return.

In call to Cre­ate­ClassProxy generic method we pass one more argu­ment – a new instance of Cal­l­Log­ging­In­ter­cep­tor. It’s a sim­ple class that also imple­ments IIn­ter­cep­tor inter­face that logs all the inter­cepted calls to the con­sole. This also means that you can have more than one inter­cep­tor for a proxy which is a very pow­er­ful and handy capability.

With that, we basi­cally have out ini­tial imple­men­ta­tion com­plete, we only need to cre­ate miss­ing excep­tion classes and we are good to go. Indeed, all the tests should pass now.

dptutorial_1_tests_pass

We can cre­ate sam­ple con­sole appli­ca­tion to see how that works:

internal class Program
{
    private static void Main(string[] args)
    {
        var rex = Freezable.MakeFreezable<Pet>();
        rex.Name = "Rex";
        Console.WriteLine(Freezable.IsFreezable(rex)
                              ? "Rex is freezable!"
                              : "Rex is not freezable. Something is not working");
        Console.WriteLine(rex.ToString());
        Console.WriteLine("Add 50 years");
        rex.Age += 50;
        Console.WriteLine("Age: {0}", rex.Age);
        rex.Deceased = true;

        Console.WriteLine("Deceased: {0}", rex.Deceased);
        Freezable.Freeze(rex);
        try
        {
            rex.Age++;
        }
        catch(ObjectFrozenException ex)
        {
            Console.WriteLine("Oups. it's frozen. Can't change that anymore");
        }
        Console.WriteLine("--- press enter to close");
        Console.ReadLine();
    }
}

public class Pet
{
    public virtual string Name { get; set; }
    public virtual int Age { get; set; }
    public virtual bool Deceased { get; set; }

    public override string ToString()
    {
        return string.Format("Name: {0}, Age: {1}, Deceased: {2}", Name, Age, Deceased);
    }
}

The out­put of the appli­ca­tion looks like this:

dptutorial_1_app

Bah! We get the behav­ior we wanted, with­out actu­ally mod­i­fy­ing the Pet class, and with sur­pris­ingly few lines of code. It may be a lit­tle bit over­whelm­ing right now, but what we did, boils down to three things:

  1. We cre­ated IIn­ter­cep­tor imple­men­ta­tion, that over­rides Inter­cept method and keeps track of freez­able state of an object.
  2. We cre­ated a proxy object with proxyGenerator.CreateClassProxy method
  3. We cre­ated really sim­ple logic to cor­re­late out freez­able objects with inter­cep­tors, that keep their state.

And with all of that we barely scratched the sur­face of what can be done with DynamicProxy.

As a bonus, if you are curi­ous how the proxy type gen­er­ated by DP looks like, here’s what Reflec­tor shows:

dptutorial_1_reflector

If the last screen­shot left you with headache don’t worry, by the end of this tuto­r­ial it will be all crys­tal clear.

See you in part II, where we will intro­duce IProx­y­Gen­er­a­tionHook, to give us more fine-grained con­trol over our interceptors.

If you have any ques­tions or sug­ges­tions please, leave a comment.

The solu­tion with tests is avail­able here.

Dynam­icProxy I use is the trunk ver­sion. You can get the lat­est ver­sion here.

To run tests, you will also need xUnit frame­work, avail­able here.

Tech­no­rati Tags: , ,
  • http://billystack.blogspot.com/ Billy Stack

    Excel­lent tutorial!

    The one very off­putting thing in rela­tion to the prac­ti­cal­ity of using DP — is that fact that you have to declare prop­er­ties as vir­tual! — Is there any way around not hav­ing to do this?

    Also, in a code­base that I work on, we write lots of man­ual code to "make" entity types "immutable". Could what you described above be used as a mech­a­nism for devel­op­ing "immutable" entity types?

  • http://devlicious.com/blogs/christopher_bennage/ Christo­pher Bennage

    I don't under­stand the rea­son for the IDictionary<object, IFreez­able> to track freez­ables. Couldn't you just do a check for the inter­face in IsFreez­able()?
    Could you elaborate?

  • http://kozmic.pl/Default.aspx Krzysztof Koźmic

    Christo­pher,
    I did this to sim­plify the exam­ple. This is the first part of the tuto­r­ial, I didn't want to jump into more advanced stuff just yet.
    Dic­tio­nary maps sim­ple proxy onto freez­able state. I can't check for the inter­face, because the proxy does not imple­ment it.

    Take a look at Make­Freez­able implementation.

    I cre­ate a new inter­cep­tor, (which is used to track­ing the freez­able state of the proxy), then I cre­ate the proxy for given class (no addi­tional inter­faces) pass­ing the cre­ated inter­cep­tor, and then I add them both (proxy and its inter­cep­tor) to the dictionary.

    I could ditch the dic­tio­nary and do that using IProx­y­Tar­ge­tAc­ces­sor, and even not vio­late SRP and extract the freez­abil­ity track­ing out of the inter­cep­tor and into a mixin, but I didn't want to intro­duce this just yet.

  • http://www.dbones.co.uk/ David Run­dle

    Many thanks for this.… its nice to see a sim­ple, yet help­ful example =)

  • http://startbigthinksmall.com/ Lars Cor­neliussen

    Funny. I'm imple­ment­ing exactly the same thing using Cas­tle Dynam­icProxy. When I tried to find a method to deter­mine if a method is a prop­erty set­ter I came to this page :-)

    You can, BTW, omit the sta­tic dic­tio­nary mem­ory leak by mix­ing in the inter­nal inter­cep­tor fol­low­ing a con­troller inter­face (in my case IFreez­able­Con­troller). Then you can just "cast" to your inter­cep­tor and con­troll the state.

  • http://kozmic.pl/Default.aspx Krzysztof Koźmic

    Lars,

    I know I can.
    But I didn't want to intro­duce all the com­plex­ity (and power) of Dynamic Proxy in the 1st part of such a long tuto­r­ial :)

  • Korvus

    Finally! A mor­bid tuto­r­ial :) The Pet is 50 years old, deceased and now, thanks to the DP, it's frozen. Cool!

  • http://kozmic.pl/Default.aspx Krzysztof Koźmic

    @Korvus ROTFLMAO