Building an Azure Application – A Case Study (Part 1)

Overview

Designed for use by the self-employed or any individual user, Azure Time Clock is a Windows Azure application that gives the user the ability to clock in and out of the application to keep track of their time worked.

The active user count and processing use can vary greatly at any given time with this type of application. We don’t want to waste any resources by dedicating any that may not be used and at the same time, we don’t want to lose users should activity with the application increase beyond what we have available for it. This also leads to time/money wastage analyzing usage reports and load balancing.

The Windows Azure platform provides excellent scalability and, like the electric bill, you only pay for resources that are used. There is no waste for unused resource dedicated or loss of users due to not having resources available. Lastly you gain man-hours because you no longer need to analyze usage report, perform load balancing, etc and can focus on the application itself. This led me to believe the Windows Azure platform was a great choice for the development of this project as well as projects like it.

The user will have two actions they can perform from the application. At the start of their workday then can enter their username and password and click the log in/out button to log in. Later in the day then can again enter their username and password and click the log in/out button to clock out. At that point the application will display the time they have worked since they clocked in as well as display their history.

Secondly, the user will also have the ability to enter their username and password and click a view history button to view all of their history without the need to clock in or out.

Figure 1 below is a Microsoft Visio flowchart that was created during the planning of this project. Some things may have changed slightly but it is included in this article so you can easily visualize the program flow and refer back to it if you wish.


Let’s get started…

Figure 1: Visio Flowchart from the planning of Azure Time Clock

Creating the Visual Studio Project

To get started, open Visual Studio and start a new project. Under project types, expand Visual C# and select Cloud Service and then select Windows Azure Cloud Service under templates. Enter “AzureTimeClock” as both the Name and Solution name and click OK to create the project.


Figure 2: Creating a new Windows Azure Cloud Service project

Now under Roles highlight ASP.Net Web Role and click the > button to add that role to the solution. Select that role and click on the pencil icon and rename it to “AzureTimeClock_WebRole”. Click OK.

Figure 3: Assigning roles to the cloud service project

If everything was done correctly, the structure of the created solution should look like figure 4 below.

Figure 4: Solution Explorer showing the Azure Time Clock application


Creating the Data Models for Entities in Table Storage (UserInfo)

We will need two Azure storage tables. The first will be used to store each user’s username and password as well as a Bool to track if the user is currently in a clocked in state and a DateTime which will be used to record the time when the user clocks in and later used to calculate the time worked when the user clocks out. The second will be used to store the time worked entries and serve as the history for all users. This will also contain a username and password column so that we can enforce some user access control to the history entries.

In Solution Explorer, right-click the AzureTimeClock solution, point to Add and select New Project. Under project types, expand Visual C# and select Windows and then select Class Library under templates. Enter “AzureTimeClock_Data” as the Name and click OK.

Figure 5: Creating a class library for AzureTimeClock entities

Delete the default class file that was generated in the AzureTimeClock_Data project. Then add a reference to the.NET Client Library for ADO.NET Data Services in the AzureTimeClock_Data project. Right-click the AzureTimeClock_Data project node, select Add Reference, click the .Net tab, select the System.Data.Service.Client component and click OK.

Figure 6: Adding a reference to the System.Data.Service.Client component

Now add a reference to the Windows Azure storage client API assembly, choosing the Microsoft.WindowsAzure.StorageClient assembly.

Figure 7: Adding a reference to the Microsoft.WindowsAzure.StorageClient assembly


Creating “UserInfo.cs”

We now need to define the schema for our UserInfo table. In Solution Explorer, right-click the AzureTimeClock_Data solution and point to Add and select New Item. Under categories, select Code and then select Class under templates. Enter “UserInfo.cs” as the Name and click Add.

Figure 8: Adding the UserInfo class


Open the UserInfo.cs file and add the Microsoft.WindowsAzure.StorageClient namespace declaration to import the types contained in the namespace.

using Microsoft.WindowsAzure.StorageClient;

Modify the declaration of the UserInfo class to make it public and derive from the Microsoft.Samples.ServiceHosting.StorageClient.TableStorageEntity class.

public class UserInfo : TableServiceEntity

{

}

Add a default constructor to the UserInfo class that initializes its PartitionKey and RowKey properties.

public UserInfo()

