2016-02-17 13 views
5

Ich benutze ASP.Net Web API 2 /. Net 4.5.2.Behalten Principal in der Warteschlange Hintergrund Arbeit Artikel

Ich versuche, den aufrufenden Principal beizubehalten, wenn ein Hintergrundarbeitselement in die Warteschlange gestellt wird. Zu diesem Zweck, ich versuche zu:

Thread.CurrentPrincipal = callingPrincipal; 

Aber wenn ich so tun, erhalte ich eine ObjectDisposedException:

System.ObjectDisposedException: Sicherer Griff hat

geschlossen Wie behalte ich den aktuellen Principal in dem Hintergrundarbeitselement?
Kann ich irgendwie eine Kopie des Prinzipals erstellen?

public void Run<T>(Action<T> action) 
{ 
    _logger.Debug("Queueing background work item"); 
    var callingPrincipal = Thread.CurrentPrincipal; 
    HostingEnvironment.QueueBackgroundWorkItem(token => 
    { 
     try 
     { 
      // UNCOMMENT - THROWS EXCEPTION 
      // Thread.CurrentPrincipal = callingPrincipal; 
      _logger.Debug("Executing queued background work item"); 
      using (var scope = DependencyResolver.BeginLifetimeScope()) 
      { 
       var service = scope.Resolve<T>(); 
       action(service); 
      } 
     } 
     catch (Exception ex) 
     { 
      _logger.Fatal(ex); 
     } 
     finally 
     { 
      _logger.Debug("Completed queued background work item"); 
     } 
    }); 
} 
+0

Haben Sie eigentlich die 'Thread.CurrentPrincipal' benötigen, oder tun Sie wirklich' HttpContext.User' brauchen? Vielleicht erläutern Sie, warum Sie den aktuellen Prinzipal so fließen müssen. –

+0

Was ist der Grund dafür, den aktuellen Principal im Hintergrund Thread zu halten? – Win

+0

Um einige persönliche Daten zu erhalten, die z. B. sehr zeitaufwendig sind. – VMAtm

Antwort

5

Es stellt sich heraus ClaimsPrincipal hat jetzt einen Kopierkonstruktor.

var principal = new ClaimsPrincipal(Thread.CurrentPrincipal); 

Das scheint das Problem zu beheben, während alle Identitäts- und Anspruchsinformationen beibehalten werden. Die vollständige Funktion folgt:

public void Run<T>(Action<T> action) 
{ 
    _logger.Debug("Queueing background work item"); 
    var principal = new ClaimsPrincipal(Thread.CurrentPrincipal); 

    HostingEnvironment.QueueBackgroundWorkItem(token => 
    { 
     try 
     { 
      Thread.CurrentPrincipal = principal; 
      _logger.Debug("Executing queued background work item"); 
      using (var scope = DependencyResolver.BeginLifetimeScope()) 
      { 
       var service = scope.Resolve<T>(); 
       action(service); 
      } 
     } 
     catch (Exception ex) 
     { 
      _logger.Fatal(ex); 
     } 
     finally 
     { 
      _logger.Debug("Completed queued background work item"); 
     } 
    }); 
} 
0

Das Problem Ihrer Situation ist, dass die Hintergrundaufgabe nach ausgeführt wird, die Thread.CurrentPrincipal angeordnet ist. Dies geschieht aufgrund des ASP.NET-Modells - die Anforderung wird im Benutzerkontext behandelt, und danach werden alle dem Benutzer entsprechenden Werte freigegeben. Das passiert genau mit deiner Identität. Versuchen Sie, die Informationen über den Benutzer und seine Identität zu speichern, um es später als Identität darzustellen.

Sie können eine support article from Microsoft für Identitätswechsel die Operationen in ASP.NET-Websites überprüfen, aber ich glaube nicht, dass dies für Sie hilfreich sein:

System.Security.Principal.WindowsImpersonationContext impersonationContext; 
impersonationContext = 
    ((System.Security.Principal.WindowsIdentity)callingPrincipal.Identity).Impersonate(); 

//Insert your code that runs under the security context of the authenticating user here. 

impersonationContext.Undo(); 

oder sein kann, können Sie die Benutzer verwenden .Token, etwa wie folgt:

HostingEnvironment.QueueBackgroundWorkItem(token => 
{ 
    try 
    { 
     _logger.Debug("Executing queued background work item"); 
     using (HostingEnvironment.Impersonate(callingPrincipal.Identity)) 
     { 
      using (var scope = DependencyResolver.BeginLifetimeScope()) 
      { 
       var service = scope.Resolve<T>(); 
       action(service); 
      } 
     } 
     // UNCOMMENT - THROWS EXCEPTION 
     // Thread.CurrentPrincipal = callingPrincipal; 
    } 
    catch (Exception ex) 
    { 
     _logger.Fatal(ex); 
    } 
    finally 
    { 
     _logger.Debug("Completed queued background work item"); 
    } 
}); 

ich schlage vor, Sie Ihr Architektur-Design zu überprüfen, so dass Sie einen Weg, um den Hintergrundbetrieb zu bewegen, um anderen Kontext zu finden, in dem die Benutzeridentität länger bleiben würde. Andere Art und Weise, zum Beispiel, ist die Weitergabe der aktuellen OperationContext zum Task zu verwenden:

// store local operation context 
var operationContext = OperationContext.Current; 
TaskFactory.StartNew(() => 
{ 
    // initialize the current operation context 
    OperationContext.Current = operationContext; 
    action(); 
}) 
+0

OP ist ganz anders als Identitätswechsel.Das Problem, das den Hauptthread hat, wird beseitigt, während Hintergrundthread verarbeitet wird. ** Es ist keine gute Praxis in ASP.Net ** weshalb Yuval Itzchakov und ich fragen. Normalerweise speichern wir die Daten im persistenten Speicher wie die Datenbank, bevor sie im Hintergrundthread verarbeitet werden. – Win

+0

Ich verstehe das Problem und versuchte zu erklären, wie man nicht an 'CurrentThread' für die lange Operation bindet. – VMAtm

Verwandte Themen