Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 41

Debugging Aspire Services in the IDE

Recommended resources

Olá! Na lição anterior, fizemos um tour pelo .NET Aspire Dashboard, executando uma aplicação multi-projeto e vendo como as ferramentas de observabilidade (logs, traces e métricas) nos dão uma visão de alto nível do comportamento do nosso sistema. Nós observamos a aplicação "de fora".

O objetivo desta lição é conectar essa visão macro com a depuração detalhada, linha a linha, que você já conhece. Vamos aprender a depurar um serviço individual dentro de uma aplicação multi-projeto com Aspire, diretamente do seu IDE. Enquanto o dashboard é excelente para identificar onde um problema está, o depurador do IDE é a ferramenta essencial para entender porquê ele está acontecendo no nível do código.

1. A Experiência "F5": Depuração Padrão no Aspire

A beleza do .NET Aspire é que ele se integra perfeitamente ao fluxo de trabalho de desenvolvimento .NET que você já conhece. Quando você inicia a depuração do projeto AppHost (seja pressionando F5 no Visual Studio/Rider ou usando um comando de depuração), o Aspire orquestra todos os serviços definidos e, por padrão, o depurador se anexa a todos os projetos .NET que estão sendo executados.

Isso permite uma experiência de depuração "cross-service" muito poderosa. Você pode definir um breakpoint em um serviço, acionar uma ação em outro serviço que o chama, e o fluxo de execução irá parar exatamente onde você espera.

Introducing .NET Aspire: Simplifying Cloud-Native ...

A documentação introdutória do Aspire no blog da Microsoft confirma este comportamento padrão, que é um dos pilares da experiência de desenvolvimento que o Aspire oferece.

Leia o parágrafo sob o subtítulo "Visual Studio Solution Tour" que descreve o projeto AppHost. O texto menciona explicitamente que, no Visual Studio, a depuração se anexa a todos os projetos em execução, permitindo que você passe por cada serviço em sua aplicação.

Vamos ver isso na prática com a aplicação que montamos na lição anterior.

  1. Abra a solução MyAspireApp no seu IDE.
  2. No projeto MyAspireApp.ApiService, abra o arquivo que contém o endpoint /weatherforecast (provavelmente Program.cs ou um arquivo de endpoints separado).
  3. Coloque um breakpoint na linha que gera ou retorna os dados do tempo.
  4. Certifique-se de que o projeto de inicialização (startup project) seja o MyAspireApp.AppHost.
  5. Inicie a depuração (F5). O Aspire irá compilar e iniciar os projetos ApiService e Web, e o Aspire Dashboard será aberto.
  6. No Dashboard, na linha correspondente ao webfrontend, clique no link do endpoint para abrir a aplicação web.
  7. Navegue até a página "Weather".

No momento em que o frontend tenta buscar os dados, seu IDE deve pausar a execução no breakpoint que você definiu no ApiService. Você agora pode inspecionar variáveis, percorrer o código (step through) e usar todas as ferramentas de depuração a que está acostumado, mesmo que a chamada tenha sido originada de um processo completamente diferente.

What is .NET Aspire? Why do you NEED it in every .NET app? How to get started in minutes!

Este vídeo de James Montemagno demonstra visualmente este exato fluxo de trabalho. É uma ótima maneira de ver a teoria em ação.

Assista ao trecho de 10:18 a 11:00. Observe como ele define um breakpoint no projeto de backend, atualiza o frontend no navegador e o IDE imediatamente pausa no breakpoint, provando que a depuração entre serviços está funcionando.

.NET Aspire Debug Console Output in JetBrains Rider
Esta imagem mostra um exemplo da janela de depuração no IDE JetBrains Rider. Note as abas na parte superior (`AspireSample.AppHost`, `AspireSample.Web-Aspire`, etc.). Isso ilustra como o IDE gerencia os processos de depuração para múltiplos serviços simultaneamente, permitindo que você alterne entre os logs e o status de cada um deles.

2. Combinando o Dashboard com o Depurador

O verdadeiro poder do Aspire vem da sinergia entre o dashboard e o depurador. Eles não são ferramentas excludentes, mas complementares, formando um ciclo de diagnóstico completo.

Imagine o seguinte cenário: você está testando sua aplicação e percebe uma lentidão inesperada ao carregar uma página.

  1. Observar (Dashboard): Você vai para a aba Traces no Aspire Dashboard e encontra a requisição lenta. O gráfico em cascata mostra que uma chamada específica para o apiservice está demorando 5 segundos, mas não há erros nos logs.
  2. Hipótese (Cérebro): Você suspeita que pode haver um processamento ineficiente ou uma espera desnecessária dentro do método do apiservice que foi chamado.
  3. Depurar (IDE): Você define um breakpoint no início do método suspeito no apiservice.
  4. Acionar (Aplicação): Você recarrega a página lenta para acionar o cenário novamente.
  5. Analisar (IDE): O breakpoint é atingido. Agora você pode percorrer o código linha a linha, inspecionar o valor das variáveis e usar o call stack para entender exatamente onde o tempo está sendo gasto. Talvez você encontre um Task.Delay(5000) esquecido, um loop ineficiente ou uma consulta lenta ao banco de dados.

Intro To Aspire 9.5 - Get Started Quickly with This Essential Tool

O vídeo a seguir, de Tim Corey, ilustra perfeitamente os primeiros passos deste fluxo de trabalho. Ele introduz um erro de propósito na aplicação e depois usa o dashboard para encontrá-lo.

