| Severity | Warning |
| Reported by | PostSharp |
| Message | An exception thrown by the OnYield or OnResume advice of the aspect "<Aspect>" in the async method "<Method>" follows the behavior of PostSharp 2026.0: it skips the catch and finally blocks around the await and the OnExit advices. Set the MSBuild property PostSharpCompatibilityLevel to 2027.0 to let it flow as an exception of the await expression, or to 2026.0 to keep this behavior without this warning. |
Cause
Since PostSharp 2027.0, the path of an exception thrown by the OnYield(MethodExecutionArgs) or OnResume(MethodExecutionArgs) advice of an async method depends on the PostSharpCompatibilityLevel MSBuild property:
- At
2027.0or higher, the exception flows through the method as an exception of theawaitexpression, so thecatchandfinallyblocks of the method and theOnExitadvices run. - Below
2027.0, or when the property is not set, the exception keeps the behavior of PostSharp 2026.0: it skips thecatchandfinallyblocks around theawaitand theOnExitadvices, and faults the task.
When the property is not set, PostSharp keeps the previous behavior and reports LA0250, so that you choose one. It reports the warning on the async method, once per aspect type that has an OnYield or OnResume advice applied to an async method, including the aspects of the Pattern Libraries. The behavior is the same whether the compiler implements the method with a state machine or with runtime async. The warning is reported whether or not the advices throw.
In the following example, the [Profile] aspect has OnYield and OnResume advices, and is applied to an async method. The @Property(CompatibilityLevel=) directive clears the compatibility level, as a project that does not set PostSharpCompatibilityLevel does.
// @Property(CompatibilityLevel=)
using System;
using System.Threading.Tasks;
using PostSharp.Aspects;
using PostSharp.Serialization;
namespace Errors.LA0250_Error;
[PSerializable]
public class ProfileAttribute : OnMethodBoundaryAspect
{
public override void OnEntry( MethodExecutionArgs args ) => Console.WriteLine( $"{args.Method.Name} starts." );
public override void OnYield( MethodExecutionArgs args ) => Console.WriteLine( $"{args.Method.Name} is suspended." );
public override void OnResume( MethodExecutionArgs args ) => Console.WriteLine( $"{args.Method.Name} resumes." );
public override void OnExit( MethodExecutionArgs args ) => Console.WriteLine( $"{args.Method.Name} completes." );
}
public class OrderService
{
// The project does not set PostSharpCompatibilityLevel, and the aspect has OnYield and OnResume advices.
[Profile]
public async Task<int> CountOrdersAsync()
{
await Task.Delay( 10 );
return 3;
}
}
public static class Program
{
public static void Main()
{
int count = new OrderService().CountOrdersAsync().GetAwaiter().GetResult();
Console.WriteLine( $"{count} orders." );
}
}
warning LA0250: LA0250_Error.cs(26,28): An exception thrown by the OnYield or OnResume advice of the aspect "Errors.LA0250_Error.ProfileAttribute" in the async method "Errors.LA0250_Error.OrderService.CountOrdersAsync" follows the behavior of PostSharp 2026.0: it skips the catch and finally blocks around the await and the OnExit advices. Set the MSBuild property PostSharpCompatibilityLevel to 2027.0 to let it flow as an exception of the await expression, or to 2026.0 to keep this behavior without this warning.
Resolution
Set the PostSharpCompatibilityLevel MSBuild property in your project, or for all the projects of a directory in a Directory.Build.props file:
<PropertyGroup>
<PostSharpCompatibilityLevel>2027.0</PostSharpCompatibilityLevel>
</PropertyGroup>
- Set it to
2027.0to adopt the new behavior. An aspect must then tolerate that the method continues after itsOnYieldorOnResumeadvice throws, because the user code can catch the exception. - Set it to
2026.0to keep the previous behavior without the warning.
In the following example, the @Property(CompatibilityLevel=2027.0) directive sets the compatibility level as the MSBuild property does, and PostSharp reports no warning.
// @Property(CompatibilityLevel=2027.0)
using System;
using System.Threading.Tasks;
using PostSharp.Aspects;
using PostSharp.Serialization;
namespace Errors.LA0250_Fixed;
[PSerializable]
public class ProfileAttribute : OnMethodBoundaryAspect
{
public override void OnEntry( MethodExecutionArgs args ) => Console.WriteLine( $"{args.Method.Name} starts." );
public override void OnYield( MethodExecutionArgs args ) => Console.WriteLine( $"{args.Method.Name} is suspended." );
public override void OnResume( MethodExecutionArgs args ) => Console.WriteLine( $"{args.Method.Name} resumes." );
public override void OnExit( MethodExecutionArgs args ) => Console.WriteLine( $"{args.Method.Name} completes." );
}
public class OrderService
{
// The directive at the top of the file sets the compatibility level to 2027.0, as PostSharpCompatibilityLevel does.
[Profile]
public async Task<int> CountOrdersAsync()
{
await Task.Delay( 10 );
return 3;
}
}
public static class Program
{
public static void Main()
{
int count = new OrderService().CountOrdersAsync().GetAwaiter().GetResult();
Console.WriteLine( $"{count} orders." );
}
}
CountOrdersAsync starts.
CountOrdersAsync is suspended.
CountOrdersAsync resumes.
CountOrdersAsync completes.
3 orders.
See Also
Reference
OnYield(MethodExecutionArgs)
OnResume(MethodExecutionArgs)
Other Resources
Semantic Advising of Iterator and Async Methods
Well-Known MSBuild Properties