2

我有一个 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-MsolServicecmdlet 创建与 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)。我这样做是因为我想防止可枚举的延迟执行,因为我认为这可能是关闭运行空间的原因。

4

1 回答 1

1

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

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

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

于 2012-08-15T09:53:48.697 回答