Getting Git

I’ve been stumbling through getting familiar with Git over the last couple of weeks.  It’s the source repository we use at work (thank goodness I’m rid of the damnable TFS nonsense!) and I have officially moved all of my Subversion & even Mercurial Repositories to Git.  I really enjoy using Unfuddle, so have moved back to that after using Repositoryhosting for a while.  The reason boils down to Open ID.  Repositoryhosting didn’t support Open ID and Unfuddle does.  Repositoryhosting supported Mercurial which I’ll admit is awesome.  I really enjoyed that but wanted the combination of Git experience + Open Id that I get with Unfuddle.  In addition, I actually like their management and project tools better.  So back I’ve come to Unfuddle.

Over the next few weeks I’ll probably be posting a few tidbits about Git.  For this entry here’s a tidbit on ignoring certain files that don’t need committed or pushed into the repository.  Based on that this is what my exclude file looks like.

  • Resharper
  • obj
  • bin
  • *.suo
  • *.user
  • *.vs10x

For more information on setting files to ignore, check out the github man page.

UPDATE (1/5/2011):  New post & updated file in this post.

Windows Azure Table Storage Part 2

In the first part of this two part series I reviewed what table storage in Windows Azure is. In addition I began a how-to for setting up an ASP.NET MVC 2 Web Application for accessing the Windows Azure Table Storage (sounds like keyword soup all of a sudden!). This sample so far is enough to run against the Windows Azure Dev Fabric. However I still need to setup the creation, update, and deletion views for the site, so without further ado, let’s roll.

  1. In the Storage directory of the ASP.NET MVC Web Application right click and select Add and then View. In the Add View Dialog select the Create a strongly-typed view option. From the View data class drop down select the EmailMergeManagement.Models.EmailMergeModel, select Create form the View content drop down box, and uncheck the Select master page check box. When complete the dialog should look as shown below.

    Add New View to Project Dialog

    Add New View to Project Dialog

  2. Now right click and add another view using the same settings for Delete and name the view Delete.
  3. Right click and add another view using the same settings for Details and name the view Details.
  4. Right click and add another view for Edit and List, naming these views Edit and List respectively.  When done the Storage directory should have the following views; Create.aspx, Delete.aspx, Details.aspx, Edit.aspx, Index.aspx, and List.aspx.

Now the next steps are to setup a RoleEntryPoint class for the web role to handle a number of configuration and initializations of the storage table.  The first bit of this code will start the diagnostics connection string and wire up the event for the role environment changing.  After this the cloud storage account will have the configuration for the publisher set so the configuration settings can be used.  Finally the role environment setting will be setup so that it will recycle so that the latest settings and credentials will be used when executing.

  1. Create a new class in the root of the ASP.NET MVC Web Application and call it EmailMergeWebAppRole.
  2. Add the following code to the EmailMergeWebAppRole class.
using System.Linq;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;

namespace EmailMergeManagement
{
    public class EmailMergeWebAppRole
    {
        public class WebRole : RoleEntryPoint
        {
            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()
                            .Any((change) =>
                                (change.ConfigurationSettingName == configName)))
                        {
                            if (!configSetter(RoleEnvironment.
                                GetConfigurationSettingValue(configName)))
                            {
                                RoleEnvironment.RequestRecycle();
                            }
                        }
                    };
                });

                return base.OnStart();
            }

            private static void RoleEnvironmentChanging(object sender,
                RoleEnvironmentChangingEventArgs e)
            {
                if (e.Changes.Any(change =>
                    change is RoleEnvironmentConfigurationSettingChange))
                {
                    e.Cancel = true;
                }
            }
        }
    }
}
  1. Now open up the StorageController class in the Controllers directory.
  2. Add an action method for the List view with the following code.
public ActionResult List()
{
    var emailMergeListing = new EmailMergeRepository().Select();
    return View(emailMergeListing);
}
  1. Add the following two actions to the StorageController Class.
