Unified Service Desk のカスタムのホストされたコントロールに SafeDispatcher を使用します
Unified Service Desk は Windows Presentation Foundation (WPF) ベースのアプリケーションであり、Unified Service Desk のすべての操作はメインの WPF ディスパッチャー スレッドで実行されます。 WPF ディスパッチャー クラスにはスレッドの作業アイテムのキューを管理するためのサービスが用意されています。
カスタム コントロールを作成して Unified Service Desk 内でホストすることにより、Unified Service Desk を拡張できます。 ただし、カスタムのホストされたコントロールが欠陥のあるコードを含んでいるか、コードの実行中に適切に例外を処理せずに新しいスレッドを使用する操作を実行すると、Unified Service Desk の安定性を脅かす問題が発生する可能性があり、クライアント アプリケーションがフリーズしたり応答しなくなる可能性があります。 サードパーティのカスタム コントロールで処理されない例外があると、製品 / サポート チームは Unified Service Desk でエラーや例外の発生理由またはエラーを発生した正確なコードの情報へのアクセス権がないため、問題を特定し、トラブルシューティングして解決するように試みます。
ハンドルされない例外のソースおよび原因に関する詳細情報の標準ログ記録の提供およびその他の手順を実行するための SafeDispatcher 例外処理の構成または上書きによって Unified Service Desk のカスタムのホストされたコントロールに強力かつ有益な例外処理機能を提供する SafeDispatcher の導入。 これは、Unified Service Desk クライアントがカスタムのホストされたコントロール コードのハンドルされない例外のため、応答しなくなることを防ぎます。
SafeDispatcher とは
SafeDispatcher は WPF ディスパッチャー と同じ行に構築され、Unified Service Desk 内のカスタムのホストされたコントロールのための弾性のある有益な例外処理を提供します。 これは保護されたプロパティ SafeDispatcher として DynamicsBaseHostedControl クラスで公開され、SafeDispatcher を DynamicsBaseHostedControl クラスから派生するすべての Unified Service Desk カスタムのホストされたコントロールで自動的に利用可能になります。
Note
SafeDispatcher クラスは SafeDispatcher の作業するコードで使用しないでください。 代わりに、SafeDispatcher を使用するため、DynamicsBaseHostedControl クラスから派生するカスタムのホストされたコントロールのインスタンスで SafeDispatcher プロパティを使用する必要があります。
WPF ディスパッチャー と同様に、SafeDispatcher には、UI スレッドで SafeDispatcher を実行するかどうかを制御する追加のブール値パラメーター runOnMainUiThread
を持つ、SafeDispatcher で同期的または非同期的に操作を実行するための、BeginInvoke、Invoke、およびInvokeAsync などのメソッドが用意されています。
SafeDispatcher には次のような利点があります。
保護されたUIディスパッチャーのスレッド: 開発者は、UI スレッドで SafeDispatcher を実行する呼び出しメソッドで
runOnMainUiThread
パラメーターを "true" に設定することで、SafeDispatcher のすべての UI 依存操作を実行することができます。 メインの UI ディスパッチャーで発生する処理されないすべての例外は、グローバル DispatcherUnhandledException イベント ハンドラーを増加せずに、ホストされたコントロール レベルで安全に処理されます。保護された 非 UI ディスパッチャー スレッド: 開発者は SafeDispatcher ですべての UI 非依存コードを実行できます。 呼び出しメソッドで
runOnMainUiThread
パラメーターを "false" に設定し、非 UI スレッドの SafeDispatcher を実行します。 メインの非 UI ディスパッチャーで発生する処理されないすべての例外は、グローバル DispatcherUnhandledException イベント ハンドラーを増加せずに、ホストされたコントロール レベルで安全に処理されます。例外のソースおよび原因に関する詳細情報 :: SafeDispatcher 例外ハンドラーは、処理されない例外が UI スレッドまたは非 UI スレッドによって DynamicsBaseHostedControl レベルで発生するときに発生し、Unified Service Desk がホストされたコントロール名、ホストされたコントロールの種類、メソッド名などのホストされたコントロール レベルでの重要な情報を取得して、例外の正確な場所と原因を特定できるようにします。
SafeDispatcher 例外ハンドラーの構成または上書き : 開発者は、ハンドルされない例外に関する情報についてユーザーを要求する SafeDispatcher 例外ハンドラーの標準の動作を活用したり、追加のログ記録の構成、セッション ベースのコントロールのクローズ、または Unified Service Desk クライアントの終了などの業務要件を上書きしたりできます。
SafeDispatcher の使用方法
SafeDispatcher プロパティは、DynamicsBaseHostedControl クラスから派生する Unified Service Desk カスタムのホストされたコントロールのインスタンスのすべてに使用することができます。 SafeDispatcher インスタンスは、カスタムのホストされたコントロールが初期化されると UI スレッドでの実行に使用することができます。 ただし、SafeDispatcher インスタンスは呼び出しメソッドを初めて実行するとき、非 UI スレッドでの実行にのみ利用できます。
同期的に SafeDispatcher を使用する UI 固有の機能を呼び出します
SafeDispatcher.Invoke(() => { ProcessData(); }, DispatcherPriority.Normal, CancellationToken.None, true);
OR
SafeDispatcher.Invoke(() => { ProcessData(); }, DispatcherPriority.Normal, CancellationToken.None);
Note
UI 固有の機能では、
runOnMainUiThread
のオプション パラメーターを「true」に設定する必要があります。 このパラメーターの値を指定しない場合、既定で「true」が渡されます。 したがって、上記のメソッドの定義はいずれもうまく機能します。非同期的に SafeDispatcher を使用する UI 固有の機能を呼び出します。
BeginInvoke
またはInvokeAsync
メソッドを使用できます。SafeDispatcher.BeginInvoke(new Action(() => { ProcessData(); }));
または
SafeDispatcher.InvokeAsync(new Action(() => { ProcessData(); }));
SafeDispatcher 例外ハンドラーをカスタマイズします
SafeDispatcher を導入すると、Unified Service Desk の処理されないすべての例外はグローバル DispatcherUnhandledException イベントの代わりに SafeDispatcherUnhandledException イベントを発生させます。 SafeDispatcherUnhandledExceptionHandler メソッド には、例外が発生するソース コントロールおよび例外の詳細を Unified Service Desk ユーザーに表示するための、SafeDispatcher の標準例外ハンドラーが用意されています。
また、セッション ベースの非動的なホストされたコントロールを閉じるユーザーへのプロンプトなどの、その他の操作を実行するために、SafeDispatcher の標準の例外処理を上書きすることもできます。
次のサンプル コードは、例外の発生時にカスタムのホストされたコントロールを閉じるプロンプトを表示するために標準の SafeDispatcher 例外ハンドラーを上書きできる方法を示します。
protected override void SafeDispatcherUnhandledExceptionHandler(object sender, SafeDispatcherUnhandledExceptionEventArgs ex)
{
string error = String.Format(CultureInfo.InvariantCulture,
"Error in hosted control Application:{0} - Exception : {1} \r\nInnerException\r\n {2}", this.ApplicationName, ex.Exception, ex.InnerException);
DynamicsLogger.Logger.Log(error, TraceEventType.Error);
if (MessageBox.Show("Exception occurred in hosted control - " + this.ApplicationName + ".Do you wish to close it ?", "Question", MessageBoxButton.YesNo,
MessageBoxImage.Warning) == MessageBoxResult.Yes)
{
SafeDispatcher.BeginInvoke(() => { this.desktopAccess.CloseDynamicApplication(this.ApplicationName); });
}
}
既存のカスタムのホストされたコントロールでの WPF ディスパッチャーから SafeDispatcher への移行
WPF ディスパッチャーと SafeDispatcher の間の契約はほとんど同じなので、WPF ディスパッチャーから SafeDispatcher への移行のための作業は最小限です。 DynamicsBaseHostedControl クラスから派生した任意のホストされたコントロールのインスタンスを移行するには、すべての "Dispatcher" インスタンスを "SafeDispatcher" に置き換えます。
たとえば、次のようなコードが考えられます。
Dispatcher.Invoke((System.Action)delegate()
{
DynamicsLogger.Logger.Log("Raising SetupHotKey's", TraceEventType.Verbose);
SetupHotkeys();
CRMGlobalManager.AppWithFocusChanged += CRMGlobalManager_AppWithFocusChanged;
FireEvent("DesktopReady");
InitializeFocusSelection();
});
上記のコードの Dispatcher
を SafeDispatcher
に置き換え、残りのコードはそのままにします。
SafeDispatcher.Invoke((System.Action)delegate()
{
DynamicsLogger.Logger.Log("Raising SetupHotKey's", TraceEventType.Verbose);
SetupHotkeys();
CRMGlobalManager.AppWithFocusChanged += CRMGlobalManager_AppWithFocusChanged;
FireEvent("DesktopReady");
InitializeFocusSelection();
});
SafeDispatcher を使用するときに考慮する事項
SafeDispatcher は、UI または非 UI スレッドに関数を同期的または非同期的にディスパッチするのに非常に有利なマルチスレッド モデルを提供します。 フォールト トレランスとともに利用できるスレッドで実行する必要がある操作は、SafeDispatcher で実行する必要があります。 ただし、マルチスレッドはスレッド間のデッドロックを回避するために、非常に注意深く実装する必要があります。 こうした例の 1 つは、非 UI スレッドからメインの WPF ディスパッチャーに同期的にディスパッチすることです。 この例を検討します。
Thread thread = new Thread(() =>
{
Dispatcher.Invoke(ProcessData);
});
thread.SetApartmentState(ApartmentState.STA);
thread.Priority = ThreadPriority.Highest;
thread.IsBackground = true;
thread.Start();
thread.Join();
thread.Join()
メソッドは、シングルスレッド アパートメント (STA) の終了するまでメイン スレッドをブロックして待機しますが、STA スレッドはメイン スレッドが ProcessData
の実行を終了するまで待機します。 これにより、アプリケーションのデッドロック状況が発生します。
同様に、次のような例を考えます。
// Invoke on STA thread
SafeDispatcher.Invoke(() =>
{
// Invoke back on main dispatcher
SafeDispatcher.Invoke(() =>
{
ProcessData();
});
}, false);
例外が WPF ディスパッチャーまたは STA 非 UI スレッドで発生し、例外が発生した各スレッドで発生する場合、SafeDispatcherUnhandledExceptionHandler メソッドが呼び出されます。 非 UI スレッドが発生した場合に、このハンドラーで上記の組み合わせを配置しておらず、同期的にメイン UI のディスパッチャーにディスパッチしないように注意する必要があります。
protected override void SafeDispatcherUnhandledExceptionHandler(object sender, SafeDispatcherUnhandledExceptionEventArgs ex)
{
Dispatcher.Invoke(LogException); // Incorrect
SafeDispatcher.Invoke(LogException); // Incorrect
SafeDispatcher.BeginInvoke(LogException); // Correct
SafeDispatcher.InvokeAsync(LogException); // Correct
}
関連項目
ユーザー定義による Unified Service Desk のホストされたコントロールの作成 Unified Service Desk の拡張 Unified Service Desk でのクライアント診断ログの構成