Compartilhar via


Novidades no .NET.NET Aspire 9.0

📢 .NET Aspire 9.0 é a próxima versão de GA (disponibilidade geral) principal do .NET Aspire; ele dá suporte a :

  • .NET LTS (suporte de longo prazo) 8.0 ou
  • .NET 9.0 Suporte a Termos Padrão (STS).

Nota

Você pode usar .NET Aspire 9.0 com .NET 8 ou .NET 9!

Esta versão aborda alguns dos recursos mais solicitados e pontos de dor da comunidade. Os melhores recursos são orientados pela comunidade! Para participar da comunidade, visite-nos no o Discord para conversar com os membros da equipe e colaborar conosco em GitHub.

Para obter mais informações sobre a versão oficial do .NET e o suporte à versão .NET Aspire, consulte:

Atualizar para .NET.NET Aspire 9

Para atualizar de versões anteriores do .NET Aspire para o .NET Aspire 9, siga as instruções no guia oficial de atualização do para .NET.NET Aspire 9. O guia fornece instruções detalhadas sobre como atualizar suas soluções de .NET Aspire existentes para .NET Aspire 9. Independentemente de você estar fazendo isso manualmente ou usando o Assistente de Atualização, o guia facilita o processo.

Aprimoramentos de ferramentas

.NET Aspire 9 torna mais simples configurar seu ambiente para desenvolver aplicativos .NET Aspire. Você não precisa mais de uma carga de trabalho .NET. Em vez disso, você instala o novo SDK .NET.NET Aspire no projeto host do aplicativo nas suas soluções .NET.NET Aspire. Para obter mais informações, consulte .NET.NET Aspire configuração e ferramentas.

Os modelos foram movidos

.NET .NET Aspire 9 está movendo o conteúdo que costumava ser instalado por meio da carga de trabalho em pacotes NuGet separados. Isso inclui os modelos para criar novos projetos e soluções .NET.NET Aspire. Esses modelos são instalados usando o comando dotnet new install. Eles podem ser instalados executando o seguinte comando:

dotnet new install Aspire.ProjectTemplates::9.0.0

Dica

Se você já tiver o pacote de trabalho .NET.NET Aspire instalado, precisará passar a flag --force para substituir os modelos existentes. Fique à vontade para desinstalar o workload .NET.NET Aspire.

Para obter mais informações, consulte .NET.NET Aspire modelos.

Aprimoramentos de UX do painel e novos recursos de interatividade

O painel .NET.NET Aspire continua a melhorar a cada versão.

Gerenciar o ciclo de vida do recurso

O recurso mais solicitado para o painel é gerenciar os ciclos de vida dos recursos nomeados orquestrados. Especificamente, a capacidade de parar, iniciar e reiniciar recursos. Esse recurso funciona para projetos, contêineres e executáveis. Ele permite reiniciar recursos individuais sem precisar reiniciar todo o host do aplicativo. Para recursos de projeto, quando o depurador é anexado, ele é anexado novamente ao reiniciar. Para obter mais informações, consulte o painel .NET.NET Aspire: Parar ou iniciar um recurso.

Suporte móvel e responsivo

O painel de .NET Aspire agora é amigável para dispositivos móveis, adaptando-se responsivamente a uma ampla gama de tamanhos de tela e habilitando o gerenciamento local de aplicativos .NET Aspire implantados. Outras melhorias de acessibilidade foram feitas, incluindo a exibição de configurações e transbordamento de conteúdo em dispositivos móveis.

Propriedades confidenciais, volumes e verificações de integridade nos detalhes do recurso

A exibição de detalhes do recurso contém várias melhorias:

  • As propriedades podem ser marcadas como confidenciais, mascarando-as automaticamente na interface do usuário do painel. Esse recurso de segurança ajuda a evitar a divulgação acidental de chaves ou senhas ao compartilhar o painel com outras pessoas. Por exemplo, argumentos de contêiner podem passar informações confidenciais e, portanto, são mascarados por padrão.

  • Os volumes de contêiner configurados são listados nos detalhes do recurso.

  • .NET .NET Aspire 9 adiciona suporte para verificações de integridade. Informações detalhadas sobre essas verificações agora podem ser exibidas no painel de detalhes do recurso, mostrando por que um recurso pode ser marcado como não íntegro ou degradado. Saiba mais sobre verificações de integridade aqui.

Log de console colorido

códigos de escape ANSI formatar texto em terminais controlando cores (primeiro plano e plano de fundo) e estilos como negrito, sublinhado e itálico. Anteriormente, a página de registros do console do painel de controle só podia renderizar um código de escape ANSI por vez, falhando ao combinar vários códigos. Por exemplo, ele poderia exibir texto vermelho, mas não texto que fosse vermelho e negrito.

Uma contribuição da comunidade de @mangeg melhorou o suporte para códigos de escape ANSI e removeu essa limitação.

logs de console coloridos

Uma outra melhoria nos logs de console é ocultar códigos de escape sem suporte. Códigos que não estão relacionados à exibição de texto, como posicionar o cursor ou se comunicar com o sistema operacional, não fazem sentido nessa interface do usuário e ficam ocultos.

Telemetria com adições centradas no usuário

telemetria continua sendo um aspecto vital do .NET.NET Aspire. No .NET.NET Aspire 9, muitos novos recursos foram introduzidos no serviço de Telemetria.

Filtragem de telemetria aprimorada

Os traços podem ser filtrados com valores de atributo. Por exemplo, se você quiser exibir apenas rastreamentos para um ponto de extremidade em seu aplicativo, o atributo http.route em solicitações HTTP poderá ser filtrado para um valor especificado.

A filtragem de telemetria também dá suporte ao preenchimento automático de valores existentes. A caixa de diálogo Adicionar filtro fornece uma caixa de combinação para selecionar entre os valores disponíveis no painel. Esse recurso facilita muito a filtragem para dados reais e ajuda a evitar erros de digitação inserindo um valor por conta própria.

Para obter mais informações, consulte o painel .NET.NET Aspire: Filtrar rastreamentos.

Combinar telemetria de vários recursos

Quando um recurso tem várias réplicas, agora você pode filtrar a telemetria para exibir dados de todas as instâncias ao mesmo tempo. Selecione o recurso pai, rotulado como (application). Para obter mais informações, consulte .NET.NET Aspire painel: Combine telemetria de vários recursos.

Suporte à telemetria do navegador

O painel dá suporte ao Protocolo OpenTelemetry (OTLP) por HTTP e CORS (compartilhamento de recursos entre origens). Esses recursos permitem enviar OpenTelemetry de aplicativos de navegador para o painel .NET Aspire.

Por exemplo, um SPA (aplicativo de página única) baseado em navegador pode configurar o do SDK OpenTelemetry JavaScript para enviar logs estruturados, rastreamentos e métricas criados no navegador para o painel. A telemetria do navegador é exibida juntamente com a telemetria server.

página de detalhes do rastreamento com telemetria de dados do navegador

Para obter mais informações sobre como configurar a telemetria do navegador, consulte Habilitar a telemetria do navegador documentação.

Host do Aplicativo (Orquestração)

O host do aplicativo .NET.NET Aspire é um dos recursos mais importantes de do .NET.NET Aspire. No .NET.NET Aspire 9, vários novos recursos foram adicionados específicos ao host do aplicativo.

Aguardando dependências

Se você estiver acompanhando .NET.NET Aspire, já sabe que o projeto de hospedagem do seu aplicativo é onde você define o modelo do aplicativo. Você cria um construtor de aplicativos distribuído, adiciona e configura recursos e expressa suas dependências. Agora, você pode especificar que um recurso deve aguardar por outro recurso antes de começar. Isso pode ajudar a evitar erros de conexão durante a inicialização iniciando apenas os recursos quando suas dependências estiverem "prontas".

var builder = DistributedApplication.CreateBuilder(args);

