我有一个 MVC Web 应用程序,它显示了我们 AD 中用户的一些信息。AD 与 Office 365 同步,因此使用 UPN,我可以使用适用于 Office 365 的Windows PowerShell cmdlet从 Office 365 检索许可证信息。基本上这一切都很好。
由于初始化 cmdletConnect-MsolService
需要一些时间才能完成,因此我正在为我的Office365Connector
班级使用一种单例模式。在我Global.asax
的 inApplication_Start()
我初始化单例实例,在Application_End()
我处置它。连接器类只使用了我的类的一个实例PowerShellInvoker
——顾名思义——封装了 PowerShell 调用。构造函数中的 PowerShell 初始化代码PowerShellInvoker
如下所示:
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);
}
该类使用as 参数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
不知道它必须重新连接到 Office 365。(这也不能解决问题。)将两者结合起来classes 也不是解决方案,因为在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
在方法返回值中添加了一些 s(尤其是在 中PowerShellInvoker
)。我这样做是因为我想防止可枚举的延迟执行,因为我认为这可能是关闭运行空间的原因。