MemoryStream 到 HttpResponseMessage

Posted

技术标签:

【中文标题】MemoryStream 到 HttpResponseMessage【英文标题】:MemoryStream to HttpResponseMessage 【发布时间】:2017-07-16 00:53:20 【问题描述】:

我在服务器上生成了一个 Pdf,需要将其作为响应返回给我的 Web 客户端,以便我得到一个“另存为”对话框。

生成 pdf,并保存到内存流...然后返回到我的方法,该方法将返回 HttpResponseMessage。

方法是:

[Route("GeneratePdf"), HttpPost]
public HttpResponseMessage GeneratePdf(PlateTemplateExtendedDto data)


    var doc = GeneratePdf(DataForThePdf);

    //using (var file = File.OpenWrite("c:\\temp\\test.pdf"))
    //    doc.CopyTo(file); // no need for manual stream copy and buffers

    HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);

    byte[] buffer = new byte[0];
    //get buffer
    buffer = doc.GetBuffer();
    //content length for use in header
    var contentLength = buffer.Length;

    response.Headers.AcceptRanges.Add("bytes");
    response.StatusCode = HttpStatusCode.OK;
    response.Content = new StreamContent(doc);
    response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("render");
    response.Content.Headers.ContentDisposition.FileName = "yes.pdf";
    response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
    response.Content.Headers.ContentLength = doc.Length;

    return response;

但是,文档呈现为空白文件,虽然它具有文件大小和我创建的文档的属性(如果文件属性没问题,则为 pdf 信息,以及页面宽度和高度),但文档显示为空白。

如果我取消注释被注释掉的代码,以保存在本地,则该文件是完美的。文件大小为 228,889 字节。但是,当我让它转到我的网页并保存时,它是 405,153 字节,文件名是“未定义”。

如果我断点,我会看到这些结果:

在前端脚本中,我这样处理下载的对象:

$.post("/api/PlateTemplate/GeneratePdf", data).done(function (data, status, headers) 

            // headers = headers();

            var filename = headers['x-filename'];
            var contentType = headers['content-type'];
            //Create a url to the blob
            var blob = new Blob([data],  type: contentType );
            var url = window.URL.createObjectURL(blob);
            var linkElement = document.createElement('a');
            linkElement.setAttribute('href', url);
            linkElement.setAttribute("download", filename);

            //Force a download
            var clickEvent = new MouseEvent("click", 
                "view": window,
                "bubbles": true,
                "cancelable": false
            );
            linkElement.dispatchEvent(clickEvent);
        );

我不确定文件损坏的位置。我做错了什么?

编辑:按照建议使用以下代码:

$.post("/api/PlateTemplate/GeneratePdf", data).done(function (data, status, headers) 
            alert(data.length);

            var xhr = new XMLHttpRequest();

            $("#pdfviewer").attr("src", URL.createObjectURL(new Blob([data], 
                type: "application/pdf"
            )))

.net代码:

var doc = GeneratePdf(pdfParams);

            HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);

            byte[] buffer = new byte[0];
            //get buffer
            buffer = doc.ToArray();
            //content length for use in header
            var contentLength = buffer.Length;

            response.Headers.AcceptRanges.Add("bytes");
            response.StatusCode = HttpStatusCode.OK;
            response.Content = new StreamContent(doc);
            response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("render");
            response.Content.Headers.ContentDisposition.FileName = "yes.pdf";
            response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
            response.Content.Headers.ContentLength = doc.Length;

            return response;

看来我正在丢失数据。 在我从调用中取回数据后,警报是我的 javascript 中“data.length”的长度。 文件属性为原始pdf文件信息。

从 api 发送的文件,大小为 227,564,如果我保存它,它与磁盘上的字节大小匹配。所以看起来发送是可以的。但是在javascript大小上,当我读入文件时,它是424946,当我这样做时: var file = new Blob([data], type: 'application/pdf' ); (其中 data 是来自服务器的响应)。

【问题讨论】:

使用doc.ToArray() 而不是doc.GetBuffer() jQuery ajax 默认不处理二进制数据Displaying pdf from arraybuffer,另见How to build PDF file from binary string returned from a web-service using javascript @L.B 和 Guest - 我已经尝试了您的两个想法,并编辑了我的问题。似乎我在某处丢失了一些数据.... PDF 正在尝试渲染,但我的字节数不足,所以文件似乎以某种方式被截断?我已将详细信息添加到问题的末尾。 尝试了你们所说的所有内容以及更多内容。从 api 发送的文件,大小为 227,564,如果我保存它,它与磁盘上的字节大小相匹配。所以看起来发送是可以的。但是在javascript大小上,当我读入文件时,它是424946,当我这样做时: var file = new Blob([data], type: 'application/pdf' ); (其中数据是来自服务器的响应)。 【参考方案1】:

ContentLength 设置看起来有些可疑(不是结果):

       //content length for use in header
        var contentLength = buffer.Length;
        response.Content.Headers.ContentLength = doc.Length;

【讨论】:

我将 doc.Length 更改为 contentLength,但得到了相同的结果。大小差异不同,但仍小于应有的大小。【参考方案2】:

我通过使用从 .Net 控制器到 javascript web api 调用结果的 base64 编码字符串“修复”了这个问题,然后允许浏览器通过指定类型('application/pdf')将其转换为二进制。

【讨论】:

以上是关于MemoryStream 到 HttpResponseMessage的主要内容,如果未能解决你的问题,请参考以下文章

PDFsharp 保存到 MemoryStream

将 iTextSharp 文档加载到 MemoryStream

将文件从 MemoryStream 附加到 C# 中的 MailMessage

memorystream - 字符串流,字符串,其他?

无法写入新的 MemoryStream - 流已关闭

在 MemoryStream 中拆分 mp3 音频的正确方法是啥?