var rabbit = builder.AddRabbitMQ("rabbit");

builder.AddProject<Projects.WebApplication1>("api")
       .WithReference(rabbit)
       .WaitFor(rabbit); // Don't start "api" until "rabbit" is ready...

builder.Build().Run();

Quando o host do aplicativo é iniciado, ele espera que o recurso rabbit esteja pronto antes de iniciar o recurso api.

Há dois métodos disponíveis para aguardar um recurso:

  • WaitFor: aguarde até que um recurso esteja pronto antes de iniciar outro recurso.
  • WaitForCompletion: aguarde a conclusão de um recurso antes de iniciar outro recurso.

Para obter mais informações, consulte .NET.NET Aspire host do aplicativo: Aguardando recursos.

Verificação de integridade de recursos

A API WaitFor usa verificações de integridade .NET padrão para determinar se um recurso está pronto. Mas o que significa "um recurso pronto"? A melhor parte é que isso é configurável pelo consumidor além de seus valores padrão.

Quando um recurso não expõe nenhuma verificação de integridade (nenhuma verificação de integridade registrada no aplicativo), o host do aplicativo aguarda que o recurso esteja no estado Running antes de iniciar o recurso dependente.

Para recursos que expõem pontos de extremidade HTTP, você pode adicionar facilmente uma verificação de integridade que sonda um caminho específico para uma resposta HTTP 200.

var builder = DistributedApplication.CreateBuilder(args);

var catalogApi = builder.AddContainer("catalog-api", "catalog-api")
                        .WithHttpEndpoint(targetPort: 8080)
                        .WithHttpHealthCheck("/health");

builder.AddProject<Projects.WebApplication1>("store")
       .WithReference(catalogApi.GetEndpoint("http"))
       .WaitFor(catalogApi);

builder.Build().Run();

O exemplo anterior adiciona uma verificação de integridade ao recurso catalog-api. O host do aplicativo aguarda que a verificação de integridade retorne um estado saudável antes de iniciar o recurso store. Determina-se que o recurso está pronto quando o endpoint /health retorna um código de status HTTP 200.

Enquanto store aguarda catalog-api ficar saudável, os recursos no painel aparecem como:

Aguardando um recurso problemático antes de iniciar

O mecanismo de verificação de saúde do host do aplicativo é construído com base na implementação do IHealthChecksBuilder no namespace Microsoft.Extensions.Diagnostics.HealthChecks.

O relatório de dados das verificações de saúde é exibido no painel de controle.

Detalhes de verificação de integridade nos detalhes do recurso no painel de controle

Criar um check-up de saúde personalizado é simples. Comece definindo a verificação de integridade e, em seguida, associe o nome dela a quaisquer recursos aos quais se aplique.

var builder = DistributedApplication.CreateBuilder(args);

var healthyAfter = DateTime.Now.AddSeconds(20);

builder.Services.AddHealthChecks().AddCheck(
    "delay20secs",
    () => DateTime.Now > healthyAfter 
        ? HealthCheckResult.Healthy() 
        : HealthCheckResult.Unhealthy()
    );

var cache = builder.AddRedis("cache")
                   .WithHealthCheck("delay20secs");

builder.AddProject<Projects.MyApp>("myapp")
       .WithReference(cache)
       .WaitFor(cache);

O exemplo anterior adiciona uma verificação de integridade ao recurso cache, que o relata como não íntegro nos primeiros 20 segundos após o início do host do aplicativo. Portanto, o recurso myapp aguarda 20 segundos antes de começar, garantindo que o recurso cache esteja íntegro.

Os métodos AddCheck e WithHealthCheck fornecem um mecanismo simples para criar verificações de integridade e associá-las a recursos específicos.

Contêineres persistentes

O host do aplicativo agora dá suporte a contêineres persistentes de. Contêineres persistentes se desviam do ciclo de vida típico do contêiner de .NET.NET Aspire aplicativos orquestrados. Embora sejam criados e iniciados (quando ainda não estão disponíveis) pelo orquestrador .NET Aspire, eles não são destruídos por .NET Aspire.

