title: How to chain message sinks in a context bound object (aspect oriented programming)
body: <p>I am trying to use <code>ContextBoundObject</code> and message sinks to inject some aspects into my code.</p>
  
  <p>My problem is that my aspect is being called only once - 
      when I make the call: <code>myFacadee.GetValue("Tie")</code>
      I would expect to see my caching aspect be called twice</p>
  
  <ol>
  <li>Once for the '<code>GetValue</code>' method</li>
  <li>Secondly for the '<code>GetValues</code>' which is called internally in the
  '<code>GetValue</code>' method</li>
  </ol>
  
  <p>However, it's being called only once for the first '<code>GetValue</code>' method call.</p>
  
  <p><em>How can change/fix the following code to make sure that all the methods on my '<code>MyFacade</code>' object cause the caching aspect to be invoked. Even if they are being called by other methods in the same '<code>MyFacde</code>' object?</em></p>
  
  <p>Here is a simplified example of what my code looks like:</p>
  
  <p><strong>Test Application:</strong></p>
  
  <pre><code>class Program
  {
      static void Main(string[] args)
      {
          var myFacadee = new MyFacade();
  
          System.Console.WriteLine("Value:\t" + myFacadee.GetValue("Tie"));
  
          System.Console.ReadLine();
      }
  }
  </code></pre>
  
  <p><strong>Facade:</strong></p>
  
  <pre><code>[Cache]
  public class MyFacade : ContextBoundObject
  {
      public string GetValue(string name)
      {
          return GetValues().FirstOrDefault(x =&gt; x.EndsWith(name));
      }
  
      public List&lt;string&gt; GetValues()
      {
          return new List&lt;string&gt;
                     {
                         "You asked for a Shirt",
                         "You asked for a Pants",
                         "You asked for a Tie"
                     };
      }
  }
  </code></pre>
  
  <p><strong>CacheAttribute:</strong></p>
  
  <pre><code>[AttributeUsage(AttributeTargets.Class)]
  public class CacheAttribute : ContextAttribute
  {
      public CacheAttribute() : base("Security") { }
  
      public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)
      {
          ctorMsg.ContextProperties.Add(new CacheProperty());
      }
  }
  </code></pre>
  
  <p><strong>CacheProperty:</strong></p>
  
  <pre><code>public class CacheProperty : IContextProperty, IContributeObjectSink
  {
      public IMessageSink GetObjectSink(MarshalByRefObject o, IMessageSink next)
      {
          return new CacheAspect(next);
      }
  
      public void Freeze(Context newContext)
      {
          // no op
      }
  
      public bool IsNewContextOK(Context ctx)
      {
          var newContextLogProperty = ctx.GetProperty("CacheProperty") as CacheProperty;
          if (newContextLogProperty == null)
          {
              Debug.Assert(false);
              return false;
          }
          return (true);
      }
  
      public string Name { get { return "CacheProperty"; } }
  }
  </code></pre>
  
  <p><strong>CacheAspect:</strong></p>
  
  <pre><code>internal class CacheAspect : IMessageSink
  {
      internal CacheAspect(IMessageSink next)
      {
          _next = next;
      }
  
      private readonly IMessageSink _next;
  
      public IMessageSink NextSink
      {
          get { return _next; }
      }
  
      public IMessage SyncProcessMessage(IMessage msg)
      {
          Preprocess(msg);
  
          var returnMethod = _next.SyncProcessMessage(msg);
  
          return returnMethod;
      }
  
      public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
      {
          throw new InvalidOperationException();
      }
  
      private void Preprocess(IMessage msg)
      {
          // We only want to process method calls
          if (!(msg is IMethodMessage)) return;
  
          var call = msg as IMethodMessage;
          var type = Type.GetType(call.TypeName);
          var callStr = type.Name + "." + call.MethodName;
  
          var argsString = call.Args.Aggregate((current, next) =&gt; current + ", " + next);
  
          Console.WriteLine("Try to get value form cache : {0} for {1}({2})", callStr, call.MethodName, argsString);
      }
  }
  </code></pre>