簡體   English   中英

使用Thread.CurrentPrincipal與異步和等待?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM