Download blob using Azure Blob storage client library v12 for .NET
Asked Answered
E

4

7

I am using Azure.Storage.Blobs version=12.4.1. I have a REST endpoint that I want to use to download blobs from a storage account.

I need to stream the result to a HttpResponseMessage and I do not want to use a MemoryStream. I want to stream the result directly to the calling client. Is there a way to achieve this. How to get the downloaded blob in the HttpResponseMessage content? I do not want to use MemoryStream, since there will be a lot of download requests.

The BlobClient class has a method DownloadToAsync but it requires a Stream as a parameter.

        var result = new HttpResponseMessage(HttpStatusCode.OK);

        var blobClient = container.GetBlobClient(blobPath);
        if (await blobClient.ExistsAsync())
        {
            var blobProperties = await blobClient.GetPropertiesAsync();

            var fileFromStorage = new BlobResponse()
            {                    
                ContentType = blobProperties.Value.ContentType,
                ContentMd5 = blobProperties.Value.ContentHash.ToString(),
                Status = Status.Ok,
                StatusText = "File retrieved from blob"
            };

            await blobClient.DownloadToAsync(/*what to put here*/);
            return fileFromStorage;
        }
Edholm answered 7/5, 2020 at 8:39 Comment(1)
I am currently using Azure.Storage.Blobs v12.11.0 and BlobClient has OpenRead and OpenReadAsync methods, which you can use. Also, your code is using methods like CreateCloudBlobClient, which is for Legacy Azure SDK for .NET. I'll provide a more updated solution in case it is helpful for anyone using the latest Azure SDK for .NET and a later version of Azure.Storage.Blobs v12.Ghee
A
12

You could simply create a new memory stream and download the blob's content to that stream.

Something like:

        var connectionString = "UseDevelopmentStorage=true";
        var blobClient = new BlockBlobClient(connectionString, "test", "test.txt");
        var ms = new MemoryStream();
        await blobClient.DownloadToAsync(ms);

ms will have the blob's contents. Don't forget to reset memory stream's position to 0 before using it.

Arlinearlington answered 7/5, 2020 at 9:12 Comment(7)
I want to avoid using MemoryStream, I do not want to have the blob content in memoryEdholm
It's not very clear what exactly do you want. This method needs a stream. If memory stream is not an option then you may want to save to a file?Arlinearlington
Other options would be to use DownloadAsync method which returns a BlobDownloadInfo. You can pass that object to the client directly.Arlinearlington
What is the v12 replacement for DownloadTextAsync? That was such a useful method to load templates stored in blob storage.Corrinnecorrival
Hi, @dinotom, have you found the DownloadTextAsync replacement?Ahmednagar
I understood, the right replacement is to use the DownloadToAsync method where we got the MemoryStream and then can create a StreamReader based on the memory stream and utilize the ReadToEndAsync method.Ahmednagar
This is an outdated solution that works for Legacy Azure SDK for .NET, but not the latest Azure SDK for .NET using Azure.Storage.Blobs v12.11.0 for example.Ghee
H
1

You need to use

 BlobDownloadInfo download = await blobClient.DownloadAsync();

download.Content is blob Stream. You can use it to copy directly to other stream.

using (var fileStream = File.OpenWrite(@"C:\data\blob.bin"))
{
    await download.CopyToAsync(fileStream);
}
Huihuie answered 31/7, 2020 at 14:47 Comment(1)
I think this is no longer an option: learn.microsoft.com/en-us/dotnet/api/…Newsreel
G
0

To download a blob using Azure.Storage.Blobs v12.11.0, we can use OpenReadAsync or OpenRead

string connectionString = Environment.GetEnvironmentVariable("AZURE_STORAGE_CONNECTION_STRING")!;
var serviceClient = new BlobServiceClient(connectionString);
var container = serviceClient.GetBlobContainerClient("myblobcontainername");

string blobName; // the name of the blob
var client = container.GetBlobClient(HttpUtility.UrlDecode(blobName));
var properties = (await client.GetPropertiesAsync()).Value;
Response.Headers.Add("Content-Disposition", $"attachment; filename={Path.GetFileName(client.Name)}");
Response.Headers.Add("Content-Length", $"{properties.ContentLength}");
return File(await client.OpenReadAsync(), properties.ContentType);
Ghee answered 29/4, 2022 at 16:15 Comment(0)
T
-1

Try to use the code as below to download blob into HttpResponseMessage.

try
{
    var storageAccount = CloudStorageAccount.Parse("{connection string}");
    var blobClient = storageAccount.CreateCloudBlobClient();
    var Blob = await blobClient.GetBlobReferenceFromServerAsync(new Uri("https://{storageaccount}.blob.core.windows.net/{mycontainer}/{blobname.txt}"));
    var isExist = await Blob.ExistsAsync();
    if (!isExist) {
        return Request.CreateErrorResponse(HttpStatusCode.NotFound, "file not found");
    }
    HttpResponseMessage message = new HttpResponseMessage(HttpStatusCode.OK);
    Stream blobStream = await Blob.OpenReadAsync();
    message.Content = new StreamContent(blobStream);
    message.Content.Headers.ContentLength = Blob.Properties.Length;
    message.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(Blob.Properties.ContentType);
    message.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
    {
        FileName = "{blobname.txt}",
        Size = Blob.Properties.Length
    };
    return message;
}
catch (Exception ex)
{
    return new HttpResponseMessage
    {
        StatusCode = HttpStatusCode.InternalServerError,
        Content = new StringContent(ex.Message)
    };
}
Tolman answered 7/5, 2020 at 9:5 Comment(3)
This is what I used to have, but now I need to use Azure.Storage.Blobs version=12.4.1 and BlobClient that does not have OpenReadAsyncEdholm
Same problem. It would be nice if this reflected the latest Azure.Storage.Blogs library which is at v12.Separates
Azure.Storage.Blobs v12.11.0 has OpenReadAsync or OpenRead so it looks like Microsoft brought it backGhee

© 2022 - 2024 — McMap. All rights reserved.