Skip to content

Latest commit

 

History

History
402 lines (252 loc) · 20.4 KB

azure-storage-components.md

File metadata and controls

402 lines (252 loc) · 20.4 KB
title description ms.date ms.topic zone_pivot_groups ms.custom
Connect an ASP.NET Core app to .NET Aspire storage components
Learn how to connect an ASP.NET Core app to .NET Aspire storage components.
06/05/2024
tutorial
azure-storage-mechanism
devx-track-extended-azdevcli

Tutorial: Connect an ASP.NET Core app to .NET Aspire storage components

Cloud-native apps often require scalable storage solutions that provide capabilities like blob storage, queues, or semi-structured NoSQL databases. .NET Aspire components simplify connections to various storage services, such as Azure Blob Storage. In this tutorial, you'll create an ASP.NET Core app that uses .NET Aspire components to connect to Azure Blob Storage and Azure Queue Storage to submit support tickets. The app sends the tickets to a queue for processing and uploads an attachment to storage. You'll learn how to:

[!div class="checklist"]

  • Create a basic .NET app that is set up to use .NET Aspire components
  • Add .NET Aspire components to connect to multiple storage services
  • Configure and use .NET Aspire Component features to send and receive data

[!INCLUDE aspire-prereqs]

Explore the completed sample app

A completed version of the sample app from this tutorial is available on GitHub. The project is also structured as a template for the Azure Developer CLI, meaning you can use the azd up command to automate Azure resource provisioning if you have the tool installed.

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

Set up the Azure Storage resources

:::zone pivot="azure-portal,azure-cli"

For this article, you'll need data contributor access to an Azure Storage account with a blob container and storage queue. Ensure you have the following resources and configurations available:

:::zone-end

:::zone pivot="azurite"

For this article, you'll need to create a blob container and storage queue resource in your local development environment using an emulator. To do so, use Azurite. Azurite is a free, open source, cross-platform Azure Storage API compatible server (emulator) that runs in a Docker container.

To use the emulator you need to install Azurite.

:::zone-end :::zone pivot="azure-portal"

  1. An Azure Storage account - Create a storage account.
  2. A Blob Storage container named fileuploads - Create a blob storage container.
  3. A Storage Queue named tickets - Create a storage queue.

:::zone-end :::zone pivot="azure-cli"

Run the following commands in the Azure CLI or CloudShell to set up the required Azure Storage resources:

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

:::zone-end :::zone pivot="azure-portal,azure-cli"

You also need to assign the following roles to the user account you are logged into Visual Studio with:

:::zone-end :::zone pivot="azure-developer-cli"

The Azure Developer CLI enables you to provision and deploy Azure resources using a template system. This tutorial provides a complete template that provisions the required Azure resources and includes the completed sample application code. Run the following commands to initialize and run the template:

  1. Run azd auth login to sign-in to Azure:

    azd auth login
    
  2. Run azd init to clone and initialize the sample template:

    azd init --template dotnet-aspire-connect-storage
    
  3. Run azd up to provision the Azure resources:

    azd up
    
  4. When prompted, select the subscription and Azure region for the provisioned resources. The template runs and completes the following tasks for you:

    • Creates an Azure Storage Account with blob and queue services enabled
    • Creates a blob storage container named fileUploads
    • Creates a queue named tickets
    • Assigns the following roles to the user account that ran the template.
      • Storage Blob Data Contributor
      • Storage Queue Data Contributor

After the operation completes successfully, you have two options moving forward:

  • Option 1: Run the .NET sample app in the template src directory to experiment with the completed app.
  • Option 2: Build the sample app step by step using the sections ahead and connect it to the Azure resources provisioned by azd.

:::zone-end

Create the sample solution

Create a .NET Aspire project using either Visual Studio or the .NET CLI.

  1. At the top of Visual Studio, navigate to File > New > Project.
  2. In the dialog window, search for Aspire and select .NET Aspire Starter Application. Choose Next.
  3. On the Configure your new project screen:
    • Enter a Solution Name of AspireStorage and select Next.
  4. On the Additional information screen:
    • Uncheck Use Redis for caching (not required for this tutorial).
    • Select Create.

