Compartilhar via


visão geral das integrações .NET AspireAzure

Azure é a plataforma de nuvem mais popular para criar e implantar aplicativos .NET. O SDK do Azure para .NET permite gerenciamento fácil e uso dos serviços de Azure. .NET Aspire fornece um conjunto de integrações com serviços Azure, em que você é livre para adicionar novos recursos ou se conectar aos existentes. Este artigo detalha alguns aspectos comuns de todas as integrações Azure no .NET Aspire e tem como objetivo ajudar você a entender como usá-las.

Adicionar Azure recursos

Todas as integrações de hospedagem .NET AspireAzure expõem recursos Azure e, por convenção, são adicionadas usando APIs de AddAzure*. Quando você adiciona esses recursos ao host do aplicativo .NET Aspire, eles representam um serviço Azure. A API AddAzure* retorna um IResourceBuilder<T> em que T é o tipo de recurso Azure. Essas interfaces IResourceBuilder<T> (builder) fornecem uma API fluente que permite configurar o recurso subjacente Azure dentro do modelo de aplicativo . Há APIs para adicionar novos recursos de Azure, marcar recursos como existentes e configurar como os recursos se comportam em vários contextos de execução.

Experiência típica do desenvolvedor

Quando o host do aplicativo .NET Aspire contém Azure recursos e você o executa localmente (experiência típica de desenvolvedor F5 ou dotnet run), os recursos Azure são provisionados na sua assinatura Azure. Isso permite que você, como desenvolvedor, depure contra eles localmente no ambiente do host do seu aplicativo.

.NET .NET Aspire tem como objetivo minimizar os custos, adotando como padrão a Básica ou PadrãoUnidade de Manutenção de Estoque (SKU) para suas integrações de Azure. Embora essas configurações padrão sensatas sejam fornecidas, você pode personalizar os recursos Azure para atender às suas necessidades. Além disso, algumas integrações dão suporte a emuladores ou contêineres, que são úteis para desenvolvimento local, teste e depuração. Por padrão, quando você executa seu aplicativo localmente, os recursos de Azure usam o serviço de Azure real. No entanto, você pode configurá-los para usar emuladores ou contêineres locais, evitando custos associados ao serviço de Azure real durante o desenvolvimento local.

Emuladores locais

Alguns serviços de Azure podem ser emulados para serem executados localmente. Atualmente, .NET Aspire dá suporte aos seguintes emuladores de Azure:

Integração de hospedagem Descrição
Azure Cosmos DB Chame AzureCosmosExtensions.RunAsEmulator no IResourceBuilder<AzureCosmosDBResource> para configurar o recurso Cosmos DB para ser emulado com a API NoSQL.
Azure Event Hubs Chame AzureEventHubsExtensions.RunAsEmulator no IResourceBuilder<AzureEventHubsResource> para configurar o recurso do Event Hubs para que seja emulado.
Azure Service Bus Chamar AzureServiceBusExtensions.RunAsEmulator no IResourceBuilder<AzureServiceBusResource> para configurar o recurso do Barramento de Serviço para ser emulado com o emulador do Barramento de Serviço.
Azure SignalR Service Chame AzureSignalRExtensions.RunAsEmulator no IResourceBuilder<AzureSignalRResource> para configurar o recurso SignalR para ser emulado como com o emulador AzureSignalR.
Armazenamento Azure Chame AzureStorageExtensions.RunAsEmulator no IResourceBuilder<AzureStorageResource> para configurar o recurso de Armazenamento para ser emulado com Azurite.

Para que seus recursos de Azure usem os emuladores locais, encadeia uma chamada ao método RunAsEmulator no construtor de recursos Azure. Esse método configura o recurso Azure para usar o emulador local em vez do serviço de Azure real.

Importante

Ao chamar qualquer uma das APIs disponíveis de RunAsEmulator em um construtor de recursos Azure, isso não tem efeito sobre o manifesto de publicação . Quando você publica seu aplicativo, arquivo Bicep gerado reflete o serviço real, não o emulador local.

Contêineres locais

Alguns recursos Azure podem ser substituídos localmente usando contêineres de software livre ou locais. Para substituir um recurso Azure localmente em um contêiner, encadeia uma chamada ao método RunAsContainer no construtor de recursos Azure. Esse método configura o recurso Azure para usar uma versão em contêineres do serviço para desenvolvimento e teste local, em vez do serviço de Azure real.

Atualmente, .NET Aspire dá suporte aos seguintes serviços de Azure como contêineres:

Integração de hospedagem Detalhes
Azure Cache for Redis Chame AzureRedisExtensions.RunAsContainer no IResourceBuilder<AzureRedisCacheResource> para configurá-lo para ser executado localmente em um contêiner, com base na imagem docker.io/library/redis.
Azure PostgreSQL Server Flexível Chame AzurePostgresExtensions.RunAsContainer no IResourceBuilder<AzurePostgresFlexibleServerResource> para configurá-lo para ser executado localmente em um contêiner, com base na imagem docker.io/library/postgres.
Azure SQL Server Chame AzureSqlExtensions.RunAsContainer no IResourceBuilder<AzureSqlServerResource> para configurá-lo para ser executado localmente em um contêiner, com base na imagem mcr.microsoft.com/mssql/server.

Nota

Assim como os emuladores, chamar RunAsContainer em um construtor de recursos Azure não afeta o manifesto de publicação . Quando você publica seu aplicativo, o arquivo Bicep gerado reflete o Azure, não o contêiner local.

Entender as APIs de integração Azure

A força do .NET.NET Aspireestá em sua capacidade de fornecer um ciclo interno de desenvolvimento incrível. As integrações Azure não são diferentes de outras. Eles fornecem um conjunto de APIs e padrões comuns que são compartilhados em todos os recursos Azure. Essas APIs e padrões são projetados para facilitar o trabalho com recursos Azure de maneira consistente.

