その場で作成した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();
}
}
私は 見た たくさんの リンク –を持っていますが、何もうまくいきません。私は多くの人がMemoryStream.WriteTo
を使用し、一部の人はBinaryWrite
を使用します–現時点では、正しい方法が何であるかわかりません。また、より長いコンテンツタイプ、つまりapplication/vnd.openxmlformats-officedocument.wordprocessingml.document
を試しましたが、うまくいきませんでした。
一部のスクリーンショット–回復しようとしても、同じ「パーツが欠落しているか無効」になります
この質問につまずいた人のための解決策:
using
のWordProcessingDocument
ディレクティブ内で、以下を呼び出す必要があります。
wordDocument.Save();
また、MemoryStream
を正しくストリーミングするには、外部のusingブロックでこれを使用します。
Response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
Response.AppendHeader("Content-Disposition", "attachment;filename=HelloWorld.docx");
mem.Position = 0;
mem.CopyTo(Response.OutputStream);
Response.Flush();
Response.End();
代わりにCopyTo
を使用してください。代わりに、WriteTo
にバグがあり、ターゲットストリームが一度にすべてを書き込むことをサポートしていない場合、バッファのコンテンツ全体を書き込めません。
.NET Framework3.5以下のバリアントとして。このバージョンのフレームワークには、クラスCopyTo
のメソッドStream
がありません。したがって、メソッドWriteTo
は次のコードに置き換えられます。
byte[] arr = documentStream.ToArray();
fileStream.Write(arr, 0, arr.Length);
コードをコピーして貼り付けたところ、: "wordDocument.close();"であることがわかりました。 clausuleが欠落していて、追加して機能しました(Asp.NET MVCでアクションをウィッティングしました)
ContentTypeの値が正しくないと思います。これはWord97-2003形式用です。次のように変更します。
application/vnd.openxmlformats-officedocument.wordprocessingml.document
それで問題が解決するかどうかを確認してください。
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();
まず、常に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");
}
(これはOpenXML SDK v2.10.0および.NetCore v2.2を使用しています)
私はこれが答えられたことを知っていますが、私は別の選択肢を捨てたかったのです。以下のようにFile()でストリームを送り返そうとすると、ドキュメントが破損するのは正しいことです。
MemoryStream updateStream = new MemoryStream();
wordDocument.Save();
wordDocument.Clone(updateStream);
return File(updateStream, "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
`
非常に簡単な代替/回避策は、ストリームを以下のようにbyte []に変換するだけで、Worddocxが機能するようになります。
MemoryStream updateStream = new MemoryStream();
wordDocument.Save();
wordDocument.Clone(updateStream);
return File(updateStream.ToArray(), "application/vnd.openxmlformats-officedocument.wordprocessingml.document");