Skip to main content

Azure Table Storage - Putting It All Together


Back - Azure > Azure Storage

The Requirement
Assuming that we already completed the 1.1 Create/Add Azure Table Storage Entity and 1.2 Get All Entities In Azure Table, We are now ready to refactor our simple CRUD operation in a single .dll file that we may reference in our Middle Tier ( Web Api ).

Consideration
This code base is proposed for the intention for understanding its usage, for production/release we might need to tweak it to meet the company policy, best practice and industry standards.

Refactor The Account Setup
In the previous implementations, we saw some repeatable code that we may refactor, We start by refactoringg the CloudStorageAccount instantiation in a static class.In the proposed code below, we also introduce an overload for the SetupAccount method , this will allow the reference library open for dynamic variables that may be used in the Middle tier ( in this case, Asp.Net Web API ).
using Microsoft.WindowsAzure.Storage;
namespace CrudAzureTablseStorage
{
public static class AzureSettings
{
// Overload For Clients Implementations
public static CloudStorageAccount SetupAccount(string AccountName, string AccountKey)
{
Microsoft.WindowsAzure.Storage.Auth.StorageCredentials cred =
new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials(
AccountName,
AccountKey
);
CloudStorageAccount acc = new CloudStorageAccount(cred, AccountName, StorageSettings.EndPointSuffix, true);
return acc;
}
// Overload For Dev Settings
// May be used for Productions too , Provided that the policy allow to Hard Code Details in the .dll
// The best practice is to use Azure AD(Cloud)/AD(OnPrem)/RBAC alongside with Key Vault(Cloud)
public static CloudStorageAccount SetupAccount(bool IsLive)
{
Microsoft.WindowsAzure.Storage.Auth.StorageCredentials cred =
new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials(
StorageSettings.AzureStorageAccountName(IsLive),
StorageSettings.AzureStorageKey(IsLive)
);
CloudStorageAccount acc = new CloudStorageAccount(cred, StorageSettings.AzureStorageAccountName(IsLive), StorageSettings.EndPointSuffix, true);
return acc;
}
}
internal static class StorageSettings
{
public static string AzureStorageAccountName(bool IsLive)
{
if(IsLive)
return "LiveDataAzureStorageTableName";
else
return "DevAzureStorageTableName";
}
public static string AzureStorageKey(bool IsLive)
{
if(IsLive)
return "LiveKey";
else
return "DevKey";
}
public static string EndPointSuffix { get { return "core.windows.net"; } }
}
}

Refactor The Add Operation Helper
In our code below only 2 methods that are accessible to the clients who referenced this .dll, The AppOperation method access modifier is decorated with internal which protect it from being used by other assemblies.We also decorated the Add.New method with overload for dynamic configuration at the client side.
using System;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
namespace CloudAzureTableseStorage
{
public static class Add
{
// Overload For Dev Settings
public static bool New(string TableName, ITableEntity DataModel,bool IsLive)
{
if(IsLive != null)
CloudStorageAccount sa = AzureSettings.SetupAccount(IsLive);
else
CloudStorageAccount sa = AzureSettings.SetupAccount(false);
return AddOperation(TableName,DataModel,sa);
}
// Overload For Live/Production Settings
public static bool New(string TableName, ITableEntity DataModel,string AccName , string AccKey)
{
CloudStorageAccount sa = AzureSettings.SetupAccount(AccName,AccKey);
return AddOperation(TableName,DataModel,sa);
}
internal static bool AddOperation(string TableName, ITableEntity DataModel, CloudStorageAccount sa)
{
CloudTableClient tc = sa.CreateCloudTableClient();
CloudTable ct = tc.GetTableReference(TableName);
ct.CreateIfNotExistsAsync();
TableOperation b = TableOperation.InsertOrReplace(DataModel);
try
{
ct.ExecuteAsync(b);
return true;
}
catch (Exception ex)
{
string temp = ex.Message;
// Call Logger
return false;
}
}
}
}

Refactor The Get Operation Helper
Same as the Add Operation refactoring, we create an internal protected operation with 2 public method that is open to clients.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.RetryPolicies;
using Microsoft.WindowsAzure.Storage.Table;
namespace AzureTableseStorage
{
public static class Get
{
public static class List
{
public async static Task< List<T>> All<T>(string TableName , string AccName, string AccKey) where T : TableEntity, new()
{
try
{
List<T> Data = new List<T>();
CloudStorageAccount storageAccount = AzureSettings.SetupAccount(AccName,AccKey);
return GetOperation(TableName,storageAccount);
}
catch (Exception ex)
{
string temp = ex.Message;
// Call Logger
return null;
}
}
public async static Task< List<T>> All<T>(string TableName , bool IsLive) where T : TableEntity, new()
{
try
{
List<T> Data = new List<T>();
CloudStorageAccount storageAccount = AzureSettings.SetupAccount(IsLive);
return GetOperation(TableName,storageAccount);
}
catch (Exception ex)
{
string temp = ex.Message;
// Call Logger
return null;
}
}
internal async static Task<List<T>> GetOperation(string TableName, CloudStorageAccount storageAccount)
{
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
tableClient.DefaultRequestOptions.RetryPolicy = new ExponentialRetry(TimeSpan.FromSeconds(1), 10);
CloudTable table = tableClient.GetTableReference(TableName);
//await table.CreateIfNotExistsAsync();
TableContinuationToken tableContinuationToken = null;
do
{
TableQuery<T> query = new TableQuery<T>().Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, TableName));
try
{
var queryResponse = await table.ExecuteQuerySegmentedAsync<T>(query, tableContinuationToken, null, null);
tableContinuationToken = queryResponse.ContinuationToken;
Data.AddRange(queryResponse.Results);
}
catch (Exception exquery)
{
Console.WriteLine(exquery.InnerException);
return null;
}
}
while (tableContinuationToken != null);
return Data;
}
}

Consuming in WebAPI
We then may reference the library in our Web Api solution by calling it like below.
using SplashBanners = CrudAzureTableseStorage;
public class SplashBannerController : ApiController
{
[HttpPost]
[Route("Api/SplashBanner/AddAzure")]
public bool AddAzurestring (
string SplashBannerID,
string Title,
string Description,
string ButtonTitle,
string ButtonURL,
string ImageURL)
{
// Perform Validation
// Perform Audit Trail,
// Check Authorization/RBAC,
// Logging Or Other CrossCutting Concern in typical Middle Tier Layer
return SplashBanners.Add.New(SplashBannerID, Title, Description,ButtonTitle, ButtonURL, ImageURL , false);
}
}

Conclusion
From the article we may conclude that we may place all the related CRUD operations in a data access layer and reference it in our WebApi for consumption.

Back - Azure > Azure Storage

Published on : 7-May-2018
Ref no : DDN-WPUB-000015

About Author

My photo
Wan Mohd Adzha MCPD,MCSD,MCSE
I am passionate about technology and of course love Durians. Certified by Microsoft as MCP Since 2011. Blogging from Malaysia

Comments