【问题标题】:Don't know why C# PowerShell Runspace is closing irregularly不知道为什么 C# PowerShell Runspace 不规则关闭
【发布时间】:2012-07-19 16:00:43
【问题描述】:

我有一个 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 字段以供以后执行命令。这两个字段都将在PowerShellInvokerDispose 方法中进行处理(在处理Office365Connector 类时调用该方法)。脚本执行由这行代码完成:

_invoker.Invoke(scriptText);

介绍就这么多——现在真正的问题来了:

在我的应用程序中,我有一个用户列表。当我单击用户时,会使用 AJAX 请求加载附加信息。在此请求中,我的应用程序使用 Office365Connector 类的单例实例来检索用户的许可证信息。在大多数情况下,这一切都很完美。但有时 AJAX 请求以代码 500 结束。调试我的源代码时,我偶然发现在上面“调用”行的PowerShellInvoker 中抛出了一个异常,告诉我运行空间不再打开,我可以不知道为什么。我什至无法真正复制它。有时,当我单击第二个用户时会发生错误。有时,错误发生在第 10 位或第 15 位用户身上。我已经想过 MVC 使用的一些奇怪的清理、超时或垃圾收集技术,但我还没有得出结论。恕我直言,Runspace 关闭不能基于时间,因为“用户点击”之间的时间只有几秒钟。

Connect-MsolService cmdlet 创建到 Office 365 的连接,但它不返回任何内容。因此,如果需要重新创建运行空间不是一种解决方法,因为这将由 PowerShellInvoker 类完成,而 Office365Connector 不会知道它必须重新连接到 Office 365。(而且这不会 解决这个问题。)结合这两个类也不是一个解决方案,因为PowerShellInvoker也在其他地方使用。

那么谁能告诉我如何防止运行空间关闭或为什么它被关闭?

编辑:更多代码

完整的PowerShellInvoker类可以在here找到。

Office365Connector 类中,目前有很多开销。以下是一些sn-ps:

在构造函数中初始化:

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

如您所见,我在方法返回值中添加了一些ToLists(尤其是在PowerShellInvoker 中)。我这样做是因为我想防止可枚举的延迟执行,因为我认为这可能是关闭 Runspace 的原因。

【问题讨论】:

  • 我没有答案,但我有兴趣尝试找出答案。您可以分享更多代码吗?另外,您是否尝试过在打开运行空间后立即启动 PowerShell 脚本?看看它是否记录了任何有用的东西会很有趣。
  • @ElijahW.Gagne 我编辑了问题并添加了更多代码。我会尽快尝试转录的想法。
  • 感谢老兄的问答 - 在尝试为 PS 提供商编写测试时帮助了我!

标签: c# asp.net-mvc-3 powershell office365


【解决方案1】:

好吧,这是我自己犯的一个愚蠢的错误——虽然我真的不明白为什么 MVC 会这样做:

在我解决问题的众多尝试之一中,我将Office365Connector 的处理代码移至应用程序的Dispose 方法(在Global.asax.cs 中)。在那之后,我显然修复了原始错误,但由于处置的东西,它没有解决。显然,应用程序实例的处置频率比“结束”的频率高。当我将代码移回它所属的Application_End() 时,一切正常。

这使我原来的问题有点无效,因为我写了我的处置代码已经在Application_End() 中。 :-\

【讨论】:

    猜你喜欢
    • 2012-03-14
    • 2018-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多