Delete temporary file sent through StreamContent in ASP.NET Web API HttpResponseMessage



Recently I had to delete a temporary (temp) file/resource sent through HttpResponseMessage. The code I tried first was like this:

var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
var response = new HttpResponseMessage();
                response.StatusCode = HttpStatusCode.OK;
                response.Content = new StreamContent(fileStream);
                response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
                {
                    FileName = fileName
                };
File.Delete(filePath);
return response;

Fooling myself I didn’t notice that one cannot do File.Delete(filePath); before returning the file because it’ll be deleted from the server disk before arriving at the client – see that response.Content receives a StreamContent, that is, the file is yet to be streamed to the client – only after it’s been streamed is that we can delete the file.

This is the exception that was being logged:

20131028 18:29:10 435 [7299] ERROR com.itvizion.data.services.Controllers.DataTablesController - Unhandled exception during file action Could not find a part of the path 'C:\ITVizion\MyProject\FileExportService\Files\datatable.csv'.

Sure it could not find the file, it had already been deleted. D'oh

So how can we dispose a managed resource (in this case the file) after the client has successfully downloaded it? That’s a damn good question I made myself and Google yesterday.

Googling I found this StackOverflow question:

How to delete the file that was sent as StreamContent of HttpResponseMessage

The asker pointed me in the right direction. One has to inherit from HttpResponseMessage and override the Dispose method like this:

public class FileHttpResponseMessage : HttpResponseMessage
{
    private string filePath;

    public FileHttpResponseMessage(string filePath)
    {
        this.filePath = filePath;
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);

        Content.Dispose();

        File.Delete(filePath);
    }
}

Note the order of the calls inside the Dispose method. This is an essential part that differs from the hint given by the SO question I mentioned above.

Now what’s left is put FileHttpResponseMessage to use like this:

var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);

var response = new FileHttpResponseMessage(filePath);
response.StatusCode = HttpStatusCode.OK;
response.Content = new StreamContent(fileStream);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
    FileName = fileName
};

return response;

FileHttpResponseMessage will take care of calling Dispose on the correct time deleting the temporary file from the server disk right after the client has finished downloading the file.

Cleaning up the server disk is a good practice after all. This can avoid future headaches.

Hope it helps.