Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FileStreamResult: ObjectDisposedException: Cannot access a disposed object. #336

Closed
vitali-karmanov opened this issue Feb 29, 2024 · 4 comments

Comments

@vitali-karmanov
Copy link

Hello,

What is the right way of using a RecyclableMemoryStreamManager with FileStreamResult? I'm having the following issue:

image
public class PdfFileAttachment
{
    public byte[] FileBytes { get; set; }
    public string ContentType { get; set; }
}

PdfFileAttachment pdfFileAttachment = await _pdfService.GetPdfFileAttachment();

var options = new RecyclableMemoryStreamManager.Options()
{
    BlockSize = 1024,
    LargeBufferMultiple = 1024 * 1024,
    MaximumBufferSize = 16 * 1024 * 1024,
    GenerateCallStacks = true,
    AggressiveBufferReturn = true,
    MaximumLargePoolFreeBytes = 16 * 1024 * 1024 * 4,
    MaximumSmallPoolFreeBytes = 100 * 1024,
};

var manager = new RecyclableMemoryStreamManager(options);

using (var memoryStream = manager.GetStream())
{
    memoryStream.Write(pdfFileAttachment.FileBytes, 0, pdfFileAttachment.FileBytes.Length);
    
    return new FileStreamResult(memoryStream, pdfFileAttachment.ContentType);
}

The end goal is to return a pdf file that is stored in a byte[].

Thank you!

@sgorozco
Copy link

sgorozco commented Feb 29, 2024 via email

@vitali-karmanov
Copy link
Author

If I remove the using and I added pdfFileStream.Seek(0, SeekOrigin.Begin) before the return it works.

public class PdfFileAttachment
{
    public byte[] FileBytes { get; set; }
    public string ContentType { get; set; }
}

PdfFileAttachment pdfFileAttachment = await _pdfService.GetPdfFileAttachment();

var options = new RecyclableMemoryStreamManager.Options()
{
    BlockSize = 1024,
    LargeBufferMultiple = 1024 * 1024,
    MaximumBufferSize = 16 * 1024 * 1024,
    GenerateCallStacks = true,
    AggressiveBufferReturn = true,
    MaximumLargePoolFreeBytes = 16 * 1024 * 1024 * 4,
    MaximumSmallPoolFreeBytes = 100 * 1024,
};

var manager = new RecyclableMemoryStreamManager(options);

var memoryStream = manager.GetStream();

memoryStream.Write(pdfFileAttachment.FileBytes, 0, pdfFileAttachment.FileBytes.Length);

pdfFileStream.Seek(0, SeekOrigin.Begin);

return new FileStreamResult(memoryStream, pdfFileAttachment.ContentType);

However, doesn't removing the using kind of defeat the purpose of the RecyclableMemoryStream by not disposing the stream?

Thank you!

@sgorozco
Copy link

When you dispose of the stream, the recyclable buffers, which act as storage for the stream, are returned to their pool. It's important to dispose of the stream, but make sure to do this after you've processed the FileStreamResult you're returning. The Dispose() method call, whether explicit or implicit through the using() statement, should be made from outside the method that creates and returns the FileStreamResult.

@steve-warren
Copy link

FileStreamResult is automatically disposed per FileStreamResultExecutor.ExecuteAsync:

https://github.com/dotnet/aspnetcore/blob/d9df235c2e6d41b65d8e860c5e209d9df8cbcae1/src/Mvc/Mvc.Core/src/Infrastructure/FileStreamResultExecutor.cs#L31

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants