2017-04-21 1 views
2

Je génère un document Excel à partir de MVC en utilisant Open XML.Création d'un classeur en lecture seule à partir de MVC Controller avec OpenXML

Le code est comme ci-dessous:

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

} 

Ma méthode CreateExcelDoc est comme ci-dessous:

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

} 

Avec la méthode de création de la feuille Excel est en cours de téléchargement comme prévu. Cependant, je voulais que le classeur soit en lecture seule, donc essayer la méthode .Open passant le flux mem et le jeu isEditable à false mais je reçois un YSOD quand je frappe le contrôleur avec une erreur Exception Details: System.IO.FileFormatException: Archive file cannot be size 0.

Répondre

1

Une manière plus simple de rendre votre Excel uniquement en lecture est de Protect the worksheet (see Step 2 at link).

Le code OpenXML pour ce faire est une ligne par feuille:

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

J'ai poussé un new version of the reference implementation MVC qui utilise cette technique. Le SheetProtection semble être pris en charge dans Excel 2007, où le marquage en tant que Final est uniquement pris en charge depuis Excel 2013.

+0

c'est exactement ce dont j'ai besoin - Merci :) –

1

L'appel SpreadsheetDocument.Open ne résulte pas en un fichier en lecture seule. It merely opens the memory stream in read only mode. (isEditable is false) Cela verrouille le flux d'être modifié par le reste de votre code. Cela explique pourquoi vous avez probablement généré une amende Excel avant d'avoir ajouté cet appel, et pourquoi vous obtenez l'exception d'archivage vide après avoir ajouté cet appel. N'utilisez pas SpreadsheetDocument.Open à cette fin.

Je ne vous recommande pas d'essayer d'envoyer votre fichier Excel en tant que fichier en lecture seule. L'utilisateur peut le télécharger sur n'importe quel système d'exploitation et le renommer et modifier les autorisations de fichier comme il le souhaite. Ce que je recommande est d'ajouter le code openXML mark your Excel as final. Microsoft a ajouté cette fonctionnalité aux documents Office car elle décourage formellement les utilisateurs d'apporter des modifications au fichier au lieu de simples autorisations de fichiers. Toute modification apportée à l'un de ces fichiers nécessite un nouveau nom de fichier.

Le code OpenXml recommandé sera generate a Custom Property. Lorsque l'utilisateur téléchargera le fichier, il sera marqué comme Final pour décourager les modifications de l'utilisateur.

Voici la méthode qui ajoutera la propriété personnalisée:

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

J'ai écrit une application simple MVC qui génère un fichier Excel vide marqué comme final pour vous une implémentation de référence. The code is hosted on GitHub. Lorsque vous l'exécutez, cliquez sur le lien du menu le plus à droite "Télécharger Excel". Cela va télécharger un Excel avec un classeur nommé Walter's Workbook et aucune donnée. L'excel sera marqué comme final. Le code pour la propriété personnalisée a été généré avec l'outil de productivité OpenXML. Bonne chance pour votre projet.

+0

Très malade, essayez-le. Mon utilisateur final pourrait avoir une ancienne version de Excel..office 2003 probablement. Si la version finale ne fonctionne pas avec OpenXML, il faudra peut-être regarder dans une autre bibliothèque ... l'application est celle que j'ai déjà utilisée mais elle peut être coûteuse –