Apr 15 2010

A ghostly proxy

Take a look at the following pseudocode:

START to SaveSomething CALL Logger with 'Entering SaveSomething' BEGIN IF User Has Permission CALL PersistSomething EXCEPTION CALL Logger with 'Procedure Failed' END CALL Logger with 'Exiting SaveSomething' END SaveSomething

If you stand-back and squint your eyes, this will probably look a little familiar. This represents that all-to-familiar pattern where we blur the lines of responsibility because its the most convenient way to accomplish things like logging, permission checks, tracing, etc... Unfortunately, this can lead to things like the following making your code much harder to read, debug, etc...

#if (DEBUG) CALL Logger with 'Procedure Entered' #endif

The slippery slope should be obvious, but the more important issue is that we've mixed completely separate areas of concern making our code more inflexible. In this case, authorization, logging, and entity specific domain logic are all jumbled together. Putting this specific; and possibly terrible; example aside... this may be reasonable in some cases, but there are patterns that can provide us more flexibility. Ideally we'd be able to aggregate concerns such as these without being so tightly coupled. In this case, we'll explore a combination of the Proxy Pattern and the Interceptor Pattern which are commonly found in Aspect-Oriented Programming (AOP). The combination of these patterns creates what is loosely defined as a Ghost Proxy Object, although some usages do not include interception. Lets start with a simple Domain Object with a simple operation.

public class DomainObject : IDomainObject { private readonly IDal _dal; public DomainObject() : this(IoC.Resolve<IDal>()) { } internal DomainObject(IDal injectedDal) { _dal = injectedDal; } public virtual void SaveSomething(object thing) { _dal.SaveSomething(thing); } }

The class is pretty straightforward... get an object, and then save it. From a Domain perspective, that is the only concern this component needs to have. Now lets wrap this in a proxy and add methods to wire-up externally supplied delegates. The actual code to wire-up the delegates is not really important and would be pretty trivial to implement. suffice it to say, registered delegates will be called before and after the proxied method is called. The goal is to have a class that represents the base DomainObject while providing us with opportunities to execute externally registered logic. Additionally, all this should be accomplished without any changes to; or accommodations by; the base type aside from it being inheritable.

public sealed class ProxyObject : DomainObject, IInterceptable { /* The real domain object instance to be called */ readonly IDomainObject _realInstance; static IDictionary<string, BeginAction[]> _beginActions = new Dictionary<string, BeginAction[]>(); static IDictionary<string, EndAction[]> _endActions = new Dictionary<string, EndAction[]>(); public ProxyObject() : this(IoC.Resolve<IDal>()) { } internal ProxyObject(IDal injectedDal) { _realInstance = new DomainObject(injectedDal); } public override void SaveSomething(object thing) { this.InvokeBeginMethod(ref _beginActions, "Void SaveSomething(System.Object)", new[] { thing }); _realInstance.SaveSomething(thing); this.InvokeEndMethod(ref _endActions, "Void SaveSomething(System.Object)", new[] { thing }, null); } public void AddInterceptMethod(MemberInfo memberInfo, BeginAction beginAction, EndAction endAction) { /* Extension Method for instances of IInterceptable */ this.AddInterceptMethod(ref _beginActions, ref _endActions, memberInfo, beginAction, endAction); } public void RemoveInterceptMethod(MemberInfo memberInfo) { /* Extension Method for instances of IInterceptable */ this.RemoveInterceptMethod(ref _beginActions, ref _endActions, memberInfo); } }

Lets start by calling the un-proxied DomainObject to see the basic behavior in action.

IDomainObject realObject = new DomainObject(); realObject.SaveSomething("Foo");

Calling an instance of the proxy would produce the same result, but we need to inject additional functionality such as logging, tracing, security, etc... To do this, we must first create an instance of the Proxy and register the Delegates which will be called before and after proxied methods are called.

MethodInfo methodToIntercept = typeof(IDomainObject).GetMethod("SaveSomething"); ProxyObject proxyObject = new ProxyObject(); proxyObject.AddInterceptMethod(methodToIntercept, LogBeginAction, LogEndAction); proxyObject.AddInterceptMethod(methodToIntercept, PermissionCheckBeginAction, null);

Once registered, any calls to new instances of the proxy type will be wrapped with the intercepting delegate calls.

