Introduction
Windows® Azure™ Blob storage service is a key and value store of unstructured data that can be accessed from anywhere in the world via HTTP or HTTPS. The term “blob” is commonly understood to mean “Binary Large OBject.” An Azure Storage Account can contain one or more Containers, which are created and named by the user to hold Blobs. It functions like file storage in the cloud. This simple data structure makes blob storage very powerful where files such as images, audios, videos, PDFs, documents, etc. are not only stored very economically but also highly scalable. A single storage account can store hundreds of TBs of blob data. Many of Azure’s customers store hundreds of petabytes. Microsoft SkyDrive – re-launched now as “OneDrive” uses blob storage.
Blob URL format:http://<your-storage-account-name>/blob.core.windows.net/<container-name>/blob-name.
Common uses of Blob storage include:
- Serving images or documents directly to a browser
- Storing files for distributed access
- Streaming video and audio
- Performing secure backup and disaster recovery
- Storing data for analysis by an on-premises or Azure-hosted service
- You can use Blob storage to expose data publicly to the world or privately for internal application storage.
Now I will demonstrate how you can use blob storage for Windows Phone application data.
Scenario
You are going to create a Windows Phone application that can save user profile information in Azure SQL Database and Blob Storage. The user profile contains a picture, which will be stored as a blob.
Prerequisites
1. Windows Account to access Windows Azure (Free)
2. Windows Azure account (At least Free Trial version)
3. Visual Studio 2013
4. Windows 8 system or VM
5. Windows Phone 8 SDK
Sample Application for This Illustration
This application will consume Mobile Services as the backend. For this demo, I have created a sample app called “ProfileManager”. You can use this app as starting point for this illustration. You can download it from here: https://github.com/manoj-kumar1/Azure-MobSvc-As-Backend-For-SQL-DB
The Profile Manger app has the following screens to create and view user’s profiles.
Profiler Manager App Screens
Create an Azure Storage Account
You need to have a Windows Azure storage account to consume table storage service. Follow these steps to create one:
1. Login to https://manage.windowsazure.com/.
2. Select +NEW.
3. Select “Quick Create” in the following menu:
Select Quick Create
4. Specify a unique name, location and replication for your storage. Replication means – Azure constantly maintains healthy replicas of your data, but it comes at an added cost. So if you do not want your data geo-replicated, you can disable geo-replication. This is called Locally Redundant Storage, and is a 23% to 34% discounted price over geo-replicated storage.
5. Click “CREATE STORAGE ACCOUNT” to finish creating your Azure Storage account.
Create Mobile Service in Azure
You will need a mobile service to access Table storage. You can create a mobile service in Windows Azure by following these steps:
1. Login to https://manage.windowsazure.com/.
2. Select “+New” at bottom.
3. From the menu, select mobile service –> Create.
4. Give a proper name to the mobile service and select a new or existing database instance:
Create a Mobile Service
5. Mobile service uses Azure SQL Database, so when you create a mobile service a new database will be created. You can create a new database or use any existing one. In this demo, I am going to create a new database along with its server.
Specify Database Settings
6. In this way a new mobile service with the name “ProfileMobileSvc” will be created.
7. Create the required tables in this new “ProfileMobileSvc_Db” database: Open mobile service “ProfileMobileSvc”, go to Data tab, and select “Add a table” to add “UserProfile” as new table. Add columns: Name, Email, Phone, PictureBlobContainerName, PictureName, PictureBlobUrl, SasQueryString.
Use Server Scripts to Alter the Behavior of “UserProfile” Table Insert
You can register “Server Scripts” in a Mobile Service to perform many operations on data being inserted and updated, including validation and data modification. Create a blob container and blob URL stored in Azure SQL database table column.
You can follow these steps to modify insert and read behavior:
1. Go to newly created “ProfileMobileSvc”.
2. Click on “Data” tab and open “UserProfile” table.
3. For this illustration, you need to customize the default insert behavior by using following scripts:
Insert:
var azure = require('azure'); var qs = require('querystring'); function insert(item, user, request) { var accountName = '<your_storage_account_name>'; var accountKey = '<your_storage_account_key>'; var host = accountName + '.blob.core.windows.net'; var containerName = item.PictureBlobContainerName.toLowerCase(); var pictureRelativePath = '/' + containerName + '/' + item.PictureName.toLowerCase(); //Create the container if it does not exist, Use public read access for the blobs, and the SAS to upload var blobService = azure.createBlobService(accountName, accountKey, host); blobService.createContainerIfNotExists(containerName, { publicAccessLevel: 'blob' }, function (error) { if (!error) { var sharedAccessPolicy = { AccessPolicy: { Permissions: azure.Constants.BlobConstants.SharedAccessPermissions.WRITE, // Start: use for start time in future, beware of server time skew Expiry: formatDate(new Date(new Date().getTime() + 5 * 60 * 1000)) // 5 minutes from now } }; var sasQueryString = getSAS(accountName, accountKey, blobRelativePath, azure.Constants.BlobConstants.ResourceTypes.BLOB, sharedAccessPolicy); // Create the blobs urls with the SAS item.sasQueryString = sasQueryString; item.picturebloburl = 'https://' + host + blobRelativePath + '?' + sasQueryString; } else { console.error(error); } request.execute(); }); } function getSAS(accountName, accountKey, path, resourceType, sharedAccessPolicy) { return qs.encode(new azure.SharedAccessSignature(accountName, accountKey) .generateSignedQueryString(path, {}, resourceType, sharedAccessPolicy)); } function formatDate(date) { var raw = date.toJSON(); // Blob service does not like milliseconds on the end of the time so strip return raw.substr(0, raw.lastIndexOf('.')) + 'Z'; }
This insert script performs the following actions:
- Creates the blob container if it doesn’t exist.
- Creates the shared policies.
- Creates SAS Query String and blob URL, and assign this to item.
Modify Phone Application to Save Data in Blob Storage
Now you can update the “ProfileManager” Windows Phone application, so that the user profile picture can be saved as blob storage in Azure. If you have not already downloaded this sample app, you can download it from: https://github.com/manoj-kumar1/Azure-MobSvc-As-Backend-For-SQL-DB
You can follow these steps to store the picture into the Azure blob storage:
1. Open “ProfileManagerSoln.sln” from “FinalProfileManagerSoln” folder downloaded from above github location.
2. Setup the correct Mobile Service name and key in the App in App.xaml.cs:
Key is from newly created Azure Mobile Service “ProfileMobileSvc” (Details for existing app):
public static MobileServiceClient MobileService = new MobileServiceClient( "https://profilemobilesvc.azure-mobile.net/", "<xxxxxxxxxxxxxxxxxxxxxxxxxx>"); //Put name and key of your mobile service
3. Modify the model class UserProfileunder Model folder in the project: This class represents columns needed for saving the table in Azure table storage.
using Newtonsoft.Json; using System; namespace ProfileManager.Model { public class UserProfile { [JsonProperty(PropertyName = "id")] public string Id { get; set; } [JsonProperty(PropertyName="name")] public string Name { get; set; } [JsonProperty(PropertyName = "email")] public string Email { get; set; } [JsonProperty(PropertyName = "phone")] public string Phone { get; set; } [JsonProperty(PropertyName = "PictureBlobContainerName")] public string PictureBlobContainerName { get; set; } [JsonProperty(PropertyName = "PictureName")] public string PictureName { get; set; } [JsonProperty(PropertyName = "picturebloburl")] public string PictureBlobUrl { get; set; } [JsonProperty(PropertyName = "sasQueryString")] public string SasQueryString { get; set; } } }
4. Add Nuget package “WindowsAzure” by opening package console.
Run command: Install-Package WindowsAzure.Storage-Preview -Pre
5. Update EditPage.xaml to add a field for the photo:
<Grid x:Name="LayoutRoot" Background="Transparent" d:DataContext="{Binding Items[0]}"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <!--TitlePanel contains the name of the application and page title--> <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> <TextBlock Text="Update Profile" Style="{StaticResource PhoneTextLargeStyle}"/> <TextBlock Text="Name" Margin="9,30,0,0" Style="{StaticResource PhoneTextNormalStyle}"/> <TextBox x:Name="txtName" Text="{Binding Name}"></TextBox> </StackPanel> <!--ContentPanel contains details text. Place additional content here--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <TextBlock Text="Phone" Margin="9,0,0,0" Style="{StaticResource PhoneTextNormalStyle}"/> <TextBox x:Name="txtPhone" Text="{Binding Phone}" Margin="0,30,0,0" ></TextBox> </Grid> <Grid x:Name="ContentPanel2" Grid.Row="2" Margin="12,30,12,0"> <TextBlock Text="Email" Margin="9,0,0,0" Style="{StaticResource PhoneTextNormalStyle}"/> <TextBox x:Name="txtEmail" Text="{Binding Email}" Margin="0,30,0,0" ></TextBox> </Grid> <Grid x:Name="ContentPanel3" Grid.Row="3" Margin="12,30,12,0"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"></ColumnDefinition> <ColumnDefinition Width="150"></ColumnDefinition> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> </Grid.RowDefinitions> <TextBlock TextWrapping="Wrap" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left">Profile Picture</TextBlock> <Image x:Name="profileImg" Grid.Column="1" Grid.Row="0" Grid.RowSpan="2" Height="120" Width="180" ></Image> <Button x:Name="BtnPickPhoto" Grid.Column="0" Grid.Row="1" Width="180" Content="Pick photo" Click="BtnPickPhoto_Click"/> </Grid> </Grid> <Grid x:Name="ContentPanel4" Grid.Row="4" Margin="12,20,12,0"> <Button x:Name="saveBtn" Click="saveBtn_Click" Width="200" HorizontalAlignment="Center">Save</Button> </Grid> </Grid>
6. Update EditPage.xaml.cs to add a photo chooser task for selecting a photo as profile pic:
Add fields:
PhotoChooserTask photoChooserTask; Stream currentPicture;
In constructor:
photoChooserTask = new PhotoChooserTask(); photoChooserTask.Completed += new EventHandler<PhotoResult>(photoChooserTask_Completed);
Handler:
private void photoChooserTask_Completed(object sender, PhotoResult e) { if (e.TaskResult == TaskResult.OK) { //Code to display the photo on the page in an image control named myImage. System.Windows.Media.Imaging.BitmapImage bmp = new System.Windows.Media.Imaging.BitmapImage(); currentPicture = e.ChosenPhoto; bmp.SetSource(currentPicture); profileImg.Source = bmp; } }
7. Update the saveBtn_Clickmethod in EditPage.xaml.cs as follow:
var profile = new UserProfile() { Name = txtName.Text, Phone = txtPhone.Text, Email = txtEmail.Text, PictureBlobContainerName = "profilePic", PictureName = txtName.Text.Replace(" ", "") }; await userProfileTbl.InsertAsync(profile); // If we have a returned SAS, then upload the blob. if (!string.IsNullOrEmpty(profile.SasQueryString)) { StorageCredentials cred = new StorageCredentials(profile.SasQueryString); var imageUri = new Uri(profile.PictureBlobUrl); CloudBlobContainer container = new CloudBlobContainer( new Uri(string.Format("https://{0}/{1}", imageUri.Host, profile.PictureBlobContainerName)), cred); //Upload picture CloudBlockBlob blobFromSASCredential = container.GetBlockBlobReference(profile.PictureName); await blobFromSASCredential.UploadFromStreamAsync(currentPicture); currentPicture.Close(); currentPicture = null; App.ViewModel.LoadData(); } NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
8.Build and run the application.
9.Click “Add User” and add a new user profile.
10. Select photo from photo gallery.
11. Click save; it will save the user profile and store the blob into the blob container.
12. Verify the blob URL in the Azure SQL table.
Conclusion
In this illustration, I have explained how you can leverage “Azure Mobile Services” to store blob data of Windows Phone 8 applications in Azure blob Storage. You can use this technique to store large amounts of unstructured blob data in Azure, which is readily accessible and more economical.