Visualizadores de dados personalizados do depurador do Visual Studio (.NET)

Um visualizador é uma parte da interface do usuário do depurador do Visual Studio que exibe uma variável ou um objeto de maneira apropriada ao seu tipo de dados. Por exemplo, um visualizador do bitmap interpreta uma estrutura do bitmap e exibe o gráfico que ele representa. Alguns visualizadores permitem modificar, bem como exibir, os dados. No depurador, um visualizador é representado por um ícone de lupa VisualizerIcon. Você pode selecionar o ícone em uma DataTip, uma janela Inspeção do depurador ou uma caixa de diálogo QuickWatch e, em seguida, selecionar o visualizador adequado ao objeto correspondente.

Além dos visualizadores internos padrão, mais visualizadores podem estar disponíveis para download na Microsoft, em terceiros e na comunidade. Você também pode escrever seus visualizadores e instalá-los no depurador do Visual Studio.

Este artigo fornece uma visão geral de alto nível da criação do visualizador. Para obter instruções detalhadas, confira os seguintes artigos:

Observação

Não há suporte para visualizadores personalizados em aplicativos da Plataforma Universal do Windows (UWP) e do Windows 8.x.

Visão geral

Você pode escrever um visualizador personalizado para um objeto de qualquer classe gerenciada com exceção de Object ou Array.

A arquitetura de um visualizador de depurador tem duas partes:

  • O lado do depurador é executado no depurador do Visual Studio e cria e exibe a interface do usuário do visualizador.

    Como o Visual Studio é executado no .NET Framework Runtime, esse componente precisa ser escrito para o .NET Framework. Por esse motivo, não é possível escrevê-lo para o .NET Core.

  • O lado a ser depurado é executado dentro do processo que o Visual Studio está depurando (o lado a ser depurado). O objeto de dados a ser visualizado (por exemplo, um objeto String) existe no processo no depurador. O lado do depurado envia o objeto para o lado do depurador, que o exibe na interface do usuário que você cria.

    O runtime para o qual você compila esse componente deve corresponder àquele que o processo do depurado será executado, ou seja, .NET Framework ou .NET Core.

O lado do depurador recebe o objeto de dados de um provedor de objeto que implementa a interface IVisualizerObjectProvider. O lado do depurado envia o objeto por meio da origem do objeto, que é derivada de VisualizerObjectSource.

O provedor do objeto também pode enviar dados de volta para a origem do objeto, que permite escrever um visualizador que pode editar dados. Substitua o provedor de objetos para se comunicar com o avaliador de expressão e a origem do objeto.

O lado do depurado e o lado do depurador se comunicam entre si por meio de métodos Stream que serializam um objeto de dados em um Stream e desserializam o Stream de volta em um objeto de dados.

Você poderá escrever um visualizador para um tipo genérico somente se o tipo for um tipo aberto. Essa restrição é a mesma que a restrição ao usar o atributo DebuggerTypeProxy. Para obter detalhes, consulte Usar o atributo DebuggerTypeProxy.

Os visualizadores personalizados podem ter considerações de segurança. Confira Considerações de segurança do visualizador.

Criar a interface do usuário do lado do depurador

Para criar a interface do usuário do visualizador no lado do depurador, você cria uma classe que herda de DialogDebuggerVisualizer e substitui o método Microsoft.VisualStudio.DebuggerVisualizers.DialogDebuggerVisualizer.Show para exibir a interface. Você pode usar IDialogVisualizerService para exibir formulários, caixas de diálogo e controles do Windows no visualizador.

  1. Use os métodos IVisualizerObjectProvider para obter o objeto visualizado no lado do depurador.

  2. Crie uma classe que herda de DialogDebuggerVisualizer.

  3. Substitua o método Microsoft.VisualStudio.DebuggerVisualizers.DialogDebuggerVisualizer.Show para exibir sua interface. Use os métodos IDialogVisualizerService para exibir os formulários, as caixas de diálogo e os controles do Windows na interface.

  4. Aplique DebuggerVisualizerAttribute, dando a ele o visualizador para exibir (DialogDebuggerVisualizer).