public ActionResult Create()
{
    return View();
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(EmailMergeModel emailMergeModel)
{
    if (!ModelState.IsValid)
        return View();

    emailMergeModel.LastEditStamp = DateTime.Now;
    emailMergeModel.RowKey = Guid.NewGuid().ToString();

    var emailMergeRepository = new EmailMergeRepository();
    emailMergeRepository.Insert(emailMergeModel);

    return RedirectToAction("List");
}
  1. On the Index.aspx view add some action links for the following commands.
<ul>
	<li>Email Merge Items
        <%: Html.ActionLink("List", "List", "Storage") %>.</li>
	<li>
        <%: Html.ActionLink("Create", "Create", "Storage") %>
        a new Email Merge Item.</li>
</ul>
  1. Open up the Create.aspx view and remove the following HTML & other related markup from the page.
<div class="editor-label">
    <%: Html.LabelFor(model => model.LastEditStamp) %></div>
<div class="editor-field">
    <%: Html.TextBoxFor(model => model.LastEditStamp) %>
    <%: Html.ValidationMessageFor(model => model.LastEditStamp) %></div>
<div class="editor-label">
    <%: Html.LabelFor(model => model.Timestamp) %></div>
<div class="editor-field">
    <%: Html.TextBoxFor(model => model.Timestamp) %>
    <%: Html.ValidationMessageFor(model => model.Timestamp) %></div>
<div class="editor-label">
    <%: Html.LabelFor(model => model.PartitionKey) %></div>
<div class="editor-field">
    <%: Html.TextBoxFor(model => model.PartitionKey) %>
    <%: Html.ValidationMessageFor(model => model.PartitionKey) %></div>
<div class="editor-label">
    <%: Html.LabelFor(model => model.RowKey) %></div>
<div class="editor-field">
    <%: Html.TextBoxFor(model => model.RowKey) %>
    <%: Html.ValidationMessageFor(model => model.RowKey) %></div>

There is now enough collateral in the web application to run the application and create new EmailMergeModel items and view them with the list view. Click on F5 to run the application. The first page that should come up is show below.

Windows Azure Storage Samples Site Home Page

Windows Azure Storage Samples Site Home Page

Click on the Windows Azure Table Storage link to navigate to the main view of the storage path. Here there is now the Create and List link. Click on the Create link and add a record to the table storage. The Create view will look like below when you run it.

Windows Azure Storage Samples Site Create Email Merge Listing

Windows Azure Storage Samples Site Create Email Merge Listing

I’ve added a couple just for viewing purposes, with the List view now looking like this.

Windows Azure Storage Samples Site Listings

Windows Azure Storage Samples Site Listings

Well that’s a fully functional CRUD (CReate, Update, and Delete) Web Application running against Windows Azure.  With a details screen to boot.

Google Docs, Why 90% of Users Should Migrate Yesterday

That video alone pretty much says it all.  It isn’t about the word processor, or the device, it’s just about writing what you want when you want and how you want.  The old legacy mindset of an installed word processor is a bit feeble these days.  Especially considering the integrity of Google Docs vs. Microsoft Word.  Don’t even get me started on how flimsy Excel is.  The old installed application sweet of several hundred Megabytes just doesn’t hold up for an fast paced, quickly adaptive, thought leader style business.  Microsoft said it best in the old wars between WordPerfect and Word, even though WordPerfect (which I think version 9 or 11 or something is STILL more feature rich than Word) had tons of more features, Microsoft stated frequently that 80-90% of users never used those features.

Now we’re in a situation were 80-90% of people don’t use the features in Word, and it costs a lot of cash versus the free offering from Google Docs.  Funny how the tides turn to throw Microsoft’s won words back at the company.

Some may be screaming at this point, “nobody is going to dump Word & the Office Suite”.  Again, the same thing was said about WordPerfect in the late 90’s.  Does anyone still use it?  Maybe 1-2% of the market?

Other people may also argue, “but all of the programmable extensible… [fill in some form of extending Office here] …stuff for Office makes it immensely valuable!”  Maybe, but it is a small subset of users that actually use addons to their Microsoft Office Suite.  In addition, most developers don’t want to touch Office addons at all, they’d rather the suite languish than to develop to the jumbled chaos that is the Microsoft Office Suite Addons and such.

But I digress, one might say, “you’re just biased and don’t like the Microsoft Office Suite”…  and I’d say you got me there!  I’m guilty.  Over the years Microsoft has made billions of dollars on this suite.  By proxy they’ve then dumped billions of dollars into software development and other things.  However, people really shouldn’t be spending vast sums of money on something that should – and will – become a commodity software product over the next 1-5 years.  As Enterprises realize they can easily provide word processor, spreadsheet, and presentation software for small percentages of what Microsoft does the transitions should continue to occur.

Microsoft even seems convinced of this and started making the move with Office 365 + SaaS based Office provision on Windows Live.  I don’t wish the company ill will of any sort, so hopefully they’ll pull out of their software nose dive with the SaaS offering.

Windows Azure Table Storage Part 1

This is the first part of a two part series on building a basic working web app using ASP.NET MVC to create, update, delete, and access views of the data in a Windows Azure Table Storage Service.  The second part will be published this next Monday.  With that stated, let’s kick off with some technical specifics about Windows Azure Table Storage.

The Windows Azure Table service provides a structured storage in the form of tables.  The table storage you would setup within Windows Azure is globally unique.  Any number of tables can be created within a given account with the requirement that each table has a unique name.

The table storage account is specified within a unique URI such as:

http://myaccount.table.core.windows.net

Within each table the data is broken into collections called entities.  Entities are basically rows of data, similar to a row in a spreadsheet or a row within a database.  Each entity has a required primary key and a set of properties.  The properties are a name, typed-value pair, similar to a column.

Tables, Entities, and Properties

There are three core concepts to know when dealing with Windows Azure Tables; Table, Entities, and Properties.  For each of these core features of the Windows Azure Table Storage it is important to be able to add, possibly update, and delete the respective table, entity, or property.

Windows Azure Table Hierarchy;

  • Table – Similar to a spreadsheet or table in a relational database.
  • Entity – Similar to a row of data in a spreadsheet, relational database, or flat file.
  • Property – Similar to a cell in a spreadsheet or tuple in a relational database.

Each entity has the following system properties; a partition key, row key, and time stamp.  These properties are included with every entity and have reserved naming.  The partition and row key are responsibilities of the developer to insert into, while the time stamp is managed by the server and is read only.

Three properties that are part of every table;

  • Partition Key
  • Row Key
  • Time Stamp

Each table name must conform to the following rules; a name may have only alphanumeric characters, may not begin with a numeric character, are case-insensitive, and must be between 3 and 63 characters.

Tables are split across many nodes for horizontal scaling.  The traffic to these nodes is load balanced.  The entities within a table are organized by partition.  A partition is a consecutive range of entities possessing the same key value, the key being a unique identifier within a table for the partition.  The partition key is the first part of the entity’s primary key and can be up to 1 KB in size.  This partition key must be included in every insert, update, and delete operation.

The second part of the primary key is the row key property.  It is a unique identifier that should not be read, set on insert or update, and generally left as is.

The Timestamp property is a DateTime data type that is maintained by the server to record the entity for last modifications.  This value is used to provide optimistic concurrency to table storage and should not be read, inserted, or updated.

Each property name is case sensitive and cannot exceed 255 characters.  The accepted practice around property names is that they are similar to C# identifiers, yet conform to XML specifications.  Examples would include; “streetName”, “car”,  or “simpleValue”.

To learn more about the XML specifications check out the W3C link here:  http://www.w3.org/TR/REC-xml/.  This provides additional information about properly formed XML that is relatable to the XML usage with Windows Azure Table Storage.

Coding for Windows Azure Tables

What I am going to show for this code sample is how to setup an ASP.NET MVC Application using the business need of keeping an e-mail list for merges and other related needs.

I wrote the following user stories around this idea.

  1. The site user can add an e-mail with first and last name of the customer.
  2. The site user can view a listing of all the e-mail listings.
  3. The site user can delete a listing from the overall listings.
  4. The site user can update a listing from the overall listings.

This will provide a basic fully functional create, update, and delete against the Windows Azure Table Storage.  Our first step is to get started with creating the necessary projects within Visual Studio 2010 to create the site with the Windows Azure Storage and Deployment.

  1. Right click on Visual Studio 2010 and select Run As Administrator to execute Visual Studio 2010.
  2. Click on File, then New, and finally Project.  The new project dialog will appear.
  3. Select the Web Templates and then ASP.NET MVC 2 Empty Web Application.
  4. Name the project EmailMergeManagement.  Click OK.
  5. Now right click on the Solution and select Add and then New Project.  The new project dialog will appear again.
  6. Select the Cloud Templates and then the Windows Azure Cloud Service.
  7. Name the project EmailMergeManagementAzure.  Click OK.
  8. When the New Cloud Service Project dialog comes up, just click OK without selecting anything.
  9. Right click on the Roles Folder within the EmailMergeManagementAzure Project and select Add and then Web Role Project in Solution.
  10. Select the project in the Associate with Role Project Dialog and click OK.

The Solutions Explorer should have the follow projects, folders, files, and Roles setup.

Solution Explorer

Solution Explorer

  1. Now create controller classes called StorageController and one called HomeController.
  2. Now a Storage and Home directory in the Views directory.
  3. Add a view to each of those directories called Index.aspx.
  4. In the Index.aspx view in the Home directory add the following HTML.
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>

        <%:Html.Encode(ViewData["Message"])%>
<h1>
        <%:Html.Encode(ViewData["Message"])%></h1>
        This ASP.NET MVC Windows Azure Project provides examples around
        the Windows Azure Storage usage utilizing the Windows Azure SDK.
<ul>
	<li>
            <%:Html.ActionLink("Windows Azure Table Storage", "Index",                                               "Storage")%></li>
</ul>
  1. In the Storage directory Index.aspx view add the following code.
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>

        <%: Html.Encode(ViewData["Message"])%>
<h1>
        <%: Html.Encode(ViewData["Message"])%></h1>
  1. In the StorageController add this code.
using System.Web.Mvc;

namespace EmailMergeManagement.Controllers
{
    public class StorageController : Controller
    {
        public ActionResult Index()
        {
            ViewData["Message"] = "Windows Azure Table Storage Sample";
            return View();
        }
    }
}
  1. In the HomeController add this code.
using System.Web.Mvc;

namespace EmailMergeManagement.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewData["Message"] = "Windows Azure Storage Samples";
            return View();
        }
    }
}

