繁体   English   中英

不知道为什么C#PowerShell Runspace不定期关闭

[英]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字段以供以后执行命令。 这两个字段都将在PowerShellInvokerDispose方法中进行处置(在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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM