Open sandboxFocusImprove this doc

LA0165: Async Interception Advice Does Not Return a Task

Severity Error
Reported by PostSharp
Message Advice "<Advice>" is not valid on method "<Method>": method return type must be "<ReturnType>".

Cause

An advice method marked with OnMethodInvokeAsyncAdvice intercepts async methods, as OnInvokeAsync does in a MethodInterceptionAspect. It must have the same signature as OnInvokeAsync and return a Task, so that PostSharp can await the advice and return its task to the caller. <ReturnType> is always System.Threading.Tasks.Task.

The error usually comes from an advice declared async void, as in the following example.

using System;
using System.Threading.Tasks;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;

namespace Errors.LA0165_Error;

[PSerializable]
public class LogAttribute : MethodLevelAspect
{
    [OnMethodInvokeAdvice]
    public void OnInvoke( MethodInterceptionArgs args )
    {
        Console.WriteLine( $"Calling {args.Method.Name}." );
        args.Proceed();
    }

    // The async advice returns void instead of Task.
    [OnMethodInvokeAsyncAdvice]
    public async void OnInvokeAsync( MethodInterceptionArgs args )
    {
        Console.WriteLine( $"Calling {args.Method.Name} asynchronously." );
        await args.ProceedAsync();
    }
}

public class OrderService
{
    [Log]
    public async Task PlaceOrderAsync( string product )
    {
        await Task.Yield();
        Console.WriteLine( $"Order for {product} placed." );
    }
}

public static class Program
{
    public static async Task Main()
    {
        await new OrderService().PlaceOrderAsync( "Chair" );
    }
}

PostSharp discards the invalid advice, so it also warns (LA0186) that PlaceOrderAsync, an async method, receives the synchronous OnInvoke advice without an async advice:

error LA0165: LA0165_Error.cs(21,23): Advice "PostSharp.Aspects.Advices.OnMethodInvokeAsyncAdvice" is not valid on method "Errors.LA0165_Error.LogAttribute.OnInvokeAsync(PostSharp.Aspects.MethodInterceptionArgs)": method return type must be "System.Threading.Tasks.Task".
warning LA0186: LA0165_Error.cs(31,23): Semantic advising for the "Errors.LA0165_Error.LogAttribute.OnInvoke(PostSharp.Aspects.MethodInterceptionArgs)" advice is enabled for the "Errors.LA0165_Error.OrderService.PlaceOrderAsync(System.String)" 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'.

Resolution

Make the advice method return Task: declare it async Task instead of async void.

In the following example, the async advice intercepts PlaceOrderAsync.

using System;
using System.Threading.Tasks;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;

namespace Errors.LA0165_Fixed;

[PSerializable]
public class LogAttribute : MethodLevelAspect
{
    [OnMethodInvokeAdvice]
    public void OnInvoke( MethodInterceptionArgs args )
    {
        Console.WriteLine( $"Calling {args.Method.Name}." );
        args.Proceed();
    }

    // The async advice returns a Task, which PostSharp awaits.
    [OnMethodInvokeAsyncAdvice]
    public async Task OnInvokeAsync( MethodInterceptionArgs args )
    {
        Console.WriteLine( $"Calling {args.Method.Name} asynchronously." );
        await args.ProceedAsync();
    }
}

public class OrderService
{
    [Log]
    public async Task PlaceOrderAsync( string product )
    {
        await Task.Yield();
        Console.WriteLine( $"Order for {product} placed." );
    }
}

public static class Program
{
    public static async Task Main()
    {
        await new OrderService().PlaceOrderAsync( "Chair" );
    }
}
Calling PlaceOrderAsync asynchronously.
Order for Chair placed.

See Also

Reference

OnMethodInvokeAsyncAdvice
OnMethodInvokeAdvice
OnInvokeAsync

Other Resources

Advice Methods
Semantic Advising of Iterator and Async Methods