Assista ao trecho de 26:15 a 33:15. Ele primeiro adiciona um log estruturado customizado, o que é ótimo de ver. Mais importante, ele lança uma exceção NotImplementedException de propósito na página de clima. Observe como ele usa as abas Structured Logs e Traces no dashboard para identificar o erro e sua origem. Isso demonstra os passos de "Observar" e "Hipótese". O passo seguinte, que é o foco da nossa lição, seria usar essa informação para colocar um breakpoint no local exato e depurar.

Teste seu entendimento!

Ao navegar para a página /weather no seu webfrontend, a página fica presa em "Loading..." e nunca exibe os dados. No Aspire Dashboard, você vê na aba Traces que a chamada para apiservice está marcada com um ícone de erro vermelho. Descreva os próximos passos que você tomaria, combinando o dashboard e o depurador, para encontrar a causa raiz.

Show answer
  1. Dashboard - Aprofundar: Clicaria na trace com erro no dashboard. Dentro dos detalhes da trace, eu procuraria pelo span correspondente à chamada do apiservice e o selecionaria.
  2. Dashboard - Logs Correlacionados: Com o span selecionado, eu usaria a funcionalidade "View logs" para ver os logs estruturados associados apenas àquela operação específica. Isso provavelmente me mostraria a exceção exata que foi lançada (ex: NullReferenceException, InvalidOperationException, etc.) e a stack trace no apiservice.
  3. IDE - Depurar: Com a informação da exceção e da stack trace, eu colocaria um breakpoint no método do apiservice onde o erro ocorreu.
  4. Acionar e Analisar: Reiniciaria o processo de depuração e navegaria para a página /weather novamente. Quando o breakpoint fosse atingido, eu examinaria o estado das variáveis locais para entender por que a exceção está sendo lançada (por exemplo, uma variável que deveria ter um valor está nula).

3. Foco em um Único Serviço: Depuração com Launch Profiles

Depurar todos os serviços de uma vez é ótimo, mas para aplicações grandes, pode consumir muitos recursos e tornar a inicialização mais lenta. Às vezes, você quer apenas focar em um único serviço e deixar os outros rodarem normalmente, sem o overhead do depurador.

Além disso, pode haver cenários em que você queira iniciar um serviço com uma configuração de depuração específica (por exemplo, com variáveis de ambiente diferentes). É aqui que os Launch Profiles entram em jogo.

Como você sabe, projetos .NET têm um arquivo Properties/launchSettings.json que define diferentes perfis de inicialização. O Aspire é inteligente o suficiente para usar esses perfis. Por padrão, ele tenta usar um perfil no serviço que tenha o mesmo nome do perfil usado para iniciar o AppHost.

No entanto, podemos instruir o AppHost a usar um perfil de inicialização específico para um determinado projeto.

Launch profiles | Aspire

A documentação oficial do Aspire detalha como os launch profiles funcionam e como você pode controlá-los explicitamente. Isso nos dá um controle granular sobre como cada serviço é iniciado.

Leia as seções "AppHost launch profiles and service projects" e "Control launch profile selection". Preste atenção especial na lógica de precedência e no exemplo de código que mostra como usar um argumento launchProfileName no método AddProject.

Vamos criar um perfil de depuração customizado para nosso ApiService:

  1. No projeto MyAspireApp.ApiService, abra o arquivo Properties/launchSettings.json.
  2. Dentro do objeto profiles, adicione um novo perfil chamado special-debug:
    "special-debug": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "swagger",
      "applicationUrl": "https://localhost:7101;http://localhost:5101",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "SPECIAL_DEBUG_FLAG": "ENABLED" // Nossa variável customizada
      }
    }
    
  3. Agora, no Program.cs do MyAspireApp.AppHost, modifique a linha que adiciona o ApiService para especificar este perfil:
    // Antes
    // var apiService = builder.AddProject<Projects.MyAspireApp_ApiService>("apiservice");
    
    // Depois
    var apiService = builder.AddProject<Projects.MyAspireApp_ApiService>("apiservice", launchProfileName: "special-debug");
    
  4. Coloque um breakpoint em qualquer lugar no ApiService e inicie a depuração. Quando o breakpoint for atingido, use a janela de inspeção ou o console imediato para verificar o valor de Environment.GetEnvironmentVariable("SPECIAL_DEBUG_FLAG"). O valor deve ser ENABLED, confirmando que o Aspire iniciou o serviço usando seu perfil customizado.

Essa técnica é extremamente útil para alternar entre diferentes configurações de depuração sem ter que comentar/descomentar código ou alterar as configurações do projeto.


Conclusão

Nesta lição, você aprendeu a ir além da simples observação e a mergulhar na depuração ativa de aplicações .NET Aspire.

Principais Pontos:

  • A experiência de depuração padrão ("F5") no Aspire anexa o depurador a todos os projetos .NET, permitindo a depuração transparente entre serviços.
  • O Aspire Dashboard e o depurador do IDE são ferramentas complementares: use o dashboard para identificar onde está um problema e o depurador para descobrir porquê ele ocorre.
  • Você pode usar launch profiles customizados e o método AddProject para ter um controle refinado sobre como cada serviço é iniciado durante a depuração.

Até agora, focamos em orquestrar e depurar nossos próprios projetos. Mas o poder do Aspire se estende muito além. Na próxima lição, vamos explorar os componentes e integrações do .NET Aspire, onde aprenderemos como o Aspire simplifica drasticamente a adição e configuração de dependências externas, como bancos de dados (PostgreSQL), caches (Redis) e filas de mensagens (RabbitMQ), tornando o ambiente de desenvolvimento local ainda mais robusto e próximo da produção.