Condividi tramite


Panoramica delle integrazioni di .NET AspireAzure

Azure è la piattaforma cloud più diffusa per la creazione e la distribuzione di applicazioni .NET. L'SDK di Azure per .NET consente di gestire e usare facilmente i servizi di Azure. .NET Aspire fornisce un set di integrazioni con i servizi di Azure, in cui è possibile aggiungere nuove risorse o connettersi a quelle esistenti. Questo articolo illustra in dettaglio alcuni aspetti comuni di tutte le integrazioni di Azure in .NET Aspire e mira a comprendere come usarle.

Aggiungere risorse Azure

Tutte le integrazioni di hosting .NET AspireAzure espongono le risorse Azure e, per convenzione, vengono aggiunte utilizzando le API AddAzure*. Quando si aggiungono queste risorse all'host dell'app .NET Aspire, esse rappresentano un servizio Azure. L'API AddAzure* restituisce un IResourceBuilder<T> in cui T è il tipo di risorsa Azure. Queste interfacce IResourceBuilder<T> (generatore) forniscono un'API fluente che consente di configurare la risorsa sottostante Azure all'interno del modello di app . Sono disponibili API per aggiungere nuove risorse Azure, contrassegnare le risorse come esistenti e configurare il comportamento delle risorse in vari contesti di esecuzione.

Esperienza di sviluppo tipica

