This article outlines a set of functionalities for interacting with Azure Blob Storage using C#. A relevant code sample can be downloaded from GitHub by the Blob Storage
The HandleBlob class enables you to upload files to Azure Blob Storage and retrieve a list of blobs from a specific container. Designed for efficiency, the class supports advanced features like uploading large files in chunks and retrieving metadata about existing blobs.
Class Breakdown
Private Fields
- _connectionString: Stores the Azure Storage account connection string, which is required for authenticating and interacting with the Azure Blob Storage service.
- _containerName: Represents the name of the blob container where the blobs (files) will be stored.
- _blobName: The name of the specific blob (file) you want to interact with, like the name of the uploaded file.
- _fileStream: A FileStream object that represents the local file being uploaded to Azure Blob Storage.
private string _connectionString { get; set; }
private string _containerName { get; set; }
private string _blobName { get; set; }
private FileStream _fileStream { get; set; }
UploadFileToBlob() Method
This method uploads a file to Azure Blob Storage in chunks using the block blob storage model.
public async Task<Uri> UploadFileToBlob()
{
Uri? blobUri = null;
BlobServiceClient blobServiceClient = new BlobServiceClient(_connectionString);
BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(_containerName);
await containerClient.CreateIfNotExistsAsync();
BlockBlobClient blockBlobClient = containerClient.GetBlockBlobClient(_blobName);
using (FileStream fs = _fileStream)
{
long fileSize = fs.Length;
int blockSize = 1 * 1024 * 1024;
List<Task> uploadTasks = new List<Task>();
int blockCount = (int)Math.Ceiling((double)fileSize / blockSize);
byte[] buffer = new byte[blockSize];
for (int i = 0; i < blockCount; i++)
{
int bytesRead = await fs.ReadAsync(buffer, 0, blockSize);
byte[] blockData = buffer.Take(bytesRead).ToArray();
string blockId = Convert.ToBase64String(BitConverter.GetBytes(i));
uploadTasks.Add(blockBlobClient.StageBlockAsync(blockId, new MemoryStream(blockData)));
}
await Task.WhenAll(uploadTasks);
List<string> blockIds = uploadTasks
.Select(task => Convert.ToBase64String(BitConverter.GetBytes(uploadTasks.IndexOf(task))))
.ToList();
await blockBlobClient.CommitBlockListAsync(blockIds);
blobUri = blockBlobClient.Uri;
}
return blobUri;
}
The method is asynchronous (async), and it returns a Uri pointing to the uploaded blob in Azure.
- BlobServiceClient: First, it creates a BlobServiceClient object using the provided connection string, which is used to interact with Azure Blob Storage.
- BlobContainerClient: It then retrieves a BlobContainerClient for the specified container, ensuring that the container exists by calling CreateIfNotExistsAsync(). This ensures that the container will be created if it doesn't already exist.
- BlockBlobClient: It gets a BlockBlobClient for the specified blob name. This client is responsible for managing block-level blob operations, including uploading blocks of data.
- File Upload in Chunks: The file is uploaded in chunks to handle large files. The file is read in 1MB blocks, and each block is uploaded asynchronously using StageBlockAsync.
- Block Size: The file is divided into blocks of 1MB. This size is configurable based on your needs.
- Task List: A list of Task objects is created to upload each block concurrently, improving upload performance.
- Commit Block List: After all the blocks are uploaded, the method calls CommitBlockListAsync, passing a list of block IDs. This operation commits the blocks and finalizes the blob upload.
- Returning the Blob URI: After the upload is complete, the method returns the URI of the uploaded blob, which is used to access the blob.
LoadAllBlobs() Method
This method asynchronously loads all the blobs in the specified container and returns a list of Blobs objects that contain metadata for each blob.
public async Task<List<Blobs>> LoadAllBlobs()
{
BlobServiceClient blobServiceClient = new BlobServiceClient(_connectionString);
BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(_containerName);
List<Blobs> blobs = new List<Blobs>();
await foreach (BlobItem blobItem in containerClient.GetBlobsAsync())
{
Blobs blob = new Blobs
{
name = blobItem.Name,
blobUrl = containerClient.GetBlobClient(blobItem.Name).Uri.ToString(),
dateModified = blobItem.Properties.LastModified?.DateTime ?? DateTime.MinValue
};
blobs.Add(blob);
}
return blobs;
}
Here’s how it works?
- BlobServiceClient: Creates a BlobServiceClient to interact with Azure Blob Storage.
- BlobContainerClient: Retrieves the BlobContainerClient for the specified container, allowing access to the blobs inside.
- BlobItem Enumeration: The method uses GetBlobsAsync() to iterate over all blobs in the container. Each BlobItem contains the name of the blob and metadata such as the last modified date.
- List of Blobs: For each blob, it creates a Blobs object containing the blob’s name, URL, and last modified date. These are added to the blobs list.
- Return List: After iterating through all the blobs, the list of Blobs objects is returned.
Key Components
- File Uploading in Chunks: The method UploadFileToBlob handles large file uploads by breaking the file into blocks. This approach is beneficial when uploading large files to Azure Blob Storage, as it allows for more efficient and resilient uploads.
- Asynchronous Operations: Both UploadFileToBlob and LoadAllBlobs methods use async/await to perform non-blocking operations, improving the application’s responsiveness when interacting with Azure Blob Storage.
- Blob URI: The UploadFileToBlob method returns the Uri of the uploaded blob, which is the unique address to access the blob in Azure.
- Blob Metadata: The LoadAllBlobs method retrieves important metadata for each blob, such as the name, URL, and last modified timestamp, which can be useful for listing or managing blobs.
Conclusion
The HandleBlob class provides a simple and efficient way to manage Azure Blob Storage operations such as uploading files in chunks and listing all blobs in a container.
It uses asynchronous methods to ensure non-blocking operations, making it suitable for production environments that require handling large files and high concurrency.