Verwendung SafeDispatcher für die benutzerdefinierte Steuerelemente in Unified Service Desk

Unified Service Desk ist eine Windows Presentation Foundation (WPF)-basierte Anwendung, bei der alle Vorgänge in Unified Service Desk auf dem Haupt-Thread WPF Dispatcher ausgeführt werden. Die WPF Dispatcher-Klasse stellt Services für die Verwaltung von Warteschlange Arbeitselementen für einen Thread bereit.

Sie können Unified Service Desk erweitern, indem Sie angepasste Steuerelemente erstellen und in Unified Service Desk hosten. Wenn ein benutzerdefiniertes gehostetes Steuerelement jedoch fehlerhaften Code enthält oder Vorgänge unter Verwendung neuer Threads ausführt, ohne Ausnahmen während der Codeausführung angemessen zu behandeln, kann dies zu Stabilitätsproblemen in Unified Service Desk führen und sogar dazu, dass die Client-Anwendung einfriert oder nicht mehr reagiert. Die unbehandelten Ausnahmen in angepassten Steuerelementen von Drittanbietern machen es für das Produkt-/Supportteam schwierig, das Problem zu identifizieren, zu beheben und zu lösen, da sie möglicherweise keinen Zugriff auf die Informationen haben, warum ein Fehler/eine Ausnahme in Unified Service Desk aufgetreten ist, und auf den genauen Code, der den Fehler verursacht hat.

Einführung von SafeDispatcher, das einen leistungsstarken und informativen Mechanismus zur Behandlung von Ausnahmen für benutzerdefinierte gehostete Steuerelemente in Unified Service Desk bietet, indem es ein Out-of-Box-Protokoll für unbehandelte Ausnahmen mit detaillierten Informationen über die Quelle und die Ursache der Ausnahme bereitstellt und es Ihnen erlaubt, die SafeDispatcher-Ausnahmebehandlung zu konfigurieren oder zu überschreiben, um einige andere Schritte durchzuführen. Dadurch wird auch verhindert, dass der Unified Service Desk Client aufgrund von unbehandelten Ausnahmen im Code des angepassten gehosteten Steuerelements nicht mehr reagiert.

Was ist SafeDispatcher?

SafeDispatcher basiert auf denselben Zeilen wie der WPF Dispatcher und bietet eine robuste und informative Ausnahmebehandlung für angepasste gehostete Steuerelemente innerhalb von Unified Service Desk. Er ist als geschützte Eigenschaft SafeDispatcher in der Klasse DynamicsBaseHostedControl enthalten, wodurch SafeDispatcher automatisch für alle angepassten gehosteten Steuerelemente von Unified Service Desk verfügbar ist, die von der Klasse DynamicsBaseHostedControl abgeleitet sind.

Notiz

Verwenden Sie die SafeDispatcher-Klasse nicht in Ihrem Code, um mit SafeDispatcher zu arbeiten. Stattdessen müssen Sie die Eigenschaft SafeDispatcher auf Ihrer benutzerdefinierten gehosteten Steuerelement-Instanz verwenden, die von der Klasse DynamicsBaseHostedControl abgeleitet ist, um SafeDispatcher zu verwenden.

Wie bei WPF Dispatcher stellt SafeDispatcher Methoden wie BeginInvoke, Invoke und InvokeAsync bereit, um Ausführungsvorgänge synchron oder asynchron in runOnMainUiThread auszufüḧren mit einem weiteren booleschen Parameter, der bestimmt, ob SafeDispatcher im UI-Thread oder nicht ausgeführt wird.

