Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NullReferenceException when returning Blob stream in MVC after updating to Storage 2.1.0.3

I have several Actions in my MVC Controllers that return an Azure blob by passing a blob stream into a FileResult. Like this:

    public FileResult DownloadReport(string Id)
    {
        // Look up model
        string fileName = messenger.ReportTitle(Id);

        // Get a reference to the blob
        CloudBlockBlob mainReportBlob = cloudBlobContainer.GetBlockBlobReference(Id);

        // Return as a FileResult
        using (var reportReader = mainReportBlob.OpenRead())
        {
            return File(reportReader , "application/pdf", fileName );
        }
    }

I recently updated my Azure Storage library to the latest and started receiving the following exceptions:

System.NullReferenceException was unhandled by user code
HResult=-2147467261
Message=Object reference not set to an instance of an object.
Source=Microsoft.WindowsAzure.Storage
StackTrace:
at Microsoft.WindowsAzure.Storage.Blob.BlobReadStreamBase.ConsumeBuffer(Byte[] buffer, Int32 offset, Int32 count) in e:\projects\azure-sdk-for-net\microsoft-azure-api\Services\Storage\Lib\Common\Blob\BlobReadStreamBase.cs:line 222
at Microsoft.WindowsAzure.Storage.Blob.BlobReadStream.Read(Byte[] buffer, Int32 offset, Int32 count) in e:\projects\azure-sdk-for-net\microsoft-azure-api\Services\Storage\Lib\DotNetCommon\Blob\BlobReadStream.cs:line 72
at System.Web.Mvc.FileStreamResult.WriteFile(HttpResponseBase response)
at System.Web.Mvc.FileResult.ExecuteResult(ControllerContext context)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList
1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)

The error seems to be coming from within the Azure libraries themselves. Any ideas?

like image 755
Stevoman Avatar asked Nov 07 '13 18:11

Stevoman


1 Answers

So after stepping thru things with a decompiler, I found the BlobReadStreamBase.Dispose() method was being called before it had been read. Digging further, it seems that returning File() from a controller doesn't actually read the stream, but simply passes it up to the rest of MVC to deal with it.

What this means is that my using() block was closing the Blob stream before MVC could read it further down the pipeline. I changed my Action to this:

    public FileResult DownloadReport(string Id)
    {
        // Look up model
        string fileName = messenger.ReportTitle(Id);

        // Get a reference to the blob
        CloudBlockBlob mainReportBlob = cloudBlobContainer.GetBlockBlobReference(Id);

        // Return as a FileResult, DON'T place in a using() block or it will be closed early
        var reportReader = mainReportBlob.OpenRead();
        return File(reportReader , "application/pdf", fileName );
    }

This works. Furthermore, I set a breakpoint in my decompiler and BlobReadStreamBase.Dispose() is being called later, so presumably MVC is cleaning things up further down the pipeline.

I'm not sure why this worked before, as it shouldn't have. Maybe a bug that was fixed in the Azure libraries?

like image 127
Stevoman Avatar answered Oct 15 '22 10:10

Stevoman