My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
StrongTypedBlobName  
Strong-typed patterns to work with the Blob Storage
Updated Mar 17, 2011 by joannes.vermorel

Introduction

The Blob Storage is a very scalable hierarchical storage bundled with Windows Azure. For an introduction to the Blob Storage, check the Blob Storage API. Apps implemented against the raw API tends to rely on brittle implementations. Lokad.Cloud exposes a pattern named BlobName<T> which helps developers to strengthen their interactions with the Blob Storage.

The problem

Blob Storage is basically a hierarchical storage, that is to say, we have the possibly to enumerate items that match a certain blob name prefix. For example, considering

/customers/country/city/customer-id

where customers is the container, it is possible to enumerate only customers related to a specific country code through the List operation on containers.

The naive approach to compose blob names consist in concatenating strings, with

var myBlobName = myCountryCode + Delimiter + myCity + Delimiter + myCustomerId;

Obviously, this approach suffers from several drawbacks:

  • logic is brittle, no validation of any kind to check if the blob name is valid considering the current convention.
  • logic is verbose, as we end up introducing + Delimiter for each hierarchy level.
  • no strong typing of the content referenced by the blob name, which lead to cloud equivalent of the InvalidCastException if we were storing loads of misc object in an untyped collection.

The solution: BlobName

Lokad.Cloud.Storage provides a generic abstract class named BlobName<T> to deal with this situation. In short, Lokad.Cloud is using .NET reflection to implicitly generate and parse blob name associated with existing classes in your code.

Let us consider the example:

public class CustomerBlobName : BlobName<Customer>
{
  public override string ContainerName
  {
    get { return "customers"; }
  }

  [Rank(0)] public CountryCode Country { get; set; }
  [Rank(1)] public CityCode City { get; set; }
  [Rank(2)] public long CustomerId { get; set; }
}

The class CustomerBlobName as been introduced as a strong type pattern to reference Customer instances in the blob storage (notice that the type is provided as a generic argument).

The RankAttribute (part of Lokad.Cloud) is used to specify the actual property (or field) ordering used for the fields. In case of a BlobName composed through inheritance, fields of ascendant classes always comes before the fields of their inheritors.

Calling CustomerBlobName.ToString() directly returns the generated blob name, and CustomerBlobName.Parse(string rawBlobName) returns the parsed instance. Although, those primitives are not intended to be used directly in the client code as Lokad.Cloud provides convenient utilities for that.

Strong-typed get and put

For example, let us consider a direct data retrieval with:

IBlobStorageProvider storage = ... ; // init snipped
CustomerBlobName name = ... ; // init snipped
var customer = storage.GetBlob(name); // strong type retrieved

Here customer is a strong typed object of type Customer. If there is no such instance in the blob storage, the method would simply return null.

Note also that IBlobStorageProvider is an interface provided with Lokad.Cloud, the actual implementation is typically obtained through IoC (inversion of control).

In a similar fashion, a customer can be stored with:

storage.PutBlob(name, customer); // strong type stored

Strong-typed list

Back to our example, we would like now to enumerate all customers of a specified country. This could be done by instantiating a partially populated instance. We enumerate customers of a specified country with:

foreach(var name in storage.List(new CustomerBlobName { Country = country })
{
  var customer = storage.GetBlob(name); // strong type
  // do something with 'customer', snipped
}

Customers are iterated in a strong typed manner, through a List method that returns CustomerBlobName instances. Note that List is a lazy enumerator moving forward with the underlying Blob Storage API only when needed (i.e. we don't try to retrieve at first all the blob names).

Stand-alone code sample

The following code sample illustrates how to store entities in the Blob Storage, and then how to list them through the pseudo-hierarchical properties of the Blob Storage. In order to get the code working, you need to reference two libraries:

  • System.Runtime.Serialization.dll
  • Lokad.Cloud.Storage.dll
using System;
using System.Runtime.Serialization;
using Lokad.Cloud;
using Lokad.Cloud.Storage;

namespace SimpleBlob
{
    [DataContract]
    class Book
    {
        [DataMember]
        public string Title { get; set; }

        [DataMember]
        public string Author { get; set; }
    }

    class BookName : BlobName<Book>
    {
        public override string ContainerName
        {
            get { return "books"; } // default container for 'Book' entities
        }

        [Rank(0)] public string Publisher { get; set;}

        // TreatDefaultAsNull = true, '0' will be ignored
        [Rank(1, true)] public int BookId { get; set;}
    }

    class Program
    {
        static void Main(string[] args)
        {            
            // TODO: change your connection string here
            var providers = CloudStorage.ForAzureConnectionString(
               "DefaultEndpointsProtocol=https;AccountName=;AccountKey=").BuildStorageProviders();
            var blobStorage = providers.BlobStorage;

            var potterBook = new Book { Author = "J. K. Rowling", Title = "Harry Potter" };
            // Resulting blob name is: Bloomsbury Publishing/1
            var potterRef = new BookName {Publisher = "Bloomsbury Publishing", BookId = 1};

            var poemsBook = new Book { Author = "John Keats", Title = "Complete Poems" };
            // Resulting blob name is: Harvard University Press/2
            var poemsRef = new BookName {Publisher = "Harvard University Press", BookId = 2};
            
            // writing entities to the storage
            blobStorage.PutBlob(potterRef, potterBook);
            blobStorage.PutBlob(poemsRef, poemsBook);

            // retrieving all entities from 'Bloomsbury Publishing'
            foreach (var bookName in blobStorage.List(new BookName { Publisher = "Bloomsbury Publishing" }))
            {
                var book = blobStorage.GetBlob(bookName).Value;
                Console.WriteLine("{0} by {1}", book.Title, book.Author);
            }

            Console.WriteLine("Press enter to exit.");
            Console.ReadLine();
        }
    }
}

Notice that the 'book' instances as retrieved from the Blob Storage are strong-typed as Book instead of being objects or byte[].

Comment by ramvil...@gmail.com, Aug 25, 2011

How to we query book list with aggrigate functions.

Comment by ramvil...@gmail.com, Aug 25, 2011

Is it possible to use LINQ query to Blob Storage.


Sign in to add a comment
Powered by Google Project Hosting