บทนำ

เพื่อนร่วมงานส่งฉบับแก้ไขสัญญาสองฉบับและขอให้คุณเปรียบเทียบความแตกต่าง คุณใส่ทั้งสองไฟล์ลงในบริการเปรียบเทียบของคุณ ผลลัพธ์ก็กลับมาและทุกอย่างดูปกติ สิ่งที่คุณไม่ได้เห็นคือเอกสารหนึ่งมีภาพที่เชื่อมโยงไปยัง URL และเซิร์ฟเวอร์ของคุณได้ติดต่อโฮสต์นั้นทันทีที่ไฟล์ถูกเปิด ไม่มีอะไรในผลลัพธ์บอกว่ามันเกิดขึ้น

นี่ไม่ใช่ข้อบกพร่อง – นี่คือสิ่งที่การโหลดเอกสารอย่างสมบูรณ์หมายถึง ไฟล์ OOXML สามารถอ้างอิงภาพที่อยู่บนเว็บเซิร์ฟเวอร์แทนที่จะอยู่ในแพ็กเกจ และทั้ง Word และไลบรารีใด ๆ ที่โหลดเอกสารอย่างถูกต้องก็จะแก้ไขการอ้างอิงนั้น GroupDocs.Comparison for .NET เปิดเผยคุณสมบัติสองอย่างบน LoadOptions ที่ให้คุณตัดสินใจว่าจะทำอย่างไร: SkipExternalResources และ WhitelistedResources

โดยรวมแล้วคุณสมบัติเหล่านี้ให้การกำหนดค่าได้สามแบบ และบทความนี้เปรียบเทียบทั้งสาม – ค่าเริ่มต้นที่ยืดหยุ่น, การบล็อกทุกอย่าง, และการบล็อกทุกอย่างยกเว้นการอ้างอิงที่ระบุชื่อไว้ ตอนจบคุณจะรู้ว่าจะเลือกแบบไหนสำหรับแหล่งที่มาของเอกสารแต่ละประเภท และสองข้อผิดพลาดที่ทำให้การตั้งค่าเหล่านี้ดูเหมือนว่าไม่ทำงาน

💡 ตัวอย่างทำงานเต็มรูปแบบ: block-external-resources-on-document-load-dotnet – โครงการคอนโซลที่สามารถรันได้ซึ่งให้บริการภาพที่อ้างอิงเองและบันทึกทุกคำขอ เพื่อให้คุณเห็นการทำงานของแต่ละการตั้งค่า

ที่ซ่อนการอ้างอิงภายนอก

ก่อนที่จะเลือกการตั้งค่า ควรเข้าใจว่าคุณกำลังเลือกอะไร .docx มีการอ้างอิงภายนอกอยู่สองตำแหน่งที่แตกต่างกันและง่ายต่อการพลาดเพราะไม่มีตำแหน่งใดที่มองเห็นในข้อความของเอกสาร

ตำแหน่งแรกคือความสัมพันธ์ใน word/_rels/document.xml.rels ที่มี TargetMode="External" และ URL แบบเต็ม ภาพจะแสดงในเนื้อหาเป็นรูปวาดที่ชี้ไปที่ความสัมพันธ์ตาม ID ดังนั้น URL เองจะไม่ปรากฏใกล้กับเนื้อหาที่มันส่งผล

ตำแหน่งที่สองคือโค้ดฟิลด์ INCLUDEPICTURE ในเนื้อหาเอกสาร ที่เก็บ URL ไว้ในคำสั่งฟิลด์ Word จะแก้ไขเมื่อหน้าแสดงผล; ไลบรารีเปรียบเทียบจะแก้ไขเมื่อเอกสารโหลด

กลไกทั้งสองเคารพสองตัวเลือกการโหลดที่อธิบายไว้ด้านล่าง ซึ่งสำคัญเพราะเอกสารอาจใช้ได้ทั้งสองหรืออย่างใดอย่างหนึ่ง การอ้างอิงที่คุณพบในไฟล์ความสัมพันธ์ไม่ได้เป็นหลักฐานว่ามีการอ้างอิงในฟิลด์โค้ดหรือไม่

วิธีที่ 1: ค่าเริ่มต้น – แก้ไขการอ้างอิง

SkipExternalResources มีค่าเริ่มต้นเป็น false ดังนั้นเอกสารที่โหลดโดยไม่มีการกำหนดค่าจะมีการแก้ไขการอ้างอิงระยะไกล:

LoadOptions loadOptions = new LoadOptions
{
    SkipExternalResources = false
};

using (Comparer comparer = new Comparer(sourcePath, loadOptions))
{
    comparer.Add(targetPath, loadOptions);
    comparer.Compare(outputPath);
}

นี่ให้ความแม่นยำสูงสุด: เอกสารที่เปรียบเทียบจะมีทุกอย่างที่อ้างอิงไว้, เหมือนกับที่ Word จะเรนเดอร์ หากเป็นเอกสารที่แอปพลิเคชันของคุณหรือเทมเพลตสร้างขึ้น, ที่ทุก URL ชี้ไปยังโครงสร้างพื้นฐานที่คุณควบคุม, นี่เป็นตัวเลือกที่ถูกต้อง – และภาพที่เชื่อมโยงหายไปอาจทำให้การเปรียบเทียบให้ข้อมูลที่หลอกลวง

ค่าใช้จ่ายคือการที่ทุกการอ้างอิงจะถูกติดต่อ, ไม่ว่าใครเป็นผู้ใส่ไว้ นอกจากนี้ยังมีค่าใช้จ่ายด้านเวลาโดยไม่เกี่ยวกับความเชื่อถือ: URL ที่ไม่สามารถแก้ได้จะทำให้การโหลดต้องรอจนการเชื่อมต่อครบถ้วนในทุกการเปรียบเทียบ

วิธีที่ 2: บล็อกทุกทรัพยากรภายนอก

คุณสมบัติเพียงอย่างเดียวที่ปิดการแก้ไขการอ้างอิงระยะไกลสำหรับเอกสารนั้น:

LoadOptions loadOptions = new LoadOptions
{
    SkipExternalResources = true
};

using (Comparer comparer = new Comparer(sourcePath, loadOptions))
{
    comparer.Add(targetPath, loadOptions);
    comparer.Compare(outputPath);
}

ไม่มีคำขอใดถูกส่ง ภาพที่อ้างอิงจะไม่มีในผลลัพธ์ และ – นี่คือส่วนที่ควรชัดเจน – สิ่งอื่นไม่เปลี่ยนแปลง การตั้งค่ากำหนดว่าอะไรจะถูกโหลด, ไม่ได้กำหนดวิธีการค้นหาความแตกต่าง, ดังนั้นการเปลี่ยนแปลงเชิงข้อความและโครงสร้างระหว่างสองเอกสารจะถูกตรวจพบเช่นเดิม สิ่งเดียวที่คุณเสียคือความสามารถในการตรวจจับการเปลี่ยนแปลง ภายใน ภาพที่อ้างอิง, ซึ่งไม่เคยถูกโหลด

นี่เป็นการกำหนดค่าที่ควรใช้เป็นฐานสำหรับเอกสารที่คุณไม่ได้สร้าง: การอัปโหลดของผู้ใช้ในเว็บแอป, ไฟล์ที่รับมาทางอีเมล, หรือเอกสารใด ๆ ที่เปรียบเทียบบนเอเจนต์การสร้างที่ไม่คาดหวังการร้องขอออกไป มันเป็นการบล็อกทั้งหมดหรือไม่มีเลย – ภาพที่คุณต้องการจริง ๆ จะถูกบล็อกพร้อมกับอื่น ๆ, และผลลัพธ์ก็จะไม่มีภาพนั้นโดยไม่มีการแจ้งเตือน

วิธีที่ 3: บล็อกทุกอย่างยกเว้นการอ้างอิงที่ระบุชื่อ

การกำหนดค่าที่สามคือการที่ให้ผลตอบแทนจากการอ่านอย่างละเอียด WhitelistedResources รับค่าเป็น List<string> และจะถูกตรวจสอบเฉพาะเมื่อ SkipExternalResources เป็น 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);
}

