How to delete a file after it was streamed in ASP.NET Core

五迷三道 提交于 2021-02-04 19:16:29

问题


I would like to delete a temporary file after returning it form action. How can i achieve that with ASP.NET Core:

public IActionResult Download(long id)
{
    var file = "C:/temp/tempfile.zip";
    var fileName = "file.zip;
    return this.PhysicalFile(file, "application/zip", fileName);
    // I Would like to have File.Delete(file) here !!
}

The file is too big for returning using memory stream.


回答1:


File() or PhysicalFile() return a FileResult-derived class that just delegates processing to an executor service. PhysicalFileResult's ExecuteResultAsync method calls :

var executor = context.HttpContext.RequestServices
                 .GetRequiredService<IActionResultExecutor<PhysicalFileResult>>();
return executor.ExecuteAsync(context, this);

All other FileResult-based classes work in a similar way.

The PhysicalFileResultExecutor class essentially writes the file's contents to the Response stream.

A quick and dirty solution would be to create your own PhysicalFileResult-based class that delegates to PhysicalFileResultExecutor but deletes the file once the executor finishes :

public class TempPhysicalFileResult : PhysicalFileResult
{
    public TempPhysicalFileResult(string fileName, string contentType)
                 : base(fileName, contentType) { }
    public TempPhysicalFileResult(string fileName, MediaTypeHeaderValue contentType)
                 : base(fileName, contentType) { }

    public override async  Task ExecuteResultAsync(ActionContext context)
    {
        await base.ExecuteResultAsync(context);
        File.Delete(FileName);
    }
}

Instead of calling PhysicalFile() to create the PhysicalFileResult you can create and return a TempPhysicalFileResult, eg :

return new TempPhysicalFileResult(file, "application/zip"){FileDownloadName=fileName};

That's the same thing PhysicalFile() does :

[NonAction]
public virtual PhysicalFileResult PhysicalFile(
    string physicalPath,
    string contentType,
    string fileDownloadName)
    => new PhysicalFileResult(physicalPath, contentType) { FileDownloadName = fileDownloadName };

A more sophisticated solution would be to create a custom executor that took care eg of compression as well as cleaning up files, leaving the action code clean of result formatting code




回答2:


It would be hard to do this within the same request as the requests ends directly after the streaming is complete. A better option might be to run a timed background task via a hosted service which periodically removes all files (e.g. with a last write time of >5 minutes ago) from the temp directory.




回答3:


You can load content of file. delete file and send content in response. in MVC you can return a file in response. check the snippet below

public FileResult Download()
{
    var fileName = $"client-file-name.ext";
    var filepath = $"filepath";
    byte[] fileBytes = System.IO.File.ReadAllBytes(filepath);
    //delete file here
    return File(fileBytes, "application/x-msdownload", fileName);
}



回答4:


Since the file is big one solution is to send a token (like a guid) along side the request. Only once the download has been completed you want to delete the file (otherwise you risk losing it). So using that token the client will make a new request using the aforementioned token. So you will know that the download was successful and that you can proceed to delete the file.

I suggest using a Dictionary to map a token to a file.

Deleting on one request seems like a bad practice due to the fact that you can easily lose the file.

Also you can use Henk Mollema answer to be certain that all files are cleared periodically if that is what you are trying to achieve.



来源:https://stackoverflow.com/questions/54901479/how-to-delete-a-file-after-it-was-streamed-in-asp-net-core

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!