Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Streaming an Azure blob to the client asynchronously with .NET 4.5 async, await

I'm implementing my own async HTTP handler with HttpTaskAsyncHandler and using async & await to keep it fully asynchronous.

I want to stream an azure blob directly to the client. It's true that I can redirect the client to the blob URL and have them download it directly, but let's assume I don't want to do that (my blob is private for example).

This is my current implementation:

Code:

    public async Task<bool> DownloadToStreamAsync(ICloudBlob blob, Stream stream)
    {
        bool blobFound = true; 
        IAsyncResult asyncResult = blob.BeginDownloadToStream(stream, null, null);
        await Task.Factory.FromAsync(asyncResult, (r) =>
        {
            try
            {
                blob.EndDownloadToStream(r);
            }
            catch (StorageException)
            {
                blobFound = false;
            }
        });
        return blobFound;
    }

Usage:

    public override async Task ProcessRequestAsync(HttpContext context)
    {
        CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageAccountConnectionString"));
        CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
        CloudBlobContainer container = blobClient.GetContainerReference("container1");
        CloudBlockBlob blockBlob = container.GetBlockBlobReference("blob1.txt");

        await DownloadToStreamAsync(blockBlob, context.Response.OutputStream);
    }

Is this code indeed fully asynchronous and will free my HTTP server to handle other clients while the streaming takes place? (ie if I had a single server thread)

Is it possible to keep the blobs compressed (GZIP) and have the client deflate them using Content-Encoding: gzip?

Update: (as of Storage 2.1.0.0 RC)

Async now supported natively.

CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageAccountConnectionString"));
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference("container1");
CloudBlockBlob blockBlob = container.GetBlockBlobReference("blob1.txt");

await blockBlob.DownloadToStreamAsync(context.Response.OutputStream);
like image 796
talkol Avatar asked Aug 13 '13 20:08

talkol


1 Answers

Your current solution is asynchronous, and will free up the server request thread. See my answer to your other question for recommendations re TaskFactory.FromAsync.

Is it possible to keep the blobs compressed (GZIP) and have the client deflate them using Content-Encoding: gzip?

I have no idea. That's an interesting question; you may want to post it as a separate question.

like image 81
Stephen Cleary Avatar answered Oct 09 '22 06:10

Stephen Cleary