| Severity | Error |
| Reported by | PostSharp.Patterns.Threading |
| Message | Cannot add [Background] to method "<Method>" because the [ThreadAffine] threading model is applied to the type "<Type>". Apply [Background] to a static method, or to a method of another type. |
Cause
The ThreadAffineAttribute threading model allows an object to be accessed only from the thread that created it. The BackgroundAttribute aspect executes a method in a thread of the thread pool. An instance method of a thread-affine object with this aspect would therefore always access the object from the wrong thread, so PostSharp reports THR036.
The check applies only to instance methods. A static method does not belong to an object, so it can have the BackgroundAttribute aspect.
In the following example, the BuildReportAsync instance method of the thread-affine OrderListView class has the BackgroundAttribute aspect.
using System;
using System.Threading;
using System.Threading.Tasks;
using PostSharp.Patterns.Threading;
namespace Errors.THR036_Error;
[ThreadAffine]
public class OrderListView
{
private int orderCount;
public int OrderCount => this.orderCount;
public void AddOrder()
{
this.orderCount++;
}
// An instance method of a thread-affine object cannot run in a background thread.
[Background]
public async Task<string> BuildReportAsync( int orderCount )
{
await Task.Yield();
return $"Report of {orderCount} orders, built in the thread pool: {Thread.CurrentThread.IsThreadPoolThread}";
}
}
public static class Program
{
public static void Main()
{
var view = new OrderListView();
view.AddOrder();
view.AddOrder();
var report = view.BuildReportAsync( view.OrderCount ).GetAwaiter().GetResult();
Console.WriteLine( report );
}
}
error THR036: THR036_Error.cs(22,31): Cannot add [Background] to method "Errors.THR036_Error.OrderListView.BuildReportAsync(System.Int32)" because the [ThreadAffine] threading model is applied to the type "Errors.THR036_Error.OrderListView". Apply [Background] to a static method, or to a method of another type.
Resolution
- When the background work does not need the state of the object, make the method
staticand pass it the data it needs as parameters. - Otherwise, move the background work to a method of another class that does not have the ThreadAffineAttribute threading model, and update the thread-affine object from its own thread when the work completes.
In the following example, BuildReportAsync is a static method that receives the number of orders.
using System;
using System.Threading;
using System.Threading.Tasks;
using PostSharp.Patterns.Threading;
namespace Errors.THR036_Fixed;
[ThreadAffine]
public class OrderListView
{
private int orderCount;
public int OrderCount => this.orderCount;
public void AddOrder()
{
this.orderCount++;
}
// A static method does not access the thread-affine object, so it can run in a background thread.
[Background]
public static async Task<string> BuildReportAsync( int orderCount )
{
await Task.Yield();
return $"Report of {orderCount} orders, built in the thread pool: {Thread.CurrentThread.IsThreadPoolThread}";
}
}
public static class Program
{
public static void Main()
{
var view = new OrderListView();
view.AddOrder();
view.AddOrder();
var report = OrderListView.BuildReportAsync( view.OrderCount ).GetAwaiter().GetResult();
Console.WriteLine( report );
}
}
Report of 2 orders, built in the thread pool: True
See Also
Reference
BackgroundAttribute
ThreadAffineAttribute
Other Resources
Thread Affine Threading Model
Dispatching a Method to Background