During our work on Firstonsite we needed a good way to let the user upload video to the site. Firstonsite is hosted on Windows Azure, Microsofts cloud platform, and the uploaded file are to be stored in the Windows Azure Blob Storage.
ProblemFirstonsites goal is to be a marketplace for news media, allowing anyone to upload images and video of interesting events and offer it news desks for sale. To be able to handle large amounts of media files from many concurrent users we wanted to leverage the power of Windows Azure and its Blob Storage to allow the users to upload directly into our blob storage without first having to pass through our web back-end. This allow us to avoid a bottleneck when several users wants to upload large files and remove the need for creating several web roles just for this purpose.
SolutionWhen we first tried to implement this solution we ran into an unexpected problem, Blob Storage does not have CORS support (yet). We decided to push the feature until CORS was supported but recently I found a very interesting blog by Gaurav Mantri with a solution to the problem. The workaround is to place the code for the file upload on the Blob Storage thus removing the need for cross domain access.
Example codeI have created an example site implementing Mantri’s solution using a controller to create a Shared Access Signature and sending this to the static HTML page on the Blob Storage. In order to prevent people from draining my Azure account dry I used the MVC 4 Simple Membership provider template to add login to the page.
The upload controller creates the SAS and adds it as a query parameter to the address of the static site. To avoid Blob Storage parsing the parameter (assuming that it is a SAS used to access the requested HTML file) the string is base 64 encoded first. The upload.js script running at the Blob Storage extracts the sas query parameter using purl.js and decodes the string to get the URI for the file to be uploaded to.
The user can select a file and when the Upload File button is pressed a FileReader starts reading slices of that file. Each slice is uploaded to the Blob Storage together with a six digit block id. This Id is later used to combine the slices at the Blob Storage.
If an error occurs the code will retry the transmission of the current slice several times before failing the file upload. This takes care of occasional glitches that can occur normally. After all slices have been uploaded a list of all slices and their order are sent as a block list and the file transfer will be complete.
All code can be found at https://github.com/MartinWa/BlobUploader
How to test itThe easiest way to test this is to clone the code from GitHub to a local folder (using git), open the solution file in Visual Sudio 2012 (with the Azure SDK), start the storage emulator and run the debugger.
The contents of the blobstorageFiles folder must be stored on the development Blob Storage in a container named public (with public access rights). Note that the content type of the HTML file must be set to text/html. I do all this using the Azure Storage Explorer tool. If you have done everything correct you should be able to browse tohttp://127.0.0.1:10000/devstoreaccount1/public/upload.html.
In order to be able to access the Upload tab you must create a uploader entry in the webpages_Roles table and then set that role to your user in webpages_UsersInRoles.
Deploy your ownIf you like to deploy to your own Windows Azure Web Site clone the repository to your own GitHub account.
Create a new Azure Web Site using the custom create wizard
Now the management portal will deploy the main branch of the repository to the Web Site. It will also deploy any changes you push to main giving you an instant continuous deployment. Since we need file storage we also need to create a storage account
Now all that remains is to set the database connection and the storage account. Go to configure on the Web Site and add an app setting:
[text]StorageConnection : DefaultEndpointsProtocol=https;AccountName=xxx;AccountKey=***[/text]
replacing the account name with the name of your storage account and *** with the primary access key. Then rename the DefaultConnectionconnection string to DatabaseConnection
The site should now be up. As in the local case you need to add roles and copy the static HTML page to the Blob Storage (set up the account in the Windows Azure explorer).
See my site at http://blobupload.azurewebsites.net/
Future improvementsThe file upload should be done in parallel to improve upload speed..