Skip to content

Instantly share code, notes, and snippets.

@chgeuer
Last active August 11, 2024 11:08
Show Gist options
  • Save chgeuer/d30a9284c772b918cea1 to your computer and use it in GitHub Desktop.
Save chgeuer/d30a9284c772b918cea1 to your computer and use it in GitHub Desktop.
Azure Blob Storage from Androind and iOS

Generate an SAS from CSharp

Now full sample at https://github.com/chgeuer/UploadProfilePicture

An ad-hoc signature

An ad-hoc signature is one which is purely time-based, i.e. it cannot be valid for longer than an hour (to prevent yourself from creating a vulnarability).

public async Task<string> Get(string container, string filename)
{
    var connectionString = ConfigurationManager.AppSettings["storageAccount"];
    var account = CloudStorageAccount.Parse(connectionString);
    var blobClient = account.CreateCloudBlobClient();
    var blobContainer = blobClient.GetContainerReference(container);
    await blobContainer.CreateIfNotExistsAsync();

    var blob = blobContainer.GetBlockBlobReference(filename);
    if (await blob.ExistsAsync())
    {
        throw new NotSupportedException("Blob exists");
    }

    var sas = blob.GetSharedAccessSignature(new SharedAccessBlobPolicy()
    {
        Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read,
        SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-5),//SAS Start time is back by 5 minutes to take clock skewness into consideration
        SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(15),
    });

    var uri = string.Concat(blob.Uri.AbsoluteUri, sas);

    return uri;
}

Uploading large (> 4MB) bits

Simply speaking, you must upload in chunks (each not greater than 4MB). Each chunk (block) is uploaded through the blockBlob.PutBlockAsync() method, and each block has a unique blockID. When all blocks are successfully uploaded, you call blockBlob.PutBlockListAsync(blockIdList) to instruct Azure Storage to 'assemble' the final large blob.

Java to use an SAS

public static void MyUploadBlob(String containerName, String containerSAS, CloudBlobClient blobClient)
     throws URISyntaxException, StorageException, FileNotFoundException, IOException
{

    String blobName = "image1.jpg";  // Name as it will appear in blob storage.
    String localFileName = "c:\\myimages\\image1.jpg";  // Path and name of the local file.

    // Append the container name, blob name, and
    // shared access signature to the URI.
    URI uri = new URI(blobClient.getEndpoint().toString() + "/" +
                      containerName + "/" + 
                      blobName + 
                      "?" + 
                      containerSAS);

    // Create a blob using the URI that contains the shared access signature.
    CloudBlockBlob sasBlob = new CloudBlockBlob(uri, blobClient);
    
    // Get a file reference to the local file.
    File fileReference = new File (localFileName);
    
    // Upload the file to the blob.
    sasBlob.upload(new FileInputStream(fileReference), fileReference.length());
}

iOS

Didn't find the Objective-C code, probably in here somewhere: https://github.com/WindowsAzure-Samples/iOS-MobileServices-Storage/tree/master/source/end/StorageDemo

Upload via C# SDK

using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using System;
using System.Configuration;
using System.Text;
using System.Threading.Tasks;

public async Task<string> GetFromServerAsync(string container, string filename)
{
    var connectionString = ConfigurationManager.AppSettings["storageAccount"];
    var account = CloudStorageAccount.Parse(connectionString);
    var blobClient = account.CreateCloudBlobClient();
    var blobContainer = blobClient.GetContainerReference(container);
    await blobContainer.CreateIfNotExistsAsync();
    blobContainer.SetPermissions(new BlobContainerPermissions() { PublicAccess = BlobContainerPublicAccessType.Blob });

    var blob = blobContainer.GetBlockBlobReference(filename);

    var sas = blob.GetSharedAccessSignature(new SharedAccessBlobPolicy()
    {
        Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.Delete,
        SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-5),//SAS Start time is back by 5 minutes to take clock skewness into consideration
        SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(15),
    });

    var uri = string.Concat(blob.Uri.AbsoluteUri, sas);

    return uri;
}

public void UploadPicAsync()
{
    byte[] bytes = Encoding.UTF8.GetBytes("Some text to upload4");

    var uri = GetFromServerAsync("profilepics", "1.jpg").Result;
    var blob = new CloudBlockBlob(new Uri(uri));

    blob.UploadFromByteArray(bytes, 0, bytes.Length);

    Console.WriteLine("Upload succeeded to {0}", uri);
}

static void Main(string[] args)
{
    new Program().UploadPicAsync();
}

Traces

https://chgeuerams2.blob.core.windows.net/profilepics/1.jpg?sv=2014-02-14&sr=b&sig=gXP8rv3lxF9sjwSvA1xlLzj7W%2F0vxXklMoyFRWhDwVU%3D&st=2014-12-09T09%3A50%3A27Z&se=2014-12-09T10%3A10%3A27Z&sp=rwd
https://chgeuerams2.blob.core.windows.net/profilepics/1.jpg?st=2014-12-09T09%3A50%3A27Z&se=2014-12-09T10%3A10%3A27Z&sp=rwd&sr=b&sv=2014-02-14&sig=gXP8rv3lxF9sjwSvA1xlLzj7W%2F0vxXklMoyFRWhDwVU%3D
https://chgeuerams2.blob.core.windows.net/profilepics/1.jpg?st=2014-12-09T09%3A50%3A27Z&se=2014-12-09T10%3A10%3A27Z&sp=rwd&sr=b&sv=2014-02-14&sig=gXP8rv3lxF9sjwSvA1xlLzj7W%2F0vxXklMoyFRWhDwVU%3D&api-version=2014-02-14&


PUT https://chgeuerams2.blob.core.windows.net/profilepics/1.jpg?st=2014-12-09T09%3A50%3A27Z&se=2014-12-09T10%3A10%3A27Z&sp=rwd&sr=b&sv=2014-02-14&sig=gXP8rv3lxF9sjwSvA1xlLzj7W%2F0vxXklMoyFRWhDwVU%3D&api-version=2014-02-14& HTTP/1.1
Host: chgeuerams2.blob.core.windows.net
Content-MD5: d0diP2gZOtu9koivIArSlw==
Content-Length: 20
x-ms-version: 2014-02-14
x-ms-blob-type: BlockBlob
x-ms-client-request-id: 6883f3c5-4284-4e3e-92df-7d29ae28cd2f
User-Agent: WA-Storage/4.3.0 (.NET CLR 4.0.30319.0; Win32NT 6.2.9200.0)

Some text to upload4

HTTP/1.1 201 Created
Transfer-Encoding: chunked
Content-MD5: d0diP2gZOtu9koivIArSlw==
Last-Modified: Tue, 09 Dec 2014 09:55:26 GMT
ETag: "0x8D1E1AD645D4C62"
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
Date: Tue, 09 Dec 2014 09:55:27 GMT
x-ms-request-id: f31e9b1e-0001-0039-5ea5-053522000000
x-ms-version: 2014-02-14

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment