使用 OpenXML 从 MVC 控制器将工作簿设为只读

Making workbook readonly from MVC Controller with OpenXML

我正在使用 Open XML 从 MVC 生成一个 Excel 文档。

代码如下:

public ActionResult ExcelReport()
{
  var custId = 1234; //ToDo get from session when it is set

  using (MemoryStream mem = new MemoryStream())
  {
    ExcelReportGenerator excel = new ExcelReportGenerator();

    excel.CreateExcelDoc(mem);

    var reportName = string.Format("MyReport_{0}.xlsx", custId);

    return File(mem.ToArray(), System.Net.Mime.MediaTypeNames.Application.Octet, reportName);
  }

}

我的创建Excel文档方法如下:

public void CreateExcelDoc(MemoryStream mem)
{
  SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(mem, SpreadsheetDocumentType.Workbook);

  //SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Open(mem, false);

  //Code removed for brevity 

  worksheetPart.Worksheet.Save();
  spreadsheetDocument.Close();

}

使用创建方法,excel sheet 正在按预期下载。但是,我想将工作簿设置为只读,所以尝试使用 .Open 方法传递内存流并将 isEditable 设置为 false,但是当我用错误 Exception Details: System.IO.FileFormatException: Archive file cannot be size 0.[=13 击中控制器时,我得到了一个 YSOD =]

调用 SpreadsheetDocument.Open 不会生成只读文件。 It merely opens the memory stream in read only mode. (isEditable is false) 这会阻止流被您的其余代码更改。这解释了为什么在添加该调用之前可能会生成 excel 罚款,以及为什么在添加该调用之后出现空存档异常。不要为此目的使用 SpreadsheetDocument.Open

我不建议您尝试将 Excel 作为只读文件发送。用户可以在任何操作系统上下载它并根据需要重命名和更改文件权限。

我推荐的是添加 mark your Excel as final 的 openXML 代码。微软将此功能添加到 Office 文档中,因为它更正式地阻止用户将来对文件进行更改,而不是简单的文件权限。对这些文件之一的任何更改都需要一个新文件名。

推荐的 OpenXml 代码 generate a Custom Property 因此当用户下载文件时,它会被标记为 Final 以阻止用户编辑。

这是添加自定义 属性:

的方法
private void GenerateCustomFilePropertiesPart1Content(CustomFilePropertiesPart customFilePropertiesPart1)
    {
        Op.Properties properties2 = new Op.Properties();
        properties2.AddNamespaceDeclaration("vt", "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes");

        Op.CustomDocumentProperty customDocumentProperty1 = new Op.CustomDocumentProperty() { FormatId = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}", PropertyId = 2, Name = "_MarkAsFinal" };
        Vt.VTBool vTBool1 = new Vt.VTBool();
        vTBool1.Text = "true";

        customDocumentProperty1.Append(vTBool1);

        properties2.Append(customDocumentProperty1);

        customFilePropertiesPart1.Properties = properties2;
    }

我编写了一个简单的 MVC 应用程序,它生成一个空的 Excel 文件,供您标记为最终文件作为参考实现。 The code is hosted on GitHub。当你运行它的时候,点击最右边的菜单link"Download Excel"。这将下载一个 Excel,其中包含一个名为 Walter's Workbook 且没有数据的工作簿。 excel 将被标记为最终的。 Custom 属性 的代码是使用 OpenXML Productivity Tool 生成的。祝你的项目好运。

使 excel 只读的更简单方法是 Protect the worksheet (see Step 2 at link)

执行此操作的 OpenXML 代码是每个 sheet:

一行
workSheet.Append(new SheetProtection() { Sheet = true, Objects = true, Scenarios = true });

我推出了一个使用此技术的 new version of the reference implementation MVC。 SheetProtection 似乎在 Excel 2007 年得到支持,其中自 Excel 2013 年起才支持标记为 Final。