Apa perbedaan antara AssemblyVersion, AssemblyFileVersion, dan AssemblyInformationalVersion?

860

Ada tiga atribut versi perakitan. Apa perbedaannya? Apakah boleh jika saya menggunakan AssemblyVersiondan mengabaikan sisanya?


MSDN mengatakan:

  • AssemblyVersion :

    Menentukan versi perakitan yang dikaitkan.

  • AssemblyFileVersion :

    Menginstruksikan kompiler untuk menggunakan nomor versi spesifik untuk sumber daya versi file Win32. Versi file Win32 tidak harus sama dengan nomor versi majelis.

  • AssemblyInformationalVersion :

    Menentukan informasi versi tambahan untuk manifes perakitan.


Ini merupakan tindak lanjut dari Apa praktik terbaik untuk menggunakan Atribut Majelis?

Jakub Šturc
sumber

Jawaban:

907

AssemblyVersion

Di mana majelis lain yang merujuk majelis Anda akan melihat. Jika nomor ini berubah, majelis lain harus memperbarui referensi mereka ke majelis Anda! Hanya perbarui versi ini, jika rusak kompatibilitas. The AssemblyVersiondiperlukan.

Saya menggunakan format: major.minor . Ini akan menghasilkan:

[assembly: AssemblyVersion("1.0")]

Jika Anda mengikuti SemVer dengan ketat maka ini berarti Anda hanya memperbarui ketika perubahan besar , jadi 1.0, 2.0, 3.0, dll.

AssemblyFileVersion

Digunakan untuk penyebaran. Anda dapat menambah nomor ini untuk setiap penyebaran. Ini digunakan oleh program pengaturan. Gunakan untuk menandai majelis yang memiliki hal yang samaAssemblyVersion , tetapi dihasilkan dari bangunan yang berbeda.

Di Windows, itu dapat dilihat di properti file.

AssemblyFileVersion adalah opsional. Jika tidak diberikan, AssemblyVersion digunakan.

Saya menggunakan format: major.minor.patch.build , di mana saya mengikuti SemVer untuk tiga bagian pertama dan menggunakan buildnumber dari buildserver untuk bagian terakhir (0 untuk local build). Ini akan menghasilkan:

[assembly: AssemblyFileVersion("1.3.2.254")]

Ketahuilah bahwa System.Version menyebut bagian-bagian ini sebagai major.minor.build.revision!

AssemblyInformationalVersion

Versi produk perakitan. Ini adalah versi yang akan Anda gunakan ketika berbicara dengan pelanggan atau untuk ditampilkan di situs web Anda. Versi ini bisa berupa string, seperti ' 1.0 Release Calon '.

Ini AssemblyInformationalVersionopsional. Jika tidak diberikan, AssemblyFileVersion digunakan.

Saya menggunakan format: major.minor [.patch] [revisi as string] . Ini akan menghasilkan:

[assembly: AssemblyInformationalVersion("1.0 RC1")]
Rémy van Duijkeren
sumber
4
Untuk AssemblyFileVersion, "Jika memungkinkan, biarkan dihasilkan oleh MSBuild" - Mengapa? Anda baru saja menjelaskan alasan yang bagus untuk mengendalikannya secara manual :)
mo.
3
Peringatan pada format AssemblyInformationalVersion masih ada di VS2010 hari ini (21 Mei 2013) dan tautan Anda sudah mati.
reinierpost
22
Sayangnya Kelas Versi mendefinisikan major.minor[.build[.revision]]dan tidak major.minor.revision.builddemikian dalam jawaban yang diberikan angka build dan revisi akan ditukar jika Anda menggunakan properti kelas atau System.Reflection.Assembly.GetExecutingAssembly().GetName().Versionuntuk mendeteksi nomor build dan revisi.
thinkOfaNumber
9
@thinkOfaNumber Hak Anda tentang Kelas Versi, tapi itu cara versi Microsoft. Saya pribadi berpikir itu aneh untuk tidak memiliki buildnumber pada akhirnya dan itu sebabnya saya hanya menempatkan format saya sebagai contoh, berdasarkan Semantic Versioning . Anda bebas menggunakan cara Microsoft atau cara Anda sendiri tentunya.
Rémy van Duijkeren
6
Harus dicatat bahwa untuk AssemblyInformationalVersion, jika dihilangkan, AssemblyFileVersiondigunakan. Lalu AssemblyVersion jika keduanya dihilangkan.
Drazen Bjelovuk
588

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 AssemblyFileVersionini 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 AssemblyInformationalVersiondimaksudkan 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 AssemblyVersionadalah 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 AssemblyVersionharus 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!

Daniel Fortunov
sumber
9
Jawaban yang bagus Saya pikir poin paling penting yang Anda buat - dan apa yang seharusnya direkomendasikan oleh MS secara eksplisit - adalah membuat perubahan pada AssemblyVersion jika dan hanya jika versi baru merusak kompatibilitas ke belakang.
mwolfe02
1
Salah satu pertanyaan yang berulang kali saya tanyakan pada diri saya adalah kapan saya harus mengubah masing-masing nomor versi ini, poin-poin Anda pada AssemblyVersion menambahkan kejelasan yang baik untuk ini dan seluruh jawaban adalah bacaan yang menarik.
RyanfaeScotland
Saya melihat banyak jawaban yang menjelaskan konsep di balik tiga hal ini. Tetapi bagaimana mereka berhubungan dengan nomor versi yang dapat diedit di properti proyek? Ketika Anda mengklik Informasi Perakitan ... Anda mendapatkan opsi untuk mengubah dua versi. Dan di sana mengubah Versi Perakitan mengubah folder tempat user.config ditemukan, dan mengubah Versi File mengubah nomor versi yang ditunjukkan ketika Anda mengklik kanan file exe dan pergi ke propertinya. Jadi, bagaimana kedua nomor versi itu sesuai dengan AssemblyVersion, AssemblyFileVersion, dan AssemblyInformationalVersion?
Kyle Delaney
Tautan ke posting blog yang Anda tulis semula memberikan 404. Apakah ada lokasi baru untuk itu?
Rob K
@RobK: Ah, permintaan maaf. Situs web itu tidak aktif, tetapi seluruh konten posting blog direproduksi dalam jawaban sehingga Anda tidak kehilangan apa pun. Saya akan menghapus tautan yang rusak sekarang.
Daniel Fortunov
43

AssemblyVersioncukup banyak tetap internal untuk. NET, sementara AssemblyFileVersionapa yang dilihat Windows. Jika Anda pergi ke properti perakitan yang duduk di direktori dan beralih ke tab versi, theAssemblyFileVersion itulah yang akan Anda lihat di bagian atas. Jika Anda mengurutkan file berdasarkan versi, inilah yang digunakan oleh Explorer.

Itu AssemblyInformationalVersion memetakan ke "Versi Produk" dan dimaksudkan untuk menjadi murni "manusia-digunakan".

AssemblyVersiontentu saja yang paling penting, tetapi saya juga tidak akan melewatkannya AssemblyFileVersion. Jika Anda tidak menyediakan AssemblyInformationalVersion, kompiler menambahkannya untuk Anda dengan menghapus bagian "revisi" dari nomor versi Anda dan meninggalkan major.minor.build.

Bob King
sumber
23

AssemblyInformationalVersiondan AssemblyFileVersionditampilkan ketika Anda melihat informasi "Versi" pada file melalui Windows Explorer dengan melihat properti file. Atribut-atribut ini sebenarnya dikompilasi ke VERSION_INFOsumber daya yang dibuat oleh kompiler.

AssemblyInformationalVersionadalah nilai "Versi produk". AssemblyFileVersionadalah nilai "Versi file".

Ini AssemblyVersionkhusus untuk .NET assemblies dan digunakan oleh .NET assembly loader untuk mengetahui versi perakitan mana yang akan dimuat / diikat saat runtime.

Dari semua ini, satu-satunya yang mutlak diperlukan oleh .NET adalah AssemblyVersionatribut. Sayangnya itu juga dapat menyebabkan masalah paling banyak ketika itu berubah tanpa pandang bulu, terutama jika Anda kuat memberi nama majelis Anda.

Scott Dorman
sumber
9

Untuk menjaga pertanyaan ini tetap terkini, perlu disorot yang AssemblyInformationalVersiondigunakan oleh NuGet dan mencerminkan versi paket termasuk akhiran pra-rilis apa pun.

Sebagai contoh, AssemblyVersion 1.0.3. * Dikemas dengan inti asp.net dotnet-cli

dotnet pack --version-suffix ci-7 src/MyProject

Menghasilkan paket dengan versi 1.0.3-ci-7 yang dapat Anda periksa dengan refleksi menggunakan:

CustomAttributeExtensions.GetCustomAttribute<AssemblyInformationalVersionAttribute>(asm);
KCD
sumber
7

Perlu dicatat beberapa hal lain:

1) Seperti ditunjukkan dalam dialog Windows Explorer Properties untuk file assembly yang dihasilkan, ada dua tempat yang disebut "Versi file". Yang terlihat di header dialog menunjukkan AssemblyVersion, bukan AssemblyFileVersion.

Di bagian informasi versi lain, ada elemen lain yang disebut "Versi File". Di sinilah Anda bisa melihat apa yang dimasukkan sebagai AssemblyFileVersion.

2) AssemblyFileVersion hanyalah teks biasa. Itu tidak harus sesuai dengan batasan skema penomoran yang dilakukan oleh AssemblyVersion (<build> <65K, misalnya). Itu bisa 3.2. <Rilis tag teks>. <datetime>, jika Anda suka. Sistem build Anda harus mengisi token.

Selain itu, itu tidak tunduk pada penggantian wildcard yang AssemblyVersion. Jika Anda hanya memiliki nilai "3.0.1. *" Di AssemblyInfo.cs, itulah yang akan ditampilkan di informasi Versi lain-> elemen Versi File.

3) Saya tidak tahu dampaknya pada installer menggunakan sesuatu selain nomor versi file numerik.

DavidM
sumber
2

Ketika AssemblyVersion majelis diubah, Jika memiliki nama yang kuat, majelis referensi perlu dikompilasi ulang, jika tidak majelis tidak memuat! Jika tidak memiliki nama yang kuat, jika tidak secara eksplisit ditambahkan ke file proyek, itu tidak akan disalin ke direktori output ketika membangun sehingga Anda mungkin kehilangan bergantung majelis, terutama setelah membersihkan direktori output.

linquize
sumber
Ini sangat menarik! Bisakah Anda menguraikan sedikit pada bagian "tidak akan disalin ke direktori keluaran"? Mungkin tautan ke tempat perilaku ini didefinisikan. Saya tidak pernah mengerti mengapa beberapa dependensi tidak langsung kadang-kadang disalin, tetapi tidak selalu. Ini harus 100% terkait dengan itu.
julealgon