Creating a photo album for ASP.NET MVC 5 Users using Azure BLOB storage

In this blog post, we will integrate ASP.NET MVC with Azure BLOB Storage by saving an image for an ASP.NET Identity 2.0 user in Azure BLOB Storage. We’re going to cover a lot of ground in this post, including:

  • Using ASP.NET Identity 2.0 user as reference in other table.
  • Creating a one to many relationship with ASP.NET Identity 2.0 user table
  • Connecting an ASP.NET MVC application to Azure Storage
  • Creating or Uploading a BLOB
  • Deleting a BLOB
  • Downloading a BLOB
  • Uploading a file from MVC form to a Azure BLOB

The final output of the blog post we plan on creating in this post will look more or less like the image below. As you can see, a user can upload a photo to her album, delete a photo, and of course, view photos too.

image

Architecture of the Application

The High-level architecture of the application can be drawn as shown in the image below:

image

Creating tables to save images

When we create an ASP.NET MVC application using the given MVC template in Visual Studio, by default, a basic authentication gets created using the ASP.NET Identity 2.0. In a default MVC project, a template for the authentication and authorization purpose ASP.NET Identity 2.0 creates the tables as shown in the image below:

Read full article on the Infragistics Blog

How to create a Container in Azure Storage from MVC application

I am working on a MVC application in which I need to work with Microsoft Azure storage .I had a requirement to create An Azure storage container from the MVC application. In this post I will share my learning that how I created a container programmatically.

I created the view as shown in below image. User has to enter the azure storage account name, azure storage key and the name of the container to be created.

image

Above View is MVC razor view, and it is created using the cshtml as shown below:

 


@{
    ViewBag.Title = "BLOB Manager";
}
<div class="jumbotron">
    <div class="row">
        <div class="col-md-8">
            <section id="loginForm">
                @using (Html.BeginForm("AzureInfo", "Manage", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
                {
                    @Html.AntiForgeryToken()
                    <h2> Manage BLOB Container</h2>
                    <hr />
                    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
                    <div class="form-group">
                        <div class="col-md-10 input-group input-group-lg">
                            @Html.TextBox("AccountName", "", new { @class = "form-control", @placeholder = "Account Name" })
                            @Html.ValidationMessage("AccountName", "", new { @class = "text-danger" })
                        </div>
                    </div>
                    <div class="form-group">

                        <div class="col-md-10 input-group input-group-lg">
                            @Html.TextBox("AccountKey", "", new { @class = "form-control", @placeholder = "Account Key" })
                            @Html.ValidationMessage("AccountKey", "", new { @class = "text-danger" })
                        </div>
                    </div>
                    <div class="form-group">

                        <div class="col-md-10 input-group input-group-lg">
                            @Html.TextBox("ContainerName", "", new { @class = "form-control", @placeholder = "Container Name" })
                            @Html.ValidationMessage("containername", "", new { @class = "text-danger" })
                        </div>
                    </div>
                    <div class="form-group input-group input-group-lg">
                        <div class="col-md-offset-2 col-md-10">
                            <input type="submit" value="Create Container" class="btn btn-lg btn-success" />
                        </div>
                    </div>

                }
            </section>
        </div>
    </div>
</div>

Above I am creating,

  • Three text boxes with the placeholder and the class set to bootstrap form-control
  • A submit button with the class set to bootstrap btn-lg and btn-success
  • All the controls are inside the form.
  • On form post operation, AzureInfo action of the Manage controller will be called.

Once the View is ready, let us go ahead and create an azure utility class. In this class we will put all the operations related to the azure storage. But before that you need to add Azure storage library to the project. Either you can use NuGet package manager or console to add the library. I am using console to install Azure storage library. I have taken the 4.3 version because at the time of writing this post, this was the latest stable version available.

image

Once package is successfully installed, add following namespaces.

 


using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.WindowsAzure;

To create the container in the Azure storage, I have created a function CreateContainer. This function takes three input parameters, account name, account key and the container name.

 


public static class AzureUtility
    {
        public static string  CreateContainer(string AccountName, string AccountKey, string ContainerName)
        {

            string UserConnectionString = string.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}", AccountName, AccountKey);
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(UserConnectionString);
            CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
            CloudBlobContainer container = blobClient.GetContainerReference(ContainerName.ToLower());
            if (container.CreateIfNotExists())
            {
                container.SetPermissions(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob });
                return container.Name;
            }
            else
            {
                return string.Empty;
            }
        }
    }

Now let us examine the above code line by line.

  • In first line I created the connection string for the azure storage. It takes two parameters, account name and the account key. These values are passed as input parameter to the function. I am using these two parameter to create connection string.
  • Using CloudStorageAccount to parse the connection string from the constructed string.
  • Creating the CloudBlobClient
  • Getting the container reference of the BLOB.
  • If container reference does not exist, creating new container.
  • On successful creation of the container function returns name of the container else empty string.

 


