Skip to content
February 21, 2010 / mattdyor

Creating an MVC + ASP.net + Azure Storage Table Site in 10 minutes

Get Started

  • Get the proper software (Visual Studio 2010, possibly need cloud computing tools…not sure what is in the box)
  • File > New Project > Cloud Service
    • Call the solution “XXX” (where XXX is the name of your site, like RallyWire for http://www.RallyWire.com)
    • The solution name (eg-XXX) will be the namespace for your solution. (not correct)
    • A “New Cloud Service Project” window will appear — at least add an ASP.net MVC 2 Web Role and hit OK
  • Accept defaults on the “Create Unit Test Project” window and hit OK

Build your model 

  • Right click on References > Add Reference > .NET > System.Data.Services.Client
  • Right click the Models folder, add > class
  • Name the class YYY (where YYY is the singular form of the class, such as RallyPoint for www.RallyWire.com)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.WindowsAzure.StorageClient;
using Microsoft.WindowsAzure;
using System.ComponentModel.DataAnnotations;
using System.Web.Security;

namespace MvcWebRole1.Models
{
    public class YYY : TableServiceEntity
    {
        public YYY(string partitionKey, string rowKey)
            : base(partitionKey, rowKey)
        {
        }

        public YYY()
            : base()
        {
            PartitionKey = string.Empty;
            RowKey = Guid.NewGuid().ToString();
        }

        public string Name
        {
            get;
            set;
        }

        //when you add a new property, you must include this property in the edit method below or the value will not be updateable.
        //search for ITEMTOEDIT_UPDATE
    }

    //this is the context - akin to a data connection between the model and azure table storage
    /// <summary>
    /// DO NOT USE THIS FROM THE CONTROLLER. Use the YYYDataSource instead
    /// </summary>
    public class YYYData : TableServiceContext
    {

        public YYYData(string baseAddress, StorageCredentials credentials)
            : base(baseAddress, credentials)
        {
        }

        public const string YYYTableName = "YYYTable";

        public IQueryable<YYY> YYYTable
        {
            get
            {
                return this.CreateQuery<YYY>(YYYTableName);
            }
        }
    }
    /// <summary>
    /// This is the bridge between the controller and the model; you drop the following code on your controller to implement
    /// var svc = new Models.YYYDataSource();
    /// </summary>
    public class YYYDataSource
    {
        private YYYData _ServiceContext = null;

        public YYYDataSource()
        {
            var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
            storageAccount.CreateCloudTableClient().CreateTableIfNotExist(YYYData.YYYTableName);
            _ServiceContext = new YYYData(storageAccount.TableEndpoint.ToString(), storageAccount.Credentials);
        }

        private IQueryable<YYY> YYYTable
        {
            get
            {
                return _ServiceContext.YYYTable;
            }
        }

        public IEnumerable<YYY> Select()
        {
            var results = from c in _ServiceContext.YYYTable
                          select c;

            var query = results.AsTableServiceQuery<YYY>();
            var queryResults = query.Execute();

            return queryResults;
        }

        public void Edit(string id, YYY itemToEdit)
        {
            //var svc = new Models.YYYDataSource();
            var q = (from rp in YYYTable
                     where rp.RowKey == id
                     select rp).Single();

            //ITEMTOEDIT_UPDATE
            q.Name = itemToEdit.Name;

            _ServiceContext.UpdateObject(q);
            _ServiceContext.SaveChanges();

        }

        public void Delete(string id, YYY itemToEdit)
        {
            //var svc = new Models.YYYDataSource();
            var q = (from rp in YYYTable
                     where rp.RowKey == id
                     select rp).Single();
            _ServiceContext.DeleteObject(q);
            _ServiceContext.SaveChanges();
        }

        public void Insert(YYY newItem)
        {
            if (newItem.PartitionKey == null)
                newItem.PartitionKey = "primaryPartition";
            _ServiceContext.AddObject(YYYData.YYYTableName, newItem);
            _ServiceContext.SaveChanges();
        }
    }
}

Update WebRole.cs

  • In WebRole.cs in your MVCWebRole1 project, add a using Microsoft.Azure directive and replace your current OnStart() method with the following
        public override bool OnStart()
        {
            DiagnosticMonitor.Start("DiagnosticsConnectionString");
            RoleEnvironment.Changing += RoleEnvironmentChanging;
            CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
            {
                configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
                RoleEnvironment.Changed += (sender, arg) =>
                {
                    if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>()
                        .Any((change) => (change.ConfigurationSettingName == configName)))
                    {
                        if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
                        {
                            RoleEnvironment.RequestRecycle();
                        }
                    }
                };
            });
            return base.OnStart();
        }

