Day 2 – Adding Entities to a Storage Account Table

In this series we are looking at the basic mechanics of interacting with cloud-based Table Storage from an MVC 5 Application, using the Visual Studio 2013 IDE and Microsoft Azure infrastructure.

We’ve got some basics in place, namely loading up all resources from a table, but it turns out that users want to be able to add records, too. Who knew?  To allow this to happen, we’re going to need to update our view a little and add an appropriate method on our controller.  Let’s make that happen, then we’re going to take a look at why our approach is breaking down.  Don’t worry, we’ll start fixing things up in Day 3!

If you want to follow along, please pop into Azure and make sure you’ve got an account ready to go. The trial is free, so get at it!

Updating Our View

We’re going to keep working off of the view we created in Day 1, just simply by adding a form below the existing UI. 

<h2>Like Kittehs? Add a Kitteh!</h2>
@using (Html.BeginForm(“Index”, “Home”, FormMethod.Post))
{
<div class=“form-group”>
<label for=“ImageUrl”>What kind of Kitteh is it?</label>
<select class=“form-control” name=“PartitionKey”>
<option value=“FunnyKittehs”>Funny Kitteh</option>
<option value=“CuteKittehs”>Cute Kitteh</option>
</select>
</div>
<div class=“form-group”>
<label for=“RowKey”>Kitteh Name</label>
<input type=“text” class=“form-control” id=“RowKey” name=“RowKey” placeholder=“SeriousKitteh”>
</div>
<div class=“form-group”>
<label for=“ImageUrl”>Image URL</label>
<input type=“url” class=“form-control” id=“ImageUrl” name=“ImageUrl” placeholder=http://awesomekittehs.org/pic1.jpg>
</div>
<button type=“submit” class=“btn btn-default”>Submit</button>
}

If you’re new to Bootstrap, it may seem like there’s a lot going on there, but you get used to it pretty quickly. Our form has three “groups” in it.  This is a construct in Bootstrap that allows us to associate controls and labels and get the CSS styling we expect.   Each form group has a label and a control, in our case, and we’re simply putting in the properties we need in order to create a new row in our Azure Table.

The form is configured to POST to the Index action on the Home controller, so let’s set up someone to answer when the calls start coming.

Updating Our Controller

The next piece is just as easy. We want to accept the form information (our controller will leverage MVC’s model binding) and then create a new entity in the Table.

[HttpPost]
public ActionResult Index(KittehEntity entity)
{
var storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting(“StorageConnectionString”));

var client = storageAccount.CreateCloudTableClient();
var kittehTable = client.GetTableReference(<span class="str">"PicturesOfKittehs"</span>);

var insert = TableOperation.Insert(entity);
kittehTable.Execute(insert);

var kittehQuery = <span class="kwrd">new</span> TableQuery&lt;KittehEntity&gt;()
    .Where(TableQuery.GenerateFilterCondition(<span class="str">"PartitionKey"</span>, QueryComparisons.Equal, <span class="str">"FunnyKittehs"</span>));

var kittehs = kittehTable.ExecuteQuery(kittehQuery).ToList();

<span class="kwrd">return</span> View(kittehs);

}

The insert is a type of TableOperation that we get by calling the static method aptly named “Insert” and passing in our entity. Our kittehTable object here is created in the context of a table reference that we load from our storage account by name.

At the tail end of the insert operation, we reload the list of kittehs (everyone is here to see the kittehs, after all) and return the view to render the list.

It’s Falling Apart!

Good grief, Charlie Brown, you’ve repeated all your code!  Our controllers should handle the mapping of requests and related payload to service endpoints, and direct users to the correct views.

Putting application logic into our methods is a dangerous slope, and anytime our actions start doing more than one thing we start making it hard to test and maintain our software.  This is ungood.

Next Steps

A lot of times tutorials and blog posts fall short in the area of best practices, and I don’t want to go there for this one. In tomorrow’s exercise we’re going to break our problem down into better pieces that more accurately represent what you’d be doing in a real-world application.