Intro to Azure Storage with .Net 5
Tags: azure, serverless, storage, dotnet
Published: 2021-02-18 10:44:52

In this article i will explaining to you how we can utilise Azure Storage specifically Blobs in our application.

You watch the full step by step video on Youtube
{% youtube B_yDG35lb5I %}

You also get the source code from Github:
https://github.com/mohamadlawand087/v15-AzureStorage

So what are we going to cover today:

- What do we need to get started
- Azure Storage basics
- The structure of our application
- Code

If you find this video helpful, please like, share and subscribe as it will really help the channel.

Before we start you will need to have 

- Azure account (https://portal.azure.com)
- Dotnet SDK ([https://dotnet.microsoft.com/download](https://dotnet.microsoft.com/download))
- Visual Studio Code ([https://code.visualstudio.com/](https://code.visualstudio.com/))

So what are we going to build today, we will build a sample application which will list all of the blobs that we have, we will be able to add and delete blobs as well.

Azure storage is a highly scalable service in azure allowing us to store files, images, tables, videos, unstructured data, messages and NoSql databases.

Azure storage features: 

- durable: high availability data centers managed by Microsoft
- secure: All data is encrypted
- scalable
- managed
- accessible: API and SDKs available to integrate with these services

Services that are part of storage account 

- Blob
- File
- Queue
- Table

**Blob Storage:** 

[Azure Blob storage](https://azure.microsoft.com/services/storage/blobs/) is a service for storing large amounts of unstructured object data, such as text or binary data. You can use Blob storage to expose data publicly to the world, or to store application data privately. Common uses of Blob storage include:

- Serving images or documents directly to a browser
- Storing files for distributed access
- Streaming video and audio
- Storing data for backup and restore, disaster recovery, and archiving
- Storing data for analysis by an on-premises or Azure-hosted service

Structure of blob storage

Account → Container → Files

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k7pko3ce1svftisgddsr.png)

**File Storage**

Its a service that allows your to create fully managed file shares in the cloud that are accessible

via Server Message Block (SMB) and Network File Service (NFS)

It has the same structure as blob storage the main difference is that instead of only hosting files it contains folders 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t7wce8qo3jd1qurcaqht.png)

So when do you choose Blob or File storage, if you use Lift and Shift you should use File Storage other then that Blob storage is recommended due to its maturity levels.

**Storage Queue**

Azure Queue Storage provides cloud messaging between application components. Queue Storage delivers asynchronous messaging between application components, whether they are running in the cloud, on the desktop, on an on-premises server, or on a mobile device.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g7b5w7hu3vdczvea8dyi.png)

Its a simple messaging service which can be utilised in Azure Storage

**Table Storage**

Azure Table storage stores large amounts of structured data. The service is a NoSQL datastore which accepts authenticated calls from inside and outside the Azure cloud. Azure tables are ideal for storing structured, non-relational data.

It is the simplest NoSql db we can use but its also very secure and scalable, storage tables are seperated into datable and every table will contain NoSql data

Every record can be public or private depends on the configuration of the table.

Common use cases

- Storing tables of structured data capable of serving web scale applications
- Storing datasets
- Quickly querying data using a clustered index
- Accessing data using the OData protocol and LINQ queries

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wce1iw948fy0yh0evqog.png)

Now lets jump into coding

We will need first to create a new mvc application using the dotnet new keyword

```bash
dotnet new mvc -n "BlobSampleApp"
```

Now we need to add Blob nuget package

```bash
dotnet add package Azure.Storage.Blobs --version 12.8.0
```

Once the application is created we need to add a folder to the root directory of our application called Services

Inside the Services folder we need to create 2 files IBlobService and BlobService lets start with the interface

```csharp
public interface IBlobService
{
	  Task<string> GetBlob(string name, string containerName);
    Task<IEnumerable<string>> AllBlobs(string containerName);
    Task<bool> UploadFileBlob(string name, IFormFile file, string containerName);
    Task<bool> DeleteBlob(string name, string containerName);
}
```

```csharp
public class BlobService : IBlobService
{
    public Task<IEnumerable<string>> AllBlobs(string containerName)
    {
        throw new System.NotImplementedException();
    }

    public Task<bool> DeleteBlob(string name, string containerName)
    {
        throw new System.NotImplementedException();
    }

    public Task<string> GetBlob(string name, string containerName)
    {
        throw new System.NotImplementedException();
    }

    public Task<bool> UploadFileBlob(string name, IFormFile file, string containerName)
    {
        throw new System.NotImplementedException();
    }
}
```

The next step is creating a Blob resource on Azure, we need to navigate in our browser to portal.azure.com

- click on create resource
- In the search bar type "storage account"
- select Storage Account from the result list
- Click on create
- Create or select a resource group
- Give it a name "mlyoutubedata"
- choose a location
- Select Standard in performance
- Account kind StorageV2
- Replication Locally redundant storage LRS
- Now lets click on create and review
- and then create

This should take few minutes to be complete, once the task is completed we need to go to the resource

- Select containers
- click on Add container
- Give it a name "personal"
- keep the access level to public (only for testing)
- click on create

The last step is to get the keys which will allow us to communicate with our blob storage.

lets navigate to the main storage resource and click on Access keys under settings and lets copy the connection string 

Now lets navigate back to our code and inside our appsettings.json lets add the following

```json
"BlobConnection" : "xxxxxxxxxConnectionStringFromAzurexxxxxxxxxxxxx"
```

Next we will need to go to our startup class and register our blob client, inside our ConfigureServicesMethod we need to add the following

```csharp
// Initialising the BlobService, this will allow us to inject the blob 
// client into our service
var blobConnection = Configuration.GetValue<string>("BlobConnection");
services.AddSingleton(x => new BlobServiceClient(blobConnection));

// We need to add our own custom blob service
services.AddSingleton<IBlobService, BlobService>();
```

Now lets start implementing our Service

```csharp
public class BlobService : IBlobService
{
    private readonly BlobServiceClient _blobClient;

    public BlobService(BlobServiceClient blobClient)
    {
        _blobClient = blobClient;
    }
    
    public async Task<IEnumerable<string>> AllBlobs(string containerName)
    {
        // This will me to access data inside the personal container
        var containerClient = _blobClient.GetBlobContainerClient(containerName);
        var files = new List<string>();

        var blobs = containerClient.GetBlobsAsync();

        // We are awaiting a foreach here as the 
        // blobs are streambale objects we need to wait until they are available
        await foreach(var item in blobs)
        {
            files.Add(item.Name);
        }

        return files;
    }

    public async Task<bool> DeleteBlob(string name, string containerName)
    {
       // This will me to access data inside the personal container
        var containerClient = _blobClient.GetBlobContainerClient(containerName);
        var blobClient = containerClient.GetBlobClient(name);
        return await blobClient.DeleteIfExistsAsync(); 
    }

    public async Task<string> GetBlob(string name, string containerName)
    {
         // In order for us to get access to anything inside our blob 
        // We first need to connect to the blob container 
        // and then we need to get the container client which referes to the 
        // specific container we want to access

        // This will me to access data inside the personal container
        var containerClient = _blobClient.GetBlobContainerClient(containerName);
        var blobClient = containerClient.GetBlobClient(name);

        var str = blobClient.Uri.AbsoluteUri;

        return str;
    }

    public async Task<bool> UploadFileBlob(string name, IFormFile file, string containerName)
    {
        try
        {
            var containerClient = _blobClient.GetBlobContainerClient(containerName);

            // The idea of getting a reference to a blob client which doesnt exist 
            // is the way Azure blobs are implemented, we initiate these client 
            // and then we do checks if actually exist or not and then we can perform
            // any action we want upload, delete ...
            var blobClient = containerClient.GetBlobClient(name);
            //var blobClient1 = containerClient.GetBlobClient("1"+name);

            var httpHeaders = new BlobHttpHeaders() { 
                ContentType=file.ContentType 
            };

            var blobInfo = await blobClient.UploadAsync(file.OpenReadStream(), httpHeaders);

            if(blobInfo != null)
                return true;
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
        }           

        return false;
    }
}
```

Now after our service is ready lets build our controller, inside our controllers folder lets create a new controller called "FilesController"

```csharp
public class FilesController : Controller
{
    private readonly IBlobService _blobService;

    public FilesController(IBlobService blobService)
    {
        _blobService = blobService;
    }
    
    [HttpGet]
    public async Task<IActionResult> Index()
    {
        var files = await _blobService.AllBlobs("personal");
        return View(files);
    }

     [HttpGet]
    public async Task<IActionResult> ViewFile(string name)
    {
        var res = await _blobService.GetBlob(name, "personal");
       
        return Redirect(res);
    }

     [HttpGet]
    public async Task<IActionResult> DeleteFile(string name)
    {
        await _blobService.DeleteBlob(name, "personal");

         return RedirectToAction("Index");
    }

    [HttpGet]
    public IActionResult AddFile()
    {
        return View();
    }
    
    [HttpPost]
    public async Task<IActionResult> AddFile(IFormFile file)
    {
         if (file == null || file.Length <= 0) return View();

        if (file!=null)
        {
            string fileName= Guid.NewGuid().ToString() + Path.GetExtension(file.FileName.Replace(" ",""));
            var res = await _blobService.UploadFileBlob(fileName, file, "personal");

            if(res)
                return RedirectToAction("Index");
        }
        return View();
    }  
}
```

Then we need to create a folder called Files inside our Views folder, then we need to create a file called index.cshtml and update to the below

```csharp
@model List<string>

<div class="row">
    <div class="col-md-12">
        <a asp-action="AddFile" asp-controller="Files" class="btn btn-success"> upload files</a>
    </div>
     <div class="col-md-12">
        <ul>
@foreach (var item in Model)
{
    <li>
        <a asp-action="ViewFile" asp-controller="Files" asp-route-name="@item" target="_blank"> @item</a> - <a asp-action="DeleteFile" asp-controller="Files" asp-route-name="@item" class="btn btn-danger"> Delete</a>
    </li>
}
</ul>
    </div>
</div>
```

Lastly we need to create our AddFile view by adding a file called AddFile.cshtml and update the code to the below

```csharp
<form class="col-xs-12" method="post" asp-action="AddFile" asp-controller="Files" enctype="multipart/form-data">

     <div class="form-group">
        <input type="file" class="form-control" name="file" />
     </div>

     <div class="form-group">
        <button type="submit" class="btn btn-primary col-xs-12">Add</button>
     </div>
  </form>
```

Thank you for reading, please share and like if you find it useful