Question

This is what I am trying to accomplish: Currently I am converting a 2500 integration tests from nunit to mstest, so that we can run them with Microsoft Test Manager/Lab. Most tests need to run on the user interface thread of the product I am working on or they will not succeed.

This is my problem: I have created a postsharp aspect that will automatically run mstest test methods that will initialize the environment for the tests and run them on a UI thread. This works fine, except for the tests that are created with Specflow. Specflow generates code behind classes that are marked with the System.Runtime.CompilerServices.CompilerGenerated attribute. And when a class is marked with that attribute, Postsharp seems to skip all methods in it.

The aspect is defined on the assembly level. I have tried to use MulticastAttributes.CompilerGenerated attributes during the registration but it does not seem to change the behavior. When I place the aspect directly on a method, it works.

I am using the latest stable version of Postsharp (currently 3.1.).

A sample aspect:

[Serializable]
public class MyAspect : PostSharp.Aspects.OnMethodBoundaryAspect
{
    public override void OnEntry(PostSharp.Aspects.MethodExecutionArgs args)
    {
        Console.WriteLine("Starting {0}", args.Method.Name);
    }

    public override void OnExit(PostSharp.Aspects.MethodExecutionArgs args)
    {
        Console.WriteLine("Completed {0}", args.Method.Name);
    }
}

The code that I am trying to apply it to:

[assembly: PostSharpTestAspects.MyAspect( AttributeTargetTypeAttributes = MulticastAttributes.Public | MulticastAttributes.AnyGeneration, AttributeTargetElements = MulticastTargets.Method, AttributeTargetMemberAttributes = MulticastAttributes.Public | MulticastAttributes.AnyGeneration)]

class Program
{
    static void Main(string[] args)
    {
        new MyTestClass().MyTestMethod();
        Console.WriteLine("Press a key to exit..."); 
        Console.ReadKey();
    }
}

[System.Runtime.CompilerServices.CompilerGenerated]
public class MyTestClass
{        
    public void MyTestMethod()
    {
        Console.WriteLine("Executing MyTestMethod..");
    }
}

When removing the CompilerGenerated attribute PostSharp applies the aspect.

My questions are: Is this behavior by design? Is this a bug? Is there some workaround? Maybe I need to apply the MulticastAttributes differently in the assembly attribute?

Was it helpful?

Solution

PostSharp ignores all the types that have [CompilerGenerated] attribute applied when performing the multicasting of the aspect attributes. This functionality is by design and is needed to avoid the application of the aspects on all the types generated by the C# compiler. The generated types represent the implementation details of the C# compiler and applying the attributes by default would expose these implementation details to the user.

However, PostSharp treats generated methods in non-generated types with less restriction. These are the methods where the user normally expects to apply the aspects by default. For example, the automatic property accessors are marked as [CompilerGenerated]. You can control this behavior by setting the flags MulticastAttributes.CompilerGenerated and MulticastAttributes.UserGenerated on the AttributeTargetTypeAttributes property of your aspect.

If you need to apply the aspect to compiler-generated types, then you can do it by implementing your own aspect provider and applying it on the assembly level.

[MulticastAttributeUsage(MulticastTargets.Assembly)]
public class SampleAspectProvider : MulticastAttribute, IAspectProvider
{
    public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
    {
        var myAspect = new MyAspect();
        var assembly = (Assembly) targetElement;

        foreach (var type in assembly.GetTypes())
        {
            if (/* type is a valid target */)
            {
                foreach (var methodInfo in type.GetMethods())
                {
                    yield return new AspectInstance(methodInfo, myAspect);
                }
            }
        }
    }
}

And apply in the target assembly:

[assembly: SampleAspectProvider]
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top