Upload And Download File To Azure Blob Storage Using C#

Introduction

Azure Storage is a service provided by Microsoft to store the data, such as text or binary. You can use this data to make it available to the public or secure it from public access. There are multiple ways I found on the internet to upload the content to Azure Blob Storage like you can use shared keys, or use a Connection string, or a native app.

Problem

Now, here is the problem. Suppose you have to create a Windows Service that will upload and download your files to the Azure Blob Storage. And as per the requirements, you don’t have to use a shared key or connection string, or simply your client didn’t share it. The client wants to get it done by Active Directory Authentication. With the Native app, as most of the samples are over the internet, user consent is required if your token expires and that’s why it cannot be used in Windows Service.

Solution

After spending some time on it, I found the right way to upload and download a file on Azure Blob Storage. As I didn’t find any documentation or samples particular to this requirement over the internet, I am sharing it. Hope it will help.

Create an application on Azure

Create an application of Web app/API type on the Azure portal.

Azure portal

Get Keys for Authentication

You need to have the application ID, tenant/Directory ID, and Client Secret key.

After application creation, you will see the below screen where you have the application ID and from the Keys section, you can generate the Client Secret key. See the below screens.

Client Secret key

To get a Directory/ Tenant ID.

Directory

Tenant ID

Role assignment to your Azure application

Now, go to your storage account that you want to use and assign your application Storage Blob Data Owner/Contributor Role.

Contributor Role

IAM

Actually, the above role gives you permissions to read/write/delete on Blob Management and Data. With Management permission, you can read/write/delete a container in the Blob and with Data, you can read/write/delete content in it.

 Blob Management

Now, you have all the things you need to build an application. Let's see the code snippets.

Authentication

The first thing you need is to get an access token and you can get it using the below method.

static string GetUserOAuthToken(string tenantId, string applicationId, string clientSecret)  
{  
    const string ResourceId = "https://storage.azure.com/";  
    const string AuthInstance = "https://login.microsoftonline.com/{0}/";  
  
    string authority = string.Format(CultureInfo.InvariantCulture, AuthInstance, tenantId);  
    AuthenticationContext authContext = new AuthenticationContext(authority);  
  
    var clientCred = new ClientCredential(applicationId, clientSecret);  
    AuthenticationResult result = authContext.AcquireTokenAsync(  
                                            ResourceId,  
                                            clientCred  
                                        ).Result;  
    return result.AccessToken;  
}

File Upload and Download Methods

Below is the code snippet to upload and download the file to Azure Blob Storage.

public static class AzureOperations
{
    #region ConfigParams
    public static string tenantId;
    public static string applicationId;
    public static string clientSecret;
    #endregion

    public static void UploadFile(AzureOperationHelper azureOperationHelper)
    {
        CloudBlobContainer blobContainer = CreateCloudBlobContainer(
            tenantId,
            applicationId,
            clientSecret,
            azureOperationHelper.storageAccountName,
            azureOperationHelper.containerName,
            azureOperationHelper.storageEndPoint
        );

        blobContainer.CreateIfNotExists();
        CloudBlockBlob blob = blobContainer.GetBlockBlobReference(azureOperationHelper.blobName);
        blob.UploadFromFile(azureOperationHelper.srcPath);
    }

    public static void DownloadFile(AzureOperationHelper azureOperationHelper)
    {
        CloudBlobContainer blobContainer = CreateCloudBlobContainer(
            tenantId,
            applicationId,
            clientSecret,
            azureOperationHelper.storageAccountName,
            azureOperationHelper.containerName,
            azureOperationHelper.storageEndPoint
        );

        CloudBlockBlob blob = blobContainer.GetBlockBlobReference(azureOperationHelper.blobName);
        blob.DownloadToFile(azureOperationHelper.destinationPath, FileMode.OpenOrCreate);
    }

