繁体   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