Introduction

Azure BLOB storage is a persistent Cloud data storage that serves a variety of purposes. Windows Azure BLOB storage service can be used to store and retrieve massive amounts of unstructured data, such as text or binary data. Objects in Blob storage can be accessed from anywhere in the world via HTTP or HTTPS through URLs, the Azure Storage REST APIAzure PowerShellAzure CLI, or an Azure Storage client library.

Why use BLOB Storage?

There are many reasons why you should consider using BLOB storage. The most common usage are:

  • 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.

To demonstrate the use of BLOB Storage, we will be writing an Api that could be used to do a chat, stores text, music, video, audio files and also retrieves them. We will also be doing a database using SQL Server. To make use of this api, we will be doing a NativeScript chat app, but that will be for another blog. To follow along you will need to have installed Microsoft SQL Server Management Studio 2016 and Visual Studio 2017 with .NET Core 2.1 SDK.

First things first

Before creating the Api, you will need to create an azure account. You can do so by registering for a free trial. Then you will need to create a storage account.

To create a storage account, first you select the storage account option on the side. Then select Add and fill in the options:

  1. First write the name for your storage account. It can be any name
  2. In the deployment model choose Resource manager to get the latest features.
  3. On the account kind option select blob storage
  4. On the location option you select the region you want to host the blob storage on.
  5. On the replication option you can choose Locally reduntant storage (LRS), geo-reduntannt storage (GRS) or read-access geo-reduntannt storage (RA-GRS).

    Geo Replication means that the Windows Azure Table and BLOB data that you place into the account will not only be stored in the primary location but will also be replicated in triplicate to another data center within the same region.

    Storage accounts that have Geo Replication enabled are referred to as geo redundant storage (GRS) and cost slightly more than accounts that do not have it enabled, which are called locally redundant storage (LRS).

    RA-GRS provides read-only access to the data in the secondary location, in addition to geo-replication across two regions.

  6. On the performance option leave it to the fefault option
  7. On the Access tier option, you ca choose Hot or Cool.

    Hot storage has higher storage costs than cool and archive storage, but the lowest access costs.

    Cool storage tier has lower storage costs and higher access costs compared to hot storage.

  8. On the secure transfer required option you can choose to disable or enabling it. If you enabled it, this means that the REST Apis that make a request to the storage must be over HTTPS, otherwise the request will be denied
  9. On the subscription option, if you have a free trial Azure account you can choose Free Trial, otherwise you need to have a Pay-As-You-Go subscription plan.
  10. On the Resource group you can either create one or choose an existing one.

Next you will want the the access keys to be able to authenticate your requests to your Azure storage account. In this case you will use the connection string in the following page.

Creating the Database

For this tutorial we will be using a simple schema that stores the information we need for a chat where we can store files:

  1. ChatRoom – This table will simply represent the chat room. We’re using a unique identifier column because we will be using it as the name for the container for the blob
  2. Member – This table represents the member in the chat room.
  3. Message – this table represents the message sent to the chat room by a member. It contains a nullable column for the message type since the message doesnt necessarily have to be a blob.
  4. MessageType – This table represents the type of the message. The types will be Audio, Document, Video or Image.
  5. ChatRoomMember – This is a many to many table that represents the relationship between ChatRoom and Member.
  6. ChatRoomMessage – This is a many to many table that relates the message that a member sent to a chat.
  7. BlobData – This is the table that will store the information needed to fetch the blobs and relate it to a message.

The database we will be created through Visual Studio 2017. First we will be creating a Web Api project through Visual Studio 2017 with Asp NetCore 2.1.

When choosing the template, we will choose the API option, just like in the screenshot

Then we will create a database project in the solution called ChatDb:

Next we will create 7 tables inside the ChatDb project with the following names:

Below you will see the create statements for each of the tables in the database project:

Seed Data

Since in the Api we will only sending messages, we will create seed data for the members, chats and the relationships between the members and chats. First we will create another database project called SeedData:

We will create the scripts by choosing the Not in build option:

For the StartupScript we will choose the Build option:

This is the INSERT statement for each of the scripts:

ChatRoomSeedData:

INSERT INTO ChatRoom DEFAULT VALUES
INSERT INTO ChatRoom DEFAULT VALUES
INSERT INTO ChatRoom DEFAULT VALUES
INSERT INTO ChatRoom DEFAULT VALUES
INSERT INTO ChatRoom DEFAULT VALUES

MemberSeedData:


INSERT INTO Member (MemberName)
VALUES ('John Doe'), ('Jane Doe'), ('Richard Doe'), ('James Doe'), ('Charles Doe')

MessageTypeSeedData:


INSERT INTO MessageType (MessageType)
VALUES ('Document'), ('Audio'), ('Image'), ('Video')

ChatRoomMemberSeedData:


INSERT INTO ChatRoomMember (ChatRoomId, MemberId)
VALUES (1, 1), (1, 2), (2, 3), (2, 4)

StartupScript:

print ‘Deploying MemberSeedData’
go
:r .\MemberSeedData.sql
go
print ‘Deployed MemberSeedData’

print ‘Deploying ChatRoomSeedData’
go
:r .\ChatRoomSeedData.sql
go
print ‘Deployed ChatRoomSeedData’

print ‘Deploying ChatRoomMemberData’
go
:r .\ChatRoomMemberData.sql
go
print ‘Deployed ChatRoomMemberData’

print ‘Deploying MessageTypeData’
go
:r .\MessageTypeData.sql
go
print ‘Deployed MessageTypeData’

Deploying the Database project

First you will need to publish the database project to you local SQL Server. Right click on the ChatDb project and click on publish. You will see the following dialog:

Then click on Edit and you will see the following dialog:

Click on Show Connection Properties and set the fields as shown on the screenshot above. Click Ok and then click on Publish. Do the same steps for the SeedData project to deploy and insert the data into the tables.

Scaffold the database

We will scaffold the database to generate the code needed to access the database and store data in it. First create a .NET Standard class library project that will hold the code that the scaffolding will generate:

In this tutorial we will use a Visual Studio Extension called SQLite/SQL Server Compact Toolbox to scaffold the database and generate our code. Download version 4.7.234 from this link. After you install the extension, make sure that you add the Database connection by going to Server Explorer and then right click on Data Connections as in the following screenshot:

Choose Microsoft SQL Server and then press continue. You will then see a dialog like the one below:

On server name type . and then select the database ChatDb. Press OK. Next click on the new project you just created, then go to the SQLite/SQL Server Compact Toolbox, right click the Database you just added and then press on the Add EF Core Model to current project option. Then you will see a list of the tables in the Chat database. Press Ok. You should then see the following dialog:

Make sure that the correct name is already in the Namespace box. If not, you will to do the above steps again and make sure you first click on the project before opening the SQLite/SQL Server Compact toolbox. After you fill the Context name and the project name as in the image above, press Ok. After it generates the code it might show a warning that you dont have the Microsoft.EntityFrameworkCore.SqlServer Nuget package. If that’s the case, go ahead and install it:

Creating the Api

In this api we will be using a simple Request/Response pattern. First create a project which will contain our services. In this tutorial we will only be creating a service called MessageService which will only be used to send messages and get a file:

To process sending a message, we will create a method called SendMessage which will accept a SendMessageRequest object as a parameter and return a SendMessageResponse object.

You will need to create the SendMessageRequest class. I created it in a separate project which will hold all of my classes that represent a request:

As for the SendMessageResponse class, I also created a separate project which will hold all of the classes that represent a response.

Now we’re ready to do the logic to store a message in the database

Before proceeding to do the logic to store a message, first you need to create a service which will be used to store a file to the azure blob. We’re calling it AzureBlobService. In this service we will have the logic to upload a file and to download a file. You will need to install the WindowsAzure.Storage Nuget Package.

We’ll also be using Dependency Injection so you will need to create the interface of the service which will be created in a separate project that will hold the interfaces:

Now that we have the service that download/uploads to the blob, we can go ahead and create the logic to store a message:

Notice that in the constructor we’re injecting IOptions and IAzureService. You will need to register these two dependendencies which we will do later on.

In the SendMessage method, first we’re getting the first file from the collection. If the file object is not null we will map the data that we need to the FileViewModel object in the request. Then we’re going to get the id of the message type which we will need it to store which type of file we’re storing in the database. Notice that we’re using the ChatDbContext which was generated earlier when we did scaffolding to access the database entities.

Then we’ll query for the chat room that we passed in the request to get the unique identifier which we’ll use to set the container name for the azure storage. We’re only using a max of 60 characters, the max characters that azure blobs allow for the container name is 68.

We created a method that returns a ChatRoomMessage Object which we’ll store in a local variable so that we can then store it in the database and later get the data needed for the response that the Api will return. If the file isnt null then we will upload the file to the azure storage as a blob.

The GetFile method will be used to retrieve the blob details from the database and then pass it to the download method in the AzureBlobService to fetch the file and stream it so it can be consumed. Notice that you also need to create the interface for the MessageService.

Next in the WebApi project, the one we created when we first created the solution, we will create a static class where we will define an extension method to register the services and the BlobOptions class:

We will then invoke the AddChatApiServices method in the Startup class:

Notice that we’re passing the Configuration object to the AddChatApiServices method which contains the BlobOptions configuration from the appsettings.json:

Next we create the MessagesController where we will define the endpoints to be consumed in the NativeScript. We will inject the IMessageService into the constructor:

We’re using two api methods, one to send the request as a Form to be able to send a file using the FromForm attribute and another one to send the request if you dont need to send a file, using the FromBody attribute. You can also use the api method that accepts a form even if you dont need to send a file. Also notice that on the api method where you can send a form im invoking this method:

result.File.Href = Url.Link(nameof(GetFile), new { fileId = result.File.FileId });

That is used to generate the url for the file dynamically.

Now that the api is done, we can test it by running the Api locally using ISS Express and using Postman to send the request and make sure that its storing the message:

We see now that the schema works and now we can store messages to the database and to an azure storage blob. This is the project structure that we ended with:

Everything so far in a nutshell

Now that you know how to create an azure storage account, create a database with a minimal schema for a chat that be used to store files and retrieve them through an api using dependency injection, we can now create a client that can consume these apis. In my next blog we will do so through a NativeScript app. Stay tuned!