Using spatial data in the Windows Azure Blob Storage

[Infragistics] Mihail Mateev / Sunday, April 17, 2011

When talking about spatial data in the Windows Azure understand SQL Azure Spatial. Windows Azure presents other options when you file your sources for spatial data is to use Windows Azure Blob Storage. Due to the lack of good examples of this I decided to write this article.

Demo application is a Silverlight application for visualization of spatial data that uses data from the Windows Azure Blob Storage. This application uses Infragistics Silverlight XamMap component for visualization of spatial data.

Unlike my other articles about Windows Azure that will use in Windows Azure Emulator, which is installed with Windows Azure Tools and you can use to test your Windows Azure applications.

Windows Azure Blob Storage Concepts

Accessing the Windows Azure Storage is done via a storage account. A storage account can have many blob containers.
A container is a user-defined set of blobs that has only properties, which include a list of the blobs it contains. Containers don’t store data directly.

Defining the blob

The word blob stands for binary large objects. Blobs store binary data, such as images, XML documents, compressed (zipped or gzipped) files, and other content as an arbitrary array of bytes within a container that’s associated with a storage account.

Blob URL

http://<Account>.blob.core.windows.net/<Container>/<BlobName>

Example:

Types of Blobs
  • Block Blob

A Block blobs is a collection of blocks, where each block has a block ID (of 64 bytes). A Block Blob can be up to 200GB. You can upload a maximum of 64MB of data in a Put Blob operation to create a blob. If it is larger than 64MB it must be sent in multiple chunks of no more than 4MB, with Put Block operations.

  • Page Blob

A Page Blob can be up to 1TB is size and is organized into 512 byte pages within the block. Any point in the blob can be accessed for read or write operations by using the offside from the start of the blob.

Requirements to build a sample application:

  1. Visual Studio 2010
  2. SQL Server 2008 R2 Express or higher license. (to use a Windows Azure emulator)
  3. NetAdvantage for Silverlight Data Visualization 2010 vol.3
  4. The most recent version of Windows Azure Tools for Visual Studio
  5. Windows Azure account

Steps to create the sample application

  1. Create a Silverlight Application,  hosted in an ASP.Net Web Application.
  2. Add references to Microsoft.WindowsAzure.Diagnostics, Microsoft.WindowsAzure.ServiceRuntime and  Microsoft.WindowsAzure.StorageClient from Windows Azure SDK.
  3. Implement a WCF to upload and download files, using Windows Azure Blob Storage.
  4. Add in the client Silverlight application XamMap component.
  5. Implement shapefile loading from Isolated Storage to XamMap.
  6. Create a new Windows Azure Storage Account and a Hosted Service (if you are using a Windows Azure Account).
  7. Add a Web Role project in Solution
  8. Edit settings in ServiceReferences.ClientConfig .
  9. Publish the Windows Azure Cloud Service (if you are using a Windows Azure Account). :
  10. Run the demo application

 

Create a Silverlight Application, hosted in an ASP.Net Web Application.

Add references to Microsoft.WindowsAzure.Diagnostics, Microsoft.WindowsAzure.ServiceRuntime and Microsoft.WindowsAzure.StorageClient from Windows Azure SDK.

Add in the client Silverlight application XamMap component.

   1: <ig:XamMap  
   2:             HorizontalAlignment="Stretch" 
   3:             Margin="30" 
   4:             x:Name="xamMap" 
   5:             VerticalAlignment="Top" 
   6:             ElementClick="XamMapElementClick"
   7:             MapProjectionType="Equirectangular"
   8:             Loaded="XamMapLoaded" >
   9:     <ig:MapNavigationPane Name="navPane" Width="100" Height="300" Margin="0,0,0,0" 
  10:             HorizontalAlignment="Left" VerticalAlignment="Top"/>
  11:  
  12:     <ig:XamMap.Layers>
  13:             <ig:MapLayer 
  14:             x:Name="World" Brushes="#4C2C42C0 #4C218B93 #4CDC1C1C #4C3D7835 #4C701B51" 
  15:             FillMode="Choropleth">
  16:                 
  17:                 <ig:MapLayer.ValueScale>
  18:                     <ig:LinearScale IsAutoRange="True"/>
  19:                 </ig:MapLayer.ValueScale>
  20:             </ig:MapLayer>
  21:         </ig:XamMap.Layers>
  22: </ig:XamMap>

 

Implement a WCF to upload and download files, using Windows Azure Blob Storage.