SafeDispatcher bietet die folgenden Vorteile:

  • Geschützter UI Dispatcher Thread:Entwickler können alle UI-abhängigen Vorgänge auf SafeDispatcher ausführen, indem sie den runOnMainUiThread Parameter auf "True" in der Invoke-Methode zum Ausführen von SafeDispatcher im UI-Thread festlegen. Jede nicht verarbeitete Ausnahme, die für den Haupt-UI-Dispatcher ausgelöst wird, wird sicher auf der Ebene des gehosteten Steuerelements verarbeitet statt vom globalen Handler DispatcherUnhandledExceptions-Ereignis.

  • Geschützter Nicht-UI-Dispatcher-Thread: Entwickler können alle UI-unabhängigen Code auf SafeDispatcher ausführen. mithilfe des runOnMainUiThread-Parameters auf "False" in der Invoke-Methode zum ausführen des SafeDispatcher Nicht-UI Threads. Jede nicht verarbeitete Ausnahme, die für Nicht-UI-Dispatcher ausgelöst wird, wird sicher auf der Ebene des gehosteten Steuerelements verarbeitet statt vom globalen Handler DispatcherUnhandledExceptions-Ereignis.

  • Detaillierte Informationen über Ausnahmequelle und -ursache:: Der SafeDispatcher Exception Handler wird ausgelöst, wenn eine unbehandelte Ausnahme auf der Ebene DynamicsBaseHostedControl durch den UI- oder Nicht-UI-Thread ausgelöst wird. Dies lässt zu, dass Unified Service Desk wichtige Informationen auf der Ebene des gehosteten Steuerelements erfasst, z.B. den Namen des gehosteten Steuerelements, den Typ des gehosteten Steuerelements, den Namen der Methode und den vollständigen Stack-Trace, um den genauen Ort und die Ursache der Ausnahme zu identifizieren.

  • Konfigurieren oder überschreiben Sie den SafeDispatcher Handler für Ausnahmen: Entwickler können das standardmäßige Verhalten des SafeDispatcher Handlers für Ausnahmen nutzen, um den Benutzer mit Informationen über die unbehandelte Ausnahme zu versorgen oder das Verhalten entsprechend ihrer Geschäftsanforderungen zu überschreiben, z.B. zusätzliche Protokollierung konfigurieren, sitzungsbasierte Steuerelemente schließen oder den Unified Service Desk Client beenden.

So verwenden Sie SafeDispatcher

Die Eigenschaft SafeDispatcher ist für alle benutzerdefinierten gehosteten Steuerelemente von Unified Service Desk verfügbar, die von der Klasse DynamicsBaseHostedControl abgeleitet sind. Eine SafeDispatcher-Instanz ist verfügbar, um über den UI-Thread ausgeführt zu werden, wenn das benutzerdefinierte gehostete Steuerelement initialisiert wird. Eine SafeDispatcher-Instanz nur verfügbar, um über den Nicht-UI-Thread auszuführen, wenn Sie die Invoke-Methode zum ersten mal ausführen.

  • Eine UI-spezifische Funktion über den SafeDispatcher synchron aufrufen

    SafeDispatcher.Invoke(() =>
                {
                    ProcessData();
                }, DispatcherPriority.Normal, CancellationToken.None, true);
    

    ODER

    SafeDispatcher.Invoke(() =>
                {
                    ProcessData();
                }, DispatcherPriority.Normal, CancellationToken.None);
    

    Notiz

    Für UI-Funktionen sollten Sie den optionalen Parameter runOnMainUiThread auf "True" festlegen. Wird dieser Wert nicht angegeben, wird der Standard "True" verwendet. Jeder oben angegebenen Methodendefinition funktioniert.

  • Eine UI-spezifische Funktion über den SafeDispatcher asynchron aufrufen Sie können die Methode BeginInvoke oder InvokeAsync verwenden.

    SafeDispatcher.BeginInvoke(new Action(() =>
                {
                   ProcessData();
                }));
    
    

    ODER

    SafeDispatcher.InvokeAsync(new Action(() =>
                {
                   ProcessData();
                }));
    
    

Anpassen der SafeDispatcher-Ausnahmehandler

Mit der Einführung von SafeDispatcher lösen alle unbehandelten Ausnahmen in Unified Service Desk das SafeDispatcherUnhandledException Event anstelle des globalen DispatcherUnhandledException Event aus. Die SafeDispatcherUnhandledExceptionHandler Methode stellt einen vordefinierten Ausnahmehandler für den SafeDispatcher zur Anzeige von Informationen für den Unified Service Desk-Benutzer mit den folgenden Informationen bereit: Quellsteuerelement, wo eine Ausnahme aufgetreten ist und ausführliche Informationen zur Ausnahme.

Sie können die Ausnahmebehandlung auch überschreiben, um SafeDispatcher andere Vorgänge wie eine Benachrichtigung des Benutzers zum Schließen eines sitzungsbasierten dynamisches gehosteten Steuerelements zu informieren.