[HttpPost]
        public ActionResult AzureInfo(string AccountName, string AccountKey, string ContainerName)
        {

           var result= AzureUtility.CreateContainer(AccountName, AccountKey, ContainerName);

           if (result != string.Empty)
             {

                 return RedirectToAction("Index", "Home");
             }
             else
             {
                 return RedirectToAction("Index");
             }
        }

In the action we are using the utility class to create the container. In this way an azure container can be created from the MVC application.

I hope it is useful. Thanks for reading. Happy Coding.

Conditional Reading of Windows Azure BLOB

Conditional reading of BLOB implies, you want to read BLOB only when BLOB is modified. There are scenarios when you need to read BLOB frequently. In that case to avoid network usage and bandwidth, you may consider reading BLOB only when BLOB has been modified since last read or download. This type of BLOB reading is termed as Conditional BLOB reading.

Usually to read or download BLOB, you create reference of BLOB as below

image

In above code snippet

  1. ConnectionString is connection string to your storage account.
  2. Containername is name of the public container.
  3. Doc1.docx is name of the BLOB.

If you want to read it without any condition or in other words you want to read the BLOB regardless of whether it has been modified or not then you can read it in byte array as below,

image

As of now everything is fine for unconditional read but if you want to do Conditional read on the BLOB then you will have to use ,

  • IfNoneMatch
  •  eTag

IfNoneMatch is a static variable of AccessCondition structure. When you download a BLOB you can additionally provide BLOBRequestOptions. Almost all Download functions are overloaded with BlobRequestOptions.

image

If you don’t specify BLOBRequestOptions then you will perform unconditional read.

To perform conditional read, you need to follow below steps,

Step 1

Save ETag value from the server at time of first reading in a local variable

clip_image001

Step 2

Create instance of BLOBRequestOptions with setting AccessCondition as below,

clip_image001[6]

In above code we are passing locally saved ETag value to IfNoneMatch

 

Step 3

At time of making second call onward to download BLOB pass Request Option as below,

clip_image002

If BLOB is not modified then you will get into the Exception

At time of downloading BLOB in above code, server will fist check for the ETatg in IfNoneMatch header. If server don’t find new version, it will send HTTP 304 request to the storage library.

For your reference full source code of conditional BLOB reading is as below,


using System;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;

namespace ConsoleApplication7
{
class Program
{
static void Main(string[] args)
{

CloudStorageAccount account = CloudStorageAccount.
Parse("connectionString");

CloudBlobClient BlobClient = account.CreateCloudBlobClient();

CloudBlobContainer ContainerReference = BlobClient.
GetContainerReference
("dhananjay");

CloudBlob BlobReference = ContainerReference.
GetBlobReference
("Doc1.docx");

byte[] DownloadAsByteArray = BlobReference.DownloadByteArray();

var LastReadETag = BlobReference.Properties.ETag;

BlobRequestOptions RequestOption = new BlobRequestOptions
{ AccessCondition = AccessCondition.IfNoneMatch
(LastReadETag)
};

try
{
byte[] DownloadByteArraySecondTimeOnward = BlobReference.
DownloadByteArray(RequestOption);

}
catch (StorageClientException ex)
{
if (ex.StatusCode == System.Net.HttpStatusCode.NotModified)
{

}
}

}
}

}

&nbsp;

In this way you can perform conditional reading on Windows Azure BLOB. I hope this post is useful. Thanks for reading  Smile

 

If you find my posts useful you may like to follow me on twitter http://twitter.com/debug_mode or may like Facebook page of my blog http://www.facebook.com/DebugMode.Net If you want to see post on a particular topic please do write on FB page or tweet me about that, I would love to help you.

Downloading file as byte array from AZURE BLOB storage in WCF Service

In this post I will show you how you can download a file from AZURE BLOB storage as byte array.

Contract


using System.Collections.Generic;
using System.IO;
using System.ServiceModel;
using WcfService15testapi.Entities;

namespace WcfService15testapi
{

    [ServiceContract]
    public interface IService1
    {

       [OperationContract]

        byte[] DownLoadFileForBLOB(string ContainerName, string fileName);
    }

}

To download file client will have to provide ContainerName and filename to be downloaded.

Service Implementation

Very first you need to add reference of,

Microsoft.WindowsAzure

Microsoft.WindowsAzure.StorageClient

Second you need to create connection string to fetch file from AZURE BLOB.

Connection String

DefaultEndPoint=https;AccountName=STORAGEACCOUNTNAME;AccountKey=ACCOUNTKEY

So if yours,

Storage Account Name = “Test Account

Storage Account Key = “xxxxxxxxxxxxxxxxxxxxxx/xxxxxxx==” 

Then connection string to AZURE Storage account would be,

