Search code examples
uwpazure-storageazure-blob-storageazure-stream-analytics

The specified blob does not exist, using DownloadToStreamAsync


I have a piece of code (in a UWP app) that reads a blob from Azure storage. I can connect, enumerate the container and find the blob, however when I try to download it I get the exception: The specified blob does not exist.

Using the Azure portal, I can browse the container, I see the blob and can even download interactively. I've checked the URL's and they match. I have other blobs in other folders in the same container, the code downloads them fine.

The blob is created automatically via a Stream Analytics job, this is the same way the other blobs were created.

    string csvText = null;

    CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CONNECTION_STRING);
    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
    CloudBlobContainer container = blobClient.GetContainerReference(CONTAINER_NAME);

    OperationContext context = new OperationContext();
    BlobRequestOptions options = new BlobRequestOptions();

    string prefix = string.Format("{0}/{1:yyyy/MM/dd/HH}", ROOT_FOLDER, SAMPLE_DATE); // ex: telemetry/2016/12/31/22
    var blobs = await container.ListBlobsSegmentedAsync(prefix, true, BlobListingDetails.All, null, null, options, context);

    CloudBlockBlob item = blobs.Results.FirstOrDefault() as CloudBlockBlob; //     <<<< I see the blob here.
    using (var memoryStream = new MemoryStream())
    {
        await item.DownloadToStreamAsync(memoryStream); //     <<<< The specified blob does not exist.
        csvText = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
    }

EDIT: Stack Trace:

Source  Microsoft.WindowsAzure.Storage
at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.<ExecuteAsyncInternal>d__c`1.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.WindowsAzure.Storage.Blob.CloudBlob.<>c__DisplayClass11.<<DownloadRangeToStreamAsync>b__10>d__13.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at HomeControl.Views.Historical.<LoadData>d__7.MoveNext()

I tried to get a fiddler trace, but was having trouble using it with a UWP app. Any suggestions on how I can troubleshoot this error?

Thanks

-John


Solution

  • Found it.

    Turns out that by passing BlobListingDetails.All, I was including uncommitted blobs, which in my case included a blob I had deleted earlier. In my post I mentioned the URLs matched, apparently I overlooked the "_2.csv" that was incremented, presumably by the stream job.

    Looking at the actual server request, this adds the following query string:

        &include=snapshots,uncommittedblobs,metadata,copy
    

    I assumed my FirstOrDefault() was picking up the first and only result in that container (with that prefix), but there were 2 blobs, and the first was the original deleted (uncommitted) blob.

    By passing BlobListingDetails.None, this removes the &include query string, and only returns committed blobs.

        var blobs = await container.ListBlobsSegmentedAsync(prefix, true, BlobListingDetails.None, null, null, options, context);
        var item = blobs.Results.OfType<CloudBlockBlob>().FirstOrDefault();
    

    -John

    P.S. I never got Fiddler to run in my UWP, I had to move to a console application to troubleshoot this in Fiddler.