---
title: "Storing Images in Azure Blob Storage with ASP.NET Core"  
description: "Learn how an ASP.NET Core app can upload and serve images with Azure Blob Storage, including container access, validation, configuration, and secure d"  
author: "Ravi Vishwakarma"  
published: 2026-10-09  
updated: 2026-10-09  
canonical: https://www.mindstick.com/blog/307084/storing-images-in-azure-blob-storage-with-asp-net-core  
category: "Azure Blob Storage"  
tags: ["Azure", "asp.net core", "Blob Storage", "web development", "Image Upload"]  
reading_time: 6 minutes  

---

# Storing Images in Azure Blob Storage with ASP.NET Core

[Azure Blob Storage](https://answers.mindstick.com/blog/276/implement-azure-blob-storage-with-net-core-api-production-ready-guide) is a practical place to keep images uploaded to an ASP.NET Core application. Instead of saving large files inside your web server’s folder or database, you store each image as a blob and keep its name or URL in your app’s data.

## How the pieces fit together

A **storage account** is the Azure resource that holds your data. Inside it, a **container** groups blobs, much like a folder. Each uploaded image is a **blob**, identified by its name. Your ASP.NET Core app uses the Azure Storage SDK to authenticate and upload or download those blobs.

For user uploads, keep the container private by default. Public access can expose every image in a container, while a private container lets your application decide who can view each file. You can serve images through an authorized app endpoint or issue short-lived, read-only SAS links when direct browser access is needed.

## 1. Create a container and configure access

Create a storage account in Azure, then create a container such as `images`. Leave its public access level set to private. In production, prefer Microsoft Entra ID with a managed identity and a narrowly scoped storage role over a long-lived account key. For local development, a connection string kept in user secrets or an environment variable is convenient.

Install the client library:

```plaintext
dotnet add package Azure.Storage.Blobs
```

For local development, add a connection string to user secrets or an environment variable named `ConnectionStrings__AzureBlobStorage`. Avoid committing credentials to source control. Then register a container client in `Program.cs`:

```cs
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

// Read the connection string from configuration, not from source code.
var connectionString =
    builder.Configuration.GetConnectionString("AzureBlobStorage")
    ?? throw new InvalidOperationException(
        "Azure Blob Storage is not configured.");

builder.Services.AddSingleton(_ =>
    new BlobContainerClient(connectionString, "images"));

var app = builder.Build();

app.MapControllers();
app.Run();
```

Add the required namespaces where needed: `Azure.Storage.Blobs` and `Azure.Storage.Blobs.Models`. In a deployed app, configure the client with managed identity instead of a storage account connection string.

## 2. Upload an image

Use a generated blob name rather than the uploaded filename. User-provided names can contain awkward characters, reveal personal information, or collide with existing files. Keep the original filename in your database only if the application needs it.

This small service uploads the stream and records the content type so a browser knows how to handle the image:

```cs
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;

public sealed class ImageStorage
{
    private readonly BlobContainerClient _container;

    public ImageStorage(BlobContainerClient container)
    {
        _container = container;
    }

    public async Task<string> UploadAsync(
        Stream image,
        string contentType,
        CancellationToken cancellationToken)
    {
        // A random name avoids collisions and does not trust the client filename.
        var blobName = $"{Guid.NewGuid():N}";

        var blob = _container.GetBlobClient(blobName);

        // Save the browser-facing content type with the blob.
        await blob.UploadAsync(
            image,
            new BlobUploadOptions
            {
                HttpHeaders = new BlobHttpHeaders
                {
                    ContentType = contentType
                }
            },
            cancellationToken);

        return blobName;
    }

    public async Task<BlobDownloadStreamingResult> DownloadAsync(
        string blobName,
        CancellationToken cancellationToken)
    {
        var blob = _container.GetBlobClient(blobName);

        // The SDK returns the stream and blob properties for the stored image.
        var response = await blob.DownloadStreamingAsync(
            cancellationToken: cancellationToken);

        return response.Value;
    }
}
```

Register the service with `builder.Services.AddSingleton<ImageStorage>();` after registering the container client. Create the container ahead of time through Azure Portal, infrastructure as code, or a controlled deployment step; the application identity should have only the permissions it needs.

## 3. Validate uploads in the API

Checking the file extension or the browser-supplied MIME type alone is not enough: both can be forged. The example below applies a size limit and an allowlist for common image types. For a public upload feature, also inspect the file signature, consider decoding and re-encoding images, and add malware scanning if your risk profile calls for it.

```cs
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/images")]
public sealed class ImagesController : ControllerBase
{
    private const long MaxImageBytes = 5 * 1024 * 1024;

    private static readonly HashSet<string> AllowedTypes =
        new(StringComparer.OrdinalIgnoreCase)
        {
            "image/jpeg",
            "image/png",
            "image/webp"
        };

    private readonly ImageStorage _storage;

    public ImagesController(ImageStorage storage)
    {
        _storage = storage;
    }

    [HttpPost]
    [RequestSizeLimit(MaxImageBytes)]
    public async Task<IActionResult> Upload(
        IFormFile file,
        CancellationToken cancellationToken)
    {
        if (file is null || file.Length == 0)
        {
            return BadRequest("Choose an image to upload.");
        }

        if (file.Length > MaxImageBytes)
        {
            return BadRequest("The image must be 5 MB or smaller.");
        }

        // This is a useful first filter, not proof that the content is an image.
        if (!AllowedTypes.Contains(file.ContentType))
        {
            return BadRequest("Only JPEG, PNG, and WebP images are accepted.");
        }

        await using var stream = file.OpenReadStream();

        var blobName = await _storage.UploadAsync(
            stream,
            file.ContentType,
            cancellationToken);

        // Store this name with the related record in your database.
        return Ok(new { blobName });
    }

    [HttpGet("{blobName}")]
    public async Task<IActionResult> Get(
        string blobName,
        CancellationToken cancellationToken)
    {
        try
        {
            var image = await _storage.DownloadAsync(
                blobName,
                cancellationToken);

            // Returning through the app keeps the container private.
            return File(image.Content, image.Details.ContentType);
        }
        catch (Azure.RequestFailedException ex) when (ex.Status == 404)
        {
            return NotFound();
        }
    }
}
```

The download route should also check that the current user is allowed to see the requested image. A blob name is an identifier, not an authorization mechanism. If images are public by design, you can instead serve them through a CDN or generate a short-lived SAS URL with read-only permission.

## 4. Keep image data and app data separate

Blob Storage holds the file; your database can hold the blob name alongside the image owner, upload time, and any application-specific metadata. This makes it easier to associate an image with a user or record without storing the image bytes in a database row.

- **Do not store secrets in the repository.** Use managed identity in Azure and secret storage for local or other hosted environments.
- **Set size and request limits.** Consider reverse-proxy and server request limits as well as the controller limit.
- **Plan for cleanup.** Delete the blob when its associated record is removed, or use a background process to find orphaned uploads.
- **Think about image delivery.** The app endpoint provides a place for authorization checks, while a CDN or SAS links may suit high-traffic or temporary access scenarios.

With this setup, ASP.NET Core handles upload validation and access decisions, while Azure Blob Storage handles durable file storage. The blob name is the link between the two.

---

Original Source: https://www.mindstick.com/blog/307084/storing-images-in-azure-blob-storage-with-asp-net-core

Copyright © MindStick Software Pvt. Ltd. This Markdown version is provided for developers, AI systems, and offline reading.
