In a continuation from my previous post, I wanted to provide a quick example of how a combination of ContextBoundObjects and ContextAttributes can allow complete access to message interception and processing in the .Net framework (in this case, intercepting exceptions and logging them) with minimal code injection/dependencies in your existing code base simply by placing an attribute on a class, and inheriting from ContextBoundObject.
For a quick high level primer on this subject and how it relates to orthoganality (and AOP), have a look at this post first; he does a great job of explaining this. A little background as to why the ContextBoundObject exists is probably in order as well.
All applications run within an application domain, and this domain can contain numerous contexts…an application which is executing within a given app domain isn’t necessarily tied to one specific context though, it is free to switch contexts freely (meaning it is context agile); thus getting a reference to a specific object means obtaining a direct reference which makes it impossible to hook into and perform processing on the messages the object contains (method calls, exceptions, etc). By deriving an object from ContextBoundObject you force the runtime to isolate the object into a single context where it will remain for it’s entire lifetime. Any hooks into this object from other contexts are done via a runtime generated proxy which is a reference to the object; there are no direct hooks into the object itself. As it’s a proxy, it is now possible to write your own sinks to hook into the message chain and perform any type of processing you’d like. This is comparable to remoting in .Net (and indeed most of the objects needed for this live in the System.Runtime.Remoting namespace), albeit on a smaller scale.
So how does this relate to real world programming? There are certain services that need to be applied to every layer of the application and are not domain specific; in the case of the typical 3 tier app which contains a data layer, a business layer, and a presentation layer; they all need common services such as logging and exception management. The most common approach to solve this is to write a separate utility library that accomplishes the functionality you need, and then just reference it from your projects…this can create unneeded dependencies though, and in the case of exceptions means lots of try/catch blocks with logging code in each catch block (in the case of a web application, I do realize this can be centralized in Application_OnError which is great in theory, but is usually not used out in the real world). This can get a quite messy in larger applications. In this case, I’ll attempt to provide an alternate solution to this by providing a simple example that centralizes exception logging by using a ContextAttribute and a ContextBoundObject which allows the attribute to hook into the message chain.
In essence this will allow you to change code that looks like this:
public class myClass
{
private void button1_Click(object sender, System.EventArgs e)
{
try
{
anotherClass.doSomething();
}
catch (Exception exc)
{
// log the exception
ExceptionLogger.Log(exc);
}
}
}
public class anotherClass
{
public void doSomething()
{
throw new DivideByZeroException();
}
}
To something more like:
[Loggable(true, TraceLevel.Error)]
public class myClass
{
private void button1_Click(object sender, System.EventArgs e)
{
anotherClass.doSomething();
}
}
public class anotherClass : ContextBoundObject
{
public void doSomething()
{
throw new DivideByZeroException();
}
}
While it appears the exception logging code has simply vanished, it indeed has not. By adding a context bound attribute to the class, then deriving the anotherClass object from ContextBoundObject you can now hook into the message sink, then intercept and log the exception (or whatever else you want to do with it). Let’s take a look at the Loggable context bound attribute first.
A context bound attribute is basically the same thing as any other attribute, except that it derives from ContextAttribute (which in turn derives from Attribute) to hook into the context of the ContextBoundObject, as well as IContributeObjectSink so that it can participate in the message sink chain. Here’s what the code would look like for the attribute:
[AttributeUsage(AttributeTargets.Class, Inherited=true, AllowMultiple=false)]
public class LoggableAttribute : ContextAttribute, IContributeObjectSink
{
private bool _isLoggable;
private TraceLevel _level;
public LoggableAttribute(bool isLoggable, TraceLevel level)
:base("ThisIsGreatStuff")
{
_isLoggable = isLoggable;
_level = level;
if (_isLoggable)
{
// initialize your logging class here if need be
}
}
// inherited from IContributeObjectSink
public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)
{
return new LoggingSink(nextSink, this);
}
}
The two most notable changes are the call the base constructor where you must provide a simple string key value so that the runtime can keep up with the context, and the GetObjectSink method call, which taps into the message sink pipeline. Up until this point however, it’s completely useless without having a custom IMessageSink object to tap into the chain itself.
This part is also fairly trivial to do in this scenario, you simple need to create a class that derives from IMessageSink and complete the method stubs that are generated (this will hold the object reference returned in the call to GetObjectSink in the attribute). You’ll also need two member variables; one that refers to the context attribute we created above, and another to reference the sink in the message sink chain, which are the parameters passed in to LoggingSink’s constructor. Here’s the code:
public class LoggingSink : IMessageSink
{
private IMessageSink _nextSink;
private LoggableAttribute _logInfo;
public LoggingSink(IMessageSink nextSink, LoggableAttribute logInfo)
{
_nextSink = nextSink;
_logInfo = logInfo;
}
public IMessage SyncProcessMessage(IMessage msg)
{
msg = preProcess(msg);
IMessage returnMsg = _nextSink.SyncProcessMessage(msg);
return postProcess(msg, returnMsg);
}
public IMessageSink NextSink
{
get { return _nextSink; }
}
public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
{
return null;
}
private IMessage preProcess(IMessage msg)
{
return msg;
}
private IMessage postProcess(IMessage msg, IMessage returnMsg)
{
IMethodReturnMessage rm = (IMethodReturnMessage)returnMsg;
if(rm.Exception != null)
{
rm = new ReturnMessage(
new LoggableException(rm.Exception, _logInfo),
(IMethodCallMessage)msg);
// log the exception
ExceptionLogger.Log(rm.Exception);
}
return rm;
}
}
As you can see, SyncProcessMessage is where all the magic happens; it’s just a message interceptor that acts recursively on all incoming messages, and allows for both pre (perhaps some formatting, or checking for specific message parameters before continuing) and post processing (logging in this case) on the message. In postProcess, we check to see if the IMessage passed in has an associated exception attached to it; if there’s an exception then process it accordingly. The only thing left to do is create an exception container that derives from CustomException to take the place of the LoggableException I used in postProcess…I’ll leave that as an exercise to the reader as no doubt everyone should be familiar with that process.
This is just one example of how to use context attributes and context bound objects to hook into the message chain and intercept type data as it passes through; in a future post I’ll show how this can be extended to provide basic logging/tracing throughout your application, again all handled behind the scenes without the need to inject messy plumbing code into your application. The greatest benefit of the above solution is the complete abstraction of the implementation of the processing mechanism; it can be changed in isolation without affecting any of the other layers. This is extremely powerful stuff, and lends itself tremendously to aspect oriented programming.
Share this post: 
|

|

|

|

|