{

PartitionKey = DateTime.UtcNow.ToString(“MMddyyyy”);

RowKey = string.Format(“{0:10}_{1}”, DateTime.MaxValue.Ticks –

DateTime.Now.Ticks, Guid.NewGuid());

}

Lastly, add properties for UserName, Password, ClockedIn, and ClockedInTime to hold information about the user entry.

public string UserName { get; set; }

public string Password { get; set; }

public bool ClockedIn { get; set; }

public DateTime ClockedInTime { get; set; }

Creating “UserInfoContext.cs”

We now need to create the context class required to access the UserInfo table using ADO.NET Data Services. Right-click the AzureTimeClock_Data project and point to Add and select Class. Enter “UserInfoContext.cs” as the name and click Add.

Figure 9: Adding the UserInfoContext class


Open the UserInfoContext.cs file and add the Microsoft.WindowsAzure and Microsoft.WindowsAzure.StorageClient namespace declaration to import the types contained in the namespaces.

using Microsoft.WindowsAzure;

using Microsoft.WindowsAzure.StorageClient;

Modify the declaration of the UserInfoContext class to make it public and inherit the TableServiceContext class.

public class UserInfoContext : TableServiceContext

{

}

Now add a default constructor to initialize its base class with storage information.

public UserInfoContext(string baseAddress, StorageCredentials credentials) : base(baseAddress, credentials)

{

}

Add a property to the UserInfoContext class to expose the UserInfo table. To do this, insert the following code into the class.

public IQueryable UserInfo

{

get

{

return this.CreateQuery(“UserInfo”);

}

}

Creating “UserInfoDataSource.cs”

We now need to implement an object that can be bound to data controls in ASP.NET. Right-click the AzureTimeClock_Data project and point to Add and select Class. Enter “UserInfoDataSource.cs” as the name and click Add.

Figure 10: Adding the UserInfoDataSource class


Open the UserInfoDataSource.cs file and add the Microsoft.WindowsAzure, Microsoft.WindowsAzure.StorageClient, and System.Data.Service.Client namespace declarations to import the types contained in the namespaces.

using Microsoft.WindowsAzure;

using Microsoft.WindowsAzure.StorageClient;

using System.Data.Services.Client;

In the UserInfoDataSource class, make the class public and define member fields for data context and the storage account information.

private static CloudStorageAccount storageAccount;

private UserInfoContext context;

private static CloudStorageAccount csa = CloudStorageAccount.FromConfigurationSetting(“DataConnectionString”);

private static CloudTableClient ctc = csa.CreateCloudTableClient();

private static TableServiceContext tsc = ctc.GetDataServiceContext();

Add a static constructor to the UserInfoDataSource class that creates the tables from the UserInfoContext class.

static UserInfoDataSource()

{

storageAccount = CloudStorageAccount.FromConfigurationSetting(“DataConnectionString”);

CloudTableClient.CreateTablesFromModel(

typeof(UserInfoContext),

storageAccount.TableEndpoint.AbsoluteUri,

storageAccount.Credentials);

}

Add a default constructor to the UserInfoDataSource class to initialize the data context class used to access table storage.

public UserInfoDataSource()

{

this.context =

new UserInfoContext(storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials);

this.context.RetryPolicy = RetryPolicies.Retry(3, TimeSpan.FromSeconds(1));

}

Now, add the following method which we will use to insert new entries into the UserInfo table when there is a new user.

public void AddUserInfoEntry(UserInfo newItem)

{

this.context.AddObject(“UserInfo”, newItem);

this.context.SaveChanges();

}

We will need a way to query the UserInfo table to verify is a user is in the table. To accomplish this we will need to add the below method. When the method is called an object of type UserInfo will be passed in and we will query the UserInfo table for an entry that has the username that is equal to the username in the object that was passed. If an entry is found the method will return true, otherwise it will return false.

public bool DoesUserExist(UserInfo user)

{

bool result;


UserInfo userResult =

(from a in tsc.CreateQuery(“UserInfo”)

where a.UserName == user.UserName

select a).FirstOrDefault();


if (userResult == null)

{

result = false;

}

else

{

result = true;

}


return result;

}

Now we need a method that will query the UserInfo table and retrieve a user’s entry and check to see if the username and password match. Add the method below, when the method is called an object of type UserInfo will be passed in containing the username and password that the end user enters. After retrieving the entry from the UserInfo table we check to see if the passwords match. If they

public bool DoUserNameAndPasswordMatch(UserInfo user)

{

bool result;


UserInfo userResult =

(from a in tsc.CreateQuery(“UserInfo”)

where a.UserName == user.UserName

select a).FirstOrDefault();


if (userResult.Password == user.Password)

{

result = true;

}

else

{

result = false;

}

return result;

}

We need a method that will accept a object of type UserInfo and query the UserInfo table for that user and see if the user is currently clocked in (designated by the ClockedIn property of UserInfo). Add the method below which returns true if the user is already clocked in and false if they are not.

public bool IsUserClockedIn(UserInfo user)

{

bool result;


UserInfo userResult =

(from a in tsc.CreateQuery(“UserInfo”)

where a.UserName == user.UserName

select a).FirstOrDefault();


if (userResult.ClockedIn == true)

{

result = true;

}

else

{

result = false;

}


return result;

}

Add the below method to clock in a user. This method, when called will query the UserInfo table for a specified user and set the clockedIn property to true and the ClockedInTime property to datetime.now recording the time the user clocked in.

Note: Take into account that the DateTime.Now will run on the server which will most lilky be in a different timezone as the end user. You may want to get this locally.

public void ClockInUser(UserInfo user)

{


UserInfo userResult =

(from a in tsc.CreateQuery(“UserInfo”)

where a.UserName == user.UserName

select a).FirstOrDefault();


userResult.ClockedIn = true;

userResult.ClockedInTime = DateTime.Now;

tsc.UpdateObject(userResult);

DataServiceResponse DSR = tsc.SaveChangesWithRetries(SaveChangesOptions.ReplaceOnUpdate);

}

Lastly, Add the below method to clock out a user. This method, when called will query the UserInfo table for a specified user and set the clockedIn property to false and calculate the time worked from the clockedInTime property and datetime.now and return the time worked.

Note: Take into account that the DateTime.Now will run on the server which will most lilky be in a different timezone as the end user. You may want to get this locally.

public TimeSpan ClockOutUser(UserInfo user)

{

TimeSpan timeWorked;


UserInfo userResult =

(from a in tsc.CreateQuery(“UserInfo”)

where a.UserName == user.UserName

select a).FirstOrDefault();


timeWorked = DateTime.Now – userResult.ClockedInTime;

userResult.ClockedIn = false;

tsc.UpdateObject(userResult);

DataServiceResponse DSR = tsc.SaveChangesWithRetries(SaveChangesOptions.ReplaceOnUpdate);


return timeWorked;

}

Creating the Data Models for Entities in Table Storage (UserHistory)

Creating “UserHistory.cs”

We now need to define the schema for our UserHistory table. In Solution Explorer, right-click the AzureTimeClock_Data solution and point to Add and select New Item. Under categories, select Code and then select Class under templates. Enter “UserHistory.cs” as the Name and click Add.

Figure 11: Adding the UserHistory class


Open the UserHistory.cs file and add the Microsoft.WindowsAzure.StorageClient namespace declaration to import the types contained in the namespace.

using Microsoft.WindowsAzure.StorageClient;

Modify the declaration of the UserHistory class to make it public and derive from the TableStorageEntity class.

public class UserHistory : TableServiceEntity

{

}

Add a default constructor to the UserHistory class that initializes its PartitionKey and RowKey properties.

public UserHistory()

{

PartitionKey = “a”;

RowKey = string.Format(“{0:10}_{1}”, DateTime.MaxValue.Ticks –

DateTime.Now.Ticks, Guid.NewGuid());

}

Lastly, add properties for UserName, Password, Date, and TimeWorked to hold information about the user history entry.

public string UserName { get; set; }

public string Password { get; set; }

public DateTime Date { get; set; }

public string TimeWorked { get; set; }

Creating “UserHistoryContext.cs”


We now need to create the context class required to access the UserHistory table using ADO.NET Data Services. Right-click the AzureTimeClock_Data project and point to Add and select Class. Enter “UserHistoryContext.cs” as the name and click Add.


Open the UserHistoryContext.cs file and add the Microsoft.WindowsAzure and Microsoft.WindowsAzure.StorageClient namespace declaration to import the types contained in the namespaces.

