我正在使用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);
}
}
我的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();
}
使用create方法,excel表正按预期下载。但是,我想让工作簿只读,所以尝试将.Open方法传递给mem流并将isEditable设置为false但是当我按下错误Exception Details: System.IO.FileFormatException: Archive file cannot be size 0.
答案 0 :(得分:2)
将excel只读的简单方法是Protect the worksheet (see Step 2 at link)。
执行此操作的OpenXML代码是每张一行:
workSheet.Append(new SheetProtection() { Sheet = true, Objects = true, Scenarios = true });
我推了一个使用这种技术的new version of the reference implementation MVC。 Excel 2007中似乎支持SheetProtection,其中仅在Excel 2013之后支持标记为Final。
答案 1 :(得分:1)
调用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代码。 Microsoft将此功能添加到Office文档中,因为它更正式地阻止用户对文件进行更改,而不是简单的文件权限。对其中一个文件的任何更改都需要新的文件名。
推荐的OpenXml代码将generate a 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;
}
我编写了一个简单的MVC应用程序,它生成一个标记为final的空Excel文件作为参考实现。 The code is hosted on GitHub。当您运行它时,单击最右侧的菜单链接“下载Excel”。这将下载一个名为Walter's Workbook的工作簿并且没有数据的Excel。 excel将标记为final。 Custom Property的代码是使用OpenXML Productivity Tool生成的。祝你的项目好运。