我有一個MVC Web應用程序,它顯示了我們AD中用戶的一些信息。 AD與Office 365同步,因此使用UPN我可以使用Windows PowerShell cmdlets for Office 365從Office 365檢索許可證信息。基本上這一切都很好。不知道爲什麼C#PowerShell運行空間不規律地關閉
由於初始化cmdlet Connect-MsolService
需要一些時間才能完成,因此我爲我的Office365Connector
類使用了一種單例模式。在我的Global.asax
Application_Start()
我初始化單例實例,在Application_End()
我處理它。連接器類正好使用我的PowerShellInvoker
類的一個實例,顧名思義,它封裝了PowerShell調用。在PowerShellInvoker
構造函數中PowerShell的初始化代碼如下所示:
public PowerShellInvoker(params string[] modules)
{
var iss = InitialSessionState.CreateDefault();
iss.ImportPSModule(modules);
iss.ThrowOnRunspaceOpenError = true;
_runspace = RunspaceFactory.CreateRunspace(iss);
_runspace.Open();
_invoker = new RunspaceInvoke(_runspace);
}
的Office365Connector
類調用此構造與"MSOnline"
作爲參數。 MSOnline
模塊包含用於Office 365的cmdlet。我保留_runspace
和_invoker
字段以便稍後執行命令。這兩個字段將在Dispose
方法PowerShellInvoker
(當Office365Connector
類正在處理時調用)中處理。腳本執行由該行代碼完成的:
_invoker.Invoke(scriptText);
這麼多的介紹 - 現在,這裏是真正的問題:
在我的申請,我有一個用戶列表。當我點擊一個用戶時,使用AJAX請求加載附加信息。在此請求中,我的應用使用Office365Connector
類的單例實例來檢索用戶的許可證信息。在大多數情況下,這一切都很完美。但是有時AJAX請求最終會以代碼500結束。調試我的源代碼時,我偶然發現上面「Invoke」行中的PowerShellInvoker
中引發了異常,告訴我Runspace不再打開,而且我也無法找出原因。我甚至不能真正重現它。有時,當我單擊第二個用戶時發生錯誤。有時,錯誤發生在第10或第15個用戶。我已經想過MVC使用的一些奇怪的清理,超時或垃圾收集技術,但我還沒有得出結論。恕我直言,Runspace關閉不能基於時間,因爲「用戶點擊」之間的時間只有幾秒鐘。
該Connect-MsolService
cmdlet創建到Office 365的連接,但它不返回任何內容。因此,如果需要重新創建Runspace不是解決方法,因爲這將由PowerShellInvoker
類完成,並且Office365Connector
不會知道它必須重新連接到Office 365.(這也不會解決問題。 )結合這兩個類不是解決方案,因爲PowerShellInvoker
也在其他地方使用。
那麼有誰能告訴我如何防止Runspace關閉或爲什麼關閉?
編輯:更多代碼
全PowerShellInvoker
類可以發現here。
在Office365Connector
類中,目前存在很多開銷。下面是一些片段:
初始化在構造函數:
var cred = new PSCredential(adminUpn, adminPassword);
_psi = new PowerShellInvoker("MSOnline");
_psi.ExecuteCommand("Connect-MsolService", new { Credential = cred });
方法檢索一個UPN許可證:
public IEnumerable<string> GetUserLicenses(string upn)
{
PSObject[] licenses = _psi.ExecuteScript(string.Format("(Get-MsolUser -UserPrincipalName \"{0}\").Licenses | % {{ $_.AccountSkuId }}", upn)).ToArray();
// no licenses: a list with one element (which is null) is returned.
if (licenses.Length == 1 && licenses[0] == null)
{
licenses = new PSObject[0];
}
return licenses.Select(pso => pso.ToString()).ToList();
}
正如你所看到的,我加了一些ToList
小號到方法返回值(特別是在PowerShellInvoker
)。我這樣做是因爲我想阻止枚舉類的惰性執行,因爲我認爲這可能是關閉的Runspace的原因。
我沒有答案,但我有興趣試圖找出答案。是否有可能分享更多的代碼?另外,您是否嘗試在打開運行空間後立即啓動PowerShell腳本?看看它是否記錄了任何有用的內容會很有趣。 – 2012-07-19 17:14:49
@ ElijahW.Gagne我編輯了這個問題並添加了更多的代碼。我會盡快嘗試記錄的想法。 – fero 2012-07-20 07:47:53
感謝您的問題和答案 - 幫助我在爲PS提供商編寫測試時幫助我! – penderi 2012-10-31 09:54:40