2017-12-27 8 views
0

Betrachten Sie den folgenden Code, der eine ClaimsPrincipal auf einem einzigen Haupt-Thread von Ausführungssätzen und führt dann eine Aufgabe und versucht, den ClaimsPrincipal zuzugreifen:Verwenden von Thread.CurrentPrincipal mit async und warten?

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

und

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

Die Ausgabe des Programms

ist
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 

Was ich dachte ich sehen würde, ist dies:

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 

Was ist mit dem ClaimsPrincipal passiert, die auf der Haupt-Thread (bei dieser speziellen Ausgabe ManagedThreadId 2) eingestellt wurde? Warum wurde das ClaimsPrincipal nicht in den anderen Thread kopiert, als der ExecutionContext kopiert wurde?

Aktualisieren: Das .NET-Zielframework ist .NET Core 2.0.

Update 2: Dieses Problem scheint spezifisch für .NET Core zu sein. Wenn ich den gleichen Code verwende, aber stattdessen auf .NET 4.6.1 abziele, bekomme ich die erwartete Ausgabe.

+0

Auf welcher .NET-Version führen Sie das aus? – Evk

+0

Das Zielframework ist .NET Core 2.0. Ich denke, ich kann es in einer anderen Version versuchen und sehen, was passiert. –

+1

Ich denke, auf vollen .net (wie 4.6) sollte es funktionieren, wie Sie erwarten – Evk

Antwort

1

Sie können sich nicht auf Thread-Eigenschaften verlassen, da Details wie die Thread-Zuweisung zur Aufgabe von konkreten ThreadScheduler (https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskscheduler(v=vs.110).aspx) abhängen. Es gibt viele verschiedene ThreadScheduler-Implementierungen.

Es gibt eine Option, um Ihren eigenen benutzerdefinierten TaskScheduler zu implementieren, in dem Sie Thread.CurrentPrincipal auf Ihre Werte festlegen, aber besser nicht auf alle Threading-Eigenschaften verlassen, die auf "Task-Ebene" bleiben.