    private static CloudBlobContainer CreateCloudBlobContainer(
        string tenantId,
        string applicationId,
        string clientSecret,
        string storageAccountName,
        string containerName,
        string storageEndPoint
    )
    {
        string accessToken = GetUserOAuthToken(tenantId, applicationId, clientSecret);
        TokenCredential tokenCredential = new TokenCredential(accessToken);
        StorageCredentials storageCredentials = new StorageCredentials(tokenCredential);
        CloudStorageAccount cloudStorageAccount = new CloudStorageAccount(
            storageCredentials,
            storageAccountName,
            storageEndPoint,
            useHttps: true
        );

        CloudBlobClient blobClient = cloudStorageAccount.CreateCloudBlobClient();
        CloudBlobContainer blobContainer = blobClient.GetContainerReference(containerName);
        return blobContainer;
    }

    static string GetUserOAuthToken(string tenantId, string applicationId, string clientSecret)
    {
        const string ResourceId = "https://storage.azure.com/";
        const string AuthInstance = "https://login.microsoftonline.com/{0}/";
        string authority = string.Format(CultureInfo.InvariantCulture, AuthInstance, tenantId);
        AuthenticationContext authContext = new AuthenticationContext(authority);
        var clientCred = new ClientCredential(applicationId, clientSecret);
        AuthenticationResult result = authContext.AcquireTokenAsync(ResourceId, clientCred).Result;
        return result.AccessToken;
    }
}

Test it in a Console application.

class Program
{
    static void Main(string[] args)
    {
        // Set Ids of your Azure account
        AzureOperations.applicationId = "";
        AzureOperations.clientSecret = "";
        AzureOperations.tenantId = "";

        // Demo Upload File
        string srcPathToUpload = @"C:\Users\abdul.rehman\Desktop\AzureFileUpload\myfile.txt";
        UploadFile(srcPathToUpload);

        // Demo Download File
        string azurePathInBlob = "dev/files/myfile.txt";
        string destinationPath = @"C:\Users\abdul.rehman\Desktop\AzureFileDownload\myfile.txt";
        DownloadFile(destinationPath, azurePathInBlob);
    }

    public static void UploadFile(string srcPath)
    {
        AzureOperationHelper azureOperationHelper = new AzureOperationHelper();
        // your Storage Account Name
        azureOperationHelper.storageAccountName = "dbpoc";
        azureOperationHelper.storageEndPoint = "core.windows.net";
        // File path to upload
        azureOperationHelper.srcPath = srcPath;
        // Your Container Name
        azureOperationHelper.containerName = "filecontainer";
        // Destination Path you can set it file name or if you want to put it in folders do it like below
        azureOperationHelper.blobName = $"dev/files/{Path.GetFileName(srcPath)}";
        AzureOperations.UploadFile(azureOperationHelper);
    }

    public static void DownloadFile(string destinationPath, string srcPath)
    {
        AzureOperationHelper azureOperationHelper = new AzureOperationHelper();
        // your Storage Account Name
        azureOperationHelper.storageAccountName = "dbpoc";
        azureOperationHelper.storageEndPoint = "core.windows.net";
        // Destination Path where you want to download file
        azureOperationHelper.destinationPath = destinationPath;
        // Your Container Name
        azureOperationHelper.containerName = "filecontainer";
        // Blob Path in container where to download File
        azureOperationHelper.blobName = srcPath;

        AzureOperations.DownloadFile(azureOperationHelper);
    }
}

NuGet Dependencies

  1. WindowsAzure.Storage (I have installed v9.3.3).
  2. Microsoft.IdentityModel.Clients.ActiveDirectory (I have installed v4.4.2).

There are a few things you need to check.

  1. The container name should be in lowercase. I don't know why it is not handled but in this version, it is not working with uppercase.
  2. Permissions are very critical. Your application role must have read/write/delete permissions on Blob Management and Data as well.

Summary

In this above sample, we learned how to manage our files on Azure Blob Storage with Active Directory Authentication using the application Secret Key. And like the Native app, no popup will be shown to enter the credentials in order to get the access token.

I have also uploaded the sample console application that you can download and test with your Azure credentials. Feel free to contact me in case of an issue.

Download Complete Sample

References