DefaultEndPoint=https;AccountName= Test Account;AccountKey= xxxxxxxxxxxxxxxxxxxxxx/xxxxxxx==

Container Name

We are going to downloads file from public container. Let us say public container name is TESTCONTAINER.

Full Service implementation is as below,


using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Xml.Linq;
using WcfService15testapi.Entities;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;

namespace WcfService15testapi
{

    public class Service1 : IService1
    {
        public byte[]   DownLoadFileForBLOB (string ContainerName, string fileName)
        {

            CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName= Test Account;AccountKey=xxxxxxx==");
            CloudBlobClient cloudBlobClient = cloudStorageAccount.CreateCloudBlobClient();
            CloudBlobContainer cloudBlobContainer = cloudBlobClient.GetContainerReference(ContainerName);
            CloudBlob cloudBlob = cloudBlobContainer.GetBlobReference(fileName);
            byte[] byteData = cloudBlob.DownloadByteArray();
                        return byteData;

        }
    }
}

Creating X.509 certificate from Windows Azure BLOB

Sometime you may have to create X.509 certificate on the fly. Imagine you are writing a WCF Service to be hosted in App Fabric or creating a WCF Service Web Role to be hosted in Microsoft Data center. In these scenarios you don’t have access to local file system and in the service you are performing Azure subscription level operation using Windows Azure Management API. So to authenticate WCF Service against Windows Service subscription you need to provide the certificate.

 

image

 

Essentially there are three steps involved in this process,

  1. Read X.509 Certificate file (.cer) from AZURE BLOB.
  2. Create X.509 certificate from the downloaded file from Azure BLOB.
  3. Pass the created certificate as part of request to authenticate.

 

Read Certificate file from Windows AZURE BLOB storage as byte array

image

In above code snippet, we are reading certificate file from BLOB as an array of byte data. You need to add reference of Microsoft.WindowsAzure and Microsoft.WindowsAzure.StorageClient . Container Name is name of your public container.

Create X.509 certificate

Once you have byte array form Azure BLOB, you can create X.509 certificate to be authenticated using the byte array as below,

image

Pass the Certificate to authenticate

 

clip_image001

clip_image002

Here while making call you can add certificate created from AZURE BLOB file .

For your reference full source code is as below,

 



using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Xml.Linq;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;



namespace ConsoleApplication26
{
    class Program
    {
        static void Main(string[] args)
        {

                      CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse("DataConnectionString");
            CloudBlobClient cloudBlobClient = cloudStorageAccount.CreateCloudBlobClient();
            CloudBlobContainer cloudBlobContainer = cloudBlobClient.GetContainerReference("ContainerName");
            CloudBlob cloudBlob = cloudBlobContainer.GetBlobReference("debugmode.cer");
            Console.WriteLine(cloudBlob.DownloadText());
            Console.ReadKey(true);
            byte[] byteData = cloudBlob.DownloadByteArray();
            X509Certificate2 certificate = new X509Certificate2(byteData);

           var request = (HttpWebRequest)WebRequest.Create("https://management.core.windows.net/697714da-b267-4761-bced-b75fcde0d7e1/services/hostedservices");
           request.Headers.Add("x-ms-version:2009-10-01");
           request.ClientCertificates.Add(certificate);

            var response = request.GetResponse().GetResponseStream();
            var xmlofResponse = new StreamReader(response).ReadToEnd();

            XDocument doc = XDocument.Parse(xmlofResponse);
            XNamespace ns = "http://schemas.microsoft.com/windowsazure";
            var servicesName = from r in doc.Descendants(ns + "HostedService")
                               select new HostedServices
                               {
                                   serviceName = r.Element(ns + "ServiceName").Value
                               };

            foreach (var a in servicesName)
            {
                Console.WriteLine(a.serviceName);
            }



            Console.ReadKey(true);


        }

        static public  byte[] ReadToEnd(System.IO.Stream stream)
        {
            long originalPosition = stream.Position;
            stream.Position = 0;
            try
            {
                byte[] readBuffer = new byte[4096];
                int totalBytesRead = 0;
                int bytesRead;
                while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
                {
                    totalBytesRead += bytesRead;
                    if (totalBytesRead == readBuffer.Length)
                    {
                        int nextByte = stream.ReadByte();
                        if (nextByte != -1)
                        {
                            byte[] temp = new byte[readBuffer.Length * 2];
                            Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
                            Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
                            readBuffer = temp;
                            totalBytesRead++;
                        }
                    }
                }
                byte[] buffer = readBuffer;
                if (readBuffer.Length != totalBytesRead)
                {
                    buffer = new byte[totalBytesRead];
                    Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
                }
                return buffer;
            }
            finally
            {
                stream.Position = originalPosition;
            }
        }

     public    class HostedServices
        {
            public string serviceName { get; set; }
        }
    }
}


 

I hope this post was useful. Thanks for reading Smile