Search code examples
.net-assemblypostsharp

PostSharp - Applying aspect to mscorlib but prohibit modifying calls in my own class


My aspect:

[Serializable]
class DumbLogger : OnMethodBoundaryAspect
{
    public override void OnEntry(MethodExecutionArgs args)
    {
        Log.Print("Entry: ") + args.Method.Name;
        args.FlowBehavior = FlowBehavior.Continue;
    }
}

This is what i am using to modify the calls in mscorlib AND trying to exclude them from being modified in my class called LOG

    [assembly: MY_PROJECT.DumbLogger(
    AttributeTargetTypes = "MY_PROJECT.Log",
    AttributeExclude = true,
    AttributePriority = 1)]


    [assembly: MY_PROJECT.DumbLogger(
    AttributeTargetAssemblies = "mscorlib",
    AttributePriority = 2)]

But.. This doesnt do the trick because if i look at my LOG class with ILspy decompiler i can see method calls to any class @ mscorlib.dll being modified for example:

<>z__Aspects.<System.Object.ToString>b__v(text)

The reason i wanna do this is because when i enter the method Log.Print it will generate a stackoverflow exception and will infinitely call itself.

I am already aware of maybe excluding certain namespaces and classes like string from mscorlib but i have my reasons to do it the way i described.


Solution

  • PostSharp Aspects in general are applied to declarations (assemblies, types, methods, parameters, fields, etc.). When you are applying an MethodLevelAspect (base class of OnMethodBoundaryAspect) on an external method, PostSharp transforms the call site (call instruction in IL), but still thinks of the aspect as being on the declaration itself.

    There is currently no way to filter by call site and it would require a different kind of aspect and/or advices. Therefore your AttributeExclude=true specifying attribute on the assembly does not have any effect as it says that the aspect should not be applied on Log type, which it is not.

    The common technique that solves exactly this case is to use a ThreadStatic variable to break the recursion cycle as the following code demonstrates:

    [Serializable]
    class DumbLogger : OnMethodBoundaryAspect
    {
        [ThreadStatic] private static bool logging;
    
        public override void OnEntry(MethodExecutionArgs args)
        {
            if (logging)
                return;
    
            try
            {
                logging = true;
                Log.Print("Entry: " + args.Method.Name);
                args.FlowBehavior = FlowBehavior.Continue;
            }
            finally
            {
                logging = false;
            }
        }
    }
    

    Please also note that MethodInterception and OnMethodBoundary aspects are the only aspect that work on external assemblies.