2016-02-17 44 views
5

我正在使用ASP.Net Web API 2/.Net 4.5.2。保留隊列中的主體內部工作項

我試圖在排隊後臺工作項目時保留調用委託人。爲此,我想:

Thread.CurrentPrincipal = callingPrincipal; 

但是,當我這樣做,我得到一個的ObjectDisposedException:

System.ObjectDisposedException:安全句柄已關閉

如何我是否將當前的委託人保留在後臺工作項目中?
我能否以某種方式製作校長副本?

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

你確實需要'Thread.CurrentPrincipal',還是你真的需要'HttpContext.User'?也許詳細說明爲什麼你需要像這樣流動當前的委託人。 –

+0

在後臺線程中保留Current Principal的原因是什麼? – Win

+0

例如,獲取一些非常耗時的個人數據。 – VMAtm

回答

5

原來ClaimsPrincipal現在有一個拷貝構造函數。

var principal = new ClaimsPrincipal(Thread.CurrentPrincipal); 

這似乎可以解決問題,同時保留所有身份和聲明信息。完整的功能如下:

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

你的情況的問題是在處置Thread.CurrentPrincipal之後執行的後臺任務。發生這種情況是因爲ASP.NET模型 - 請求正在用戶上下文中處理,之後所有與用戶對應的值都被釋放。所以這恰好發生在你的身份上。嘗試保存關於用戶和他的身份的信息以便稍後模擬它。

您可以查看一個support article from Microsoft在ASP.NET網站冒充的操作,但我不認爲這將是對你有幫助:

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

,或者可能是,你可以使用用戶.Token,這樣的事情:

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

我建議你檢查你的架構設計,所以你可以找到一種方法,後臺操作移動到其他方面,其中用戶身份會停留更長的時間。其他的方式,例如,是使用傳遞當前OperationContextTask

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

OP與假冒完全不同。主線程有OP的問題是在Background Thread正在處理的時候配置的。 **在ASP.Net **中這不是一個好習慣,這就是爲什麼Yuval Itzchakov和我問。通常,我們將數據存儲在數據庫之類的持久性存儲中,然後在後臺線程中處理。 – Win

+0

我明白了這個問題,並試圖解釋如何在長操作中不綁定到'CurrentThread'。 – VMAtm