Isso é útil quando você deseja manter o contêiner em execução mesmo depois que o host do aplicativo for interrompido.

Importante

Para excluir esses contêineres, você deve pará-los manualmente usando o runtime do contêiner.

Para definir um IResourceBuilder<ContainerResource> com um tempo de vida persistente, chame o método WithLifetime e passe ContainerLifetime.Persistent:

var builder = DistributedApplication.CreateBuilder(args);

var queue = builder.AddRabbitMQ("rabbit")
                   .WithLifetime(ContainerLifetime.Persistent);

builder.AddProject<Projects.WebApplication1>("api")
       .WithReference(queue)
       .WaitFor(queue);

builder.Build().Run();

O painel mostra contêineres persistentes com um ícone de alfinete.

contêineres persistentes

Depois que o host do aplicativo for interrompido, o contêiner continuará a ser executado:

Docker área de trabalho mostrando RabbitMQ.

O mecanismo de persistência de contêiner tenta identificar quando você pode querer recriar o contêiner. Por exemplo, se o ambiente do contêiner for alterado, o contêiner será reiniciado para que você não precise interromper manualmente o contêiner se a configuração de entrada do recurso tiver sido alterada.

Comandos de recursos

O host do aplicativo dá suporte à adição de comandos personalizados aos recursos. Isso é útil quando você deseja adicionar funcionalidades personalizadas que não têm suporte nativo pelo host do aplicativo. Provavelmente, há muitas oportunidades em que expor métodos de extensão personalizados em recursos será útil. O .NET.NET Aspire Community Toolkit pode ser um bom lugar para compartilhar essas extensões.

Quando você define um comando personalizado, ele está disponível no painel como um recurso de experiência do usuário.

Importante

Esses comandos de painel .NET.NET Aspire só estão disponíveis ao executar o painel localmente. Eles não estão disponíveis ao executar o painel no Azure Container Apps.

Para obter mais informações sobre como criar comandos de recursos personalizados, consulte Instruções: Criar comandos de recursos personalizados no .NET.NET Aspire.

Rede de contêiner

O host do aplicativo agora adiciona todos os contêineres a uma rede comum chamada default-aspire-network. Isso é útil quando você deseja se comunicar entre contêineres sem passar pela rede de host. Isso também facilita a migração de docker Compose para o host do app, pois os contêineres podem se comunicar entre si usando o nome do contêiner.

Modelo de evento

O modelo de evento permite que os desenvolvedores conectem-se ao ciclo de vida do aplicativo e dos recursos. Isso é útil para executar código personalizado em pontos específicos no ciclo de vida do aplicativo. Há várias maneiras de assinar eventos, incluindo eventos globais e eventos por recurso.

Eventos globais:

  • BeforeStartEvent: um evento que é disparado antes do início do aplicativo. Esse é o último lugar em que as alterações no modelo de aplicativo são observadas. Isso funciona nos modos "Executar" e "Publicar". Esse é um evento de bloqueio, o que significa que o aplicativo não é iniciado até que todos os manipuladores tenham sido concluídos.
  • AfterResourcesCreatedEvent: um evento que é disparado após a criação dos recursos. Isso funciona somente no modo executar.
  • AfterEndpointsAllocatedEvent: um evento que é disparado depois que os endpoints são alocados para todos os recursos. Isso é executado somente no modo de execução.

Os eventos globais são análogos aos eventos do ciclo de vida do host do aplicativo. Para obter mais informações, consulte Ciclos de vida do aplicativo host.

eventos por recurso:

  • BeforeResourceStartedEvent: Um evento que é acionado antes do início de um recurso único. Isso é executado somente no Modo de Execução. Esse é um evento de bloqueio, o que significa que o recurso não é iniciado até que todos os manipuladores sejam concluídos.
  • ConnectionStringAvailableEvent: um evento que é disparado quando uma cadeia de conexão está disponível para um recurso. Isso é executado somente no Modo de Execução.
  • ResourceReadyEvent: um evento que é disparado quando um recurso está pronto para ser usado. Isso funciona apenas no modo de execução.

