| Severity | Warning |
| Reported by | PostSharp |
| Message | Semantic advising for the "<Advice>" advice is enabled for the "<Method>" method, but the OnInvokeAsync advice is not implemented. To suppress this message either implement the [OnMethodInvokeAsyncAdvice] advice or set the SemanticallyAdvisedMethodKinds property of the master advice to 'None'. |
Cause
An aspect built from advices intercepts a method with an OnMethodInvokeAdvice advice. For an async method, or a method returning an awaitable type such as Task, it can also have an OnMethodInvokeAsyncAdvice advice, which can await the end of the task. This is called semantic advising, and it is enabled by default by the SemanticallyAdvisedMethodKinds property of the master advice.
When the aspect has no OnMethodInvokeAsyncAdvice advice, PostSharp falls back to the OnMethodInvokeAdvice advice, <Advice>, and reports LA0186 on the target method. Proceed() then returns as soon as the method returns its task, at the first await that does not complete synchronously, so the code after it runs before the asynchronous operation ends. Aspects derived from MethodInterceptionAspect report LA0185 in the same situation.
In the following example, the [Log] aspect has only an [OnMethodInvokeAdvice] advice, and is applied to the async method ShipAsync.
using System;
using System.Threading.Tasks;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0186_Error;
[PSerializable]
public class LogAttribute : MethodLevelAspect
{
[OnMethodInvokeAdvice]
public void OnInvoke( MethodInterceptionArgs args )
{
Console.WriteLine( $"Entering {args.Method.Name}" );
args.Proceed();
Console.WriteLine( $"Leaving {args.Method.Name}" );
}
}
public class OrderService
{
// The aspect intercepts this async method with OnInvoke, because it has no [OnMethodInvokeAsyncAdvice] advice.
[Log]
public async Task ShipAsync( int orderId )
{
Console.WriteLine( $"Preparing order {orderId}" );
await Task.Delay( 10 );
Console.WriteLine( $"Shipped order {orderId}" );
}
}
public static class Program
{
public static async Task Main()
{
await new OrderService().ShipAsync( 42 );
}
}
warning LA0186: LA0186_Error.cs(25,23): Semantic advising for the "Errors.LA0186_Error.LogAttribute.OnInvoke(PostSharp.Aspects.MethodInterceptionArgs)" advice is enabled for the "Errors.LA0186_Error.OrderService.ShipAsync(System.Int32)" method, but the OnInvokeAsync advice is not implemented. To suppress this message either implement the [OnMethodInvokeAsyncAdvice] advice or set the SemanticallyAdvisedMethodKinds property of the master advice to 'None'.
The program shows that the advice leaves the method before the order is shipped:
Entering ShipAsync
Preparing order 42
Leaving ShipAsync
Shipped order 42
Resolution
- Add a public method with the signature of OnInvokeAsync(MethodInterceptionArgs) and the OnMethodInvokeAsyncAdvice attribute, and await ProceedAsync() in it.
- When the advice must intercept only the call that starts the task, set the SemanticallyAdvisedMethodKinds property of the OnMethodInvokeAdvice attribute to None.
In the following example, the aspect has an [OnMethodInvokeAsyncAdvice] advice, which awaits the end of ShipAsync.
using System;
using System.Threading.Tasks;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0186_Fixed;
[PSerializable]
public class LogAttribute : MethodLevelAspect
{
[OnMethodInvokeAdvice]
public void OnInvoke( MethodInterceptionArgs args )
{
Console.WriteLine( $"Entering {args.Method.Name}" );
args.Proceed();
Console.WriteLine( $"Leaving {args.Method.Name}" );
}
// This advice intercepts async methods and awaits the end of the task.
[OnMethodInvokeAsyncAdvice]
public async Task OnInvokeAsync( MethodInterceptionArgs args )
{
Console.WriteLine( $"Entering {args.Method.Name}" );
await args.ProceedAsync();
Console.WriteLine( $"Leaving {args.Method.Name}" );
}
}
public class OrderService
{
[Log]
public async Task ShipAsync( int orderId )
{
Console.WriteLine( $"Preparing order {orderId}" );
await Task.Delay( 10 );
Console.WriteLine( $"Shipped order {orderId}" );
}
}
public static class Program
{
public static async Task Main()
{
await new OrderService().ShipAsync( 42 );
}
}
Entering ShipAsync
Preparing order 42
Shipped order 42
Leaving ShipAsync
See Also
Reference
OnMethodInvokeAdvice
OnMethodInvokeAsyncAdvice
SemanticallyAdvisedMethodKinds
Other Resources
Semantic Advising of Iterator and Async Methods
Advice Methods