Now the next step is to get our Models put together.  This section will include putting together the class for the Email Merge Listing Model, the repository class for getting the data in and out of the table, and the context object that is used for connecting to the actual Development Fabric or Windows Azure Table Storage.

Solution Explorer

Solution Explorer

  1. First add the following references; System.Data.Services.Client,  Microsoft.WindowsAzure.CloudDrive, Microsoft.WindowsAzure.Diagnostics, Microsoft.WindowsAzure.ServiceRuntime, and Microsoft.WindowsAzure.StorageClient to the project by right clicking on the References virtual folder for the EmailMergeManagement Project.
  2. Once you add these references create a class in the Models folder called EmailMergeModel and add the following code.  I’ve added some basic validation attributes to the Email, First, and Last Properties of the EmailMergeModel Class just so that it has a little more semblance of something you may actually see in real world use.
using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.WindowsAzure.StorageClient;

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

        public EmailMergeModel()
            : this(Guid.NewGuid().ToString(), string.Empty)
        {
        }

        [Required(ErrorMessage = "Email is required.")]
        [RegularExpression("^[a-z0-9_\\+-]+(\\.[a-z0-9_\\+-]+)*@[a-z0-9_\\+-]+(\\.[a-z0-9_\\-]+)*\\.([a-z]{2,4})$",
            ErrorMessage = "Not a valid e-mail address.")]
        public string Email { get; set; }

        [Required(ErrorMessage = "First name is required.")]
        [StringLength(50, ErrorMessage = "Must be less than 50 characters.")]
        public string First { get; set; }

        [Required(ErrorMessage = "Last name is required.")]
        [StringLength(50, ErrorMessage = "Must be less than 50 characters.")]
        public string Last { get; set; }

        public DateTime LastEditStamp { get; set; }
    }
}
  1. Now add a class titled EmailMergeDataServiceContext for our data context.  This class provides the basic TableServiceContext inheritance that allows for creation of the table, entities, and properties through the Windows Azure SDK.
  2. Add the following code to the EmailMergeDataServiceContext Class.
