การกำหนดเวอร์ชันของแอสเซมบลีใน. NET อาจเป็นโอกาสที่ทำให้สับสนเนื่องจากปัจจุบันมีอย่างน้อยสามวิธีในการระบุเวอร์ชันสำหรับแอสเซมบลีของคุณ
นี่คือแอสเซมบลีที่เกี่ยวข้องกับรุ่นหลักที่สามที่:
// Assembly mscorlib, Version 2.0.0.0
[assembly: AssemblyFileVersion("2.0.50727.3521")]
[assembly: AssemblyInformationalVersion("2.0.50727.3521")]
[assembly: AssemblyVersion("2.0.0.0")]
โดยการประชุมในสี่ส่วนของรุ่นที่จะเรียกว่าเป็นรุ่นใหญ่ , ไมเนอร์เวอร์ชัน , รูปร่างและการทบทวน
AssemblyFileVersion
มีวัตถุประสงค์เพื่อระบุตัวตนของการสร้างของการชุมนุมของแต่ละบุคคล
โดยทั่วไปคุณจะตั้ง Major และ Minor AssemblyFileVersion ด้วยตนเองเพื่อให้สอดคล้องกับเวอร์ชันของชุดประกอบจากนั้นเพิ่ม Build และ / หรือ Revision ทุกครั้งที่ระบบประกอบของคุณคอมไพล์ชุดประกอบ AssemblyFileVersion ควรอนุญาตให้คุณระบุโครงสร้างของแอสเซมบลีที่ไม่ซ้ำกันเพื่อให้คุณสามารถใช้เป็นจุดเริ่มต้นสำหรับการดีบักปัญหาใด ๆ
ในโครงการปัจจุบันของฉันเรามีการสร้างเซิร์ฟเวอร์เข้ารหัสหมายเลขรายการการเปลี่ยนแปลงจากแหล่งเก็บข้อมูลการควบคุมของเราลงในส่วนการสร้างและการแก้ไขของ AssemblyFileVersion สิ่งนี้ทำให้เราสามารถแมปโดยตรงจากแอสเซมบลีไปยังซอร์สโค้ดของมันสำหรับแอสเซมบลีใด ๆ ที่สร้างโดยเซิร์ฟเวอร์การสร้าง (โดยไม่ต้องใช้ป้ายชื่อหรือสาขาในการควบคุมแหล่งที่มา
หมายเลขรุ่นนี้ถูกเก็บไว้ในทรัพยากรรุ่น Win32 และสามารถดูได้เมื่อดูหน้าคุณสมบัติ Windows Explorer สำหรับแอสเซมบลี
CLR ไม่สนใจหรือตรวจสอบ AssemblyFileVersion
AssemblyInformationalVersion
มีจุดมุ่งหมายเพื่อเป็นตัวแทนของรุ่นของผลิตภัณฑ์ทั้งหมดของคุณ
AssemblyInformationalVersion มีวัตถุประสงค์เพื่อให้การกำหนดเวอร์ชันที่สอดคล้องกันของผลิตภัณฑ์ทั้งหมดซึ่งอาจประกอบด้วยแอสเซมบลีจำนวนมากที่เป็นเวอร์ชันอิสระอาจมีนโยบายการกำหนดเวอร์ชันที่แตกต่างกันและอาจพัฒนาโดยทีมที่แตกต่างกัน
“ ตัวอย่างเช่นผลิตภัณฑ์เวอร์ชัน 2.0 อาจมีชุดประกอบหลายชุด หนึ่งในแอสเซมบลีเหล่านี้ถูกทำเครื่องหมายเป็นรุ่น 1.0 เนื่องจากเป็นแอสเซมบลีใหม่ที่ไม่ได้จัดส่งในเวอร์ชัน 1.0 ของผลิตภัณฑ์เดียวกัน โดยทั่วไปคุณตั้งค่าชิ้นส่วนหลักและรองของหมายเลขรุ่นนี้เพื่อเป็นตัวแทนรุ่นสาธารณะของผลิตภัณฑ์ของคุณ จากนั้นคุณเพิ่มส่วนการสร้างและการแก้ไขในแต่ละครั้งที่คุณบรรจุผลิตภัณฑ์ที่สมบูรณ์พร้อมชุดประกอบทั้งหมด” - Jeffrey Richter, [CLR ผ่าน C # (Second Edition)] p. 57
CLR ไม่สนใจหรือตรวจสอบ AssemblyInformationalVersion
AssemblyVersion
เป็นรุ่นเดียวที่ใส่ใจเกี่ยวกับ CLR ( แต่มันใส่ใจเกี่ยวกับทั้งหมดAssemblyVersion
)
AssemblyVersion ถูกใช้โดย CLR เพื่อเชื่อมโยงกับชุดประกอบที่ตั้งชื่ออย่างยิ่ง มันถูกเก็บไว้ในตาราง AssemblyDef รายการข้อมูลเมตาของแอสเซมบลีที่สร้างขึ้นและในตาราง AssemblyRef ของแอสเซมบลีใด ๆ ที่อ้างอิง
สิ่งนี้สำคัญมากเพราะหมายความว่าเมื่อคุณอ้างอิงชุดประกอบที่มีชื่ออย่างยิ่งคุณจะต้องผูกพันกับแอสเซมบลีรุ่นเฉพาะของแอสเซมบลีนั้นอย่างแน่นหนา AssemblyVersion ทั้งหมดจะต้องตรงกันทั้งหมดเพื่อให้การเชื่อมสำเร็จ ตัวอย่างเช่นถ้าคุณอ้างอิงรุ่น 1.0.0.0 ของแอสเซมบลีที่ตั้งชื่ออย่างยิ่งที่ build-time แต่เฉพาะแอสเซมบลีนั้นเวอร์ชัน 1.0.0.1 เท่านั้นที่พร้อมใช้งานในขณะใช้งานการเชื่อมโยงจะล้มเหลว! (จากนั้นคุณจะต้องแก้ไขปัญหานี้โดยใช้การเปลี่ยนเส้นทาง Assembly Binding )
ความสับสนเกี่ยวกับว่าทั้งหมดAssemblyVersion
จะต้องตรงกับ (ใช่.)
มีความสับสนเล็กน้อยเกี่ยวกับว่า AssemblyVersion ทั้งหมดจะต้องตรงกันทั้งหมดเพื่อให้สามารถโหลดชุดประกอบได้หรือไม่ บางคนอยู่ภายใต้ความเชื่อที่ผิด ๆ ว่ามีเพียงส่วนหลักและส่วนย่อยของ AssemblyVersion เท่านั้นที่จะต้องตรงกันเพื่อให้สามารถเข้าร่วมได้สำเร็จ นี่เป็นข้อสันนิษฐานที่สมเหตุสมผลอย่างไรก็ตามท้ายที่สุดมันไม่ถูกต้อง (ณ . NET 3.5) และเป็นเรื่องเล็กน้อยที่จะตรวจสอบเรื่องนี้สำหรับ CLR เวอร์ชันของคุณ เพียงรันโค้ดตัวอย่างนี้
ในเครื่องของฉันการโหลดแอสเซมบลีที่สองล้มเหลวและสองบรรทัดสุดท้ายของบันทึกการฟิวชั่นทำให้มันชัดเจนว่าทำไม:
.NET Framework Version: 2.0.50727.3521
---
Attempting to load assembly: Rhino.Mocks, Version=3.5.0.1337, Culture=neutral, PublicKeyToken=0b3305902db7183f
Successfully loaded assembly: Rhino.Mocks, Version=3.5.0.1337, Culture=neutral, PublicKeyToken=0b3305902db7183f
---
Attempting to load assembly: Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f
Assembly binding for failed:
System.IO.FileLoadException: Could not load file or assembly 'Rhino.Mocks, Version=3.5.0.1336, Culture=neutral,
PublicKeyToken=0b3305902db7183f' or one of its dependencies. The located assembly's manifest definition
does not match the assembly reference. (Exception from HRESULT: 0x80131040)
File name: 'Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f'
=== Pre-bind state information ===
LOG: User = Phoenix\Dani
LOG: DisplayName = Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f
(Fully-specified)
LOG: Appbase = [...]
LOG: Initial PrivatePath = NULL
Calling assembly : AssemblyBinding, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v2.0.50727\config\machine.config.
LOG: Post-policy reference: Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f
LOG: Attempting download of new URL [...].
WRN: Comparing the assembly name resulted in the mismatch: Revision Number
ERR: Failed to complete setup of assembly (hr = 0x80131040). Probing terminated.
ฉันคิดว่าแหล่งที่มาของความสับสนนี้อาจเป็นเพราะเดิมที Microsoft ตั้งใจที่จะผ่อนปรนในการจับคู่ AssemblyVersion ที่เข้มงวดนี้โดยการจับคู่เฉพาะในรุ่น Major และ Minor:
“ เมื่อโหลดแอสเซมบลี CLR จะค้นหาเวอร์ชันการให้บริการที่ติดตั้งล่าสุดโดยอัตโนมัติซึ่งตรงกับเวอร์ชันหลัก / รองของแอสเซมบลีที่ถูกร้องขอ” - Jeffrey Richter, [CLR ผ่าน C # (Second Edition)] p. 56
นี่เป็นพฤติกรรมในเบต้า 1 ของ 1.0 CLR อย่างไรก็ตามคุณลักษณะนี้ถูกลบออกก่อนการเปิดตัว 1.0 และไม่ได้จัดการให้ปรากฏขึ้นอีกครั้งใน. NET 2.0:
“ หมายเหตุ: ฉันเพิ่งอธิบายว่าคุณควรคิดถึงหมายเลขรุ่นอย่างไร น่าเสียดายที่ CLR ไม่ได้จัดการกับหมายเลขเวอร์ชันด้วยวิธีนี้ [ใน. NET 2.0], CLR จะถือว่าหมายเลขรุ่นเป็นค่าทึบและถ้าแอสเซมบลีขึ้นอยู่กับรุ่น 1.2.3.4 ของแอสเซมบลีอื่น CLR พยายามโหลดรุ่น 1.2.3.4 เท่านั้น (เว้นแต่ว่ามีการเปลี่ยนเส้นทางการผูกไว้ ) อย่างไรก็ตาม
ไมโครซอฟท์มีแผนที่จะเปลี่ยนโหลดเดอร์ของ CLR ในเวอร์ชันอนาคตเพื่อให้สามารถโหลดบิวด์การสร้าง / การแก้ไขล่าสุดสำหรับแอสเซมบลีรุ่นหลัก / รองที่กำหนด. ตัวอย่างเช่นในเวอร์ชันอนาคตของ CLR หากตัวโหลดพยายามค้นหาเวอร์ชัน 1.2.3.4 ของแอสเซมบลีและเวอร์ชัน 1.2.5.0 มีอยู่ตัวโหลดที่พร้อมรับเวอร์ชันการให้บริการล่าสุดโดยอัตโนมัติ นี่จะเป็นการเปลี่ยนแปลงที่น่ายินดีมากสำหรับตัวโหลด CLR - ฉันรอไม่ไหวแล้ว” - Jeffrey Richter, [CLR ผ่าน C # (Second Edition)] p. 164 (เหมืองเน้น)
เนื่องจากการเปลี่ยนแปลงนี้ยังไม่ได้รับการดำเนินการฉันคิดว่ามันปลอดภัยที่จะสมมติว่า Microsoft มีการติดตามย้อนกลับเกี่ยวกับความตั้งใจนี้และอาจช้าเกินไปที่จะเปลี่ยนแปลงในตอนนี้ ฉันพยายามค้นหาทางเว็บเพื่อค้นหาว่าเกิดอะไรขึ้นกับแผนเหล่านี้ แต่ฉันไม่พบคำตอบ ฉันยังต้องการที่จะไปที่ด้านล่างของมัน
ดังนั้นฉันจึงส่งอีเมล Jeff Richter และถามเขาโดยตรง - ฉันคิดว่าถ้าใครรู้ว่าเกิดอะไรขึ้นมันจะเป็นเขา
เขาตอบกลับภายใน 12 ชั่วโมงในเช้าวันเสาร์ไม่น้อยและชี้แจงว่าตัวโหลด. NET 1.0 Beta 1 ได้ใช้กลไก 'roll-forward-forward' นี้โดยอัตโนมัติเพื่อรับ Build และ Revision ของแอสเซมบลีล่าสุด แต่พฤติกรรมนี้ ย้อนกลับก่อนที่จะส่ง. NET 1.0 ภายหลังมีวัตถุประสงค์เพื่อฟื้นฟูสิ่งนี้ แต่ไม่ได้ทำก่อนที่จะส่ง CLR 2.0 จากนั้น Silverlight มาซึ่งให้ความสำคัญกับทีม CLR ดังนั้นการทำงานนี้จึงล่าช้าออกไปอีก ในขณะเดียวกันผู้คนส่วนใหญ่ที่อยู่ในยุค CLR 1.0 Beta 1 ได้ย้ายมาตั้งแต่ดังนั้นจึงไม่น่าที่สิ่งนี้จะเห็นแสงของวันแม้จะมีการทำงานหนักทั้งหมดที่ได้ใส่เข้าไปแล้ว
ดูเหมือนว่าพฤติกรรมปัจจุบันจะอยู่ที่นี่
นอกจากนี้ยังเป็นที่น่าสังเกตจากการสนทนาของฉันกับเจฟฟ์ว่า AssemblyFileVersion ถูกเพิ่มเข้ามาหลังจากการลบกลไก 'roll-forward' โดยอัตโนมัติหลังจากที่ 1.0 Beta 1 การเปลี่ยนแปลงใด ๆ ของ AssemblyVersion นั้นเป็นการเปลี่ยนแปลงที่ไม่ดีสำหรับลูกค้าของคุณ ไม่มีที่เก็บหมายเลขการสร้างของคุณอย่างปลอดภัย AssemblyFileVersion นั้นเป็นสวรรค์ที่ปลอดภัยเนื่องจาก CLR ไม่เคยตรวจสอบโดยอัตโนมัติ บางทีอาจเป็นเรื่องที่ชัดเจนกว่านั้นโดยมีหมายเลขรุ่นสองหมายเลขแยกกันโดยมีความหมายแยกต่างหากแทนที่จะพยายามแยกดังกล่าวระหว่าง Major / Minor (แบ่ง) และ Build / Revision (ไม่ทำลาย) ของ AssemblyVersion
บรรทัดล่าง: คิดอย่างรอบคอบเมื่อคุณเปลี่ยน AssemblyVersion
คุณธรรมคือถ้าคุณกำลังจัดส่งชุดประกอบที่นักพัฒนาคนอื่นกำลังจะอ้างอิงคุณจะต้องระมัดระวังอย่างมากเกี่ยวกับเมื่อคุณทำ (และไม่) เปลี่ยน AssemblyVersion ของชุดประกอบเหล่านั้น การเปลี่ยนแปลงใด ๆ ใน AssemblyVersion จะหมายความว่าผู้พัฒนาแอปพลิเคชันจะต้องรวบรวมใหม่กับเวอร์ชันใหม่ (เพื่ออัปเดตรายการ AssemblyRef เหล่านั้น) หรือใช้การเปลี่ยนเส้นทางการรวมแอสเซมบลีเพื่อแทนที่การผูกด้วยตนเอง
- อย่าเปลี่ยน AssemblyVersion สำหรับรุ่นที่ให้บริการซึ่งมีวัตถุประสงค์เพื่อให้ใช้งานร่วมกับรุ่นหลังได้
- ทำการเปลี่ยนแปลง AssemblyVersion สำหรับรุ่นที่คุณรู้ว่ามีการเปลี่ยนแปลง
เพียงดูที่คุณสมบัติของรุ่นอื่น ๆ บน mscorlib:
// Assembly mscorlib, Version 2.0.0.0
[assembly: AssemblyFileVersion("2.0.50727.3521")]
[assembly: AssemblyInformationalVersion("2.0.50727.3521")]
[assembly: AssemblyVersion("2.0.0.0")]
โปรดทราบว่านี่คือ AssemblyFileVersion ที่มีข้อมูลการบริการที่น่าสนใจทั้งหมด (เป็นส่วนการแก้ไขของรุ่นนี้ที่จะบอกคุณว่าคุณกำลังใช้ Service Pack อยู่) ในขณะที่ AssemblyVersion นั้นได้รับการแก้ไขที่เก่าน่าเบื่อ 2.0.0.0 การเปลี่ยนแปลงใด ๆ ใน AssemblyVersion จะบังคับให้แอปพลิเคชัน. NET ทุกตัวที่อ้างอิง mscorlib.dll เพื่อรวบรวมใหม่กับเวอร์ชันใหม่!