รายการที่ใส่เป็น ส่วนของ URL, ไม่ใช่ชื่อไฟล์ แต่ละรายการจะถูกจับคู่กับ URL ของการอ้างอิง, และการจับคู่ที่ใดก็ได้ใน URL จะยอมรับทรัพยากรนั้น นี่คือเหตุผลที่ทำให้ whitelist พกพาได้: "includepicture-field.png" จะยอมรับภาพไม่ว่ามีสคีม, โฮสต์ หรือพาธใดก็ตาม, ดังนั้นรายการเดียวกันจึงทำงานได้ทั้งในสภาพแวดล้อมการพัฒนาและการผลิตโดยไม่ต้องแก้ไข

คุณสมบัติเช่นเดียวกันก็อาจทำให้เกิดปัญหาในทางกลับกัน ส่วนที่สั้นหรือทั่วไป – logo.png, หรือแย่กว่า, .png – อาจจับคู่กับการอ้างอิงที่คุณไม่ต้องการให้อนุญาต เลือกส่วนที่เฉพาะพอที่จะระบุทรัพยากรที่คุณต้องการเท่านั้น

ในตัวอย่างการอ้างอิงนี้ การกำหนดค่านี้จะดึงภาพที่อยู่ใน whitelist และบล็อกภาพที่อ้างอิงที่สองซึ่งไม่มีรายการใดครอบคลุม การบันทึกคำขอจะแสดงสามคำขอ ในขณะที่ค่าเริ่มต้นที่ยืดหยุ่นสร้างห้าคำขอ และแสดงชื่อไฟล์ที่อยู่ใน whitelist เท่านั้น

ควรใช้การกำหนดค่าแบบใด?

จับคู่การตั้งค่ากับแหล่งที่มาของเอกสาร เอกสารที่แอปพลิเคชันหรือเทมเพลตของคุณสร้างขึ้นสามารถใช้ค่าเริ่มต้นได้, เพราะทุก URL ชี้ไปยังโครงสร้างพื้นฐานที่คุณควบคุมอยู่แล้ว เอกสารใด ๆ ที่มาจากภายนอก – การอัปโหลดของผู้ใช้, ไฟล์แนบอีเมล, ไฟล์ของบุคคลที่สาม – ควรใช้ SkipExternalResources = true เพิ่มส่วน WhitelistedResources ที่แคบเฉพาะเมื่อการอ้างอิงที่เชื่อถือได้จริง ๆ จำเป็นต้องแก้ไข

การเปรียบเทียบทั้งสาม

ข้อกังวล ค่าเริ่มต้น ข้ามทั้งหมด ข้าม + รายชื่อที่อนุญาต
คุณสมบัติที่ต้องตั้งค่า 0 1 2
คำขอออก อ้างอิงทั้งหมด ไม่มี เฉพาะที่อยู่ในรายการที่อนุญาต
การควบคุมต่ออ้างอิง ไม่มี ไม่มี มี
URL ที่เสียทำให้โหลดช้า มี ไม่มี เฉพาะที่อยู่ในรายการที่อนุญาต
เหมาะสำหรับ เอกสารที่คุณสร้าง เอกสารจากแหล่งอื่น เทมเพลตที่เชื่อถือได้ในเนื้อหาไม่เชื่อถือ

การตัดสินใจขึ้นอยู่กับที่มาของเอกสารมากกว่าประสิทธิภาพ เอกสารที่ระบบของคุณสร้างขึ้นสามารถใช้ค่าเริ่มต้นได้ เอกสารจากภายนอกควรบล็อก whitelist ควรใช้ส่วน URL ที่แคบเฉพาะเมื่อมีการอ้างอิงที่เชื่อถือได้จริง ๆ – เช่นเทมเพลตองค์กรที่ดึงภาพหัวเรื่องจาก URL ภายใน, ในรายงานที่ผู้เขียนแทรกภาพจากที่ใดก็ได้

สองข้อผิดพลาด

