Open sandboxFocusImprove this doc

LA0182: Method Boundary Advice Applied to a Static Constructor of Another Assembly

Severity Error
Reported by PostSharp
Message Advice "<Advice>" is not valid on the static constructor of type "<Type>": applying OnMethodEntryAdvice, OnMethodSuccessAdvice, OnMethodExitAdvice or OnMethodExceptionAdvice to a static constructor of another assembly is not supported. Restrict the advice to methods.

Cause

PostSharp can apply advices 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 advices. A static constructor is never called by your code, but by the runtime, so PostSharp reports LA0182 when an OnMethodEntryAdvice, an OnMethodSuccessAdvice, an OnMethodExitAdvice or an OnMethodExceptionAdvice targets the static constructor of a type of another assembly. <Advice> is an advice method of the group, and the message is reported at its location: the advice that has the pointcut of the group, or else the advice that sets a property of the group, or else the first advice of the group. <Type> is the type that declares the static constructor.

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.

LA0180 is the same error for an OnMethodBoundaryAspect or an OnExceptionAspect.

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

using System.Collections.Generic;

namespace Errors.LA0182_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, whose OnEntry advice has no pointcut and therefore applies to the target of the aspect, to the static constructor and to the methods of TaxRates:

// @SkipPostSharpOnDependency

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

[assembly: Errors.LA0182_Error.LogShippingLibrary]

namespace Errors.LA0182_Error;

[PSerializable]
public class LogAttribute : MethodLevelAspect
{
    [OnMethodEntryAdvice]
    public 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 LA0182: LA0182_Error.cs(19,17): Advice "Errors.LA0182_Error.LogAttribute.OnEntry(PostSharp.Aspects.MethodExecutionArgs)" is not valid on the static constructor of type "Errors.LA0182_Error.Shipping.TaxRates": applying OnMethodEntryAdvice, OnMethodSuccessAdvice, OnMethodExitAdvice or OnMethodExceptionAdvice to a static constructor of another assembly is not supported. Restrict the advice to methods.

Resolution

  • Provide the aspect for methods only, not for the static constructor.
  • When the advice selects its targets with another pointcut, such as a MethodPointcut, exclude the static constructors from the pointcut.
  • 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.LA0182_Fixed.Shipping;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;

[assembly: Errors.LA0182_Fixed.LogShippingLibrary]

namespace Errors.LA0182_Fixed;

[PSerializable]
public class LogAttribute : MethodLevelAspect
{
    [OnMethodEntryAdvice]
    public 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

OnMethodEntryAdvice
MethodLevelAspect
IAspectProvider

Other Resources

Adding Aspects Programmatically Using IAspectProvider