Rakesh Kumar
Rakesh Kumar

Reputation: 3129

Getting error "404 The specified blob does not exist" when downlading blob using Uri

I am trying to download blob using blob url in Service Bus Topic trigger Azure function, but getting below error:

Status: 404 (The specified blob does not exist.)
 ErrorCode: BlobNotFound
Content:
<?xml version="1.0" encoding="utf-8"?><Error><Code>BlobNotFound</Code><Message>The specified blob does not exist.
</Message></Error>

Below is my Startup.cs file:

[assembly: FunctionsStartup(typeof(Startup))]
namespace Emails.Dispatcher
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddSingleton(x =>
            new BlobServiceClient(connectionString: Environment.GetEnvironmentVariable("AzureWebJobsStorage")));

            builder.Services.AddSingleton<IBlobService, BlobService>();

            builder.Services.AddLogging();
            builder.Services.AddHttpClient();
            builder.AddHelpers();
            builder.Services.AddWorkers();

        }
    }
}

BlobService:

public class BlobService : IBlobService
{
    private readonly BlobServiceClient _blobServiceClient;

    public BlobService(BlobServiceClient blobServiceClient)
    {
        this._blobServiceClient = blobServiceClient;
    }

    public async Task<byte[]> DownloadAsync(string containerName, string fileUri)
    {
        var containerClient = _blobServiceClient.GetBlobContainerClient(containerName);

        var blobClient = containerClient.GetBlobClient(fileUri);

        using (var ms = new MemoryStream())
        {
            await blobClient.DownloadStreamingAsync();
            return ms.ToArray();
        }
    }

    public async Task<BlobDto> UploadAsync(string containerName, string filename, string content)
    {
        var containerClient = _blobServiceClient.GetBlobContainerClient(containerName);

        var blobClient = containerClient.GetBlobClient(filename);

        var bytes = Encoding.UTF8.GetBytes(content);

        await using var memoryStream = new MemoryStream(bytes);

        await blobClient.UploadAsync(content);

        return new BlobDto
        {
            Uri = blobClient.Uri,
            Name = blobClient.Name
        };
    }
}

public interface IBlobService
{
    Task<BlobDto> UploadAsync(string containerName, string filename, string content);

    Task<byte[]> DownloadAsync(string containerName, string fileUri);
}

Actually this service is receiving full blob url (i.e. https://{storage-url}.blob.core.windows.net/{container-name}/files/unzip/691ec307-7c2b-4aaa-8f75-8742c9faa9f5/1615015726/{file-name}.pdf).

Am i missing anythigng here?

Upvotes: 2

Views: 8972

Answers (3)

Ayobami Idubor
Ayobami Idubor

Reputation: 1

You likely have unallocated strings in the blob name.

Workaround that works: replace segment number with your file container segment number and use replace to fix the unknown file name character.

CloudBlobDirectory dira = Container.GetDirectoryReference(string.Empty);
var rootDirFolders = dira.ListBlobsSegmentedAsync(true, BlobListingDetails.Metadata, null, null, null, null).Result.Results;
foreach (var blob in rootDirFolders)
{
    var blockBlob = Container.GetBlockBlobReference(blob.StorageUri.PrimaryUri.Segments[2].Replace("%20", " "));
    var blockBlobRecent = blockBlob.Name.Contains(formatdateValue); //filters blobs by date. Standard practice is that each blob has date in the name. Avoid using Modified date as filter
    if (blockBlobRecent)
    {
        string localPath = DownloadPath + blob.StorageUri.PrimaryUri.Segments[2].Replace("%20", " ");
        string localPathfinal = localPath.Replace("%20", " ");
        await blockBlob.DownloadToFileAsync(localPathfinal, FileMode.Create).ConfigureAwait(false);
    }
    else
    {
        //do nothing
    }
}

Upvotes: 0

Rakesh Kumar
Rakesh Kumar

Reputation: 3129

I am able to download blob file with the help of Uri and and Name property of CloudBlockBlob. As shown below:

  public async Task<byte[]> DownloadAsync(string containerName, string fileUri)
        {
            var containerClient = _blobServiceClient.GetBlobContainerClient(containerName);

            var blobUri = new System.Uri(fileUri);

            var name = new CloudBlockBlob(blobUri).Name;

            var blobClient = containerClient.GetBlobClient(name);

            var response = await blobClient.DownloadStreamingAsync();

            using MemoryStream ms = new MemoryStream();

            await response.Value.Content.CopyToAsync(ms);

            ms.Position = 0;

            return ms.ToArray();
        }

Upvotes: 2

Gaurav Mantri
Gaurav Mantri

Reputation: 136226

The issue is with the following line of code:

var blobClient = containerClient.GetBlobClient(fileUri);

When you create a BlobClient using ContainerClient and GetBlobClient, you need to provide just the name of the blob and not the entire URL.

To fix the issue, just pass the blob name.

Upvotes: 1

Related Questions