Quando l'host dell'app contiene risorse ed esso viene eseguito in locale (con il tipico comando F5 dello sviluppatore o un'esperienza ), il provisioning delle risorse viene effettuato nella tua sottoscrizione . Questo permette a te, in qualità di sviluppatore, di eseguire il debug in locale nel contesto dell'host della tua app.

.NET .NET Aspire mira a ridurre al minimo i costi impostando di default su Base o StandardUnità di Gestione delle Scorte (SKU) per le integrazioni Azure. Mentre vengono fornite impostazioni predefinite convenienti, è possibile personalizzare le risorse Azure per soddisfare le proprie esigenze. Inoltre, alcune integrazioni supportano emulatori o contenitoriutili per lo sviluppo, il test e il debug locali. Per impostazione predefinita, quando si esegue l'app in locale, le risorse Azure usano il servizio di Azure effettivo. Tuttavia, è possibile configurarli per l'uso di emulatori o contenitori locali, evitando i costi associati al servizio Azure effettivo durante lo sviluppo locale.

Emulatori locali

Alcuni servizi Azure possono essere emulati per l'esecuzione in locale. Attualmente, .NET Aspire supporta gli emulatori di Azure seguenti:

Integrazione hosting Descrizione
Azure Cosmos DB Chiamare AzureCosmosExtensions.RunAsEmulator sul IResourceBuilder<AzureCosmosDBResource> per configurare la risorsa Cosmos DB da essere emulata con API NoSQL.
Azure Event Hubs Chiamare AzureEventHubsExtensions.RunAsEmulator su IResourceBuilder<AzureEventHubsResource> per configurare la risorsa Event Hubs affinché sia emulata.
Azure Service Bus Chiamare AzureServiceBusExtensions.RunAsEmulator su IResourceBuilder<AzureServiceBusResource> per configurare la risorsa di Service Bus affinché venga emulata con l'emulatore di Service Bus.
Azure SignalR Service Chiamare AzureSignalRExtensions.RunAsEmulator sul IResourceBuilder<AzureSignalRResource> per configurare la risorsa SignalR affinché sia emulata come usando l'emulatore AzureSignalR.
Azure Archiviazione Chiamare AzureStorageExtensions.RunAsEmulator sul IResourceBuilder<AzureStorageResource> per configurare la risorsa di Archiviazione in modo che sia emulata con Azurite.

Per fare in modo che le risorse Azure usino gli emulatori locali, concatenare una chiamata al metodo RunAsEmulator nel generatore di risorse Azure. Questo metodo configura la risorsa Azure per l'uso dell'emulatore locale anziché del servizio Azure effettivo.

Importante

La chiamata a una delle API di RunAsEmulator disponibili in un generatore di risorse Azure non influisce sul manifesto di pubblicazione . Quando si pubblica l'app, il file Bicep generato riflette il Azure servizio effettivo, non l'emulatore locale.

Contenitori locali

Alcune risorse Azure possono essere sostituite localmente usando contenitori open source o in sede. Per sostituire una risorsa Azure in locale in un contenitore, concatenare una chiamata al metodo RunAsContainer nel generatore di risorse Azure. Questo metodo configura la risorsa Azure per l'uso di una versione in contenitori del servizio per lo sviluppo e il test locali, anziché per il servizio Azure effettivo.

Attualmente, .NET Aspire supporta i servizi di Azure seguenti come contenitori:

Integrazione hosting Dettagli
Azure Cache for Redis Chiamare AzureRedisExtensions.RunAsContainer sul IResourceBuilder<AzureRedisCacheResource> per configurarlo per l'esecuzione in locale in un contenitore, in base all'immagine docker.io/library/redis.
Azure PostgreSQL Flessibile Server Chiamare AzurePostgresExtensions.RunAsContainer sul IResourceBuilder<AzurePostgresFlexibleServerResource> per configurarlo per l'esecuzione in locale in un contenitore, in base all'immagine docker.io/library/postgres.
Azure SQL Server Chiamare AzureSqlExtensions.RunAsContainer sul IResourceBuilder<AzureSqlServerResource> per configurarlo per l'esecuzione in locale in un contenitore, in base all'immagine mcr.microsoft.com/mssql/server.

Nota

Analogamente agli emulatori, la chiamata di RunAsContainer su un generatore di risorse Azure non influisce sul manifesto di pubblicazione . Quando si pubblica l'app, il file Bicep generato riflette il servizio Azure effettivo, non il contenitore locale.

Informazioni sulle API di integrazione di Azure

Risiede nella forza di .NET.NET Aspirela capacità di fornire un incredibile ciclo di sviluppo interno. Le integrazioni di Azure non sono affatto diverse. Forniscono un set di API e modelli comuni condivisi tra tutte le risorse Azure. Queste API e modelli sono progettati per semplificare l'uso delle risorse Azure in modo coerente.

Nella sezione precedente sui contenitori, abbiamo visto come eseguire localmente i servizi Azure nei contenitori. Se sei familiare con .NET.NET Aspire, ti potresti chiedere in che modo chiamare AddAzureRedis("redis").RunAsContainer() per ottenere un container locale docker.io/library/redis sia diverso da AddRedis("redis"), poiché entrambi portano allo stesso container locale.

La risposta è che non esiste alcuna differenza durante l'esecuzione in locale. Tuttavia, quando vengono pubblicati si ottengono risorse diverse:

API Modalità di esecuzione Modalità di pubblicazione
AddAzureRedis("redis").RunAsContainer() Contenitore Redis locale Azure Cache for Redis
AddRedis("redis") Contenitore Redis locale Azure applicazione contenitore con immagine Redis

Lo stesso vale per i servizi SQL e PostgreSQL:

API Modalità di esecuzione Modalità di pubblicazione
AddAzurePostgresFlexibleServer("postgres") RunAsContainer() Contenitore PostgreSQL locale Azure PostgreSQL Flessibile Server
AddPostgres("postgres") Contenitore PostgreSQL locale Azure l'app container con immagine PostgreSQL
AddAzureSqlServer("sql"). RunAsContainer() Contenitore SQL Server locale Azure SQL Server
AddSqlServer("sql") Contenitore SQL Server locale Azure Applicazione contenitore con immagine SQL Server

Per ulteriori informazioni sulla differenza tra le modalità di esecuzione e pubblicazione, consulta .NET.NET Aspire host dell'app: Contesto di esecuzione.

API per l'espressione di risorse Azure in modalità diverse

Il generatore di applicazioni distribuite, parte dell'host dell'app , usa il modello di generatore per AddAzure* risorse nel modello di app . Gli sviluppatori possono configurare queste risorse e definirne il comportamento in contesti di esecuzione diversi. Azure le integrazioni di hosting forniscono API per specificare il modo in cui queste risorse devono essere "pubblicate" e "eseguite".

Quando viene eseguito, l'host dell'app utilizza il contesto di esecuzione per determinare se si trova in modalità Run o Publish. Le convenzioni di denominazione per queste API indicano l'azione prevista per la risorsa.

La tabella seguente riepiloga le convenzioni di denominazione usate per esprimere Azure risorse:

Operazione API Descrizione
Pubblicare PublishAsConnectionString<T>(IResourceBuilder<T>) Modifica la risorsa da pubblicare come riferimento alla stringa di connessione nel file manifesto.
Pubblicare PublishAsExisting Usa una risorsa Azure esistente quando l'applicazione viene distribuita anziché crearne una nuova.
Correre AzureSqlExtensions.RunAsContainer(IResourceBuilder<AzureSqlServerResource>, Action<IResourceBuilder<SqlServerServerResource>>)
AzureRedisExtensions.RunAsContainer(IResourceBuilder<AzureRedisCacheResource>, Action<IResourceBuilder<RedisResource>>)
RunAsContainer(IResourceBuilder<AzurePostgresFlexibleServerResource>, Action<IResourceBuilder<PostgresServerResource>>)
Configura un contenitore equivalente per l'esecuzione in locale. Per altre informazioni, vedere Contenitori locali.
Correre 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 la risorsa Azure da emulare. Per ulteriori informazioni, vedere emulatori locali.
Correre RunAsExisting Usa una risorsa esistente quando l'applicazione è in esecuzione anziché crearne una nuova.
Pubblica ed Esegui AsExisting<T>(IResourceBuilder<T>, IResourceBuilder<ParameterResource>, IResourceBuilder<ParameterResource>) Usa una risorsa esistente indipendentemente dall'operazione.

Nota

Non tutte le API sono disponibili in tutte le risorse Azure. Ad esempio, alcune risorse Azure possono essere incluse in contenitori o emulate, mentre altre non possono.

Per altre informazioni sulle modalità di esecuzione, vedere Contesto di esecuzione.

Casi d'uso generali dell'API per la modalità di esecuzione

Usare RunAsExisting quando è necessario interagire dinamicamente con una risorsa esistente durante il runtime senza dover distribuirla o aggiornarla. Usare PublishAsExisting quando si dichiarano le risorse esistenti come parte di una configurazione di distribuzione, assicurandosi che vengano applicati gli ambiti e le autorizzazioni corretti. Usare infine AsExisting<T>(IResourceBuilder<T>, IResourceBuilder<ParameterResource>, IResourceBuilder<ParameterResource>) per dichiarare le risorse esistenti in entrambe le configurazioni, con un requisito per parametrizzare i riferimenti.

È possibile eseguire una query per stabilire se una risorsa è contrassegnata come risorsa esistente chiamando il metodo di estensione IsExisting(IResource) nel IResource. Per altre informazioni, vedere Usare risorse di Azure esistenti.

Usare le risorse di Azure esistenti

.NET Aspire fornisce supporto per fare riferimento alle risorse di Azure esistenti. È possibile contrassegnare una risorsa esistente tramite le API PublishAsExisting, RunAsExistinge AsExisting. Queste API consentono agli sviluppatori di fare riferimento a risorse Azure già distribuite, configurarle e generare manifesti di distribuzione appropriati usando i modelli Bicep.

Le risorse esistenti a cui si fa riferimento con queste API possono essere migliorate con le assegnazioni di ruolo e altre personalizzazioni disponibili con l'infrastruttura di .NET.NET Aspirecome funzionalità di codice. Queste API sono limitate alle risorse Azure che possono essere distribuite con i modelli Bicep.

Configurare le risorse di Azure esistenti per la modalità di esecuzione

Il metodo RunAsExisting viene usato quando un'applicazione distribuita viene eseguita in modalità "esecuzione". In questa modalità si presuppone che la risorsa di Azure a cui si fa riferimento esista già e si integra con essa durante l'esecuzione senza effettuare il provisioning della risorsa. Per contrassegnare una risorsa Azure come esistente, chiamare il metodo RunAsExisting nel generatore di risorse. Si consideri l'esempio seguente:

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");

Il codice precedente:

  • Crea una nuova istanza di builder.
  • Aggiunge un parametro denominato existingServiceBusName al generatore.
  • Aggiunge al generatore una risorsa Azure Service Bus denominata messaging.
  • Chiama il metodo RunAsExisting nel generatore di risorse serviceBus, passando il parametro existingServiceBusName, in alternativa, è possibile usare l'overload del parametro string.
  • Aggiunge una coda denominata queue alla risorsa serviceBus.

Per impostazione predefinita, si presuppone che il riferimento al parametro del bus di servizio si trova nello stesso gruppo di risorse Azure. Tuttavia, se si trova in un gruppo di risorse diverso, è possibile passare il gruppo di risorse in modo esplicito come parametro per specificare correttamente il raggruppamento di risorse appropriato.

Configurare le risorse di Azure esistenti per la modalità di pubblicazione

Il metodo PublishAsExisting viene usato in modalità "publish" quando la finalità è dichiarare e fare riferimento a una risorsa Azure già esistente durante la modalità di pubblicazione. Questa API facilita la creazione di manifesti e modelli che includono definizioni di risorse mappate alle risorse esistenti in Bicep.

Per contrassegnare una risorsa Azure come esistente in per la modalità di pubblicazione, chiamare il metodo PublishAsExisting nel generatore di risorse. Si consideri l'esempio seguente:

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");

Il codice precedente:

  • Crea una nuova istanza di builder.
  • Aggiunge un parametro denominato existingServiceBusName al generatore.
  • Aggiunge al generatore una risorsa Azure Service Bus denominata messaging.
  • Chiama il metodo PublishAsExisting nel generatore di risorse serviceBus, passando il parametro existingServiceBusName, in alternativa, è possibile usare l'overload del parametro string.
  • Aggiunge una coda denominata queue alla risorsa serviceBus.

Dopo l'esecuzione dell'host dell'app in modalità di pubblicazione, il file manifesto generato includerà il parametro existingResourceName, che può essere usato per fare riferimento alla risorsa Azure esistente. Si consideri il frammento parziale generato seguente del file 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}"
}

Per altre informazioni sul file manifesto, vedere .NET.NET Aspire formato manifesto per i generatori di strumenti di distribuzione.

Inoltre, il modello Bicep generato include il parametro existingResourceName, che può essere usato per fare riferimento alla risorsa Azure esistente. Si consideri il modello Bicep generato seguente:

@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

Per ulteriori informazioni sui modelli Bicep generati, consultare Infrastruttura come codice e considerare altre API di pubblicazione.

Avvertimento

Quando si interagisce con le risorse esistenti che richiedono l'autenticazione, assicurarsi che la strategia di autenticazione da configurare nel modello di applicazione .NET.NET Aspire sia allineata alla strategia di autenticazione consentita dalla risorsa esistente. Ad esempio, non è possibile usare l'identità gestita rispetto a una risorsa di AzurePostgreSQL esistente non configurata per consentire l'identità gestita. Analogamente, se una risorsa AzureRedis esistente ha disabilitato le chiavi di accesso, non è possibile usare l'autenticazione della chiave di accesso.

Configurare le risorse Azure esistenti in tutte le modalità

Il metodo AsExisting<T>(IResourceBuilder<T>, IResourceBuilder<ParameterResource>, IResourceBuilder<ParameterResource>) viene usato quando l'applicazione distribuita è in esecuzione in modalità "run" o "publish". Poiché il metodo AsExisting opera in entrambi gli scenari, supporta solo un riferimento con parametri al nome della risorsa o al nome del gruppo di risorse. Questo approccio consente di evitare l'uso della stessa risorsa sia negli ambienti di test che in ambienti di produzione.

Per contrassegnare una risorsa Azure come esistente, chiamare il metodo AsExisting nel generatore di risorse. Si consideri l'esempio seguente:

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");

Il codice precedente:

  • Crea una nuova istanza di builder.
  • Aggiunge un parametro denominato existingServiceBusName al generatore.
  • Aggiunge al generatore una risorsa Azure Service Bus denominata messaging.
  • Chiama il metodo AsExisting nel generatore di risorse serviceBus passando il parametro existingServiceBusName.
  • Aggiunge una coda denominata queue alla risorsa serviceBus.

Aggiungere risorse esistenti di Azure con stringhe di connessione

.NET .NET Aspire consente di connettersi alle risorse esistenti, incluse le risorse Azure. L'espressione delle stringhe di connessione è utile quando sono presenti risorse Azure da usare nell'app .NET Aspire. L'API AddConnectionString viene usata con il contesto di esecuzione dell'host dell'app per aggiungere in modo condizionale una stringa di connessione al modello di app.

Nota

Le stringhe di connessione vengono usate per rappresentare un'ampia gamma di informazioni di connessione, tra cui connessioni di database, broker messaggi, URI endpoint e altri servizi. Nella .NET.NET Aspire denominazione, il termine "stringa di connessione" viene usato per rappresentare qualsiasi tipo di informazioni di connessione.

Si consideri l'esempio seguente, nella modalità di pubblicazione si aggiunge una risorsa di archiviazione Azure mentre nella modalità di esecuzione si aggiunge una stringa di connessione a una risorsa di archiviazione Azure esistente.

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...

Il codice precedente:

  • Crea una nuova istanza di builder.
  • Aggiunge una risorsa di archiviazione Azure denominata storage in modalità "pubblicazione".
  • Aggiunge una stringa di connessione a una risorsa di archiviazione Azure esistente denominata storage in modalità "run".
  • Aggiunge un progetto nominato api al costruttore.
  • Il progetto api fa riferimento alla risorsa storage indipendentemente dalla modalità .

Il progetto API di utilizzo usa le informazioni sulla stringa di connessione senza alcuna conoscenza del modo in cui l'host dell'app lo ha configurato. In modalità "pubblicazione" il codice aggiunge una nuova risorsa di archiviazione Azure, che si rifletterà nel manifesto della distribuzione di conseguenza. Quando in modalità "run" la stringa di connessione corrisponde a un valore di configurazione visibile all'host dell'app. Si presuppone che tutte le assegnazioni di ruolo per la risorsa di destinazione siano configurate. Ciò significa che è probabile che si configuri una variabile di ambiente o un segreto utente per archiviare la stringa di connessione. La configurazione viene risolta dalla chiave di configurazione ConnectionStrings__storage (o ConnectionStrings:storage). Questi valori di configurazione possono essere visualizzati durante l'esecuzione dell'app. Per altre informazioni, vedere Dettagli risorsa.

