使用.NET 4.5异步将Azure blob异步下载到字符串,等待

tal*_*kol 12 c# azure azure-storage-blobs async-await .net-4.5

我正在尝试使用.NET 4.5异步和等待实现完全异步的 blob下载.

让我们假设整个blob可以立即适应内存,我们想把它保存在一个string.

码:

public async Task<string> DownloadTextAsync(ICloudBlob blob)
{
    using (Stream memoryStream = new MemoryStream())
    {
        IAsyncResult asyncResult = blob.BeginDownloadToStream(memoryStream, null, null);
        await Task.Factory.FromAsync(asyncResult, (r) => { blob.EndDownloadToStream(r); });
        memoryStream.Position = 0;

        using (StreamReader streamReader = new StreamReader(memoryStream))
        {
            // is this good enough?
            return streamReader.ReadToEnd();

            // or do we need this?
            return await streamReader.ReadToEndAsync();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

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

string text = await DownloadTextAsync(blockBlob);
Run Code Online (Sandbox Code Playgroud)

这段代码是否正确,这确实是完全异步的?你会以不同的方式实现吗?

我会感谢一些额外的澄清:

  1. GetContainerReference并且GetBlockBlobReference不需要异步,因为他们还没有联系服务器,对吧?

  2. 是否streamReader.ReadToEnd需要异步?

  3. 我有点困惑的是什么BeginDownloadToStream...到时候EndDownloadToStream被调用,我的内存流是否包含所有数据?或者只是预先读取的流?

更新:(从存储2.1.0.0 RC开始)

Async现在支持本机.

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

string text = await blockBlob.DownloadTextAsync();
Run Code Online (Sandbox Code Playgroud)

Ste*_*ary 16

这段代码是否正确,这确实是完全异步的?

是.

你会以不同的方式实现吗?

是.特别是,TaskFactory.FromAsync如果传入Begin/ End方法对而不是传入现有包装,则包装器的效率会更高IAsyncResult.像这样:

await Task.Factory.FromAsync(blob.BeginDownloadToStream,
    blob.EndDownloadToStream, memoryStream, null);
Run Code Online (Sandbox Code Playgroud)

我也喜欢将它们包装成单独的扩展方法,所以我可以像这样调用它:

await blog.DownloadToStreamAsync(memoryStream);
Run Code Online (Sandbox Code Playgroud)

请注意,下一版本的客户端库(2.1,当前在RC中)将具有async-ready方法,即DownloadToStreamAsync.

GetContainerReference和GetBlockBlobReference不需要异步,因为他们还没有联系服务器,对吧?

正确.

streamReader.ReadToEnd是否需要异步?

它不(也不应该).编程Stream有点不寻常async.通常,如果有async方法,那么您应该在async代码中使用它,但该指南不适用于Stream类型.原因是基Stream类不知道它的实现是同步还是异步,所以它假定它是同步的,并且默认情况下只是通过在后台线程上进行同步工作来伪造它的异步操作.真正的异步流(例如NetworkStream)会覆盖它并提供真正的异步操作.同步流(例如MemoryStream)保持此默认行为.

所以,你不要想叫ReadToEndAsyncMemoryStream.

我对BeginDownloadToStream的作用有点困惑..当调用EndDownloadToStream时,我的内存流是否包含所有数据?

是.操作是DownloadToStream; 它,它将blob下载到流中.由于您将blob下载到a中MemoryStream,因此在此操作完成时blob完全在内存中.