Na seção de contêineres anterior, você viu como executar serviços Azure localmente em contêineres. Se você estiver familiarizado com .NET.NET Aspire, talvez se pergunte como chamar AddAzureRedis("redis").RunAsContainer() para obter um contêiner de docker.io/library/redis local difere de AddRedis("redis")— pois ambos resultam no mesmo contêiner local.

A resposta é que não há diferença ao executar localmente. No entanto, quando eles são publicados, você obtém recursos diferentes:

API Modo de execução Modo de publicação
AddAzureRedis("redis").RunAsContainer() Contêiner local Redis Azure Cache for Redis
AddRedis("redis") Contêiner local Redis Azure Aplicativo em Contêiner com imagem Redis

O mesmo vale para serviços sql e PostgreSQL:

API Modo de execução Modo de publicação
AddAzurePostgresFlexibleServer("postgres").RunAsContainer() Contêiner local PostgreSQL Azure PostgreSQL Server Flexível
addPostgres("postgres") Contêiner local PostgreSQL Azure Aplicativo de Contêiner com PostgreSQL imagem
AddAzureSqlServer("sql").RunAsContainer() Contêiner local SQL Server Azure SQL Server
AddSqlServer("sql") Contêiner local SQL Server Azure Aplicativo de Contêiner com imagem SQL Server

Para obter mais informações sobre a diferença entre os modos de execução e publicação, consulte .NET.NET Aspire host do aplicativo: contexto de execução.

APIs para expressar recursos Azure em modos diferentes

O construtor de aplicativos distribuídos, parte do host do aplicativo, usa o padrão do construtor para adicionar recursos ao modelo de aplicativo. Os desenvolvedores podem configurar esses recursos e definir seu comportamento em diferentes contextos de execução. Azure integrações de hospedagem fornecem APIs para especificar como esses recursos devem ser "publicados" e "executados".

Quando o host do aplicativo é executado, o contexto de execução é usado para determinar se o host do aplicativo está no modo Run ou Publish. As convenções de nomenclatura dessas APIs indicam a ação pretendida para o recurso.

A tabela a seguir resume as convenções de nomenclatura usadas para expressar os recursos Azure:

Operação API Descrição
Publicar PublishAsConnectionString<T>(IResourceBuilder<T>) Altera o recurso para que seja publicado como uma referência de string de conexão no manifesto.
Publicar PublishAsExisting Usa um recurso de Azure existente quando o aplicativo é implantado em vez de criar um novo.
Correr AzureSqlExtensions.RunAsContainer(IResourceBuilder<AzureSqlServerResource>, Action<IResourceBuilder<SqlServerServerResource>>)
AzureRedisExtensions.RunAsContainer(IResourceBuilder<AzureRedisCacheResource>, Action<IResourceBuilder<RedisResource>>)
RunAsContainer(IResourceBuilder<AzurePostgresFlexibleServerResource>, Action<IResourceBuilder<PostgresServerResource>>)
Configura um contêiner equivalente para ser executado localmente. Para obter mais informações, consulte Contêineres locais.
Correr AzureCosmosExtensions.RunAsEmulator(IResourceBuilder<AzureCosmosDBResource>, Action<IResourceBuilder<AzureCosmosDBEmulatorResource>>)
AzureSignalRExtensions.RunAsEmulator(IResourceBuilder<AzureSignalRResource>, Action<IResourceBuilder<AzureSignalREmulatorResource>>)
AzureStorageExtensions.RunAsEmulator(IResourceBuilder<AzureStorageResource>, Action<IResourceBuilder<AzureStorageEmulatorResource>>)
AzureEventHubsExtensions.RunAsEmulator(IResourceBuilder<AzureEventHubsResource>, Action<IResourceBuilder<AzureEventHubsEmulatorResource>>)
AzureServiceBusExtensions.RunAsEmulator(IResourceBuilder<AzureServiceBusResource>, Action<IResourceBuilder<AzureServiceBusEmulatorResource>>)
Configura o recurso Azure a ser emulado. Para obter mais informações, consulte Emuladores locais.
Correr RunAsExisting Usa um recurso existente quando o aplicativo está em execução em vez de criar um novo.
Publicar e executar AsExisting<T>(IResourceBuilder<T>, IResourceBuilder<ParameterResource>, IResourceBuilder<ParameterResource>) Usa um recurso existente, independentemente da operação.

Nota

Nem todas as APIs estão disponíveis em todos os recursos Azure. Por exemplo, alguns recursos de Azure podem ser contêinerizados ou emulados, enquanto outros não podem.

Para obter mais informações sobre modos de execução, consulte contexto de execução.

Casos gerais de uso da API do modo de execução

Use RunAsExisting quando precisar interagir dinamicamente com um recurso existente durante o runtime sem precisar implantá-lo ou atualizá-lo. Use PublishAsExisting ao declarar recursos existentes como parte de uma configuração de implantação, garantindo que os escopos e permissões corretos sejam aplicados. Por fim, use AsExisting<T>(IResourceBuilder<T>, IResourceBuilder<ParameterResource>, IResourceBuilder<ParameterResource>) ao declarar recursos existentes em ambas as configurações, com um requisito parametrizar as referências.

Você pode consultar se um recurso está marcado como um recurso existente chamando o método de extensão IsExisting(IResource) no IResource. Para obter mais informações, consulte Usar recursos de Azure existentes.

Utilizar recursos Azure existentes

.NET Aspire fornece suporte para referenciar recursos de Azure existentes. Você marca um recurso existente por meio das APIs PublishAsExisting, RunAsExistinge AsExisting. Essas APIs permitem que os desenvolvedores façam referência a recursos de Azure já implantados, configurem-nos e gerem manifestos de implantação apropriados usando modelos Bicep.