Update Configuration

  • Finally, you are ready to point your Model at the right data store. Start by using local storage, which involves right clicking on the MVCWebRole1 role in the XXX project, selecting Properties > Settings > Add Setting, Name = DataConnectionString, Type = ConnectionString, value = UseDevelopmentStorage=true (you can specify this last parameter by clicking the elipses, but you do have to remember what you named your connection string in your YYY.cs file)
  • All of these steps are described in great detail at http://blogs.msdn.com/jnak/archive/2010/01/06/walkthrough-windows-azure-table-storage-nov-2009-and-later.aspx (steps 1-21), but then that article goes off to implement a grid view so it will not help you beyond this point.
  • Save and Build.

Update your controller 

  • In the controllers folder in the MVCWebRole1 folder, overwrite the original code with the following code: 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using MvcWebRole1.Models;
using System.Collections;
using System.Linq;
namespace MvcWebRole1.Controllers
{
    public class HomeController : Controller
    {
        //private MvcWebRole1.Models.YYYDataSource _entities = new YYYDataSource();
        YYYDataSource svc = new Models.YYYDataSource();
        //
        // GET: /Home/
        public ActionResult Index()
        {
            return View(svc.Select());
        }
        //
        // GET: /Home/Details/5
        //On the details page, add a link to get you to the delete (just copy the edit page)
        public ActionResult Details(string id)
        {
            var originalItem = svc.Select().First(i => i.RowKey == id);
            return View(originalItem);
        }
        //
        // GET: /Home/Create
        public ActionResult Create()
        {
            return View();
        }
        //
        // POST: /Home/Create
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Create([Bind(Exclude = "RowKey")]YYY itemToCreate)
        {
            svc.Insert(itemToCreate);
            return RedirectToAction("Index");
        }
        //
        // GET: /Home/Edit/5
        public ActionResult Edit(string id)
        {
            var originalItem = svc.Select().First(i => i.RowKey == id);
            return View(originalItem);
        }
        //
        // POST: /Home/Edit/5
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Edit(string id, YYY itemToEdit)
        {
            var originalItem = svc.Select().First(i => i.RowKey == id);
            svc.Edit(id, itemToEdit);
            return RedirectToAction("Index");
        }
        //
        // GET: /Home/Delete/5
        //To generate this page, right click, Add View, add it as an update page and remove all of the fields and just have a button that says confirm and cancel
        public ActionResult Delete(string id)
        {
            var originalItem = svc.Select().First(i => i.RowKey == id);
            return View(originalItem);
        }
        //
        // POST: /Home/Delete/5
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Delete(string id, YYY itemToDelete)
        {
            svc.Delete(id, itemToDelete);
            return RedirectToAction("Index");
        }
    }
}

Now Create Views

  • Build your solution. (i threw an error on one of the tests for an about page, so I deleted the failing test)
  • Delete About and Index from the Views > Home folder (we are going to create new ones)
  • Right click on Index, select Add View > Strongly Typed View > Select “MvcWebRole1.Models.YYY” from the top drop down and “List” from the bottom, Click Add.
  • Open the Index view under the home folder. You can modify the view to suit your needs (eg-remove columns that your visitors do not care about). Also, modify the links at the bottom of the page as follows:

<%= Html.ActionLink(“Edit”, “Edit”, new {  id=item.RowKey}) %> |
<%= Html.ActionLink(“Details”, “Details”, new { id = item.RowKey })%> |
<%= Html.ActionLink(“Delete”, “Delete”, new { id = item.RowKey })%>

  • Back on the HomeController, right click the delete method, and select Add View. Select strongly typed view and, in the content drop down, select Details.
  • On the Delete view, add the following code (probably below the fieldset):
    <% using (Html.BeginForm()) {%>
        <fieldset>
            <p>
                <input type="submit" value="Delete" />
            </p>
        </fieldset>
    <% } %>
  • You will need to uncomment and modify the Edit ActionLink to say:
id=Model.RowKey
  • Create views for Edit and Details. These are straight forward. Remember to uncomment and modify the id=Model.RowKey on the Details page.

Go Live

  • You are now ready to MVC out. Go to www.azure.com and get an account.
  • You need to get your keys from Azure and update your Web Config (see Update Configuration above…but use the key from your Azure storage account).
  • Right click on the XXX project and select publish. This will open a folder on your machine and a web page. Use the web page to upload the items in the folder.
  • Note: Azure charges you per hour that your instance exists, so you need to either buy the $60/month version, or delete (not suspend) the active instance (you get 25 hours for free in a month…that is one day).
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: