How do I dispose my filestream when implementing a file download in ASP.NET?
Asked Answered
H

2

25

I have a class DocumentGenerator which wraps a MemoryStream. So I have implemented IDisposable on the class.

I can't see how/where I can possibly dispose it though.

This is my current code, which performs a file download in MVC:

using (DocumentGenerator dg = DocumentGenerator.OpenTemplate(path))
{
    /* some document manipulation with the 
       DocumentGenerator goes here ...*/

    return File(dg.GetDocumentStream(), "text/plain", filename);
}

This errors as the stream is closed/disposed before the controller has finished with it. How can I make sure my resources are properly disposed in this situation?

EDIT: My implementation of IDisposable at the moment just disposes the MemoryStream. I know it's not a proper implementation, I just used it as a test. Is there something different I could do here to make it work?

public void Dispose()
{
    _ms.Dispose();
    _ms = null;
}
Hypogeal answered 21/6, 2010 at 11:53 Comment(3)
Can you show us the implementation of IDisposable, please?Nellanellda
Is that _ms the same that you get after calling GetDocumentStream?Unthoughtof
@Jordão: yes that's correct, hence the problem.Hypogeal
W
34

You don't need to dispose the stream. It will be disposed by the FileStreamResult.WriteFile method. Code excerpt from this class:

public FileStreamResult(Stream fileStream, string contentType) : base(contentType)
{
    if (fileStream == null)
    {
        throw new ArgumentNullException("fileStream");
    }
    this.FileStream = fileStream;
}

protected override void WriteFile(HttpResponseBase response)
{
    Stream outputStream = response.OutputStream;
    using (this.FileStream)
    {
        byte[] buffer = new byte[0x1000];
        while (true)
        {
            int count = this.FileStream.Read(buffer, 0, 0x1000);
            if (count == 0)
            {
                return;
            }
            outputStream.Write(buffer, 0, count);
        }
    }
}

Notice the using. When you call File(dg.GetDocumentStream(), "text/plain", filename) from your controller this invokes the constructor which stores the stream into a public property which is disposed during the rendering.

Conclusion: you don't need to worry about disposing the stream obtain with dg.GetDocumentStream().

Wilfredwilfreda answered 21/6, 2010 at 16:6 Comment(1)
What about if your stream comes from another disposable object like HttpWebResponse? Should I worry about disposing the HttpWebResponse or just assume that it will get garbage collected? Example var response = (HttpWebResponse)request.GetResponse(); return File(response.GetResponseStream(), "image/JPEG");Insurrection
S
0

Just to add to what Darin has said, it's important to note this concept:

public Stream GetDownloadFile(...)
{
  using (var stream = new MemoryStream()) {
    return stream;
  }
}

public Stream GetDownloadFile(...)
{
  using (var generator = DocumentGenerator.OpenTemplate(path))
  {
    // Document manipulation.

    return File(generator.GetDocumentStream(), "text/plain", filename);
  }
}

Regardless of how you are using it in your method, the using block ensures that Dispose is always called, this is important when you consider to use the result of the using block as a return statement, it won't stop it from being disposed....

Stichomythia answered 23/6, 2010 at 6:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.