Visual Studio creates a new ASP.NET Core solution that is structured to use .NET Aspire.

Use the dotnet new command to create a new .NET Aspire project:

dotnet new aspire-starter --name AspireStorage

The solution consists of the following projects:

  • AspireStorage.ApiService - An API project with default .NET Aspire service configurations.
  • AspireStorage.AppHost - An orchestrator project designed to connect and configure the different projects and services of your app. The orchestrator should be set as the startup project.
  • AspireStorage.ServiceDefaults - A shared class library to hold code that can be reused across the projects in your solution.
  • AspireStorage.Web - A Blazor Server project that serves as the front end of your app.

Add the Worker Service project

Next, add a Worker Service project to the solution to retrieve and process messages as they are added to the Azure Storage queue.

  1. In the solution explorer, right click on the top level AspireStorage solution node and select Add > New project.
  2. Search for and select the Worker Service template and choose Next.
  3. For the Project name, enter AspireStorage.WorkerService and select Next.
  4. On the Additional information screen:
    • Make sure .NET 8.0 is selected.
    • Make sure Enlist in .NET Aspire orchestration is checked and select Create.

Visual Studio adds the project to your solution and updates the :::no-loc text="Program.cs"::: file of the AspireStorage.AppHost project with a new line of code:

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

Visual Studio tooling added this line of code to register your new project with the xref:Aspire.Hosting.IDistributedApplicationBuilder object, which enables orchestration features. For more information, see .NET Aspire orchestration overview.

  1. In the root directory of the app, use the dotnet new command to create a new Worker Service app:

    dotnet new worker --name AspireStorage.WorkerService
    
  2. Use the dotnet sln command to add the project to the solution:

    dotnet sln AspireStorage.sln add AspireStorage.WorkerService/AspireStorage.WorkerService.csproj
    
  3. Use the dotnet add reference command to add project reference between the .AppHost and .WorkerService project:

    dotnet add AspireStorage.AppHost/AspireStorage.AppHost.csproj reference AspireStorage.WorkerService/AspireStorage.WorkerService.csproj
    
  4. Add the following line of code to the :::no-loc text="Program.cs"::: file in the AspireStorage.AppHost project:

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

The completed solution structure should resemble the following:

:::image type="content" loc-scope="visual-studio" source="media/storage-project.png" alt-text="A screenshot showing the structure of the .NET Aspire storage sample solution.":::

Add the .NET Aspire components to the Blazor app

Add the .NET Aspire Azure Blob Storage component and .NET Aspire Azure Queue Storage component packages to your AspireStorage.Web project:

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

Your AspireStorage.Web project is now set up to use .NET Aspire components. Here's the updated AspireStorage.Web.csproj file:

:::code language="xml" source="snippets/tutorial/AspireStorage/AspireStorage.Web/AspireStorage.Web.csproj" highlight="14-15":::

The next step is to add the components to the app.

In the :::no-loc text="Program.cs"::: file of the AspireStorage.Web project, add calls to the xref:Microsoft.Extensions.Hosting.AspireBlobStorageExtensions.AddAzureBlobClient%2A and xref:Microsoft.Extensions.Hosting.AspireQueueStorageExtensions.AddAzureQueueClient%2A extension methods after the creation of the builder but before the call to AddServiceDefaults. For more information, see .NET Aspire service defaults. Provide the name of your connection string as a parameter.

:::zone pivot="azurite"

:::code source="snippets/tutorial/AspireStorage/AspireStorage.Web/Program.cs" highlight="4-5,9-10,36-48":::

:::zone-end :::zone pivot="azure-portal,azure-cli"

:::code source="snippets/tutorial/AspireStorage/AspireStorage.Web/Program.cs" range="1-35,49-63" highlight="2-3,7-8":::

:::zone-end

