ASP.NET Core – How To Create A Development Environment For Using Azure Queue Storage Using The ASP.NET Core Framework.
Azure Queue Storage is one of Microsoft’s solutions for messaging and can be a very powerful tool for inter-process communications, and event triggers. In this demonstration we will be creating an ASP.NET Core MVC Web Application. That web application is going to display the contents of a message log blob. It will also allow the user to send a message to the storage queue. We will also be creating an Azure Functions project from a Queue Trigger. The trigger will take the content of the message and append it to the Azure Storage blob.
In this tutorial we will:
-
-
- Create a development container with C# and Azurite (to emulate Azure Storage). The container will also have the tools needed to create Azure Function Projects.
- Confirm connectivity to Azurite
- Create a new C# solution
- Create an MVC Web Application
- Create an Azure Functions Project
- Configure Debugging for both the Web Application and Functions Project
- Build out the Functions Project
- Build out the Web Application
- Test the Web Application
-
Create a Development Container with C# and Azurite
-
1 – Create a new folder on your computer. I will be calling mine “azure-queue-storage-demo”
2 – Open the folder with Visual Studio Code.
3 – Create a .devcontainer folder
4 – Create a Dockerfile within that .devcontainer folder.
Give it the following code:
# [Choice] .NET version: 6.0-focal, 3.1-focal
ARG VARIANT="6.0-focal"
FROM mcr.microsoft.com/vscode/devcontainers/dotnet:0-${VARIANT}
# [Choice] Node.js version: none, lts/*, 18, 16, 14
ARG NODE_VERSION="none"
RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>
# [Optional] Uncomment this line to install global node packages.
RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g azure-functions-core-tools@4 --unsafe-perm true" 2>&1
-
5 – Create a docker-compose.yml file in that .devcontainer folder.
Give it the following code:
version: '3'
services:
app:
build:
context: .
dockerfile: Dockerfile
args:
# Update 'VARIANT' to pick a version of .NET: 3.1-focal, 6.0-focal
VARIANT: "6.0-focal"
# Optional version of Node.js
NODE_VERSION: "lts/*"
volumes:
- ..:/workspace:cached
# Overrides default command so things don't shut down after the process ends.
command: sleep infinity
# Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function.
network_mode: service:azurite
# Uncomment the next line to use a non-root user for all processes.
# user: vscode
# Use "forwardPorts" in **devcontainer.json** to forward an app port locally.
# (Adding the "ports" property to this file will not forward from a Codespace.)
azurite:
image: mcr.microsoft.com/azure-storage/azurite
restart: unless-stopped
command: "azurite -d /opt/azurite/azurite_logs.txt"
# Add "forwardPorts": ["1433"] to **devcontainer.json** to forward MSSQL locally.
# (Adding the "ports" property to this file will not forward from a Codespace.)
-
6 – Create a devcontainer.json file in that .devcontainer folder.
Give it the following code:
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.238.0/containers/dotnet-mssql
{
"name": "C# (.NET) and Azurite",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Set *default* container specific settings.json values on container create.
"settings": {},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"ms-dotnettools.csharp",
"ms-azuretools.vscode-azurefunctions"
]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [10000, 10001, 10002],
// [Optional] To reuse of your local HTTPS dev cert:
//
// 1. Export it locally using this command:
// * Windows PowerShell:
// dotnet dev-certs https --trust; dotnet dev-certs https -ep "$env:USERPROFILE/.aspnet/https/aspnetapp.pfx" -p "SecurePwdGoesHere"
// * macOS/Linux terminal:
// dotnet dev-certs https --trust; dotnet dev-certs https -ep "${HOME}/.aspnet/https/aspnetapp.pfx" -p "SecurePwdGoesHere"
//
// 2. Uncomment these 'remoteEnv' lines:
// "remoteEnv": {
// "ASPNETCORE_Kestrel__Certificates__Default__Password": "SecurePwdGoesHere",
// "ASPNETCORE_Kestrel__Certificates__Default__Path": "/home/vscode/.aspnet/https/aspnetapp.pfx",
// },
//
// 3. Next, copy your certificate into the container:
// 1. Start the container
// 2. Drag ~/.aspnet/https/aspnetapp.pfx into the root of the file explorer
// 3. Open a terminal in VS Code and run "mkdir -p /home/vscode/.aspnet/https && mv aspnetapp.pfx /home/vscode/.aspnet/https"
// postCreateCommand.sh parameters: $1=SA password, $2=dacpac path, $3=sql script(s) path
"features": {
"github-cli": "latest",
"azure-cli": "latest"
}
}
- We are adding the csarp plug-in (OmniSharp) as well as the AzureFunctions tool to allow us to be able to debug functions in our development environment.
- We are forwarding ports 10000, 10001, 10002 which are the Azureite services Blob, Queue, and Table services. Making it so that we can access those items from the Azure Storage Explorer Via our local computer.
- We have also instead the latest github and azure command line interfaces.
This should be sufficient to setup a development environment to run and debug our app as well as have Azurite run as a service in a separate container that both our local machine, and app container can access.
Open the command pallet (CTRL+SHIFT+P) and select the “Remote-Containers: Rebuild and Reopen in Container” option.
Confirm Connectivity to Azurite
Launch the Azure Storage Explorer on your computer.
According to https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azurite the default HTTP Connection string is:
DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;TableEndpoint=http://127.0.0.1:10002/devstoreaccount1;
-
1 – Right-click on Storage Accounts and click on Connect to Azure Storage.
2 – Select that you want to connect to a Storage account or service.
-
3 – Select connection string
4 – Give it a display name such as “Dev Container”, and then copy and paste the connection string from above.
-
5 – Click on Next, and then click on Connect.
You will now see the storage account in your available connections.
Double click on it and perform any experiments that you like.
Create a new C# Solution
We will now create a solution file to hold information about all of our projects.
Open a new terminal in Visual Studio Code (CTRL+SHIFT+`) and execute the following commands:
dotnet new sln
mv workspace.sln azure-queue-storage-demo.sln
Create an MVC Web Application
The web application will display the Blob Content and Send Messages to the Queue.
Execute the following commands, assuming that you are still in the /workspace directory:
dotnet new mvc -o AzureQueueStorageDemo.Web
dotnet sln add ./AzureQueueStorageDemo.Web/
dotnet dev-certs https --trust
Select the option to Restart OmniSharp.
When prompted say “Yes” to add the Debug files.
Create an Azure Functions Project
The azure functions project will be monitoring the Queue Storage, and executing tasks when the messages come in.
Execute the following commands, assuming that you are still in the /workspace directory:
mkdir AzureQueueStorageDemo.AzureFunctions
cd AzureQueueStorageDemo.AzureFunctions/
func init (select options 1, and 1)
Execute the following commands, assuming that you are still in the /workspace/AzureQueueStorageDemo.AzureFunction/ directory:
func new (select options 1, give it the name of AddMessageLogRequest)
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;TableEndpoint=http://127.0.0.1:10002/devstoreaccount1;",
"FUNCTIONS_WORKER_RUNTIME": "dotnet"
}
}
func start
Open the AddMessageLogRequest.cs file.
You can see that all it is doing at this time is looking for messages to be sent to the “myqueue-items” message queue and then log that the function was processed and give the message content.
Open your storage explorer.
Go to the storage account associated with the Dev Container. Create a queue named “myqueue-items”. And then send a message and you will see that your terminal notices that a message has been received.
Press CTRL + C to exit out of the function.
You can even create a bunch of messages while the trigger is shut down, and then turn the trigger back on with the func start command, and then all of the unprocessed messages will be processed once you start the functions up again.
Now that we have confirmed that we have a valid queue function. Let’s go ahead and setup our debugger and start logging the messages that we receive to a Blob in Blob storage.
Configure Debugging for both the Web Application and Functions Project
Earlier when you restarted OmniSharp and said Yes to add the Debug files it should have created a .vscode folder with a launch.json and tasks.json files.
To the Tasks.json add the following code to clean, and build the Azure Functions after the “watch” label key:
{
"label": "clean (functions)",
"options": {
"cwd": "${workspaceFolder}/AzureQueueStorageDemo.AzureFunctions"
},
"command": "dotnet",
"args": [
"clean",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"type": "process",
"problemMatcher": "$msCompile"
},
{
"label": "build (functions)",
"options": {
"cwd": "${workspaceFolder}/AzureQueueStorageDemo.AzureFunctions"
},
"command": "dotnet",
"args": [
"build",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"type": "process",
"dependsOn": "clean (functions)",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": "$msCompile"
},
{
"type": "func",
"dependsOn": "build (functions)",
"options": {
"cwd": "${workspaceFolder}/AzureQueueStorageDemo.AzureFunctions/bin/Debug/net6.0"
},
"command": "host start",
"isBackground": true,
"problemMatcher": "$func-dotnet-watch"
}
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/AzureQueueStorageDemo.Web/AzureQueueStorageDemo.Web.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/AzureQueueStorageDemo.Web/AzureQueueStorageDemo.Web.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/AzureQueueStorageDemo.Web/AzureQueueStorageDemo.Web.csproj"
],
"problemMatcher": "$msCompile"
},
{
"label": "clean (functions)",
"options": {
"cwd": "${workspaceFolder}/AzureQueueStorageDemo.AzureFunctions"
},
"command": "dotnet",
"args": [
"clean",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"type": "process",
"problemMatcher": "$msCompile"
},
{
"label": "build (functions)",
"options": {
"cwd": "${workspaceFolder}/AzureQueueStorageDemo.AzureFunctions"
},
"command": "dotnet",
"args": [
"build",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"type": "process",
"dependsOn": "clean (functions)",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": "$msCompile"
},
{
"type": "func",
"dependsOn": "build (functions)",
"options": {
"cwd": "${workspaceFolder}/AzureQueueStorageDemo.AzureFunctions/bin/Debug/net6.0"
},
"command": "host start",
"isBackground": true,
"problemMatcher": "$func-dotnet-watch"
}
]
}
{
"name": "Attach to .NET Functions",
"type": "coreclr",
"request": "attach",
"processId": "${command:azureFunctions.pickProcess}"
},
"compounds": [
{
"name": "Attach to functions and launch web app",
"configurations": [".NET Core Launch (web)", "Attach to .NET Functions"],
"stopAll": true
}
]
{
"version": "0.2.0",
"configurations": [
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"name": ".NET Core Launch (web)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/AzureQueueStorageDemo.Web/bin/Debug/net6.0/AzureQueueStorageDemo.Web.dll",
"args": [],
"cwd": "${workspaceFolder}/AzureQueueStorageDemo.Web",
"stopAtEntry": false,
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
"serverReadyAction": {
"action": "openExternally",
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"sourceFileMap": {
"/Views": "${workspaceFolder}/Views"
}
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
},
{
"name": "Attach to .NET Functions",
"type": "coreclr",
"request": "attach",
"processId": "${command:azureFunctions.pickProcess}"
},
],
"compounds": [
{
"name": "Attach to functions and launch web app",
"configurations": [".NET Core Launch (web)", "Attach to .NET Functions"],
"stopAll": true
}
]
}
You also still have the option of only debugging one at a time as well. Look at the debug area, and when you click the drop down you will see four different options to select from when debugging. Which ever one is in the drop down is what F5 will use.
Build out the Functions Project
Dependency injection is sort of a foreign concept to the functions projects out of the box. Luckily it is still available to be used. Let’s add some packages to get started.
At the /workspace/AzureQueueStorageDemo.AzureFunctions/ directory, execute the following commands:
dotnet add package Microsoft.Azure.Functions.Extensions
dotnet add package Microsoft.Extensions.DependencyInjection
dotnet add package Microsoft.Extensions.Azure
dotnet add package Azure.Identity
dotnet add package Azure.Storage.Blobs
Give it the following code:
using Azure.Identity;
using Microsoft.Extensions.Azure;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
[assembly: FunctionsStartup(typeof(AzureQueueStorageDemo.Startup))]
namespace AzureQueueStorageDemo;
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddAzureClients(azureClientsBuilder => {
azureClientsBuilder.AddBlobServiceClient(builder.GetContext().Configuration["AzureWebJobsStorage"]);
azureClientsBuilder.UseCredential(new DefaultAzureCredential());
});
}
public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
base.ConfigureAppConfiguration(builder);
}
}
using Azure.Storage.Blobs;
using System;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Extensions.Logging;
using Azure.Storage.Blobs.Specialized;
using System.IO;
using Microsoft.Extensions.Configuration;
namespace AzureQueueStorageDemo.AzureFunctions
{
public class AddMessageLogRequest
{
private readonly BlobServiceClient _blobServiceClient;
public AddMessageLogRequest(BlobServiceClient blobServiceClient)
{
_blobServiceClient = blobServiceClient;
}
[FunctionName("AddMessageLogRequest")]
public void Run([QueueTrigger("myqueue-items")] string myQueueItem, ILogger log)
{
BlobContainerClient containerClient = _blobServiceClient.GetBlobContainerClient("my-message-log-container");
containerClient.CreateIfNotExists();
AppendBlobClient appendBlobClient = containerClient.GetAppendBlobClient("message-log.txt");
appendBlobClient.CreateIfNotExists();
// Convert myQueueItem to a stream
Stream contentStream = new MemoryStream();
StreamWriter streamWriter = new StreamWriter(contentStream);
streamWriter.Write(myQueueItem + Environment.NewLine);
streamWriter.Flush();
contentStream.Position = 0;
appendBlobClient.AppendBlock(contentStream);
log.LogInformation($"C# Queue trigger function processed: {myQueueItem}");
}
}
}
At this point you can run just the functions app. Use the storage explorer and send some more messages. You should start noticing that it is creating this file and more information is being put in to it as you send more and more messages.
Build out the Web Application
Our web application will need some libraries to be able to connect to the Blob Storage and Queue Storage. Execute the following commands from the /workspace/AzureQueueStorageDemo.Web/ folder
dotnet add package Azure.Storage.Blobs
dotnet add package Azure.Storage.Queues
dotnet add package Microsoft.Extensions.Azure
// Register Azure Clients
builder.Services.AddAzureClients(azureClientsBuilder => {
azureClientsBuilder.AddQueueServiceClient(builder.Configuration.GetConnectionString("AzureStorage")).ConfigureOptions(queueOptions => {
queueOptions.MessageEncoding = QueueMessageEncoding.Base64;
});
azureClientsBuilder.AddBlobServiceClient(builder.Configuration.GetConnectionString("AzureStorage"));
});
Create a new file called “IAzureQueueStorageService.cs”.
Give it the following code:
namespace AzureQueueStorageDemo.Web.Services;
public interface IAzureQueueStorageService
{
public Task SendMessageAsync(string message);
}
Give it the following code:
using Azure;
using Azure.Storage.Queues;
namespace AzureQueueStorageDemo.Web.Services;
public abstract class AzureQueueStorageService : IAzureQueueStorageService
{
private readonly QueueServiceClient _queueServiceClient;
private readonly string _queueName;
public AzureQueueStorageService(QueueServiceClient queueServiceClient, string queueName)
{
_queueServiceClient = queueServiceClient;
_queueName = queueName;
}
public async Task SendMessageAsync(string message)
{
var queueClient = await GetQueueClientAsync();
await queueClient.SendMessageAsync(message);
}
private async Task<QueueClient> GetQueueClientAsync()
{
var queueClient = _queueServiceClient.GetQueueClient(_queueName);
await queueClient.CreateIfNotExistsAsync();
return queueClient;
}
}
Give it the following code:
namespace AzureQueueStorageDemo.Web.Services;
public interface IMyQueueItemsQueStorageService : IAzureQueueStorageService
{
}
Give it the following code:
using Azure.Storage.Queues;
namespace AzureQueueStorageDemo.Web.Services;
public class MyQueueItemsAzureQueueStorageService : AzureQueueStorageService, IMyQueueItemsQueStorageService
{
public MyQueueItemsAzureQueueStorageService(QueueServiceClient queueServiceClient) : base (queueServiceClient, "myqueue-items")
{
}
}
Now modify the Program.cs file again and add this just after the previous code that you added earlier:
// Register Services
builder.Services.AddTransient<IMyQueueItemsQueStorageService, MyQueueItemsAzureQueueStorageService>();
using Azure.Identity;
using Azure.Storage.Queues;
using AzureQueueStorageDemo.Web.Services;
using Microsoft.Extensions.Azure;
var builder = WebApplication.CreateBuilder(args);
// Register Azure Clients
builder.Services.AddAzureClients(azureClientsBuilder => {
azureClientsBuilder.AddQueueServiceClient(builder.Configuration.GetConnectionString("AzureStorage")).ConfigureOptions(queueOptions => {
queueOptions.MessageEncoding = QueueMessageEncoding.Base64;
});
azureClientsBuilder.AddBlobServiceClient(builder.Configuration.GetConnectionString("AzureStorage"));
});
// Register Services
builder.Services.AddTransient<IMyQueueItemsQueStorageService, MyQueueItemsAzureQueueStorageService>();
// Add services to the container.
builder.Services.AddControllersWithViews();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// 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.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
To the Models folder in the Web Application add a file called MessageLogViewModel.cs.
Give it the following code:
namespace AzureQueueStorageDemo.Web.Models;
public class MessageLogViewModel
{
public string? MessageLogContents {get; set;}
}
Give it the following code:
using Azure.Storage.Blobs;
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using AzureQueueStorageDemo.Web.Services;
using AzureQueueStorageDemo.Web.Models;
namespace AzureQueueStorageDemo.Web.Controllers;
public class MessagesController : Controller
{
private readonly IMyQueueItemsQueStorageService _myQueueItemsQueStorageService;
private readonly BlobServiceClient _blobServiceClient;
public MessagesController(IMyQueueItemsQueStorageService myQueueItemsQueStorageService, BlobServiceClient blobServiceClient)
{
_myQueueItemsQueStorageService = myQueueItemsQueStorageService;
_blobServiceClient = blobServiceClient;
}
[HttpGet]
public async Task<IActionResult> Index()
{
var results = new MessageLogViewModel();
results.MessageLogContents = "";
var containerClient = _blobServiceClient.GetBlobContainerClient("my-message-log-container");
await containerClient.CreateIfNotExistsAsync();
var blobClient = containerClient.GetBlobClient("message-log.txt");
if(blobClient.Exists()) {
var blobContent = await blobClient.OpenReadAsync();
var streamReader = new StreamReader(blobContent);
results.MessageLogContents = await streamReader.ReadToEndAsync();
}
return View(results);
}
[HttpGet]
public IActionResult Create()
{
var newMessage = new MessageLogViewModel();
return View(newMessage);
}
[HttpPost]
public async Task<IActionResult> Create(MessageLogViewModel newMessage)
{
if(newMessage.MessageLogContents is not null) {
await _myQueueItemsQueStorageService.SendMessageAsync(newMessage.MessageLogContents);
}
return RedirectToAction("Index");
}
}
To the Views folder create a new folder called “Messages”.
To the new Messages folder create a new file called Index.cshtml.
Give it the following code
@model MessageLogViewModel
@{
ViewData["Title"] = "Messages in the Messages Log";
}
<h1>@ViewData["Title"]</h1>
<a class="btn btn-primary" asp-action="Create">Add a Message</a>
<p class="text-info">*If you recently added some messages, then you may need to refresh a few times to see the results of the Azure Function Processing the message.</p>
<pre class="form-control" readonly>
@Model.MessageLogContents
</pre>
Give it the following code
@model MessageLogViewModel
@{
ViewData["Title"] = "Add a Message to the Messages Log";
}
<h1>@ViewData["Title"]</h1>
<form asp-action="Create" method="post">
<div class="form-group">
<label asp-for="MessageLogContents"></label>
<textarea class="form-control" asp-for="MessageLogContents"></textarea>
</div>
<input class="btn btn-primary" type="submit" value="Send" />
</form>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Messages" asp-action="Index">Messages</a>
</li>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - AzureQueueStorageDemo.Web</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/AzureQueueStorageDemo.Web.styles.css" asp-append-version="true" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container-fluid">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">AzureQueueStorageDemo.Web</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Messages" asp-action="Index">Messages</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2022 - AzureQueueStorageDemo.Web - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>
Test the Web Application
Click on the Messages link. If you still have some test data from before when you were testing the queue out directly through the Azure explorer you should already see some messages. If not. Click on the Create button, and start adding messages.
Take note of your message-log.txt file in the Azure Storage Explorer. The size should increase each time the function executes.
You may also want to practice adding and removing break points to see the code in action.
You can even delete the message-log.txt file manually from the storage explorer to start over.
Conclusion
Azure Queue Storage is just one of many Microsoft Technologies that have event driven messaging. This can allow your web application some freedom and cycle time from doing expensive operations that are required after a particular action has been completed, thus allowing the user to return to the next page, while the processing of the request continues in another area.
GitHub Repo: https://github.com/woodman231/azure-queue-storage-demo
About Intertech
Intertech is a Software Development Consulting Firm that provides single and multiple turnkey software development teams, available on your schedule and configured to achieve success as defined by your requirements independently or in co-development with your team. Blackslate Software teams combine proven full-stack, DevOps, Agile-experienced lead consultants with Delivery Management, User Experience, Software Development, and QA experts in Business Process Automation (BPA), Microservices, Client- and Server-Side Web Frameworks of multiple technologies, Custom Portal and Dashboard development, Cloud Integration and Migration (Azure and AWS), and so much more. Each Blackslate Software employee leads with the soft skills necessary to explain complex concepts to stakeholders and team members alike and makes your business more efficient, your data more valuable, and your team better. In addition, Blackslate Software is a trusted partner of more than 4000 satisfied customers and has a 99.70% “would recommend” rating.