Friday, July 30, 2010
 
   
 
Welcome to my site

First let me say thanks for stopping by my site. My name is David Hanson-Graville and I am a IT consultant working in the UK. Let me make it clear, I am passionate about technology and specifically .net and its various forms. I've programmed in a range of langages, but I can say, I am now at my happiest when coding with c#. I hope my blog is an enjoyable & educational read and please feel free to email me at David.Hanson@OnTheBlog.net if you have any questions. 

Raising binding exceptions in WPF & Silverlight with .net 4.0 Dynamics Minimize
Location: BlogsOnTheBlog    
Posted by: David Hanson Mon, 14 Dec 2009 14:00:19 GMT
It’s been a while since I’ve posted anything. Sorry about that. This has mainly been due to a busy social and work schedule which has not given me the time I’ve needed to create the content that’s been floating around my desk as post it notes. In this post I would like to revisit dynamic typing support in .NET 4.0 and apply it to a real world scenario.
 
Proxying and Interception with Dynamics
 
If you’re like me then I imagine you have been playing with .NET 4.0 for quite a while now. There is a wealth of new language features to play with in this release and I’m excited about the RTM come march. One of the features I have discussed previously is the support for dynamic typing. Dynamics brings with it some new approaches to problems that static languages have often found difficult to solve. In this post we will be looking at the topic of dynamic proxying, interception and AOP.
 
The common goal of these techniques is to allow a programmer to be able to inject code transparently before and after a method has been invoked. This is illustrated below in the diagram below.
 

 
If you have not come across this concept before you may ask what is the point of intercepting a method before and after execution. A layer of indirection is particularly useful when trying to inject code between a client and our objects. The reason we do this as it allows us to implement secondary support functions such as logging, transaction management, code contracts and other utility code outside the body of our method. What we find when we implement an proxy pattern is that once we have removed this secondary code the readability of our code improves tremendously and we have also increased our separation of concerns.
 
Now you can see the benefits of this approach, let’s turn our attention to how we go about implementing this in our code. Luckily for us there has been a lot of smart people working hard to help make this process easier. If you do a search for proxy pattern’s or aspect orientated programming you will find a heap of information. When it comes to AOP there are a number of frameworks which have already been developed. These are listed below. 
 
Aspect#
Encase AOP
Spring.NET
Aspect.NET
AspectDNG
Dynamic Proxy
Compose*
Loom.NET
PostSharp
 
Each of these frameworks make use of a number techniques to the injection of code both before and after execution of a method. These generally fall into 4 categories.
 
MSIL injection – Here we inject MSIL code into the body of the method being executed. (Post sharp)
 
Runtime dynamic injection – Using techniques such as reflection we invoke methods dynamically.
 
Type builder injection – Related to runtime injection, we create a type based on the type we wish to proxy and then marshal requests through this type. (Dynamic Proxy)
 
Container injection – Requests pass through a container which invokes code before and after our method being executed.
 
WPF Bindings with dynamic objects
 
So now that C# 4.0 brings with it support for dynamic objects I thought I would take a look at how I can go about implementing a simple interception pattern for static objects. I am currently working on a project which makes extensive use of WPF. We follow and MVP pattern and our views are bound directly to our presenters in order to reduce the amount of code in our views. If you have worked with WPF you will probably know some of the great benefits of the binding model. Using simple XAML expressions you can bind controls to properties deep down in your object graph. However, sometimes you need to do something a little more complicated. If you have use data templates for list controls you may have found the need to bind to something that’s way up the visual tree. Below is a good example of this.
 
<Button Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.AddPersonComand}"/>
 
In this scenario I have bound a button command to a command definition which sits on my presenter. However, you will notice I made a deliberate mistake. I spelt the word command wrong in the path. As a result WPF will fail to locate the binding and when I actually click on this button nothing will happen. This is frustrating and there things I can do to identify this issue. Bea Costa has some good posts around this topic here. The problem with these approaches are that none of them are particularly obvious to the developer.
 
What I would really like is to be able to throw an exception whenever a binding fails. I would also like to show debug statements printed in my output window when a binding access occurs. As I already have a substantial codebase that I do not have the time or urge to go through in order to support this functionality I want to do it in a low impact way.
 
Building the Dynamic Binding Interceptor
 
When we look at how I bind my presenter you can see it’s a fairly simple affair. My view Implements IBindableView which exposes the Views DataContext to the presenter. Therefore it’s a trivial process for creating the binding.
 
View.DataContext = this;
 
It at this point where I would like to attack the problem at hand. As dynamic objects use dynamic dispatch to query a type, my best approach is to set the views data context to be a dynamic object of my choice and then route the requests to my presenter. The key thing here is that I do not want to change my existing presenter code in anyway. I want my binding code to look like this.
 
View.DataContext = new BindingInterceptor(this);
 
Given that, I need to create my new interceptor class and implement the behaviours I mentioned. To do this we need to create a new class that inherits from DynamicObject and provide a constructor which takes our source for binding. This class is show below.
 
    ///
    /// Provides interception of properties for bound objects.
    ///
    public class BindingInterceptor: DynamicObject
    {
        protected dynamic Source{ get; set;}
 
        public BindingInterceptor(dynamic source)
        {
            Source = source;
        }
    }
 
You can see that we store the source for future use. The interception of properties will be achieved by overriding two methods on DynamicObject. These are shown below.
 
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            return base.TryGetMember(binder, out result);
        }
 
        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            return base.TrySetMember(binder, value);
        }
 
These two methods will be invoked whenever our View tries to access a property on its data context, which in our case will be the our BindingInterceptor. It would be a simple task to implement the desired behaviour of logging and throwing exceptions within our BindingInterceptor, however on this occasion I would like something a little more flexible. Instead I would like to be able to instruct the BindingInterceptor of the behaviours I would like it to execute before and after accessing a property. Looking back at our binding code, I would now rather it looked more like the following.
 
bindingInterceptor
    .OnGet
        .BeforeGet((binding) => Debug.WriteLine(string.Format("TRY GET: Name={0}", binding.Name)))
        .AfterGet((binding, value) => Debug.WriteLine(string.Format("GET RESULT: Name={0}, Value={1}, Result={2}", binding.Name, value, "Success")))
        .IfGetException((binding, exception) => { throw new BindingException(string.Format("Failed to Get [{0}]", binding.Name), exception); })
    .OnSet
        .BeforeSet((binding, value) => Debug.WriteLine(string.Format("TRY SET: Name={0}, Value={1}", binding.Name, value)))
        .AfterSet((binding, value) => Debug.WriteLine(string.Format("SET RESULT: Name={0}, Value={1}, Result={2}", binding.Name,value, "Success")))
        .IfSetException((binding, exception) => { throw new BindingException(string.Format("Failed to Set [{0}]", binding.Name), exception); });
 
 
Although this code is more verbose, it does allow me to specify exactly what I would like implemented on access of properties. It also uses a fluent interface which to a reader who is new to the code should be relatively easy to follow. In order to implement this in our BindingInterceptor we need to add a few simple methods which will take an Action as their input and return an instance of the BindingInterceptor. These methods are shown below.
 
public BindingInterceptor OnGet { get { return this; } }
 
public BindingInterceptor OnSet { get { return this; } }
 
public BindingInterceptor BeforeGet(Action<GetMemberBinder> beforeGet)
{
    BeforeGetPropertyDelegate = beforeGet;
    return this;
}
 
public BindingInterceptor AfterGet(Action<GetMemberBinder, object> afterGet)
{
    AfterGetPropertyDelegate = afterGet;
    return this;
}
 
public BindingInterceptor BeforeSet(Action<SetMemberBinder, object> beforeSet)
{
    BeforeSetPropertyDelegate = beforeSet;
    return this;
}
 
public BindingInterceptor AfterSet(Action<SetMemberBinder, object> afterSet)
{
    AftersetPropertyDelegate = afterSet;
    return this;
}
 
public BindingInterceptor IfGetException(Action<GetMemberBinder,Exception> getException)
{
    GetExceptionDelegate = getException;
    return this;
}
 
public BindingInterceptor IfSetException(Action<SetMemberBinder,Exception> setException)
{
    SetExceptionDelegate = setException;
    return this;
}
 
Now we have the ability to inform the BindingInterceptor of the behaviours we would like it to carry out, the final task for us to do is make sure that the these behaviours are invoked and that the value is marshalled to and from our source presenter. I have highlighted this below.
 
        private void GetValue(GetMemberBinder binder, out object result)
        {
            try
            {
                if (BeforeGetPropertyDelegate != null) BeforeGetPropertyDelegate(binder);
 
                Type type = Source.GetType();
                result = type.GetProperties().FirstOrDefault(p => p.Name == binder.Name).GetValue(Source, null);
 
                if (AfterGetPropertyDelegate != null) AfterGetPropertyDelegate(binder, result);
            }
            catch (Exception exception)
            {
                if (GetExceptionDelegate != null) GetExceptionDelegate(binder, exception);
            }
        }
 
        private void SetValue(SetMemberBinder binder, object value)
        {
            try
            {
                if (BeforeSetPropertyDelegate != null) BeforeSetPropertyDelegate(binder, value);
 
                Type type = Source.GetType();
                type.GetProperties().FirstOrDefault(p => p.Name == binder.Name).SetValue(Source,value,null);
 
                if (AftersetPropertyDelegate != null) AftersetPropertyDelegate(binder, value);
            }
            catch (Exception exception)
            {
                if (SetExceptionDelegate != null) SetExceptionDelegate(binder, exception);
            }
        }
 
 
