在常规的MVC控制器中,我们可以输出带有FileContentResult的pdf。

public FileContentResult Test(TestViewModel vm)
{
    var stream = new MemoryStream();
    //... add content to the stream.

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

但是我们如何把它变成ApiController呢?

[HttpPost]
public IHttpActionResult Test(TestViewModel vm)
{
     //...
     return Ok(pdfOutput);
}

这是我试过的方法,但似乎不管用。

[HttpGet]
public IHttpActionResult Test()
{
    var stream = new MemoryStream();
    //...
    var content = new StreamContent(stream);
    content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
    content.Headers.ContentLength = stream.GetBuffer().Length;
    return Ok(content);            
}

在浏览器中返回的结果为:

{"Headers":[{"Key":"Content-Type","Value":["application/pdf"]},{"Key":"Content-Length","Value":["152844"]}]}

还有一篇类似的关于SO的文章:在ASP中从控制器返回二进制文件。NET Web API 。它讨论的是输出一个现有文件。但是我不能让它在溪流中工作。

有什么建议吗?


当前回答

 var memoryStream = new MemoryStream();
                await cloudFile.DownloadToStreamAsync(memoryStream);
                responseMessage.result = "Success";

                var contentType = "application/octet-stream";
            
                **using (var stream = new MemoryStream())
                {                    
                    return File(memoryStream.GetBuffer(), contentType, "Cartage.pdf");
                }**

其他回答

而不是返回StreamContent作为内容,我可以使它与ByteArrayContent一起工作。

[HttpGet]
public HttpResponseMessage Generate()
{
    var stream = new MemoryStream();
    // processing the stream.

    var result = new HttpResponseMessage(HttpStatusCode.OK)
    {
        Content = new ByteArrayContent(stream.ToArray())
    };
    result.Content.Headers.ContentDisposition =
        new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
    {
        FileName = "CertificationCard.pdf"
    };
    result.Content.Headers.ContentType =
        new MediaTypeHeaderValue("application/octet-stream");

    return result;
}

我发现这篇文章很有用:https://codeburst.io/download-files-using-web-api-ae1d1025f0a9

基本上它说:

[Route("api/[controller]")]
[ApiController]
public class JobController : ControllerBase
{
    [HttpGet]
    public ActionResult GetFile()
    {
        byte[] fileContent = GetFile();
        return File(fileContent, "application/pdf", "test.pdf");
    }
}

如果你想返回IHttpActionResult,你可以这样做:

[HttpGet]
public IHttpActionResult Test()
{
    var stream = new MemoryStream();

    var result = new HttpResponseMessage(HttpStatusCode.OK)
    {
        Content = new ByteArrayContent(stream.GetBuffer())
    };
    result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
    {
        FileName = "test.pdf"
    };
    result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

    var response = ResponseMessage(result);

    return response;
}

我不太确定是哪一部分的问题,但这就是为什么MemoryStream不适合你:

当你写入MemoryStream时,它会增加它的Position属性。 StreamContent的构造函数会考虑流的当前位置。因此,如果您写入流,然后将其传递给StreamContent,响应将从流末尾的虚无开始。

有两种方法可以正确解决这个问题:

construct content, write to stream [HttpGet] public HttpResponseMessage Test() { var stream = new MemoryStream(); var response = Request.CreateResponse(HttpStatusCode.OK); response.Content = new StreamContent(stream); // ... // stream.Write(...); // ... return response; } write to stream, reset position, construct content [HttpGet] public HttpResponseMessage Test() { var stream = new MemoryStream(); // ... // stream.Write(...); // ... stream.Position = 0; var response = Request.CreateResponse(HttpStatusCode.OK); response.Content = new StreamContent(stream); return response; } looks a little better if you have a fresh Stream, 1) is simpler if your stream does not start at 0

这个问题帮助了我。

所以,试试这个:

控制器代码:

[HttpGet]
public HttpResponseMessage Test()
{
    var path = System.Web.HttpContext.Current.Server.MapPath("~/Content/test.docx");;
    HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
    var stream = new FileStream(path, FileMode.Open);
    result.Content = new StreamContent(stream);
    result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
    result.Content.Headers.ContentDisposition.FileName = Path.GetFileName(path);
    result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
    result.Content.Headers.ContentLength = stream.Length;
    return result;          
}

查看Html标记(点击事件和简单的url):

<script type="text/javascript">
    $(document).ready(function () {
        $("#btn").click(function () {
            // httproute = "" - using this to construct proper web api links.
            window.location.href = "@Url.Action("GetFile", "Data", new { httproute = "" })";
        });
    });
</script>


<button id="btn">
    Button text
</button>

<a href=" @Url.Action("GetFile", "Data", new { httproute = "" }) ">Data</a>