using System.Linq;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;

namespace TestingCloudsWebApp.Models
{
    public class EmailMergeDataServiceContext : TableServiceContext
    {
        public const string EmailMergeTableName = "EmailMergeTable";

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

        public IQueryable EmailMergeTable
        {
            get { return CreateQuery(EmailMergeTableName); }
        }
    }
}
  1. Create a class in the Models directory called EmailMergeRepository.  This is the class I will use to add the insert, update, and delete functionality.
  2. Now add a constructor and private readonly EmailMergeDataServiceContext member as shown below.
private readonly EmailMergeDataServiceContext _serviceContext;

public EmailMergeRepository()
{
    var storageAccount = CloudStorageAccount.
        FromConfigurationSetting("DiagnosticsConnectionString");
    _serviceContext =
        new EmailMergeDataServiceContext(
            storageAccount.TableEndpoint.ToString(),
            storageAccount.Credentials);

    storageAccount.CreateCloudTableClient().
        CreateTableIfNotExist(
            EmailMergeDataServiceContext.EmailMergeTableName);
}
  1. Next add the select and get by methods to retrieve EmailMergeModel Objects.
public IEnumerable<EmailMergeModel> Select()
{
    var results = from c in _serviceContext.EmailMergeTable
                    select c;

    var query = results.AsTableServiceQuery();
    var queryResults = query.Execute();

    return queryResults;
}