To test our BindingInterceptor I need to create a simple user interface. I want to be able to bind two presenters, one good presenter that meets all the requirements of the bound controls and one bad presenter that wont.

 
When we click the “Bind good presenter” option we use our BindingInterceptor to wrap our presenter instance and then set this as the data context of the window. Doing this provides us with the following output in the debug window. 
 
----------------BEGIN GET--------------------
TRY GET: Name=LikeDynamics
GET RESULT: Name=LikeDynamics, Value=True, Result=Success
----------------END GET----------------------
----------------BEGIN GET--------------------
TRY GET: Name=WantToSeeMore
GET RESULT: Name=WantToSeeMore, Value=True, Result=Success
----------------END GET----------------------
----------------BEGIN GET--------------------
TRY GET: Name=Comments
GET RESULT: Name=Comments, Value=Good presenter is bound., Result=Success
----------------END GET----------------------
 
 
You can see the initial binding of the data context causes our control bindings to refresh the values from their source. Each of these requests is serviced via our BindingInterceptor. If we then uncheck the “I like .net 4.0 dynamics?” checkbox we can see the value being passed from the windows through our interceptor and into our good presenter.
 
----------------BEGIN SET--------------------
TRY SET: Name=LikeDynamics, Value=False
SET RESULT: Name=LikeDynamics, Value=False, Result=Success
----------------END SET----------------------
----------------BEGIN GET--------------------
TRY GET: Name=LikeDynamics
GET RESULT: Name=LikeDynamics, Value=False, Result=Success
----------------END GET----------------------
 
 
Now we have met the first objective of our interceptor class. We have provided a level of logging without having to change our existing presenter code. Our second objective was to raise exceptions when a binding fails. We do this by selecting the “Bind Bad Presenter” option which does not have the properties required for binding.
 
----------------BEGIN GET--------------------
TRY GET: Name=LikeDynamics
System.Windows.Data Error: 17 : Cannot get 'LikeDynamics' value (type 'Object') from '' (type 'BindingInterceptor'). BindingExpression:Path=LikeDynamics; DataItem='BindingInterceptor' (HashCode=7063836); target element is 'CheckBox' (Name=''); target property is 'IsChecked' (type 'Nullable`1') BindingException:'DynamicInterceptor.BindingException: Failed to Get [LikeDynamics] ---> Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot perform runtime binding on a null reference
 
This time we can see that the request to read the property “LikeDynamics” fails with an Binding exception. This is as expected as we defined this in our BindingInterceptor behaviours. However, unfortunately for us the application does not raise any exceptions and therefore the binding is invisible. This is NOT what we want. The reason this occurs is due to the fact that when WPF attempts to access a binding it is wrapped in an TryCatch block and the exception is hidden. As part of this post I did take the time to look through the .NET source code and actually found the code where this occurs. I noticed that all exceptions are ignored accept a number of Critical exception types. These exceptions such as StackOverflow, OutOfMemory, NullReference are the only ones which will bubble up to the surface. Therefore If I want my custom binding exception to be raised, I need to ensure the exception inherits from NullReferenceException. Making this small change and rebinding to the bad presenter now causes an exception to be thrown.
 
Conclusion
 
In this post I wanted to introduce a new approach to proxying using c# 4.0 dynamics. This simple example should have provided you with a good insight into interception techniques. From there it opens the door for whole range of exciting opportunities to solve complex problems. You can see the code required to implement this pattern is minimal. I plan to follow up this post with a series of posts which will outline some cool uses for dynamic interception in a range of problems. This approach can be used for both Silverlight and WPF as Microsoft are making great efforts to support dynamics across technologies.
 
If you want the source code for this post you can download it here.
Permalink |  Trackback