Os recursos existentes referenciados com essas APIs podem ser aprimorados com atribuições de função e outras personalizações disponíveis com a infraestrutura do .NET.NET Aspirecomo recursos de código. Essas APIs são limitadas a recursos Azure que podem ser implantados usando modelos Bicep.

Configurar recursos de Azure existentes para o modo de execução

O método RunAsExisting é usado quando um aplicativo distribuído está em execução no modo "run". Nesse modo, ele pressupõe que o recurso de Azure referenciado já existe e se integra a ele durante a execução sem provisionar o recurso. Para marcar um recurso Azure como existente, chame o método RunAsExisting no construtor de recursos. Considere o seguinte exemplo:

var builder = DistributedApplication.CreateBuilder();

var existingServiceBusName = builder.AddParameter("existingServiceBusName");
var existingServiceBusResourceGroup = builder.AddParameter("existingServiceBusResourceGroup");

var serviceBus = builder.AddAzureServiceBus("messaging")
                        .RunAsExisting(existingServiceBusName, existingServiceBusResourceGroup);

serviceBus.AddServiceBusQueue("queue");

O código anterior:

  • Cria uma nova instância de builder.
  • Adiciona um parâmetro chamado existingServiceBusName ao construtor.
  • Adiciona um recurso Azure Service Bus chamado messaging ao construtor.
  • Chama o método RunAsExisting no construtor de recursos serviceBus, passando o parâmetro existingServiceBusName—alternativamente, você pode usar a sobrecarga de parâmetro string.
  • Adiciona uma fila chamada queue ao recurso serviceBus.

Por padrão, pressupõe-se que a referência de parâmetro do Barramento de Serviço esteja no mesmo grupo de recursos Azure. No entanto, se ele estiver em um grupo de recursos diferente, você poderá passar o grupo de recursos explicitamente como um parâmetro para especificar corretamente o agrupamento de recursos apropriado.

Configurar recursos de Azure existentes para o modo de publicação

O método PublishAsExisting é usado no modo "publish" quando a intenção é declarar e fazer referência a um recurso de Azure já existente durante o modo de publicação. Esta API facilita a criação de manifests e modelos que incluem definições de recursos que se correspondem com recursos existentes no Bicep.

Para marcar um recurso Azure como existente no modo "publicar", chame o método PublishAsExisting no construtor de recursos. Considere o seguinte exemplo:

var builder = DistributedApplication.CreateBuilder();

var existingServiceBusName = builder.AddParameter("existingServiceBusName");
var existingServiceBusResourceGroup = builder.AddParameter("existingServiceBusResourceGroup");

var serviceBus = builder.AddAzureServiceBus("messaging")
                        .PublishAsExisting(existingServiceBusName, existingServiceBusResourceGroup);

serviceBus.AddServiceBusQueue("queue");

O código anterior:

  • Cria uma nova instância de builder.
  • Adiciona um parâmetro chamado existingServiceBusName para o construtor.
  • Adiciona um recurso Azure Service Bus chamado messaging ao construtor.
  • Chama o método PublishAsExisting no construtor de recursos serviceBus, passando o parâmetro existingServiceBusName—alternativamente, você pode usar a sobrecarga de parâmetro string.
  • Adiciona uma fila chamada queue ao recurso serviceBus.

Depois que o host do aplicativo for executado no modo de publicação, o arquivo de manifesto gerado incluirá o parâmetro existingResourceName, que pode ser usado para referenciar o recurso de Azure existente. Considere o seguinte trecho parcial gerado do arquivo de manifesto:

"messaging": {
  "type": "azure.bicep.v0",
  "connectionString": "{messaging.outputs.serviceBusEndpoint}",
  "path": "messaging.module.bicep",
  "params": {
    "existingServiceBusName": "{existingServiceBusName.value}",
    "principalType": "",
    "principalId": ""
  }
},
"queue": {
  "type": "value.v0",
  "connectionString": "{messaging.outputs.serviceBusEndpoint}"
}

Para obter mais informações sobre o arquivo de manifesto, consulte .NET.NET Aspire formato de manifesto para desenvolvedores de ferramentas de implantação.

Além disso, o modelo Bicep gerado inclui o parâmetro existingResourceName, que pode ser usado para referenciar o recurso de Azure existente. Considere o seguinte modelo Bicep gerado:

@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location

param existingServiceBusName string

param principalType string

param principalId string

resource messaging 'Microsoft.ServiceBus/namespaces@2024-01-01' existing = {
  name: existingServiceBusName
}

resource messaging_AzureServiceBusDataOwner 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(messaging.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '090c5cfd-751d-490a-894a-3ce6f1109419'))
  properties: {
    principalId: principalId
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '090c5cfd-751d-490a-894a-3ce6f1109419')
    principalType: principalType
  }
  scope: messaging
}

resource queue 'Microsoft.ServiceBus/namespaces/queues@2024-01-01' = {
  name: 'queue'
  parent: messaging
}

output serviceBusEndpoint string = messaging.properties.serviceBusEndpoint

Para mais informações sobre os modelos Bicep gerados, verifique Infraestrutura como código e considere outras APIs de publicação.

Aviso

Ao interagir com recursos existentes que exigem autenticação, verifique se a estratégia de autenticação que você está configurando no modelo de aplicativo .NET.NET Aspire se alinha à estratégia de autenticação permitida pelo recurso existente. Por exemplo, não é possível usar a identidade gerenciada em um recurso de AzurePostgreSQL existente que não está configurado para permitir a identidade gerenciada. Da mesma forma, se um recurso AzureRedis existente tiver desabilitado as chaves de acesso, não será possível usar a autenticação de chave de acesso.

Configurar recursos de Azure existentes em todos os modos

O método AsExisting<T>(IResourceBuilder<T>, IResourceBuilder<ParameterResource>, IResourceBuilder<ParameterResource>) é usado quando o aplicativo distribuído está em execução no modo "run" ou "publish". Como o método AsExisting opera em ambos os cenários, ele dá suporte apenas a uma referência parametrizada ao nome do recurso ou ao nome do grupo de recursos. Essa abordagem ajuda a impedir o uso do mesmo recurso em ambientes de teste e de produção.

