我无法将我创建的word文档流式传输到浏览器。我不断收到来自Microsoft Word的消息,该文档已损坏。
当我通过控制台应用程序运行代码并将ASP.NET从图片中删除时,文档生成正确且没有任何问题。我相信一切都围绕着写下文件。
这是我的代码:
using (MemoryStream mem = new MemoryStream())
{
// Create Document
using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(mem, WordprocessingDocumentType.Document, true))
{
// Add a main document part.
MainDocumentPart mainPart = wordDocument.AddMainDocumentPart();
new Document(new Body()).Save(mainPart);
Body body = mainPart.Document.Body;
body.Append(new Paragraph(new Run(new Text("Hello World!"))));
mainPart.Document.Save();
// Stream it down to the browser
// THIS IS PROBABLY THE CRUX OF THE MATTER <---
Response.AppendHeader("Content-Disposition", "attachment;filename=HelloWorld.docx");
Response.ContentType = "application/vnd.ms-word.document";
mem.WriteTo(Response.OutputStream);
Response.End();
}
}
我在很多looked都有links - 但没有什么可行的。很多人使用MemoryStream.WriteTo
而有些人使用BinaryWrite
- 此时我不确定正确的方法是什么。此外,我尝试了较长的内容类型,即application/vnd.openxmlformats-officedocument.wordprocessingml.document
,但没有运气。
一些截图 - 即使您尝试恢复,也会获得相同的“部件丢失或无效”
那些偶然发现此问题的人的解决方案:
在using
的{{1}}指令中,您必须致电:
WordProcessingDocument
另外,为了正确地传输wordDocument.Save();
,请在外部使用块中使用它:
MemoryStream
答案 0 :(得分:7)
使用CopyTo
代替,WriteTo
中存在一个错误,当目标流不支持一次编写所有内容时,它会无法写入缓冲区的全部内容。
答案 1 :(得分:2)
我相信您的ContentType值不正确;这是Word 97 - 2003格式。将其更改为:
application/vnd.openxmlformats-officedocument.wordprocessingml.document
并查看是否可以解决问题。
答案 2 :(得分:2)
我复制并粘贴了你的代码并注意到:“wordDocument.close();” clausule丢失,添加它并且它工作(我在Asp.NET MVC做了一个动作)
答案 3 :(得分:2)
作为.NET Framework 3.5及更低版本的变体。此版本的框架在类CopyTo
中没有方法Stream
。因此,方法WriteTo
将替换为下一个代码:
byte[] arr = documentStream.ToArray();
fileStream.Write(arr, 0, arr.Length);
找到了示例
答案 4 :(得分:1)
(这使用的是OpenXML SDK v 2.10.0和.Net Core v2.2)
我知道已经回答了,但是我想提出另一种选择。尝试像下面这样在File()中发送回流将导致文档损坏,这是正确的:
MemoryStream updateStream = new MemoryStream();
wordDocument.Save();
wordDocument.Clone(updateStream);
return File(updateStream, "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
`
一种超级简单的替代方法/解决方法是将您的流简单地转换为byte [],如下所示,这将产生一个有效的文档docx
MemoryStream updateStream = new MemoryStream();
wordDocument.Save();
wordDocument.Clone(updateStream);
return File(updateStream.ToArray(), "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
答案 5 :(得分:0)
要扩展Rodion的答案并匹配问题中使用的变量,这对我有用:
Response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
Response.AppendHeader("Content-Disposition", "attachment;filename=HelloWorld.docx");
mem.Position = 0;
byte[] arr = mem.ToArray();
Response.BinaryWrite(arr);
Response.Flush();
Response.End();
答案 6 :(得分:0)
首先,始终包含Content-Length。如果浏览器不知道http响应正文的长度,则连接保持打开状态(保持活动状态)。如果没有其他方法,则将内容保存到临时文件中(带有关闭时删除选项),然后获取内容长度。
第二,处理IN-MEM的文档不适用于所有选项(例如,您不能在文档中插入块。必须使用文件模式)。
下面是aspnet核心的示例:
[HttpPost]
public async Task<ActionResult<MopedResponse>> PostAsync(IFormCollection collection)
{
string pathTemp = Path.GetTempFileName(); // get the temp file name
// create or process the word file
// reopen it for serving
FileStream merged = new FileStream(pathTemp, FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose);
System.Net.Mime.ContentDisposition cd = new System.Net.Mime.ContentDisposition
{
FileName = "parafa.docx",
Inline = true // false = prompt the user for downloading; true = browser to try to show the file inline
};
Response.Headers.Add("Content-Disposition", cd.ToString());
Response.Headers.Add("Content-Length", merged.Length.ToString());
return File(merged, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "mywordFile1.docx");
}