Considerações especiais do lado do depurador para .NET 5.0+

Visualizadores personalizados transferem dados entre os lados do depurado e do depurador por meio da serialização binária usando a classe BinaryFormatter por padrão. No entanto, esse tipo de serialização está sendo reduzido no .NET 5 e superior devido a preocupações de segurança em relação às vulnerabilidades não corrigíveis. Além disso, ele foi marcado como completamente obsoleto no ASP.NET Core 5 e seu uso será gerado conforme descrito na Documentação do ASP.NET Core. Esta seção descreve as etapas que você deve seguir para garantir que o visualizador ainda tenha suporte nesse cenário.

  • Por motivos de compatibilidade, o método Show que foi substituído na seção anterior ainda usa um IVisualizerObjectProvider. No entanto, começando no Visual Studio 2019 versão 16.10, ele é, na verdade, do tipo IVisualizerObjectProvider2. Por esse motivo, converta o objeto objectProvider na interface atualizada.

  • Ao enviar objetos, como comandos ou dados, para o lado do depurado, use o método IVisualizerObjectProvider2.Serialize para passá-lo para um fluxo; ele determinará o melhor formato de serialização a ser usado com base no runtime do processo do depurado. Em seguida, passe o fluxo para o método IVisualizerObjectProvider2.TransferData.

  • Se o componente do visualizador do lado do depurado precisar retornar algo para o lado do depurador, isso estará localizado no objeto Stream retornado pelo método TransferData. Use o método IVisualizerObjectProvider2.GetDeserializableObjectFrom para obter uma instância de IDeserializableObject dele e processá-la conforme necessário.

Consulte a seção Considerações especiais do lado do depurado do .NET 5.0+ para saber quais outras alterações são necessárias no lado do depurado quando o uso da Serialização Binária não tem suporte.

Observação

Se quiser obter mais informações sobre o problema, consulte o Guia de segurança do BinaryFormatter.

Para criar a origem do objeto do visualizador do lado do depurador

No código do lado do depurado, edite o DebuggerVisualizerAttribute, dando a ele o tipo a ser visualizado (a origem do objeto do lado do depurado) (VisualizerObjectSource). A propriedade Target define a origem do objeto. Se você omitir a origem do objeto, o visualizador usará uma fonte de objeto padrão.

O código do lado do depurado contém a origem do objeto que é visualizado. O objeto de dados pode substituir métodos de VisualizerObjectSource. Uma DLL do lado do depurado será necessária se você quiser criar um visualizador autônomo.

No código do lado do depurado:

  • Para permitir que o visualizador edite objetos de dados, a origem do objeto precisa herdar de VisualizerObjectSource e substituir os métodos TransferData ou CreateReplacementObject.

  • Se você precisar dar suporte a vários destinos no visualizador, poderá usar os seguintes TFMs (Monikers da Estrutura de Destino) no arquivo de projeto do lado do depurado.

    <TargetFrameworks>net20;netstandard2.0;netcoreapp2.0</TargetFrameworks>
    

    Esses são os únicos TFMs com suporte.

Considerações especiais do lado do depurado para .NET 5.0+

Importante

Etapas adicionais podem ser necessárias para que um visualizador funcione a partir do .NET 5.0 devido a preocupações de segurança em relação ao método de serialização binária subjacente usado por padrão. Leia esta seção antes de continuar.

  • Se o visualizador implementar o método TransferData, use o método GetDeserializableObject recém-adicionado, que está disponível na versão mais recente do VisualizerObjectSource. O IDeserializableObject que ele retorna ajuda a determinar o formato de serialização do objeto (binário ou JSON) e a desserializar o objeto subjacente para que ele possa ser usado.

  • Se o lado do depurado retornar dados para o lado do depurador como parte da chamada TransferData, serialize a resposta para o fluxo do lado do depurador por meio do método Serialize.