A differenza delle risorse esistenti modellate con l'API AsExisting di prima classe, le risorse esistenti modellate come stringhe di connessione non possono essere migliorate con assegnazioni di ruolo aggiuntive o personalizzazioni dell'infrastruttura.

Pubblica come Contenitore App Azure

.NET .NET Aspire consente di pubblicare risorse primitive come Azure Container Apps, una piattaforma serverless che riduce la gestione dell'infrastruttura. I tipi di risorsa supportati includono:

Per pubblicare queste risorse, usare le API seguenti:

Queste API configurano la risorsa per essere pubblicata come Container App Azure e chiamano implicitamente AddAzureContainerAppsInfrastructure(IDistributedApplicationBuilder) per aggiungere l'infrastruttura necessaria e i file Bicep al server host della tua applicazione. Si consideri ad esempio il codice seguente:

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)
                     });
                 });

Il codice precedente:

  • Crea una nuova istanza di builder.
  • Aggiunge un parametro denominato env al generatore.
  • Aggiunge un progetto nominato api al costruttore.
  • Chiama il metodo PublishAsAzureContainerApp nel generatore di risorse api, passando un'espressione lambda che configura l'infrastruttura dell'app contenitore Azure, dove infra è il AzureResourceInfrastructure e app è il ContainerApp.
    • Aggiunge una variabile di ambiente denominata Hello all'app contenitore usando il parametro env.
    • Il metodo AsProvisioningParameter viene usato per trattare env come un nuovo ProvisioningParameter nell'infrastruttura o riutilizzare un parametro bicep esistente se ne esiste già uno con lo stesso nome.

Per altre informazioni, vedere ContainerApp e AsProvisioningParameter.

Infrastruttura come codice

Lo SDK di Azure per .NET fornisce il pacchetto NuGet 📦Azure.Provisioning e una suite di pacchetti di provisioning specifici del servizio di Azure. Queste librerie di provisioning Azure semplificano la definizione dichiarativa dell'infrastruttura Azure in modo nativo in .NET. Le loro API consentono di scrivere un'infrastruttura orientata agli oggetti in C#, che si traduce in Bicep. Bicep è un DSL (Domain-Specific Language) per distribuire in modo dichiarativo le risorse Azure.

Sebbene sia possibile effettuare manualmente il provisioning delle risorse Azure, .NET Aspire semplifica il processo fornendo un set di API per esprimere le risorse Azure. Queste API sono disponibili come metodi di estensione nelle librerie di hosting .NET AspireAzure, estendendo l'interfaccia IDistributedApplicationBuilder. Quando si aggiungono le risorse Azure all'host della tua app, viene aggiunta implicitamente la funzionalità di provisioning appropriata. In altre parole, non è necessario chiamare direttamente le API di provisioning.

Poiché .NET Aspire modelli Azure risorse all'interno delle integrazioni di hosting Azure, l'SDK di Azure viene utilizzato per approvvigionare queste risorse. Vengono generati file Bicep che definiscono le risorse Azure necessarie. I file Bicep generati vengono restituiti insieme al file manifesto quando si pubblica l'app.

Esistono diversi modi per influenzare i file Bicep generati:

Configurazione locale e Azure.Provisioning

Per evitare di confondere i termini e per chiarire il significato di "provisioning", è importante comprendere la distinzione tra il provisioning locale e il Azure provisioning.

  • configurazione locale:

    Per impostazione predefinita, quando si chiama una delle API di integrazione dell'hosting Azure per aggiungere risorse Azure, l'API AddAzureProvisioning(IDistributedApplicationBuilder) viene chiamata in modo implicito. Questa API registra i servizi nel contenitore di inserimento delle dipendenze (DI) usato per fornire risorse Azure all'avvio dell'host dell'applicazione. Questo concetto è noto come approvvigionamento locale. Per ulteriori informazioni, vedere configurazione Azure locale.

  • Azure.Provisioning:

    Azure.Provisioning fa riferimento al pacchetto NuGet ed è un set di librerie che consente di usare C# per generare Bicep. Le integrazioni di hosting Azure in .NET Aspire utilizzano queste librerie in background per generare i file Bicep che definiscono le risorse Azure necessarie. Per maggiori informazioni, vedere la personalizzazione Azure.Provisioning.

personalizzazione Azure.Provisioning

Tutte le integrazioni di hosting .NET AspireAzure espongono varie risorse Azure e sono tutte sottoclassi del tipo AzureProvisioningResource, che a sua volta eredita l'AzureBicepResource. Ciò abilita le estensioni vincolate genericamente a questo tipo, consentendo a un'API fluente di personalizzare l'infrastruttura secondo le tue preferenze. Anche se .NET.NET Aspire fornisce impostazioni predefinite, è possibile influenzare il Bicep generato usando queste API.

Configurare l'infrastruttura

Indipendentemente dalla risorsa Azure con cui si sta lavorando, per configurare l'infrastruttura sottostante, si concatena una chiamata al metodo di estensione ConfigureInfrastructure. Questo metodo consente di personalizzare l'infrastruttura della risorsa Azure passando un delegato configure di tipo Action<AzureResourceInfrastructure>. Il tipo AzureResourceInfrastructure è una sottoclasse del Azure.Provisioning.Infrastructure. Questo tipo espone un'ampia superficie API per configurare l'infrastruttura sottostante della risorsa Azure.

Si consideri l'esempio seguente:

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)
        };
    });

Il codice precedente:

  • Aggiunge un parametro denominato storage-sku.
  • Aggiunge l'archiviazione Azure con l'API AddAzureStorage denominata storage.
  • Concatena una chiamata a ConfigureInfrastructure per personalizzare l'infrastruttura di archiviazione Azure:

In questo modo viene illustrato il flusso di un parametro esterno nell'infrastruttura di archiviazione Azure, con conseguente visualizzazione della configurazione desiderata nel file Bicep generato.

Aggiungi Azure infrastruttura

Non tutti i servizi Azure vengono esposti come integrazioni di .NET Aspire. Anche se potrebbero essere disponibili in un secondo momento, è comunque possibile fornire i servizi disponibili nelle librerie di Azure.Provisioning.*. Si supponga di avere un servizio di lavoro responsabile della gestione di un registro contenitori Azure. Si supponga ora che un progetto host dell'app sia dipendente dal pacchetto NuGet 📦Azure.Provisioning.ContainerRegistry.

È possibile usare l'API AddAzureInfrastructure per aggiungere l'infrastruttura del Registro dei container Azure all'host dell'app:

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));

Il codice precedente:

  • Chiama AddAzureInfrastructure con il nome di acr.
  • Fornisce un delegato configureInfrastructure per personalizzare l'infrastruttura del Registro dei Container Azure:
    • Instanzia un ContainerRegistryService con il nome acr e uno SKU standard.
    • Aggiunge il servizio Registro Container Azure alla variabile infra.
    • Istanzia un ProvisioningOutput con il nome registryName, un tipo di stringe un valore che corrisponde al nome del registro di contenitori Azure.
    • Aggiunge l'output alla variabile infra.
  • Aggiunge un progetto nominato worker al costruttore.
  • Concatena una chiamata a WithEnvironment per impostare la variabile di ambiente ACR_REGISTRY_NAME nel progetto sul valore dell'output registryName.

La funzionalità illustra come aggiungere l'infrastruttura Azure al progetto host dell'app, anche se il servizio Azure non è esposto direttamente come integrazione .NET Aspire. Illustra inoltre come indirizzare l'output del Container Registry Azure nell'ambiente di un progetto dipendente.

Si consideri il file Bicep risultante:

@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

Il file Bicep riflette la configurazione desiderata del registro contenitori Azure, come definito dall'API AddAzureInfrastructure.

Usare modelli Bicep personalizzati

Quando si ha come destinazione Azure come provider di servizi cloud desiderati, è possibile usare Bicep per definire l'infrastruttura come codice. Mira a semplificare drasticamente l'esperienza di creazione con una sintassi più pulita e un migliore supporto per la modularità e il riutilizzo del codice.

Anche se .NET.NET Aspire fornisce un set di modelli Bicep predefiniti, potrebbero verificarsi momenti in cui si vogliono personalizzare i modelli o crearne uno personalizzato. Questa sezione illustra i concetti e le API corrispondenti che è possibile usare per personalizzare i modelli Bicep.

Importante

Questa sezione non è progettata per insegnarti Bicep, ma piuttosto per fornire indicazioni su come creare modelli personalizzati in Bicep da usare con .NET.NET Aspire.

Nella storia di distribuzione Azure per .NET Aspire, il Azure Developer CLI (azd) fornisce una comprensione del tuo progetto .NET Aspire e la possibilità di distribuirlo in Azure. La CLI di azd utilizza i modelli Bicep per distribuire l'applicazione su Azure.

Installare il pacchetto Aspire.Hosting.Azure

Quando si vuole fare riferimento ai file Bicep, è possibile che non si usi alcuna delle integrazioni di hosting Azure. In questo caso, è comunque possibile fare riferimento ai file Bicep installando il pacchetto Aspire.Hosting.Azure. Questo pacchetto fornisce le API necessarie per fare riferimento ai file Bicep e personalizzare le risorse Azure.

Suggerimento

Se si usa una delle integrazioni di hosting Azure, non è necessario installare il pacchetto Aspire.Hosting.Azure, perché si tratta di una dipendenza transitiva.