Para marcar um recurso Azure como existente, chame o método AsExisting no construtor de recursos. Considere o seguinte exemplo:

var builder = DistributedApplication.CreateBuilder();

var existingServiceBusName = builder.AddParameter("existingServiceBusName");
var existingServiceBusResourceGroup = builder.AddParameter("existingServiceBusResourceGroup");

var serviceBus = builder.AddAzureServiceBus("messaging")
                        .AsExisting(existingServiceBusName, existingServiceBusResourceGroup);

serviceBus.AddServiceBusQueue("queue");

O código anterior:

  • Cria uma nova instância de builder.
  • Adiciona um parâmetro chamado existingServiceBusName ao construtor.
  • Adiciona um recurso Azure Service Bus chamado messaging ao construtor.
  • Chama o método AsExisting no construtor de recursos serviceBus, passando o parâmetro existingServiceBusName.
  • Adiciona uma fila chamada queue ao recurso serviceBus.

Adicionar recursos existentes Azure com strings de conexão

.NET .NET Aspire fornece a capacidade de se conectar aos recursos existentes, incluindo recursos de Azure. Expressar cadeias de conexão é útil quando você tem recursos Azure existentes que deseja usar em seu aplicativo .NET Aspire. A API AddConnectionString é usada com o contexto de execução do host do aplicativo para adicionar condicionalmente uma cadeia de conexão ao modelo de aplicativo.

Nota

As cadeias de conexão são usadas para representar uma ampla gama de informações de conexão, incluindo conexões de banco de dados, agentes de mensagens, URIs de ponto de extremidade e outros serviços. Em .NET.NET Aspire nomenclatura, o termo "cadeia de conexão" é usado para representar qualquer tipo de informação de conexão.

Considere o exemplo a seguir, onde no modo de publicação , você adiciona um recurso de Armazenamento Azure, enquanto no modo de execução , você adiciona uma cadeia de conexão a um armazenamento Azure existente.

var builder = DistributedApplication.CreateBuilder(args);

var storage = builder.ExecutionContext.IsPublishMode
    ? builder.AddAzureStorage("storage")
    : builder.AddConnectionString("storage");

builder.AddProject<Projects.Api>("api")
       .WithReference(storage);

// After adding all resources, run the app...

O código anterior:

  • Cria uma nova instância de builder.
  • Adiciona um recurso de Armazenamento Azure chamado storage no modo "publicar".
  • Adiciona uma cadeia de conexão a um armazenamento de Azure existente chamado storage no modo de execução.
  • Adiciona um projeto chamado api ao builder.
  • O projeto api faz referência ao recurso storage independentemente do modo.

O projeto de API de consumo usa as informações da cadeia de conexão sem conhecimento de como o host do aplicativo o configurou. No modo "publicar", o código adiciona um novo recurso de armazenamento Azure, o que será refletido adequadamente no manifesto de implantação . Quando estiver no modo "executar", a cadeia de conexão corresponde a um valor de configuração visível para o host do aplicativo. Supõe-se que todas as atribuições de função para o recurso de destino estejam configuradas. Isso significa que você provavelmente configurará uma variável de ambiente ou um segredo do usuário para armazenar a cadeia de conexão. A configuração é resolvida a partir da chave de configuração ConnectionStrings__storage (ou ConnectionStrings:storage). Esses valores de configuração podem ser exibidos quando o aplicativo é executado. Para obter mais informações, consulte Detalhes do recurso.

Ao contrário dos recursos existentes modelados com ade API de AsExisting de primeira classe, o recurso existente modelado como cadeias de conexão não pode ser aprimorado com atribuições de função adicionais ou personalizações de infraestrutura.

Publicar como Azure Aplicativo de Contêiner

.NET .NET Aspire permite publicar recursos primitivos como Azure Container Apps, uma plataforma sem servidor que reduz o gerenciamento de infraestrutura. Os tipos de recursos com suporte incluem:

Para publicar esses recursos, use as seguintes APIs:

Essas APIs configuram o recurso a ser publicado como um aplicativo de contêiner Azure e chamam implicitamente AddAzureContainerAppsInfrastructure(IDistributedApplicationBuilder) para adicionar a infraestrutura necessária e os arquivos Bicep ao host do aplicativo. Como exemplo, considere o seguinte código:

var builder = DistributedApplication.CreateBuilder();

var env = builder.AddParameter("env");

var api = builder.AddProject<Projects.AspireApi>("api")
                 .PublishAsAzureContainerApp<Projects.AspireApi>((infra, app) =>
                 {
                     app.Template.Containers[0].Value!.Env.Add(new ContainerAppEnvironmentVariable
                     {
                         Name = "Hello",
                         Value = env.AsProvisioningParameter(infra)
                     });
                 });

O código anterior:

  • Cria uma nova instância de builder.
  • Adiciona um parâmetro chamado env ao construtor.
  • Adiciona um projeto chamado api ao construtor.
  • Chama o método PublishAsAzureContainerApp no construtor de recursos api, passando uma expressão lambda que configura a infraestrutura do Aplicativo de Contêiner Azure, em que infra é o AzureResourceInfrastructure e app é o ContainerApp.
    • Adiciona uma variável de ambiente chamada Hello ao aplicativo de contêiner usando o parâmetro env.
    • O método AsProvisioningParameter é usado para tratar env como um novo ProvisioningParameter na infraestrutura, ou para reutilizar um parâmetro bicep existente se já existir um com o mesmo nome.

Para obter mais informações, consulte ContainerApp e AsProvisioningParameter.

Infraestrutura como código

