How to connect message receivers in the context of a related object (aspect-oriented programming)

I am trying to use ContextBoundObject and message receivers to inject some aspects into my code.

My problem is that my aspect is called only once - when I call: myFacadee.GetValue("Tie") I would expect my aspect of caching to be called twice

  • Once for the < GetValue method
  • Secondly, for GetValues ', which internally is' GetValue '

However, it is called only once for the first call to the GetValue method.

How to modify / fix the following code to make sure that all methods on my " MyFacade " object MyFacade caching aspect. Even if they are called by other methods in the same " MyFacde " object?

Here is a simplified example of what my code looks like:

test application:

 class Program { static void Main(string[] args) { var myFacadee = new MyFacade(); System.Console.WriteLine("Value:\t" + myFacadee.GetValue("Tie")); System.Console.ReadLine(); } } 

Facade:

 [Cache] public class MyFacade : ContextBoundObject { public string GetValue(string name) { return GetValues().FirstOrDefault(x => x.EndsWith(name)); } public List<string> GetValues() { return new List<string> { "You asked for a Shirt", "You asked for a Pants", "You asked for a Tie" }; } } 

CacheAttribute:

 [AttributeUsage(AttributeTargets.Class)] public class CacheAttribute : ContextAttribute { public CacheAttribute() : base("Security") { } public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg) { ctorMsg.ContextProperties.Add(new CacheProperty()); } } 

CacheProperty:

 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"; } } } 

CacheAspect:

 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) => current + ", " + next); Console.WriteLine("Try to get value form cache : {0} for {1}({2})", callStr, call.MethodName, argsString); } } 
+4
source share
3 answers

It is called only once, because the context boundary intersects only once. Calling the same instance from an instance does not require any sorting in the context, so your receiver is not used to intercept the message.

+2
source

I have not tested this; I will try to change the target to AttributeTargets.Method.

 [AttributeUsage(AttributeTargets.Method)] public class CacheAttribute : ContextAttribute 
0
source

Change the AttributeUsage to target Methods only, and make " [Cache] " in the method you need, in your case it should be " GetValues " not " GetValue ", which will lead to all the elements that will be cached in the collection and then you can read from this cache.

One of the leading AOS components with a reputation for PostSharp

0
source

All Articles