Versi rakitan di. NET bisa menjadi prospek yang membingungkan mengingat bahwa saat ini setidaknya ada tiga cara untuk menentukan versi untuk rakitan Anda.
Berikut adalah tiga atribut perakitan terkait versi utama:
// 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")]
Dengan konvensi, empat bagian dari versi ini disebut sebagai Versi Utama , Versi Kecil , Build , dan Revisi .
Hal AssemblyFileVersion
ini dimaksudkan untuk mengidentifikasi secara unik bangunan dari perakitan individu
Biasanya Anda akan secara manual mengatur Major dan Minor AssemblyFileVersion untuk mencerminkan versi perakitan, lalu menambah Build dan / atau Revisi setiap kali sistem build Anda mengkompilasi assembly. AssemblyFileVersion harus memungkinkan Anda mengidentifikasi secara unik susunan perakitan, sehingga Anda dapat menggunakannya sebagai titik awal untuk debugging masalah apa pun.
Pada proyek saya saat ini, kami memiliki server build yang menyandikan nomor daftar perubahan dari repositori kontrol sumber kami ke bagian Build and Revision dari AssemblyFileVersion. Ini memungkinkan kita untuk memetakan langsung dari rakitan ke kode sumbernya, untuk rakitan apa pun yang dihasilkan oleh server build (tanpa harus menggunakan label atau cabang dalam kontrol sumber, atau secara manual menyimpan catatan dari versi yang dirilis).
Nomor versi ini disimpan di sumber daya versi Win32 dan dapat dilihat saat melihat halaman properti Windows Explorer untuk perakitan.
CLR tidak peduli atau memeriksa AssemblyFileVersion.
Ini AssemblyInformationalVersion
dimaksudkan untuk mewakili versi seluruh produk Anda
AssemblyInformationalVersion dimaksudkan untuk memungkinkan versi yang koheren dari seluruh produk, yang dapat terdiri dari banyak majelis yang versi independen, mungkin dengan kebijakan versi berbeda, dan berpotensi dikembangkan oleh tim yang berbeda.
“Misalnya, versi 2.0 suatu produk mungkin mengandung beberapa rakitan; salah satu rakitan ini ditandai sebagai versi 1.0 karena ini adalah rakitan baru yang tidak dikirimkan dalam versi 1.0 dari produk yang sama. Biasanya, Anda mengatur bagian utama dan kecil dari nomor versi ini untuk mewakili versi publik produk Anda. Lalu Anda menambah komponen bangunan dan revisi setiap kali Anda mengemas produk lengkap dengan semua rakitannya. " - Jeffrey Richter, [CLR via C # (Edisi Kedua)] hlm. 57
CLR tidak peduli atau memeriksa AssemblyInformationalVersion.
Ini AssemblyVersion
adalah satu-satunya versi yang CLR pedulikan (tetapi peduli tentang keseluruhan AssemblyVersion
)
AssemblyVersion digunakan oleh CLR untuk mengikat majelis yang bernama kuat. Ini disimpan dalam tabel metadata manifes AssemblyDef dari perakitan yang dibangun, dan di tabel AssemblyRef dari setiap perakitan yang merujuknya.
Ini sangat penting, karena itu berarti bahwa ketika Anda mereferensikan sebuah rakitan yang bernama kuat, Anda terikat dengan ketat ke AssemblyVersion spesifik dari rakitan itu. Seluruh AssemblyVersion harus benar-benar cocok agar pengikatan berhasil. Misalnya, jika Anda mereferensikan versi 1.0.0.0 dari rakitan sangat bernama pada waktu-bangun, tetapi hanya versi 1.0.0.1 dari rakitan itu yang tersedia saat runtime, pengikatan akan gagal! (Anda kemudian harus mengatasi ini menggunakan Peredaran Pengikatan Majelis .)
Kebingungan apakah keseluruhan AssemblyVersion
harus cocok. (Ya, benar.)
Ada sedikit kebingungan di sekitar apakah seluruh AssemblyVersion harus sama persis agar perakitan dapat dimuat. Beberapa orang berada di bawah kepercayaan yang salah bahwa hanya bagian-bagian Besar dan Kecil dari AssemblyVersion yang harus cocok untuk mengikat agar berhasil. Ini adalah asumsi yang masuk akal, namun pada akhirnya tidak benar (pada. NET 3.5), dan ini sepele untuk memverifikasi ini untuk versi CLR Anda. Eksekusi kode contoh ini .
Pada mesin saya, beban perakitan kedua gagal, dan dua baris terakhir log fusi membuatnya sangat jelas mengapa:
.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.
Saya pikir sumber kebingungan ini mungkin karena Microsoft awalnya dimaksudkan untuk menjadi sedikit lebih lunak pada pencocokan ketat dari AssemblyVersion lengkap ini, dengan mencocokkan hanya pada bagian versi Major dan Minor:
"Saat memuat sebuah rakitan, CLR akan secara otomatis menemukan versi servis terinstal terbaru yang cocok dengan versi utama / minor dari rakitan yang diminta." - Jeffrey Richter, [CLR via C # (Edisi Kedua)] hlm. 56
Ini adalah perilaku dalam Beta 1 dari 1.0 CLR, namun fitur ini telah dihapus sebelum rilis 1.0, dan belum berhasil muncul kembali di .NET 2.0:
"Catatan: Saya baru saja menjelaskan bagaimana Anda harus memikirkan nomor versi. Sayangnya, CLR tidak memperlakukan nomor versi dengan cara ini. [Dalam. NET 2.0], CLR memperlakukan nomor versi sebagai nilai buram, dan jika sebuah rakitan bergantung pada versi 1.2.3.4 dari rakitan lain, CLR mencoba memuat versi 1.2.3.4 saja (kecuali pengalihan yang mengikat sudah ada. ). Namun demikian
Microsoft memiliki rencana untuk mengubah loader CLR di versi yang akan datang sehingga memuat build / revisi terbaru untuk versi mayor / minor dari sebuah perakitan. Sebagai contoh, pada versi CLR yang akan datang, jika loader mencoba menemukan versi 1.2.3.4 dari sebuah assembly dan versi 1.2.5.0 ada, loader dengan secara otomatis mengambil versi servis terbaru. Ini akan menjadi perubahan yang sangat disambut baik untuk loader CLR - saya tidak bisa menunggu. " - Jeffrey Richter, [CLR via C # (Edisi Kedua)] hlm. 164 (Menekankan tambang)
Karena perubahan ini masih belum diterapkan, saya pikir aman untuk mengasumsikan bahwa Microsoft telah melacak kembali maksud ini, dan mungkin sudah terlambat untuk mengubahnya sekarang. Saya mencoba mencari di web untuk mengetahui apa yang terjadi dengan rencana ini, tetapi saya tidak dapat menemukan jawaban. Saya masih ingin mencapai bagian bawahnya.
Jadi saya mengirim email kepada Jeff Richter dan menanyakannya langsung - saya pikir jika ada yang tahu apa yang terjadi, itu pasti dia.
Dia menjawab dalam waktu 12 jam, pada hari Sabtu pagi tidak kurang, dan mengklarifikasi bahwa .NET 1.0 Beta 1 loader benar-benar menerapkan mekanisme 'roll-forward' otomatis ini untuk mengambil Build and Revision terbaru dari sebuah majelis, tetapi perilaku ini adalah dikembalikan sebelum .NET 1.0 dikirimkan. Itu kemudian dimaksudkan untuk menghidupkan kembali ini tetapi tidak berhasil sebelum CLR 2.0 dikirimkan. Kemudian datang Silverlight, yang mengambil prioritas untuk tim CLR, sehingga fungsi ini tertunda lebih lanjut. Sementara itu, sebagian besar orang yang ada di sekitar zaman CLR 1.0 Beta 1 telah pindah, jadi tidak mungkin hal ini akan melihat cahaya hari, terlepas dari semua kerja keras yang telah dimasukkan ke dalamnya.
Tingkah laku saat ini, tampaknya, ada di sini untuk tinggal.
Perlu juga dicatat dari diskusi saya dengan Jeff bahwa AssemblyFileVersion hanya ditambahkan setelah penghapusan mekanisme 'roll-forward otomatis' - karena setelah 1.0 Beta 1, setiap perubahan pada AssemblyVersion adalah perubahan besar bagi pelanggan Anda, ada kemudian tidak ada tempat untuk menyimpan nomor build Anda dengan aman. AssemblyFileVersion adalah tempat yang aman, karena tidak pernah secara otomatis diperiksa oleh CLR. Mungkin lebih jelas seperti itu, memiliki dua nomor versi yang terpisah, dengan makna yang terpisah, daripada mencoba untuk membuat pemisahan antara bagian-bagian Mayor / Minor (melanggar) dan Build / Revisi (tidak melanggar) dari AssemblyVersion.
Intinya: Pikirkan baik-baik tentang kapan Anda mengubah AssemblyVersion
Moralnya adalah jika Anda mengirim rakitan yang akan dirujuk oleh pengembang lain, Anda harus sangat berhati-hati saat Anda melakukan (dan tidak) mengubah AssemblyVersion dari rakitan tersebut. Setiap perubahan pada AssemblyVersion akan berarti bahwa pengembang aplikasi harus mengkompilasi ulang terhadap versi baru (untuk memperbarui entri AssemblyRef tersebut) atau menggunakan pengalihan ikatan perakitan untuk secara manual mengesampingkan pengikatan.
- Jangan mengubah AssemblyVersion untuk rilis servis yang dimaksudkan untuk kompatibel.
- Apakah mengubah AssemblyVersion untuk rilis yang Anda tahu memiliki perubahan melanggar.
Coba lihat lagi atribut versi di 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")]
Perhatikan bahwa itu adalah AssemblyFileVersion yang berisi semua informasi servis yang menarik (bagian Revisi dari versi ini yang memberi tahu Anda apa Paket Layanan yang Anda pakai), sementara itu AssemblyVersion diperbaiki pada versi 2.0.0.0 yang lama dan membosankan. Setiap perubahan pada AssemblyVersion akan memaksa setiap aplikasi .NET mereferensikan mscorlib.dll untuk mengkompilasi ulang terhadap versi baru!