Sunday, January 31, 2016

windows azure cloud computing - Part 2 : Sample CRUD application using Azure tables


Plan

Introduction

In this chapter, we will explain step by step the creation of an Asp.Net web application that works with Azure table services.

Using the code

Prerequisite :

in this section we will define only useful classes and methods that we will used to create our sample application .

0) CloudStorageAccount class :

represents a windows azure storage account.
Methods  :
  • Parse(String connection_string) : parse a connection string and create a CloudStorageAccount object from connection string parameter.
  • CloudTableClient CreateCloudTableClient() : create a Table service client that allow us to create a table in Azure storage.

1) CloudTableClient class :

Methods  :
  • GetTableReferencet(string table_name ) :  get a reference to specified table identified by table_name parameter.

2) CloudTable class :

Represents a windows Azure table.
Methods  :
  • boolean CreateIfNotExists() : create table if not exists in the storage and return true if table is recently created, else it will return false.
  • Execute(TableOperation) : execute a specific query on a table.

3) TableOperation class :

Methods  :
  • InsertOrReplace(TableEntity table_entity) : this method can execute two operations  : updating if given entity exists in the table entities, insertion if  given tableEntity doesn't exists in table entities.
TableEntity : Represents the base object type for a table entity in the Table service.

For more documentation about Azure classes and methods you can visit the following link : Azure Table Documentation

Coding :

0) Environment setup :

Before you start coding, you need to download windows azure storage. In my case i used Nuget Package Manager :



check your project references :

1) Create a Server side

Models :
  • PersonEntity class : 
this class inherit from TableEntity, is used to create a new entity.

 using Microsoft.WindowsAzure.Storage.Table;  
 namespace DataTableStorage1Sample.Model  
 {  
   public class PersonEntity : TableEntity  
   {  
     // Your entity type must expose a parameter-less constructor  
     public PersonEntity() { }  
     // Define the PK and RK  
     public PersonEntity(string PartitionKey, string RowKey)  
     {  
       this.PartitionKey = PartitionKey;  
       this.RowKey = RowKey;  
     }  
     public string firstName { get; set; }  
     public string lastName { get; set; }  
   }  
 }  

  • AzureTableManager class :
this class contains a static methods, that allow user to  :
  • Get a reference of Azure storage Account (in our case we used the local storage),
  • Create or get a reference of Azure table by Name.
  • Create, update, delete and retrieve entities from an given Azure table.

 using System;  
 using System.Net;    
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Web;  
 using Microsoft.WindowsAzure;    
 using Microsoft.WindowsAzure.Storage;    
 using Microsoft.WindowsAzure.Storage.Table;    
 using System.Collections.Generic;    
 using DataTableStorage1Sample.Model;  
 using System.Configuration;  
 namespace WebApplicationTables.Models  
 {  
   public class AzureTableManager  
   {  
   internal const string TableName = "Person";  
   private static CloudStorageAccount CreateStorageAccountFromConnectionString(string storageConnectionString)  
   {  
     CloudStorageAccount storageAccount;  
     try  
     {  
       //get a reference for our Azure storage account  
       storageAccount = CloudStorageAccount.Parse(storageConnectionString);  
     }  
     catch (FormatException)  
     {  
       Console.WriteLine("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the application.");  
       throw;  
     }  
     catch (ArgumentException)  
     {  
       Console.WriteLine("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the sample.");  
       Console.ReadLine();  
       throw;  
     }  
     return storageAccount;  
   }  
   public static CloudTable CreateTable()  
     {  
       // Retrieve storage account information from connection string.  
       CloudStorageAccount storageAccount = CreateStorageAccountFromConnectionString(ConfigurationManager.ConnectionStrings["StorageConnectionString"].ToString());  
       // Create a table client for interacting with the table service  
       CloudTableClient tableClient = storageAccount.CreateCloudTableClient();  
       // Create a table client for interacting with the table service   
       CloudTable table = tableClient.GetTableReference(TableName);  
       try  
       {  
         if (table.CreateIfNotExists())  
         {  
           Console.WriteLine("Created Table named: {0}", TableName);  
         }  
         else  
         {  
           Console.WriteLine("Table {0} already exists", TableName);  
         }  
       }  
       catch (StorageException)  
       {  
         return null;  
       }  
       return table;  
     }  
    public static Boolean InsertEntity(CloudTable table, PersonEntity entity)  
    {  
      //i used insertorreplace method for updating and insertion operation  
      TableOperation insertOrMergeOperation = TableOperation.InsertOrReplace(entity);  
      // Execute the operation.  
      TableResult result =  table.Execute(insertOrMergeOperation);  
      PersonEntity insertedCustomer = result.Result as PersonEntity;  
      //check if the operation is well processed  
      if (insertedCustomer == null)  
      {  
        return false;  
      }  
      return true;  
    }  
    public static List<PersonEntity> RetreiveAllEntries(CloudTable table)  
    {  
      //find all available entities from given Azure table  
      var entities = table.ExecuteQuery(new TableQuery<PersonEntity>()).ToList();  
      return entities;  
    }  
    public static Boolean DeleteEntity(CloudTable table, string partitionKey, string rowKey)  
    {  
       //create our delete operation   
      TableOperation retrieveOperation = TableOperation.Retrieve<PersonEntity>(partitionKey, rowKey);  
      //execute the query  
      TableResult result =  table.Execute(retrieveOperation);  
      PersonEntity personEntity = result.Result as PersonEntity;  
      //check if the operation is well processed  
      if (personEntity == null)  
      {  
        return false;  
      }  
      //delete an existing entity  
      TableOperation deleteOperation = TableOperation.Delete(personEntity);  
      table.Execute(deleteOperation);  
      return true;  
    }  
   }  
 }  

