简体   繁体   English

使用Thread.CurrentPrincipal与异步和等待?

[英]Using Thread.CurrentPrincipal with async and await?

Consider the following code that sets a ClaimsPrincipal on a single, main thread of execution and then runs a task and tries to access the ClaimsPrincipal: 考虑以下代码,该代码在单个执行主线程上设置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"));
    }
}

and

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();
    }
}

The output of the program is 该程序的输出是

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

What I thought I would see is this: 以为我会看到的是:

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

What happened to the ClaimsPrincipal that was set on the main thread (in the case of this specific output ManagedThreadId 2)? 在主线程上设置的ClaimsPrincipal发生了什么(在此特定输出ManagedThreadId 2的情况下)? Why did the ClaimsPrincipal not get copied to the other thread when the ExecutionContext was copied? 为什么在复制ExecutionContext时没有将ClaimsPrincipal复制到另一个线程?

Update : The .Net target framework is .NET Core 2.0. 更新 :.Net目标框架是.NET Core 2.0。

Update 2 : This issue seems to be specific to .NET Core. 更新2 :此问题似乎特定于.NET Core。 Using the same code but instead targeting the .NET 4.6.1 framework I get the output I expect. 使用相同的代码,但针对.NET 4.6.1框架,我得到了期望的输出。

You just can't rely on thread properties, since such details as threads assignment to the task depends on concrete ThreadScheduler ( https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskscheduler(v=vs.110).aspx ) . 您只是不能依赖线程属性,因为诸如为任务分配线程之类的细节取决于具体的ThreadScheduler( https://msdn.microsoft.com/zh-cn/library/system.threading.tasks.taskscheduler ( v= vs.110).aspx )。 There are many different ThreadScheduler implementations. 有许多不同的ThreadScheduler实现。

There is an option to implement your own custom TaskScheduler where you will set Thread.CurrentPrincipal to your values, but better just do not rely on all threading properties at all staying on "task level". 有一个实现您自己的自定义TaskScheduler的选项,您可以在其中将Thread.CurrentPrincipal设置为您的值,但更好的是,不要完全依赖所有线程属性,而这些属性始终处于“任务级别”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM