.NET -  Iniciando com o .NET Aspire - II


  Neste artigo vamos por a mão na massa e usar alguns dos recursos do  .NET Aspire.

Continuando o artigo anterior vamos agora aplicar alguns recursos do .NET Aspire na prática.

Criando seu primeiro projeto .NET Aspire Starter

O principal objetivo do template .NET Aspire Starter App é agilizar o desenvolvimento de aplicações distribuídas ao fornecer uma base pronta e configurada. Ao utilizar esse template, você ganha tempo e evita a necessidade de configurar manualmente diversos aspectos da sua aplicação, como a configuração inicial do .NET Aspire, a criação de projetos básicos e a configuração de serviços comuns.

Podemos também configurar os serviços em cada projeto, sobrescrevendo as configurações padrão se necessário, e, após registrar os serviços no projeto .AppHost para que eles sejam gerenciados pelo sistema, podemos definir os endpoints HTTP que serão expostos por cada serviço e implementar a lógica de negócio de cada serviço.

Abra o Visual Studio 2022 e localize o template .NET Aspire Starter App :

Informe o nome da solução - AspireDemo -  e escolha o local onde vai salvar o projeto:

A seguir selecione o target framework , .NET 8.0 ,  e clique em Create.

Com isso teremos na janela Solution Explorer uma solução contendo 4 projetos:

Compreendendo a estrutura da Solution:

Projeto AppHost: Atua como orquestrador central, o AppHost coordena a execução de todos os projetos dentro do aplicativo .NET Aspire. Ele gerencia dependências, define definições de configuração e garante integração perfeita entre diferentes componentes, como ApiService e Web. A seguir temos o código do arquivo .csproj:

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
   <OutputType>Exe</OutputType>
   <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <IsAspireHost>true</IsAspireHost>
    <UserSecretsId>84ad0f0b-11c7-44b7-9da0-a49ef7d3f35e</UserSecretsId>
</PropertyGroup>

<ItemGroup>
    <PackageReference Include="Aspire.Hosting.AppHost" Version="8.2.1" />
</ItemGroup>

<ItemGroup>
   <ProjectReference Include="..\AspireApp.API\AspireApp.API.csproj" />
   <ProjectReference Include="..\AspireApp.BlazorTarefas\AspireApp.BlazorTarefas.csproj" />
</ItemGroup>

</Project>

A linha IsAspireHost Indica que este projeto é o hospedeiro principal da aplicação Aspire.

Este código faz o seguinte:

Define o projeto principal: O projeto AppHost é o ponto de partida da aplicação.
Configura o ambiente:
Define as configurações básicas do projeto, como o framework alvo e os recursos a serem utilizados.
Inclui dependências:
Adiciona as referências necessárias para o funcionamento da aplicação, incluindo o framework Aspire e os outros projetos da solução.
Especifica o tipo de saída:
Define que o resultado da compilação será um executável.

Resumindo, este código configura um projeto .NET Aspire para hospedar uma aplicação que consiste em uma API  e uma interface do usuário baseada em Blazor. O projeto AppHost serve como o ponto central, orquestrando a execução da aplicação e gerenciando as dependências entre os diferentes projetos.

Projeto ServiceDefaults: Este componente é crucial para gerenciar e configurar dependências no aplicativo. Ele fornece uma abordagem padronizada para configurar serviços, permitindo escalabilidade e manutenção mais fáceis do aplicativo.

Neste projeto você pode encontrar a configuração para a propriedade IsAspireSharedProject (no PropertyGroup), bem como os pacotes de referência que serão usados ​​pelo seu aplicativo:

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
   <TargetFramework>net8.0</TargetFramework>
   <ImplicitUsings>enable</ImplicitUsings>
   <Nullable>enable</Nullable>
   <IsAspireSharedProject>true</IsAspireSharedProject>
</PropertyGroup>

<ItemGroup>
  <FrameworkReference Include="Microsoft.AspNetCore.App" />

  <PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.9.1" />  
  <PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="8.2.1" />
  <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
  <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
  <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
  <PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0" />
  <PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.9.0" />
</ItemGroup>

</Project>

No arquivo Extensions.cs temos algums métodos de extensão :

AddServiceDefaults:  Este método adiciona os padrões para OpenTelemetry, health checks e configurações de clientes HTTP com resiliência e descoberta de serviços. Ou seja, ao incluir este método no AppHost, ele garante que esses padrões estejam habilitados em todos os serviços da aplicação.

ConfigureOpenTelemetry: Configura a telemetria da aplicação usando o OpenTelemetry, incluindo métricas e tracing para a instrumentação de requisições HTTP, tempo de execução e eventos do ASP.NET Core. Além disso, há a possibilidade de usar exportadores para enviar dados de telemetria para outros serviços, como o OTLP (OpenTelemetry Protocol) ou Azure Monitor, conforme configurado.

AddDefaultHealthChecks: Adiciona endpoints de verificações de integridade padrão e adiciona verificações de saúde (health checks) que monitoram se a aplicação está responsiva e pronta para receber tráfego. Ele também define uma verificação de "liveness" (/
alive) para garantir que a aplicação esteja rodando.

MapDefaultEndpoints: Mapeia os endpoints de health checks na aplicação, permitindo que ela exponha informações sobre sua saúde em ambientes de desenvolvimento.

Observação: A declaração da Microsoft para o projeto ServiceDefaults é que este projeto foi projetado especificamente para compartilhar o arquivo Extensions.cs e sua funcionalidade, e se você quiser ter alguma funcionalidade ou modelos compartilhados, é recomendado usar um projeto de biblioteca de classes compartilhada convencional para isso.

Os projetos ApiService e Web são projetos comuns de Web API e Blazor. Observe que em ambos os projetos há uma chamada para o método AddServiceDefaults no arquivo Program.cs.

Projeto Web: O componente Web serve como interface front-end, utilizando Blazor para interagir com o ApiService. Ele manipula interações do usuário, exibe dados buscados do backend e fornece uma interface de usuário responsiva para uma experiência de usuário perfeita.

Projeto ApiService: Este componente serve como provedor da API do backend, manipulando solicitações e respostas entre o aplicativo Web front-end e o banco de dados ou outros serviços. Ele gerencia o acesso a dados e a lógica de negócios, garantindo comunicação e processamento eficientes.

Vamos executar o projeto localmente definindo o projeto AppHost como projeto de inicialização, caso isso já não estiver definido. Este projeto irá orquestrar os demais projetos.

Verifique se o código do arquivo Program.cs esta conforme abaixo:

var builder = DistributedApplication.CreateBuilder(args);

var apiService = builder.AddProject<Projects.AspireDemo_ApiService>("apiservice");

builder.AddProject<Projects.AspireDemo_Web>("webfrontend")
           .WithExternalHttpEndpoints()
           .WithReference(apiService);

builder.Build().Run();

A primeira linha inicia a construção de um aplicativo distribuído utilizando o .NET Aspire. O método CreateBuilder recebe os argumentos da linha de comando como parâmetro, permitindo que você configure o aplicativo de acordo com as suas necessidades.

A seguir estamos adicionando um projeto chamado AspireDemo_ApiService ao seu aplicativo. O método AddProject recebe o tipo do projeto e um nome para identificar esse projeto dentro do aplicativo. Esse projeto contém as APIs que serão consumidas pela sua aplicação.

Na sequência temos :

Adição de outro projeto: Neste ponto, adicionamos outro projeto chamado AspireDemo_Web, que provavelmente é a sua interface web.

Exposição de endpoints HTTP: O método WithExternalHttpEndpoints() indica que este projeto expõe endpoints HTTP que podem ser acessados externamente

Referência ao projeto de API: O método WithReference(apiService) cria uma referência entre o projeto web e o projeto de API. Isso significa que o projeto web pode chamar as APIs do outro projeto.

Concluindo o método Build() constrói o aplicativo com base nas configurações e projetos adicionados. Em seguida, o método Run() inicia a execução do aplicativo, tornando-o disponível para receber requisições.

O que significa a execução deste código na prática ?

Imagine que você está construindo um aplicativo web que precisa de uma API para realizar algumas tarefas. Com o .NET Aspire, você pode separar a sua aplicação em dois projetos distintos: Um para a interface web e outro para as APIs. O código acima configura a relação entre esses dois projetos, permitindo que a sua aplicação web utilize as funcionalidades da API.

Quando a aplicação iniciar você verá inicialmente a janela que exibe logs sobre a inicialização do aplicativo distribuído. Esses logs mostram a versão do .NET Aspire, o diretório do projeto, a porta de escuta e o link para o dashboard.

A seguir é apresentando o dashboard:

O dashboard do .NET Aspire oferece uma interface visual para monitorar e gerenciar seus aplicativos distribuídos. As opções - Recursos, Console, Estruturado, Rastreamento e Métricas - fornecem insights valiosos sobre o estado e o desempenho do seu sistema

Recursos: Esta seção fornece informações essenciais sobre cada projeto .NET na sua configuração do .NET Aspire, incluindo status do aplicativo, endereços de endpoint e variáveis ​​de ambiente carregadas. Permite iniciar ou parar um projeto individualmente e o clicar em um projeto, você pode ver informações mais detalhadas sobre ele, como logs e métricas.

Para o nosso caso, o dashboard mostra os projetos apiservice e webfrontend, indicando que seu aplicativo é composto por uma API e uma interface web.

Na opção - Pontos de extremidade -  para o projeto apiservice , ao clicar no link iremos exibir o response do respectivo request para a API :

Para o projeto - webfrontend - clicando no link teremos a execução do projeto Blazor:

Console: Uma interface semelhante a um terminal, onde você pode executar comandos para interagir com o seu aplicativo.

Temos aqui as seguintes funcionalidades:

Executar comandos: Permite executar comandos como se estivesse em um terminal, como por exemplo, visualizar logs, executar consultas, ou até mesmo fazer depuração.

Ver logs: Exibe os logs de seus projetos em tempo real.

Executar scripts: Permite executar scripts personalizados para automatizar tarefas.

Estruturado: Apresenta uma visão estruturada do seu aplicativo, mostrando a relação entre os diferentes projetos e serviços.

Apresenta um grafo de dependências permitiindo visualizar a relação de dependência entre os projetos e mostra detalhes sobre os serviços registrados em cada projeto.

Rastreamentos: Permite rastrear as requisições HTTP que passam pelo seu aplicativo.

Permite visualizar os traces mostrando o caminho percorrido por uma requisição, desde a entrada até a saída e permite identificar gargalos e problemas de desempenho.

Métricas: Exibe métricas sobre o desempenho do seu aplicativo, como:

Aqui podemos visualizar as métricas em gráficos e dashboards personalizados. Podemos também configurar alertas para serem notificados quando as métricas atingirem determinados valores.

Desta forma, o dashboard do .NET Aspire oferece uma visão completa do seu aplicativo distribuído. Com ele, você pode

- Monitorar: Verificar o estado e o desempenho de seus projetos em tempo real.
- Gerenciar: Iniciar, parar e configurar seus projetos.
- Depurar: Identificar e resolver problemas.
- Otimizar: Melhorar o desempenho do seu aplicativo.

Lembrando que a aparência e as funcionalidades do dashboard podem variar dependendo da versão do .NET Aspire e das configurações do seu projeto.

O .NET Aspire pode ser integrado com outras ferramentas de monitoramento e observabilidade, como o Prometheus e o Grafana.

Autenticação e Autorização

Além disso, os mecanismos centralizados de autenticação e autorização fazem parte da infraestrutura do AppHost e da arquitetura Aspire em geral. Estes mecanismos são responsáveis por garantir que todos os serviços da solução Aspire sigam um padrão consistente de segurança. Eles podem atuar das seguintes maneiras:

Autenticação Compartilhada :  Em uma solução Aspire, a autenticação é gerenciada de maneira centralizada pelo AppHost ou por um serviço específico dedicado à autenticação. Todos os serviços que participam da solução utilizam este mecanismo compartilhado para validar os usuários.

Geralmente, são usados protocolos como OAuth 2.0, OpenID Connect (OIDC), ou JWT (JSON Web Tokens), com o AppHost configurando as políticas de autenticação e distribuindo tokens que podem ser consumidos por todos os outros serviços.

Autorização Centralizada: Da mesma forma, a autorização também é configurada de forma centralizada. Políticas e regras de autorização são definidas no AppHost, e todos os serviços utilizam essas políticas para restringir o acesso a determinados recursos com base nos papéis e permissões dos usuários autenticados.

Isso garante que as permissões e acessos sejam geridos de forma uniforme em toda a solução Aspire.

Esses mecanismos podem ainda não estar visíveis porque o template Aspire Empty App é um ponto de partida básico, e a configuração explícita de autenticação/autorização pode precisar ser adicionada conforme a necessidade do projeto. Em muitos casos, você vai configurar a autenticação no AppHost usando serviços como IdentityServer ou Azure AD, ou até mesmo autenticação por JWT.

Na proxima parte do artigo vamos criar um projeto usando o template .NET Aspire Empty App.

E estamos conversados...

"Tendo sido, pois, justificados pela fé, temos paz com Deus, por nosso Senhor Jesus Cristo;"
Romanos 5:1

Referências:


José Carlos Macoratti