[英]Using Thread.CurrentPrincipal with async and await?
考慮以下代碼,該代碼在單個執行主線程上設置ClaimsPrincipal,然后運行任務並嘗試訪問ClaimsPrincipal:
public class Program
{
public static void Main(string[] args)
{
//Setting the CurrentPrincipal on the main thread
Thread.CurrentPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim("name", "bob"), new Claim("role", "admin") }, "CUSTOM", "name", "role"));
Console.WriteLine("Thread.CurrentThread.ManagedThreadId " + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("Thread.CurrentPrincipal?.Identity?.Name " + (Thread.CurrentPrincipal?.Identity?.Name ?? "null"));
AsyncHelper.RunSync(
async () =>
{
Console.WriteLine("\tInside Async Method - Thread.CurrentThread.ManagedThreadId " + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("\tInside Async Method - Thread.CurrentPrincipal?.Identity?.Name " + (Thread.CurrentPrincipal?.Identity?.Name ?? "null"));
//Simulate long(er) running work
await Task.Delay(2000);
Console.WriteLine("\tInside Async Method - Thread.CurrentThread.ManagedThreadId " + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("\tInside Async Method - Thread.CurrentPrincipal?.Identity?.Name " + (Thread.CurrentPrincipal?.Identity?.Name ?? "null"));
});
Console.WriteLine("Thread.CurrentThread.ManagedThreadId " + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("Thread.CurrentPrincipal?.Identity?.Name " + (Thread.CurrentPrincipal?.Identity?.Name ?? "null"));
}
}
和
internal static class AsyncHelper
{
private static readonly TaskFactory MyTaskFactory = new
TaskFactory(CancellationToken.None,
TaskCreationOptions.None,
TaskContinuationOptions.None,
TaskScheduler.Default);
public static void RunSync(Func<Task> func)
{
AsyncHelper.MyTaskFactory
.StartNew<Task>(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
}
該程序的輸出是
Thread.CurrentThread.ManagedThreadId 2
Thread.CurrentPrincipal?.Identity?.Name bob
Inside Async Method - Thread.CurrentThread.ManagedThreadId 3
Inside Async Method - Thread.CurrentPrincipal?.Identity?.Name null
Inside Async Method - Thread.CurrentThread.ManagedThreadId 3
Inside Async Method - Thread.CurrentPrincipal?.Identity?.Name null
Thread.CurrentThread.ManagedThreadId 2
Thread.CurrentPrincipal?.Identity?.Name bob
Press any key to exit
我以為我會看到的是:
Thread.CurrentThread.ManagedThreadId 2
Thread.CurrentPrincipal?.Identity?.Name bob
Inside Async Method - Thread.CurrentThread.ManagedThreadId 3
Inside Async Method - Thread.CurrentPrincipal?.Identity?.Name bob <--- Notice here
Inside Async Method - Thread.CurrentThread.ManagedThreadId 3
Inside Async Method - Thread.CurrentPrincipal?.Identity?.Name bob <--- Notice here
Thread.CurrentThread.ManagedThreadId 2
Thread.CurrentPrincipal?.Identity?.Name bob
Press any key to exit
在主線程上設置的ClaimsPrincipal
發生了什么(在此特定輸出ManagedThreadId 2的情況下)? 為什么在復制ExecutionContext時沒有將ClaimsPrincipal復制到另一個線程?
更新 :.Net目標框架是.NET Core 2.0。
更新2 :此問題似乎特定於.NET Core。 使用相同的代碼,但針對.NET 4.6.1框架,我得到了期望的輸出。
您只是不能依賴線程屬性,因為諸如為任務分配線程之類的細節取決於具體的ThreadScheduler( https://msdn.microsoft.com/zh-cn/library/system.threading.tasks.taskscheduler ( v= vs.110).aspx )。 有許多不同的ThreadScheduler實現。
有一個實現您自己的自定義TaskScheduler的選項,您可以在其中將Thread.CurrentPrincipal設置為您的值,但更好的是,不要完全依賴所有線程屬性,而這些屬性始終處於“任務級別”。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.