| Severity | Error |
| Reported by | PostSharp |
| Message | Cannot parse the ObjectConstruction provided by the aspect provider "<AspectProvider>" applied on "<Target>". |
Cause
An IAspectProvider can describe the aspect that it provides with an ObjectConstruction instead of an instance: the type of the aspect, the arguments of its constructor, and the values of its properties or fields. PostSharp then builds a custom attribute from this description. The ObjectConstruction is not checked when you create it from a type name or a Type, so a mistake shows up only at build time:
- No constructor of the aspect takes the given number and types of arguments. PostSharp also reports PS0202, which gives the type and the types of the arguments.
- A named argument is neither a property nor a field of the aspect. PostSharp also reports PS0121, which gives the name.
PostSharp then reports LA0117, which names the aspect provider and the target <Target> of the aspect, and skips the aspect. The message points to the aspect provider.
In the following example, the [LogPublicMethods] aspect provider passes an integer to the constructor of LogAttribute, which takes a string. The build reports both LA0117 and PS0202.
using System;
using System.Collections.Generic;
using System.Reflection;
using PostSharp.Aspects;
using PostSharp.Reflection;
using PostSharp.Serialization;
using BindingFlags = System.Reflection.BindingFlags;
namespace Errors.LA0117_Error;
[PSerializable]
public class LogAttribute : OnMethodBoundaryAspect
{
public LogAttribute( string category )
{
this.Category = category;
}
public string Category { get; set; }
public override void OnEntry( MethodExecutionArgs args ) => Console.WriteLine( $"[{this.Category}] Entering {args.Method.Name}." );
}
// Logs the public methods of the target class.
[PSerializable]
public class LogPublicMethodsAttribute : TypeLevelAspect, IAspectProvider
{
public IEnumerable<AspectInstance> ProvideAspects( object targetElement )
{
Type type = (Type) targetElement;
foreach ( MethodInfo method in type.GetMethods( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly ) )
{
// LogAttribute has no constructor that takes an integer.
ObjectConstruction construction = new( typeof(LogAttribute), 42 );
yield return new AspectInstance( method, construction );
}
}
}
[LogPublicMethods]
public class OrderService
{
public void PlaceOrder( string product ) => Console.WriteLine( $"Order for {product} placed." );
}
public static class Program
{
public static void Main()
{
new OrderService().PlaceOrder( "Chair" );
}
}
error LA0117: LA0117_Error.cs(26,14): Cannot parse the ObjectConstruction provided by the aspect provider "Errors.LA0117_Error.LogPublicMethodsAttribute" applied on "Errors.LA0117_Error.OrderService.PlaceOrder(System.String)".
error PS0202: Invalid ObjectConstruction: cannot find a suitable constructor in type 'Errors.LA0117_Error.LogAttribute, LA0117_Error, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' for arguments (System.Int32).
Resolution
Make the ObjectConstruction match the aspect class: pass the arguments of an existing constructor, in the right order and with the right types, and name only properties or fields of the aspect in NamedArguments. To get these checks when the provider runs, create the ObjectConstruction from a ConstructorInfo, or provide an aspect instance instead.
In the following example, the aspect provider passes the category of the log as a string.
using System;
using System.Collections.Generic;
using System.Reflection;
using PostSharp.Aspects;
using PostSharp.Reflection;
using PostSharp.Serialization;
using BindingFlags = System.Reflection.BindingFlags;
namespace Errors.LA0117_Fixed;
[PSerializable]
public class LogAttribute : OnMethodBoundaryAspect
{
public LogAttribute( string category )
{
this.Category = category;
}
public string Category { get; set; }
public override void OnEntry( MethodExecutionArgs args ) => Console.WriteLine( $"[{this.Category}] Entering {args.Method.Name}." );
}
// Logs the public methods of the target class.
[PSerializable]
public class LogPublicMethodsAttribute : TypeLevelAspect, IAspectProvider
{
public IEnumerable<AspectInstance> ProvideAspects( object targetElement )
{
Type type = (Type) targetElement;
foreach ( MethodInfo method in type.GetMethods( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly ) )
{
// The argument matches the constructor of LogAttribute.
ObjectConstruction construction = new( typeof(LogAttribute), "Orders" );
yield return new AspectInstance( method, construction );
}
}
}
[LogPublicMethods]
public class OrderService
{
public void PlaceOrder( string product ) => Console.WriteLine( $"Order for {product} placed." );
}
public static class Program
{
public static void Main()
{
new OrderService().PlaceOrder( "Chair" );
}
}
[Orders] Entering PlaceOrder.
Order for Chair placed.
See Also
Reference
IAspectProvider
AspectInstance
ObjectConstruction
Other Resources