Compartilhar via


Use SafeDispatcher para controles hospedados personalizados no Unified Service Desk

 

Aplicável a: Dynamics 365 (online), Dynamics 365 (on-premises), Dynamics CRM 2013, Dynamics CRM 2015, Dynamics CRM 2016

O Unified Service Desk é um aplicativo baseado no Windows Presentation Foundation (WPF) onde todas as operações do Unified Service Desk são executadas no thread principal do Dispatcher do WPF. A classe Dispatcher do WPF fornece serviços para gerenciar a fila de itens de trabalho de um thread.

Você pode estender o Unified Service Desk criando controles personalizados e hospedando-os no Unified Service Desk. No entanto, se um controle hospedado personalizado contiver um código com defeito ou executar operações usando novos threads sem tratar exceções de maneira adequada durante a execução do código, isso poderá causar problemas de estabilidade no Unified Service Desk e até fazer com que o aplicativo cliente congele ou fique sem resposta. As exceções sem tratamento em controles personalizados de terceiros são difíceis de identificar e de resolver pela equipe do produto/suporte uma vez que eles talvez não tenham acesso às informações para saber porque um erro/exceção ocorreu no Unified Service Desk e o código exato que causou o erro.

Introduzindo o SafeDispatcher que fornece um mecanismo informativo e avançado de tratamento de exceções para controles hospedados personalizados no Unified Service Desk fornecendo log pronto para uso para exceções sem tratamento com informações detalhadas sobre a origem e a causa da exceção e permitindo que você configure ou substitua o tratamento de exceção do SafeDispatcher para realizar outras etapas. Isso também impede que o cliente do Unified Service Desk fique sem resposta devido a exceções não tratadas no código de controle hospedado personalizado.

Dica

Esse recurso foi apresentado no Unified Service Desk 2.2.1.

Neste tópico

O que é o SafeDispatcher?

Como usar o SafeDispatcher?

Migrando do Dispatcher do WPF para o SafeDispatcher em controles hospedados personalizados existentes

Coisas a considerar ao usar o SafeDispatcher

O que é o SafeDispatcher?

O SafeDispatcher foi desenvolvido nas mesmas linhas que o Dispatcher do WPF e fornece tratamento de exceção resiliente e informativo para controles hospedados personalizados no Unified Service Desk. Ele é exposto como uma propriedade protegida, SafeDispatcher, na classe DynamicsBaseHostedControl que disponibiliza o SafeDispatcher automaticamente para todos os controles hospedados personalizados do Unified Service Desk que são derivados da classe DynamicsBaseHostedControl.

Dica

Não use a classe SafeDispatcher em seu código para trabalhar com o SafeDispatcher. Em vez disso, use a propriedade SafeDispatcher em sua instância de controle hospedado personalizado derivada da classe DynamicsBaseHostedControl para usar o SafeDispatcher.

Assim como o WPF Dispatcher, o SafeDispatcher fornece métodos, como o BeginInvoke, o Invoke e o InvokeAsync para executar operações de maneira síncrona ou assíncrona no SafeDispatcher com um parâmetro booliano adicional, o runOnMainUiThread, que controla se o SafeDispatcher deve ser executado no thread de interface do usuário ou não.

O SafeDispatcher fornece os seguintes benefícios:

  • Thread do Dispatcher da interface do usuário protegido: os desenvolvedores podem executar todas as operações dependentes da interface do usuário no SafeDispatcher definindo o parâmetro runOnMainUiThread como "true" no método de invocação para executar o SafeDispatcher no thread da interface do usuário. Qualquer exceção sem tratamento gerada no dispatcher da interface do usuário será tratada com segurança no nível do controle hospedado e não se propagará para o manipulador do Evento DispatcherUnhandledException global.

  • Thread do Dispatcher que não é da interface do usuário protegido: os desenvolvedores podem executar todo código independente da interface do usuário no SafeDispatcher definindo o parâmetro runOnMainUiThread como "false" no método de invocação para executar o SafeDispatcher no thread que não é da interface do usuário. Toda exceção sem tratamento gerada no dispatcher principal que não seja da interface do usuário será tratada com segurança no nível do controle hospedado e não se propagará para o manipulador do Evento DispatcherUnhandledException global.

  • Informações detalhadas sobre a origem e a causa da exceção:: o manipulador de exceção do SafeDispatcher é acionado quando uma exceção sem tratamento é gerada no nível do DynamicsBaseHostedControl pelo thread da interface do usuário ou pelo thread que não seja da interface do usuário, o que permite que o Unified Service Desk capture informações críticas no nível do controle hospedado, como o nome do controle, o tipo do controle hospedado, o nome do método e o rastreamento completo da pilha, para identificar o local exato e a causa da exceção.

  • Configurar ou substituir o manipulador de exceção do SafeDispatcher: os desenvolvedores podem utilizar o comportamento pronto para uso do manipulador de exceção do SafeDispatcher para solicitar ao usuário informações sobre a exceção sem tratamento ou para substituir o comportamento do log de acordo com seu requisito de negócios, como configurar logs adicionais, fechar controles baseados em sessão ou sair do cliente do Unified Service Desk.