Der folgende Beispielcode veranschaulicht, wie Sie den vordefinierten SafeDispatcher-Ausnahmehandler überschreiben, um ein Meldungsfeld anzuzeigen, um den Benutzer zum Schließen des gehosteten benutzerdefinierten Steuerelement aufzufordern.

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

Migrieren von WPF Dispatcher zu SafeDispatcher in vorhandenen benutzerdefinierten gehosteten Steuerelementen

Da WPF Dispatcher und SafeDispatcher fast identisch sind, ist Aufwand beim Migrieren minimal. Für jede Instanz des gehosteten Steuerelements, das von der DynamicsBaseHostedControl-Klasse abgeleitet wird, ersetzen Sie alle "Dispatcher" Instanzen durch "SafeDispatcher".

Stellen Sie sich beispielsweise den folgende Code vor:

Dispatcher.Invoke((System.Action)delegate()
{
    DynamicsLogger.Logger.Log("Raising SetupHotKey's", TraceEventType.Verbose);
    SetupHotkeys();
    CRMGlobalManager.AppWithFocusChanged += CRMGlobalManager_AppWithFocusChanged;
    FireEvent("DesktopReady");
    InitializeFocusSelection();
});

Ersetzen Sie Dispatcher oben im Code durch SafeDispatcher; Der Rest des Codes bleibt unverändert:

SafeDispatcher.Invoke((System.Action)delegate()
{
    DynamicsLogger.Logger.Log("Raising SetupHotKey's", TraceEventType.Verbose);
    SetupHotkeys();
    CRMGlobalManager.AppWithFocusChanged += CRMGlobalManager_AppWithFocusChanged;
    FireEvent("DesktopReady");
    InitializeFocusSelection();
});

Zu berücksichtigende Punkte beim Verwenden von SafeDispatcher

SafeDispatcher bietet ein Multithread-Modell, das Funktionen effizient synchron und asynchron auf die UI- und Nicht-UI-Threads verteilt. Vorgänge, die über Threads ausgeführt werden müssen, die über eine Fehlertoleranz verfügen, sollten über SafeDispatcher ausgeführt werden. Allerdings sollte Multithreading sehr sorgfältig implementiert werden, um Deadlocks zwischen Threads zu vermeiden. Ein Beispiel ist das synchrone Dispatchen von Nicht-UI-Threads über den Haupt-WPF-Dispatcher. Sehen Sie sich dieses Beispiel an:

Thread thread = new Thread(() =>
{
    Dispatcher.Invoke(ProcessData);
});
thread.SetApartmentState(ApartmentState.STA);
thread.Priority = ThreadPriority.Highest;
thread.IsBackground = true;
thread.Start();
thread.Join();

Die thread.Join()-Methode blockiert den Hauptthread und wartet auf die Beendigung eines STA- Threads (single-threaded apartment). Der STA-Thread wartet jedoch auf den Hauptthread, um die Ausführung von ProcessData zu beenden. Die führt zu einer Deadlocksituation.

Stellen Sie sich den folgendes Beispiel vor:

// Invoke on STA thread
SafeDispatcher.Invoke(() =>
{
    // Invoke back on main dispatcher
    SafeDispatcher.Invoke(() =>
    {
        ProcessData();
    });
}, false);

Der SafeDispatcherUnhandledExceptionHandler Method wird bei einer Ausnahme im WPF-Dispatcher oder im STA-Nicht-UI-Thread aufgerufen und wird für den entsprechenden Thread ausgelöst, für den die Ausnahme auftritt. Sie sollten darauf achten, keine der obrigen Kombination zu verwenden (Ausnahme tritt in Nicht-UI-Thread auf, wird jedoch nicht synchron zum Haupt-UI-Dispatcher verteilt).

protected override void SafeDispatcherUnhandledExceptionHandler(object sender, SafeDispatcherUnhandledExceptionEventArgs ex)
{
    Dispatcher.Invoke(LogException);            // Incorrect
    SafeDispatcher.Invoke(LogException);        // Incorrect
    SafeDispatcher.BeginInvoke(LogException);   // Correct
    SafeDispatcher.InvokeAsync(LogException);   // Correct
}

Siehe auch

Angepasstes gehostetes Steuerelement für Unified Service Desk erstellenErweiterung von Unified Service DeskKonfigurieren Sie die Diagnoseprotokollierung des Clients in Unified Service Desk