Visión general de las integraciones de .NET AspireAzure
Azure es la plataforma en la nube más popular para compilar e implementar aplicaciones .NET. El SDK de Azure para .NET permite administrar y usar fácilmente los servicios de Azure. .NET Aspire proporciona un conjunto de integraciones con servicios Azure, donde puede agregar nuevos recursos o conectarse a los existentes. En este artículo se detallan algunos aspectos comunes de todas las integraciones de Azure en .NET Aspire y se pretende ayudarle a comprender cómo usarlos.
Agregar Azure recursos
Todas las integraciones de hospedaje de .NET AspireAzure exponen recursos Azure y por convención se agregan mediante AddAzure*
API. Al añadir estos recursos a tu host de aplicación .NET Aspire, representan un servicio Azure. La API de AddAzure*
devuelve un IResourceBuilder<T> donde T
es el tipo de recurso de Azure. Estas interfaces de IResourceBuilder<T>
(constructor) proporcionan una API fluida que permite configurar el recurso subyacente Azure dentro del modelo de aplicación. Hay API para agregar nuevos recursos de Azure, marcar los recursos como existentes y configurar cómo se comportan los recursos en varios contextos de ejecución.
Experiencia típica para desarrolladores
Cuando el host de la aplicación de .NET Aspire contiene recursos de Azure y lo ejecuta localmente (experiencia típica del desarrollador con F5 o dotnet run
), los recursos de Azure se aprovisionan en la suscripción de Azure. Esta funcionalidad le permite a usted como desarrollador depurar estos elementos localmente en el contexto del host de su aplicación.
.NET .NET Aspire pretende minimizar los costos por defecto optando por Basic o StandardStock Keeping Unit (SKU) para sus integraciones de Azure. Aunque se proporcionan estos valores predeterminados razonables, puede personalizar los recursos de Azure para satisfacer sus necesidades. Además, algunas integraciones admiten emuladores o contenedores, que son útiles para el desarrollo, las pruebas y la depuración locales. De forma predeterminada, al ejecutar la aplicación localmente, los recursos de Azure usan el servicio Azure real. Sin embargo, puede configurarlos para que usen emuladores o contenedores locales, evitando los costos asociados con el servicio Azure real durante el desarrollo local.
Emuladores locales
Algunos servicios de Azure se pueden emular para ejecutarse localmente. Actualmente, .NET Aspire admite los siguientes emuladores de Azure:
Integración de hospedaje | Descripción |
---|---|
Azure Cosmos DB | Llame a AzureCosmosExtensions.RunAsEmulator en el IResourceBuilder<AzureCosmosDBResource> para configurar el recurso Cosmos DB y que sea emulado con la API NoSQL. |
Azure Event Hubs | Llame a AzureEventHubsExtensions.RunAsEmulator en el IResourceBuilder<AzureEventHubsResource> para configurar el recurso de Event Hubs para emularlo. |
Azure Service Bus | Llame a AzureServiceBusExtensions.RunAsEmulator en el IResourceBuilder<AzureServiceBusResource> para configurar el recurso de Service Bus de manera que sea emulado con el emulador de Service Bus. |
Azure SignalR Service | Llame al AzureSignalRExtensions.RunAsEmulator en el IResourceBuilder<AzureSignalRResource> para configurar el recurso SignalR para que se emule con el emulador AzureSignalR. |
Azure almacenamiento | Utilice AzureStorageExtensions.RunAsEmulator en IResourceBuilder<AzureStorageResource> para configurar el recurso de almacenamiento que se va a emular con Azurite. |
Para que los recursos de Azure usen los emuladores locales, encadena una llamada al método RunAsEmulator
del generador de recursos Azure. Este método configura el recurso Azure para usar el emulador local en lugar del servicio Azure real.
Importante
Llamar a cualquiera de las API de RunAsEmulator
disponibles en un generador de recursos de Azure no afecta al manifiesto de publicación . Cuando publicas tu aplicación, el archivo Bicep generado refleja el servicio Azure real, no el emulador local.
Contenedores locales
Algunos recursos Azure se pueden sustituir localmente mediante contenedores de código abierto o en las instalaciones. Para sustituir un recurso de Azure localmente en un contenedor, encadene una llamada al método RunAsContainer
en el generador de recursos de Azure. Este método configura el recurso de Azure para usar una versión en contenedor del servicio para el desarrollo y las pruebas locales, en lugar del servicio Azure real.
Actualmente, .NET Aspire admite los siguientes servicios Azure como contenedores:
Integración de hospedaje | Detalles |
---|---|
Azure Cache for Redis | Ejecute AzureRedisExtensions.RunAsContainer en IResourceBuilder<AzureRedisCacheResource> para configurarlo y ejecutarlo localmente en un contenedor, basado en la imagen de docker.io/library/redis . |
Azure PostgreSQL Flexible Server | Ejecute AzurePostgresExtensions.RunAsContainer en IResourceBuilder<AzurePostgresFlexibleServerResource> para configurarlo y ejecutarlo localmente en un contenedor, basado en la imagen de docker.io/library/postgres . |
Azure SQL Server | Ejecute AzureSqlExtensions.RunAsContainer en IResourceBuilder<AzureSqlServerResource> para configurarlo y ejecutarlo localmente en un contenedor, basado en la imagen de mcr.microsoft.com/mssql/server . |
Nota
Al igual que los emuladores, invocar a RunAsContainer
en un constructor de recursos Azure no afecta al manifiesto de publicación . Al publicar tu aplicación, el archivo Bicep generado refleja el servicio Azure real, no el contenedor local.
Descripción de las API de integración de Azure
La fuerza de .NET.NET Aspirereside en su capacidad para proporcionar un ciclo interno asombroso para desarrolladores. Las integraciones de Azure no son diferentes. Proporcionan un conjunto de API y patrones comunes que se comparten en todos los recursos de Azure. Estas APIs y patrones están diseñados para facilitar el trabajo con recursos Azure de manera coherente.
En la sección de contenedores precedentes, has visto cómo ejecutar Azure servicios en contenedores de forma local. Si está familiarizado con .NET.NET Aspire, es posible que se pregunte cómo llamar a AddAzureRedis("redis").RunAsContainer()
para obtener un contenedor de docker.io/library/redis
local difiere de AddRedis("redis")
, ya que ambos dan como resultado el mismo contenedor local.
La respuesta es que no hay ninguna diferencia al ejecutarse localmente. Sin embargo, cuando se publican, consigues recursos diferentes:
API (Interfaz de Programación de Aplicaciones) | Modo de ejecución | Modo de publicación |
---|---|---|
AddAzureRedis("redis").RunAsContainer() | Contenedor local Redis | Azure Cache for Redis |
AddRedis("redis") | Contenedor local Redis | Azure app de contenedor con Redis imagen |
Lo mismo sucede con los servicios SQL y PostgreSQL:
API (Interfaz de Programación de Aplicaciones) | Modo de ejecución | Modo de publicación |
---|---|---|
AddAzurePostgresFlexibleServer("postgres").RunAsContainer() | Contenedor local PostgreSQL | Azure PostgreSQL Server flexible |
AddPostgres("postgres") | Contenedor local PostgreSQL | Azure aplicación de contenedores con PostgreSQL imagen |
AddAzureSqlServer("sql").RunAsContainer() | Contenedor local SQL Server | Azure SQL Server |
AddSqlServer("sql") | Contenedor local SQL Server | Azure Aplicación de contenedores con SQL Server imagen |
Para obtener más información sobre la diferencia entre los modos de ejecución y publicación, consulte .NET.NET Aspire host de la aplicación: Contexto de ejecución.
API para expresar recursos de Azure en distintos modos
El constructor de aplicaciones distribuidas, que forma parte del host de aplicación, utiliza el patrón de constructor para AddAzure*
recursos al modelo de aplicación. Los desarrolladores pueden configurar estos recursos y definir su comportamiento en distintos contextos de ejecución.
Azure las integraciones de hospedaje proporcionan API para especificar cómo se deben "publicar" y "ejecutar" estos recursos.
Cuando se ejecuta el host de la aplicación, se usa el contexto de ejecución para determinar si el host de la aplicación está en modo Run o Publish. Las convenciones de nomenclatura de estas API indican la acción prevista para el recurso.
En la tabla siguiente se resumen las convenciones de nomenclatura que se usan para expresar los recursos de Azure:
Nota
No todas las API están disponibles en todos los recursos de Azure. Por ejemplo, algunos recursos de Azure se pueden incluir en contenedores o emularlos, mientras que otros no.
Para obtener más información sobre los modos de ejecución, vea contexto de ejecución.
Casos de uso de la API del modo de ejecución general
Use RunAsExisting cuando necesite interactuar dinámicamente con un recurso existente durante el tiempo de ejecución sin necesidad de implementarlo ni actualizarlo. Use PublishAsExisting al declarar los recursos existentes como parte de una configuración de implementación, lo que garantiza que se aplican los ámbitos y permisos correctos. Por último, use AsExisting<T>(IResourceBuilder<T>, IResourceBuilder<ParameterResource>, IResourceBuilder<ParameterResource>) al declarar los recursos existentes en ambas configuraciones, con un requisito para parametrizar las referencias.
Puede consultar si un recurso está marcado como un recurso existente llamando al método de extensión IsExisting(IResource) en el IResource. Para obtener más información, consulte Uso de Azure recursos existentes.
Usar recursos existentes Azure
.NET Aspire proporciona soporte para referenciar los recursos existentes de Azure. Marca un recurso existente a través de las API de PublishAsExisting
, RunAsExisting
y AsExisting
. Estas API permiten a los desarrolladores hacer referencia a recursos de Azure ya implementados, configurarlos y generar manifiestos de implementación adecuados mediante plantillas de Bicep.
Los recursos existentes a los que se hace referencia con estas API se pueden mejorar con asignaciones de roles y otras personalizaciones que están disponibles con la infraestructura de de .NET.NET Aspirecomo funcionalidades de código. Estas APIs se limitan a recursos Azure que se pueden implementar con plantillas de Bicep.
Configurar los recursos de Azure existentes para el modo de ejecución
El método RunAsExisting se usa cuando una aplicación distribuida se ejecuta en modo "ejecutar". En este modo, se supone que el recurso de Azure al que se hace referencia ya existe y se integra con él durante la ejecución sin aprovisionar el recurso. Para marcar un recurso Azure como existente, llame al método RunAsExisting
en el generador de recursos. Tenga en cuenta el ejemplo siguiente:
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");
El código anterior:
- Crea una nueva instancia de
builder
. - Agrega un parámetro denominado
existingServiceBusName
al constructor. - Agrega un recurso Azure Service Bus denominado
messaging
al constructor. - Llama al método
RunAsExisting
en el generador de recursosserviceBus
, pasando el parámetroexistingServiceBusName
; alternativamente, puede usar la sobrecarga del parámetrostring
. - Agrega una cola denominada
queue
al recursoserviceBus
.
De forma predeterminada, se supone que la referencia de parámetros de Service Bus está en el mismo grupo de recursos Azure. Sin embargo, si se encuentra en otro grupo de recursos, puede pasar el grupo de recursos explícitamente como parámetro para especificar correctamente la agrupación de recursos adecuada.
Configurar los recursos de Azure existentes para el modo de publicación
El método PublishAsExisting se usa en modo "publicar" cuando la intención es declarar y hacer referencia a un recurso de Azure ya existente durante el modo de publicación. Esta API facilita la creación de manifiestos y plantillas que incluyen definiciones de recursos que se asignan a los recursos existentes en Bicep.
Para marcar un recurso de Azure como existente en para el modo "publicar", llame al método PublishAsExisting
en el generador de recursos. Tenga en cuenta el ejemplo siguiente:
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");
El código anterior:
- Crea una nueva instancia de
builder
. - Agrega un parámetro denominado
existingServiceBusName
al constructor. - Agrega un recurso Azure Service Bus denominado
messaging
al constructor. - Llama al método
PublishAsExisting
en el generador de recursosserviceBus
, pasando el parámetroexistingServiceBusName
; alternativamente, puede usar la sobrecarga del parámetrostring
. - Agrega una cola denominada
queue
al recursoserviceBus
.
Una vez ejecutado el host de la aplicación en modo de publicación, el archivo de manifiesto generado incluirá el parámetro existingResourceName
, que se puede usar para hacer referencia al recurso Azure existente. Tenga en cuenta el siguiente fragmento de código parcial generado del archivo de manifiesto:
"messaging": {
"type": "azure.bicep.v0",
"connectionString": "{messaging.outputs.serviceBusEndpoint}",
"path": "messaging.module.bicep",
"params": {
"existingServiceBusName": "{existingServiceBusName.value}",
"principalType": "",
"principalId": ""
}
},
"queue": {
"type": "value.v0",
"connectionString": "{messaging.outputs.serviceBusEndpoint}"
}
Para obtener más información sobre el archivo de manifiesto, vea .NET.NET Aspire formato de manifiesto para los generadores de herramientas de implementación.
Además, la plantilla de Bicep generada incluye el parámetro existingResourceName
, que se puede usar para hacer referencia al recurso Azure existente. Considere la siguiente plantilla generada en Bicep:
@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location
param existingServiceBusName string
param principalType string
param principalId string
resource messaging 'Microsoft.ServiceBus/namespaces@2024-01-01' existing = {
name: existingServiceBusName
}
resource messaging_AzureServiceBusDataOwner 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(messaging.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '090c5cfd-751d-490a-894a-3ce6f1109419'))
properties: {
principalId: principalId
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '090c5cfd-751d-490a-894a-3ce6f1109419')
principalType: principalType
}
scope: messaging
}
resource queue 'Microsoft.ServiceBus/namespaces/queues@2024-01-01' = {
name: 'queue'
parent: messaging
}
output serviceBusEndpoint string = messaging.properties.serviceBusEndpoint
Para obtener más información sobre las plantillas de Bicep generadas, consulte Infrastructure as code y considere otras API de publicación.
Advertencia
Al interactuar con los recursos existentes que requieren autenticación, asegúrese de que la estrategia de autenticación que está configurando en el modelo de aplicación .NET.NET Aspire se alinea con la estrategia de autenticación permitida por el recurso existente. Por ejemplo, no es posible usar la identidad administrada en un recurso de AzurePostgreSQL existente que no esté configurado para permitir la identidad administrada. De forma similar, si un recurso existente de AzureRedis deshabilitó las claves de acceso, no es posible usar la autenticación mediante clave de acceso.
Configurar los recursos de Azure existentes en todos los modos
El método AsExisting<T>(IResourceBuilder<T>, IResourceBuilder<ParameterResource>, IResourceBuilder<ParameterResource>) se usa cuando la aplicación distribuida se ejecuta en modo "ejecutar" o "publicar". Dado que el método AsExisting
funciona en ambos escenarios, solo admite una referencia con parámetros al nombre del recurso o al nombre del grupo de recursos. Este enfoque ayuda a evitar el uso del mismo recurso en entornos de prueba y producción.
Para marcar un recurso Azure como existente, llame al método AsExisting
en el generador de recursos. Tenga en cuenta el ejemplo siguiente:
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");
El código anterior:
- Crea una nueva instancia de
builder
. - Agrega un parámetro denominado
existingServiceBusName
al constructor. - Agrega un recurso Azure Service Bus denominado
messaging
al constructor. - Llama al método
AsExisting
en el generador de recursos deserviceBus
y pasa el parámetroexistingServiceBusName
. - Agrega una cola denominada
queue
al recursoserviceBus
.
Añadir recursos existentes de Azure con cadenas de conexión
.NET .NET Aspire proporciona la capacidad de conectarse a los recursos existentes, incluidos los recursos Azure. Expresar cadenas de conexión resulta útil cuando tiene recursos Azure existentes que desea usar en la aplicación de .NET Aspire. La API de AddConnectionString se usa con el contexto de ejecución del host de la aplicación para agregar condicionalmente una cadena de conexión al modelo de aplicación.
Nota
Las cadenas de conexión se usan para representar una amplia gama de información de conexión, incluidas las conexiones de base de datos, los agentes de mensajes, los URI de punto de conexión y otros servicios. En .NET.NET Aspire nomenclatura, el término "cadena de conexión" se usa para representar cualquier tipo de información de conexión.
Tenga en cuenta el ejemplo siguiente, donde en modo de publicación agrega un recurso de Almacenamiento Azure, mientras que en modo de ejecución agrega una cadena de conexión a un Almacenamiento Azure existente.
var builder = DistributedApplication.CreateBuilder(args);
var storage = builder.ExecutionContext.IsPublishMode
? builder.AddAzureStorage("storage")
: builder.AddConnectionString("storage");
builder.AddProject<Projects.Api>("api")
.WithReference(storage);
// After adding all resources, run the app...
El código anterior:
- Crea una nueva instancia de
builder
. - Agrega un recurso de Azure Storage denominado
storage
en modo "publicar". - Agrega una cadena de conexión en modo 'run' a un almacenamiento Azure existente denominado
storage
. - Agrega un proyecto llamado
api
al constructor. - El proyecto
api
hace referencia al recursostorage
independientemente del modo.
El proyecto de API de consumo usa la información de la cadena de conexión sin saber cómo lo configuró el host de la aplicación. En el modo "publicar", el código agrega un nuevo recurso de almacenamiento Azure, que se reflejaría adecuadamente en el manifiesto de implementación de . Cuando está en modo "ejecutar", la cadena de conexión corresponde a un valor de configuración visible para el host de la aplicación. Se supone que todas las asignaciones de roles para el recurso de destino están configuradas. Esto significa que es probable que configure una variable de entorno o un secreto de usuario para almacenar la cadena de conexión. La configuración se resuelve desde la clave de configuración ConnectionStrings__storage
(o ConnectionStrings:storage
). Estos valores de configuración se pueden ver cuando se ejecuta la aplicación. Para obtener más información, consulte Detalles del recurso.
A diferencia de los recursos existentes modelados con la API AsExisting
de primera clase, los recursos existentes modelados como cadenas de conexión no se pueden mejorar con asignaciones de roles adicionales ni personalizaciones de infraestructura.
Publicar como aplicación contenedora Azure
.NET .NET Aspire permite publicar recursos primitivos como Azure Container Apps, una plataforma sin servidor que reduce la administración de infraestructuras. Los tipos de recurso admitidos incluyen:
- ContainerResource: representa un contenedor especificado.
- ExecutableResource: representa un proceso ejecutable especificado.
- ProjectResource: representa un proyecto de .NET especificado.
Para publicar estos recursos, use las SIGUIENTES API:
- AzureContainerAppContainerExtensions.PublishAsAzureContainerApp<T>(IResourceBuilder<T>, Action<AzureResourceInfrastructure,ContainerApp>)
- AzureContainerAppExecutableExtensions.PublishAsAzureContainerApp<T>(IResourceBuilder<T>, Action<AzureResourceInfrastructure,ContainerApp>)
- AzureContainerAppProjectExtensions.PublishAsAzureContainerApp<T>(IResourceBuilder<T>, Action<AzureResourceInfrastructure,ContainerApp>)
Estas APIs configuran el recurso que se va a publicar como una Aplicación de Contenedor Azure y llaman implícitamente a AddAzureContainerAppsInfrastructure(IDistributedApplicationBuilder) para agregar la infraestructura necesaria y los archivos de Bicep al host de la aplicación. Por ejemplo, considere el código siguiente:
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)
});
});
El código anterior:
- Crea una nueva instancia de
builder
. - Agrega un parámetro denominado
env
al constructor. - Agrega un proyecto llamado
api
al constructor. - Llama al método
PublishAsAzureContainerApp
en el generador de recursos deapi
, pasando una expresión lambda que configura la infraestructura de Azure Container App, dondeinfra
es el AzureResourceInfrastructure yapp
es el ContainerApp.- Agrega una variable de entorno denominada
Hello
a la aplicación contenedora mediante el parámetroenv
. - El método
AsProvisioningParameter
se usa para tratarenv
como una nueva ProvisioningParameter en la infraestructura o reutiliza un parámetro bicep existente si ya existe uno con el mismo nombre.
- Agrega una variable de entorno denominada
Para obtener más información, consulte ContainerApp y AsProvisioningParameter.
Infraestructura como código
El Azure SDK para .NET proporciona el paquete NuGet de 📦Azure.Provisioning y un conjunto de paquetes de aprovisionamiento específicos para servicios Azure. Estas Azure bibliotecas de aprovisionamiento facilitan la especificación declarativa de Azure infraestructura de forma nativa en .NET. Sus API le permiten escribir infraestructura orientada a objetos en C#, lo que da lugar a Bicep. Bicep es un lenguaje específico del dominio (DSL) para implementar Azure recursos de manera declarativa.
Aunque es posible aprovisionar Azure recursos manualmente, .NET Aspire simplifica el proceso proporcionando un conjunto de API para expresar recursos Azure. Estas API están disponibles como métodos de extensión en .NET AspireAzure bibliotecas de hospedaje, ampliando la interfaz IDistributedApplicationBuilder. Al añadir recursos Azure al host de la aplicación, se añade implícitamente la funcionalidad de aprovisionamiento adecuada. En otras palabras, no es necesario llamar directamente a ninguna API de aprovisionamiento.
Dado que .NET Aspire modela recursos Azure dentro de integraciones de hospedaje Azure, el SDK de Azure se utiliza para aprovisionar estos recursos. Se generan archivos Bicep que definen los recursos Azure necesarios. Los archivos Bicep generados se generan junto al archivo de manifiesto cuando publicas tu aplicación.
Hay varias maneras de influir en los archivos Bicep generados:
-
Azure. Personalización de aprovisionamiento:
- Configurar infraestructura: personalice infraestructura de recursos Azure.
- Agregar Azure infraestructura: Agrega manualmente Azure infraestructura a tu host de la aplicación.
-
Utilizar plantillas de Bicep personalizadas:
- Hacer referencia a archivos de Bicep: agregue una referencia a un archivo de Bicep en el disco.
- Referencia Bicep en línea: Agregar una plantilla Bicep en línea.
Provisión local y Azure.Provisioning
Para evitar la confusión de términos y ayudar a aclarar el "aprovisionamiento", es importante comprender la distinción entre el aprovisionamiento local y el aprovisionamientoAzure:
Aprovisionamiento local:
De forma predeterminada, cuando se llama a cualquiera de las API de integración de hospedaje de Azure para agregar recursos de Azure, se llama implícitamente a la API de AddAzureProvisioning(IDistributedApplicationBuilder). Esta API registra los servicios en el contenedor de inyección de dependencias (DI) que se utilizan para proveer los recursos Azure cuando se inicia el host de la aplicación. Este concepto se conoce como aprovisionamiento local. Para obtener más información, consulte Azure aprovisionamiento local.
Azure.Provisioning
:Azure.Provisioning
hace referencia al paquete NuGet y es un conjunto de bibliotecas que permite usar C# para generar Bicep. Las integraciones de alojamiento en Azure utilizan internamente estas bibliotecas para generar archivos Bicep que definen los recursos Azure que necesita. Para obtener más información, veaAzure.Provisioning
personalización.
Personalización Azure.Provisioning
Todas las integraciones de alojamiento de .NET AspireAzure exponen varios recursos de Azure, y todas son subclases del tipo AzureProvisioningResource, que a su vez hereda de AzureBicepResource. Esto habilita extensiones que están restringidas genéricamente a este tipo, permitiendo que una API fluida personalice la infraestructura según sus preferencias. Aunque .NET.NET Aspire proporciona valores predeterminados, eres libre de influir en el Bicep generado mediante estas API.
Configuración de la infraestructura
Independientemente del recurso Azure con el que trabajes, encadenas una llamada al método de extensión ConfigureInfrastructure para configurar su infraestructura subyacente. Este método permite personalizar la infraestructura del recurso Azure pasando un delegado configure
de tipo Action<AzureResourceInfrastructure>
. El tipo AzureResourceInfrastructure es una subclase del Azure.Provisioning.Infrastructure. Este tipo expone una superficie de API masiva para configurar la infraestructura subyacente del recurso Azure.
Tenga en cuenta el ejemplo siguiente:
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)
};
});
El código anterior:
- Agrega un parámetro denominado
storage-sku
. - Agrega almacenamiento Azure con la API AddAzureStorage, denominada
storage
. - Encadena una llamada a
ConfigureInfrastructure
para personalizar la infraestructura de almacenamiento de Azure:- Obtiene los recursos provisionables.
- Filtra a una sola StorageAccount.
- Asigna el parámetro
storage-sku
a la propiedad StorageAccount.Sku:- Una nueva instancia del StorageSku tiene asignada su propiedad
Name
a partir del resultado de la API de AsProvisioningParameter.
- Una nueva instancia del StorageSku tiene asignada su propiedad
Esto ejemplifica introducir un parámetro externo en la infraestructura de almacenamiento de Azure, lo que da como resultado el archivo Bicep generado que refleja la configuración deseada.
Agregar Azure a la infraestructura
No todos los servicios Azure se exponen como integraciones de .NET Aspire. Aun cuando podrían estar disponibles en otro momento, todavía puede habilitar servicios que están disponibles en bibliotecas Azure.Provisioning.*
. Imagina un escenario en el que tienes un servicio de trabajador responsable de administrar un Azure Registro de Contenedores. Ahora imagine que un proyecto host de aplicación tiene una dependencia del paquete NuGet 📦Azure.Provisioning.ContainerRegistry.
Puede usar la API de AddAzureInfrastructure
para agregar la infraestructura de Azure Container Registry al host de la aplicación:
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));
El código anterior:
- Realiza una llamada a AddAzureInfrastructure con el nombre
acr
. - Proporciona un delegado
configureInfrastructure
para personalizar la infraestructura del Azure Registro de Contenedores.- Crea una instancia de un ContainerRegistryService con el nombre
acr
y una SKU estándar. - Agrega el servicio Azure Container Registry a la variable
infra
. - Crea una instancia de un ProvisioningOutput con el nombre
registryName
, un tipo destring
y un valor que corresponde al nombre del Azure Container Registry. - Agrega la salida a la variable
infra
.
- Crea una instancia de un ContainerRegistryService con el nombre
- Agrega un proyecto llamado
worker
al compilador. - Encadena una llamada a WithEnvironment para establecer la variable de entorno
ACR_REGISTRY_NAME
del proyecto con el valor del resultado deregistryName
.
La funcionalidad demuestra cómo añadir la infraestructura de Azure al proyecto host de la aplicación, incluso si el servicio Azure no se expone directamente como una .NET Aspire integración. Además, muestra cómo canalizar la salida del Azure Container Registry hacia el entorno de un proyecto dependiente.
Observa el archivo Bicep resultante.
@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location
resource acr 'Microsoft.ContainerRegistry/registries@2023-07-01' = {
name: take('acr${uniqueString(resourceGroup().id)}', 50)
location: location
sku: {
name: 'Standard'
}
}
output registryName string = acr.name
El archivo Bicep refleja la configuración deseada de Azure Container Registry, tal como se define en la API de AddAzureInfrastructure
.
Uso de plantillas personalizadas de Bicep
Cuando tenga como destino Azure como proveedor de nube deseado, puede usar Bicep para definir la infraestructura como código. Tiene como objetivo simplificar drásticamente la experiencia de creación con una sintaxis más limpia y una mejor compatibilidad con la modularidad y la reutilización de código.
Aunque .NET.NET Aspire proporciona un conjunto de plantillas de Bicep prediseñadas, puede haber ocasiones en las que desee personalizar las plantillas o crear las suyas propias. En esta sección se explican los conceptos y las API correspondientes que puede usar para personalizar las plantillas de Bicep.
Importante
Esta sección no está pensada para enseñarte Bicep, sino para proporcionar una guía sobre cómo crear plantillas personalizadas de Bicep para su uso con .NET.NET Aspire.
Como parte de la historia de implementación de Azure para .NET Aspire, el Azure Developer CLI (azd
) ofrece una comprensión de su proyecto .NET Aspire y la capacidad para implementarlo en Azure. La CLI de azd
usa las plantillas de Bicep para implementar la aplicación en Azure.
Instalación de Aspire.Hosting.Azure
paquete
Cuando quieres hacer referencia a archivos de Bicep, es posible que no estés usando ninguna de las integraciones de hospedaje Azure. En este caso, puede seguir haciendo referencia a los archivos Bicep instalando el paquete Aspire.Hosting.Azure
. Este paquete proporciona las API necesarias para hacer referencia a archivos de Bicep y personalizar los recursos de Azure.
Propina
Si usa cualquiera de las Azure integraciones de hospedaje, no es necesario instalar el paquete de Aspire.Hosting.Azure
, ya que es una dependencia transitiva.
Para usar cualquiera de estas funcionalidades, el paquete NuGet 📦Aspire.Hosting.Azure debe estar instalado.
dotnet add package Aspire.Hosting.Azure
Para obtener más información, consulte dotnet add package o Manage package dependencies in .NET applications.
Qué esperar de los ejemplos
En todos los ejemplos de esta sección, se asume que estás usando el espacio de nombres Aspire.Hosting.Azure. Además, en los ejemplos se supone que tiene una instancia de IDistributedApplicationBuilder:
using Aspire.Hosting.Azure;
var builder = DistributedApplication.CreateBuilder(args);
// Examples go here...
builder.Build().Run();
De forma predeterminada, cuando se llama a cualquiera de las API relacionadas con Bicep, también se realiza una llamada a AddAzureProvisioning que agrega compatibilidad para generar recursos de Azure dinámicamente durante el inicio de la aplicación. Para obtener más información, consulte Aprovisionamiento Local y Azure.Provisioning
.
Archivos de referencia de Bicep
Imagine que tiene una plantilla de Bicep en un archivo denominado storage.bicep
que aprovisiona una Cuenta de Almacenamiento Azure:
param location string = resourceGroup().location
param storageAccountName string = 'toylaunch${uniqueString(resourceGroup().id)}'
resource storageAccount 'Microsoft.Storage/storageAccounts@2021-06-01' = {
name: storageAccountName
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
accessTier: 'Hot'
}
}
Para agregar una referencia al archivo de Bicep en el disco, llame al método AddBicepTemplate. Tenga en cuenta el ejemplo siguiente:
builder.AddBicepTemplate(
name: "storage",
bicepFile: "../infra/storage.bicep");
El código anterior agrega una referencia a un archivo de Bicep ubicado en ../infra/storage.bicep
. Las rutas de acceso de archivo deben ser relativas al proyecto de hospedaje de la aplicación. Esta referencia da como resultado que se agregue un AzureBicepResource a la colección de recursos de la aplicación con el nombre "storage"
y la API devuelve una instancia de IResourceBuilder<AzureBicepResource>
que se puede usar para personalizar aún más el recurso.
Referencia en línea para Bicep
Aunque tener un archivo de Bicep en el disco es el escenario más común, también puede agregar plantillas de Bicep en línea. Las plantillas insertadas pueden ser útiles cuando se desea definir una plantilla en el código o cuando se desea generar la plantilla de forma dinámica. Para agregar una plantilla Bicep integrada, llame al método AddBicepTemplateString con la plantilla Bicep como string
. Tenga en cuenta el ejemplo siguiente:
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
}
}
}
"""
);
En este ejemplo, la plantilla de Bicep se define en línea como string
y se agrega a la colección de recursos de la aplicación con el nombre "ai"
. En este ejemplo, se aprovisiona un recurso de Inteligencia Artificial (IA) Azure.
Pasar parámetros a plantillas de Bicep
Bicep admite la aceptación de parámetros, que se pueden usar para personalizar el comportamiento de la plantilla. Para pasar parámetros a una plantilla de Bicep desde .NET.NET Aspire, encadene llamadas al método WithParameter como se muestra en el ejemplo siguiente:
var region = builder.AddParameter("region");
builder.AddBicepTemplate("storage", "../infra/storage.bicep")
.WithParameter("region", region)
.WithParameter("storageName", "app-storage")
.WithParameter("tags", ["latest","dev"]);
El código anterior:
- Agrega un parámetro denominado
"region"
a la instancia debuilder
. - Agrega una referencia a un archivo de Bicep ubicado en
../infra/storage.bicep
. - Pasa el parámetro
"region"
a la plantilla de Bicep, que se resuelve utilizando la resolución estándar de parámetros. - Pasa el parámetro
"storageName"
a la plantilla de Bicep con un valor codificado de forma fija. - Pasa el parámetro
"tags"
a la plantilla de Bicep con un array de cadenas de caracteres.
Para obtener más información, vea Parámetros externos.
Parámetros conocidos
.NET .NET Aspire proporciona un conjunto de parámetros conocidos que se pueden pasar a plantillas de Bicep. Estos parámetros se usan para proporcionar información sobre la aplicación y el entorno a las plantillas de Bicep. Están disponibles los siguientes parámetros conocidos:
Campo | Descripción | Valor |
---|---|---|
AzureBicepResource.KnownParameters.KeyVaultName | Nombre del recurso del almacén de claves que se utiliza para guardar outputs confidenciales. | "keyVaultName" |
AzureBicepResource.KnownParameters.Location | La ubicación del recurso. Esto es necesario para todos los recursos. | "location" |
AzureBicepResource.KnownParameters.LogAnalyticsWorkspaceId | Identificador de recurso del área de trabajo de Log Analytics. | "logAnalyticsWorkspaceId" |
AzureBicepResource.KnownParameters.PrincipalId | El identificador principal del usuario actual o de la identidad gestionada. | "principalId" |
AzureBicepResource.KnownParameters.PrincipalName | Nombre principal del usuario actual o identidad administrada. | "principalName" |
AzureBicepResource.KnownParameters.PrincipalType | El tipo principal del usuario actual o la identidad administrada.
User o ServicePrincipal . |
"principalType" |
Para usar un parámetro conocido, pase el nombre del parámetro al método WithParameter, como WithParameter(AzureBicepResource.KnownParameters.KeyVaultName)
. No se pasan valores para parámetros conocidos, ya que .NET.NET Aspire los resuelve por usted.
Considere un ejemplo en el que desea configurar un webhook de Azure Event Grid. Puede definir la plantilla de Bicep de la siguiente manera:
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
Esta plantilla de Bicep define varios parámetros, incluidos los topicName
, webHookEndpoint
, principalId
, principalType
y el location
opcional . Para pasar estos parámetros a la plantilla de Bicep, puede usar el siguiente fragmento de código:
var webHookApi = builder.AddProject<Projects.WebHook_Api>("webhook-api");
var webHookEndpointExpression = ReferenceExpression.Create(
$"{webHookApi.GetEndpoint("https")}/hook");
builder.AddBicepTemplate("event-grid-webhook", "../infra/event-grid-webhook.bicep")
.WithParameter("topicName", "events")
.WithParameter(AzureBicepResource.KnownParameters.PrincipalId)
.WithParameter(AzureBicepResource.KnownParameters.PrincipalType)
.WithParameter("webHookEndpoint", () => webHookEndpointExpression);
- El proyecto de
webHookApi
se agrega como referencia albuilder
. - Al parámetro
topicName
se le pasa un valor de nombre fijo. - El parámetro
webHookEndpoint
se pasa como una expresión que se convierte en la URL desde las referencias del proyectoapi
en el punto de conexión "https" con la ruta/hook
. - Los parámetros
principalId
yprincipalType
se pasan como parámetros conocidos.
Los parámetros conocidos se basan en convenciones y no deben ir acompañados de un valor correspondiente cuando se pasan mediante la API de WithParameter
. Los parámetros conocidos simplifican algunas funcionalidades comunes, como las asignaciones de roles , cuando se agregan a las plantillas de Bicep, como se muestra en el ejemplo anterior. Las asignaciones de roles son necesarias para que el webhook de Event Grid envíe eventos al punto de conexión especificado. Para obtener más información, consulte asignación de roles del remitente de datos de Event Grid.
Obtención de resultados a partir de referencias de Bicep
Además de pasar parámetros a las plantillas de Bicep, también puede obtener resultados de estas. Considere la siguiente plantilla de Bicep, ya que define un output
denominado 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
El Bicep define una salida denominada endpoint
. Para obtener la salida de la plantilla de Bicep, llame al método GetOutput en una instancia de IResourceBuilder<AzureBicepResource>
como se muestra en el siguiente fragmento de código de C#:
var storage = builder.AddBicepTemplate(
name: "storage",
bicepFile: "../infra/storage.bicep"
);
var endpoint = storage.GetOutput("endpoint");
En este ejemplo, la salida de la plantilla de Bicep se recupera y almacena en una variable endpoint
. Normalmente, pasarías esta salida como una variable de entorno a otro recurso que se basa en ella. Por ejemplo, si tenía un proyecto de API mínima ASP.NET Core que dependía de este punto de conexión, podría pasar la salida como una variable de entorno al proyecto mediante el siguiente fragmento de código:
var storage = builder.AddBicepTemplate(
name: "storage",
bicepFile: "../infra/storage.bicep"
);
var endpoint = storage.GetOutput("endpoint");
var apiService = builder.AddProject<Projects.AspireSample_ApiService>(
name: "apiservice"
)
.WithEnvironment("STORAGE_ENDPOINT", endpoint);
Para obtener más información, consulte los resultados de Bicep.
Obtener resultados secretos a partir de referencias de Bicep
Es importante evitar la salida de secretos cuando se trabaja con Bicep. Si una salida se considera un secreto, lo que significa que no debe exponerse en registros u otros sitios, se puede tratar como tal. Esto se puede lograr almacenando el secreto en Azure Key Vault y haciendo referencia a él en la plantilla de Bicep. La integración de .NET Aspire con Azure ofrece un patrón para almacenar de manera segura las salidas de la plantilla de Bicep, permitiendo que los recursos utilicen el parámetro keyVaultName
para guardar secretos en Azure Key Vault.
Considere la siguiente plantilla de Bicep como ejemplo que ayuda a demostrar este concepto de protección de salidas secretas:
param databaseAccountName string
param keyVaultName string
param databases array = []
@description('Tags that will be applied to all resources')
param tags object = {}
param location string = resourceGroup().location
var resourceToken = uniqueString(resourceGroup().id)
resource cosmosDb 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' = {
name: replace('${databaseAccountName}-${resourceToken}', '-', '')
location: location
kind: 'GlobalDocumentDB'
tags: tags
properties: {
consistencyPolicy: { defaultConsistencyLevel: 'Session' }
locations: [
{
locationName: location
failoverPriority: 0
}
]
databaseAccountOfferType: 'Standard'
}
resource db 'sqlDatabases@2023-04-15' = [for name in databases: {
name: '${name}'
location: location
tags: tags
properties: {
resource: {
id: '${name}'
}
}
}]
}
var primaryMasterKey = cosmosDb.listKeys(cosmosDb.apiVersion).primaryMasterKey
resource vault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
name: keyVaultName
resource secret 'secrets@2023-07-01' = {
name: 'connectionString'
properties: {
value: 'AccountEndpoint=${cosmosDb.properties.documentEndpoint};AccountKey=${primaryMasterKey}'
}
}
}
La plantilla de Bicep anterior espera un parámetro keyVaultName
, entre varios otros parámetros. A continuación, define un recurso de Azure Cosmos DB y guarda un secreto en Azure Key Vault, el cual se denomina connectionString
y representa la cadena de conexión completa a la instancia de Cosmos DB. Para acceder a este valor de cadena de conexión secreta, puede usar el siguiente fragmento de código:
var cosmos = builder.AddBicepTemplate("cosmos", "../infra/cosmosdb.bicep")
.WithParameter("databaseAccountName", "fallout-db")
.WithParameter(AzureBicepResource.KnownParameters.KeyVaultName)
.WithParameter("databases", ["vault-33", "vault-111"]);
var connectionString =
cosmos.GetSecretOutput("connectionString");
builder.AddProject<Projects.WebHook_Api>("api")
.WithEnvironment(
"ConnectionStrings__cosmos",
connectionString);
En el fragmento de código anterior, la plantilla Bicep de cosmos
se agrega como referencia al builder
. La salida secreta connectionString
se recupera de la plantilla de Bicep y se almacena en una variable. A continuación, se pasa el resultado secreto como una variable de entorno (ConnectionStrings__cosmos
) al proyecto api
. Esta variable de entorno se usa para conectarse a la instancia de Cosmos DB.
Cuando se implemente este recurso, el mecanismo de implementación subyacente referenciará automáticamente secretos de Azure Key Vault. Para garantizar el aislamiento de secretos, .NET.NET Aspire crea un Key Vault por origen.
Nota
En modo de aprovisionamiento local, el secreto se extrae de Key Vault y se establece en una variable de entorno. Para obtener más información, consulte Azure aprovisionamiento local.
Publicación
Al publicar su aplicación, el aprovisionamiento generado por Azure Bicep es utilizado por Azure Developer CLI para crear los recursos Azure en su suscripción Azure. .NET .NET Aspire genera una manifiesto de publicación, que también es una parte fundamental del proceso de publicación. El Azure Developer CLI es una herramienta de línea de comandos que proporciona un conjunto de comandos para administrar Azure recursos.
Para obtener más información sobre la publicación e implementación, consulte Implementación de un proyecto de .NET Aspire en Azure Container Apps mediante la Azure Developer CLI (guía detallada).