Per utilizzare una qualsiasi di queste funzionalità, il pacchetto NuGet 📦Aspire.Hosting.Azure deve essere installato.

dotnet add package Aspire.Hosting.Azure

Per ulteriori informazioni, vedere dotnet add package o Gestire le dipendenze dei pacchetti nelle applicazioni .NET.

Cosa aspettarsi dagli esempi

Tutti gli esempi di questa sezione presuppongono che si usi lo spazio dei nomi Aspire.Hosting.Azure. Gli esempi presuppongono inoltre di avere un'istanza IDistributedApplicationBuilder:

using Aspire.Hosting.Azure;

var builder = DistributedApplication.CreateBuilder(args);

// Examples go here...

builder.Build().Run();

Per impostazione predefinita, quando si chiama una delle API correlate a Bicep, viene effettuata anche una chiamata a AddAzureProvisioning che aggiunge il supporto per la generazione di risorse Azure in modo dinamico durante l'avvio dell'applicazione. Per altre informazioni, vedere approvvigionamento locale e Azure.Provisioning.

Fare riferimento ai file Bicep

Immagina di avere un modello Bicep in un file chiamato storage.bicep che configura un account di archiviazione 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'
  }
}

Per aggiungere un riferimento al file Bicep su disco, chiamare il metodo AddBicepTemplate. Si consideri l'esempio seguente:

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

Il codice precedente aggiunge un riferimento a un file Bicep che si trova in ../infra/storage.bicep. I percorsi dei file devono essere relativi al progetto dell'app host. Questo riferimento comporta l'aggiunta di un AzureBicepResource alla raccolta di risorse dell'applicazione con il nome "storage" e l'API restituisce un'istanza IResourceBuilder<AzureBicepResource> che può essere usata per personalizzare ulteriormente la risorsa.

Riferimento Bicep inline