Create a method UploadFile that receives file name and file content as byte array. This method saves a file in the blob storage.

   1: #region UploadFile
   2: /// <summary>
   3: /// Uploads a file with specified file name
   4: /// and content like a byte array.
   5: /// </summary>
   6: /// <param name="fileName">Name of the file.</param>
   7: /// <param name="data">The data.</param>
   8: [OperationContract]
   9: public void UploadFile(string fileName, byte[] data)
  10: {
  11:  
  12:     this.EnsureContainerExists();
  13:  
  14:     var newId = Guid.NewGuid();
  15:  
  16:     SaveShapeFile(newId.ToString(), null, fileName, @"application/octet-stream", data);
  17:  
  18: }
  19: #endregion //UploadFile

 

   1: #region EnsureContainerExists
   2:  private void EnsureContainerExists()
   3:  {
   4:      var container = GetContainer();
   5:      container.CreateIfNotExist();
   6:  
   7:      var permissions = container.GetPermissions();
   8:      permissions.PublicAccess = BlobContainerPublicAccessType.Container;
   9:      container.SetPermissions(permissions);
  10:  }
  11:  #endregion //EnsureContainerExists

 

SaveShapeFile writes file in the blob block isolated storage.

   1: #region SaveShapeFile
   2:  private void SaveShapeFile(string id, string description, string fileName, string contentType, byte[] data)
   3:  {
   4:      var blob = GetContainer().GetBlobReference(fileName);
   5:  
   6:      blob.Properties.ContentType = contentType;
   7:      var metadata = new NameValueCollection();
   8:      metadata["Id"] = id;
   9:      metadata["Filename"] = fileName;
  10:      metadata["Description"] = String.IsNullOrEmpty(description) ? "unknown" : description;
  11:  
  12:      blob.Metadata.Add(metadata);
  13:      blob.UploadByteArray(data);
  14:  }
  15:  #endregion //SaveShapeFile

 

Create a method DownloadFile that receives a content as byte array for specified file name.

   1: #region DownloadFile
   2: /// <summary>
   3: /// Downloads the file with specified file name.
   4: /// </summary>
   5: /// <param name="fileName">Name of the file.</param>
   6: /// <returns></returns>
   7: [OperationContract]
   8: public byte[] DownloadFile(string fileName)
   9: {
  10:     try
  11:     {
  12:         var srcBlob = this.GetContainer().GetBlobReference(fileName);
  13:         byte[] data = srcBlob.DownloadByteArray();
  14:         return data;
  15:     }
  16:     catch (Exception)
  17:     {
  18:         return null;
  19:     }
  20: }
  21: #endregion //DownloadFile

 

   1: private void BtnUploadFile_Click(object sender, RoutedEventArgs e)
   2: {
   3:     //create an object for file open dialog
   4:     _openDialog = new
   5:     OpenFileDialog();
   6:     _openDialog.Multiselect = false;
   7:     _openDialog.Filter = "All Files|*.*";
   8:     //show the file browser dialog to select file
   9:     _openDialog.ShowDialog();
  10:  
  11:     if (_openDialog.File != null && _openDialog.File.Name != "")
  12:     {
  13:         string fileName = _openDialog.File.Name;
  14:         Stream strm = _openDialog.File.OpenRead();
  15:         UploadFile(strm, fileName);
  16:     
  17:     
  18:     }
  19: }
  20:  
  21: #region UploadFile
  22: private void UploadFile(Stream strm, string fileName)
  23: {
  24:     byte[] buffer = new byte[strm.Length];
  25:     strm.Read(buffer, 0, (int)strm.Length);
  26:     strm.Close();
  27:  
  28:     UploadFile(buffer, fileName);
  29: }
  30:  
  31: private void UploadFile(byte[] buffer, string fileName)
  32: {
  33:     UploadServiceClient client = new UploadServiceClient();
  34:     client.UploadFileCompleted += ClientUploadFileCompleted;
  35:  
  36:     client.UploadFileAsync(fileName, buffer);
  37: }
  38: #endregion //UploadFile
  39:  
  40:  
  41:  
  42: #region ClientUploadFileCompleted
  43: private void ClientUploadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
  44: {
  45:     if (e.Error == null)
  46:     {
  47:         MessageBox.Show(_openDialog.File.Name + ": Successfully Saved at ServerLocation");
  48:  
  49:         RefreshFilesList();
  50:     }
  51:     else
  52:     {
  53:         MessageBox.Show(e.Error.Message);
  54:     }
  55: }
  56: #endregion //ClientUploadFileCompleted
  57:  
  58:  
  59: #region RefreshFilesList
  60: //Updates a list with file names from the server
  61: private void RefreshFilesList()
  62: {
  63:     UploadServiceClient client = new UploadServiceClient();
  64:  
  65:     client.RefreshFileListCompleted -= ClientRefreshFileListCompleted;
  66:     client.RefreshFileListCompleted += ClientRefreshFileListCompleted;
  67:     client.RefreshFileListAsync();
  68:     client.CloseAsync();
  69: }
  70:  
  71: void ClientRefreshFileListCompleted(object sender, RefreshFileListCompletedEventArgs e)
  72: {
  73:  
  74:     ObservableCollection<string> items = e.Result;
  75:  
  76:     this.FilesListBox.ItemsSource = items;
  77: }
  78: #endregion //RefreshFilesList

 

