SgDotNet
Singapore Professional .NET User Group -For Cool Developers

Interception && custom attribute

rated by 0 users
This post has 1 Reply | 0 Followers

Top 25 Contributor
Posts 232
Thanh Posted: 05-08-2005 12:22 AM

We often see COM+ code written like this:

[ObjectPooling(MinPoolSize = 1, MaxPoolSize = 5)]
public class Account : ServicedComponent
{
  ........
}

All we have to do is to have our class inherited from ServicedComponent and declare the custom attribute ObjectPooling, the run-time engine automatically creates the pool object and manages it for you. I often wonder how does it work? The answer lies in the ContextBoundObject. The ServicedComponent itself inherits from the ContextBoundObject. If you really want to know it in detail, please go to this link http://msdn.microsoft.com/msdnmag/issues/03/03/ContextsinNET/default.aspx For those who are familiar with .NET Remoting, the internal plumbing is very similar. 

As I'm learning the why and how of this technology, it's always good to produce a simple and practicle example without all the jargons added to it to further complicate things. Below is a sample code with brief explanation:

Client.cs

using System;
using AOP;

namespace Test
{
  public class Test
  {
    public static void Main(string[] args)
    {
      Target obj = new Target();
      Console.WriteLine(obj.Hello("My message here"));
      Console.WriteLine(obj.Add(2, 3));
    }
  }
}

1. When the client tries to create an instance of the Target class with the [MessageAttribute] attached to it, the ContextBoundObject kicks in and allow developer to inject code into the process before the actual instance is returned to the client. This process is called Interception.
2. In this case, and instance of the MessageAttribute class is created.
3. If you look carefully at the MessageAttribute class, you will see this line [AttributeUsage(AttributeTargets.Class)]. What it really means is this class can be used as a custom attribute to target any class. That's why we can use it as a custom attribute for the Target class.
4. The GetPropertiesForNewContext method of the MessageAttribute class is triggered and create a MessageProperty class.
5. The MessageProperty class is responsible for creating the message server sink which is used to process message synchronously or asynchronously.
6. When the message is completely processed by the server sink, it will eventually reachs the server object and does whatever it's asked to do, and return whatever it's asked to return.

Custom attributes by itself is not so useful. But if it's being used together with the ContextBoundObject in this way, it yields tremendous power to the hand of developer. COM+, Code Access Security, Role Based Security and many other classes use custom attributes extensively in their internal implementation.    

AOP.cs // COM+ server

using System;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Messaging;

namespace AOP // Aspect Oriented Programming
{
  [MessageAttribute]
  public class Target : ContextBoundObject
  {
    public Target() {}
   
    public string Hello(string Name)
    {
      return "Hello " + Name;
    }
     
    public string Add(int a, int b)
    {
      int Sum = a + b;
      return "The sum is " + Sum.ToString();
    }
  } 
 
  [AttributeUsage(AttributeTargets.Class)]
  public class MessageAttribute : Attribute, IContextAttribute
  {
    public MessageAttribute() {}
   
    public void GetPropertiesForNewContext(IConstructionCallMessage Msg)
    {
      MessageProperty Property = new MessageProperty();
      Msg.ContextProperties.Add(Property);
    }
   
    public bool IsContextOK(Context ctx, IConstructionCallMessage Msg)
    {
      return false;
    }   
  }
 
  public class MessageProperty : IContextProperty, IContributeServerContextSink
  {
    public MessageProperty() {}
   
    public string Name
    {
      get { return "MessageProperty"; }
    }
   
    public bool IsNewContextOK(Context ctx)
    {
      return true;
    }
   
    public void Freeze(Context NewContext) {}
   
    public IMessageSink GetServerContextSink(IMessageSink NextSink)
    {
      return new LoggingServerSink(NextSink);
    }
  }
 
  public class LoggingServerSink : IMessageSink
  {
    private IMessageSink Next;
   
    public LoggingServerSink(IMessageSink Next)
    {
      this.Next = Next;
    }
   
    public IMessage SyncProcessMessage(IMessage Msg)
    {
      Console.WriteLine(Msg.ToString());     
      return Next.SyncProcessMessage(Msg);
    }
   
    public IMessageSink NextSink
    {
      get { return this.Next; }
    }
   
    public IMessageCtrl AsyncProcessMessage(IMessage Msg, IMessageSink ReplySink)
    {
      return null;
    }
  }
}     

Type the 2 lines below at the command line prompt to compile the codes.
csc /t:library AOP.cs
csc /r:AOP.dll Client.cs

Hope it helps

Top 10 Contributor
Posts 1,626
Can also read about it here.
Software development made easy with Paladin RAD Framework. Save some trees, use Stickies.NET
Page 1 of 1 (2 items) | RSS
Copyright SgDotNet 2004-2008
Powered by Community Server (Commercial Edition), by Telligent Systems