在ASP.NET MVC中下载动态生成的文件

时间:2012-05-12 03:38:53

标签: asp.net-mvc

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

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

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

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

5 个答案:

答案 0 :(得分: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);
}

答案 1 :(得分:3)

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

答案 2 :(得分:3)

如果您想将其作为文件下载,那么您可以尝试@Tungano建议的自定义ActionResult,否则如果您想直接进入响应,则内置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);
  }
}

答案 3 :(得分:3)

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

在我的情况下,我需要从Controller Action生成一个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);
}

请注意,在将其传递给File()函数之前,应该处理Stream或StreamWriter,因为处理它们会关闭流,使其无法使用。

答案 4 :(得分:2)

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