Tutorial: Conexión de una aplicación de ASP.NET Core a las integraciones de almacenamiento de .NET Aspire
Las aplicaciones nativas de la nube suelen requerir soluciones de almacenamiento escalables que proporcionan funcionalidades como blob storage, colas o bases de datos NoSQL semiestructuradas. .NET Aspire integraciones simplifican las conexiones a varios servicios de almacenamiento, como Azure Blob Storage. En este tutorial, creará una aplicación de ASP.NET Core que usa integraciones de .NET Aspire para conectarse a Azure Blob Storage y Azure Queue Storage para enviar incidencias de soporte técnico. La aplicación envía las entradas a una cola para su procesamiento y carga un adjunto en el almacenamiento. Aprenderá a:
- Creación de una aplicación de .NET básica que esté configurada para usar integraciones de .NET Aspire
- Incorporación de integraciones de .NET.NET Aspire para conectarse a varios servicios de almacenamiento
- Configuración y uso de características de componente de .NET.NET Aspire para enviar y recibir datos
Prerrequisitos
Para trabajar con .NET.NET Aspire, necesita lo siguiente instalado localmente:
- .NET 8.0 o .NET 9.0
- Un entorno de ejecución de contenedor compatible con OCI, como:
- Docker de escritorio o Podman. Para obtener más información, consulte container runtime.
- Un entorno para desarrolladores integrado (IDE) o un editor de código, como:
- Visual Studio 2022 versión 17.9 o posterior (opcional)
-
Visual Studio Code (opcional)
- C# Dev Kit: extensión (opcional)
- JetBrains Rider con el plugin .NET.NET Aspire (opcional)
Para obtener más información, consulte configuración y herramientas de .NET.NET Aspirey sdk de .NET.NET Aspire.
Explora la aplicación de ejemplo completada
Hay disponible una versión completa de la aplicación de ejemplo de este tutorial en GitHub. El proyecto también se estructura como plantilla para el Azure Developer CLI, lo que significa que puede usar el comando azd up
para automatizar el aprovisionamiento de recursos Azure si tiene instalada la herramienta .
git clone https://github.com/Azure-Samples/dotnet-aspire-connect-storage.git
Configuración de los recursos de almacenamiento de Azure
Para este artículo, necesitará acceso de colaborador de datos a una cuenta de almacenamiento de Azure con un contenedor de blobs y una cola de almacenamiento. Asegúrese de que tiene disponibles los siguientes recursos y configuraciones:
Para este artículo, deberá crear un contenedor de blobs y un recurso de cola de almacenamiento en el entorno de desarrollo local mediante un emulador. Para ello, use Azurite. Azurite es un Azure (emulador) compatible con server la API de Storage de código abierto y de código abierto que se ejecuta en un contenedor de Docker.
Para usar el emulador, debe instalar Azurite.
- Una cuenta de almacenamiento de Azure: Crear una cuenta de almacenamiento.
- Un contenedor de Blob Storage denominado fileuploads - Crear un contenedor de Blob Storage.
- Una cola de almacenamiento denominada tickets - . Crear una cola de almacenamiento.
Ejecute los siguientes comandos en la CLI de Azure o CloudShell para configurar los recursos necesarios Azure Storage:
az group create --name aspirestorage --location eastus2
az storage account create -n aspirestorage -g aspirestorage -l eastus2
az storage container create -n fileuploads --account-name aspirestorage
az storage queue create -n tickets --account-name aspirestorage
También debe asignar los siguientes roles a la cuenta de usuario con la que ha iniciado sesión Visual Studio:
- Colaborador de datos de Storage Blob - Asignar el rol RBAC Azure
- Colaborador de datos de la cola de almacenamiento: Asignar un rol de RBAC Azure
El Azure Developer CLI permite aprovisionar e implementar Azure recursos mediante un sistema de plantillas. En este tutorial se proporciona un plantilla completa que aprovisiona los recursos Azure necesarios e incluye el código de aplicación de ejemplo completado. Ejecute los siguientes comandos para inicializar y ejecutar la plantilla:
Ejecute
azd auth login
para iniciar sesión en Azure:azd auth login
Ejecute
azd init
para clonar e inicializar la plantilla de ejemplo:azd init --template dotnet-aspire-connect-storage
Ejecute
azd up
para aprovisionar los recursos de Azure:azd up
Cuando se le solicite, seleccione la suscripción y la región Azure para los recursos aprovisionados. La plantilla se ejecuta y lleva a cabo las siguientes tareas por ti:
- Crea una cuenta de almacenamiento de Azure con blobs y servicios de cola habilitados
- Crea un contenedor de Blob Storage denominado
fileUploads
- Crea una cola denominada
tickets
- Asigna los siguientes roles a la cuenta de usuario que ejecutó la plantilla.
- Colaborador de datos de Storage Blob
- Colaborador de datos de cola de almacenamiento
Una vez completada correctamente la operación, tiene dos opciones de cara al futuro:
- Opción 1: ejecute la aplicación de ejemplo .NET en el directorio
src
plantilla para experimentar con la aplicación completada. - Opción 2: Compile la aplicación de ejemplo paso a paso con las secciones que se describen y conéctela a los recursos de Azure aprovisionados por
azd
.
Creación de la solución de ejemplo
Cree un proyecto de .NET Aspire mediante Visual Studio o la CLI de .NET.
- En la parte superior de Visual Studio, vaya a Archivo>Nuevo proyecto de>.
- En la ventana de diálogo, busque Aspire y seleccione .NET.NET Aspire Aplicación de inicio. Elija Siguiente.
- En la pantalla Configura tu nuevo proyecto:
- Escribe un nombre de solución de AspireStorage y selecciona Siguiente.
- En la pantalla Información adicional:
- Desactive Use Redis for caching (no se requiere para este tutorial).
- Seleccione Crear.
Visual Studio crea una solución nueva de ASP.NET Core estructurada para usar .NET Aspire.
La solución consta de los siguientes proyectos:
- AspireStorage.ApiService: un proyecto de API con configuraciones de servicio de .NET.NET Aspire predeterminadas.
- AspireStorage.AppHost: un proyecto de orquestador diseñado para conectar y configurar los diferentes proyectos y servicios de la aplicación. El orquestador debe ser configurado como proyecto de inicio.
- AspireStorage.ServiceDefaults: una biblioteca de clases compartida para contener código que se puede reutilizar en los proyectos de la solución.
- AspireStorage.Web: un proyecto de BlazorServer que actúa como front-end de la aplicación.
Añade el proyecto Worker Service
A continuación, agregue un proyecto de Worker Service a la solución para recuperar y procesar mensajes a medida que se agregan a la cola de Azure Storage.
- En el Explorador de Soluciones, haga clic con el botón derecho en el nodo de solución AspireStorage
de nivel superior y seleccione Agregar Nuevo Proyecto . - Busque y seleccione la plantilla de Worker Service y elija Siguiente.
- En Nombre del proyecto, escriba AspireStorage.WorkerService y seleccione Siguiente.
- En la pantalla Información adicional:
- Asegúrese de que .NET 9.0 esté seleccionado.
- Asegúrese de que Enlist in .NET.NET Aspire orquestación esté activada y seleccione Crear.
Visual Studio agrega el proyecto a la solución y actualiza el archivo Program.cs del proyecto AspireStorage.AppHost con una nueva línea de código:
builder.AddProject<Projects.AspireStorage_WorkerService>(
"aspirestorage-workerservice");
La herramienta Visual Studio ha agregado esta línea de código para registrar su nuevo proyecto con el objeto IDistributedApplicationBuilder, lo que habilita funciones de orquestación. Para obtener más información, consulte .NET.NET Aspire visión general de orquestación.
La estructura de la solución completada debe ser similar a la siguiente:
Incorporación de las integraciones de .NET Aspire a la aplicación Blazor
Agregue los paquetes de integración de .NET AspireAzure Blob Storage y .NET AspireAzure Queue Storage, al proyecto AspireStorage.Web.
dotnet add package Aspire.Azure.Storage.Blobs
dotnet add package Aspire.Azure.Storage.Queues
El proyecto de AspireStorage.Web ahora está configurado para usar integraciones de .NET.NET Aspire. Aquí está el archivo AspireStorage.Web.csproj actualizado:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AspireStorage.ServiceDefaults\AspireStorage.ServiceDefaults.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Aspire.Azure.Storage.Blobs" Version="9.0.0" />
<PackageReference Include="Aspire.Azure.Storage.Queues" Version="9.0.0" />
</ItemGroup>
</Project>
El siguiente paso es agregar las integraciones a la aplicación.
En el archivo Program.cs del proyecto AspireStorage.Web, agregue llamadas a los métodos de extensión AddAzureBlobClient y AddAzureQueueClient después de la creación de builder
, pero antes de la llamada a AddServiceDefaults
. Para obtener más información, consulte .NET.NET Aspire configuraciones predeterminadas del servicio. Proporcione el nombre de la cadena de conexión como parámetro.
using AspireStorage.Web;
using AspireStorage.Web.Components;
using Azure.Storage.Blobs;
using Azure.Storage.Queues;
var builder = WebApplication.CreateBuilder(args);
builder.AddAzureBlobClient("BlobConnection");
builder.AddAzureQueueClient("QueueConnection");
// Add service defaults & Aspire components.
builder.AddServiceDefaults();
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
builder.Services.AddOutputCache();
builder.Services.AddHttpClient<WeatherApiClient>(client =>
{
// This URL uses "https+http://" to indicate HTTPS is preferred over HTTP.
// Learn more about service discovery scheme resolution at https://aka.ms/dotnet/sdschemes.
client.BaseAddress = new("https+http://apiservice");
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
else
{
// In development, create the blob container and queue if they don't exist.
var blobService = app.Services.GetRequiredService<BlobServiceClient>();
var docsContainer = blobService.GetBlobContainerClient("fileuploads");
await docsContainer.CreateIfNotExistsAsync();
var queueService = app.Services.GetRequiredService<QueueServiceClient>();
var queueClient = queueService.GetQueueClient("tickets");
await queueClient.CreateIfNotExistsAsync();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAntiforgery();
app.UseOutputCache();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
app.MapDefaultEndpoints();
app.Run();
using AspireStorage.Web;
using AspireStorage.Web.Components;
using Azure.Storage.Blobs;
using Azure.Storage.Queues;
var builder = WebApplication.CreateBuilder(args);
builder.AddAzureBlobClient("BlobConnection");
builder.AddAzureQueueClient("QueueConnection");
// Add service defaults & Aspire components.
builder.AddServiceDefaults();
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
builder.Services.AddOutputCache();
builder.Services.AddHttpClient<WeatherApiClient>(client =>
{
// This URL uses "https+http://" to indicate HTTPS is preferred over HTTP.
// Learn more about service discovery scheme resolution at https://aka.ms/dotnet/sdschemes.
client.BaseAddress = new("https+http://apiservice");
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAntiforgery();
app.UseOutputCache();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
app.MapDefaultEndpoints();
app.Run();
Con las instrucciones using
adicionales, estos métodos realizan las siguientes tareas:
- Registre un Azure.Storage.Blobs.BlobServiceClient y un Azure.Storage.Queues.QueueServiceClient con el contenedor de inserción de dependencias para conectarse a Azure Storage.
- Habilite automáticamente las comprobaciones de estado, el registro y la telemetría correspondientes para los servicios respectivos.
Cuando se inicie el proyecto de AspireStorage.Web, creará un contenedor de fileuploads
en Azurite Blob Storage y una cola de tickets
en Azurite Queue Storage. Esto es condicional cuando la aplicación se ejecuta en un entorno de desarrollo. Cuando la aplicación se ejecuta en un entorno de producción, se supone que el contenedor y la cola ya se han creado.
Agregue la integración de .NET Aspire al Worker Service
El servicio de procesamiento gestiona la extracción de mensajes de la cola de almacenamiento Azure para su procesamiento. Agregue el paquete de integración de
dotnet add package Aspire.Azure.Storage.Queues
En el archivo Program.cs del proyecto AspireStorage.WorkerService, agregue una llamada al método de extensión AddAzureQueueClient después de la creación del builder
, pero antes de la llamada a AddServiceDefaults
:
using AspireStorage.WorkerService;
var builder = Host.CreateApplicationBuilder(args);
builder.AddAzureQueueClient("QueueConnection");
builder.AddServiceDefaults();
builder.Services.AddHostedService<WorkerService>();
var host = builder.Build();
host.Run();
Este método controla las siguientes tareas:
- Registre un QueueServiceClient con el contenedor de inserción de dependencias para conectarse a Azure Storage Queues.
- Habilite automáticamente las comprobaciones de estado, el registro y la telemetría correspondientes para los servicios respectivos.
Creación del formulario
La aplicación requiere un formulario para que el usuario pueda enviar información de incidencias de soporte técnico y cargar datos adjuntos. La aplicación carga el archivo adjunto en la propiedad Document
(IFormFile) en Azure Blob Storage utilizando el BlobServiceClientinsertado. El QueueServiceClient envía un mensaje compuesto por el Title
y el Description
a la cola de almacenamiento Azure.
Use el siguiente marcado de Razor para crear un formulario básico, reemplazando el contenido del archivo de Home.razor en el directorio AspireStorage.Web/Components/Pages:
@page "/"
@using System.ComponentModel.DataAnnotations
@using Azure.Storage.Blobs
@using Azure.Storage.Queues
@inject BlobServiceClient BlobClient
@inject QueueServiceClient QueueServiceClient
<PageTitle>Home</PageTitle>
<div class="text-center">
<h1 class="display-4">Request Support</h1>
</div>
<EditForm Model="@Ticket" FormName="Tickets" method="post"
OnValidSubmit="@HandleValidSubmit" enctype="multipart/form-data">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="mb-4">
<label>Issue Title</label>
<InputText class="form-control" @bind-Value="@Ticket.Title" />
<ValidationMessage For="() => Ticket.Title" />
</div>
<div class="mb-4">
<label>Issue Description</label>
<InputText class="form-control" @bind-Value="@Ticket.Description" />
<ValidationMessage For="() => Ticket.Description" />
</div>
<div class="mb-4">
<label>Attachment</label>
<InputFile class="form-control" name="Ticket.Document" />
<ValidationMessage For="() => Ticket.Document" />
</div>
<button class="btn btn-primary" type="submit">Submit</button>
<button class="btn btn-danger mx-2" type="reset" @onclick=@ClearForm>Clear</button>
</EditForm>
@code {
[SupplyParameterFromForm(FormName = "Tickets")]
private SupportTicket Ticket { get; set; } = new();
private async Task HandleValidSubmit()
{
var docsContainer = BlobClient.GetBlobContainerClient("fileuploads");
// Upload file to blob storage
await docsContainer.UploadBlobAsync(
Ticket.Document.FileName,
Ticket.Document.OpenReadStream());
// Send message to queue
var queueClient = QueueServiceClient.GetQueueClient("tickets");
await queueClient.SendMessageAsync(
$"{Ticket.Title} - {Ticket.Description}");
ClearForm();
}
private void ClearForm() => Ticket = new();
private class SupportTicket()
{
[Required] public string Title { get; set; } = default!;
[Required] public string Description { get; set; } = default!;
[Required] public IFormFile Document { get; set; } = default!;
}
}
Para obtener más información sobre la creación de formularios en Blazor, vea ASP.NET CoreBlazor forms overview.
Actualización de AppHost
El proyecto AspireStorage.AppHost es el orquestador para tu app. Es responsable de conectar y configurar los diferentes proyectos y servicios de la aplicación. El orquestador debe ser configurado como proyecto de inicio.
Para agregar compatibilidad con el hospedaje de Azure Storage a la IDistributedApplicationBuilder, instale el 📦Aspire.Hosting.Azure.almacenamiento NuGet paquete.
dotnet add package Aspire.Hosting.Azure.Storage
Reemplace el contenido del archivo de Program.cs en el proyecto de AspireStorage.AppHost por el código siguiente:
using Microsoft.Extensions.Hosting;
var builder = DistributedApplication.CreateBuilder(args);
var storage = builder.AddAzureStorage("Storage");
if (builder.Environment.IsDevelopment())
{
storage.RunAsEmulator();
}
var blobs = storage.AddBlobs("BlobConnection");
var queues = storage.AddQueues("QueueConnection");
var apiService = builder.AddProject<Projects.AspireStorage_ApiService>("apiservice");
builder.AddProject<Projects.AspireStorage_Web>("webfrontend")
.WithExternalHttpEndpoints()
.WithReference(apiService)
.WithReference(blobs)
.WithReference(queues);
builder.AddProject<Projects.AspireStorage_WorkerService>("aspirestorage-workerservice")
.WithReference(queues);
builder.Build().Run();
El código mostrado anteriormente agrega almacenamiento de tipo Azure, así como blobs y colas, y en modo de desarrollo se utiliza el emulador. Cada proyecto define referencias para estos recursos de los que dependen.
using Microsoft.Extensions.Hosting;
var builder = DistributedApplication.CreateBuilder(args);
var storage = builder.AddAzureStorage("Storage");
var blobs = storage.AddBlobs("BlobConnection");
var queues = storage.AddQueues("QueueConnection");
var apiService = builder.AddProject<Projects.AspireStorage_ApiService>("apiservice");
builder.AddProject<Projects.AspireStorage_Web>("webfrontend")
.WithExternalHttpEndpoints()
.WithReference(apiService)
.WithReference(blobs)
.WithReference(queues);
builder.AddProject<Projects.AspireStorage_WorkerService>("aspirestorage-workerservice")
.WithReference(queues);
builder.Build().Run();
El código anterior agrega Azure almacenamiento, blobs y colas, y define referencias para estos recursos dentro de cada proyecto que dependa de ellos.
Procesar los elementos de la cola
Cuando se coloca un nuevo mensaje en la cola de tickets
, el servicio de trabajo debe recuperar, procesar y eliminar el mensaje. Actualice la clase Worker.cs y reemplace el contenido por el código siguiente:
using Azure.Storage.Queues;
using Azure.Storage.Queues.Models;
namespace AspireStorage.WorkerService;
public sealed class WorkerService(
QueueServiceClient client,
ILogger<WorkerService> logger) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var queueClient = client.GetQueueClient("tickets");
await queueClient.CreateIfNotExistsAsync(cancellationToken: stoppingToken);
while (!stoppingToken.IsCancellationRequested)
{
QueueMessage[] messages =
await queueClient.ReceiveMessagesAsync(
maxMessages: 25, cancellationToken: stoppingToken);
foreach (var message in messages)
{
logger.LogInformation(
"Message from queue: {Message}", message.MessageText);
await queueClient.DeleteMessageAsync(
message.MessageId,
message.PopReceipt,
cancellationToken: stoppingToken);
}
// TODO: Determine an appropriate time to wait
// before checking for more messages.
await Task.Delay(TimeSpan.FromSeconds(15), stoppingToken);
}
}
}
Para que el servicio de trabajo pueda procesar mensajes, debe poder conectarse a la cola de almacenamiento Azure. Con Azurite, debe asegurarse de que la cola está disponible antes de que el servicio de trabajo empiece a ejecutar el procesamiento de la cola de mensajes.
using Azure.Storage.Queues;
using Azure.Storage.Queues.Models;
namespace AspireStorage.WorkerService;
public sealed class WorkerService(
QueueServiceClient client,
ILogger<WorkerService> logger) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var queueClient = client.GetQueueClient("tickets");
while (!stoppingToken.IsCancellationRequested)
{
QueueMessage[] messages =
await queueClient.ReceiveMessagesAsync(
maxMessages: 25, cancellationToken: stoppingToken);
foreach (var message in messages)
{
logger.LogInformation(
"Message from queue: {Message}", message.MessageText);
await queueClient.DeleteMessageAsync(
message.MessageId,
message.PopReceipt,
cancellationToken: stoppingToken);
}
// TODO: Determine an appropriate time to wait
// before checking for more messages.
await Task.Delay(TimeSpan.FromSeconds(15), stoppingToken);
}
}
}
El servicio de trabajo procesa los mensajes conectándose a la cola de almacenamiento de Azure y extrayendo mensajes de la cola.
El servicio de trabajo procesa los mensajes en la cola y los elimina cuando se han procesado.
Configuración de las cadenas de conexión
Los proyectos AspireStorage y AspireStorage.Worker deben configurarse para conectarse a la cuenta de almacenamiento Azure correcta que creó anteriormente. Puede especificar los puntos de conexión para los servicios de blobs y colas en la cuenta de almacenamiento mediante el archivo appsettings.json de cada proyecto.
En el proyecto AspireStorage, agregue la siguiente configuración al archivo
appsettings.Development.json
:"ConnectionStrings": { "BlobConnection": "https://<your-storage-account-name>.blob.core.windows.net/", "QueueConnection": "https://<your-storage-account-name>.queue.core.windows.net/" }
En el proyecto AspireStorage.Worker, añada la siguiente configuración al archivo
appsettings.Development.json
:"ConnectionStrings": { "QueueConnection": "https://<your-storage-account-name>.queue.core.windows.net/" }
Ejecución y prueba local de la aplicación
La aplicación de ejemplo ya está lista para las pruebas. Compruebe que los datos del formulario enviado se envían a Azure Blob Storage y Azure Queue Storage completando los pasos siguientes:
Presione el botón Ejecutar situado en la parte superior de Visual Studio para iniciar el panel del proyecto de .NET Aspire en el explorador.
En la página de recursos, en la fila aspirestorage.web, haga clic en el enlace de la columna de Endpoints para abrir la interfaz de la aplicación.
Escriba datos de ejemplo en los campos de formulario
Title
yDescription
y seleccione un archivo sencillo para cargar.Seleccione la botón Enviar y el formulario envía la incidencia de soporte técnico para su procesamiento y borra el formulario.
En una pestaña independiente del navegador, use el portal de Azure para navegar al explorador de Storage en su cuenta de almacenamiento de Azure.
Seleccione Contenedores y, a continuación, acceda al contenedor de Documentos para ver el archivo cargado.
Puede comprobar que el mensaje de la cola se procesó examinando los registros de Project del panel de control .NET.NET Aspirey seleccionando el aspirestorage.workerservice en el menú desplegable.
Resumen
La aplicación de ejemplo que creó muestra los blobs persistentes de una aplicación web de ASP.NET CoreBlazor y las colas de procesamiento en un .NET Worker Service. La aplicación se conecta a Azure Storage mediante integraciones de .NET Aspire. La aplicación envía las incidencias de soporte técnico a una cola para su procesamiento y carga un archivo adjunto en el almacenamiento.
Puesto que decide usar Azurite, no es necesario limpiar estos recursos cuando haya terminado de probarlos, ya que los creó localmente en el contexto de un emulador. El emulador le permitió probar la aplicación localmente sin incurrir en ningún costo, ya que no se aprovisionaron ni crearon recursos Azure.
Limpieza de recursos
Ejecute el siguiente comando Azure CLI para eliminar el grupo de recursos cuando ya no necesite los recursos de Azure que creó. Al eliminar el grupo de recursos también se eliminan los recursos contenidos en él.
az group delete --name <your-resource-group-name>
Para obtener más información, consulte Limpieza de recursos en Azure.