| Severity | Error |
| Reported by | PostSharp |
| Message | The custom attribute "<Attribute>" cannot be applied to "<Target>": <Reason> |
Cause
Any custom attribute, not only an aspect, can check at build time that it is applied to a valid declaration: it implements IValidableAnnotation, and PostSharp calls its CompileTimeValidate(object) method for each declaration that it is applied to, with the reflection object of this declaration, such as a MethodBase. To reject the declaration with an error, the method throws an InvalidAnnotationException. PostSharp then reports PS0285 on the declaration. <Reason> is the message of the exception.
When the method returns false instead, PostSharp ignores the attribute on this declaration without reporting anything. For an aspect, the same exception is reported as LA0252.
In the following example, the [WebEndpoint] attribute requires a public method, and it is applied to a private one.
// @DisabledMessages(PS0131)
using System;
using System.Reflection;
using PostSharp.Extensibility;
namespace Errors.PS0285_Error;
// A custom attribute, not an aspect, that checks its target at build time.
[AttributeUsage( AttributeTargets.Method )]
public sealed class WebEndpointAttribute : Attribute, IValidableAnnotation
{
public bool CompileTimeValidate( object target )
{
MethodBase method = (MethodBase) target;
if ( !method.IsPublic )
{
throw new InvalidAnnotationException( $"The method {method.Name} must be public to be exposed as a web endpoint." );
}
return true;
}
}
public class OrderController
{
// The method is private, so CompileTimeValidate rejects the attribute.
[WebEndpoint]
private string GetOrder( int orderId ) => $"Order {orderId}";
public string Describe( int orderId ) => this.GetOrder( orderId );
}
public static class Program
{
public static void Main()
{
Console.WriteLine( new OrderController().Describe( 42 ) );
}
}
error PS0285: PS0285_Error.cs(30,20): The custom attribute "Errors.PS0285_Error.WebEndpointAttribute" cannot be applied to "Errors.PS0285_Error.OrderController.GetOrder(System.Int32)": The method GetOrder must be public to be exposed as a web endpoint.
Resolution
Fix the declaration so that it meets the requirement that <Reason> describes, or remove the attribute from it. When the validation itself is wrong, correct the CompileTimeValidate method of the attribute.
In the following example, the method is public, and the validation accepts the attribute.
// @DisabledMessages(PS0131)
using System;
using System.Reflection;
using PostSharp.Extensibility;
namespace Errors.PS0285_Fixed;
// A custom attribute, not an aspect, that checks its target at build time.
[AttributeUsage( AttributeTargets.Method )]
public sealed class WebEndpointAttribute : Attribute, IValidableAnnotation
{
public bool CompileTimeValidate( object target )
{
MethodBase method = (MethodBase) target;
if ( !method.IsPublic )
{
throw new InvalidAnnotationException( $"The method {method.Name} must be public to be exposed as a web endpoint." );
}
return true;
}
}
public class OrderController
{
// The method is public, so CompileTimeValidate accepts the attribute.
[WebEndpoint]
public string GetOrder( int orderId ) => $"Order {orderId}";
public string Describe( int orderId ) => this.GetOrder( orderId );
}
public static class Program
{
public static void Main()
{
Console.WriteLine( new OrderController().Describe( 42 ) );
bool isEndpoint = typeof(OrderController).GetMethod( nameof(OrderController.GetOrder) )!.IsDefined( typeof(WebEndpointAttribute), false );
Console.WriteLine( $"GetOrder is a web endpoint: {isEndpoint}." );
}
}
Order 42
GetOrder is a web endpoint: True.
See Also
Reference
IValidableAnnotation
InvalidAnnotationException
Other Resources