With the additional using statements, these methods accomplish the following tasks:

  • Register a xref:Azure.Storage.Blobs.BlobServiceClient?displayProperty=fullName and a xref:Azure.Storage.Queues.QueueServiceClient?displayProperty=fullName with the DI container for connecting to Azure Storage.
  • Automatically enable corresponding health checks, logging, and telemetry for the respective services.

:::zone pivot="azurite"

When the AspireStorage.Web project starts, it will create a fileuploads container in Azurite Blob Storage and a tickets queue in Azurite Queue Storage. This is conditional when the app is running in a development environment. When the app is running in a production environment, the container and queue are assumed to have already been created.

:::zone-end

Add the .NET Aspire component to the Worker Service

The worker service handles pulling messages off of the Azure Storage queue for processing. Add the .NET Aspire Azure Queue Storage component component package to your AspireStorage.WorkerService app:

dotnet add package Aspire.Azure.Storage.Queues

In the :::no-loc text="Program.cs"::: file of the AspireStorage.WorkerService project, add a call to the xref:Microsoft.Extensions.Hosting.AspireQueueStorageExtensions.AddAzureQueueClient%2A extension method after the creation of the builder but before the call to AddServiceDefaults:

:::code source="snippets/tutorial/AspireStorage/AspireStorage.WorkerService/Program.cs" highlight="5":::

This method handles the following tasks:

  • Register a xref:Azure.Storage.Queues.QueueServiceClient with the DI container for connecting to Azure Storage Queues.
  • Automatically enable corresponding health checks, logging, and telemetry for the respective services.

Create the form

The app requires a form for the user to be able to submit support ticket information and upload an attachment. The app uploads the attached file on the Document (xref:Microsoft.AspNetCore.Http.IFormFile) property to Azure Blob Storage using the injected xref:Azure.Storage.Blobs.BlobServiceClient. The xref:Azure.Storage.Queues.QueueServiceClient sends a message composed of the Title and Description to the Azure Storage Queue.

Use the following Razor markup to create a basic form, replacing the contents of the Home.razor file in the AspireStorage.Web/Components/Pages directory:

:::code language="razor" source="snippets/tutorial/AspireStorage/AspireStorage.Web/Components/Pages/Home.razor":::

For more information about creating forms in Blazor, see ASP.NET Core Blazor forms overview.

Update the AppHost

The AspireStorage.AppHost project is the orchestrator for your app. It's responsible for connecting and configuring the different projects and services of your app. The orchestrator should be set as the startup project.

To add Azure Storage hosting support to your xref:Aspire.Hosting.IDistributedApplicationBuilder, install the Aspire.Hosting.Azure.Storage NuGet package.

dotnet add package Aspire.Hosting.Azure.Storage
<PackageReference Include="Aspire.Hosting.Azure.Storage"
                  Version="[SelectVersion]" />

Replace the contents of the :::no-loc text="Program.cs"::: file in the AspireStorage.AppHost project with the following code:

:::zone pivot="azurite"

:::code source="snippets/tutorial/AspireStorage/AspireStorage.AppHost/Program.cs":::

The preceding code adds Azure storage, blobs, and queues, and when in development mode, it uses the emulator. Each project defines references for these resources that they depend on.

:::zone-end :::zone pivot="azure-portal,azure-cli"

:::code source="snippets/tutorial/AspireStorage/AspireStorage.AppHost/Program.cs" range="1-6,12-27":::

The preceding code adds Azure storage, blobs, and queues, and defines references for these resources within each project that depend on them.

:::zone-end

Process the items in the queue

When a new message is placed on the tickets queue, the worker service should retrieve, process, and delete the message. Update the Worker.cs class, replacing the contents with the following code:

:::zone pivot="azurite"

:::code source="snippets/tutorial/AspireStorage/AspireStorage.WorkerService/Worker.cs":::

Before the worker service can process messages, it needs to be able to connect to the Azure Storage queue. With Azurite, you need to ensure that the queue is available before the worker service starts executing message queue processing.

