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