ASP.NET 5 Web API如何返回文件

14

我的之前的问题:如何从ASP.net 5 Web API返回文件

我尝试在Web API POST请求的响应中返回一个文件。

我正在使用dnx451框架和rc1-final版本。控制器方法:

[HttpPost("")]
public ActionResult Post([FromBody]DocumentViewModel vm)
{
    try
    {
        if (ModelState.IsValid)
        {

            var Document = _repository.GetDocumentByGuid(vm.DocumentGuid, User.Identity.Name);
            var Params = Helper.ClientInputToRealValues(vm.Parameters, Document.DataFields);
            var file = Helper.GeneratePdf(Helper.InsertValues(Params, Document.Content));
            FileStream stream = new FileStream(file,FileMode.Open);

            return File(stream, "application/pdf", "test.pdf");

        }

    }
    catch (Exception ex)
    {
        Response.StatusCode = (int)HttpStatusCode.BadRequest;
        return null;
    }
    Response.StatusCode = (int)HttpStatusCode.BadRequest;
    return null;

}
结果是,我得到一个名为“response”的文件。 将其保存为PDF后,我尝试打开它,但它显示为损坏。 希望您能帮助我。 我正在使用Postman作为测试客户端。 谢谢。

当您调试此代码时,是否到达了return File()行?响应中收到的内容和标头是什么? - David
你的 Helper.GeneratePdf() 代码是否正确运行?file 的值是多少?文件能否被打开,并且在将其发送回浏览器之前,你是否检查了生成的文件? - Leonardo Herrera
是的,PDF 文件已经生成了,我可以从文件浏览器中打开它并且一切都很正常。 - Joonas Püüa
3个回答

25
请查看我在另一篇帖子中的答案:返回文件作为响应 供参考,我认为这符合您的需求:
public FileResult TestDownload()
{
    HttpContext.Response.ContentType = "application/pdf";
    FileContentResult result = new FileContentResult(System.IO.File.ReadAllBytes("YOUR PATH TO PDF"), "application/pdf")
    {
        FileDownloadName = "test.pdf"
    };

    return result;                                
}

结果仍然是一样的。响应返回名为“response”的文件。如果我将其重命名为somthing.pdf并尝试打开它-它仍然是损坏的。 - Joonas Püüa
我已经在本地使用本地PDF测试了该代码,文件成功下载并且我可以打开它。PDF路径是您的机器本地路径吗?还是您正在动态生成它之类的操作?在“YOUR PATH TO PDF”处,您必须包括扩展名。 - Ian Auty
很可能,为了确认代码是否适用于你的PDF文件,你可以创建一个新的MVC项目,并将该方法添加到为你生成的HomeController.cs中。这就是我在发布之前测试的方法。然后你就可以从那里找出罪魁祸首 :) - Ian Auty
基本上我会自己制作我的测试客户端,因为Postman不够用,或者至少我不知道它应该如何与之配合,谢谢。 - Joonas Püüa
2
FileResult和FileContentResult是Mvc类,而不是Webapi。 - Boanerge
显示剩余3条评论

12

我刚刚遇到了这个问题并找到了解决方法。只要您有文件的绝对路径,就可以返回PhysicalFileResult并在Response上显式设置Content-Disposition头,如下所示:

[HttpGet("{key}")]
public IActionResult Get(string key)
{
    var file = _files.GetPath(key);

    var result = PhysicalFile(file.Path, "text/text");

    Response.Headers["Content-Disposition"] = new ContentDispositionHeaderValue("attachment")
    {
        FileName = file.Name
    }.ToString();

    return result;
}

使用 PhysicalFile 的优点在于,所有异步流传输等操作都由框架处理。


2

也许更好的选择是考虑使用FileStreamResult操作结果。

这样做的优点是不需要将整个文件内容保存在内存中,这取决于文件的大小、流量水平等因素,否则很容易导致规模问题。

可以尝试以下代码:

[HttpGet]
public FileStreamResult DownloadFile()
{
    var Document = _repository.GetDocumentByGuid(vm.DocumentGuid, User.Identity.Name);
    var Params = Helper.ClientInputToRealValues(vm.Parameters, Document.DataFields);
    var file = Helper.GeneratePdf(Helper.InsertValues(Params, Document.Content));
    var stream = new FileStream(file,FileMode.Open);
    return new FileStreamResult(stream, "application/pdf")
    {
        FileDownloadName = "test.pdf"
    };
}

2
FileStreamResult 不是来自 MVC 吗? - Tobias
这需要导入System.Web.Mvc,这会破坏WebAPI控制器中的其他内容。问题是关于WebAPI的。 - Florian Winter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接