Step-by-Step Guide to Amazon DynamoDB for .NET Developers

Amazon DynamoDB is the latest NoSQL offering from AWS. It is a managed, scalable and on-demand database with provisioned throughput. Provisioned Throughput will let you state your read and write throughput requirements upfront based on which the cost will be calculated. For an introduction to Amazon DynamoDB, refer to this article we covered on CloudStory.in.

This tutorial is meant for the .NET developers to get started with Amazon DynamoDB. I will show you how to create a Table and perform CRUD operations on it. Amazon DynamoDB provides a low-level API and an Object Persistence API for the .NET developers. In this tutorial, we will see how to use the Object Persistence API to talk to Amazon DynamoDB. We will model a component that represents a DVD Library with capabilities to add, modify, query and delete individual DVDs.

Prerequisites

Index

Step 1- Let’s start by creating a new Console project in Visual Studio and setting up the environment.

Create a New Console Project

Add a reference to the AWSSDK.dll by browsing to the location of the AWS SDK for .NET. This is typically at C:Program FilesAWS SDK for .NETbin.

Add a reference to AWS SDK

Add a new Application configuration file and leave the default filename as App.config.

Add App.config file to the Project

Visit the AWS Security Credentials page and make a note of your Access Key and Secret Key.

AWS Access Key & Secret Key

Add the using statement
[crayon lang="C#"]
using Amazon.DynamoDB.DataModel;
[/crayon]

Add the AWS Access Key and Secret Key to the App.config file.

App.config File

Step 2 – In this step, we will create a Class that is modeled around the Amazon DynamoDB schema with the following properties and methods

Class modeled for the DynamoDB Table

Add a new Class and call it DVD.cs.

Add a new Class for the DVD Model

Add the using statement

[crayon lang="c#"]
using Amazon.DynamoDB.DataModel;
[/crayon]

Add the properties and override the ToString method
[crayon lang="c#"]
public class DVD
{
public string Title { get; set; }

public int ReleaseYear { get; set; }

public ListActorNames { get; set; }

public string Director { get; set; }

public string Producer { get; set; }

public override string ToString(){
return string.Format(@”{0} – {1} Actors: {2}”, Title, ReleaseYear, string.Join(“, “, ActorNames.ToArray()));}
}
}
[/crayon]

We finally need to add the Amazon DynamoDB specific attributes to identify the Table, Hash Key and Range Key. Here is the code of the final DVD.cs with all the attributes in place.

[crayon lang="c#"]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Amazon.DynamoDB.DataModel;

namespace DVDsOnCloud
{
[DynamoDBTable("DVD")]
public class DVD
{
[DynamoDBHashKey]
public string Title { get; set; }

[DynamoDBRangeKey]
public int ReleaseYear { get; set; }

[DynamoDBProperty]
public List ActorNames { get; set; }

public string Director { get; set; }

public string Producer { get; set; }

public override string ToString()
{
return string.Format(@”{0} – {1} Actors: {2}”, Title, ReleaseYear, string.Join(“, “, ActorNames.ToArray()));
}
}
}
[/crayon]
[jbox color="yellow" border="2" radius="4" shadow="1" jbox_css="font-size:12px;"]Here is a short note on the Hash Key and Range Key. A Hash Key is comparable to the Primary Key of a Table. This is always expected to be unique and this is the chosen key for most of the queries. A Range Key is a secondary key that is used by DynamoDB to create a sorted index range. Ideally, this key is used as the secondary criterion for the queries. Though the Range Key is optional, using a combination of Hash Key and Range Key will optimize the query performance.[/jbox]

Step 3 – Let’s create a wrapper for the DynamoDB API in a class that can be consumed by any client.

Let’s add a new class called DVDLibray.cs

DVDLibrary Class

We will then add the using statements referring to the Amazon DynamoDB