O SDK do para fornece o pacote NuGet de provisionamento e um conjunto de pacotes específicos do serviço de provisionamento . Essas bibliotecas de provisionamento Azure facilitam a especificação declarativa de Azure infraestrutura de forma nativa no .NET. Suas APIs permitem que você escreva a infraestrutura orientada a objetos em C#, resultando em Bicep. Bicep é uma linguagem específica de domínio (DSL) para implantar Azure recursos declarativamente.

Embora seja possível provisionar Azure recursos manualmente, .NET Aspire simplifica o processo fornecendo um conjunto de APIs para expressar Azure recursos. Essas APIs estão disponíveis como métodos de extensão em bibliotecas de hospedagem .NET AspireAzure, estendendo a interface IDistributedApplicationBuilder. Quando você adiciona recursos Azure ao host do aplicativo, eles adicionam a funcionalidade de provisionamento apropriada implicitamente. Em outras palavras, você não precisa chamar nenhuma API de provisionamento diretamente.

Como .NET Aspire modela Azure recursos dentro de Azure integrações de hospedagem, o SDK Azure é usado para provisionar esses recursos. São gerados arquivos Bicep que definem os recursos Azure de que você precisa. Os arquivos Bicep gerados são emitidos junto ao arquivo de manifesto quando você publica seu aplicativo.

Há várias maneiras de influenciar os arquivos Bicep gerados:

Provisionamento local e Azure.Provisioning

Para evitar confundir termos e ajudar a desambiguar o "provisionamento", é importante entender a distinção entre provisionamento local e provisionamento Azure:

  • Provisionamento local:

    Por padrão, quando você chama qualquer uma das APIs de integração de hospedagem Azure para adicionar recursos Azure, a API AddAzureProvisioning(IDistributedApplicationBuilder) é chamada implicitamente. Essa API registra serviços no contêiner de injeção de dependência (DI) que são usados para provisionar recursos Azure quando o host do aplicativo inicia. Esse conceito é conhecido como provisionamento local. Para obter mais informações, consulte provisionamento local Azure.

  • Azure.Provisioning:

    Azure.Provisioning refere-se ao pacote NuGet e é um conjunto de bibliotecas que permite usar C# para gerar o Bicep. O Azure integrações de hospedagem no .NET Aspire usar essas bibliotecas nas capas para gerar arquivos Bicep que definem os recursos de Azure necessários. Para obter mais informações, consulte Azure.Provisioning personalização.

personalização Azure.Provisioning

Todas as integrações de hospedagem .NET AspireAzure expõem vários recursos Azure e todas elas são subclasses do tipo AzureProvisioningResource, que herda o AzureBicepResource. Isso permite extensões que são restritas genericamente a esse tipo, permitindo que uma API fluente personalize a infraestrutura de acordo com seu gosto. Embora .NET.NET Aspire forneça padrões, você é livre para influenciar o Bicep gerado usando essas APIs.

Configurar a infraestrutura

Independentemente do recurso Azure com o qual você está trabalhando, para configurar sua infraestrutura subjacente, você faz uma chamada encadeada ao método de extensão ConfigureInfrastructure. Esse método permite personalizar a infraestrutura do recurso de Azure passando um delegado configure do tipo Action<AzureResourceInfrastructure>. O tipo AzureResourceInfrastructure é uma subclasse do Azure.Provisioning.Infrastructure. Esse tipo expõe uma área de superfície de API massiva para configurar a infraestrutura subjacente do recurso Azure.

Considere o seguinte exemplo:

var sku = builder.AddParameter("storage-sku");

var storage = builder.AddAzureStorage("storage")
    .ConfigureInfrastructure(infra =>
    {
        var resources = infra.GetProvisionableResources();

        var storageAccount = resources.OfType<StorageAccount>().Single();

        storageAccount.Sku = new StorageSku
        {
            Name = sku.AsProvisioningParameter(infra)
        };
    });

O código anterior:

  • Adiciona um parâmetro chamado storage-sku.
  • Adiciona armazenamento Azure com a API AddAzureStorage chamada storage.
  • Encadeia uma chamada para ConfigureInfrastructure para personalizar a infraestrutura de armazenamento Azure:

Isso exemplifica o fluxo de um parâmetro externo para a infraestrutura de Armazenamento Azure, resultando no arquivo Bicep gerado refletindo a configuração desejada.

Adicionar infraestrutura Azure

Nem todos os serviços Azure são expostos como integrações .NET Aspire. Ainda que eles possam ser implementados em um momento posterior, você ainda pode disponibilizar serviços que estão disponíveis nas bibliotecas Azure.Provisioning.*. Imagine um cenário em que você tem um serviço de trabalho responsável pelo gerenciamento de um Registro de Contêiner Azure. Agora imagine que um projeto de host de aplicativo tenha uma dependência do pacote NuGet 📦Azure.Provisioning.ContainerRegistry.

Você pode usar a API AddAzureInfrastructure para adicionar a infraestrutura do Registro de Contêiner Azure ao host do aplicativo:

var acr = builder.AddAzureInfrastructure("acr", infra =>
{
    var registry = new ContainerRegistryService("acr")
    {
        Sku = new()
        {
            Name = ContainerRegistrySkuName.Standard
        },
    };
    infra.Add(registry);

    var output = new ProvisioningOutput("registryName", typeof(string))
    {
        Value = registry.Name
    };
    infra.Add(output);
});

builder.AddProject<Projects.WorkerService>("worker")
       .WithEnvironment(
            "ACR_REGISTRY_NAME",
            new BicepOutputReference("registryName", acr.Resource));

