Open sandboxFocusImprove this doc

LA0180: Method Boundary Aspect Applied to a Static Constructor of Another Assembly

Severity Error
Reported by PostSharp
Message Cannot apply the aspect "<Aspect>" to the static constructor of type "<Type>": applying OnMethodBoundaryAspect or OnExceptionAspect to a static constructor of another assembly is not supported. Restrict the aspect to methods.

Cause

PostSharp can apply an aspect to a method of a referenced assembly without modifying that assembly: it replaces the calls that the current assembly makes to the method with calls to a generated method that runs the aspect. A static constructor is never called by your code, but by the runtime, so PostSharp reports LA0180 when an OnMethodBoundaryAspect or an OnExceptionAspect targets the static constructor of a type of another assembly. <Type> is the type that declares the static constructor. The message has no location in the source code.

Multicasting with AttributeTargetAssemblies only reaches the members of another assembly that the current assembly references, which never include a static constructor. The message comes from an IAspectProvider that provides the aspect for the static constructor explicitly, for example from TypeInitializer.

In the following example, a shipping library defines TaxRates, which has a static constructor:

using System.Collections.Generic;

namespace Errors.LA0180_Error.Shipping;

public static class TaxRates
{
    private static readonly Dictionary<string, decimal> rates;

    static TaxRates()
    {
        rates = new Dictionary<string, decimal> { ["BE"] = 0.21m, ["FR"] = 0.20m };
    }

    public static decimal GetRate( string country ) => rates[country];
}

An assembly-level aspect provider of the application adds a [Log] aspect to the static constructor and to the methods of TaxRates:

// @SkipPostSharpOnDependency

using System;
using System.Collections.Generic;
using System.Reflection;
using Errors.LA0180_Error.Shipping;
using PostSharp.Aspects;
using PostSharp.Serialization;

[assembly: Errors.LA0180_Error.LogShippingLibrary]

namespace Errors.LA0180_Error;

[PSerializable]
public class LogAttribute : OnMethodBoundaryAspect
{
    public override void OnEntry( MethodExecutionArgs args )
    {
        Console.WriteLine( $"Calling {args.Method.DeclaringType!.Name}.{args.Method.Name}" );
    }
}

[PSerializable]
public class LogShippingLibraryAttribute : AssemblyLevelAspect, IAspectProvider
{
    public IEnumerable<AspectInstance> ProvideAspects( object targetElement )
    {
        // The static constructor of TaxRates is in another assembly.
        yield return new AspectInstance( typeof(TaxRates).TypeInitializer!, new LogAttribute() );

        foreach ( MethodInfo method in typeof(TaxRates).GetMethods( BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly ) )
        {
            yield return new AspectInstance( method, new LogAttribute() );
        }
    }
}

public static class Program
{
    public static void Main()
    {
        Console.WriteLine( $"VAT in Belgium: {TaxRates.GetRate( "BE" ):0.00}" );
    }
}
error LA0180: Cannot apply the aspect "Errors.LA0180_Error.LogAttribute" to the static constructor of type "Errors.LA0180_Error.Shipping.TaxRates": applying OnMethodBoundaryAspect or OnExceptionAspect to a static constructor of another assembly is not supported. Restrict the aspect to methods.

Resolution

  • Provide the aspect for methods only, not for the static constructor.
  • When you own the library, apply the aspect in the library itself, where PostSharp can enhance the static constructor.

In the following example, the aspect provider no longer targets the static constructor of TaxRates.

// @SkipPostSharpOnDependency

using System;
using System.Collections.Generic;
using System.Reflection;
using Errors.LA0180_Fixed.Shipping;
using PostSharp.Aspects;
using PostSharp.Serialization;

[assembly: Errors.LA0180_Fixed.LogShippingLibrary]

namespace Errors.LA0180_Fixed;

[PSerializable]
public class LogAttribute : OnMethodBoundaryAspect
{
    public override void OnEntry( MethodExecutionArgs args )
    {
        Console.WriteLine( $"Calling {args.Method.DeclaringType!.Name}.{args.Method.Name}" );
    }
}

[PSerializable]
public class LogShippingLibraryAttribute : AssemblyLevelAspect, IAspectProvider
{
    public IEnumerable<AspectInstance> ProvideAspects( object targetElement )
    {
        // The static constructor of TaxRates is no longer a target: only its methods are.
        foreach ( MethodInfo method in typeof(TaxRates).GetMethods( BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly ) )
        {
            yield return new AspectInstance( method, new LogAttribute() );
        }
    }
}

public static class Program
{
    public static void Main()
    {
        Console.WriteLine( $"VAT in Belgium: {TaxRates.GetRate( "BE" ):0.00}" );
    }
}
Calling TaxRates.GetRate
VAT in Belgium: 0.21

See Also

Reference

IAspectProvider
OnMethodBoundaryAspect
OnExceptionAspect

Other Resources

Adding Aspects Programmatically Using IAspectProvider