ทั้งสองข้อทำให้เกิดอาการเดียวกัน: คุณตั้งค่าตัวเลือกแล้วดูเหมือนว่าไม่มีผล

Whitelist โดยไม่มีสวิตช์ WhitelistedResources จะถูกตรวจสอบเฉพาะเมื่อ SkipExternalResources เป็น true หากตั้งค่าแยกคนเดียวมันจะไม่มีผลเลย – ไม่มีการบล็อกให้มันทำข้อยกเว้น หาก whitelist ดูเหมือนถูกละเลย ให้ตรวจสอบสิ่งนี้เป็นอันดับแรก

ตัวเลือกบนแหล่งที่มาเท่านั้น นี่เป็นข้อที่ละเอียดกว่า ตัวเลือกการโหลดอธิบายวิธีที่ หนึ่ง เอกสารถูกโหลด ตัวสร้าง Comparer รับตัวเลือกสำหรับแหล่งที่มา; ทุกการเรียก Add() รับตัวเลือกสำหรับเป้าหมายนั้น:

using (Comparer comparer = new Comparer(sourcePath, loadOptions))
{
    comparer.Add(targetPath, loadOptions);
    comparer.Compare(outputPath);
}

ถ้าคุณส่งตัวเลือกไปยังคอนสตรัคเตอร์แล้วลืมส่งให้ Add() แหล่งที่มาจะได้รับการปกป้องในขณะที่เป้าหมายทุกอันยังคงดึงการอ้างอิงของมัน การเปรียบเทียบจะสำเร็จ, ผลลัพธ์ดูสมเหตุสมผล, แต่ครึ่งหนึ่งของเอกสารของคุณยังคงติดต่อเครือข่าย เมื่อแหล่งที่มาและเป้าหมายต้องการการจัดการที่ต่างกัน ให้ส่ง LoadOptions แยกกัน – นั่นคือเหตุผลที่ API รับค่าตัวเลือกต่อเอกสาร

ตรวจสอบว่ามันทำงานจริงหรือไม่

ทรัพยากรที่ถูกบล็อกจะทิ้งร่องรอยแทบไม่มี เอกสารผลลัพธ์จะขาดภาพ, ซึ่งดูคล้ายกับเอกสารที่ไม่มีภาพเลย การอ่านไฟล์ผลลัพธ์จึงเป็นวิธีที่แย่ในการยืนยันว่าการตั้งค่ามีผล

ให้ดูที่ด้านเซิร์ฟเวอร์แทน ตัวอย่างการอ้างอิงใช้วิธีนี้โดยเจตนา: มันเริ่ม HTTP listener เล็ก ๆ บนพอร์ต loopback ที่ว่าง, เขียนเอกสารสาธิตที่ชี้ไปที่พอร์ตนั้น, และบันทึกทุกคำขอที่ได้รับ, พิมพ์จำนวนต่อการเปรียบเทียบ ห้าคำขอ, แล้วศูนย์, แล้วสาม คำขอ การตรวจสอบเครือข่ายกับแหล่งที่มาของเอกสารจริงของคุณก็ให้ความมั่นใจเช่นเดียวกัน

สรุป

สามการกำหนดค่า, กฎการตัดสินใจหนึ่งข้อ: ให้เอกสารที่คุณสร้างไว้ใช้ค่าเริ่มต้น, ตั้งค่า SkipExternalResources = true สำหรับทุกอย่างอื่น, และ whitelist ส่วน URL ที่แคบเฉพาะเมื่อการอ้างอิงที่เชื่อถือได้ต้องแก้ไขจริง ๆ

จากนั้นตรวจสอบสองสิ่งที่ทำให้การทำงานถูกยกเลิกโดยเงียบ – whitelist โดยไม่มี SkipExternalResources = true, และตัวเลือกที่ส่งไปยังคอนสตรัคเตอร์ Comparer แต่ไม่ได้ส่งให้ทุกการเรียก Add() – และยืนยันจากด้านเซิร์ฟเวอร์แทนไฟล์ผลลัพธ์

แหล่งข้อมูลเพิ่มเติม