Para obter mais informações, consulte a seção de Eventos em .NET.NET Aspire.

Integrações

.NET .NET Aspire continua a adicionar integrações que facilitam a introdução aos seus serviços e ferramentas favoritos. Para obter mais informações, consulte .NET.NET Aspire visão geral de integrações.

Insight de Redis

O suporte para Redis Insights está disponível em um recurso de Redis:

var builder = DistributedApplication.CreateBuilder(args);

builder.AddRedis("redis")
       .WithRedisInsight(); // Starts a Redis Insight container image
                            // that is pre-configured to work with the
                            // Redis instance.

O método de extensão WithRedisInsight pode ser aplicado a vários recursos de Redis e cada um deles ficará visível no painel do Redis Insight.

Painel de Redis Insight mostrando várias instâncias de Redis

Para obter mais informações, consulte Adicionar Redis recurso com Redis Insights.

OpenAI (versão prévia)

A partir de .NET Aspire 9, está disponível uma integração adicional OpenAI que permite o uso direto da biblioteca oficial mais recente OpenAI dotnet. A integração client registra o OpenAIClient como um serviço singleton na coleção de serviços. O client pode ser usado para interagir com a API OpenAIREST.

Além disso, a integração .NET AspireAzureOpenAI já disponível no foi aprimorada para oferecer uma maneira flexível de configurar um OpenAIClient, seja para um serviço de Azure AI OpenAI ou uma API dedicada de OpenAIREST, com o novo método de construção AddOpenAIClientFromConfiguration(IHostApplicationBuilder, String). O exemplo a seguir detecta se a cadeia de conexão é para um serviço AzureAzure AI OpenAI e registra automaticamente a instância de OpenAIClient mais apropriada.

builder.AddOpenAIClientFromConfiguration("openai");

Por exemplo, se a conexão openai se parecesse com Endpoint=https://{account}.azure.com;Key={key}; ele poderia supor que poderia registrar um Azure AI OpenAIclient por causa do nome de domínio. Caso contrário, um OpenAIClient comum seria usado.

Leia Azurede resolução independente de client para obter mais detalhes.

MongoDB

Adicionado suporte para especificar o nome de usuário e a senha MongoDB ao usar o método de extensão AddMongoDB(IDistributedApplicationBuilder, String, Nullable<Int32>, IResourceBuilder<ParameterResource>, IResourceBuilder<ParameterResource>). Se não for especificado, um nome de usuário aleatório e uma senha serão gerados, mas poderão ser especificados manualmente usando recursos de parâmetro.

var builder = DistributedApplication.CreateBuilder(args);

var username = builder.AddParameter("mongousername");
var password = builder.AddParameter("mongopassword", secret: true);

var db = builder.AddMongo("db", username, password);

Melhorias importantes Azure

As seções a seguir descrevem Azure melhorias adicionadas no .NET Aspire 9. Para obter uma listagem completa de todas as alterações disruptivas, consulte Alterações disruptivas no .NET.NET Aspire 9.

Azure personalização de recursos

No .NET Aspire 8, a personalização dos recursos Azure foi marcada como experimental porque as bibliotecas subjacentes Azure.Provisioning eram novas e estavam coletando feedback antes de poderem ser marcadas como estáveis. Em .NET.NET Aspire 9 essas APIs foram atualizadas e remove o atributo experimental.

Azure mudança de ruptura na nomenclatura de recursos

Como parte da atualização para as bibliotecas de Azure.Provisioning, o esquema de nomenclatura padrão para recursos de Azure foi atualizado com melhor suporte para várias políticas de nomenclatura. No entanto, essa atualização resultou em uma alteração na forma como os recursos são nomeados. A nova política de nomenclatura pode fazer com que os recursos de Azure existentes sejam abandonados e novos recursos Azure sendo criados, depois de atualizar o aplicativo .NET Aspire de 8 para 9. Para continuar usando as mesmas políticas de nomenclatura do .NET.NET Aspire 8, você pode adicionar o seguinte código ao AppHost Program.cs :