public EmailMergeModel GetEmailMergeModel(string rowKey)
{
    EmailMergeModel result = (from c in _serviceContext.EmailMergeTable
                                where c.RowKey == rowKey
                                select c).FirstOrDefault();
    return result;
}
  1. Next add a method to add our custom date & time stamp for inserts and updates.
private static EmailMergeModel StampIt(EmailMergeModel emailMergeModel)
{
    // This is a sample of adding a cross cutting concern or similar functionality.
    emailMergeModel.LastEditStamp = DateTime.Now;
    return emailMergeModel;
}
  1. Finally the delete, insert, and update methods can be added.
public void Delete(EmailMergeModel emailMergeModelToDelete)
{
    _serviceContext.Detach(emailMergeModelToDelete);
    _serviceContext.AttachTo(EmailMergeDataServiceContext.EmailMergeTableName,
        emailMergeModelToDelete, "*");
    _serviceContext.DeleteObject(emailMergeModelToDelete);
    _serviceContext.SaveChanges();
}

public void Insert(EmailMergeModel emailMergeModel)
{
    _serviceContext.AddObject(EmailMergeDataServiceContext.EmailMergeTableName, StampIt(emailMergeModel));
    _serviceContext.SaveChanges();
}

public void Update(EmailMergeModel emailMergeModelUpdate)
{
    var emailMergeModelOld = GetEmailMergeModel(emailMergeModelUpdate.RowKey);
    Delete(emailMergeModelOld);
    Insert(StampIt(emailMergeModelUpdate));
}
  1. At this point the Solution Explorer should have the following files and structure.

Storage Explorer

Storage Explorer

That’s it for part 1 of this two part series.  The next entry I’ll have posted this coming Monday, so stay tuned for the final steps.  🙂

Shout it

Webtrend SDK and REST API Calls (DataExchange)

Even though I left Webtrends well over 6 months ago, I still regularly talk to a number of my cohorts there.  I also still talk to a number of customers who I became friends with over my years with the company.  I was contacted recently by a couple of those contacts asking if the posts I made or the SDK I helped put together were still available.  I went to searching and I found the following blog entries that I had put together while at Webtrends.  In addition I did find a link to the Webtrends DX .NET SDK.  I however would check with someone at Webtrends as to if it is supported or has been kept up to date.  Either way, it provides a great resource for a starting point in accessing the Webtrends DX RESTful APIs.

Blog Entries

Webtrends DX .NET SDK

Hope these links provide a good kick start for using the Webtrends DX API.  🙂