2013-05-14 9 views
6

Przy użyciu interfejsu ASP.NET WebAPI podczas uwierzytelniania ustawia się Thread.CurrentPrincipal, aby kontrolerzy mogli później korzystać z właściwości ApiController.User.Ustaw Asynchronicznie wątek.CurrentPrincipal?

Jeśli ten krok uwierzytelniania stanie się asynchroniczny (w celu sprawdzenia innego systemu), utracona zostanie jakakolwiek mutacja CurrentPrincipal (gdy program wywołujący await przywróci kontekst synchronizacji).

Oto bardzo uproszczony przykład (w rzeczywistym kodu uwierzytelniania dzieje się w filtrze działania):

using System.Diagnostics; 
using System.Security.Principal; 
using System.Threading; 
using System.Threading.Tasks; 

public class ExampleAsyncController : System.Web.Http.ApiController 
{ 
    public async Task GetAsync() 
    { 
     await AuthenticateAsync(); 

     // The await above saved/restored the current synchronization 
     // context, thus undoing the assignment in AuthenticateAsync(). 
     Debug.Assert(User is GenericPrincipal); 
    } 

    private static async Task AuthenticateAsync() 
    { 
     // Save the current HttpContext because it's null after await. 
     var currentHttpContext = System.Web.HttpContext.Current; 

     // Asynchronously determine identity. 
     await Task.Delay(1000); 
     var identity = new GenericIdentity("<name>"); 

     var roles = new string[] { }; 
     Thread.CurrentPrincipal = new GenericPrincipal(identity, roles); 
     currentHttpContext.User = Thread.CurrentPrincipal; 
    } 
} 

Jak ustawić Thread.CurrentPrincipal w funkcji asynchronicznej tak, że rozmówcy await nie odrzuca tę mutację podczas przywracania kontekstu synchronizacji?

+1

Nie jestem pewien co do twojego problemu, ale najlepiej byłoby go uwierzytelnić przed wywołaniem kontrolera. W moich projektach WebAPI lubię konfigurować 'DelegatingHandler', który dokonuje uwierzytelnienia, zanim dotrze do kontrolera. – Matthew

+0

@Matthew, zgadzam się i tak działa prawdziwy kod, filtr akcji obsługuje uwierzytelnianie przed wywołaniem metody kontrolera. Wyłączyłem filtr akcji, aby uprościć mój przykład, ale problem jest taki sam w obu sytuacjach. –

+0

Od tej odpowiedzi stackoverflow, pojawia się, jeśli ustawisz CurrentPrincipal będzie trwał w wątku wywoływania: http://stackoverflow.com/a/12460170/507793, w przeciwnym razie nie jestem pewien, jak rozwiązać swój problem. – Matthew

Odpowiedz

7

Należy również ustawić HttpContext.Current.User. Aby uzyskać więcej informacji, zobacz this answer i this blog post.

Aktualizacja: zapewniają również używasz na .NET 4.5 i mieć UserTaskFriendlySynchronizationContext zestaw do true.

+0

Dziękuję, że pomogłeś Stephen. Dodałem ustawienie 'HttpContext.Current.User' (i zaktualizowałem kod w moim pytaniu), ale to nie pomaga. Problem pozostaje niezmieniony. –

+0

To zdecydowanie działa dla mnie. Tworzę nowy projekt WebAPI z powyższym kodem w ValuesController i działa dobrze. Pytania uzupełniające: czy korzystasz z platformy .NET 4.5 i czy dla opcji "UseTaskFriendlySynchronizationContext" ustawiono wartość true? –

+0

Ustawienie "UseTaskFriendlySynchronizationContext" na true naprawiło problem! Dziękujemy za poświęcenie czasu na zbadanie sprawy! –

Powiązane problemy