IDomainObject proxyDomainObject = new ProxyObject(); proxyDomainObject.SaveSomething("Foo");

As you can see this works fine, but this could be improved by using an IoC container. This gives us the flexibility to control this behavior externally, which provides a wide range of new options. In this case, my IoC Container returns an instance of ProxyObject which is mapped to the IDomainObject interface in an external configuration file.

IDomainObject proxyDomainObject2 = IoC.Resolve<IDomainObject>(); proxyDomainObject2.SaveSomething("Foo");

These patterns can provide some really interesting capabilities although; as you can see; they require some investment in additional code. These days, proxies such as this can be automatically created using Code Generation or Dynamic Proxy tools (here is a sample). Another important consideration is performance... Profile your application and you'll see more in memory which means more to be GC'd. In the end, this means things will be slower. Like anything else, this is all about options, so take a look and see where this pattern might fit into your tool bag. Enjoy...

Tags: , ,

Feb 11 2010

Hiding from the debugger

Category: Tips and TricksJoeGeeky @ 18:56

There is no doubt the modern debugger has made developers lives so much easier and without it... well... lets just not think about that. More specifically, the Microsoft Visual Studio debugger is really a beautiful piece of engineering kit. Having praised it, now lets talk about the pain it can cause us. Tools like this have become so advanced, providing so much detail that sometimes it can actually hamper our efficiency or in some cases give away more information than we are comfortable with. Consider the following examples:

  • When you have deep inheritance chains, auto-generated code for things like designers, or methods with high Cyclomatic Complexity, stepping through code can take considerably longer than you might like and if segments of the code are already trustworthy, you may wish to have the Debugger ignore them when stepping through code
  • When dealing with classes that have large numbers of private variables & properties that reflect the same values this can clutter up the variables windows makings your debugging experience less then optimal
  • When developing applications to be consumed by third-parties, you may wish to hide select members from the debugger. This could be a desired part of your obfuscation process or simply to make the debugging experience less confusing for consumers of your API

Lucky for us, these and other scenarios can be dealt with easily by using facilities provided within the System.Diagnostics namespace.

Lets start with hiding code from the Debugger:

public void MyHiddenMethod()
{ /* Do something */ }

By simply appling the attribute DebuggerHidden when stepping through code, any time this method is encountered by the debugger, it will skip over it. This will occur even if the method or a descendant has a breakpoint set.

Hiding select members can be just as easy. Lets say we have a simple variable that we want to hide. Before hiding the variable we can see that it is clearly visible in the debugger.

private string _internalMember;

To hide this member, all we need to do is apply the DebuggerBrowsable attribute:

private string _internalMember;

When debugging you will see that the member is now missing from variable windows such as Locals.

While writing this, I tried to think of some basic rules for when to apply this. The truth is, there aren't any "rules". This is something you will have to apply when it feels right for your situation. Keep in mind that applying techniques like this can lead to hiding important information, on the other hand it can make debugging experiences more productive. With that said, remember to never apply these techniques until you are absolutely sure the code being hidden is trusted. Take a look at the System.Diagnostics namespace for more tricks you can use to make you debugging experience better.

Tags: ,

Apr 30 2006

Automatic Code Generation, Code that writes itself!

Category: Selfish MotivationJoeGeeky @ 01:02

Billy Hollis once said that developers have an addiction... Writing code... After much sole searching and a little Freudian introspection, I realized that I was a code addict. Having faced my demon, I set out to address my addiction head-on.  What was the answer? Simple… write code that writes itself. 

As usual Microsoft was thinking ahead, and provided us with a very powerful .NET namespace containing tons of great classes to facilitate this process. That namespace is System.CodeDom…

Consider for a moment, how many times you’ve had to produce an information class filled with public properties and their private members. This is tedious work and really doesn’t lend itself to making you a better programmer. Like the first step in a 10-step program, my first application was geared towards making this portion of my job obsolete, allowing me to provide basic property information in a language neutral short-hand and then producing a complete code set in the language of my choice. I don’t normally post my code but this is something that more developers need to explore. To that end, the below links are provided to help proliferate this type of practice… 

Thanks Billy, you saved my soul….

Joes Property Code Generator - Binaries.zip (19.49 kb)

Joes Property Code Generator - VS 2K5 Source Code.zip (26.81 kb)

Note: You must have both the .NET Runtime and the J# 2.0 Runtime installed to use this.

Tags: ,