Open sandboxFocusImprove this doc

LA0032: Aspect Provided to a Parameter of an Unknown Method

Severity Error
Reported by PostSharp
Message Cannot apply the aspect <Aspect> to a parameter of method <DeclaringType>.<Method> because PostSharp cannot find this method in the current assembly or in the assemblies that it references.

Cause

An aspect that implements IAspectProvider adds aspects to other declarations by returning AspectInstance objects from its ProvideAspects method. The target element of each AspectInstance is a reflection object, which PostSharp maps back to a declaration of the code that it compiles. When the target element is a parameter, PostSharp looks for the method that declares it. If it cannot find this method in the current assembly or in the assemblies that the project references, it reports LA0032.

This happens when the reflection object does not describe the code that you compile, but an implementation detail of the .NET runtime that no reference assembly exposes. The most common mistake is to call GetType() on the target element: the target element of a type-level aspect is already a Type, so GetType() returns System.RuntimeType, the class of reflection objects, and its methods are internal to the runtime. PostSharp reports LA0032 once for each parameter that the provider returns, on the aspect provider class.

In the following example, the [NotEmptyStringParameters] aspect is meant to add a [NotEmpty] validation aspect to each string parameter of OrderService, but it enumerates the methods of System.RuntimeType.

using System;
using System.Collections.Generic;
using System.Reflection;
using PostSharp.Aspects;
using PostSharp.Reflection;
using PostSharp.Serialization;

namespace Errors.LA0032_Error;

[PSerializable]
public class NotEmptyAttribute : LocationLevelAspect, ILocationValidationAspect<string>
{
    public Exception? ValidateValue( string value, string locationName, LocationKind locationKind, LocationValidationContext context )
        => string.IsNullOrEmpty( value ) ? new ArgumentException( "The value cannot be empty.", locationName ) : null;
}

[PSerializable]
public class NotEmptyStringParametersAttribute : TypeLevelAspect, IAspectProvider
{
    public IEnumerable<AspectInstance> ProvideAspects( object targetElement )
    {
        // GetType() returns the type of the reflection object, System.RuntimeType, instead of the target class.
        Type type = targetElement.GetType();

        foreach ( MethodInfo method in type.GetMethods( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly ) )
        {
            foreach ( ParameterInfo parameter in method.GetParameters() )
            {
                if ( parameter.ParameterType == typeof(string) )
                {
                    yield return new AspectInstance( parameter, new NotEmptyAttribute() );
                }
            }
        }
    }
}

[NotEmptyStringParameters]
public class OrderService
{
    public string PlaceOrder( string product ) => $"Order placed for {product}.";
}

public static class Program
{
    public static void Main()
    {
        var service = new OrderService();

        Console.WriteLine( service.PlaceOrder( "Book" ) );

        try
        {
            service.PlaceOrder( "" );
        }
        catch ( ArgumentException e )
        {
            Console.WriteLine( $"Rejected: {e.Message}" );
        }
    }
}
error LA0032: LA0032_Error.cs(18,14): Cannot apply the aspect Errors.LA0032_Error.NotEmptyAttribute to a parameter of method System.RuntimeType.GetEvent because PostSharp cannot find this method in the current assembly or in the assemblies that it references.
error LA0032: LA0032_Error.cs(18,14): Cannot apply the aspect Errors.LA0032_Error.NotEmptyAttribute to a parameter of method System.RuntimeType.GetField because PostSharp cannot find this method in the current assembly or in the assemblies that it references.
error LA0032: LA0032_Error.cs(18,14): Cannot apply the aspect Errors.LA0032_Error.NotEmptyAttribute to a parameter of method System.RuntimeType.GetInterface because PostSharp cannot find this method in the current assembly or in the assemblies that it references.
error LA0032: LA0032_Error.cs(18,14): Cannot apply the aspect Errors.LA0032_Error.NotEmptyAttribute to a parameter of method System.RuntimeType.GetMember because PostSharp cannot find this method in the current assembly or in the assemblies that it references.
error LA0032: LA0032_Error.cs(18,14): Cannot apply the aspect Errors.LA0032_Error.NotEmptyAttribute to a parameter of method System.RuntimeType.GetNestedType because PostSharp cannot find this method in the current assembly or in the assemblies that it references.
error LA0032: LA0032_Error.cs(18,14): Cannot apply the aspect Errors.LA0032_Error.NotEmptyAttribute to a parameter of method System.RuntimeType.InvokeMember because PostSharp cannot find this method in the current assembly or in the assemblies that it references.

Resolution

Get the parameters from the target element itself: cast it to Type in a type-level aspect, or to MethodBase in a method-level aspect, instead of calling GetType(). More generally, provide aspects only to parameters of methods of the current assembly, which are the only ones that PostSharp can transform; the DeclaredOnly binding flag excludes the methods that the target type inherits.

In the following example, the provider casts the target element to Type, and PlaceOrder rejects an empty string.

using System;
using System.Collections.Generic;
using System.Reflection;
using PostSharp.Aspects;
using PostSharp.Reflection;
using PostSharp.Serialization;

namespace Errors.LA0032_Fixed;

[PSerializable]
public class NotEmptyAttribute : LocationLevelAspect, ILocationValidationAspect<string>
{
    public Exception? ValidateValue( string value, string locationName, LocationKind locationKind, LocationValidationContext context )
        => string.IsNullOrEmpty( value ) ? new ArgumentException( "The value cannot be empty.", locationName ) : null;
}

[PSerializable]
public class NotEmptyStringParametersAttribute : TypeLevelAspect, IAspectProvider
{
    public IEnumerable<AspectInstance> ProvideAspects( object targetElement )
    {
        // The target element of a type-level aspect is the target class itself.
        Type type = (Type) targetElement;

        foreach ( MethodInfo method in type.GetMethods( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly ) )
        {
            foreach ( ParameterInfo parameter in method.GetParameters() )
            {
                if ( parameter.ParameterType == typeof(string) )
                {
                    yield return new AspectInstance( parameter, new NotEmptyAttribute() );
                }
            }
        }
    }
}

[NotEmptyStringParameters]
public class OrderService
{
    public string PlaceOrder( string product ) => $"Order placed for {product}.";
}

public static class Program
{
    public static void Main()
    {
        var service = new OrderService();

        Console.WriteLine( service.PlaceOrder( "Book" ) );

        try
        {
            service.PlaceOrder( "" );
        }
        catch ( ArgumentException e )
        {
            Console.WriteLine( $"Rejected: {e.Message}" );
        }
    }
}
Order placed for Book.
Rejected: The value cannot be empty. (Parameter 'product')

See Also

Reference

IAspectProvider
AspectInstance
ILocationValidationAspect<T>

Other Resources

Adding Aspects Dynamically
Adding Aspects Programmatically Using IAspectProvider