Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Create Singleton to Dependency Inject Azure Storage Client and Container

I have a class that has a method that does Azure Storage things and currently, I am creating the StorageContainer, BlobClient, and Container every single time it is called:

private readonly IAzureStorageConfig _config;

public SaveImageBlob(IAzureStorageConfig config)
{
    _config = config;
}

public async Task<T> ExecuteAsync(ImageSaveInput input)
{

    //get the storage account from the connection string
    CloudStorageAccount storageAccount = CloudStorageAccount.Parse(_config.ConnectionString);

    //instantiate the client
    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

    //set the container
    CloudBlobContainer container = blobClient.GetContainerReference(_config.ImagesContainerName);

    //... do things and stuff
}

Now, I want to rip that out of the SaveImageBlob.ExecuteAsync method and dependency inject it into the class, so the Azure Storage items are instantiated only once.

I currently have the interface as such:

namespace Domain.Interfaces
{
    public interface IAzureStorage
    {
        CloudStorageAccount StorageAccount { get; }

        CloudBlobClient BlobClient { get; }

        CloudBlobContainer Container { get; }
    }
}

And now, I am clueless as to how to implement that interface.

Once the interface is implemented, I imagine I'm going to change the SaveImageBlob.ExecuteAsync method to this:

private readonly IAzureStorageConfig _config;
private readonly IAzureStorage _storage;

public SaveImageBlob(IAzureStorageConfig config,
                     IAzureStorage storage)
{
    _config = config;
    _storage = storage;
}

public async Task<T> ExecuteAsync(ImageSaveInput input)
{

    //now, since I don't have to create an instance of the storageAccount, blobClient, and container, I can just access them from _storage
    //create the blockBlob
    CloudBlockBlob blockBlob = _storage.Container.GetBlockBlobReference(input.BlobUrl); 

    //... do things and stuff with a Stream (doesn't really matter)

    //upload the blob
    blockBlob.UploadFromStreamAsync(stream);

    //do more things and stuff and return something 
}

I just need to know how to implement the interface that will allow me to DI the AzureStorage class into SaveImageBlob as a Singleton. Not that it matters, but for posterity sake, I'm using Autofac for DI.

like image 889
crackedcornjimmy Avatar asked Mar 09 '23 15:03

crackedcornjimmy


1 Answers

The basic idea of a singleton consists of a private static instance variable and a public static Instance property that thread-safely checks if the instance variable is set, sets it if it isn't, then returns it.

using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using System;

public sealed class AzureStorage
{
    private static volatile AzureStorage instance;
    private static object syncRoot = new Object();

    public CloudStorageAccount StorageAccount { get; private set; }
    public CloudBlobClient BlobClient { get; private set; }
    public CloudBlobContainer Container { get; private set; }

    private AzureStorage()
    {
        StorageAccount = CloudStorageAccount.Parse(_config.ConnectionString);

        //instantiate the client
        BlobClient = StorageAccount.CreateCloudBlobClient();

        //set the container
        Container = BlobClient.GetContainerReference(_config.ImagesContainerName);

    }

    public static AzureStorage Instance
    {
        get
        {
            if (instance == null)
            {
                lock (syncRoot)
                {
                    if (instance == null)
                        instance = new AzureStorage();
                }
            }

            return instance;
        }
    }
}

The exercise left to the reader is to provide the configuration.

like image 199
tpsands Avatar answered Apr 08 '23 04:04

tpsands