💡 Voll funktionsfähiges Beispiel auf GitHub verfügbar:
compare-encrypted-pdf-and-word-documents-dotnet
Der alte Weg war schmerzhaft
Zwei Versionen eines Liefervertrags landen in Ihrem Posteingang. Beide sind passwortgeschützt, jedes mit einem anderen Passwort, und jemand benötigt eine markierte Kopie, die die Änderungen zeigt. Die Vergleichsbibliothek, die Sie verwenden, erwartet Klartext‑Eingaben, also wächst die Pipeline um einen Schritt: Beide Dateien in einen temporären Ordner entschlüsseln, die Klartext‑Kopien vergleichen und dann daran denken, sie zu löschen. Dieser temporäre Ordner ist nun das schwächste Glied in einem Workflow, der gerade deshalb existiert, weil die Dokumente sensibel sind.
Es gibt eine zweite Variante desselben Problems, die leichter zu übersehen ist. Einige Teams überspringen den temporären Ordner und entschlüsseln stattdessen in den Speicher, was das Aufräum‑Problem löst, aber nicht das Format‑Problem: Die Entschlüsselungs‑API unterscheidet sich je nach Format, sodass die Unterstützung verschlüsselter Tabellenkalkulationen nach verschlüsselten PDFs einen zweiten Integrationsaufwand bedeutet und nicht nur eine zweite Code‑Zeile.
Die Kosten liegen nicht hauptsächlich im Entschlüsselungsaufruf – sie liegen in allem, was drumherum passiert. Klartext‑Kopien müssen irgendwo geschrieben, bei jedem Beendigungsweg (einschließlich Fehlermodi) bereinigt und aus Backups sowie Crash‑Dumps herausgehalten werden. Ein auf diese Weise erzeugtes Diff wird standardmäßig ungeschützt geliefert, sodass das Ergebnis aus zwei verschlüsselten Eingaben die eine Datei in der Kette wird, die jeder öffnen kann.
Die wirklichen Kosten des Entschlüsselungs‑Umwegs: ein temporäres Verzeichnis, das Klartext‑Kopien von Dokumenten enthält, die aus einem Grund verschlüsselt wurden, mit einer Aufräum‑Logik, die bei jedem Fehlerpfad korrekt sein muss.
Es gibt einen besseren Weg
Passwortgeschützter Vergleich ist eine GroupDocs.Comparison‑Funktion für .NET, die verschlüsselte PDF‑, DOCX‑, XLSX‑ und PPTX‑Dateien direkt öffnet und entscheidet, welches Passwort das Vergleichsergebnis schützt. Kein Entschlüsselungsschritt, keine Klartext‑Zwischenschritte: Das Passwort reist zusammen mit dem Dokument in den eigentlichen Vergleich, als Eigenschaft von LoadOptions.
Bevor wir beginnen, benötigen Sie:
- .NET 8.0 SDK oder neuer
- GroupDocs.Comparison 26.9.0 (temporäre Lizenz)
- Zwei verschlüsselte Dokumente desselben Formats sowie deren Passwörter
Installation mit einem Befehl:
dotnet add package GroupDocs.Comparison
Der neue Weg: Verschlüsselte Dokumente direkt in den Comparer laden
Das folgende Beispiel vergleicht zwei verschlüsselte PDFs – die Quelle öffnet sich mit 1234, das Ziel mit 4321 – und schreibt eine einzige Ergebnisdatei, in die die Änderungen inline eingefügt werden. Unterschiedliche Passwörter sind absichtlich, weil dort der erste Fehler liegt.
Schritt 1 – Jeder Dokument ein eigenes LoadOptions zuweisen
Ein Comparer hält eine Quelle und beliebig viele Ziele, und jedes Dokument trägt seinen eigenen Schutz. Das Passwort der Quelle wird dem Konstruktor übergeben; das Passwort jedes Ziels wird seinem eigenen Add‑Aufruf übergeben.
// One LoadOptions per document - the constructor's options unlock the
// source only, and never reach the targets.
using var comparer = new Comparer("source.pdf",
new LoadOptions { Password = "1234" });
comparer.Add("target.pdf", new LoadOptions { Password = "4321" });
Das ist das Detail, das viele überrascht. Einen einzigen LoadOptions‑Parameter an den Konstruktor zu übergeben und zu erwarten, dass er auch die Ziele abdeckt, ist die häufigste Fehlerquelle – und weil der Fehler zur falschen Zeit auftritt, wird er dort nicht angezeigt, wo man nach ihm suchen würde.
Schritt 2 – Entscheiden, was das Ergebnis schützt
CompareOptions.PasswordSaveOption wählt den Schutz des Outputs: None, Source, Target oder User. Der Standard ist None, wodurch zwei verschlüsselte Eingaben stillschweigend zu einem ungeschützten Ergebnis werden.
// Inline markup, and the result reuses the source document's password.
var options = new PdfCompareOptions
{
DisplayMode = PdfCompareOptions.ComparisonDisplayMode.Inline,
PasswordSaveOption = PasswordSaveOption.Source
};
comparer.Compare("Result/1-pdf-inline.pdf", options);
Wichtige Punkte:
- PasswordSaveOption:
Sourceverwendet das Quell‑Passwort für das Ergebnis. Wählen SieUserzusammen mitSaveOptions.Password, um ein neues Passwort zu vergeben. - ComparisonDisplayMode: befindet sich innerhalb von
PdfCompareOptionsund bietet außerdemSideBySideundInterleaved.WordCompareOptionsdefiniert ein eigenes Enum gleichen Namens mit anderen Werten, sodass das bloße Namen‑Verwenden nicht kompiliert – qualifizieren Sie es.
Schritt 3 – Das Ergebnis mit einem eigenen Passwort schützen
Wenn das Diff an Prüfer geht, die keines der Original‑Passwörter besitzen sollen, nimmt PasswordSaveOption.User den Wert aus SaveOptions.Password statt ein Eingabepasswort wiederzuverwenden.
var compareOptions = new PdfCompareOptions
{
DisplayMode = PdfCompareOptions.ComparisonDisplayMode.Inline,
PasswordSaveOption = PasswordSaveOption.User
};
var saveOptions = new SaveOptions { Password = "5678" };
comparer.Compare("Result/4-own-password.pdf", saveOptions, compareOptions);
Beide Objekte werden an die dreifache Compare‑Überladung übergeben. Das alleinige Setzen von SaveOptions.Password ändert nichts – erst der Enum‑Wert aktiviert das Passwort auf der Speicher‑Seite. Das Ergebnis dieses Aufrufs öffnet sich mit 5678 und verwirft 1234.
Warum fängt mein try/catch um den Comparer kein falsches Passwort ab?
Weil der Konstruktor das Dokument nie öffnet. Er speichert nur den Pfad, ebenso wie Add. Beide Dokumente werden erst beim Aufruf von Compare gelesen, und dort wird PasswordProtectedFileException mit der Meldung Password is missing geworfen. Ein falsches Passwort verhält sich identisch: Es wird stillschweigend beim Konstruktor akzeptiert und erst später bei Compare abgelehnt.
Deshalb sollten Sie den Vergleichsaufruf schützen, nicht den Konstruktor. Ich habe das auf die harte Tour herausgefunden, indem ich die Konstruktion in ein try gepackt und beobachtet habe, wie eine verschlüsselte Datei erst drei Zeilen später beim Vergleich fehlschlägt. Das Repository gibt jede Phase aus, was die Reihenfolge beim ersten Lesen klar macht:
using var comparer = new Comparer("source.pdf"); // succeeds
comparer.Add("target.pdf"); // succeeds
comparer.Compare("Result/unreachable.pdf"); // throws here
Gegenüberstellung: Vorher vs. Nachher
| Vorher (zuerst entschlüsseln) | Nachher (GroupDocs.Comparison) | |
|---|---|---|
| Pipeline‑Schritte | Entschlüsseln, vergleichen, temporäre Kopien löschen | Vergleichen |
| Klartext auf Festplatte | Zwei Kopien, Aufräumen bei jedem Fehlerpfad | Keine |
| Ergebnis‑Schutz | Separater Re‑Verschlüsselungsschritt | Ein PasswordSaveOption‑Wert |
| Format‑Abdeckung | Entschlüsselungs‑Tools je Format | Ein LoadOptions.Password für PDF, DOCX, XLSX, PPTX |
| Benötigter Code | Entschlüsselungs‑Hilfsmittel + Vergleich | 4 Zeilen |
Die Vergleichsfunktionen ändern sich bei verschlüsselten Eingaben nicht. Anzeige‑Modi, Zusammenfassungsseiten und Stilerkennung verhalten sich exakt wie bei Klartext‑Dateien, weil der Schutz vollständig in der Lade‑Schicht gehandhabt wird.
Diese Schichtung macht die Format‑Abdeckung günstig. LoadOptions.Password ist eine einfache string‑Eigenschaft, und dieselbe Eigenschaft entsperrt PDF, DOCX, XLSX und PPTX – der Lade‑Code im Word‑Beispiel weiter unten ist Zeichen‑für‑Zeichen derselbe wie in den PDF‑Beispielen. Nur die Options‑Klasse ändert sich, und das nur, weil jedes Format unterschiedliche Rendering‑Optionen bietet. Das Hinzufügen von verschlüsselter Tabellenkalkulation‑Unterstützung zu Code, der bereits verschlüsselte PDFs vergleicht, kostet im Lade‑Pfad nichts.
Praxisbeispiel: Vertrags‑Redlining zwischen Kanzleien
Ein Rechts‑Team erhält jede Revision eines Vertrags verschlüsselt, wobei das Passwort pro Austausch rotiert wird, damit ein geleaktes Passwort nicht die gesamte Historie offenbart. Der prüfende Partner benötigt pro Runde ein markiertes Dokument, und nach Aufbewahrungs‑Regeln darf die markierte Kopie nicht ungeschützt auf einem Dateiserver liegen.
Zwei Einstellungen decken das ab. Jedes Dokument wird durch sein eigenes LoadOptions entsperrt, sodass Passwort‑Rotation keine Sonderbehandlung erfordert, und PasswordSaveOption.User gibt jedem verteilten Diff ein eigenes Passwort – eines, das den Vergleich öffnet und sonst nichts.
// Word revisions, so the reviewing partner can accept or reject each edit.
var options = new WordCompareOptions
{
DisplayMode = WordCompareOptions.ComparisonDisplayMode.Revisions,
PasswordSaveOption = PasswordSaveOption.Source
};
using var comparer = new Comparer("round3.docx",
new LoadOptions { Password = "1234" });
comparer.Add("round4.docx", new LoadOptions { Password = "4321" });
comparer.Compare("Result/redline.docx", options);
Was lässt sich sonst noch mit GroupDocs.Comparison machen?
- Mehr als zwei geschützte Dokumente vergleichen: Mehrere verschlüsselte Ziele zu einem Vergleich hinzufügen, für Word‑ und Präsentationsformate.
- Native Word‑Revisionen erzeugen:
WordCompareOptions.ComparisonDisplayMode.Revisionsschreibt Änderungen, die ein Prüfer direkt in Word annehmen oder ablehnen kann. - Externes Ressourcen‑Laden steuern: Remote‑Referenzen, die ein Dokument enthält, blockieren oder auf eine Whitelist setzen – ein weiteres
LoadOptions‑Sicherheitsmerkmal. - Zusammenfassungsseite erzeugen:
GenerateSummaryPagefügt dem Ergebnisdokument eine Übersicht der Änderungen hinzu.
Fazit
Der Entschlüsselungs‑Umweg drehte sich nie um den Vergleich selbst – er entstand, weil die Bibliothek das Eingabematerial nicht lesen konnte. Das Setzen von LoadOptions.Password pro Dokument eliminiert den temporären Ordner, die Aufräum‑Pfade und das ungeschützte Diff am Ende der Kette. Es bleiben nur drei Entscheidungen: ein Passwort pro Dokument, ein explizites PasswordSaveOption statt des Standard‑None und Fehlerbehandlung rund um Compare, wo der Fehler tatsächlich auftritt.
Bereit, Ihren Dokument‑Workflow zu automatisieren?
- Probieren Sie die kostenlose API‑Testversion
- Erkunden Sie das Laden passwortgeschützter Dokumente
- Lesen Sie den vollständigen Vergleichs‑Leitfaden für geschützte Dokumente
- Schauen Sie sich das Beispielprojekt auf GitHub an