编辑 OpenXML docx 模板并将其 return 作为 FileResult

Edit OpenXML docx template and return it as FileResult

我想为我的应用程序的用户提供下载一个 docx 文件的机会,该文件将根据他们的请求包含动态内容。 我用 header 准备了一个模板,否则 OpenXML 的创建在某个地方会很痛苦。 现在我在编辑它并在我的 ASP MVC 应用程序中将其 return 作为 FileResult 时遇到问题。

我的计划是将文件读取到 MemoryStream 并将其编辑为 WordprocessingDocument,然后 returning MemoryStream as Byte[]

我这里有两个问题:

  1. 如果我在没有内存流的情况下直接从文件读取 WordprocessingDocument,我看不到将其转换为 FileResult() 想要的形状的方法。
  2. 如果我用空 MemoryStream 创建新的 WordprocessingDocument 我可以简单地创建内容并将其 return 作为 File 但我缺少之前准备好的 header与所需的内容。

那么,如何编辑 .docx 模板并将其return 编辑为 FileResult()

这就是您如何使用 MemoryStream 创建新的电子表格文档,然后将其保存到 Byte[]

Byte[] file;
using (MemoryStream mem = new MemoryStream())
{
    using (SpreadsheetDocument spreadsheetDocument = 
        SpreadsheetDocument.Create(mem, SpreadsheetDocumentType.Workbook))
    {
        WorkbookPart workbookpart = spreadsheetDocument.AddWorkbookPart();
        workbookpart.Workbook = new Workbook();
        WorksheetPart worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
        worksheetPart.Worksheet = new Worksheet(new SheetData());

        Sheets sheets = spreadsheetDocument.WorkbookPart.Workbook.
            AppendChild<Sheets>(new Sheets());

        Sheet sheet = new Sheet()
        {
            Id = spreadsheetDocument.WorkbookPart.
                GetIdOfPart(worksheetPart),
            SheetId = 1,
            Name = "aStupidSheet"
        };
        sheets.Append(sheet);
        workbookpart.Workbook.Save()
        spreadsheetDocument.Close();
    }
    file = mem.ToArray();
}

在 FortyTwo 的帮助下,我实现了目标。

所以想要的"workflow"是:

  1. .docx 模板(添加 headers 或其他内容)复制到内存中
  2. 编辑文档内容
  3. return 此文档为 FileResult 而不保存对模板的更改

代码如下:

public FileResult EditDOCXBody()
{
    // Prepare file path
    string file = "../WordTemplates/EmptyTemplate.docx";
    String fullFilePath = HttpContext.ApplicationInstance.Server.MapPath(file);                   

    // Copy file content to MemeoryStream via byte array
    MemoryStream stream = new MemoryStream();                          
    byte[] fileBytesArray = System.IO.File.ReadAllBytes(fullFilePath);  
    stream.Write(fileBytesArray, 0, fileBytesArray.Length);             // copy file content to MemoryStream
    stream.Position = 0;                                                

    // Edit word document content
    using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(stream, true))  
    {
        MainDocumentPart mainPart = wordDoc.MainDocumentPart;                
        Body body = mainPart.Document.Body;

        // add some text to body
        body.Append(new Paragraph(
                    new Run(
                        new Text("Current time is: " + DateTime.Now.ToLongTimeString()))));

        // Save changes to reflect on stream object
        mainPart.Document.Save();                
    }
    return File(stream.ToArray(), "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "servedFilename.docx");            
}

一些重要说明:

  • 您需要手动将文件字节写入 MemoryStream,否则您会收到 Memory stream is not expandable 错误。更多信息 here
  • 您必须使用 mainPart.Document.Save() 才能使更改在 MemoryStream
  • 生效
  • 当 return 编辑文件时,您必须使用 .ToArray() 否则 return 编辑的文件已损坏