O código anterior:

  • Chama AddAzureInfrastructure com o nome de acr.
  • Fornece um delegado configureInfrastructure para personalizar a infraestrutura do Registro de Contêineres Azure.
    • Instancia um ContainerRegistryService com o nome acr e um SKU padrão.
    • Adiciona o serviço Azure Registro de Contêiner à variável infra.
    • Instancia um ProvisioningOutput com o nome registryName, um tipo de stringe um valor que corresponde ao nome do Registro de Contêiner Azure.
    • Adiciona a saída à variável infra.
  • Adiciona um projeto chamado worker ao construtor.
  • Encadeia uma chamada para WithEnvironment para definir a variável de ambiente ACR_REGISTRY_NAME no projeto com o valor da saída registryName.

A funcionalidade demonstra como adicionar a infraestrutura Azure ao projeto de host do aplicativo, mesmo que o serviço Azure não seja exposto diretamente como uma integração .NET Aspire. Ele mostra ainda como direcionar a saída do Registro de Contêineres Azure para o ambiente de um projeto dependente.

Considere o arquivo Bicep resultante:

@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location

resource acr 'Microsoft.ContainerRegistry/registries@2023-07-01' = {
  name: take('acr${uniqueString(resourceGroup().id)}', 50)
  location: location
  sku: {
    name: 'Standard'
  }
}

output registryName string = acr.name

O arquivo Bicep reflete a configuração desejada do Registro de Contêiner Azure, conforme definido pela API AddAzureInfrastructure.

"Utilizar modelos Bicep personalizados"

Ao direcionar Azure como seu provedor de nuvem desejado, você pode usar o Bicep para definir sua infraestrutura como código. Ele visa simplificar drasticamente a experiência de criação com uma sintaxe mais limpa e um melhor suporte para modularidade e reutilização de código.

Embora .NET.NET Aspire forneça um conjunto de modelos Bicep predefinidos, pode haver momentos em que você deseja personalizar os modelos ou criar seus próprios. Esta seção explica os conceitos e as APIs correspondentes que você pode usar para personalizar os modelos do Bicep.

Importante

Esta seção não se destina a ensinar o Bicep, mas sim para fornecer diretrizes sobre como criar modelos Bicep personalizados para uso com .NET.NET Aspire.

Como parte da Azure história de implantação para .NET Aspire, o Azure Developer CLI (azd) fornece uma compreensão do seu projeto de .NET Aspire e a capacidade de implantá-lo no Azure. A CLI do azd usa os templates Bicep para implantar o aplicativo em Azure.

Instalar o pacote Aspire.Hosting.Azure

Quando você deseja referenciar arquivos Bicep, é possível que você não esteja usando nenhuma das integrações de hospedagem Azure. Nesse caso, você ainda pode referenciar arquivos Bicep instalando o pacote Aspire.Hosting.Azure. Esse pacote fornece as APIs necessárias para referenciar arquivos Bicep e personalizar os recursos Azure.

Dica

Se você estiver usando qualquer uma das integrações de hospedagem Azure, não será necessário instalar o pacote Aspire.Hosting.Azure, pois ele é uma dependência transitiva.

Para usar qualquer uma dessas funcionalidades, o pacote NuGet 📦Aspire.Hosting.Azure deve ser instalado.

dotnet add package Aspire.Hosting.Azure

Para obter mais informações, consulte dotnet add package ou Gerencie dependências de pacotes em aplicativos .NET.

O que esperar dos exemplos

Todos os exemplos nesta seção pressupõem que você está usando o namespace Aspire.Hosting.Azure. Além disso, os exemplos pressupõem que você tenha uma instância de IDistributedApplicationBuilder:

using Aspire.Hosting.Azure;

var builder = DistributedApplication.CreateBuilder(args);

// Examples go here...

builder.Build().Run();

Por padrão, quando você chama qualquer uma das APIs relacionadas ao Bicep, uma chamada também é feita para AddAzureProvisioning que adiciona suporte para gerar recursos Azure dinamicamente durante a inicialização do aplicativo. Para obter mais informações, consulte Provisionamento local e Azure.Provisioning.

Faça referência a arquivos Bicep

Imagine que você tenha um modelo Bicep em um arquivo chamado storage.bicep que provisiona uma conta de armazenamento Azure:

param location string = resourceGroup().location
param storageAccountName string = 'toylaunch${uniqueString(resourceGroup().id)}'

resource storageAccount 'Microsoft.Storage/storageAccounts@2021-06-01' = {
  name: storageAccountName
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: {
    accessTier: 'Hot'
  }
}

Para adicionar uma referência ao arquivo Bicep no disco, chame o método AddBicepTemplate. Considere o seguinte exemplo:

builder.AddBicepTemplate(
    name: "storage",
    bicepFile: "../infra/storage.bicep");

O código anterior adiciona uma referência a um arquivo Bicep localizado em ../infra/storage.bicep. Os caminhos de arquivo devem ser relativos ao projeto de host do aplicativo . Essa referência resulta em uma AzureBicepResource sendo adicionada à coleção de recursos do aplicativo com o nome "storage" e a API retorna uma instância IResourceBuilder<AzureBicepResource> que pode ser usada para personalizar ainda mais o recurso.

Referenciar o Bicep de forma embutida

Embora ter um arquivo Bicep no disco seja o cenário mais comum, você também pode adicionar modelos Bicep diretamente. Modelos embutidos podem ser úteis quando você deseja definir um modelo no código ou quando você deseja gerar o modelo dinamicamente. Para adicionar um modelo Bicep em linha, chame o método AddBicepTemplateString com o modelo Bicep como um string. Considere o seguinte exemplo:

builder.AddBicepTemplateString(
        name: "ai",
        bicepContent: """
        @description('That name is the name of our application.')
        param cognitiveServiceName string = 'CognitiveService-${uniqueString(resourceGroup().id)}'

        @description('Location for all resources.')
        param location string = resourceGroup().location

        @allowed([
          'S0'
        ])
        param sku string = 'S0'

        resource cognitiveService 'Microsoft.CognitiveServices/accounts@2021-10-01' = {
          name: cognitiveServiceName
          location: location
          sku: {
            name: sku
          }
          kind: 'CognitiveServices'
          properties: {
            apiProperties: {
              statisticsEnabled: false
            }
          }
        }
        """
    );

