OutOfMemoryException when returning Azure blob stream as HttpResult

We have the following code for downloading blobs from Azure:

ICloudBlob reference = _container.GetBlobReferenceFromServer(blobName);
Stream stream = return reference.OpenRead();
HttpResult httpResult = new HttpResult(stream, mimeType);

if (asAttachment)
{
    string createdOnString = dbBlob.CreatedOn.ToString("R").Replace(",", "");

    httpResult.Options.Add(HttpHeaders.ContentDisposition, $@"attachment; filename=""{fileName}""; size={stream.Length}; creation-date={createdOnString}; modification-date={createdOnString}; read-date={createdOnString}");
}

return httpResult;

When downloading a large file (1.7 GB), this results in an OutOfMemoryException:

System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
   at ServiceStack.HttpRequestExtensions.ToStatusCode(Exception ex)
   at ServiceStack.ServiceStackHost.HandleUncaughtException(IRequest httpReq, IResponse httpRes, String operationName, Exception ex)
   at ServiceStack.HostContext.RaiseAndHandleUncaughtException(IRequest httpReq, IResponse httpRes, String operationName, Exception ex)
   at ServiceStack.HttpResponseExtensionsInternal.WriteToResponse(IResponse response, Object result, ResponseSerializerDelegate defaultAction, IRequest request, Byte[] bodyPrefix, Byte[] bodySuffix)
   at ServiceStack.HttpResponseExtensionsInternal.WriteToResponse(IResponse httpRes, IRequest httpReq, Object result, Byte[] bodyPrefix, Byte[] bodySuffix)
   at ServiceStack.Host.RestHandler.<>c__DisplayClass5.<ProcessRequestAsync>b__0(Object response)
   at ServiceStack.Host.Handlers.ServiceStackHandlerBase.HandleResponse(Object response, Func`2 callback, Func`2 errorCallback)

What are we doing wrong?

The site is hosted on Azure in an App Service (ASP.NET).

This OutOfMemoryException is generated by ASP.NET since you’re trying to write to the response larger than it can handle. Microsoft provides some guidance on how to troubleshoot ASP.NET OutOfMemory Exceptions on MSDN.

This is an underlying ASP.NET limitation being exceeded and not something which can be fixed within ServiceStack which is just writing directly to the ASP.NET Response Output Stream in 4k chunks. Something you can try is explicitly disable buffering, in ASP.NET if you have Dynamic Compression enabled ASP.NET will buffer the response so you’ll need to disable it with:

<system.webServer>
   <urlCompression doStaticCompression="true" doDynamicCompression="false" />
</system.webServer>

Also you can try explicitly disabling the Response Buffer in a PreRequestFilter in your AppHost with:

this.PreRequestFilters.Add((req, res) => {
    var aspRes = (HttpResponseBase)res.OriginalResponse;
    aspRes.Buffer = false;
    aspRes.BufferOutput = false;
});

Ideally this will prevent ASP.NET from buffering internally and let you write larger responses in ASP.NET.

But I’d be looking at reducing your downloads into more manageable sizes, e.g. if your client supports HTTP partial content and the Azure blob stream is seekable ServiceStack will automatically fulfill Partial Content Requests when you return a stream in a HttpResult, e.g. new HttpResult(stream, mimeType).

Thanks a lot for helping out, even if it wasn’t a ServiceStack problem, @mythz! :slight_smile:

1 Like