Open sandboxFocusImprove this doc

LA0172: Async Interception Advice Applied to an Unsupported Method

Severity Error
Reported by PostSharp
Message Cannot apply the advice "<Advice>" to target "<Method>": async interception can be applied only to methods that return Task or Task<T> and have no by-reference parameter. Add a non-async OnMethodInvokeAdvice to the group and, if the method returns an awaitable type, set the UnsupportedTargetAction property of the master advice to Fallback, or to Ignore to skip the method.

Cause

An advice marked with OnMethodInvokeAsyncAdvice intercepts the task that a method returns, and supports only the methods that return a Task or a Task<TResult> and have no ref or out parameter. PostSharp reports LA0172 on the target method in the following cases:

  • The method is async void, or returns another awaitable type, such as ValueTask<TResult>, or a task with a by-reference parameter, and the UnsupportedTargetAction property of the master advice of the group keeps its default value, Fail.
  • The method is not advised semantically, for example a method that returns void or a value, and the group of the advice has no advice marked with OnMethodInvokeAdvice to intercept it. The UnsupportedTargetAction property does not suppress the error in this case.

<Advice> is the advice method, and <Method> is the target method.

In the following example, the [Log] aspect has only an async interception advice, and it is applied to a method that returns a ValueTask<decimal>.

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

namespace Errors.LA0172_Error;

[PSerializable]
public class LogAttribute : MethodLevelAspect
{
    [OnMethodInvokeAsyncAdvice]
    public async Task OnInvokeAsync( MethodInterceptionArgs args )
    {
        Console.WriteLine( $"Calling {args.Method.Name} asynchronously." );
        await args.ProceedAsync();
    }
}

public class PriceService
{
    // Async interception does not support methods that return ValueTask<T>.
    [Log]
    public async ValueTask<decimal> GetPriceAsync( string product )
    {
        await Task.Yield();

        return product.Length * 1.5m;
    }
}

public static class Program
{
    public static async Task Main()
    {
        Console.WriteLine( await new PriceService().GetPriceAsync( "Coffee" ) );
    }
}
error LA0172: LA0172_Error.cs(24,37): Cannot apply the advice "Errors.LA0172_Error.LogAttribute.OnInvokeAsync(PostSharp.Aspects.MethodInterceptionArgs)" to target "Errors.LA0172_Error.PriceService.GetPriceAsync(System.String)": async interception can be applied only to methods that return Task or Task<T> and have no by-reference parameter. Add a non-async OnMethodInvokeAdvice to the group and, if the method returns an awaitable type, set the UnsupportedTargetAction property of the master advice to Fallback, or to Ignore to skip the method.

Resolution

  • Make the target method return a Task or a Task<TResult>, without ref or out parameters.
  • Add an advice marked with OnMethodInvokeAdvice to the group, and set the UnsupportedTargetAction property of the master advice to Fallback, so that the non-async advice intercepts the unsupported methods (see LA0173).
  • Set the property to Ignore to skip the async void methods and the methods that return another awaitable type.
  • Do not apply the aspect to the method.

In the following example, the method returns a Task<decimal>, which the advice intercepts.

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

namespace Errors.LA0172_Fixed;

[PSerializable]
public class LogAttribute : MethodLevelAspect
{
    [OnMethodInvokeAsyncAdvice]
    public async Task OnInvokeAsync( MethodInterceptionArgs args )
    {
        Console.WriteLine( $"Calling {args.Method.Name} asynchronously." );
        await args.ProceedAsync();
    }
}

public class PriceService
{
    // The method returns a Task<T>, which async interception supports.
    [Log]
    public async Task<decimal> GetPriceAsync( string product )
    {
        await Task.Yield();

        return product.Length * 1.5m;
    }
}

public static class Program
{
    public static async Task Main()
    {
        Console.WriteLine( await new PriceService().GetPriceAsync( "Coffee" ) );
    }
}
Calling GetPriceAsync asynchronously.
9.0

See Also

Reference

OnMethodInvokeAsyncAdvice
OnMethodInvokeAdvice
UnsupportedTargetAction

Other Resources

Advice Methods
Semantic Advising of Iterator and Async Methods