2

AD のユーザーに関する情報を表示する MVC Web アプリケーションがあります。AD は Office 365 と同期されているため、UPN を使用して、Office 365用の Windows PowerShell コマンドレットを使用して Office 365 からライセンス情報を取得できます。基本的に、これはすべて正常に機能します。

初期化コマンドレットConnect-MsolServiceが完了するまでに時間がかかるため、Office365Connectorクラスに一種のシングルトン パターンを使用しています。私のGlobal.asax中でApplication_Start()シングルトンインスタンスを初期化し、Application_End()それを破棄します。コネクタ クラスはPowerShellInvoker、名前が示すように、PowerShell の呼び出しをカプセル化するクラスのインスタンスを 1 つだけ使用します。コンストラクター内の 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);
}

クラスは、パラメータとしてOffice365Connectorこのコンストラクタを呼び出し"MSOnline"ます。このMSOnlineモジュールには、Office 365 のコマンドレットが含まれています。後でコマンドを実行するために、 フィールド_runspaceとフィールドを保持しています。_invoker両方のフィールドは、(クラスが破棄されるときに呼び出される) のDisposeメソッドで破棄されます。スクリプトの実行は、次のコード行によって行われます。PowerShellInvokerOffice365Connector

_invoker.Invoke(scriptText);

紹介は以上です - ここで本当の問題が発生します。

私のアプリケーションには、ユーザー リストがあります。ユーザーをクリックすると、AJAX リクエストを使用して追加情報が読み込まれます。このリクエスト内で、アプリはクラスのシングルトン インスタンスを使用してOffice365Connector、ユーザーのライセンス情報を取得します。ほとんどの場合、これはすべて完全に機能します。しかし、AJAX リクエストがコード 500 で終了することがあります。ソース コードをデバッグしていると、例外がPowerShellInvoker上記の「呼び出し」行で、実行空間がもう開いていないことを教えてくれますが、その理由はわかりません。私は本当にそれを再現することさえできません。2 番目のユーザーをクリックすると、エラーが発生することがあります。場合によっては、10 番目または 15 番目のユーザーでエラーが発生します。MVC で使用される奇妙なクリーンアップ、タイムアウト、またはガベージ コレクションの手法については既に考えましたが、結論には達していません。IMHO、「ユーザーのクリック」の間の時間はわずか数秒であるため、Runspace の終了を時間ベースにすることはできません。

コマンドレットは Office 365 へのConnect-MsolService接続を作成しますが、何も返しません。そのため、必要に応じて実行空間を再作成することは回避策ではありません。これは、PowerShellInvokerクラスによって実行され、 Office365ConnectorOffice 365 に再接続する必要があることを認識しないためです。(これでも問題は解決しません。)クラスは他のPowerShellInvoker場所でも使用されているため、解決策ではありません。

では、Runspace が閉じないようにする方法、または閉じられる理由を誰か教えてもらえますか?

編集:より多くのコード

完全な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) にいくつかの s を追加しました。これを行ったのは、これが閉じられた実行空間の理由である可能性があると考えたため、列挙型の遅延実行を防ぎたかったからです。

4

1 に答える 1

1

OK、これは私自身のばかげた間違いでした-MVCがこれを行っている理由はよくわかりませんが:

この問題を解決するための多くの試みの 1 つで、私は自分の処分コードをアプリケーションOffice365ConnectorDisposeメソッドに移動しました ( Global.asax.cs)。その後、元のエラーを修正したようですが、廃棄物のためにうまくいきませんでした。どうやら、アプリケーションインスタンスは「終了」するよりも頻繁に破棄されます。コードを元のApplication_End()場所に戻すと、すべて正常に機能しました。

私のdisposeコードはすでにApplication_End(). :-\

于 2012-08-15T09:53:48.697 に答える