Multiple Aspects on a Single Method

In my application, I previously used regular C # attributes to “annotate” a method. For example:.

[Foo(SomeKey="A", SomeValue="3")] [Foo(SomeKey="B", SomeValue="4")] public void TheMethod() { SpecialAttributeLogicHere(); } 

What SpecialAttributeLogicHere () did was to reflect all the Foo attributes that annotated this particular method. Then he (by himself) would create his own dictionary for all keys and values.

Now I'm trying to go to PostSharp, because SpecialAttributeLogic can be placed in the aspect (and removed from the body of the method, which is much cleaner!), Inside OnEntry. Foo will be replaced by an aspect that extends OnMethodBoundaryAspect.

I would still like to use it as follows:

 [Foo(SomeKey="A", SomeValue="3")] [Foo(SomeKey="B", SomeValue="4")] 

But if Foo has OnEntry, it means that "SpecialAttributeLogic" will execute twice. I basically need to “collect” all the keys and values ​​from each Foo (), into a dictionary, into which I then apply some logic.

How to do it (or best practices) with PostSharp? Thanks!

+8
c # aop postsharp
source share
2 answers

It looks like you want to create a valuepair name inside your method. You cannot do this with the aspect. I suggest you use the MethodInterceptionAspect method and reflect the attributes of the method, and then create your collection and pass it to the method using a parameter (possibly using an overloaded method) or setting it as a member of the class.

You can display values ​​at compile time to ensure optimal performance.

Here is a brief solution to your problem. This is a little ugly (you will need to make changes to the size). There are other ways, but they are not "generic".

 namespace ConsoleApplication12 { class Program { static void Main(string[] args) { MyExampleClass ec = new MyExampleClass(); ec.MyMethod(); } } public class MyExampleClass { [Special(Key = "test1", Value = "1234")] [Special(Key = "test2", Value = "4567")] [MyAspect] public void MyMethod() { MyMethod(new Dictionary<string, string>()); } public void MyMethod(Dictionary<string, string> values) { //Do work } } [Serializable] public class MyAspect : MethodInterceptionAspect { Dictionary<string, string> values = new Dictionary<string, string>(); MethodInfo target; public override void CompileTimeInitialize(System.Reflection.MethodBase method, AspectInfo aspectInfo) { target = method.DeclaringType.GetMethod(method.Name, new Type[] { typeof(Dictionary<string, string>) }); foreach (Attribute a in method.GetCustomAttributes(false)) { if (a is SpecialAttribute) { values.Add(((SpecialAttribute)a).Key, ((SpecialAttribute)a).Value); } } } public override void OnInvoke(MethodInterceptionArgs args) { if (values == null || values.Count < 1) { args.Proceed(); } else { target.Invoke(args.Instance, new object[] { values }); } } } [AttributeUsage(AttributeTargets.Method, AllowMultiple = true) ] public class SpecialAttribute : Attribute { public string Key { get; set; } public string Value { get; set; } } } 

target and values ​​are initialized at compiletime (and not at run time) for consumption at run time. They get serialized with aspect in compiletime. This way you retain the reflection effect at runtime.

+2
source share

As a note, I ended up using MethodInterceptionAspect and only redefined OnInvoke. In OnInvoke, I looked at args.Method.GetCustomAttributes (), giving me all the System.Attributes attributes that I set (for example, SpecialAttribute in the DustinDavis example).

Using these attributes and their properties, I can run the logic that I need to run. If the logic succeeds, I end with args.Proceed (), if not I make an exception.

0
source share

All Articles