Controllers :
  • RestAzureTableMethodsController class :
this class inherits from ApiController, that implement Restful services that permit to :
  • add a new entity to Azure table,
  • modify some attributes of an existing entity in Azure table,
  • delete an existing entity from Azure table,
  • retrieve all entities from an existing Azure table.

 using DataTableStorage1Sample.Model;  
 using Microsoft.WindowsAzure.Storage.Table;  
 using Newtonsoft.Json;  
 using Newtonsoft.Json.Linq;  
 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Net;  
 using System.Net.Http;  
 using System.Web;  
 using System.Web.Http;  
 using System.Web.Script.Serialization;  
 using WebApplicationTables.Models;  
 namespace WebApplicationTables.Controllers  
 {  
   public class RestAzureTableMethodsController : ApiController  
   {  
      [HttpGet]  
     public HttpResponseMessage insertEntity()  
     {  
        //get reference of current request  
        var request = HttpContext.Current.Request;  
        var status = false;  
       try{  
         //get parameters : obj is json object  
         var obj = request.Params["obj"];  
         //create a new entity from given parameter   
         PersonEntity personEntity = JsonConvert.DeserializeObject<PersonEntity>(obj);  
         //generate keys  
         //specify partition key  
         string partitionKey = "partitionKey1";  
         //create a unique key  
         string rowKey = DateTime.Now.ToString("ddMMyyyyHmmss");  
         CloudTable table = AzureTableManager.CreateTable();  
         personEntity.PartitionKey = partitionKey;  
         personEntity.RowKey = rowKey;  
         status = AzureTableManager.InsertEntity(table, personEntity);  
       }  
       catch  
       {  
         ;  
       }  
       if (status == true)  
       {  
         return (new HttpResponseMessage(HttpStatusCode.OK));  
       }  
       else  
       {  
         return (new HttpResponseMessage(HttpStatusCode.NotFound));  
       }  
     }  
     [HttpGet]  
     public HttpResponseMessage updateEntity()  
     {  
       //get reference of current request  
        var request = HttpContext.Current.Request;  
        var status = false;  
        try  
        {  
          //get parameters : obj is json object  
          var obj = request.Params["obj"];  
          PersonEntity personEntity = JsonConvert.DeserializeObject<PersonEntity>(obj);  
          CloudTable table = AzureTableManager.CreateTable();  
          status = AzureTableManager.InsertEntity(table, personEntity);  
        }  
        catch (Exception e)  
        {  
          ;  
        }  
       if (status == true)  
       {  
         return (new HttpResponseMessage(HttpStatusCode.OK));  
       }  
       else  
       {  
         return (new HttpResponseMessage(HttpStatusCode.NotFound));  
       }  
     }  
     [HttpGet]  
     public HttpResponseMessage deleteEntity()  
     {  
       //get reference of current request  
        var request = HttpContext.Current.Request;  
        var status = false;  
        try  
        {   
          //get parameters : we need only entity identifier  
          string partitionKey = request.Params["PartitionKey"];  
          string rowKey = request.Params["RowKey"];  
          CloudTable table = AzureTableManager.CreateTable();  
          status = AzureTableManager.DeleteEntity(table, partitionKey, rowKey);  
        }catch(Exception e){  
          status = false;  
        }  
       if (status == true)  
       {  
         return (new HttpResponseMessage(HttpStatusCode.OK));  
       }  
       else  
       {  
         return (new HttpResponseMessage(HttpStatusCode.NotFound));  
       }  
     }  
     [HttpGet]  
     public IEnumerable<PersonEntity> retreiveEntities()  
     {  
       CloudTable table = AzureTableManager.CreateTable();  
       //return all available entities  
       return AzureTableManager.RetreiveAllEntries(table);  
     }  
   }  
 }  

2) Create a Client side

