0

I'm creating a file on the fly on a WebAPI call, and sending that file back to the client.

I think I'm misunderstanding flush/close on a FileStream:

Dim path As String = tempFolder & "\" & fileName
Dim result As New HttpResponseMessage(HttpStatusCode.OK)
Dim stream As New FileStream(path, FileMode.Open)
With result
    .Content = New StreamContent(stream)
    .Content.Headers.ContentDisposition = New Headers.ContentDispositionHeaderValue("attachment")
    .Content.Headers.ContentDisposition.FileName = fileName
    .Content.Headers.ContentType = New Headers.MediaTypeHeaderValue("application/octet-stream")
    .Content.Headers.ContentLength = stream.Length
End With

'stream.Flush()
'stream.Close()
'Directory.Delete(tempFolder, True)

Return result

You can see where I've commented things out above.

Questions:

  1. Does the stream flush/close itself?
  2. How can I delete the tempFolder after returning the result?

On top of all this, it would be great to know how to generate the file and send it to the user without writing it to the file system first. I'm confident this is possible, but I'm not sure how. I'd love to be able to understand how to do this, and solve my current problem.

Update:

I went ahead with accepted answer, and found it to be quite simple:

Dim ReturnStream As MemoryStream = New MemoryStream()
Dim WriteStream As StreamWriter = New StreamWriter(ReturnStream)
With WriteStream
    .WriteLine("...")
End With
WriteStream.Flush()
WriteStream.Close()

Dim byteArray As Byte() = ReturnStream.ToArray()
ReturnStream.Flush()
ReturnStream.Close()

Then I was able to stream the content as bytearraycontent:

With result
    .Content = New ByteArrayContent(byteArray)
...
End With
user1447679
  • 3,076
  • 7
  • 32
  • 69
  • 1
    For #2, use an action filter. Override `onActionExecuted` - https://msdn.microsoft.com/en-us/library/system.web.http.filters.actionfilterattribute.onactionexecuted%28v=vs.118%29.aspx – Francis Ducharme Apr 29 '15 at 20:26
  • @FrancisDucharme I've nearly figured this out. What I need access to in the onActionExecuted override is the variable "tempFolder" that was created. Could you give me an example of this please? Or just another nudge in the right direction? – user1447679 Apr 29 '15 at 21:51
  • Oh I think I just figured it out, with Request.Properties – user1447679 Apr 29 '15 at 21:55
  • Yep. During method execution you can append data in there – Francis Ducharme Apr 29 '15 at 21:57
  • Now I have a whole new issue. It can't delete the folder because its in use, which I'm assuming is because I'm not flushing and closing the stream. – user1447679 Apr 29 '15 at 22:11

1 Answers1

3

On top of all this, it would be great to know how to generate the file and send it to the user without writing it to the file system first. I'm confident this is possible, but I'm not sure how. I'd love to be able to understand how to do this, and solve my current problem.

To do the same thing without writing a file to disk, you might look into the MemoryStream class. As you'd guess, it streams data from memory like the FileStream does from a file. The two main steps would be:

  1. Take your object in memory and instead of writing it to a file, you'd serialize it into a MemoryStream using a BinaryFormatter or other method (see that topic on another StackOverflow Q here: How to convert an object to a byte array in C#).
  2. Pass the MemoryStream to the StreamContent method, exactly the same way you're passing the FileStream now.
Community
  • 1
  • 1
Arin
  • 1,373
  • 2
  • 10
  • 23
  • 2
    +1. This is how I always handle generated content - no need to write anything to the file system which causes wasteful I/O and requires write permissions. – Shaun Apr 29 '15 at 22:41
  • Trying this now... still would like to figure out how to deal with that stream properly. – user1447679 Apr 29 '15 at 22:54
  • Very cool. Found a simple way to do this, see my update. The file being generated was basically text. Any issues there or looks good? – user1447679 Apr 29 '15 at 23:28
  • Great; glad you got that working! One last suggestion would be to employ a `Using` statement or a `Try...Finally` block with your MemoryStream, as it implements IDisposable. That way, even if an exception occurs, your stream will always get closed & disposed properly. To see examples of how this looks, see the MSDN code sample for [MemoryStream](https://msdn.microsoft.com/en-us/library/system.io.memorystream%28v=vs.110%29.aspx) or [IDisposable](https://msdn.microsoft.com/en-us/library/system.idisposable%28v=vs.110%29.aspx). For example, `Using WriteStream As New StreamWriter(ReturnStream)...` – Arin Apr 30 '15 at 14:02