Does Filestreamresult Close Stream

Does FileStreamResult close Stream?

Yes. It uses a using block around the stream, and that ensures that the resource will dispose.

Here is the internal implementation of the FileStreamResult WriteFile method:

protected override void WriteFile(HttpResponseBase response)
{
// grab chunks of data and write to the output stream
Stream outputStream = response.OutputStream;
using (FileStream)
{
byte[] buffer = new byte[BufferSize];

while (true)
{
int bytesRead = FileStream.Read(buffer, 0, BufferSize);
if (bytesRead == 0)
{
// no more data
break;
}

outputStream.Write(buffer, 0, bytesRead);
}
}
}

Does a Stream get Disposed when returning a File from an Action?

According to source code here aspnet/AspNetWebStack/blob/master/src/System.Web.Mvc/FileStreamResult.cs

Yes

protected override void WriteFile(HttpResponseBase response)
{
// grab chunks of data and write to the output stream
Stream outputStream = response.OutputStream;
using (FileStream)
{
byte[] buffer = new byte[BufferSize];

while (true)
{
int bytesRead = FileStream.Read(buffer, 0, BufferSize);
if (bytesRead == 0)
{
// no more data
break;
}

outputStream.Write(buffer, 0, bytesRead);
}
}
}

Where FileStream would have been the stream passed when you called

return File(stream, "application/octet-stream", "forums.csv");

Update.

Your question was originally tagged as Asp.Net MVC but the code looks like the more recent core framework.

Found it there as well though written differently it does the same thing technically.

aspnet/AspNetCore/blob/master/src/Mvc/Mvc.Core/src/Infrastructure/FileResultExecutorBase.cs

protected static async Task WriteFileAsync(HttpContext context, Stream fileStream, RangeItemHeaderValue range, long rangeLength)
{
var outputStream = context.Response.Body;
using (fileStream)
{
try
{
if (range == null)
{
await StreamCopyOperation.CopyToAsync(fileStream, outputStream, count: null, bufferSize: BufferSize, cancel: context.RequestAborted);
}
else
{
fileStream.Seek(range.From.Value, SeekOrigin.Begin);
await StreamCopyOperation.CopyToAsync(fileStream, outputStream, rangeLength, BufferSize, context.RequestAborted);
}
}
catch (OperationCanceledException)
{
// Don't throw this exception, it's most likely caused by the client disconnecting.
// However, if it was cancelled for any other reason we need to prevent empty responses.
context.Abort();
}
}
}

Does File() In asp.net mvc close the stream?

If you are using the File object to send the resulting file for download as bob.html then yes.

I believe that all standard Streams (OutputStream, FileStream, CryptoStream) will attempt to flush when closed or disposed.

There are a number of classes within the MVC framework that implement the base FileResult class.

System.Web.Mvc.FileResult
System.Web.Mvc.FileContentResult
System.Web.Mvc.FilePathResult
System.Web.Mvc.FileStreamResult

Why does ASP.NET MVC Controller FileStreamResult error on closed stream?

You should remove:

using (memoryStream)

FileStreamResult will dispose memoryStream for you.

The reason that your code doesn't work is that the actual work that reads from memoryStream is not in your code - it is in MVC code that calls fileStream.WriteFile. But that code is executed somewhere higher up the call stack. And by the time WriteFile is called (which needs memoryStream) you have already disposed it.

Do I need to close this memory stream?

Since the memory stream is encapsulated in the return value, you should not dispose it. If you do, it will be disposed before the FileStreamResult can access it.

The stream is already disposed inside the FileStreamResultExecutor.ExecuteAsync method, as you can see in the source.

The same is true for ASP.NET MVC, where is it FileStreamResult.WriteFile that does the disposal (source).

Cannot access a closed Stream when returning FileStreamResult from C# .NetCore API

Using statements close and unload the variable from memory set in the using statement which is why you are getting an error trying to access a closed memory stream. You don't need to use a using statement if you are just going to return the result at the end.

Using statements are useful for taking care of removing data from memory for you but you could always dispose of the data yourself using .dispose()

With FileStreamResult, how is the MemoryStream closed?

The FileStreamResult will do that for you. When in doubt always check the code, because the code never lies and since ASP.NET MVC is open source it's even more easy to view the code.

A quick search on Google for FileStreamResult.cs lets you verify that in the WriteFile method the stream is correctly disposed using the using statement. (no pun intended)

protected override void WriteFile(HttpResponseBase response) {
// grab chunks of data and write to the output stream
Stream outputStream = response.OutputStream;
using (FileStream) {
byte[] buffer = new byte[_bufferSize];

while (true) {
int bytesRead = FileStream.Read(buffer, 0, _bufferSize);
if (bytesRead == 0) {
// no more data
break;
}

outputStream.Write(buffer, 0, bytesRead);
}
}
}

FileStreamResult - The process cannot access the file, because it is being used by another process

It seems the source of the FileStreamResult class shows it has no support for cancellation.
You will need to implement your own, if required. E.g. (not-tested, just imagined)

using System.IO;

namespace System.Web.Mvc
{
public class CancellableFileStreamResult : FileResult
{
// default buffer size as defined in BufferedStream type
private const int BufferSize = 0x1000;

private readonly CancellationToken _cancellationToken;

public CancellableFileStreamResult(Stream fileStream, string contentType,
CancellationToken cancellationToken)
: base(contentType)
{
if (fileStream == null)
{
throw new ArgumentNullException("fileStream");
}

FileStream = fileStream;
_cancellationToken = cancellationToken;
}

public Stream FileStream { get; private set; }

protected override void WriteFile(HttpResponseBase response)
{
// grab chunks of data and write to the output stream
Stream outputStream = response.OutputStream;
using (FileStream)
{
byte[] buffer = new byte[BufferSize];

while (!_cancellationToken.IsCancellationRequested)
{
int bytesRead = FileStream.Read(buffer, 0, BufferSize);
if (bytesRead == 0)
{
// no more data
break;
}

outputStream.Write(buffer, 0, bytesRead);
}
}
}
}
}

You can then use it like

public IActionResult Download(string path, string fileName, CancellationToken cancellationToken)
{
var fileStream = System.IO.File.OpenRead(path);
var result = new CancellableFileStreamResult(
fileStream, "application/force-download", cancellationToken);
result.FileDownloadName = fileName;
return result;
}

Again, I'm this is not tested, just imagined.
Maybe this doesn't work, as the action is already finished, thus cannot be cancelled anymore.

EDIT:
The above answer "Imagined" for ASP.net framework. ASP.net core has a quite different underlying framework: In .net core, the action is processed by and executor, as shown in the source. That will eventually call WriteFileAsync in the FileResultHelper. There you can see that StreamCopyOperation is called with the cancellationToken context.RequestAborted. I.e. cancellation is in place in .net Core.

The big question is: why isn't the request aborted in your case.



Related Topics



Leave a reply



Submit