When download file from blob storage you need to save it in the Silverlight application Isolated Storage.

   1: #region BtnDownloadClick
   2: private void BtnDownloadClick(object sender, RoutedEventArgs e)
   3: { 
   4:  
   5:     if (this.FilesListBox.SelectedItem == null)
   6:     {
   7:         return;
   8:     }
   9:  
  10:     string fileName = this.FilesListBox.SelectedItem.ToString();
  11:  
  12:     UploadServiceClient client = new UploadServiceClient();
  13:  
  14:     client.DownloadCompleted -= ClientDownloadCompleted;
  15:  
  16:     client.DownloadCompleted += ClientDownloadCompleted;
  17:  
  18:     client.DownloadAsync(fileName, fileName);
  19:  
  20: }
  21:  
  22: void ClientDownloadCompleted(object sender, DownloadCompletedEventArgs e)
  23: {
  24:     byte[] res = e.Result;
  25:  
  26:     string fileName = e.UserState.ToString();
  27:  
  28:     if (fileName != null)
  29:     {
  30:         WriteDataToStore(res, fileName);
  31:     }
  32:     
  33: }
  34: #endregion //BtnDownloadClick

 

   1: #region WriteDataToStore
   2: // Writes a file to an Isolated IStrorage, specified via its name 
   3: // and content like a byte array
   4: private void WriteDataToStore(byte[] data, string fileName)
   5: {
   6:     if (data == null || data.Length == 0)
   7:         return;
   8:     using (var store = IsolatedStorageFile.GetUserStoreForApplication())
   9:     {
  10:  
  11:         IsolatedStorageFileStream fileStream = store.CreateFile(fileName);
  12:         fileStream.Write(data, 0, data.Length);
  13:         fileStream.Close();
  14:  
  15:     }
  16:  
  17:     RefreshIsoFilesList();
  18: }
  19:  
  20: #endregion //WriteDataToStore

 

Implement shapefile loading from Isolated Storage to XamMap.

Shapefile is one of the first file formats, used to keep a spatial data.

 

More information about shapefile format you could find here:
http://en.wikipedia.org/wiki/Shapefile

Load the shape files from isolated storage using the ShapeFileReader:

You could redirect URI requests by registering custom prefixes in Silverlight.
The important line here being:

   1: WebRequest.RegisterPrefix("iso",  
   2:                     new IsoStorageRequestCreator());  

Which will register the iso:// prefix with our custom request creator.

More detailed information could be found in this post:

http://blogs.infragistics.com/forums/p/39754/224780.aspx

Create a new Windows Azure Storage Account and a Hosted Service

This sample will use Windows Azure simulator. Details, related with creating a Windows Azure Storage Account you could find in the article Migrating Spatial Data from SQL Server 2008 to SQL Azure

Add a Web Role project in Solution

When use a Windows Azure Emulator just set for Web Role settings for ConnectionString and DataConnectionString: “UseDevelopmentStorage=true”.

Edit settings in ServiceReferences.ClientConfig

   1: <configuration>
   2:     <system.serviceModel>
   3:         <bindings>
   4:             <customBinding>
   5:                 <binding name="CustomBinding_UploadService">
   6:                     <binaryMessageEncoding />
   7:                     <httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
   8:                 </binding>
   9:             </customBinding>
  10:         </bindings>
  11:         <client>
  12:                    
  13:             <endpoint address="http://127.0.0.1:81/UploadService.svc"
  14:                 binding="customBinding" bindingConfiguration="CustomBinding_UploadService"
  15:                 contract="UploadService.UploadService" name="CustomBinding_UploadService" />
  16:  
  17:           <!--<endpoint address="http://localhost:37804/UploadService.svc"
  18:                 binding="customBinding" bindingConfiguration="CustomBinding_UploadService"
  19:                 contract="UploadService.UploadService" name="CustomBinding_UploadService" />-->
  20:         </client>
  21:     </system.serviceModel>
  22: </configuration>

 

Run the demo application

Start the application

Upload files “cntry00.shp”, “cntry00.dbf” and “cntry00.shx” from local directory

Now parts of the shapefile are loaded in the blob storage.

Select each of the files from the blob storage and select “Download” button.
Now all files are saved in the Isolated Storage of the Silverlight application.

Select “Load from Iso” button to load shapefile.
Now data is loaded in the Infragistics XamMap component.

Navigate with the map. Enjoy! You have a working application that use a spatial data from Windows Azure blob storage.