Introduction
Un collègue vous envoie deux révisions d’un contrat et vous demande d’en faire la comparaison. Vous déposez les deux fichiers dans votre service de comparaison, le résultat revient, et tout semble normal. Ce que vous n’avez pas vu, c’est que l’un de ces documents contenait une image liée pointant vers une URL, et que votre serveur a contacté cet hôte dès que le fichier a été ouvert. Rien dans la sortie ne vous indique que cela s’est produit.
Ce n’est pas un défaut – c’est ce que signifie charger un document fidèlement. Un fichier OOXML peut référencer une image qui vit sur un serveur web plutôt qu’à l’intérieur du paquet, et Word ainsi que toute bibliothèque qui charge correctement le document résolvent cette référence. GroupDocs.Comparison pour .NET expose deux propriétés sur LoadOptions qui vous permettent de décider s’il le fait : SkipExternalResources et WhitelistedResources.
Ensemble, elles offrent trois configurations, et cet article compare les trois — le comportement permissif par défaut, le blocage complet, et le blocage de tout sauf les références nommées. À la fin, vous saurez laquelle choisir selon la provenance du document, ainsi que les deux erreurs qui donnent l’impression que ces paramètres ne fonctionnent pas.
💡 Exemple complet fonctionnel : block-external-resources-on-document-load-dotnet – un projet console exécutable qui héberge les images référencées lui‑même et journalise chaque requête, afin que vous puissiez observer l’effet de chaque réglage.
Où les références externes se cachent
Avant de choisir un réglage, il est utile de savoir ce que vous choisissez. Un fichier .docx contient des références externes à deux endroits distincts, et elles sont faciles à manquer car aucune n’est visible dans le texte du document.
La première se trouve dans une relation dans word/_rels/document.xml.rels portant TargetMode="External" et une URL absolue. L’image apparaît dans le corps sous forme de dessin qui pointe vers la relation par son ID, de sorte que l’URL elle‑même n’apparaît jamais près du contenu qu’elle affecte.
La seconde est un champ de code INCLUDEPICTURE dans le corps du document, contenant son URL à l’intérieur d’une instruction de champ. Word la résout lors du rendu de la page ; une bibliothèque de comparaison la résout lors du chargement du document.
Les deux mécanismes respectent les deux options de chargement décrites ci‑dessous, ce qui est important car un document peut utiliser l’un ou l’autre, voire les deux. Une référence que vous avez repérée dans le fichier de relations ne prouve pas qu’il n’y a pas de seconde référence dans un champ de code.
Approche 1 : Le comportement par défaut – Références résolues
SkipExternalResources vaut false par défaut, donc un document chargé sans configuration a ses références distantes résolues :
LoadOptions loadOptions = new LoadOptions
{
SkipExternalResources = false
};
using (Comparer comparer = new Comparer(sourcePath, loadOptions))
{
comparer.Add(targetPath, loadOptions);
comparer.Compare(outputPath);
}
Cela offre la plus grande fidélité : les documents comparés contiennent tout ce qu’ils référencent, exactement comme Word les rendrait. Pour les documents que votre propre application ou vos modèles ont produits, où chaque URL de référence pointe vers une infrastructure que vous gérez, c’est le bon choix – et une image liée manquante pourrait rendre la comparaison trompeuse.
Le coût est que chaque référence est contactée, quel que soit son auteur. Il y a également un coût de temporisation qui n’a rien à voir avec la confiance : une URL de référence qui ne résout plus oblige le chargement à attendre toute la tentative de connexion, à chaque comparaison.
Approche 2 : Bloquer toutes les ressources externes
Une propriété désactive la résolution des références distantes pour ce document :
LoadOptions loadOptions = new LoadOptions
{
SkipExternalResources = true
};
using (Comparer comparer = new Comparer(sourcePath, loadOptions))
{
comparer.Add(targetPath, loadOptions);
comparer.Compare(outputPath);
}
Aucune requête n’est émise. Les images référencées sont absentes du résultat, et – c’est le point à préciser – rien d’autre ne change. Le réglage détermine ce qui est chargé, pas comment les différences sont détectées, de sorte que les modifications textuelles et structurelles entre les deux documents sont toujours détectées exactement comme avant. La seule chose que vous perdez est la capacité de détecter un changement à l’intérieur d’une image référencée, qui n’a jamais été chargée.
C’est la configuration à considérer comme votre référence de base pour les documents que vous n’avez pas créés : téléchargements d’utilisateurs dans une application web, fichiers reçus par e‑mail, tout ce qui est comparé sur un agent de build où une requête sortante est rarement souhaitée. C’est tout ou rien, cependant – une image liée que vous vouliez réellement est bloquée avec le reste, et le résultat se contente de l’omettre sans l’annoncer.
Approche 3 : Bloquer tout sauf les références nommées
La troisième configuration est celle qui récompense une lecture attentive. WhitelistedResources accepte une List<string> et n’est consultée que lorsque SkipExternalResources vaut true :
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);
}
Les entrées sont des fragments d’URL, pas des noms de fichiers. Chaque fragment est comparé à l’URL de référence, et une correspondance n’importe où dans celle‑ci autorise la ressource. C’est ce qui rend la liste blanche portable : "includepicture-field.png" autorise l’image quel que soit le schéma, l’hôte et le chemin qui la précèdent, de sorte que la même liste fonctionne en développement comme en production sans réécriture.
La même propriété fonctionne dans l’autre sens. Un fragment court ou générique – logo.png, ou pire, .png – peut correspondre à des références que vous n’aviez jamais l’intention d’autoriser. Choisissez un fragment suffisamment spécifique pour identifier la ressource unique que vous vouliez autoriser.
Dans l’exemple de référence, cette configuration récupère l’image blanche et laisse bloquée la seconde image référencée, qui n’est couverte par aucune entrée. Le journal des requêtes montre trois requêtes alors que le comportement permissif par défaut en produisait cinq, et ne nomme que le fichier de la liste blanche.
Quelle configuration choisir ?
Adaptez le réglage à la provenance du document. Les documents générés par votre propre application ou vos modèles peuvent conserver le comportement par défaut, car chaque URL de référence pointe vers une infrastructure que vous contrôlez déjà. Tout ce qui provient de l’extérieur – téléchargements d’utilisateurs, pièces jointes d’e‑mail, fichiers tiers – justifie SkipExternalResources = true. N’ajoutez un fragment WhitelistedResources étroit que lorsqu’une référence de confiance doit réellement être résolue.
Comparaison des trois
| Préoccupation | Par défaut | Tout bloquer | Bloquer + liste blanche |
|---|---|---|---|
| Propriétés à définir | 0 | 1 | 2 |
| Requêtes sortantes | toutes les références | aucune | uniquement celles de la liste blanche |
| Contrôle par référence | non | non | oui |
| Les URL mortes coûtent du temps de chargement | oui | non | uniquement celles de la liste blanche |
| Idéal pour | documents que vous avez produits | documents provenant d’ailleurs | modèles de confiance parmi du contenu non fiable |
La décision suit la provenance du document plutôt que les performances. Les documents générés par vos systèmes peuvent garder le comportement par défaut. Les documents provenant de l’extérieur justifient le blocage. Utilisez la liste blanche uniquement lorsqu’une référence spécifique doit absolument être résolue – par exemple un modèle d’entreprise qui récupère son image d’en‑tête depuis une URL interne, parmi des rapports dont les auteurs ont inséré des images depuis n’importe où.
Les deux erreurs
Ces deux erreurs produisent le même symptôme : vous définissez l’option, et il semble qu’elle ne fasse rien.
Une liste blanche sans l’interrupteur. WhitelistedResources n’est consultée que lorsque SkipExternalResources vaut true. Si elle est définie seule, elle ne fait absolument rien – il n’y a aucun blocage dont elle pourrait faire une exception. Si une liste blanche semble ignorée, vérifiez d’abord cela.
Options appliquées uniquement à la source. Celle‑ci est plus subtile. Les options de chargement décrivent comment un document est chargé. Le constructeur de Comparer prend les options pour la source ; chaque appel à Add() prend les options pour la cible :
using (Comparer comparer = new Comparer(sourcePath, loadOptions))
{
comparer.Add(targetPath, loadOptions);
comparer.Compare(outputPath);
}
Les passer au constructeur et oublier de les fournir à l’appel Add() protège la source tandis que chaque cible continue de récupérer ses références. La comparaison réussit, le résultat paraît plausible, et la moitié de vos documents continue de toucher le réseau. Lorsque source et cible nécessitent des traitements différents, passez des instances distinctes de LoadOptions – c’est précisément la raison pour laquelle l’API les accepte par document.
Vérifier que cela a réellement fonctionné
Une ressource bloquée laisse presque aucune trace. Le document de sortie ne contient pas l’image, ce qui ressemble à un document qui n’en a jamais eu. Lire le fichier de résultat est donc une mauvaise façon de confirmer que le réglage a été appliqué.
Surveillez plutôt le côté serveur. L’exemple de référence adopte délibérément cette approche : il démarre un petit écouteur HTTP sur un port de boucle libre, écrit ses documents de démonstration pointant vers ce port, et journalise chaque requête reçue, affichant le nombre par comparaison. Cinq requêtes, puis zéro, puis trois. Une trace réseau sur vos véritables sources de documents vous donne la même confiance.
Conclusion
Trois configurations, une règle de décision : laissez les documents que vous avez générés garder le comportement par défaut, définissez SkipExternalResources = true pour tout le reste, et ajoutez un fragment d’URL étroit à la liste blanche uniquement lorsqu’une référence de confiance doit encore être résolue.
Ensuite, vérifiez les deux points qui annulent silencieusement le travail – une liste blanche sans SkipExternalResources = true, et des options passées au constructeur de Comparer mais pas à chaque appel Add() – et validez du côté serveur plutôt que du fichier de sortie.
Ressources supplémentaires
- Configuration du chargement des ressources externes dans GroupDocs.Comparison pour .NET – le guide d’utilisation, avec la matrice de décision et la FAQ
- block-external-resources-on-document-load-dotnet – l’exemple complet exécutable, incluant l’hôte d’images en boucle locale
- Charger des documents protégés par mot de passe –
LoadOptions.Password, le paramètre frère avec la même règle de portée par document - Charger des polices personnalisées – résolution de polices non standard au moment du chargement avec
LoadOptions.FontDirectories - Référence API GroupDocs.Comparison pour .NET – détails complets sur
LoadOptionset la classeComparer - Free support forum – questions sur la gestion des ressources externes et le comportement de comparaison