Поделиться через


Руководство. Подключение приложения ASP.NET Core к интеграции с хранилищем .NET Aspire

Для облачных приложений часто требуются масштабируемые решения для хранения, которые предоставляют такие возможности, как хранилище BLOB-объектов, очереди или частично структурированные базы данных NoSQL. .NET Aspire интеграции упрощают подключения к различным службам хранилища, например Azure Blob Storage. В этом руководстве вы создадите приложение ASP.NET Core, использующее интеграции .NET Aspire для подключения к хранилищам очередей Azure Blob Storage и Azure для подачи заявок в службу поддержки. Приложение отправляет билеты в очередь для обработки и отправляет вложение в хранилище. Вы узнаете, как:

  • Создание базового приложения .NET, настроенного для использования интеграции .NET Aspire
  • Добавление интеграции .NET.NET Aspire для подключения к нескольким службам хранилища
  • Настройка и использование функций компонента .NET.NET Aspire для отправки и получения данных

Необходимые условия

Для работы с .NET.NET Aspireвам потребуется следующее, установленное локально:

Дополнительные сведения см. в разделе и материалах по средствам установки и инструментам, а также по пакету SDK.

Изучение готового примера приложения

Завершенная версия примера приложения из этого руководства доступна на GitHub. Проект также структурирован как шаблон для Azure Developer CLI, что означает, что вы можете использовать команду azd up для автоматизации развертывания ресурсов Azure, если у вас установлен инструмент .

git clone https://github.com/Azure-Samples/dotnet-aspire-connect-storage.git

Настройка ресурсов хранилища Azure

Для этой статьи вам потребуется доступ для работы с данными в учетной записи хранения Azure с контейнером BLOB и очередью хранения. Убедитесь, что доступны следующие ресурсы и конфигурации:

Для этой статьи вам нужно создать контейнер BLOB и ресурс очереди хранилища в локальной среде разработки с помощью эмулятора. Для этого используйте Azurite. Azurite — это бесплатный, с открытым исходным кодом, кроссплатформенный сервер, совместимый с API хранилища Azure (эмулятор), который работает в контейнере Docker.

Чтобы использовать эмулятор, необходимо установитьAzurite.

  1. Учетная запись для хранения — создание учетной записидля хранения .
  2. Контейнер хранилища BLOB-объектов с именем fileuploads - Создание контейнера хранилища BLOB-объектов.
  3. Очередь хранилища, названная , билетов - . Создание очереди хранилища.

Выполните следующие команды в интерфейсе командной строки Azure или CloudShell, чтобы настроить необходимые ресурсы хранилища Azure:

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

Кроме того, необходимо назначить следующие роли учетной записи пользователя, вошедшего в Visual Studio:

Azure Developer CLI позволяет подготавливать и развертывать ресурсы Azure с помощью системы шаблонов. В этом руководстве представлен полный шаблон, который подготавливает необходимые Azure ресурсы и включает полный пример кода приложения. Выполните следующие команды, чтобы инициализировать и запустить шаблон:

  1. Запустите azd auth login, чтобы войти в Azure.

    azd auth login
    
  2. Выполните azd init, чтобы клонировать и инициализировать пример шаблона:

    azd init --template dotnet-aspire-connect-storage
    
  3. Выполните azd up для настройки ресурсов Azure:

    azd up
    
  4. При появлении запроса выберите подписку и регион Azure для подготовленных ресурсов. Шаблон запускается и выполняет следующие задачи:

    • Создает учетную запись для хранения Azure с включенными службами BLOB и очередей.
    • Создает контейнер хранилища BLOB с именем fileUploads
    • Создает очередь с именем tickets
    • Назначает следующие роли учетной записи пользователя, которая запустила шаблон.
      • Вкладчик данных blob-объектов хранилища
      • Участник данных очереди хранилища

После успешного завершения операции у вас есть два варианта перехода вперед:

  • Вариант 1. Запустите пример приложения .NET в каталоге шаблонов src, чтобы экспериментировать с завершенным приложением.
  • Вариант 2. Создайте пример приложения шаг за шагом, используя следующие разделы, и подключите его к ресурсам Azure, предоставленным azd.

Создание примера решения

Создайте проект .NET Aspire с помощью Visual Studio или интерфейса командной строки .NET.

  1. В верхней части Visual Studioперейдите к File>New>Project.
  2. В окне диалога найдите Aspire и выберите .NET.NET Aspire Стартовое приложение. Выберите Далее.
  3. На экране Настройте ваш новый проект:
    • Введите имя решения для AspireStorage и выберите Далее.
  4. На экране Дополнительные сведения:
    • Снимите флажок Использовать Redis для кэширования (не требуется для этого руководства).
    • Выберите Создать.

Visual Studio создает новое решение ASP.NET Core, структурированное для использования .NET Aspire.

Решение состоит из следующих проектов:

  • AspireStorage.ApiService — проект API с конфигурациями служб .NET.NET Aspire по умолчанию.
  • AspireStorage.AppHost — оркестраторский проект, предназначенный для подключения и настройки различных проектов и служб вашего приложения. Оркестратор должен быть задан в качестве запускаемого проекта.
  • AspireStorage.ServiceDefaults — общая библиотека классов для хранения кода, который можно повторно использовать в проектах в решении.
  • AspireStorage.Web — проект BlazorServer, который служит фронтендом вашего приложения.

Добавление проекта Worker Service

Затем добавьте проект Worker Service в решение для извлечения и обработки сообщений по мере их добавления в очередь хранилища Azure.

  1. В обозревателе решений щелкните правой кнопкой мыши узел решения верхнего уровня AspireStorageи выберите Добавитьновый проект.
  2. Найдите и выберите шаблон Worker Service и выберите Далее.
  3. Для имени проекта введите AspireStorage.WorkerService и выберите Далее.
  4. На экране Дополнительные сведения:
    • Убедитесь, что выбран .NET 9.0.
    • Убедитесь, что регистрация в .NET.NET Aspire оркестрации отмечено, и выберите Создать.

Visual Studio добавляет проект в решение и обновляет файл Program.cs проекта AspireStorage.AppHost с новой строкой кода:

builder.AddProject<Projects.AspireStorage_WorkerService>(
    "aspirestorage-workerservice");

Visual Studio инструмент добавил эту строку кода для регистрации вашего нового проекта с объектом IDistributedApplicationBuilder, что обеспечивает возможности оркестрации. Дополнительные сведения см. в .NET.NET Aspire обзоре оркестрации.

Завершенная структура решения должна выглядеть следующим образом:

Снимок экрана, показывающий структуру примера решения для хранилища .NET.NET Aspire.

Добавление интеграции .NET Aspire в приложение Blazor

Добавьте интеграции и пакеты интеграции хранилища очередей в проект AspireStorage. Web:

dotnet add package Aspire.Azure.Storage.Blobs
dotnet add package Aspire.Azure.Storage.Queues

Теперь проект AspireStorage.Web настроен для использования интеграции .NET.NET Aspire. Ниже приведен обновленный файл AspireStorage.Web.csproj:

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

Следующим шагом является добавление интеграции в приложение.

В файле Program.cs проекта AspireStorage.Web добавьте вызовы методов расширения AddAzureBlobClient и AddAzureQueueClient после создания builder, но перед вызовом AddServiceDefaults. Для получения дополнительной информации см. настройки .NET.NET Aspire службы по умолчанию. Укажите имя строки подключения в качестве параметра.

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

С дополнительными операторами using эти методы выполняют следующие задачи:

  • Зарегистрируйте Azure.Storage.Blobs.BlobServiceClient и Azure.Storage.Queues.QueueServiceClient в контейнере DI для подключения к хранилищу Azure.
  • Автоматически включите соответствующие проверки работоспособности, ведение журнала и телеметрию для соответствующих служб.

При запуске проекта AspireStorage.Web он создаст контейнер fileuploads в хранилище BLOB-объектов Azurite и очередь tickets в хранилище очередей Azurite. Это условно, если приложение работает в среде разработки. Если приложение запущено в рабочей среде, предполагается, что контейнер и очередь уже созданы.

Добавление интеграции .NET Aspire в Worker Service

Рабочая служба занимается извлечением сообщений из очереди хранилища Azure для обработки. Добавьте пакет интеграции хранилища очередей .NET AspireAzure в приложение AspireStorage.WorkerService:

dotnet add package Aspire.Azure.Storage.Queues

В файле Program.cs проекта AspireStorage.WorkerService добавьте вызов метода расширения AddAzureQueueClient после создания builder, но перед вызовом AddServiceDefaults.

using AspireStorage.WorkerService;

var builder = Host.CreateApplicationBuilder(args);

builder.AddAzureQueueClient("QueueConnection");

builder.AddServiceDefaults();
builder.Services.AddHostedService<WorkerService>();

var host = builder.Build();
host.Run();

Этот метод обрабатывает следующие задачи:

  • Зарегистрируйте QueueServiceClient в контейнере DI для подключения к Azure Storage Queues.
  • Автоматически включите соответствующие проверки работоспособности, ведение журнала и телеметрию для соответствующих служб.

Создание формы

Приложению требуется форма для того, чтобы пользователь мог отправлять сведения о запросе в службу поддержки и отправлять вложение. Приложение загружает вложенный файл на свойство Document (IFormFile) в Azure Blob Storage с помощью внедренного BlobServiceClient. QueueServiceClient отправляет сообщение, состоящее из Title и Description в очередь хранилища Azure.

Используйте следующую разметку Razor для создания базовой формы, заменив содержимое файла Home.razor в каталоге 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!;
    }
}

См. подробный обзор форм в для дополнительных сведений о создании форм в .

Обновите AppHost

Проект AspireStorage.AppHost является координатором для вашего приложения. Он отвечает за подключение и настройку различных проектов и служб приложения. Оркестратор должен быть задан в качестве запускаемого проекта.

Чтобы добавить поддержку размещения Azure Storage в IDistributedApplicationBuilder, установите 📦Aspire.Hosting.Azure.Storage NuGet-пакет.

dotnet add package Aspire.Hosting.Azure.Storage

Замените содержимое файла Program.cs в проекте AspireStorage.AppHost следующим кодом:

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

Предыдущий код добавляет хранилище Azure, большие двоичные объекты и очереди, и когда используется в режиме разработки, он применяет эмулятор. Каждый проект определяет ссылки на эти ресурсы, от которых они зависят.

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

Приведенный выше код добавляет Azure хранилище, большие двоичные объекты и очереди, а также определяет ссылки на эти ресурсы в каждом проекте, который зависит от них.

Обработайте элементы в очереди

Когда новое сообщение помещается в очередь tickets, рабочая служба должна получить, обработать и удалить сообщение. Обновите класс Worker.cs, заменив содержимое следующим кодом:

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

Прежде чем рабочая служба сможет обработать сообщения, необходимо подключиться к очереди хранилища Azure. Используя Azurite, необходимо убедиться, что очередь доступна, прежде чем рабочая служба начнет выполнять обработку очереди сообщений.

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

Рабочая служба обрабатывает сообщения, подключаясь к очереди хранилища Azure и извлекая сообщения из очереди.

Рабочая служба обрабатывает сообщения в очереди и удаляет их после обработки.

Настройка строк подключения

Проекты и AspireStorage.Worker должны быть настроены для подключения к правильной учетной записи хранения Azure, созданной ранее. Конечные точки для служб BLOB-объектов и очередей можно указать в учетной записи хранения с помощью файла appsettings.json в каждом проекте.

  1. В проекте AspireStorage добавьте следующую конфигурацию в файл appsettings.Development.json:

      "ConnectionStrings": {
        "BlobConnection": "https://<your-storage-account-name>.blob.core.windows.net/",
        "QueueConnection": "https://<your-storage-account-name>.queue.core.windows.net/"
      }
    
  2. В проекте AspireStorage.Worker добавьте следующую конфигурацию в файл appsettings.Development.json:

      "ConnectionStrings": {
        "QueueConnection": "https://<your-storage-account-name>.queue.core.windows.net/"
      }
    

Запуск и тестирование приложения локально

Пример приложения теперь готов к тестированию. Убедитесь, что отправленные данные формы отправляются в Azure Blob Storage и Azure хранилище очередей, выполнив следующие действия.

  1. Нажмите кнопку запуска в верхней части Visual Studio, чтобы запустить панель мониторинга проекта .NET Aspire в браузере.

  2. На странице ресурсов в строке aspirestorage.web нажмите ссылку в столбце Точки доступа, чтобы открыть пользовательский интерфейс вашего приложения.

    Снимок экрана с домашней страницей приложения поддержки .NET.NET Aspire.

  3. Введите примеры данных в поля формы Title и Description и выберите простой файл для отправки.

  4. Нажмите кнопку Отправить, а форма отправляет запрос в службу поддержки для обработки и очищает форму.

  5. На отдельной вкладке браузера используйте портал , чтобы перейти к браузера хранилища в учетной записи хранения .

  6. Выберите контейнеры , а затем перейдите в контейнер документов, чтобы увидеть загруженный файл.

  7. Вы можете проверить сообщение в очереди, просмотрев журналы Project.NET.NET Aspire панели мониторингаи выбрав aspirestorage.workerservice в раскрывающемся списке.

    Снимок экрана: выходные данные консоли рабочего приложения.

Сводка

Пример приложения, созданного вами, демонстрирует сохранение больших двоичных объектов из веб-приложения ASP.NET CoreBlazor и обработку очередей в .NET Worker Service. Приложение подключается к хранилищу Azure с помощью интеграции .NET Aspire. Приложение отправляет заявки в службу поддержки в очередь для обработки и загружает вложение в хранилище.

Так как вы решили использовать Azurite, не нужно очищать эти ресурсы при выполнении тестирования, так как вы создали их локально в контексте эмулятора. Эмулятор позволяет протестировать приложение локально без каких-либо затрат, так как Azure ресурсы не были подготовлены или созданы.

Очистка ресурсов

Выполните следующую команду Azure CLI, чтобы удалить группу ресурсов, если вам больше не нужны созданные ресурсы Azure. При удалении группы ресурсов также удаляются ресурсы, содержащиеся в нем.

az group delete --name <your-resource-group-name>

Дополнительные сведения см. в разделе Очистка ресурсов в Azure.