Einführung
Ein Kollege sendet zwei Versionen eines Vertrags und bittet Sie, sie zu vergleichen. Sie legen beide in Ihren Vergleichsdienst, das Ergebnis kommt zurück und alles sieht normal aus. Was Sie nicht sehen, ist, dass eines dieser Dokumente ein verknüpftes Bild enthält, das auf eine URL verweist, und Ihr Server diesen Host kontaktiert, sobald die Datei geöffnet wird. Nirgends im Ergebnis wird angezeigt, dass das passiert ist.
Das ist kein Defekt – das ist das, was das korrekte Laden eines Dokuments bedeutet. Eine OOXML‑Datei kann ein Bild referenzieren, das auf einem Web‑Server liegt, anstatt im Paket enthalten zu sein, und sowohl Word als auch jede Bibliothek, die das Dokument korrekt lädt, löst diese Referenz auf. GroupDocs.Comparison für .NET stellt zwei Eigenschaften in LoadOptions bereit, mit denen Sie entscheiden können, ob das geschieht: SkipExternalResources und WhitelistedResources.
Zusammen ergeben sie drei Konfigurationen, und dieser Artikel vergleicht alle drei – die permissive Vorgabe, das Blockieren aller Ressourcen und das Blockieren aller außer benannten Referenzen. Am Ende wissen Sie, welche Einstellung Sie für eine gegebene Dokumentenquelle wählen sollten, und welche beiden Fehler dazu führen, dass diese Einstellungen scheinbar nicht funktionieren.
💡 Voll funktionsfähiges Beispiel: block-external-resources-on-document-load-dotnet – ein ausführbares Konsolenprojekt, das die referenzierten Bilder selbst bereitstellt und jede Anfrage protokolliert, sodass Sie jede Einstellung in Aktion sehen können.
Wo externe Referenzen versteckt sind
Bevor Sie eine Einstellung wählen, sollten Sie wissen, worum es geht. Eine .docx enthält externe Referenzen an zwei unterschiedlichen Stellen, und sie sind leicht zu übersehen, weil keine von beiden im Dokumenttext sichtbar ist.
Die erste ist eine Beziehung in word/_rels/document.xml.rels mit TargetMode="External" und einer absoluten URL. Das Bild erscheint im Textkörper als Zeichnung, die über die Beziehungs‑ID auf die Beziehung verweist, sodass die URL selbst nie in der Nähe des betroffenen Inhalts erscheint.
Die zweite ist ein INCLUDEPICTURE‑Feld im Dokumentkörper, das seine URL in einer Feld‑Anweisung enthält. Word löst sie beim Rendern der Seite auf; eine Vergleichsbibliothek löst sie beim Laden des Dokuments auf.
Beide Mechanismen respektieren die beiden unten beschriebenen Ladeoptionen, was wichtig ist, weil ein Dokument entweder das eine oder das andere oder beides verwenden kann. Eine Referenz, die Sie in der Beziehungsdatei entdeckt haben, beweist nicht, dass es keine zweite in einem Feldcode gibt.
Ansatz 1: Die Vorgabe – Referenzen werden aufgelöst
SkipExternalResources ist standardmäßig false, sodass ein Dokument ohne weitere Konfiguration seine entfernten Referenzen auflöst:
LoadOptions loadOptions = new LoadOptions
{
SkipExternalResources = false
};
using (Comparer comparer = new Comparer(sourcePath, loadOptions))
{
comparer.Add(targetPath, loadOptions);
comparer.Compare(outputPath);
}
Das liefert die höchste Treue: Die verglichenen Dokumente enthalten alles, worauf sie verweisen, exakt so, wie Word sie rendern würde. Für Dokumente, die Ihre eigene Anwendung oder Vorlagen erzeugt haben, bei denen jede Referenz‑URL auf Infrastruktur zeigt, die Sie betreiben, ist das die richtige Wahl – und ein fehlendes verknüpftes Bild könnte den Vergleich aktiv irreführen.
Der Nachteil ist, dass jede Referenz kontaktiert wird, egal wer sie dort platziert hat. Außerdem entsteht ein Zeitaufwand, der nichts mit Vertrauen zu tun hat: Eine URL, die nicht mehr aufgelöst werden kann, lässt das Laden die gesamte Verbindungsversuchsdauer warten, bei jedem einzelnen Vergleich.
Ansatz 2: Alles externe Ressourcen blockieren
Eine Eigenschaft schaltet die Auflösung entfernter Referenzen für dieses Dokument aus:
LoadOptions loadOptions = new LoadOptions
{
SkipExternalResources = true
};
using (Comparer comparer = new Comparer(sourcePath, loadOptions))
{
comparer.Add(targetPath, loadOptions);
comparer.Compare(outputPath);
}
Es wird keine Anfrage gesendet. Die referenzierten Bilder fehlen im Ergebnis, und – das ist wichtig zu verstehen – sonst ändert sich nichts. Die Einstellung bestimmt, was geladen wird, nicht, wie Unterschiede gefunden werden, sodass textuelle und strukturelle Änderungen zwischen den beiden Dokumenten genau wie zuvor erkannt werden. Das Einzige, was Sie verlieren, ist die Möglichkeit, eine Änderung innerhalb eines referenzierten Bildes zu erkennen, das nie geladen wurde.
Dies ist die Konfiguration, die Sie als Basis für Dokumente verwenden sollten, die Sie nicht erstellt haben: Benutzer‑Uploads in einer Web‑Anwendung, per E‑Mail empfangene Dateien, alles, was auf einem Build‑Agent verglichen wird, wo ausgehende Anfragen selten beabsichtigt sind. Es ist ein Alles‑oder‑Nichts‑Ansatz – ein verknüpftes Bild, das Sie tatsächlich wollten, wird zusammen mit den anderen blockiert, und das Ergebnis fehlt einfach, ohne dies anzukündigen.
Ansatz 3: Alles blockieren außer benannten Referenzen
Die dritte Konfiguration ist die, die bei genauer Lektüre belohnt. WhitelistedResources nimmt eine List<string> entgegen und wird nur berücksichtigt, wenn SkipExternalResources true ist:
LoadOptions loadOptions = new LoadOptions
{
SkipExternalResources = true,
WhitelistedResources = new List<string> { "includepicture-field.png" }
};
using (Comparer comparer = new Comparer(sourcePath, loadOptions))
{
comparer.Add(targetPath, loadOptions);
comparer.Compare(outputPath);
}
Die Einträge sind URL‑Fragmente, keine Dateinamen. Jeder Eintrag wird mit der Referenz‑URL verglichen, und ein Treffer irgendwo darin erlaubt diese Ressource. Das macht die Whitelist portabel: "includepicture-field.png" erlaubt das Bild, egal welches Schema, welcher Host und welcher Pfad davorstehen, sodass dieselbe Liste in Entwicklung und Produktion ohne Änderungen funktioniert.
Die gleiche Eigenschaft wirkt in die andere Richtung. Ein kurzes oder generisches Fragment – logo.png oder schlimmer, .png – kann Referenzen treffen, die Sie nie zulassen wollten. Wählen Sie ein Fragment, das spezifisch genug ist, um die eine Ressource zu identifizieren, die Sie gemeint haben.
Im Referenzbeispiel lädt diese Konfiguration das whitelisted Bild und lässt ein zweites referenziertes Bild, für das kein Eintrag existiert, blockiert. Das Anfragen‑Log zeigt drei Anfragen, während die permissive Vorgabe fünf erzeugte, und nennt nur die whitelisted Datei.
Welche Konfiguration sollten Sie verwenden?
Passen Sie die Einstellung an die Herkunft des Dokuments an. Dokumente, die Ihre eigene Anwendung oder Vorlagen erzeugt haben, können die Vorgabe beibehalten, weil jede Referenz‑URL auf Infrastruktur zeigt, die Sie bereits betreiben. Alles, was von außen kommt – Benutzer‑Uploads, E‑Mail‑Anhänge, Drittanbieter‑Dateien – rechtfertigt SkipExternalResources = true. Ergänzen Sie ein enges WhitelistedResources‑Fragment nur dann, wenn eine vertrauenswürdige Referenz wirklich aufgelöst werden muss.
Vergleich der drei Optionen
| Aspekt | Vorgabe | Alles blockieren | Blockieren + Whitelist |
|---|---|---|---|
| Zu setzende Eigenschaften | 0 | 1 | 2 |
| Ausgehende Anfragen | alle Referenzen | keine | nur whitelisted |
| Kontrolle pro Referenz | nein | nein | ja |
| Tote URL kostet Ladezeit | ja | nein | nur whitelisted |
| Ideal für | Dokumente, die Sie erstellt haben | Dokumente von überall sonst | vertrauenswürdige Vorlagen unter unzuverlässigem Inhalt |
Die Entscheidung folgt der Herkunft des Dokuments, nicht der Performance. Dokumente, die Ihre Systeme erzeugen, können die Vorgabe behalten. Dokumente von außen sollten blockiert werden. Whitelisten Sie nur dann, wenn eine bestimmte Referenz wirklich aufgelöst werden muss – etwa eine Unternehmensvorlage, die ihr Header‑Bild von einer internen URL zieht, während Berichte von Autoren beliebige Bilder einbetten.
Die beiden Fehler
Beide führen zum gleichen Symptom: Sie setzen die Option, und sie scheint nichts zu bewirken.
Eine Whitelist ohne den Schalter. WhitelistedResources wird nur berücksichtigt, wenn SkipExternalResources true ist. Allein gesetzt, bewirkt sie nichts – es gibt keine Blockierung, zu der sie eine Ausnahme bilden könnte. Wenn eine Whitelist ignoriert zu werden scheint, prüfen Sie das zuerst.
Optionen nur für die Quelle. Das ist der subtilere Fehler. Ladeoptionen beschreiben, wie ein Dokument geladen wird. Der Comparer‑Konstruktor nimmt die Optionen für die Quelle; jeder Add()‑Aufruf nimmt die Optionen für das jeweilige Ziel:
using (Comparer comparer = new Comparer(sourcePath, loadOptions))
{
comparer.Add(targetPath, loadOptions);
comparer.Compare(outputPath);
}
Geben Sie sie nur dem Konstruktor und vergessen Sie den Add()‑Aufruf, dann ist die Quelle geschützt, während jedes Ziel weiterhin seine Referenzen abruft. Der Vergleich gelingt, das Ergebnis wirkt plausibel, und die Hälfte Ihrer Dokumente greift noch ins Netzwerk. Wenn Quelle und Ziel unterschiedliche Behandlung benötigen, übergeben Sie separate LoadOptions‑Instanzen – genau dafür nimmt die API sie pro Dokument entgegen.
Verifizieren, dass es wirklich funktioniert hat
Eine blockierte Ressource hinterlässt fast keine Spuren. Das Ausgabedokument fehlt ein Bild, was fast genauso aussieht wie ein Dokument, das nie eines hatte. Das Lesen der Ergebnisdatei ist daher ein schlechter Weg, um zu bestätigen, dass die Einstellung wirksam war.
Beobachten Sie stattdessen die Servier‑Seite. Das Referenzbeispiel wählt bewusst diesen Ansatz: Es startet einen kleinen HTTP‑Listener auf einem freien Loopback‑Port, schreibt seine Demo‑Dokumente, die auf diesen Port zeigen, und protokolliert jede empfangene Anfrage, wobei es die Anzahl pro Vergleich ausgibt. Fünf Anfragen, dann null, dann drei. Ein Netzwerk‑Trace Ihrer echten Dokumentenquellen gibt Ihnen das gleiche Vertrauen.
Fazit
Drei Konfigurationen, eine Entscheidungsregel: Lassen Sie von Ihnen erzeugte Dokumente die Vorgabe behalten, setzen Sie SkipExternalResources = true für alles andere und whitelisten Sie ein enges URL‑Fragment nur dort, wo eine bestimmte vertrauenswürdige Referenz noch aufgelöst werden muss.
Prüfen Sie anschließend die beiden Dinge, die die Arbeit stillschweigend rückgängig machen – eine Whitelist ohne SkipExternalResources = true und Optionen, die nur dem Comparer‑Konstruktor, nicht jedem Add()‑Aufruf übergeben wurden – und verifizieren Sie vom Server‑Side‑Ende statt von der Ausgabedatei.
Weitere Ressourcen
- Konfiguration des Ladens externer Ressourcen in GroupDocs.Comparison für .NET – der Anwendungsfall‑Leitfaden mit Entscheidungs‑Matrix und FAQ
- block-external-resources-on-document-load-dotnet – das vollständige ausführbare Beispiel, inklusive des Loopback‑Bild‑Hosts
- Passwortgeschützte Dokumente laden –
LoadOptions.Password, die verwandte Einstellung mit derselben pro‑Dokument‑Gültigkeitsregel - Benutzerdefinierte Schriftarten laden – Auflösung nicht‑standardmäßiger Schriftarten zur Ladezeit mit
LoadOptions.FontDirectories - GroupDocs.Comparison für .NET API‑Referenz – vollständige Details zu
LoadOptionsund derComparer‑Klasse - Free support forum – Fragen zur Handhabung externer Ressourcen und zum Vergleichsverhalten