Como usar o SafeDispatcher?

A propriedade SafeDispatcher está disponível para todas as instâncias de controle hospedado personalizado do Unified Service Desk que são derivadas da classe DynamicsBaseHostedControl . Uma instância do SafeDispatcher estará disponível para executar no thread da interface do usuário quando o controle hospedado personalizado for iniciado. No entanto, uma instância do SafeDispatcher só estará disponível para executar no thread que não é da interface do usuário quando você executar o método de invocação pela primeira vez.

  • Invocar uma função específica da interface do usuário de forma síncrona usando o SafeDispatcher

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

    ou

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

    Dica

    Para uma função específica da interface do usuário, defina o parâmetro opcional runOnMainUiThread como ”true”. Se você não especificar um valor para esse parâmetro, "true" será passado como padrão. Portanto, qualquer definição do método acima funciona bem.

  • Invocar uma função específica da interface do usuário de forma assíncrona usando o SafeDispatcher. Você pode usar o método BeginInvoke ou o método InvokeAsync.

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

    ou

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

Personalizar o manipulador de exceção do SafeDispatcher

Com a introdução do SafeDispatcher, todas as exceções sem tratamento no Unified Service Desk acionarão o SafeDispatcherUnhandledException Event em vez do Evento DispatcherUnhandledException global. O SafeDispatcherUnhandledExceptionHandler Method fornece um manipulador de exceção pronto para uso para o SafeDispatcher exibir informações para o usuário do Unified Service Desk com os seguintes detalhes: controle de origem onde a exceção ocorreu e informações detalhadas sobre a exceção.

Você também pode substituir o tratamento de exceção pronto para uso para o SafeDispatcher executar outra operação, como solicitar que o usuário feche um controle hospedado não dinâmico baseado em sessão.

O código de exemplo a seguir demonstra como você pode substituir o manipulador de exceção pronto para uso do SafeDispatcher para exibir uma caixa de mensagem para solicitar ao usuário para fechar o controle hospedado personalizado quando ocorrer uma exceção:

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

Migrando do Dispatcher do WPF para o SafeDispatcher em controles hospedados personalizados existentes

Como o contrato entre o Dispatcher do WPF e o SafeDispatcher é quase idêntico, o esforço de mudar do Dispatcher do WPF para o SafeDispatcher é mínimo. Para migrar uma instância de controle hospedado derivada da classe DynamicsBaseHostedControl, substitua todas as instâncias de "Dispatcher" por "SafeDispatcher".

Por exemplo, considere o seguinte código:

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

Substitua Dispatcher no código acima por SafeDispatcher. O restante do código permanece o mesmo:

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

Coisas a considerar ao usar o SafeDispatcher

O SafeDispatcher oferece um modelo multi-threaded que é altamente benéfico em funções de expedição síncronas ou assíncronas para threads da interface do usuário ou que não são da interface do usuário. Operações que precisam ser executadas em threads disponíveis com tolerância a falhas devem ser executadas no SafeDispatcher. No entanto, multi-threading deve ser implementado muito cuidadosamente para evitar deadlock entre threads. Um exemplo é a expedição de thread que não é da interface do usuário para o Dispatcher do WPF principal de maneira síncrona. Vamos considerar este exemplo:

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

O método thread.Join() está fazendo com que o thread principal fique bloqueado para a terminação do thread de STA (Single-Threaded Apartment), mas o thread de STA está esperando que o thread principal termine a execução de ProcessData. Isso faz com que seu aplicativo fique em uma situação de deadlock.

Da mesma forma, considere o seguinte exemplo:

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

O SafeDispatcherUnhandledExceptionHandler Method será chamado se ocorrer uma exceção no Dispatcher do WPF ou no thread que não é da interface do usuário do STA e será acionado no thread respectivo no qual ocorreu a exceção. Você deve ter o cuidado de não colocar a combinação acima nesse manipulador, isto é, se a exceção ocorreu em um thread que não é da interface do usuário, não faça a expedição de maneira síncrona para o dispatcher principal da interface do usuário.

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

Confira Também

Passo a passo: criar um controle hospedado personalizado para o Unified Service Desk
Estender o Unified Service Desk
TechNet: Configurar log de diagnóstico de cliente no Unified Service Desk

Unified Service Desk 2.0

© 2017 Microsoft. Todos os direitos reservados. Direitos autorais