var builder = DistributedApplication.CreateBuilder(args);

builder.Services.Configure<AzureProvisioningOptions>(options =>
{
    options.ProvisioningBuildOptions.InfrastructureResolvers.Insert(0, new AspireV8ResourceNamePropertyResolver());
});

Azure SQL, PostgreSQLe Redis Atualização

Os recursos Azure SQL, PostgreSQLe Redis são diferentes de outros recursos Azure, pois existem recursos locais de contêiner para essas tecnologias. No .NET Aspire 8, para criar esses recursos Azure, era necessário começar com um recurso de contêiner local e, em seguida, aplicar "Como" ou "PublicarComo" para transformá-lo em um recurso de Azure. Esse design introduziu problemas e não se encaixava em outras APIs.

Por exemplo, você pode ter esse código no .NET.NET Aspire 8:

var builder = DistributedApplication.CreateBuilder(args);

var sql = builder.AddSqlServer("sql")
                 .PublishAsAzureSqlDatabase();

var pgsql = builder.AddPostgres("pgsql")
                   .PublishAsAzurePostgresFlexibleServer();

var cache = builder.AddRedis("cache")
                   .PublishAsAzureSqlDatabase();

Em .NET.NET Aspire 9 estas APIs foram marcadas como obsoletas e um novo padrão de API implementado:

var builder = DistributedApplication.CreateBuilder(args);

var sql = builder.AddAzureSqlServer("sql")
                 .RunAsContainer();

var pgsql = builder.AddAzurePostgresFlexibleServer("pgsql")
                   .RunAsContainer();

var cache = builder.AddAzureRedis("cache")
                   .RunAsContainer();
Identificação do Microsoft Entra por padrão

Para tornar os aplicativos .NET Aspire mais seguros, o banco de dados Azure para recursos de PostgreSQL e Azure Cache for Redis foi atualizado para usar Microsoft Entra ID por padrão. Isso requer alterações em aplicativos que precisam se conectar a esses recursos. Confira o seguinte para atualizar aplicativos para usar a ID do Microsoft Entra para se conectar a esses recursos:

Os exemplos a seguir demonstram como configurar seu aplicativo para se conectar aos recursos de Azure usando a ID do Microsoft Entra:

Se você precisar usar a autenticação de senha ou chave de acesso (não recomendado), poderá ativar com o seguinte código:

var builder = DistributedApplication.CreateBuilder(args);

var pgsql = builder.AddAzurePostgresFlexibleServer("pgsql")
                   .WithPasswordAuthentication();

var cache = builder.AddAzureRedis("cache")
                   .WithAccessKeyAuthentication();

Suporte para funções de Azure (versão prévia)

O suporte para Azure Functions é um dos recursos mais amplamente solicitados no rastreador de problemas .NET.NET Aspire e estamos animados para introduzir o suporte de visualização para ele nesta versão. Para demonstrar esse suporte, vamos usar .NET.NET Aspire para criar e implantar um webhook.

Para começar, crie um novo projeto do Azure Functions usando a janela de diálogo Visual Studio Novo Projeto. Quando solicitado, selecione a caixa de seleção Inscrever-se em Aspire orquestração ao criar o projeto.

Criar um projeto novo do .NET AspireAzure Functions.

No projeto de host do aplicativo, observe que há um PackageReference para o novo 📦Aspire.Hospedagem.Azure.Funções pacote NuGet:

<ItemGroup>
    <PackageReference Include="Aspire.Hosting.AppHost" Version="9.0.0" />
    <PackageReference Include="Aspire.Hosting.Azure.Functions" Version="9.0.0" />
</ItemGroup>

Esse pacote fornece uma API AddAzureFunctionsProject<TProject>(IDistributedApplicationBuilder, String) que pode ser invocada no host do aplicativo para configurar projetos do Azure Functions em um host .NET Aspire:

