10

我需要在 ASP.NET MVC 中实现文件下载。在网上搜索,我发现了这样的代码:

public ActionResult GetFile()
{
    return File(filename, "text/csv", Server.UrlEncode(filename));
}

很好,但我想动态创建这个文件的内容。

我意识到我可以动态创建文件,然后使用上面的语法下载该文件。但是,如果我可以简单地将我的内容直接写入响应,那不是更有效吗?这在 MVC 中可能吗?

4

5 回答 5

14

这是我最终使用的代码的过度简化版本。它满足我的需求。

[HttpGet]
public ActionResult GetFile()
{
    Response.Clear();
    Response.AddHeader("Content-Disposition", "attachment; filename=myfile.csv");
    Response.ContentType = "text/csv";

    // Write all my data
    Response.Write(...);
    Response.End();

    // Not sure what else to do here
    return Content(String.Empty);
}
于 2012-05-12T04:51:34.707 回答
4

另一种解决方案是使用接受流的 File() 的重载。

就我而言,它是我需要从控制器操作生成的 csv,所以它有点像这样:

[HttpGet]
public ActionResult DownloadInvalidData(int fileId)
{
    string invalidDataCsv = this.importService.GetInvalidData(fileId);
    string downloadFileName = "error.csv";

    var stream = new MemoryStream();
    var writer = new StreamWriter(stream);

    writer.Write(invalidDataCsv);
    writer.Flush();
    stream.Position = 0;

    return File(stream, "text/csv", downloadFileName);
}

请注意,您不应将 Stream 或 StreamWriter 传递给 File() 函数之前将其处理掉,因为处理任何一个都会关闭流,使其无法使用。

于 2015-10-05T15:08:40.673 回答
3

如果您想将其作为文件下载,那么您可以ActionResult按照@Tungano 的建议尝试自定义,否则如果您想直接进入响应,那么内置的ContentResult就可以,但它可以使用简单的字符串,并且在复杂的场景中您必须延长它。

public class CustomFileResult : FileContentResult
{
  public string Content { get; private set; }

  public string DownloadFileName { get; private set; }

  public CustomFileResult(string content, string contentType, string downloadFileName)
    : base(Encoding.ASCII.GetBytes(content), contentType)
  {
    Content = content;
    DownloadFileName = downloadFileName;
  }

  public override void ExecuteResult(ControllerContext context)
  {
    context.HttpContext.Response.AppendHeader("Content-Disposition", "attachment; filename=" + DownloadFileName);

    base.ExecuteResult(context);
  }
}


public class BlogController : Controller
{
  public ActionResult Index()
  {
    return View();
  }

  public CustomFileResult GetMyFile()
  {
    return CustomFile("Hello", "text/plain", "myfile.txt");
  }

  protected internal CustomFileResult CustomFile(string content, string contentType, string downloadFileName)
  {
    return new CustomFileResult(content, contentType, downloadFileName);
  }
}
于 2012-05-12T05:03:55.417 回答
3

我很确定这就是 FileStreamResult 的作用。但是,如果您不想使用它,只需将其写入响应即可。

于 2012-05-12T03:47:30.587 回答
2

您可以直接写入 Response.OutputStream ,类似于流式传输到文件的方式。为了保持它的可测试性和 MVC 风格,您可以创建自己的 ActionResult 类,该类对您传递的模型对象进行流式传输。

于 2012-05-12T04:06:43.007 回答