[英]Don't know why C# PowerShell Runspace is closing irregularly
我有一个MVC Web应用程序,其中显示了有关我们AD中用户的一些信息。 AD与Office 365同步,因此使用UPN可以使用Office 365的Windows PowerShell cmdlet从Office 365检索许可证信息。 基本上,这一切都很好。
由于初始化cmdlet Connect-MsolService
需要一些时间才能完成,因此我在Office365Connector
类中使用了一种单例模式。 在Application_Start()
Global.asax
中,我初始化单例实例,在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
字段以供以后执行命令。 这两个字段都将在PowerShellInvoker
的Dispose
方法中进行处置(在Dispose
Office365Connector
类时会调用此Office365Connector
)。 脚本执行通过以下代码行完成:
_invoker.Invoke(scriptText);
这么多的介绍-现在是真正的问题:
在我的应用程序中,我有一个用户列表。 当我单击用户时,将使用AJAX请求加载其他信息。 在此请求中,我的应用程序使用Office365Connector
类的单例实例来检索用户的许可证信息。 在大多数情况下,这一切都很好。 但是有时AJAX请求最终以代码500结束。在调试我的源代码时,我偶然发现PowerShellInvoker
在上面“调用”行上引发了异常,告诉我运行空间不再打开,并且我不能找出原因。 我什至无法真正复制它。 有时,当我单击第二个用户时,会发生错误。 有时,错误发生在第10位或第15位用户上。 我已经考虑过MVC使用的一些怪异的清理,超时或垃圾收集技术,但是我尚未得出结论。 恕我直言,运行空间的关闭不能基于时间,因为“用户单击”之间的时间只有几秒钟。
Connect-MsolService
cmdlet创建与Office 365的连接,但不返回任何内容。 因此,如果需要的话,重新创建运行空间不是一种解决方法,因为这将由PowerShellInvoker
类完成,并且Office365Connector
不会知道它必须重新连接至Office365Connector
。(这也无法解决问题。)这两个类都不是解决方案,因为PowerShellInvoker
也用在其他地方。
那么谁能告诉我如何防止运行空间关闭或为什么关闭它?
编辑:更多代码
完整的PowerShellInvoker
类可在此处找到。
在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()
。 : - \\
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.