In client side, we used AngularJs framework .
  • JavaScript Code :

 <script>  
   var app = angular.module('myApp', []);  
   app.factory('DataService', ['$http', function ($http) {  
     var entriesList = function () {  
       return $http.get("api/RestAzureTableMethods/retreiveEntities");  
     }  
     var updateEntity = function (elem) {  
       var data = angular.copy(elem);  
       var parameters = {  
         obj: JSON.stringify(data),  
       };  
       var config = {  
         params: parameters  
       };  
       return $http.get("api/RestAzureTableMethods/updateEntity", config);  
     }  
     var insertEntity = function (elem) {  
       var data = angular.copy(elem);  
        var parameters = {  
         obj: JSON.stringify(data),  
       };  
       var config = {  
         params: parameters  
       };  
       return $http.get("api/RestAzureTableMethods/insertEntity", config);  
     }   
     var deleteEntity = function (elem) {  
       var parameters = {  
         PartitionKey: elem.PartitionKey,  
         RowKey: elem.RowKey,  
       };  
       var config = {  
         params: parameters  
       };  
       return $http.get("api/RestAzureTableMethods/deleteEntity", config);  
     }  
     return {  
       entriesList: entriesList,  
       updateEntity: updateEntity,  
       deleteEntity: deleteEntity,  
       insertEntity: insertEntity  
     }  
   }]);  
   app.controller("MainCtrl", ["$scope", "DataService",  
     function ($scope, DataService) {  
       getEntriesList();  
       function getEntriesList() {  
         DataService.entriesList().then(function (response) {  
           $scope.entriesList = response.data;  
         });  
       }  
       $scope.updateEntity = function (elem) {  
         DataService.updateEntity(elem).then(function (response) {  
           getEntriesList();  
         });  
       }  
       $scope.deleteEntity = function (elem) {  
         DataService.deleteEntity(elem).then(function (response) {  
           getEntriesList();  
         });  
       }  
       $scope.insertEntity = function (elem) {  
         DataService.insertEntity(elem).then(function (response) {  
           getEntriesList();  
         });  
       }  
     }  
   ]);  
   $(document).on("click", "#addbutton", function () {  
     //animation for opening and closing insertion form  
     $("#PanelToHide").fadeToggle();  
   });  
 </script>  

  • Html code :

 <div ng-app="myApp" ng-controller="MainCtrl">  
   <div class="row">  
     <div class="col-md-6">  
       <div class="panel panel-primary">  
         <div class="panel-heading">  
           <h3 class="panel-title">Azure Table Content</h3>  
           <div class="pull-right">  
             <span class="clickable filter" id="addbutton" data-toggle="tooltip" title="Toggle table filter" data-container="body">  
               <i class="glyphicon glyphicon-plus-sign"></i>  
             </span>  
           </div>  
         </div>  
         <div id="PanelToHide" class="panel-body">  
           <center><label class="col-sm-12 control-label"><h3>Add new Entry</h3></label></center>  
             <form class="form-horizontal" id="formUploadFile" name="formUploadFile">  
               <div class="form-group">  
                 <label class="col-sm-2 control-label">first Name</label>  
                 <div class="col-sm-10">  
                   <input type="text" ng-model="master.firstName" />  
                 </div>  
               </div>  
               <div class="form-group">  
                 <label class="col-sm-2 control-label">last Name</label>  
                 <div class="col-sm-10">  
                   <input type="text" ng-model="master.lastName" />  
                 </div>  
               </div>  
               <div class="form-group">  
                 <div class="col-sm-offset-2 col-sm-10">  
                   <button type="submit" ng-click="insertEntity(master)" class="btn btn-default">Save</button>  
                 </div>  
               </div>  
             </form>  
           </div>  
         <table class="table table-hover" id="dev-table">  
           <thead>  
             <tr>  
               <th>First Name</th>  
               <th>Last Name</th>  
               <th></th>  
             </tr>  
           </thead>  
           <tbody ng-repeat="elem in entriesList">  
             <tr>  
               <td><input type="text" ng-model="elem.firstName" /></td>  
               <td><input type="text" ng-model="elem.lastName" /></td>  
               <td><button type="button" ng-click="updateEntity(elem)" class="btn btn-default">edit</button>   
               <button type="button" ng-click="deleteEntity(elem)" class="btn btn-default">delete</button></td>  
             </tr>  
           </tbody>  
         </table>  
       </div>  
     </div>  
   </div>  
 </div>  

3) Scenario of execution

  •  Show all entries :
when you load or reload page, you will get all available entries in your Azure table.


  •  Insertion of new Entry :
First you must open the insertion form by clicking on . next you should complete the form, and click on save button.



  •  Update an exiting entry :
choose an entry from table and modify its value,  to save new changes you can click on edit button.


  •  Delete an existing entry :
click on delete button of a chosen entry.


Conclusion

In the next tutorial we will create a sample cloud Azure service that work with Azure blob storage and Azure Queue storage

No comments:

Post a Comment