Your name:
Title:
Comment:
Security Code
Enter the code shown above in the box below
Add Comment   Cancel 
Tweets Minimize
Twitter / LordHanson
  1. LordHanson: Flash on iPad....nice. http://www.tipb.com/2010/07/04/frash-android-flash-ported-ipad/

    Published Sun, 04 Jul 2010 22:07:55 +0000 by
  2. LordHanson: Anyone noticed that when typing on your iPhone it sounds like your holding a gieger counter?

    Published Sun, 04 Jul 2010 22:05:28 +0000 by
  3. LordHanson: Missing wacko's music... What's happened to the album he was working on before he died?

    Published Fri, 25 Jun 2010 23:01:45 +0000 by
  4. LordHanson: New version of Connectify cannot recognise my active Internet connection! Had to roll back to previous version! #fail

    Published Fri, 25 Jun 2010 22:54:54 +0000 by
  5. LordHanson: vuvuzela blowing spoils the world cup! Fact!

    Published Mon, 14 Jun 2010 05:08:43 +0000 by
  6. LordHanson: About http://www.theaustralian.com.au/business/news/us-competition-regulators-to-investigate-apple/story-e6frg90x-1225878779986

    Published Mon, 14 Jun 2010 00:04:45 +0000 by
  7. LordHanson: In the camper van and a storm is coming.....How exciting.

    Published Sun, 25 Apr 2010 04:39:48 +0000 by
  8. LordHanson: My vaio p is doing well while travelling. 3g Internet, HD movies, digital tv, photo editing, wifi router for iPods and much more. Love it

    Published Wed, 10 Mar 2010 10:29:19 +0000 by
  9. LordHanson: Ok so I need to stay techie while away from a computer for a year. Anyone got any ideas.

    Published Mon, 22 Feb 2010 12:31:09 +0000 by
  10. LordHanson: Sitting in YHA Glebe Sydney waiting for the movie night to start

    Published Thu, 18 Feb 2010 08:13:10 +0000 by
  11. LordHanson: I finished work today in prep for travelling. I must admit as i left the office i felt a little emotional. Sign of a good job with great ...

    Published Tue, 26 Jan 2010 17:48:49 +0000 by
  12. LordHanson: Lots of sick sounding people creeping onto the trains today. Stay away stay away!

    Published Fri, 22 Jan 2010 08:14:36 +0000 by
  13. LordHanson: LMAO RT @colmbrophy: so have you seen who owns http://wwwbing.com ? it's not microsoft

    Published Tue, 19 Jan 2010 17:35:43 +0000 by
  14. LordHanson: RT @TeemuHyn: RT @eldarmurtazin: Hate Windows Mobile 7. No apps from previous versions of WM working here. Not compatible at all.

    Published Sun, 17 Jan 2010 19:01:29 +0000 by
  15. LordHanson: The girlfriend has gone all science on me.... She has her head in books about quasars!

    Published Sat, 16 Jan 2010 16:38:58 +0000 by
  16. LordHanson: New blog post: Invoking generic methods with Expression.Call http://bit.ly/5g99Ih

    Published Sat, 16 Jan 2010 16:34:00 +0000 by
  17. LordHanson: Found a nice way to invoke generic methods using expression trees and importantly avoiding Type.Getmethods() which you normally have to do!

    Published Fri, 15 Jan 2010 18:55:38 +0000 by
  18. LordHanson: Tried a dummy run of packing my backpack last night. Just managed to get it all in. The sleeping bag takes half the space. Not good.

    Published Fri, 15 Jan 2010 08:28:47 +0000 by
  19. LordHanson: Why do we get headaches for no apparent reason?

    Published Tue, 12 Jan 2010 15:28:29 +0000 by
  20. LordHanson: @swhelband beer time my friend

    Published Sun, 10 Jan 2010 21:49:44 +0000 by
Print  
Archive Minimize
Print  
Contact me Minimize
Print  
Microsoft Certs Minimize







Print  
Silverlight News Minimize
Silverlight - Google News
  1. Top 10 Things I Wish I Knew Before I Started My Silverlight 4 Project - Redmond Developer News

    Published Thu, 29 Jul 2010 23:21:01 GMT+00:00 by
  2. Microsoft's Flash challenger Silverlight hits Symbian - Register

    Published Tue, 06 Jul 2010 18:54:39 GMT+00:00 by
  3. Windows Phone 7 misses big-business support tools - Register

    Published Mon, 26 Jul 2010 20:32:23 GMT+00:00 by
  4. Neustar Reports Q2 Results, Stock Repurchase - TMCnet

    Published Fri, 30 Jul 2010 13:13:57 GMT+00:00 by
  5. Intertainment begins commercial rollout of Ad Taffy - PR Newswire (press release)

    Published Fri, 30 Jul 2010 14:19:22 GMT+00:00 by
  6. Download Microsoft Expression Studio Ultimate 4.0.20525.0 Free Trial / Full ... - Soft Sailor (blog)

    Published Fri, 30 Jul 2010 08:50:54 GMT+00:00 by
  7. Managing change in the application portfolio - Register

    Published Thu, 29 Jul 2010 09:36:57 GMT+00:00 by
  8. Queen Victoria in Liverpool panoramic picture - Liverpool Echo

    Published Mon, 26 Jul 2010 11:56:30 GMT+00:00 by
  9. AEBN's Silverlight Player Gains Traction with Users - AVN News (press release)

    Published Tue, 27 Jul 2010 20:28:37 GMT+00:00 by
  10. Written by David Conrad - iProgrammer

    Published Tue, 27 Jul 2010 12:39:37 GMT+00:00 by
Print