Anche se la presenza di un file Bicep su disco è lo scenario più comune, è anche possibile aggiungere modelli Bicep inline. I modelli inline possono essere utili quando si vuole definire un modello nel codice o quando si vuole generare il modello in modo dinamico. Per aggiungere un modello Bicep inline, chiamare il metodo AddBicepTemplateString con il modello Bicep come string. Si consideri l'esempio seguente:

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
            }
          }
        }
        """
    );

In questo esempio, il modello Bicep viene definito come inline string e aggiunto alla raccolta di risorse dell'applicazione con il nome "ai". Questo esempio fornisce una risorsa di intelligenza artificiale Azure.

Passa i parametri ai modelli Bicep

Bicep supporta l'accettazione di parametri, che può essere usato per personalizzare il comportamento del modello. Per passare parametri a un modello Bicep da .NET.NET Aspire, concatenare le chiamate al metodo WithParameter come illustrato nell'esempio seguente:

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

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

Il codice precedente:

  • Aggiunge un parametro denominato "region" all'istanza di builder.
  • Aggiunge un riferimento a un file Bicep che si trova in ../infra/storage.bicep.
  • Si passa il parametro "region" al modello Bicep, che viene risolto utilizzando la risoluzione standard dei parametri.
  • Passa il parametro "storageName" al modello Bicep con un valore hardcoded.
  • Passa il parametro "tags" al modello Bicep con una matrice di stringhe.

Per altre informazioni, vedere Parametri esterni.

Parametri noti

.NET .NET Aspire fornisce un set di parametri noti che possono essere passati ai modelli Bicep. Questi parametri vengono usati per fornire informazioni sull'applicazione e sull'ambiente ai modelli Bicep. Sono disponibili i parametri noti seguenti:

Campo Descrizione Valore
AzureBicepResource.KnownParameters.KeyVaultName Nome della risorsa del vault delle chiavi utilizzata per archiviare gli output segreti. "keyVaultName"
AzureBicepResource.KnownParameters.Location Posizione della risorsa. Questa operazione è necessaria per tutte le risorse. "location"
AzureBicepResource.KnownParameters.LogAnalyticsWorkspaceId ID della risorsa dell'area di lavoro di Log Analytics. "logAnalyticsWorkspaceId"
AzureBicepResource.KnownParameters.PrincipalId ID principale dell'utente corrente o dell'identità gestita. "principalId"
AzureBicepResource.KnownParameters.PrincipalName Nome principale dell'utente corrente o dell'identità gestita. "principalName"
AzureBicepResource.KnownParameters.PrincipalType La tipologia principale dell'utente corrente o dell'identità gestita. User o ServicePrincipal. "principalType"

Per usare un parametro noto, passare il nome del parametro al metodo WithParameter, ad esempio WithParameter(AzureBicepResource.KnownParameters.KeyVaultName). Non si passano valori per parametri noti, perché .NET.NET Aspire li risolve per conto dell'utente.

Consideriamo un esempio in cui si vuole configurare un webhook di Event Grid Azure. È possibile definire il modello Bicep come segue:

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

Questo modello Bicep definisce diversi parametri, tra cui il topicName, webHookEndpoint, principalId, principalTypee il locationfacoltativo . Per passare questi parametri al modello Bicep, è possibile usare il frammento di codice seguente:

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);
  • Il progetto webHookApi viene aggiunto come riferimento al builder.
  • Al parametro topicName viene assegnato un valore nome predefinito.
  • Il parametro webHookEndpoint viene passato come espressione che si risolve nell'URL dall'endpoint "https" dei riferimenti del progetto api con il percorso /hook.
  • I parametri principalId e principalType vengono passati come parametri noti.

I parametri noti sono basati su convenzioni e non devono essere accompagnati da un valore corrispondente quando vengono passati usando l'API WithParameter. I parametri noti semplificano alcune funzionalità comuni, ad esempio assegnazioni di ruolo, quando vengono aggiunti ai modelli Bicep, come illustrato nell'esempio precedente. Le assegnazioni di ruolo sono necessarie affinché il webhook della griglia di eventi possa inviare eventi all'endpoint specificato. Per ulteriori informazioni, vedere Mittente dati di Griglia di eventi - assegnazione di ruolo.

Ottenere gli output dai riferimenti Bicep

Oltre a passare parametri ai modelli Bicep, è anche possibile ricavare gli output dai modelli Bicep. Si consideri il seguente modello Bicep, che definisce un output denominato 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

Bicep definisce un output denominato endpoint. Per ottenere l'output dal modello Bicep, chiamare il metodo GetOutput in un'istanza di IResourceBuilder<AzureBicepResource>, come illustrato nel frammento di codice C# seguente:

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

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

In questo esempio l'output del modello Bicep viene recuperato e archiviato in una variabile endpoint. In genere, questo output viene passato come variabile di ambiente a un'altra risorsa che si basa su di essa. Ad esempio, se si dispone di un progetto API minimo ASP.NET Core che dipende da questo endpoint, è possibile passare l'output come variabile di ambiente al progetto usando il frammento di codice seguente:

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);

Per ulteriori informazioni, vedere risultati di Bicep.

Ottenere output segreti dai riferimenti Bicep

È importante evitare gli output per i segreti quando si lavora con Bicep. Se un output è considerato un segreto , ovvero non deve essere esposto nei log o in altre posizioni, è possibile considerarlo come tale. A tale scopo, è possibile archiviare il segreto in Azure Key Vault e farvi riferimento nel modello Bicep. L'integrazione .NET Aspire di Azurefornisce un modello per archiviare in modo sicuro gli output dal modello Bicep consentendo alle risorse di usare il parametro keyVaultName per archiviare i segreti in Azure Key Vault.

Considerare il seguente modello Bicep come esempio per aiutare a dimostrare questo concetto di protezione degli output segreti.

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}'
        }
    }
}

Il modello Bicep precedente prevede un parametro keyVaultName, insieme ad altri parametri. Definisce quindi una risorsa Azure Cosmos DB e inserisce un segreto in Azure Key Vault, denominato connectionString, che rappresenta la stringa di connessione completa all'istanza di Cosmos DB. Per accedere a questo valore della stringa di connessione privata, è possibile usare il frammento di codice seguente:

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);

Nel frammento di codice precedente, il modello cosmos Bicep viene aggiunto come riferimento al builder. L'uscita segreta connectionString viene recuperata dal modello Bicep e archiviata in una variabile. L'output segreto viene quindi passato come variabile di ambiente (ConnectionStrings__cosmos) al progetto api. Questa variabile di ambiente viene usata per connettersi all'istanza di Cosmos DB.

Quando questa risorsa viene distribuita, il meccanismo di distribuzione sottostante farà riferimento ai segreti da Azure Key Vault. Per garantire l'isolamento dei segreti, .NET.NET Aspire crea un Key Vault per ogni origine.

Nota

In modalità di provisioning locale, il segreto viene estratto da Key Vault e impostato in una variabile di ambiente. Per altre informazioni, vedere Azure provisioning locale.

Editoria

Quando si pubblica l'app, il provisioning generato da Bicep viene usato dal Azure Developer CLI per creare le risorse Azure nella sottoscrizione Azure. .NET .NET Aspire restituisce un manifesto di pubblicazione , che è anche una parte essenziale del processo di pubblicazione. Il Azure Developer CLI è uno strumento da riga di comando che fornisce un set di comandi per gestire le risorse Azure.

Per ulteriori informazioni sulla pubblicazione e distribuzione, vedere Distribuire un progetto .NET Aspire su Azure Container Apps usando Azure Developer CLI (guida dettagliata).