Castle Dynamic Proxy tutorial part XV: Patterns and Antipatterns

We’ve covered almost all of Dynamic Proxy. If you followed along through this series, you now know 95% of Dynamic Proxy 2.1 features that get used 99,9% of the time. Now is the time to wrap up, and with that we’ll review some of the most common pitfalls that you may encounter when developing code on top of Dynamic Proxy.

 

Leaking this

Consider this simple interface/class pair

public interface IFoo
{
    IFoo Bar();
}
 
public class Foo : IFoo
{
    public IFoo Bar()
    {
        return this;
    }
}

Now, let’s say we create a proxy for IFoo with target and use it like this:

var foo = GetFoo(); // returns proxy
var bar = foo.Bar();
bar.Bar();

Can you see the bug here? The second call is performed not on a proxy but on a target object itself! Our proxy is leaking its target.

This issue obviously does not affect class proxies (since in that case proxy and target are the same object). Why does not Dynamic Proxy handle this scenario on its own? Because there’s no general easy way to handle this. The example I showed is the most trivial one, but proxied object can leak this in a myriad of different ways. It can leak it as a property of returned object, it can leak it as sender argument of raised event, it can assign this to some global variable, it can pass itself to a method on one of its own arguments etc. Dynamic Proxy can’t predict any of these, nor should it.

In some of these cases there is often not much you can do about it, and its good to know that problem like this exist, and understand its consequences. In other cases though, fixing the issue is very simple indeed.

public class LeakingThisInterceptor:IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        invocation.Proceed();
        if(invocation.ReturnValue == invocation.InvocationTarget)
        {
            invocation.ReturnValue = invocation.Proxy;
        }
    }
}

You add an interceptor (put it as last one in the interceptors pipeline), that switches the leaking target back to proxy instance. It’s as simple as that. Notice that this interceptor is targeted specifically at the scenario from our example above (target leaking via return value). For each case you will need a dedicated interceptor.

 

Override equality

One of the most common mistakes when it comes to Dynamic Proxy is not overriding Equals/GetHashCode methods on proxy generation hooks and interceptor selectors, which means you’re giving up caching and that in turn coupled with bugs in BCL means performance hit (plus increased memory consumption).

Solution is very simple, and there’s no exceptions to this rule – always override Equals/GetHashCode methods on all your classes implementing either IProxyGenerationHook or IInterceptorSelector.

 

Make your Proxy Generation Hooks purely functional

Pure function, is a function that for given set of inputs always returns the same output. In case of proxy generation hook, it means that two equal (as specified by overriden Equals/GetHashCode methods) proxy generation hooks will for given type to proxy return the same values from their methods, and when asked again about the same type will again return the same values/throw the same exceptions.

This is a major assumption that Dynamic Proxy makes, and that’s what makes the caching mechanism work. If proxy generation hook is equal to the one already used to generate a proxy type, Dynamic Proxy will assume it would return the same values as the other one, which would result in identical proxy type, so it cuts through the generation process and returns the existing proxy type.

 

Make your supporting classes serializable

If you’re going to be serializing your proxies, you should make all the classes that go with it serializable. That includes proxy generation hooks, interceptors and interceptor selectors. Otherwise you will get an exception when trying to serialize your proxies. It is not mandatory, but I find it useful. Notice that you will need this also when persisting your proxy assembly to disk.

 

Use ProxyGenerationHooks and InterceptorSelectors for fine grained control

Do your interceptor’s methods look like this?

public void Intercept(IInvocation invocation)
{
    if(invocation.TargetType!=typeof(Foo))
    {
        invocation.Proceed();
        return;
    }
    if(invocation.Method.Name!="Bar")
    {
        invocation.Proceed();
        return;
    }
    if(invocation.Method.GetParameters().Length!=3)
    {
        invocation.Proceed();
        return;
    }
    DoSomeActualWork(invocation);
}

If they do this often means you’re doing something wrong. Move the decisions to proxy generation hook and interceptor selector

  • Do I ever want to intercept this method? If the answer is no, use proxy generation hook to filter it out of methods to proxy.

Notice that due to bug in Dynamic Proxy 2.1, if you choose not to proxy method on interface proxy, you will get an exception. Workaround for this is to say you want to intercept the method, and then use interceptor selector to return no interceptors for the method. This bug is fixed in Dynamic Proxy 2.2

  • If I do want to intercept this method, which interceptors do I want to use? Do I need all of them? Do I need just a single one? Use interceptor selector to control this.

On the other hand, remember that as every feature this one is also a double edged sword. Too liberal use of proxy generation hooks and interceptor selectors may greatly decrease efficiency of proxy type caching, which may hurt your performance. As always think how much control you need and what the implications on caching will be. Sometimes single if on top of your interceptor is lesser evil than increasing number of proxies required tenfold. As always – use the profiler in scenarios that mimic your production scenarios as closely as possible to check which option is the best for you.

 

SRP applies to interceptors

SRP stands for Single Responsibility Principle, which means that a class should do just one thing. Many people seem to forget about it when it comes to interceptors. They create one monstrous interceptor class that tries to do all the things they need from Dynamic Proxy – logging, security checking, parameter verification, augmenting target objects with behavior and many more.

Remember that Dynamic Proxy lets you have many interceptors per method call. Use this ability to split behavior between interceptors. You may end up with some general purpose interceptors for things like logging that you use for each intercepted method on each class. As long as all it does is logging – that’s ok.

You may end up with some interceptors that are used for methods on just some classes, like classes inheriting from common base class. As long as these interceptors do just one thing – that’s fine.

You may end up with some interceptors that exist solely for the purpose of intercepting just a single method on specific class or interface. That also is fine. Use interceptor selectors to match interceptors to their respective targets, and don’t be afraid to have multiple interceptors per method.

Technorati Tags: ,

Posted 10-30-2009 12:32 PM by Krzysztof Koźmic
Filed under:

[Advertisement]

Comments

DotNetShoutout wrote Castle Dynamic Proxy tutorial part XV: Patterns and Antipatterns - Krzysztof Kozmic - Devlicio.us
on 11-01-2009 1:30 AM

Thank you for submitting this cool story - Trackback from DotNetShoutout

Colour Coding wrote Decorator Pattern: The Leaking This Problem
on 03-26-2010 5:03 PM

Decorator Pattern: The Leaking This Problem

Sanjay wrote re: Castle Dynamic Proxy tutorial part XV: Patterns and Antipatterns
on 12-22-2010 10:03 PM

Hi, Thanks for this blog post, however the link - kozmic.pl/.../castle-dynamic-proxy-tutorial.aspx, seems to be be broken, couldnt reach to any other part of this tutorial.

Sanjay wrote re: Castle Dynamic Proxy tutorial part XV: Patterns and Antipatterns
on 12-22-2010 10:35 PM

Ok.... looks like I got the latest link - kozmic.pl/dynamic-proxy-tutorial

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)