free geoip December 2005 - Jayson's Blog - jaysonKnight.com
jaysonKnight.com
A conduit to the voices inside my head.

December 2005 - Jayson's Blog

  • Context Bound Objects and Context Attributes

    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.

    Filed under: ,
  • Attribute Parameters Must Be Constants

    Haacked (correctly) mentions in the comments of a previous post that using an attribute based system for the logging service I’m currently working on could be troublesome due to the fact that attribute parameters in .Net must be constants; i.e. you can’t use values provided in a configuration file as the compiler will complain loudly if you attempt to use a non-constant value.  The reason for this is simple enough:  Attributes are simply objects that get embedded into the assembly they are placed in; they provide metadata to the actual attribute object itself via either positional parameters (specified in the constructor) or named parameters (specified as read/write fields or properties).  Therefore, parameters must be constant by design. 

    A little background first.  Here’s the IL of some harness code I wrote testing out a custom attribute:

    .method private hidebysig instance void  button1_Click(object sender,
                                                           class [mscorlib]System.EventArgs e) cil managed
    {
      .custom instance void [Framework]Framework.LoggableAttribute::.ctor(bool,
                                            valuetype [System]System.Diagnostics.TraceLevel) = ( 01 00 01 04 00 00 00 00 00 )

      // Code size       29 (0x1d)
      // snipped
    } // end of method Form1::button1_Click

    As should be quite apparent from the red text, the attribute parameter data is embedded into the assembly as a series of bytes.  Thankfully, the wonders of reflection allow for easy reading of the bytes via a call to Attribute.GetCustomAttributes; once you have an instance of the attribute you’re looking for you can treat it just like any other .Net object and call properties/methods/etc to get the data you need.  Here’s a short example of how to retrieve attribute data from an attribute placed on a MemberInfo element in a parent assembly (based off the code example here):

     
    private static bool isLoggable(MemberInfo member)
    { 
     LoggableAttribute loggable = (LoggableAttribute)Attribute.GetCustomAttribute(member, 
      typeof(LoggableAttribute), true); 
     if (loggable != null)
     {
      // traceLevel defined upstream as System.Diagnostics.TraceLevel;
      traceLevel = loggable.TraceLevel;
      return loggable.IsLoggable;
     }
    } 
    

    I realize this is all custom attribute 101 stuff, but it’s still important to realize that attributes are full blown objects just like everything else in .Net; it’s just a little trickier to get an object reference to the attribute itself in that you must use reflection to get access to the contextual information from the type (or member) the attribute is placed on (as Haacked also mentioned in his comment, which is where attributes really start to shine in a scenario like this) in this case.  Powerful stuff indeed.

    So the question still remains; how to get around having to recompile your code if you want to flip an attribute’s parameter value?  The solution I’ve come up with for now is to basically allow values to be “overridden” in a configuration file, and just use that value instead in the core logging library with precedence given to the value in the configuration file (i.e. in this case if it’s false, use that value instead of the attribute’s boolean parameter…if it’s true, just ignore it and use the value specified in the attribute itself).  In essence, the attribute allows you to mark sections of code by either:

    • Setting the attribute parameter to false, which means always not logged, regardless of what the configuration file says to do.  There are plenty of scenarios where logging may not be appropriate, such as basic UI type stuff.  You could of course just leave the attribute off the member, but there are other constraints I’m building into the service that work in conjunction the attribute placement (which is outside the scope of this post for the time being).
    • Set the configuration file setting to true, which lets the individual attributes figure out what to do.

    Anyhow, that wraps up this post.  This project continues to get more and more interesting by the day; the next item on my list is to implement a ContextBoundObject scheme to handle the heavy lifting of intercepting exception/method calls, and take care of all the logging behind the scenes with minimal code injection into existing applications.  Mighty fun stuff.

    Filed under: ,
  • Getting Geared Up for Winter TV

    I don’t watch a ton of TV, but this Winter is already looking pretty good TV-wise (and as it’s looking to be an especially bad Winter over here on the East coast, that’s a good thing).  In case anyone is interested, here’s what I’ll be tuning in to:

    • Scrubs.  Finally after a long hiatus, my favorite show is returning to the air waves starting January 3rd.
    • Dirty Jobs.  New episodes start on January 10th.  Mike Rowe is my hero, and is an extremely funny guy.  From his bio:  “In cleaner days, Mike Rowe sang professionally with the Baltimore Opera.”  Huh?
    • The Sopranos.  I don’t remember the exact date the new season starts, but it’s soon.  Too bad Drea de Matteo got offed last season.
    • Grey’s Anatomy.  New episodes begin January 8th.  This was last year’s break out series IMO, and is very well written.
    • Desperate Housewives.  Yes, I’m not afraid to mention that I do watch this show…it’s mindlessly funny.
    • And finally, something I’ve been waiting 4 years for, The Winter Olympics gear up on February 10th on NBC (and broadcast in HiDef this year as well).  This is my absolute favorite event/show to watch on TV, namely due to the fact that I used to ski competitively (downhill and super-g for anyone taking notes) when I lived in New England a while back.

    I will be absolutely glued to the TV during the Olympics and can’t wait for the games to begin.  Favorite event?  Super G of course!  Favorite non-skiing event?  It’s a toss up between speed skating and skeleton (which made it’s return after decades of banishment at the last Winter games).  Unlike most, I usually pass on the figure skating.

  • Best of JaysonKnight.com -- Happy New Year!

    One thing that really bugs me about blogs is that it’s still really damn hard to find specific information on a blog once you find it.  Sure, we have things like post categories, and more recently blogs have appeared that support searching said blog for information…but the only true way to glean information from a blog is to read it from beginning to end, and who has time to do that? 

    I’ve been blogging for 2 years now, and I’m almost at 500 posts…I certainly don’t expect new readers to start from day one and read this in its entirety (unless you’re really really bored).  So this year I decided to put together a “best of” JaysonKnight.com (well, the posts I like best at least) for your reading and/or insomnia fixing pleasure.  Here’s a list of my favorite (and most heavily Googled) posts I’ve made over the years:

    I’ll end it there as this post has gone on long enough, but hopefully there’s some interesting stuff above for any of the new people.  In other JK.com news, I am once again number 1 on Google for ‘Jayson Blog’, ‘Jayson Knight’ (amongst others), and I’m number 12 for just ‘Jayson’…yet my traffic continues to languish since moving to the CS platform.

    Anyways, I plan on having a very low key New Years this year…last year I had a dozen or so folks over (and spent a few days recovering); this year a buddy of mine is graciously playing host to pretty much the same crowd out at his pad, most definitely will be a good time.

  • Akismet -- Online Comment/Trackback Spam Blacklist

    I was having a discussion recently with some colleagues over on CS.org about setting up some sort of centralized comment/trackback spam blacklist as it’s really becoming quite a pain the ass lately for lots of folks (plus it’s a big push for the next version of CS to clamp down a bit more on spam). 

    Knowing that all the great ideas I come up with have more than likely already been done, I set out to see if indeed someone had given it a shot; lo and behold someone has.  It looks like it was originally built for WordPress, but they have an open API so anyone with an API key can tap into it.  Something like this is long overdue in the blogging realm, and the CS developers have jumped all over it…so hopefully blog spam will be ancient history for us CS folks in the 2.0 release (or for anyone who chooses to use the akismet API).

  • Performancing for Firefox Extension

    The good folks over at Performancing have released what looks to be a very promising Firefox extension:  Performancing for Firefox.  I haven’t been able to get much functionality out of it yet using the MetaWeblog API (which is what Community Server uses) account settings, but apparently it’s working for other account types.  Regardless, it looks very promising, so here’s hoping they get the MetaWeblog stuff cleaned up.  I dare say it could even replace my beloved BlogJet if all the kinks get ironed out.
  • You Can't Please Everyone All Of The Time

    I mentioned earlier that I’ve only had one grievance as of late…normally I wouldn’t post about anyone disagreeing with me about something, but it was his whole (mis)demeanor about the topic that really struck a chord. 

    While I agree with him on a superfluous level in that Microsoft’s support could use a bit of work (as could most tech oriented support), I totally disagree with the way he lambasted my attempts to explain the situation to him, in which I had the best intentions.  It definitely reeks of (somewhat) typical developer ego wherein the developer thinks his time (and money) are more important than anyone else's, including the company who supplies him with tools which allow him to make a living.  Negativity always surpasses the positive, and perceived perception usually succumbs to the throngs of the “me too’s”…in this case, the group I used to work with at MS gets made out to be the bad guys, even though we were just doing our job given the tools/resources that were provided to us.  Unreal.  The sheer lunacy of his attitude about the whole situation is enough to make even the most seasoned developer shudder IMO.

    It’s also worth mentioning that I emailed this guy a product key that would get him up and running; I’ve yet to hear anything back from him.  What really drives me nuts is that his entire post is based around not having a key for a CTP of a product that won’t be released for at least six months…the CTP’s are a gift from MS; not having a key to get it installed isn’t going to hold up production of his software, and most definitely isn’t costing him any money.

    Anywho, read the thread here.  Maybe I was in the wrong, but I seriously doubt it.

    Filed under:
  • A Festivus for the Rest of Us

    The Airing of GrievancesIn an effort to be PC (that’s politically correct) this year, I want to wish everyone a happy festivus.  I already have my festivus pole up, and in the words of Frank Costanza, “I’ve got a lot of problems with you people, and now you’re going to hear about them!”  May the airing of the grievances commence.

    Actually, I only have a problem with one person right now (who really chapped my ass online recently), but to keep in the spirit of the holidays, I’ll post about that later on.  I’m hoping this person is just stressed out from all of the holiday mayhem that generally ensues around this time of year.

    In all seriousness, happy [insert whatever you celebrate here]…enjoy your time with family and friends, eat like there’s no tomorrow, and most of all just have fun!

  • About Jayson

    After two years of blogging, I finally got around to adding an “about me” page…I’m pretty terrible at introducing myself, but you can view it here.
  • Performancing Sits Down with Rob Howard

    Performancing (which is one of my new favorite sites) sat down with Rob Howard (CEO of Telligent Systems, the creator of Community Server in case you live in a black hole); the discussion ranges from Rob’s history at MS (and why he quit to form Telligent), to Telligent’s business model and how they make money given that CS is Open Source, to MS on OSS, meeting Bill Gates, and of course his take on blogging and what it’s done to change the way businesses operate.  It goes without saying that Rob is one of the brightest guys in the biz right now, so it’s definitely worth a read.

    In other news, I had the first (hopefully of many) screens with MS today for the IIS support engineer position.  It was pretty tough, but overall pretty fun.  Needless to say, there’s quite a bit about IIS that’s unknown to me (mainly the very low level workings of it), but I feel much more confident than after my SQL Server interview several months ago.  Unfortunately with it being the holidays (and the fact that MS employees get a ridiculous amount of paid time off), I probably won’t get any face to face time until after the beginning of the year.  That’s fine, more time to study!

    Here’s one teaser of a question they asked me (and I nailed):  What must ASP.NET apps support if session state is hosted out of process?  Yes, I realize that session state in ASP.NET is a no-no, but most apps still use it (though CS does not use session at all).

1 2 3 4 Next >

Copyright © :: JaysonKnight.com
External Content © :: Respective Authors

Terms of Service/Privacy Policy