[crayon lang="c#]
using Amazon;
using Amazon.DynamoDB;
using Amazon.DynamoDB.Model;
using Amazon.DynamoDB.DataModel;
using Amazon.SecurityToken;
using Amazon.Runtime;
[/crayon]

Step 4 – We will now add the public members and the constructor to the DVDLibrary class. The constructor uses AWS Security Token Authentication to check the credentials. Please refer to the AWS documentation on the Security Token Authentication.

[crayon lang="c#"]
AmazonDynamoDB client;
public DVDLibrary()
{
AmazonSecurityTokenServiceClient stsClient = new AmazonSecurityTokenServiceClient();
RefreshingSessionAWSCredentials sessionCredentials = new RefreshingSessionAWSCredentials(stsClient);
client = new AmazonDynamoDBClient(sessionCredentials);
}
[/crayon]

Step 5 – In this step, we will initialize the Amazon DynamoDB Table. We will make sure that the table doesn’t exist and then create a new one. We will also configure the required parameters like Provisioned Throughput, Hash Key and Range Key. Creating an Amazon DynamoDB Table may take a while during which no operations can be performed on it. So, we will block this method till the status of the Table becomes ‘Active’.

[crayon lang="c#"]

public void Init()
{
List currentTables = client.ListTables().ListTablesResult.TableNames;
if (!currentTables.Contains(“DVD”))
{
CreateTableRequest reqCreateTable = new CreateTableRequest();
CreateTableResponse resCreateTable=new CreateTableResponse();

reqCreateTable.TableName = “DVD”;

reqCreateTable.ProvisionedThroughput = new ProvisionedThroughput();
reqCreateTable.ProvisionedThroughput.ReadCapacityUnits=10;
reqCreateTable.ProvisionedThroughput.WriteCapacityUnits=10;

reqCreateTable.KeySchema = new KeySchema();

reqCreateTable.KeySchema.HashKeyElement = new KeySchemaElement();
reqCreateTable.KeySchema.HashKeyElement.AttributeName = “Title”;
reqCreateTable.KeySchema.HashKeyElement.AttributeType = “S”;

reqCreateTable.KeySchema.RangeKeyElement = new KeySchemaElement();
reqCreateTable.KeySchema.RangeKeyElement.AttributeName = “ReleaseYear”;
reqCreateTable.KeySchema.RangeKeyElement.AttributeType = “N”;

resCreateTable = client.CreateTable(reqCreateTable);

while (resCreateTable.CreateTableResult.TableDescription.TableStatus != “ACTIVE”)
{
System.Threading.Thread.Sleep(5000);
}
}

}
[/crayon]
[jbox color="yellow" border="2" radius="4" shadow="1" jbox_css="font-size:12px;"]Understanding the concept of Provisioned Throughput is important while working with Amazon DyanamoDB. Typically provisioning of a resource like the DB server is based on the parameters based on CPU, memory and storage. But many a times it is hard to predict the capacity upfront. What is more predictable is the throughput your application may demand. For example, if your DB is read intensive than write intensive, the read performance should be higher. Amazon DynamoDB will rely on the Read Throughput and Write Throughput parameters to allocate the right set of resources. When you need to scale the throughput, you can simply change the parameters without worrying about scaling up or scaling out the data tier. Of course, higher throughput rates will impact the cost significantly.[/jbox]

Step 6 – We will create a function called AddDVD that will accept a DVD object and creates an Item on Amazon DynamoDB.

[crayon lang="c#"]
public void AddDVD(DVD dvd)
{
DynamoDBContext context = new DynamoDBContext(client);
context.Save(dvd);
}
[/crayon]

Step 7 – The next step is to create a ModifyDVD method that tries to load an existing DVD, modifies and saves it back. If the Item doesn’t exist, it raises an exception.

[crayon lang="c#"]
public void ModifyDVD(DVD dvd)
{
DynamoDBContext context = new DynamoDBContext(client);
DVD oDVD = context.Load(dvd.Title, dvd.ReleaseYear);
if(oDVD==null)
new Exception(“Non-existent DVD”);
context.Save(dvd);
}
[/crayon]

Step 8 – We will perform a Table Scan operation to return all the DVDs

[crayon lang="c#"]
public IEnumerable GetAllDVDs()
{
DynamoDBContext context = new DynamoDBContext(client);
IEnumerable alldvds=context.Scan();
return alldvds;
}
[/crayon]
[jbox color="yellow" border="2" radius="4" shadow="1" jbox_css="font-size:12px;"]Like in any other databases, performing a full scan operation on Amazon DynamoDB is expensive. This operation will not consider the Hash Key and Range Key and iterates through every item. The scan operation gets terminated when the aggregate size of the scanned items exceeds 1MB and the client has to resume the operation for the rest of the items.[/jbox]

Step 9 – For searching the DVD, we need to use both the Hash Key and Range Key. This method will use both to query the DVD.

[crayon lang="c#"]
public IEnumerable SearchDVDs(string title, int releaseyear)
{
DynamoDBContext context = new DynamoDBContext(client);
IEnumerable alldvds = context.Query(title, Amazon.DynamoDB.DocumentModel.QueryOperator.Equal, releaseyear);
return alldvds;
}
[/crayon]

Step 10 – If you do not want to include the ReleaseYear in the search criterion, you will use the following method to query based on the Title. Notice that this returns a List object that contains a Dictionary object with the Key Value Pair of Items.

[crayon lang="c#"]
public List>SearchDVDByTitle(string title)
{
DynamoDBContext context = new DynamoDBContext(client);
QueryRequest reqQuery = new QueryRequest();
reqQuery.TableName = “DVD”;
reqQuery.HashKeyValue = new AttributeValue() { S = title };

QueryResponse resQuery = client.Query(reqQuery);

return resQuery.QueryResult.Items;
}
[/crayon]

Step 11 – Deleting a DVD is straight forward and the following method does it.

[crayon lang="c#"]
public void DeleteDVD(DVD dvd)
{
DynamoDBContext context = new DynamoDBContext(client);
DVD oDVD = context.Load(dvd.Title, dvd.ReleaseYear);
if (oDVD == null)
new Exception(“Non-existent DVD”);
context.Delete(dvd);
}
[/crayon]

Here is the complete code of DVDLibrary.cs

[crayon lang="c#"]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Amazon;
using Amazon.DynamoDB;
using Amazon.DynamoDB.Model;
using Amazon.DynamoDB.DataModel;
using Amazon.SecurityToken;
using Amazon.Runtime;

namespace DVDsOnCloud
{
class DVDLibrary
{
AmazonDynamoDB client;
public DVDLibrary()
{
AmazonSecurityTokenServiceClient stsClient = new AmazonSecurityTokenServiceClient();
RefreshingSessionAWSCredentials sessionCredentials = new RefreshingSessionAWSCredentials(stsClient);
client = new AmazonDynamoDBClient(sessionCredentials);
}

public void Init()
{
List currentTables = client.ListTables().ListTablesResult.TableNames;
if (!currentTables.Contains(“DVD”))
{
CreateTableRequest reqCreateTable = new CreateTableRequest();
CreateTableResponse resCreateTable=new CreateTableResponse();

reqCreateTable.TableName = “DVD”;

reqCreateTable.ProvisionedThroughput = new ProvisionedThroughput();
reqCreateTable.ProvisionedThroughput.ReadCapacityUnits=10;
reqCreateTable.ProvisionedThroughput.WriteCapacityUnits=10;

reqCreateTable.KeySchema = new KeySchema();

reqCreateTable.KeySchema.HashKeyElement = new KeySchemaElement();
reqCreateTable.KeySchema.HashKeyElement.AttributeName = “Title”;
reqCreateTable.KeySchema.HashKeyElement.AttributeType = “S”;

reqCreateTable.KeySchema.RangeKeyElement = new KeySchemaElement();
reqCreateTable.KeySchema.RangeKeyElement.AttributeName = “ReleaseYear”;
reqCreateTable.KeySchema.RangeKeyElement.AttributeType = “N”;

resCreateTable = client.CreateTable(reqCreateTable);

while (resCreateTable.CreateTableResult.TableDescription.TableStatus != “ACTIVE”)
{
System.Threading.Thread.Sleep(5000);
}
}

}

public void AddDVD(DVD dvd)
{
DynamoDBContext context = new DynamoDBContext(client);
context.Save(dvd);
}

public void ModifyDVD(DVD dvd)
{
DynamoDBContext context = new DynamoDBContext(client);
DVD oDVD = context.Load(dvd.Title, dvd.ReleaseYear);
if(oDVD==null)
new Exception(“Non-existent DVD”);
context.Save(dvd);
}

public IEnumerable GetAllDVDs()
{
DynamoDBContext context = new DynamoDBContext(client);
IEnumerable alldvds=context.Scan();
return alldvds;
}

public IEnumerable SearchDVDs(string title, int releaseyear)
{
DynamoDBContext context = new DynamoDBContext(client);
IEnumerable alldvds = context.Query(title, Amazon.DynamoDB.DocumentModel.QueryOperator.Equal, releaseyear);
return alldvds;
}

public List>SearchDVDByTitle(string title)
{
DynamoDBContext context = new DynamoDBContext(client);
QueryRequest reqQuery = new QueryRequest();
reqQuery.TableName = “DVD”;
reqQuery.HashKeyValue = new AttributeValue() { S = title };

QueryResponse resQuery = client.Query(reqQuery);

return resQuery.QueryResult.Items;
}

public void DeleteDVD(DVD dvd)
{
DynamoDBContext context = new DynamoDBContext(client);
DVD oDVD = context.Load(dvd.Title, dvd.ReleaseYear);
if (oDVD == null)
new Exception(“Non-existent DVD”);
context.Delete(dvd);
}
}

}
[/crayon]

The complete code of the client that consumes the DVDLibrary is shared below
[crayon lang="c#"]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DVDsOnCloud
{
class Program
{
static void Main(string[] args)
{
//Create the helper object
DVDLibrary DVDLib= new DVDLibrary();

//Initialize
DVDLib.Init();

//Create the DVD object
DVD dvd = new DVD() { Title = “Businessman”, ReleaseYear = 2011, ActorNames = new List { “Mahesh”, “Kajal” }, Director = “Puri Jagannath”, Producer = “Venkat” };

//Add the new DVD
DVDLib.AddDVD(dvd);

//Print all the DVDs
foreach (var odvd in DVDLib.GetAllDVDs())
Console.WriteLine(odvd.Title);

//Create a new DVD object with modified values
DVD newdvd = new DVD() { Title = “Businessman”, ReleaseYear = 2011, ActorNames = new List { “Mahesh Babu”, “Kajal Agarwal” }, Director = “Puri Jagannath”, Producer = “Venkat” };

//Commit the changes
DVDLib.ModifyDVD(newdvd);

//Search for the DVD
foreach (var dvd in DVDLib.SearchDVDs(“Businessman”,2011))
Console.WriteLine(dvd.Director);

//Delete the DVD
DVDLib.DeleteDVD(newdvd);
}
}
}
[/crayon]

Summary
This tutorial attempted at creating a Table and performing the CRUD operations on it. This can be extended to create a oData service for the Amazon DynamoDB tables. ASP.NET Membership and Profile providers can be targeted on Amazon DynamoDB.
Hope you found this useful! Drop a comment if you want to see specific tutorials on CloudStory.in

- Janakiram MSV, Chief Editor, CloudStory.in