0

I currently have an asp page which uses an asp control to upload files to azure. The control runs server side code which reads the file into azure local storage and then transfers the file from local storage to blob storage. This works fine. However, I would like to replace the asp control with an html control so that, in the longer term, I can run the page offline as an html page (I realise I will have to adapt the file upload again for it to work offline but as a first step I want to remove any server side controls).

I found the blog posts:

http://coderead.wordpress.com/2012/11/21/uploading-files-directly-to-blob-storage-from-the-browser/

http://gauravmantri.com/2013/02/16/uploading-large-files-in-windows-azure-blob-storage-using-shared-access-signature-html-and-javascript/

I tried uploading my file directly to blob storage as shown in these posts but ran into the problem outlined by Gaurav in answer to a previous question I posted ('Upload an image file to azure blob storage from js'). That is, that this technique only works if my page is also held in blob storage. My page is part of an azure cloud service and I'm not sure how I could integrate a page held in blob storage into my cloud service. How would this work when I want to publish my package to azure?

The other way I tried to solve this problem was to upload my file from html to azure local storage and then call a web service to transfer the file from local storage to blob storage (much as I had done for the asp solution). However, I couldn't work out how to get hold of the file in js and transfer it to azure local storage (I'm pretty new to js).

So, apologies if this is really more than one question i.e.: How can I integrate a page held in blob storage into a cloud service? OR How can I use js and html to transfer a file to azure local storage? OR Is there another way of doing this entirely?

If anyone can help me with any of these questions I would be really grateful.

Rachel Edge
  • 351
  • 2
  • 6
  • 18

2 Answers2

1

If your concern is how to host the HTML page for uploading in blob storage and refer that in a web page running inside your cloud service, you could simply include that in an iframe in your web page. So it would be something like:

<HTML>
<HEAD>
</HEAD>
<BODY>
.... some html for your web page ...
<iframe src="https://yourstorageaccount.blob.core.windows.net/yourcontainer/youruploadhtml.html">
</iframe>
.... some more html for your web page ...
</BODY>
</HTML>

Now you mentioned in your previous post that you're generating SAS URL on the server side in your web page. Since you would be creating these SAS URLs dynamically, you would need to pass this SAS URL as querystring to your HTML and then read/parse that querystring when the HTML page loads. You may find this blog post useful for that: http://jquery-howto.blogspot.in/2009/09/get-url-parameters-values-with-jquery.html.

Gaurav Mantri
  • 128,066
  • 12
  • 206
  • 241
  • OK, thanks. I'll try that out and mark this as answered if it all works out. – Rachel Edge Jul 30 '13 at 14:24
  • I've now tried this and have the following problems: 1. I tried to pass the sas url in as a query string but when the main page loaded it tried to evaluate this as a query string for the html page in the iframe and this gave errors. 2. I need to update my database at the same time as uploading the file. To do this I need to access the values of other controls on the page and I can't work out how to do this from within the iframe. 3. I would like to access a web service from within the iframe and am not sure how to do this. Sorry to keep coming back to you; I can usually solve things myself. – Rachel Edge Jul 30 '13 at 16:59
  • Regarding your comments: 1. Can you share the code? Also please tell us the error you're getting. 2. I think HTML page route will not work for you if you need to perform some database updates and stuff. I would suggest that you use regular asp.net uploader to upload the file on the web server (as we used to do in earlier days and once the file is uploaded, you write that file to blob storage). Try these: https://github.com/WindowsAzure-TrainingKit/HOL-ExploringStorage-VS2012 or http://code.msdn.microsoft.com/windowsazure/Windows-Azure-AddressBook-026fcbbb. This should give you enough idea. – Gaurav Mantri Jul 31 '13 at 14:54
0

I have now found a solution that works for this problem. My upload now works as follows:

  • I read the file as a DataURL into a FileReader

  • I slice the returned string up and send each slice up to the server where it is stored in a session variable

  • Once the whole file has been sent up I call another web service which glues the slices back together and turns the result into a byte array

  • The byte array is then stored as a file in local storage in azure

  • Finally the file is transferred from local storage into blob storage

It’s probably not the best way to do it, but it seems to work (in browsers that support html5). If anyone has suggestions for improvements, please let me know. I had to play around with the maxSliceSize to get it to work and the largest that I could get it to was 256 * 32.

Thanks to:

http://gauravmantri.com/2013/02/16/uploading-large-files-in-windows-azure-blob-storage-using-shared-access-signature-html-and-javascript/

How to convert image to byte array using javascript only to store image on sql server?

http://www.west-wind.com/weblog/posts/2009/Sep/15/Making-jQuery-calls-to-WCFASMX-with-a-ServiceProxy-Client

Code as follows (I've cut out bits of code that were only relevant to my project so hope what's left makes sense):

