title: Xamarin Android - Task.Run vs Task.Factory.StartNew and Thread.CurrentPrincipal
body: <p>I have an Xamarin.Android project, TargetFramework = Android version: 8.0 (Oreo).</p>
  
  <p>I have noticed the following problem:</p>
  
  <ol>
  <li>Set <code>Thread.CurrentPrincipal</code> to a Custom principal (being extra careful to ensure it is serializable!)</li>
  <li>Call <code>await Task.Run()</code> to run some Task.</li>
  <li>Within the <code>Task</code>, if it executes on a different Thread, the Thread.CurrentPrincipal is not set.</li>
  <li>If you use Task.Factory.StartNew() instead of Task.Run() then the Task that runs on the background thread does have Thread.CurrentPrincipal set correctly.</li>
  </ol>
  
  <p>In other words, Task.Factory.StartNew seems to flow the CurrentPrinciple to new threads, where as Task.Run doesn't</p>
  
  <p>Furthermore if you repeat this test on NET 4.7, Thread.CurrentPrincipal flows correctly in both scenarios, so this difference in behavior only appears when running on Mono / Xamarin.Android.</p>
  
  <p>Here is a test case:</p>
  
  <pre><code>    [Fact]
      public async Task LoginService_WhenUserLogsIn_PrincipalFlowsToAsyncTask()
      {    
  
          var mockIdentity = new MockIdentity(true);
          var mockPrincipal = new MockPrincipal(mockIdentity);          
          Thread.CurrentPrincipal = mockPrincipal ;          
  
          await Task.Factory.StartNew(async () =&gt;
          {
              var newThreadId = Thread.CurrentThread.ManagedThreadId; // on different thread.
              Assert.True(Thread.CurrentPrincipal.Identity.IsAuthenticated);
              Assert.Equal(mockPrincipal, Thread.CurrentPrincipal);
  
              await Task.Factory.StartNew(() =&gt;
              {
                   // still works even when nesting..
                  newThreadId = Thread.CurrentThread.ManagedThreadId;
                  Assert.True(Thread.CurrentPrincipal.Identity.IsAuthenticated);
                  Assert.Equal(mockPrincipal, Thread.CurrentPrincipal);
  
              }, TaskCreationOptions.LongRunning);
  
          }, TaskCreationOptions.LongRunning);
  
          await Task.Run(() =&gt;
          {
             // Following works on NET4.7 and fails under Xamarin.Android.
              var newThreadId = Thread.CurrentThread.ManagedThreadId;
              Assert.True(Thread.CurrentPrincipal.Identity.IsAuthenticated);
              Assert.Equal(mockPrincipal, Thread.CurrentPrincipal);
  
          });
  
      }
  </code></pre>
  
  <p>Here are some screenshots whilst debugging under Xamarin.Android application, showing the following things at different points:</p>
  
  <ol>
  <li>The Thread.CurrentPrinicpal</li>
  <li>The Thread.CurrentThread.ManagedThreadId</li>
  <li>TaskScheduler.Default</li>
  <li>TaskScheduler.Current</li>
  <li>TaskScheduler.FromCurrentSynchronizationContext();</li>
  </ol>
  
  <p>This is what things look like prior to StartNew():</p>
  
  <p><a href="https://i.stack.imgur.com/28AOo.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/28AOo.png" alt="enter image description here"></a></p>
  
  <p>Here is what things look like inside <code>StartNew()</code>: </p>
  
  <p><a href="https://i.stack.imgur.com/ssJMP.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/ssJMP.png" alt="enter image description here"></a></p>
  
  <p>Note that, the Task scheduled via StartNew() is executing on a thread pool thread, and the ShcnronisationContext TaskScheduler is null because there is no current Synchronisation Context at this point. However, also note that the principal of the thread is set correctly to "Daz" identity.</p>
  
  <p>Here is what things look like, after awaiting Task.Factory.StartNew() and before calling Task.Run():</p>
  
  <p><a href="https://i.stack.imgur.com/AxZ33.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/AxZ33.png" alt="enter image description here"></a></p>
  
  <p>Note that we are back on the main thread again, just like we were prior to calling StartNew().</p>
  
  <p>However it appears the SyncContext TaskScheduler has changed (it's ID is now 3). Not sure if that is relevant to this problem.</p>
  
  <p>Now this is what things look like during Task.Run():</p>
  
  <p><a href="https://i.stack.imgur.com/gw5Vs.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/gw5Vs.png" alt="enter image description here"></a></p>
  
  <p>Note: The Thread.CurrentPrincipal.IdentityName has been lost (i.e because the Prinicpal has not flowed to this thread as it did with StartNew().</p>
  
  <p>We are still on a background thread, just like we were with StartNew().
  There is no SynchronisationContext on this thread, which is what we expect with a background thread, and was the same within StartNew() so no difference there.
  The Default and Current task schedulers look the same (both ID = 1) so no difference there either.</p>
  
  <p>The only difference I can see, is that the Principal has not flowed to the thread.</p>
  
  <p>What is the reason? Is this a bug? I thought Thread.CurrentPrinicpal should always flow with the ExecutionContext when using Task.Run().</p>
  
  <p>I have also raised an issue on Github here: <a href="https://github.com/xamarin/xamarin-android/issues/1130" rel="nofollow noreferrer">https://github.com/xamarin/xamarin-android/issues/1130</a></p>
  
  <p>UPDATE: It looks like this has been acknowledged as a bug, hopefully it will be fixed with: <a href="https://github.com/mono/mono/pull/6326/files" rel="nofollow noreferrer">https://github.com/mono/mono/pull/6326/files</a></p>