Neste exemplo, o modelo Bicep é definido como um string embutido e adicionado à coleção de recursos do aplicativo com o nome "ai". Este exemplo provisiona um recurso de IA Azure.

Passar parâmetros para modelos Bicep

Bicep dá suporte à aceitação de parâmetros, que podem ser usados para personalizar o comportamento do modelo. Para passar parâmetros de .NET.NET Aspirepara um modelo Bicep, encadeie as chamadas ao método WithParameter, conforme mostrado no exemplo a seguir:

var region = builder.AddParameter("region");

builder.AddBicepTemplate("storage", "../infra/storage.bicep")
       .WithParameter("region", region)
       .WithParameter("storageName", "app-storage")
       .WithParameter("tags", ["latest","dev"]);

O código anterior:

  • Adiciona um parâmetro chamado "region" à instância de builder.
  • Adiciona uma referência a um arquivo Bicep localizado em ../infra/storage.bicep.
  • Passa o parâmetro "region" para o modelo Bicep, que é resolvido com a resolução padrão de parâmetros.
  • Passa o parâmetro "storageName" para o modelo Bicep com um valor hardcoded.
  • Passa o parâmetro "tags" para o modelo Bicep com uma matriz de cadeias de caracteres.

Para obter mais informações, consulte Parâmetros externos.

Parâmetros conhecidos

.NET .NET Aspire fornece um conjunto de parâmetros conhecidos que podem ser passados para modelos Bicep. Esses parâmetros são usados para fornecer informações sobre o aplicativo e o ambiente para os modelos Bicep. Os seguintes parâmetros conhecidos estão disponíveis:

Campo Descrição Valor
AzureBicepResource.KnownParameters.KeyVaultName O nome do recurso do cofre de chaves usado para armazenar informações secretas. "keyVaultName"
AzureBicepResource.KnownParameters.Location O local do recurso. Isso é necessário para todos os recursos. "location"
AzureBicepResource.KnownParameters.LogAnalyticsWorkspaceId O ID do recurso da área de trabalho do Log Analytics. "logAnalyticsWorkspaceId"
AzureBicepResource.KnownParameters.PrincipalId A ID principal do usuário atual ou da identidade gerenciada. "principalId"
AzureBicepResource.KnownParameters.PrincipalName O nome principal do usuário atual ou da identidade gerenciada. "principalName"
AzureBicepResource.KnownParameters.PrincipalType O tipo principal do usuário atual ou da identidade gerenciada. User ou ServicePrincipal. "principalType"

Para usar um parâmetro conhecido, passe o nome do parâmetro para o método WithParameter, como WithParameter(AzureBicepResource.KnownParameters.KeyVaultName). Você não passa valores para parâmetros conhecidos, pois .NET.NET Aspire os resolve em seu nome.

Considere um exemplo em que você deseja configurar um webhook da Grade de Eventos Azure. Você pode definir o modelo Bicep da seguinte maneira:

param topicName string
param webHookEndpoint string
param principalId string
param principalType string
param location string = resourceGroup().location

// The topic name must be unique because it's represented by a DNS entry. 
// must be between 3-50 characters and contain only values a-z, A-Z, 0-9, and "-".

resource topic 'Microsoft.EventGrid/topics@2023-12-15-preview' = {
  name: toLower(take('${topicName}${uniqueString(resourceGroup().id)}', 50))
  location: location

  resource eventSubscription 'eventSubscriptions' = {
    name: 'customSub'
    properties: {
      destination: {
        endpointType: 'WebHook'
        properties: {
          endpointUrl: webHookEndpoint
        }
      }
    }
  }
}

resource EventGridRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(topic.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd5a91429-5739-47e2-a06b-3470a27159e7'))
  scope: topic
  properties: {
    principalId: principalId
    principalType: principalType
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd5a91429-5739-47e2-a06b-3470a27159e7')
  }
}

output endpoint string = topic.properties.endpoint

Este modelo Bicep define vários parâmetros, incluindo o topicName, webHookEndpoint, principalId, principalTypee o locationopcional. Para passar esses parâmetros para o modelo Bicep, você pode usar o seguinte snippet de código:

var webHookApi = builder.AddProject<Projects.WebHook_Api>("webhook-api");

var webHookEndpointExpression = ReferenceExpression.Create(
        $"{webHookApi.GetEndpoint("https")}/hook");

builder.AddBicepTemplate("event-grid-webhook", "../infra/event-grid-webhook.bicep")
       .WithParameter("topicName", "events")
       .WithParameter(AzureBicepResource.KnownParameters.PrincipalId)
       .WithParameter(AzureBicepResource.KnownParameters.PrincipalType)
       .WithParameter("webHookEndpoint", () => webHookEndpointExpression);
  • O projeto webHookApi é adicionado como uma referência ao builder.
  • O parâmetro topicName recebe um valor de nome fixo.
  • O parâmetro webHookEndpoint é passado como uma expressão que se resolve na URL do endpoint "https" das referências de projeto api usando a rota /hook.
  • Os parâmetros principalId e principalType são passados como parâmetros conhecidos.

Os parâmetros conhecidos são baseados em convenção e não devem ser acompanhados com um valor correspondente quando passados usando a API WithParameter. Parâmetros conhecidos simplificam algumas funcionalidades comuns, como atribuições de função , quando adicionados aos modelos Bicep, conforme mostrado no exemplo anterior. As atribuições de função são necessárias para que o webhook do Event Grid envie eventos para o endpoint especificado. Para obter mais informações, consulte atribuição de função do Remetente de Dados da Grade de Eventos.

Obtenha resultados a partir de referências do Bicep

Além de passar parâmetros para modelos Bicep, você também pode obter resultados dos modelos Bicep. Considere o seguinte modelo Bicep, que define um output chamado endpoint:

param storageName string
param location string = resourceGroup().location

resource myStorageAccount 'Microsoft.Storage/storageAccounts@2019-06-01' = {
  name: storageName
  location: location
  kind: 'StorageV2'
  sku:{
    name:'Standard_LRS'
    tier: 'Standard'
  }
  properties: {
    accessTier: 'Hot'
  }
}

output endpoint string = myStorageAccount.properties.primaryEndpoints.blob

O Bicep define uma saída chamada endpoint. Para obter a saída do modelo Bicep, chame o método GetOutput em uma instância de IResourceBuilder<AzureBicepResource>, conforme demonstrado no seguinte snippet de código C#:

var storage = builder.AddBicepTemplate(
        name: "storage",
        bicepFile: "../infra/storage.bicep"
    );

var endpoint = storage.GetOutput("endpoint");

Neste exemplo, a saída do modelo Bicep é recuperada e armazenada em uma variável de endpoint. Normalmente, você passaria essa saída como uma variável de ambiente para outro recurso que depende dele. Por exemplo, se você tivesse um projeto de Minimal API ASP.NET Core que dependesse desse endpoint, você poderia passar a saída como uma variável de ambiente para o projeto usando o seguinte trecho de código:

var storage = builder.AddBicepTemplate(
                name: "storage",
                bicepFile: "../infra/storage.bicep"
            );

var endpoint = storage.GetOutput("endpoint");

var apiService = builder.AddProject<Projects.AspireSample_ApiService>(
        name: "apiservice"
    )
    .WithEnvironment("STORAGE_ENDPOINT", endpoint);

Para obter mais informações, consulte saídas do Bicep.

Obter resultados secretos de referências do Bicep

É importante evitar saídas para segredos ao trabalhar com Bicep. Se uma saída for considerada um segredo, o que significa que ela não deve ser exposta em logs ou em outros locais, você pode tratá-la como tal. Isso pode ser feito armazenando o segredo em Azure Key Vault e referenciando-o no modelo Bicep. A integração .NET Aspire do Azurefornece um padrão para armazenar com segurança as saídas do modelo Bicep, permitindo que os recursos usem o parâmetro keyVaultName para armazenar segredos em Azure Key Vault.

Considere o seguinte modelo Bicep como um exemplo que ajuda a demonstrar esse conceito de proteger saídas secretas:

param databaseAccountName string
param keyVaultName string

param databases array = []

@description('Tags that will be applied to all resources')
param tags object = {}

param location string = resourceGroup().location

var resourceToken = uniqueString(resourceGroup().id)

resource cosmosDb 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' = {
    name: replace('${databaseAccountName}-${resourceToken}', '-', '')
    location: location
    kind: 'GlobalDocumentDB'
    tags: tags
    properties: {
        consistencyPolicy: { defaultConsistencyLevel: 'Session' }
        locations: [
            {
                locationName: location
                failoverPriority: 0
            }
        ]
        databaseAccountOfferType: 'Standard'
    }

    resource db 'sqlDatabases@2023-04-15' = [for name in databases: {
        name: '${name}'
        location: location
        tags: tags
        properties: {
            resource: {
                id: '${name}'
            }
        }
    }]
}

var primaryMasterKey = cosmosDb.listKeys(cosmosDb.apiVersion).primaryMasterKey

resource vault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
    name: keyVaultName

    resource secret 'secrets@2023-07-01' = {
        name: 'connectionString'
        properties: {
            value: 'AccountEndpoint=${cosmosDb.properties.documentEndpoint};AccountKey=${primaryMasterKey}'
        }
    }
}

O modelo Bicep precedente espera um parâmetro keyVaultName, entre outros parâmetros. Em seguida, ele define um recurso Azure Cosmos DB e armazena um segredo em Azure Key Vault, chamado connectionString, que representa a string de conexão completamente qualificada para a instância Cosmos DB. Para acessar esse valor de cadeia de conexão secreta, você pode usar o seguinte snippet de código:

var cosmos = builder.AddBicepTemplate("cosmos", "../infra/cosmosdb.bicep")
    .WithParameter("databaseAccountName", "fallout-db")
    .WithParameter(AzureBicepResource.KnownParameters.KeyVaultName)
    .WithParameter("databases", ["vault-33", "vault-111"]);

var connectionString =
    cosmos.GetSecretOutput("connectionString");

builder.AddProject<Projects.WebHook_Api>("api")
    .WithEnvironment(
        "ConnectionStrings__cosmos",
        connectionString);

No trecho de código anterior, o modelo Bicep cosmos é adicionado como referência ao builder. A saída secreta connectionString é recuperada do template Bicep e armazenada em uma variável. Em seguida, a saída secreta é passada como uma variável de ambiente (ConnectionStrings__cosmos) para o projeto de api. Essa variável de ambiente é usada para se conectar à instância de Cosmos DB.

Quando esse recurso for implantado, o mecanismo de implantação subjacente referenciará automaticamente os segredos de Azure Key Vault. Para garantir o isolamento secreto, .NET.NET Aspire cria um Key Vault por fonte.

Nota

Em modo de provisionamento local, o segredo é extraído do Key Vault e definido em uma variável de ambiente. Para obter mais informações, consulte provisionamento local Azure.

Publicação

Quando você publica seu aplicativo, o Bicep gerado pelo provisionamento de Azure é usado pelo Azure Developer CLI para criar os recursos Azure em sua assinatura Azure. .NET .NET Aspire gera um manifesto de publicação , que também é uma parte vital do processo de publicação. O Azure Developer CLI é uma ferramenta de linha de comando que fornece um conjunto de comandos para gerenciar Azure recursos.

Para obter mais informações sobre publicação e implantação, consulte Implantar um projeto .NET Aspire no Azure Container Apps usando o Azure Developer CLI (guia detalhado).