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
.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:
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
, RunAsExisting
e 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 risorseserviceBus
, passando il parametroexistingServiceBusName
, in alternativa, è possibile usare l'overload del parametrostring
. - Aggiunge una coda denominata
queue
alla risorsaserviceBus
.
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 risorseserviceBus
, passando il parametroexistingServiceBusName
, in alternativa, è possibile usare l'overload del parametrostring
. - Aggiunge una coda denominata
queue
alla risorsaserviceBus
.
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 risorseserviceBus
passando il parametroexistingServiceBusName
. - Aggiunge una coda denominata
queue
alla risorsaserviceBus
.
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 risorsastorage
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:
- ContainerResource: rappresenta un contenitore specificato.
- ExecutableResource: rappresenta un processo eseguibile specificato.
- ProjectResource: rappresenta un progetto di .NET specificato.
Per pubblicare queste risorse, usare le API seguenti:
- AzureContainerAppContainerExtensions.PublishAsAzureContainerApp<T>(IResourceBuilder<T>, Action<AzureResourceInfrastructure,ContainerApp>)
- AzureContainerAppExecutableExtensions.PublishAsAzureContainerApp<T>(IResourceBuilder<T>, Action<AzureResourceInfrastructure,ContainerApp>)
- AzureContainerAppProjectExtensions.PublishAsAzureContainerApp<T>(IResourceBuilder<T>, Action<AzureResourceInfrastructure,ContainerApp>)
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 risorseapi
, passando un'espressione lambda che configura l'infrastruttura dell'app contenitore Azure, doveinfra
è il AzureResourceInfrastructure eapp
è il ContainerApp.- Aggiunge una variabile di ambiente denominata
Hello
all'app contenitore usando il parametroenv
. - Il metodo
AsProvisioningParameter
viene usato per trattareenv
come un nuovo ProvisioningParameter nell'infrastruttura o riutilizzare un parametro bicep esistente se ne esiste già uno con lo stesso nome.
- Aggiunge una variabile di ambiente denominata
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:
-
Azure. Personalizzazione del provisioning:
- Configurare l'infrastruttura: Personalizzare l'infrastruttura delle risorse Azure.
- Aggiungi Azure infrastruttura: aggiungi manualmente l'infrastruttura Azure all'host dell'app.
-
Utilizzare template personalizzati di Bicep:
- File di riferimento Bicep: Aggiungere un riferimento a un file Bicep su disco.
- Riferimento Bicep inline: aggiungere un modello Bicep inline.
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 personalizzazioneAzure.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:- Ottiene le risorse provisionabili.
- Filtra in un singolo StorageAccount.
- Assegna il parametro
storage-sku
alla proprietà StorageAccount.Sku:- Una nuova istanza del StorageSku ha la proprietà
Name
assegnata dal risultato dell'API AsProvisioningParameter.
- Una nuova istanza del StorageSku ha la proprietà
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 distring
e un valore che corrisponde al nome del registro di contenitori Azure. - Aggiunge l'output alla variabile
infra
.
- Instanzia un ContainerRegistryService con il nome
- 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'outputregistryName
.
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.
- .NET CLI dell'interfaccia della riga di comando
- PackageReference
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 dibuilder
. - 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
, principalType
e il location
facoltativo . 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 albuilder
. - 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 progettoapi
con il percorso/hook
. - I parametri
principalId
eprincipalType
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).