:::zone-end :::zone pivot="azure-portal,azure-cli"

:::code source="snippets/tutorial/AspireStorage/AspireStorage.WorkerService/Worker.cs" range="1-12,15-37":::

The worker service processes messages by connecting to the Azure Storage queue, and pulling messages off the queue.

:::zone-end

The worker service processes message in the queue and deletes them when they've been processed.

:::zone pivot="azure-portal,azure-cli,azure-developer-cli"

Configure the connection strings

The AspireStorage and AspireStorage.Worker projects must be configured to connect to the correct Azure Storage Account you created earlier. You can specify the endpoints for the blob and queue services in the storage account using the :::no-loc text="appsettings.json"::: file in each project.

  1. In the AspireStorage project, add the following configuration to the appsettings.Development.json file:

      "ConnectionStrings": {
        "BlobConnection": "https://<your-storage-account-name>.blob.core.windows.net/",
        "QueueConnection": "https://<your-storage-account-name>.queue.core.windows.net/"
      }
  2. In the AspireStorage.Worker project, add the following configuration to the appsettings.Development.json file:

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

:::zone-end

Run and test the app locally

The sample app is now ready for testing. Verify that the submitted form data is sent to Azure Blob Storage and Azure Queue Storage by completing the following steps:

  1. Press the run button at the top of Visual Studio to launch your .NET Aspire project dashboard in the browser.

  2. On the resources page, in the aspirestorage.web row, click the link in the Endpoints column to open the UI of your app.

    :::image type="content" source="media/support-app.png" lightbox="media/support-app.png" alt-text="A screenshot showing the home page of the .NET Aspire support application.":::

  3. Enter sample data into the Title and Description form fields and select a simple file to upload.

  4. Select the Submit button, and the form submits the support ticket for processing — and clears the form.

  5. In a separate browser tab, use the Azure portal to navigate to the Storage browser in your Azure Storage Account.

  6. Select Containers and then navigate into the Documents container to see the uploaded file.

  7. You can verify the message on the queue was processed by looking at the Project logs of the .NET Aspire dashboard, and selecting the aspirestorage.workerservice from the dropdown.

    :::image type="content" source="media/queue-output.png" lightbox="media/queue-output.png" alt-text="A screenshot showing the console output of the Worker app.":::

  1. In a terminal window at the root of your project, use the dotnet run command to start the app:

    dotnet run --project AspireStorage.AppHost
    
  2. On the resources page, in the aspirestorage row, click the link in the Endpoints column to open the UI of your app.

    :::image type="content" source="media/support-app.png" lightbox="media/support-app.png" alt-text="A screenshot showing the home page of the .NET Aspire support application.":::

  3. Enter sample data into the Title and Description form fields and select a simple file to upload.

  4. Select the Submit button, and the form submits the support ticket for processing — and clears the form.

  5. In a separate browser tab, use the Azure portal to navigate to the Storage browser in your Azure Storage Account.

  6. Select Containers and then navigate into the Documents container to see the uploaded file.

  7. You can verify the message on the queue was processed by looking at the Project logs of the .NET Aspire dashboard, and selecting the aspirestorage.workerservice from the dropdown.

    :::image type="content" source="media/queue-output.png" lightbox="media/queue-output.png" alt-text="A screenshot showing the console output of the Worker app.":::


Summary

The example app that you built demonstrates persisting blobs from an ASP.NET Core Blazor Web App and processing queues in a .NET Worker Service. Your app connects to Azure Storage using .NET Aspire components. The app sends the support tickets to a queue for processing and uploads an attachment to storage.

:::zone pivot="azurite"

Since you choose to use Azurite, there's no need to clean up these resources when you're done testing them, as you created them locally in the context of an emulator. The emulator enabled you to test your app locally without incurring any costs, as no Azure resources were provisioned or created.

:::zone-end :::zone pivot="azure-portal,azure-cli"

[!INCLUDE clean-up-resources]

:::zone-end