var reader;
var filename;
var sContainer;
var maxSliceSize = 256 * 32;
var selectedFile = null;
var sliceIds = new Array();
var upFile;

function handleFileUpload(cnt, sType) {
    var files = cnt.files; // FileList object
    selectedFile = files[0];

    //----------------------------CHECKS---------------------------
    //Check whether there is a file to upload
    if (files.length === 0) { return; }

    // Check for the various File API support.
    if (window.File && window.FileReader && window.FileList && window.Blob) {
        // Great success! All the File APIs are supported.
    } else {
        alert('The File APIs are not fully supported in this browser.');
        return;
    }

    //test whether this is an image file
    rFilter = /^(?:image\/bmp|image\/cis\-cod|image\/gif|image\/ief|image\/jpeg|image\/jpeg|image\/jpeg|image\/pipeg|image\/png|image\/svg\+xml|image\/tiff|image\/x\-cmu\-raster|image\/x\-cmx|image\/x\-icon|image\/x\-portable\-anymap|image\/x\-portable\-bitmap|image\/x\-portable\-graymap|image\/x\-portable\-pixmap|image\/x\-rgb|image\/x\-xbitmap|image\/x\-xpixmap|image\/x\-xwindowdump)$/i;
    if (!rFilter.test(selectedFile.type)) { alert("You must select a valid image file!"); return; }

    //----------------------------UPLOAD---------------------------
    //Create a name for the blob
    filename = selectedFile.name.toLowerCase();
    sContainer = "images"

    //Upload the file
    reader = new FileReader();

    reader.onloadend = function (evt) {
        if (evt.target.readyState == FileReader.DONE) { // DONE == 2
            //Initialise variables
            maxSliceSize = 256 * 32;
            upFile = evt.target.result
            sliceIds = new Array();

            uploadFileInSlices();
        }
    }

    reader.readAsDataURL(selectedFile);
}

function pad(number, length) {
    var str = '' + number;
    while (str.length < length) {
        str = '0' + str;
    }
    return str;
}

function uploadFileInSlices() {
    if (upFile != "") {
        var sliceId = pad(sliceIds.length, 6);
        console.log("slice id = " + sliceId);
        sliceIds.push(sliceId);
        //Send the first slice off to the server and remove it from the file string
        var upSlice = upFile.substring(0, maxSliceSize);
        upFile = upFile.substring(maxSliceSize);

        var params = {
            filename: filename,
            sliceID: sliceId,
            upSlice: upSlice
        };
        proxy.invoke("UploadImageSlice", params, uploadFileInSlices, onProxyFailure, true);
    } else {
        commitSliceList();
    }
}

function commitSliceList() {
    var jsonData = []; //declare object
    for (var i = 0; i < sliceIds.length; i++) {
        jsonData.push({ SliceName: sliceIds[i] });
    }
    console.log(jsonData);
    var params = {
        filename: filename,
        sliceList: jsonData,
        upFileType: selectedFile.type,
        sContainer: sContainer
    };
    proxy.invoke("UploadImage", params, onSuccess, onProxyFailure, true);
}

Web services (these aren’t complete but should give the basic idea):

<OperationContract()>
Public Function UploadImageSlice(ByVal blobFileName As String, ByVal sliceID As String, ByVal upSlice As String, iInspection As Integer) As Boolean

    HttpContext.Current.Session(blobFileName & sliceID) = upSlice

    Return true

End Function

<OperationContract()>
Public Function UploadImage(ByVal blobFileName As String,ByVal sliceList As List(Of SliceList), upFileType As String, ByVal sContainer As String) As Boolean

    'Find the root path for local storage
    Dim sRoot As String = ""
    Dim myReportsStorage As LocalResource = RoleEnvironment.GetLocalResource("myReports")
    sRoot = myReportsStorage.RootPath

    'Check whether the file already exists in local storage
    If My.Computer.FileSystem.FileExists(sRoot & blobFileName) Then
        My.Computer.FileSystem.DeleteFile(sRoot & blobFileName)
    End If

    ‘GlueUploadSlices pulls strings out of session variables and sticks them together
    Dim upFile As String = GlueUploadSlices(blobFileName, sliceList)
    Dim upFileByte As [Byte]() = New [Byte](upFile.Length - 1) {}
    'FixBase64ForImage extracts the appropriate string from upFile
    upFileByte = Convert.FromBase64String(FixBase64ForImage(upFile))

    Using fs As FileStream = File.OpenWrite(sRoot & blobFileName)
        fs.Write(upFileByte, 0, upFileByte.Length)
        fs.Close()
    End Using

    'Save file to local storage
    StoreBlob(sContainer, sRoot, blobFileName)

    Return true

End Function
Community
  • 1
  • 1
Rachel Edge
  • 351
  • 2
  • 6
  • 18