using Microsoft.WindowsAzure;

using Microsoft.WindowsAzure.StorageClient;

Modify the declaration of the UserHistoryContext class to make it public and inherit the TableServiceContext class.

public class UserHistoryContext : TableServiceContext

{

}


Now add a default constructor to initialize its base class with storage information.

public UserHistoryContext(string baseAddress, StorageCredentials credentials)

: base(baseAddress, credentials)

{ }


Add a property to the UserHistoryContext class to expose the UserHistory table. To do this, insert the following code into the class.

public IQueryable UserHistory

{

get

{

return this.CreateQuery(“UserHistory”);

}

}

Creating “UserHistoryDataSource.cs”

We now need to implement an object that can be bound to data controls in ASP.NET. Right-click the AzureTimeClock_Data project and point to Add and select Class. Enter “UserHistoryDataSource.cs” as the name and click Add.

Open the UserHistoryContext.cs file and add the Microsoft.WindowsAzure and Microsoft.WindowsAzure.StorageClient namespace declarations to import the types contained in the namespaces.

using Microsoft.WindowsAzure;

using Microsoft.WindowsAzure.StorageClient;

In the UserHistoryDataSource class, make the class public and define member fields for data context and the storage account information.

private static CloudStorageAccount storageAccount;

private UserHistoryContext context;

private static CloudStorageAccount csa = CloudStorageAccount.FromConfigurationSetting(“DataConnectionString”);

private static CloudTableClient ctc = csa.CreateCloudTableClient();

private static TableServiceContext tsc = ctc.GetDataServiceContext();


Add a static constructor to the data source class that creates the tables from the UserHistoryContext class.

static UserHistoryDataSource()

{

storageAccount = CloudStorageAccount.FromConfigurationSetting(“DataConnectionString”);

CloudTableClient.CreateTablesFromModel(

typeof(UserHistoryContext),

storageAccount.TableEndpoint.AbsoluteUri,

storageAccount.Credentials);

}


Add a default constructor to the UserInfoDataSource class to initialize the data context class used to access table storage.

public UserHistoryDataSource()

{

this.context = new UserHistoryContext(storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials);

this.context.RetryPolicy = RetryPolicies.Retry(3, TimeSpan.FromSeconds(1));

}


Next, insert the following method to return the contents of the UserHistory table. We only return entries where both the username and password match.

public IEnumerable Select(string username, string password)

{

//if it doesn’t find it it wont show anything

var results = from g in this.context.UserHistory

where g.UserName == username && g.Password ==

password

select g;


return results;

}


Now, add the following method which we will use to insert new entries into the UserHistory table when a user clocks out.

public void AddUserHistoryEntry(UserHistory newItem)

{

this.context.AddObject(“UserHistory”, newItem);

this.context.SaveChanges();

}


Since we are giving the user the ability to view their history without clocking in or out we need a way to make sure the user has an entry in the UserHistory table. Add the below method which when the method is called an object of type UserHistory will be passed in and we will query the UserHistory table for an entry that has the username that is equal to the username in the object that was passed. If an entry is found it returns true and if not it will return false.

public bool DoesUserExist(UserHistory user)

{

bool result;

UserHistory userResult =

(from a in tsc.CreateQuery(“UserHistory”)

where a.UserName == user.UserName

select a).FirstOrDefault();

if (userResult == null)

{

result = false;

}

else

{

result = true;

}

return result;

}


We now need a method that will query the UserHistory table and retrieve a user’s entry in the UserHistory table to check to see if the username and password match. Add the method below, which when the method is called an object of type UserHistory will be passed in containing the username and password that the end user enters. After retrieving the entry from the UserHistory table we check to see if the passwords match. If they match the method returns true, if not it returns false.

public bool DoUserNameAndPasswordMatch(UserHistory user)

{
bool result;
UserHistory userResult =
(from a in tsc.CreateQuery(“UserHistory”)
where a.UserName == user.UserName
select a).FirstOrDefault();
if (userResult.Password == user.Password)
{
result = true;
}
else
{
result = false;
}
return result;
}



Array
Twitter Digg Delicious Stumbleupon Technorati Facebook Email

No comments yet... Be the first to leave a reply!