C# 是否有一种干净的方法可以返回FilePathResult并在以后删除磁盘上的文件?

C# 是否有一种干净的方法可以返回FilePathResult并在以后删除磁盘上的文件?,c#,asp.net,asp.net-mvc,C#,Asp.net,Asp.net Mvc,我有一个类,它使用外部进程创建一个文件,并作为下载结果返回,此时我想从服务器上删除该文件。我通常喜欢避免磁盘上的临时文件,但在这种情况下,这是不可能避免的 我最初尝试使用Dispose方法实现此功能: public class SetupFile : IDisposable { /// <summary>Local file path</summary> public string LocalFilePath { get; set; } ///

我有一个类,它使用外部进程创建一个文件,并作为下载结果返回,此时我想从服务器上删除该文件。我通常喜欢避免磁盘上的临时文件,但在这种情况下,这是不可能避免的


我最初尝试使用Dispose方法实现此功能:

public class SetupFile : IDisposable 
{
    /// <summary>Local file path</summary>
    public string LocalFilePath { get; set; }
    /// <summary>Filename to present to user</summary>
    public string DownloadFilename { get; set; }

    public void Dispose()
    {
        System.IO.File.Delete(LocalFile);
    }
}
(注意,
Generator
Signer
正在通过依赖项注入插入控制器,为了保持关注点的分离,我不希望
SetupFileGenerator
依赖
DigitalSignatureTool
。重要的一点是,我确实需要磁盘上的文件才能运行
Signer.Sign
)--因此,
Generator.Generate()
不能只返回流)

这里的问题是,
FilePathResult
仅在稍后在处理管道中被调用时发送文件,这意味着我的
SetupFile.Dispose()
方法已被调用


我想我的下一步是做两件事中的一件:

  • 实现一个新类,该类派生自
    FilePathResult
    ,但也会在文件发送后删除该文件
  • 重构我的代码,使其不再具有属性
    字符串LocalFilePath
    ,而是具有
    MemoryStream FileContents

然而,这似乎是一种相当常见的模式,所以在我重新发明轮子之前,有没有实现的最佳实践?有什么需要特别注意的吗?

OnResultExecuted方法在响应编写之后运行。您可以使用ActionFilterAttribute覆盖它

public class DeleteFileAttribute : ActionFilterAttribute 
{ 
    public override void OnResultExecuted(ResultExecutedContext filterContext) 
    { 
        filterContext.HttpContext.Response.Flush();
        string filePath = (filterContext.Result as FilePathResult).FileName;
        System.IO.File.Delete(filePath);
    } 
} 
只需按照以下方式装饰您的方法:

[DeleteFile]
[HttpPost, Route("/download")]
public ActionResult Download(InstallParams params) 
{
    using (SetupFile file = Generator.Generate(params))
    {   
        Signer.Sign(file.LocalFilePath);

        return new FilePathResult(file.LocalFilePath, "application/octet-stream")
        {
            FileDownloadName = file.DownloadFilename
        };
    }
}

您应该将这两个过程分开,因为文件管理可以是pita。有时文件会被锁定,并导致您不想在此处管理的问题。您应该将该管理放在一个简单的服务中,可以随时运行。您可以使用从
MemoryStream继承的类,您可以在该类上重写它
Dispose()
方法?@phillip好的观点:它可能会失败,这可能有几个原因,需要定期进行带外清理操作。但这还需要考虑到它不能删除正在使用的文件(例如,当前正在下载的内容)我个人喜欢在一个View模型中包含尽可能多的相关事物。考虑一下:你可以有一个名为VMLoad Load控制器的View模型。在该视图模型中将是属性:StudiFielEng生成器、DigialSigaTurrUng工具以及安装PARAMS。把所有的逻辑放到VM中,并允许它控制工作流。可能有助于解决状态问题,因为VM将控制创建和处置。如果需要回调,该viewmodel只需要两个方法:null-CTOR和POST方法。
[DeleteFile]
[HttpPost, Route("/download")]
public ActionResult Download(InstallParams params) 
{
    using (SetupFile file = Generator.Generate(params))
    {   
        Signer.Sign(file.LocalFilePath);

        return new FilePathResult(file.LocalFilePath, "application/octet-stream")
        {
            FileDownloadName = file.DownloadFilename
        };
    }
}