var builder = DistributedApplication.CreateBuilder(args);

builder.AddAzureFunctionsProject<Projects.PigLatinApp>("piglatinapp");

builder.Build().Run();

Neste exemplo, o webhook é responsável por traduzir uma cadeia de caracteres de entrada para Pig Latin. Atualize o conteúdo do nosso gatilho com o seguinte código:

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
using System.Text;
using FromBodyAttribute = Microsoft.Azure.Functions.Worker.Http.FromBodyAttribute;

namespace PigLatinApp;

public class Function1(ILogger<Function1> logger)
{
    public record InputText(string Value);
    public record PigLatinText(string Value);

    [Function("Function1")]
    public IActionResult Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req,
        [FromBody] InputText inputText)
    {
        logger.LogInformation("C# HTTP trigger function processed a request.");

        var result = TranslateToPigLatin(inputText.Value);

        return new OkObjectResult(new PigLatinText(result));
    }

    private static string TranslateToPigLatin(string input)
    {
        if (string.IsNullOrEmpty(input))
        {
            return input;
        }

        var words = input.Split(' ');
        StringBuilder pigLatin = new();

        foreach (string word in words)
        {
            if (IsVowel(word[0]))
            {
                pigLatin.Append(word + "yay ");
            }
            else
            {
                int vowelIndex = FindFirstVowelIndex(word);
                if (vowelIndex is -1)
                {
                    pigLatin.Append(word + "ay ");
                }
                else
                {
                    pigLatin.Append(
                        word.Substring(vowelIndex) + word.Substring(0, vowelIndex) + "ay ");
                }
            }
        }

        return pigLatin.ToString().Trim();
    }

    private static int FindFirstVowelIndex(string word)
    {
        for (var i = 0; i < word.Length; i++)
        {
            if (IsVowel(word[i]))
            {
                return i;
            }
        }
        return -1;
    }

    private static bool IsVowel(char c) =>
        char.ToLower(c) is 'a' or 'e' or 'i' or 'o' or 'u';
}

Defina um ponto de interrupção na primeira linha de logger.LogInformation do método Run e pressione F5 para iniciar o host do Functions. Depois que o painel .NET.NET Aspire for lançado, você verá o seguinte:

Captura de tela do .NET Aspire em execução com um aplicativo de funções Azure.

.NET .NET Aspire tem:

  • Configurou um recurso de armazenamento emulado Azure para ser usado pelo host para registro.
  • Iniciou o host do Functions localmente, com o projeto Functions registrado definido como destino.
  • Conecte a porta definida em launchSettings.json do projeto de funções para escuta.

Use o seu HTTP client favorito para enviar uma requisição ao gatilho e observar as entradas vinculadas do corpo da requisição no depurador.

curl --request POST \
  --url http://localhost:7282/api/Function1 \
  --header 'Content-Type: application/json' \
  --data '{
  "value": "Welcome to Azure Functions"
}'

Captura de tela do painel .NET Aspire: Depurando um aplicativo de funções Azure.

Agora você está pronto para implantar nosso aplicativo no Azure Container Apps (ACA). A implantação atualmente depende de builds de visualização de pacotes do Azure Functions Worker e do SDK do Worker. Se necessário, atualize as versões referenciadas no projeto do Functions:

<ItemGroup>
    <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="2.0.0-preview2" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="2.0.0-preview2" />
</ItemGroup>

Você também precisa expor um endpoint público para o nosso projeto Functions Azure para que as solicitações possam ser enviadas ao gatilho HTTP.

builder.AddAzureFunctionsProject<Projects.PigLatinApp>("piglatinapp")
       .WithExternalHttpEndpoints();

Para implantar o aplicativo com a CLI azd, você precisa primeiro obter a versão mais recente. Para instalar a versão mais recente, você verá um aviso se sua versão estiver desatualizada. Siga as instruções para atualizar para a versão mais recente.

Depois de instalado, navegue até a pasta que contém o projeto do host do aplicativo e execute azd init:

$ azd init

Initializing an app to run on Azure (azd init)

? How do you want to initialize your app? Use code in the current directory

  (✓) Done: Scanning app code in current directory

Detected services:

  .NET (Aspire)
  Detected in: ./PigLatinApp/PigLatinApp.AppHost/PigLatinApp.AppHost.csproj

azd will generate the files necessary to host your app on Azure using Azure Container Apps.

? Select an option Confirm and continue initializing my app
? Enter a new environment name: azfunc-piglatin

Generating files to run your app on Azure:

  (✓) Done: Generating ./azure.yaml
  (✓) Done: Generating ./next-steps.md

SUCCESS: Your app is ready for the cloud!

Em seguida, implante o aplicativo executando azd up:

$ azd up 
? Select an Azure Subscription to use: 130. [redacted]
? Select an Azure location to use: 50. (US) West US 2 (westus2)

Packaging services (azd package)


Provisioning Azure resources (azd provision)
Provisioning Azure resources can take some time.

Subscription: [redacted]
Location: West US 2

  You can view detailed progress in the Azure Portal:
  [redacted]

  (✓) Done: Resource group: rg-azfunc-piglatin (967ms)
  (✓) Done: Container Registry: [redacted] (13.316s)
  (✓) Done: Log Analytics workspace: [redacted] (16.467s)
  (✓) Done: Container Apps Environment: [redacted] (1m35.531s)
  (✓) Done: Storage account: [redacted] (21.37s)

Deploying services (azd deploy)

  (✓) Done: Deploying service piglatinapp
  - Endpoint: {{endpoint-url}}

  Aspire Dashboard: {{dashboard-url}}

Por fim, teste sua aplicação Functions implantada, usando seu HTTP favorito client.

curl --request POST \
  --url {{endpoint-url}}/api/Function1 \
  --header 'Content-Type: application/json' \
  --data '{
  "value": "Welcome to Azure Functions"
}'

O suporte para Azure Functions no .NET Aspire ainda está em versão prévia com suporte para um conjunto restrito de gatilhos, incluindo:

Para obter mais informações, consulte a integração oficial das funções .NET AspireAzure (Prévia).

Personalização de Azure Container Apps

Um dos recursos mais solicitados é a capacidade de personalizar o Azure Container Apps que o host do aplicativo cria sem tocar no Bicep. Isso é possível usando as APIs PublishAsAzureContainerApp<T>(IResourceBuilder<T>, Action<AzureResourceInfrastructure,ContainerApp>) e PublishAsAzureContainerApp<T>(IResourceBuilder<T>, Action<AzureResourceInfrastructure,ContainerApp>) no namespace Aspire.Hosting.Azure.AppContainers. Esses métodos personalizam a definição do Aplicativo de Contêiner Azure que o host do aplicativo cria.

Adicione a referência de pacote ao arquivo de projeto:

<ItemGroup>
  <PackageReference Include="Aspire.Hosting.Azure.AppContainers"
                    Version="9.0.0" />
</ItemGroup>

O exemplo a seguir demonstra como escalar um Container App Azure para zero réplicas (0).

var builder = DistributedApplication.CreateBuilder(args);

var db = builder.AddAzurePostgresFlexibleServer("pg")
                .RunAsContainer()
                .AddDatabase("db");

// Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable AZPROVISION001

builder.AddProject<Projects.WebApplication1>("api")
       .WithReference(db)
       .PublishAsAzureContainerApp((module, containerApp) =>
       {
           // Scale to 0
           containerApp.Template.Value!.Scale.Value!.MinReplicas = 0;
       });

#pragma warning restore AZPROVISION001

builder.Build().Run();

O exemplo de código anterior adia a geração da definição do aplicativo de contêiner Azure para o host do aplicativo. Isso permite personalizar a definição da App Container Azure sem a necessidade de executar o azd infra synth e modificar de forma insegura os arquivos bicep gerados.

Consulte também