我有一个MVC Web应用程序,该应用程序在我们的AD中显示有关用户的一些信息。 AD与Office 365同步,因此使用UPN可以使用Windows PowerShell cmdlets for Office 365从Office 365检索许可证信息。基本上,这一切都很好。
由于初始化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结尾。在调试我的源代码时,我偶然发现上面“调用”行上的PowerShellInvoker
中引发了异常,告诉我运行空间不再打开,并且我不能找出原因。我什至无法真正复制它。有时,当我单击第二个用户时,会发生错误。有时,错误发生在第10位或第15位用户上。我已经考虑过MVC使用的一些怪异的清理,超时或垃圾收集技术,但是我尚未得出结论。恕我直言,运行空间的关闭不能基于时间,因为“用户单击”之间的时间只有几秒钟。Connect-MsolService
cmdlet创建与Office 365的连接,但不返回任何内容。因此,如果需要的话,重新创建运行空间不是一种解决方法,因为这将由PowerShellInvoker
类完成,而Office365Connector
将不知道必须重新连接到Office365。(这也无法解决问题。)这两个类都不是解决方案,因为PowerShellInvoker
也用在其他地方。那么谁能告诉我如何防止运行空间关闭或为什么关闭它?
编辑:更多代码
完整的
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的原因。 最佳答案
好的,这是我自己的一个愚蠢错误-尽管我不太了解MVC为什么这样做:
在解决问题的众多尝试之一中,我将Office365Connector
的处置代码移动到应用程序的Dispose
方法中(在Global.asax.cs
中)。在那之后,我显然解决了原始错误,但是由于处理错误而无法解决。显然,应用程序实例比“结束”实例的处置频率更高。当我将代码移回属于它的Application_End()
时,一切正常。
这使我原来的问题有点无效,因为我写道我的处置代码已经在Application_End()
中。 :-\
关于c# - 不知道为什么C#PowerShell Runspace不定期关闭,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11564774/