简体   繁体   English

使用OpenXML从MVC Controller中读取工作簿

[英]Making workbook readonly from MVC Controller with OpenXML

I am generating an Excel Document from MVC using Open XML. 我正在使用Open XML从MVC生成Excel文档。

The code is as below: 代码如下:

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);
  }

}

My CreateExcelDoc method is as below: 我的CreateExcelDoc方法如下:

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();

}

With the create method the excel sheet is downloading as expected. 使用create方法,excel表正按预期下载。 However, I wanted to make the workbook read-only so was trying the .Open method passing the mem stream and the isEditable set to false but I am getting a YSOD when I hit the controller with an Error Exception Details: System.IO.FileFormatException: Archive file cannot be size 0. 但是,我想将工作簿设置为只读,因此尝试将.Open方法传递给mem流并将isEditable设置为false但是当我使用错误Exception Details: System.IO.FileFormatException: Archive file cannot be size 0.命中控制器时,我得到一个YSOD Exception Details: System.IO.FileFormatException: Archive file cannot be size 0.

A simpler way of making your excel read only is to Protect the worksheet (see Step 2 at link) . 使excel只读的简单方法是保护工作表(参见链接中的步骤2)

The OpenXML code to do this is one line per sheet: 执行此操作的OpenXML代码是每张一行:

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

I have pushed a new version of the reference implementation MVC that uses this technique. 我已经推出了使用这种技术的新版本的参考实现 MVC。 The SheetProtection seems to be supported in Excel 2007, where the marking as Final is only supported since Excel 2013. Excel 2007中似乎支持SheetProtection,其中仅在Excel 2013之后支持标记为Final。

The call SpreadsheetDocument.Open does not result in a read only file. 调用SpreadsheetDocument.Open不会生成只读文件。 It merely opens the memory stream in read only mode. 它只是以只读模式打开内存流。 ( isEditable is false) This locks the stream from being changed by the rest your code. isEditable为false)这将isEditable流被其余代码更改。 This explains why you were likely generating an excel fine before you added that call, and why you are getting the empty archive exception after you added that call. 这解释了为什么您可能在添加该调用之前生成excel,以及在添加该调用后获得空存档异常的原因。 Do not use SpreadsheetDocument.Open for that purpose. 不要为此目的使用SpreadsheetDocument.Open

I do not recommend you try to send your Excel as a read only file. 我不建议您尝试将Excel作为只读文件发送。 The user can download it on any operating system and rename it and change the file permissions as they want to. 用户可以在任何操作系统上下载它并重命名它并根据需要更改文件权限。

What I recommend is add openXML code that mark your Excel as final . 我建议添加openXML代码, 将Excel标记为final Microsoft added this capability to Office documents as it more formally discourages users from making future changes to the file instead of simple file permissions. Microsoft将此功能添加到Office文档中,因为它更正式地阻止用户对文件进行更改,而不是简单的文件权限。 Any changes to one of these files, requires a new filename. 对其中一个文件的任何更改都需要新的文件名。

The recommended OpenXml code will generate a Custom Property so when the user downloads the file, it will be marked as Final to discourage user edits. 推荐的OpenXml代码将生成自定义属性,因此当用户下载文件时,它将被标记为“最终”以阻止用户编辑。

Here is the method that will add the custom property: 以下是添加自定义属性的方法:

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;
    }

I have written a simple MVC app that generates an empty Excel file marked as final for you as a reference implementation. 我编写了一个简单的MVC应用程序,它生成一个标记为final的空Excel文件作为参考实现。 The code is hosted on GitHub . 代码托管在GitHub上 When you run it, click on the rightmost menu link "Download Excel". 当您运行它时,单击最右侧的菜单链接“下载Excel”。 This will download an Excel with one Workbook named Walter's Workbook and no data. 这将下载一个名为Walter's Workbook的工作簿并且没有数据的Excel。 The excel will be marked as final. excel将标记为final。 The code for Custom Property was generated with the OpenXML Productivity Tool. Custom Property的代码是使用OpenXML Productivity Tool生成的。 Good luck with your project. 祝你的项目好运。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM