我需要在 ASP.NET MVC 中实现文件下载。在网上搜索,我发现了这样的代码:
public ActionResult GetFile()
{
return File(filename, "text/csv", Server.UrlEncode(filename));
}
很好,但我想动态创建这个文件的内容。
我意识到我可以动态创建文件,然后使用上面的语法下载该文件。但是,如果我可以简单地将我的内容直接写入响应,那不是更有效吗?这在 MVC 中可能吗?
我需要在 ASP.NET MVC 中实现文件下载。在网上搜索,我发现了这样的代码:
public ActionResult GetFile()
{
return File(filename, "text/csv", Server.UrlEncode(filename));
}
很好,但我想动态创建这个文件的内容。
我意识到我可以动态创建文件,然后使用上面的语法下载该文件。但是,如果我可以简单地将我的内容直接写入响应,那不是更有效吗?这在 MVC 中可能吗?
这是我最终使用的代码的过度简化版本。它满足我的需求。
[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);
}
另一种解决方案是使用接受流的 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() 函数之前将其处理掉,因为处理任何一个都会关闭流,使其无法使用。
如果您想将其作为文件下载,那么您可以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);
}
}
我很确定这就是 FileStreamResult 的作用。但是,如果您不想使用它,只需将其写入响应即可。
您可以直接写入 Response.OutputStream ,类似于流式传输到文件的方式。为了保持它的可测试性和 MVC 风格,您可以创建自己的 ActionResult 类,该类对您传递的模型对象进行流式传输。