Document Versioning With Azure Blob Storage
Build your custom Document Library using Azure Blob Storage Versioning. C# helpers to achieve Document versioning, etc.
Join the DZone community and get the full member experience.
Join For FreeSome Background First
Almost all organizations have a need for document storage for their applications. If the organization is a Microsoft shop then, one of the most popular choices for them is the SharePoint Document Library. SharePoint Document library allows you to store documents, retain their versions, provides the ability to make any old version to the current version, last but not the least deleting a specific version of a document.
With all the goodness of SharePoint, it comes with its own limitations. For many custom cloud, applications build, SharePoint may not always be the right choice because of various reasons. It needs a dedicated setup, licensing, etc. And just to use the document library feature, the investment may not always be justifiable.
So, what option do you have? Can you achieve all the above SharePoint Document Library features otherwise?
If you are building your application in Azure, then it is highly likely that you are taking the benefit of Azure Storage Account Blob Container for any storage needs, including but not limited to document/ file storage.
The good news is you can now achieve all of these using Azure Storage Account’s blob versioning feature.
In this article, I’m going to talk about how you can leverage your existing Azure Storage Account Infrastructure and use it effectively for your document and file storage needs.
I’m going to cover the following with a few C# code samples.
- Document Versioning
- List all document with all their versions
- Download a specific version of the document
- Make a specific version of the document to the current version
- Delete a specific version of the document
You can find the entire project in GitHub.
How Can You Achieve Versioning in Blob Storage?
Until this announcement of Blob Versioning for Azure Storage Account, it was tedious to maintain the versions of any document stored as a blob in a container. One such manual approach was to take a snapshot of the document while uploading. Maintain that snapshot information in some sort of table (e.g.: database tables). And to restore the file, use the table stored information to restore from the snapshot.
You can read more about Snapshot and Blob versioning here.
Okay, so those days are gone now. With some simple steps, you can enable versioning to your blob and achieve document library like features.
You can enable Versioning while creating the storage account. Under the Data protection tab check Tracking >> Turn on versioning option.
For your existing Storage Account, to enable versioning to go to the left side blade >> look for Data Protection under Blob service. On your left pane under Tracking select Turn on versioning
Now that the blob versioning is enabled, let's see it in action.
Now, Upload a File and See Blob Versioning in Action
To test it out, upload a file with the same name with varying content to the container multiple times. Now find the file in the container which you have just uploaded. You can use the Azure portal to upload the file or use the following code
xxxxxxxxxx
public async Task<string> UploadBlobAsync(string filePath)
{
var blobName = Path.GetFileName(filePath);
string uploadedDocVersion = string.Empty;
using (var ms = new MemoryStream(File.ReadAllBytes(filePath)))
{
var blobClient = BlobContainerClient.GetBlockBlobClient(blobName);
var blob = await blobClient.UploadAsync(ms);
uploadedDocVersion = blob.Value.VersionId;
}
return uploadedDocVersion;
}
Click on the View previous versions option. You will see all the versions of the file listed with a timestamp.
Now let’s write some code to list all the versions of the uploaded files in the container.
Listing All the Versions of an Uploaded File
Blob versioning features can be programmatically accessed using the Azure Storage client library for .NET, version 12.5.1, or later. However, I couldn’t find a way to list down the versions of all the files in the container using this NuGet.
So, I did a little hack. From the Azure Portal – I clicked on the View Previous Versions and I intercepted the REST API URL from the Network tab of developer tools.
Version 2019-10-10 and higher of the Azure Storage REST API supports blob versioning. Using the below code I was able to call the REST API URL. https://{accountname}.blob.core.windows.net/{containername}
?restype=container&comp=list&include=versions
and retrieve all the versions of all the files in the container.
x
public static async Task<List<FileModel>> ListAllDocumentWithVersion(string storageAccountName, string storageAccountKey, string containerName, CancellationToken cancellationToken)
{
// I intercepted this url from the Azure Portal. include=versions is doing all the magic here
var uri = string.Format("https://{0}.blob.core.windows.net/{1}?restype=container&comp=list&include=versions", storageAccountName, containerName);
Byte[] requestPayload = null;
using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uri) { Content = (requestPayload == null) ? null : new ByteArrayContent(requestPayload) })
{
// Add the request headers for x-ms-date and x-ms-version.
var now = DateTime.UtcNow;
httpRequestMessage.Headers.Add("x-ms-date", now.ToString("R", CultureInfo.InvariantCulture));
httpRequestMessage.Headers.Add("x-ms-version", "2019-12-12");
// Add the authorization header.
httpRequestMessage.Headers.Authorization = AzureStorageAuthHelper.GetAuthorizationHeader(
storageAccountName, storageAccountKey, now, httpRequestMessage);
// Send the request.
var allFiles = new List<FileModel>();
using (var httpResponseMessage = await new HttpClient().SendAsync(httpRequestMessage, cancellationToken))
{
// parse the XML response for the container names.
if (httpResponseMessage.StatusCode == HttpStatusCode.OK)
{
var xmlString = await httpResponseMessage.Content.ReadAsStringAsync();
var x = XElement.Parse(xmlString);
foreach (XElement container in x.Element("Blobs").Elements("Blob"))
{
string fileName = container.Element("Name").Value;
var model = new FileModel() { FileName = container.Element("Name").Value, FileVersion = container.Element("VersionId").Value };
allFiles.Add(model);
}
}
}
return allFiles;
}
}
Downloading a Specific Version
To download a specific version of a file use WithVersion
. This line var blob = blobClient.WithVersion(fileVersion);
in the code below is doing all the magic.
xxxxxxxxxx
public async Task<byte[]> DownloadBlobAsync(string fileToDownload, string fileVersion)
{
using (var ms = new MemoryStream())
{
var blobClient = BlobContainerClient.GetBlockBlobClient(fileToDownload);
// WithVersion() is the key piece here
var blob = blobClient.WithVersion(fileVersion);
await blob.DownloadToAsync(ms);
return ms.ToArray();
}
}
Restoring a File To a Specific Version
One of the most important functionalities if any document library is to restore any file version and make it as the current version. To restore to a specific version, you have to use the copy blob function. I found StartCopyFromUri
very helpful since I could pass the VersionId
of the file with the blob url query parameter as https://{0}.blob.core.windows.net/{1}/{2}?versionid={3}
xxxxxxxxxx
public void RestoreFileToSpecificVersion(string storageAccountName, string containerName, string fileName, string sourceVersion)
{
var blobClient = BlobContainerClient.GetBlockBlobClient(fileName); // this is pointing to the current version
//versionid={} is the most important piece here
var sourceBlobUri = new Uri(
string.Format("https://{0}.blob.core.windows.net/{1}/{2}?versionid={3}",
storageAccountName, containerName, fileName, sourceVersion));
// Since it will copy in the same storage account's container, it's a synchronous process
// Copy Operation will make the specic version as current version
// See https://docs.microsoft.com/en-us/rest/api/storageservices/copy-blob-from-url#request-headers
blobClient.StartCopyFromUri(sourceBlobUri);
}
Deleting a Specific Version
Last but not the least, you can delete a specific version of a file from the storage container. Again .WithVersion
will help you here to delete a specific version as below.
xxxxxxxxxx
public async Task DeleteSpecificVersion(string fileName, string versionToDelete)
{
// WithVersion() is the key piece here
var blobClient = BlobContainerClient.GetBlockBlobClient(fileName).WithVersion(versionToDelete);
await blobClient.DeleteAsync();
}
Wrap Up
In this post, I have covered a few key features of a Document library which you can achieve with Azure Blob Versioning and a few lines of code. This solution is not meant to replace SharePoint or any other document management solutions. I felt this would become very handy to retain document versions, restore a document, delete a specific version of a custom build application that uses Azure Storage Account as storage infrastructure.
Published at DZone with permission of Subhankar Sarkar. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments