Jakie są różnice między AssemblyVersion, AssemblyFileVersion i AssemblyInformationalVersion?

860

Istnieją trzy atrybuty wersji zestawu. Jakie są różnice? Czy to w porządku, jeśli AssemblyVersionużyję i zignoruję resztę?


MSDN mówi:

  • Montaż Wersja :

    Określa wersję przypisywanego zestawu.

  • AssemblyFileVersion :

    Nakazuje kompilatorowi użycie określonego numeru wersji dla zasobu wersji pliku Win32. Wersja pliku Win32 nie musi być taka sama jak numer wersji zestawu.

  • AssemblyInformationalVersion :

    Definiuje dodatkowe informacje o wersji manifestu zestawu.


To jest kontynuacja Jakie są najlepsze praktyki korzystania z atrybutów asemblera?

Jakub Šturc
źródło

Odpowiedzi:

907

AssemblyVersion

Gdzie będą wyglądały inne zespoły, które odnoszą się do twojego zestawu. Jeśli liczba ta ulegnie zmianie, inne zespoły muszą zaktualizować swoje odwołania do Twojego zestawu! Zaktualizuj tę wersję tylko wtedy, gdy psuje zgodność wsteczną. Jest AssemblyVersionto wymagane.

Używam formatu: major.minor . Spowodowałoby to:

[assembly: AssemblyVersion("1.0")]

Jeśli ściśle przestrzegasz SemVer, oznacza to, że aktualizujesz tylko wtedy, gdy główne zmiany, czyli 1.0, 2.0, 3.0 itp.

AssemblyFileVersion

Służy do wdrażania. Możesz zwiększyć tę liczbę dla każdego wdrożenia. Jest używany przez programy instalacyjne. Użyj go, aby oznaczyć zespoły, które mają takie same AssemblyVersion, ale są generowane z różnych kompilacji.

W systemie Windows można go wyświetlić we właściwościach pliku.

AssemblyFileVersion jest opcjonalna. Jeśli nie podano, zostanie użyta wartość AssemblyVersion.

Używam formatu: major.minor.patch.build , w którym śledzę SemVer przez pierwsze trzy części i używam numeru kompilacji serwera buildserver dla ostatniej części (0 dla wersji lokalnej). Spowodowałoby to:

[assembly: AssemblyFileVersion("1.3.2.254")]

Pamiętaj, że System.Version nazywa te części jako major.minor.build.revision!

AssemblyInformationalVersion

Wersja produktu zestawu. Jest to wersja, której będziesz używać podczas rozmowy z klientami lub do wyświetlania w swojej witrynie. Ta wersja może być ciągiem, np. „ 1.0 Release Candidate ”.

AssemblyInformationalVersionJest opcjonalne. Jeśli nie podano, zostanie użyta wartość AssemblyFileVersion.

Używam formatu: major.minor [.patch] [wersja jako ciąg] . Spowodowałoby to:

[assembly: AssemblyInformationalVersion("1.0 RC1")]
Rémy van Duijkeren
źródło
4
W przypadku AssemblyFileVersion „Jeśli to możliwe, niech zostanie wygenerowane przez MSBuild” - Dlaczego? Właśnie wyjaśniłeś dobry powód, aby ręcznie to kontrolować :)
mo.
3
Ostrzeżenie w formacie AssemblyInformationalVersion nadal istnieje w VS2010 dzisiaj (21 maja 2013 r.), A Twój link nie działa.
reinierpost
22
Niestety klasa wersji definiuje, major.minor[.build[.revision]]a nie major.minor.revision.buildw podanej odpowiedzi numery kompilacji i wersji zostałyby zamienione, gdybyś używał właściwości klasy lub System.Reflection.Assembly.GetExecutingAssembly().GetName().Versionwykrył numery kompilacji i wersji.
thinkOfaNumber
9
@thinkOfaNumber Masz prawo do Klasy wersji, ale to sposób na wersjonowanie przez Microsoft. Osobiście uważam, że to dziwne, że nie ma numeru kompilacji na końcu i dlatego podam tylko mój format jako przykład oparty na wersjach semantycznych . Możesz swobodnie korzystać ze sposobu Microsoft lub własnego sposobu oczywiście.
Rémy van Duijkeren
6
Należy zauważyć, że dla AssemblyInformationalVersion, jeśli zostanie pominięty, AssemblyFileVersionjest używany. Wtedy AssemblyVersion , gdy oba są pomijane.
Drazen Bjelovuk
588

Wersjonowanie zestawów w .NET może być mylącą perspektywą, biorąc pod uwagę, że istnieją obecnie co najmniej trzy sposoby określenia wersji dla zestawu.

Oto trzy główne atrybuty zespołu związane z wersją:

// 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")]

Umownie, cztery części wersji określane są jako główna wersja , wersja pomocnicza , produkcji i rewizji .

Ma AssemblyFileVersionon na celu jednoznaczną identyfikację kompilacji poszczególnych zespołów

Zazwyczaj ręcznie ustawiasz główny i mniejszy plikFiltVersion tak, aby odzwierciedlał wersję zestawu, a następnie zwiększaj liczbę kompilacji i / lub wersji za każdym razem, gdy system kompilacji kompiluje zestaw. AssemblyFileVersion powinien umożliwiać unikalną identyfikację kompilacji zestawu, dzięki czemu można go użyć jako punktu wyjścia do debugowania wszelkich problemów.

W moim bieżącym projekcie serwer kompilacji koduje numer listy zmian z naszego repozytorium kontroli źródła do części kompilacji i wersji AssemblyFileVersion. To pozwala nam mapować bezpośrednio z zestawu do jego kodu źródłowego, dla dowolnego zestawu wygenerowanego przez serwer kompilacji (bez konieczności używania etykiet lub rozgałęzień w kontroli źródła lub ręcznego przechowywania jakichkolwiek zapisów wydanych wersji).

Ten numer wersji jest przechowywany w zasobie wersji Win32 i można go zobaczyć podczas przeglądania stron właściwości Eksploratora Windows dla zestawu.

CLR nie przejmuje się ani nie sprawdza AssemblyFileVersion.

Ma AssemblyInformationalVersionon reprezentować wersję całego produktu

AssemblyInformationalVersion ma na celu umożliwienie spójnego wersjonowania całego produktu, który może składać się z wielu zestawów, które są niezależnie wersjonowane, być może z różnymi politykami wersjonowania i potencjalnie opracowywanych przez różne zespoły.

„Na przykład wersja 2.0 produktu może zawierać kilka zestawów; jeden z tych zespołów jest oznaczony jako wersja 1.0, ponieważ jest to nowy zespół, który nie został dostarczony w wersji 1.0 tego samego produktu. Zazwyczaj główne i podrzędne części tego numeru wersji są ustawione jako publiczna wersja Twojego produktu. Następnie zwiększasz części kompilacji i wersji za każdym razem, gdy pakujesz kompletny produkt ze wszystkimi jego zespołami. ” - Jeffrey Richter, [CLR przez C # (wydanie drugie)] str. 57

CLR nie przejmuje się ani nie analizuje AssemblyInformationalVersion.

Jest AssemblyVersionto jedyna wersja, na której zależy CLR (ale dba o całość AssemblyVersion)

AssemblyVersion jest używany przez CLR do wiązania z silnie nazwanymi zestawami. Jest on przechowywany w tabeli metadanych manifestu AssemblyDef zestawu złożonego oraz w tabeli AssemblyRef każdego zestawu, który się do niego odwołuje.

Jest to bardzo ważne, ponieważ oznacza to, że gdy odwołujesz się do mocno nazwanego zestawu, jesteś ściśle związany z konkretną wersją AssemblyVersion tego zestawu. Całe AssemblyVersion musi być dokładnie dopasowane, aby powiązanie zakończyło się powodzeniem. Na przykład, jeśli odwołujesz się do wersji 1.0.0.0 silnie nazwanego zestawu w czasie kompilacji, ale tylko wersja 1.0.0.1 tego zestawu jest dostępna w czasie wykonywania, wiązanie nie powiedzie się! (Następnie trzeba będzie obejść ten problem przy użyciu przekierowania wiązania zespołu ).

Zamieszanie co do tego, czy całość AssemblyVersionmusi się zgadzać. (Tak.)

Istnieje niewielkie zamieszanie wokół tego, czy całe AssemblyVersion musi być dokładnie dopasowane, aby zespół mógł zostać załadowany. Niektórzy ludzie są w fałszywym przekonaniu, że tylko główne i mniejsze części AssemblyVersion muszą się zgadzać, aby wiązanie się powiodło. Jest to rozsądne założenie, jednak ostatecznie jest niepoprawne (od .NET 3.5) i weryfikacja tego w przypadku wersji CLR jest banalna. Po prostu uruchom ten przykładowy kod .

Na mojej maszynie ładowanie drugiego zestawu kończy się niepowodzeniem, a ostatnie dwa wiersze dziennika zgrzewania doskonale wyjaśniają, dlaczego:

.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.

Myślę, że przyczyną tego zamieszania jest prawdopodobnie to, że Microsoft pierwotnie zamierzał być nieco łagodniejszy w tym ścisłym dopasowaniu pełnego zestawu AssemblyVersion, dopasowując tylko części w wersji Major i Minor:

„Podczas ładowania zestawu CLR automatycznie znajdzie najnowszą zainstalowaną wersję serwisową, która odpowiada głównej / podrzędnej wersji żądanego zestawu.” - Jeffrey Richter, [CLR przez C # (wydanie drugie)] str. 56

Takie zachowanie zachodziło w wersji Beta 1 CLR 1.0, jednak ta funkcja została usunięta przed wydaniem 1.0 i nie udało jej się ponownie wyświetlić w .NET 2.0:

„Uwaga: Właśnie opisałem, jak powinieneś myśleć o numerach wersji. Niestety CLR nie traktuje numerów wersji w ten sposób. [W .NET 2.0] CLR traktuje numer wersji jako wartość nieprzezroczystą, a jeśli zestaw zależy od wersji 1.2.3.4 innego zestawu, CLR próbuje załadować tylko wersję 1.2.3.4 (chyba że istnieje przekierowanie wiązania ). Jednak Microsoft planuje zmienić moduł ładujący CLR w przyszłej wersji, aby ładował najnowszą kompilację / wersję dla danej głównej / mniejszej wersji zestawu. Na przykład w przyszłej wersji CLR, jeśli moduł ładujący próbuje znaleźć wersję 1.2.3.4 zestawu i istnieje wersja 1.2.5.0, moduł ładujący z automatycznie pobiera najnowszą wersję serwisową. Będzie to bardzo mile widziana zmiana w module ładującym CLR - ja nie mogę się doczekać. ” - Jeffrey Richter, [CLR przez C # (wydanie drugie)] str. 164 (moje podkreślenie)

Ponieważ ta zmiana nadal nie została zaimplementowana, uważam, że można bezpiecznie założyć, że Microsoft dokonał wstecznej oceny tego zamiaru i być może jest już za późno, aby to zmienić. Próbowałem przeszukać sieć, aby dowiedzieć się, co się stało z tymi planami, ale nie mogłem znaleźć odpowiedzi. Nadal chciałem dojść do sedna.

Wysłałem więc e-maila do Jeffa Richtera i zapytałem go bezpośrednio - pomyślałem, że jeśli ktokolwiek wie, co się stanie, to będzie on.

Odpowiedział w ciągu 12 godzin, nie mniej w sobotę rano, i wyjaśnił, że moduł ładujący .NET 1.0 Beta 1 wdrożył ten mechanizm „automatycznego przechodzenia do przodu” polegający na pobieraniu najnowszej dostępnej kompilacji i wersji zestawu, ale takie zachowanie było cofnięte przed wysłaniem .NET 1.0. Później zamierzano to przywrócić, ale nie udało się to przed wysłaniem CLR 2.0. Potem pojawił się Silverlight, który miał priorytet dla zespołu CLR, więc ta funkcja uległa dalszemu opóźnieniu. W międzyczasie większość ludzi, którzy byli w pobliżu w czasach CLR 1.0 Beta 1, przeprowadziła się, więc jest mało prawdopodobne, że ujrzy światło dzienne, pomimo całej ciężkiej pracy, którą już w to włożyliśmy.

Wydaje się, że obecne zachowanie pozostanie.

Warto również zauważyć z mojej dyskusji z Jeffem, że AssemblyFileVersion został dodany dopiero po usunięciu mechanizmu „automatycznego przechodzenia do przodu” - ponieważ po 1.0 Beta 1 każda zmiana w AssemblyVersion była przełomową zmianą dla twoich klientów, wtedy było nigdzie nie można bezpiecznie zapisać numeru kompilacji. AssemblyFileVersion to bezpieczna przystań, ponieważ nigdy nie jest automatycznie sprawdzana przez CLR. Być może jest to w ten sposób jaśniejsze, mając dwa oddzielne numery wersji, z odrębnymi znaczeniami, zamiast próbować dokonać tego oddzielenia między częściami Major / Minor (łamanie) i Build / Revision (niełamanie) w AssemblyVersion.

Podsumowując: Zastanów się, kiedy zmienisz swój AssemblyVersion

Morał polega na tym, że jeśli wysyłasz zestawy, do których będą się odwoływać inni programiści, musisz zachować szczególną ostrożność, kiedy zmieniasz (i nie zmieniasz) wersję AssemblyVersion tych zestawów. Wszelkie zmiany w AssemblyVersion będą oznaczać, że programiści aplikacji będą musieli albo ponownie skompilować z nową wersją (aby zaktualizować te wpisy AssemblyRef), albo użyć przekierowań powiązania zestawu, aby ręcznie zastąpić powiązanie.

  • Nie zmieniaj AssemblyVersion dla wydania serwisowego, które ma być kompatybilne wstecz.
  • Czy zmienić AssemblyVersion dla uwolnienia że wiesz posiada łamanie zmian.

Jeszcze raz spójrz na atrybuty wersji na 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")]

Zauważ, że to AssemblyFileVersion zawiera wszystkie interesujące informacje dotyczące serwisowania (jest to wersja Revision tej wersji, która mówi ci, na którym dodatku Service Pack jesteś), tymczasem AssemblyVersion jest naprawiony na nudnym starym 2.0.0.0. Każda zmiana w AssemblyVersion zmusiłaby każdą aplikację .NET odwołującą się do mscorlib.dll do ponownej kompilacji z nową wersją!

Daniel Fortunov
źródło
9
Świetna odpowiedź. Myślę, że najważniejszym punktem, który podniosłeś - i co MS powinien wyraźnie zalecić - jest wprowadzenie zmian w AssemblyVersion tylko wtedy, gdy nowa wersja zepsuje kompatybilność wsteczną.
mwolfe02
1
Jednym z pytań, które wielokrotnie zadawałem sobie, jest to, kiedy powinienem zmienić każdy z tych numerów wersji, wasze punkty na Zgromadzeniu dodały do ​​tego dobrą jasność, a cała odpowiedź była interesującą lekturą.
RyanfaeScotland
Widzę wiele odpowiedzi, które wyjaśniają koncepcje tych trzech rzeczy. Ale w jaki sposób odnoszą się one do edytowalnych numerów wersji we właściwościach projektu? Po kliknięciu Informacje o zespole ... możesz zmienić dwie wersje. I tam zmiana wersji zestawu zmienia folder, w którym znajduje się user.config, a zmiana wersji pliku zmienia numer wersji pokazany po kliknięciu pliku exe prawym przyciskiem myszy i przejściu do jego właściwości. Więc w jaki sposób te dwa numery wersji odpowiadają AssemblyVersion, AssemblyFileVersion i AssemblyInformationalVersion?
Kyle Delaney
Link do posta na blogu, który pierwotnie napisałeś, daje 404. Czy jest na to nowa lokalizacja?
Rob K
@RobK: Ach, przepraszam. Ta witryna jest wyłączona, ale cała treść wpisu na blogu jest odtwarzana w odpowiedzi, więc niczego nie przegapisz. Teraz usunę uszkodzony link.
Daniel Fortunov
43

AssemblyVersionprawie pozostaje wewnętrzną częścią .NET, podczas gdy AssemblyFileVersionWindows widzi to. Jeśli przejdziesz do właściwości zestawu znajdującego się w katalogu i przełączysz na kartę wersji, AssemblyFileVersionto zobaczysz u góry. Jeśli sortujesz pliki według wersji, właśnie tego używa Eksplorator.

AssemblyInformationalVersionMapy do „wersja produktu” i ma być czysto „ludzki wykorzystane”.

AssemblyVersionjest z pewnością najważniejsze, ale też nie chciałbym pominąć AssemblyFileVersion. Jeśli nie podasz AssemblyInformationalVersion, kompilator doda go dla ciebie, usuwając fragment „wersji” numeru wersji i pozostawiając major.minor.build.

Bob King
źródło
23

AssemblyInformationalVersioni AssemblyFileVersionsą wyświetlane, gdy przeglądasz informacje o „wersji” pliku za pomocą Eksploratora Windows, przeglądając właściwości pliku. Te atrybuty są w rzeczywistości kompilowane do VERSION_INFOzasobu utworzonego przez kompilator.

AssemblyInformationalVersionto wartość „Wersja produktu”. AssemblyFileVersionto wartość „Wersja pliku”.

Jest AssemblyVersionon specyficzny dla zestawów .NET i jest używany przez moduł ładujący .NET, aby wiedzieć, która wersja zestawu ma zostać załadowana / powiązana w czasie wykonywania.

Spośród nich jedynym, który jest absolutnie wymagany przez .NET, jest AssemblyVersionatrybut. Niestety może również powodować najwięcej problemów, gdy zmienia się bez rozróżnienia, szczególnie jeśli mocno nazywasz swoje zespoły.

Scott Dorman
źródło
9

Aby utrzymać aktualność tego pytania, warto podkreślić, że AssemblyInformationalVersionjest on używany przez NuGet i odzwierciedla wersję pakietu, w tym wszelkie sufiksy przedpremierowe.

Na przykład AssemblyVersion 1.0.3. * Spakowany z rdzeniem asp.net dotnet-cli

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

Tworzy pakiet z wersją 1.0.3-ci-7, który można sprawdzić za pomocą odbicia za pomocą:

CustomAttributeExtensions.GetCustomAttribute<AssemblyInformationalVersionAttribute>(asm);
KCD
źródło
7

Warto zauważyć kilka innych rzeczy:

1) Jak pokazano w oknie dialogowym Właściwości Eksploratora Windows dla wygenerowanego pliku zespołu, istnieją dwa miejsca o nazwie „Wersja pliku”. Ten widoczny w nagłówku okna dialogowego pokazuje AssemblyVersion, a nie AssemblyFileVersion.

W sekcji Inne informacje o wersji znajduje się inny element o nazwie „Wersja pliku”. Tutaj możesz zobaczyć, co zostało wprowadzone jako AssemblyFileVersion.

2) AssemblyFileVersion jest zwykłym tekstem. Nie musi być zgodny z ograniczeniami schematu numeracyjnego, które robi AssemblyVersion (np. <buduj> <65 KB). Może to być 3.2. <Tekst tagu zwolnienia>. <datetime>, jeśli chcesz. Twój system kompilacji będzie musiał wypełnić tokeny.

Co więcej, nie podlega zamianie symboli wieloznacznych, jaką jest AssemblyVersion. Jeśli masz po prostu wartość „3.0.1. *” W pliku AssemblyInfo.cs, dokładnie to pokaże w elemencie Inne informacje o wersji -> Wersja pliku.

3) Nie wiem jednak, jaki wpływ na instalatora ma użycie czegoś innego niż numeryczne numery wersji plików.

DavidM
źródło
2

Gdy zmienna AssemblyVersion zestawu, jeśli ma mocną nazwę, zestawy odniesienia muszą zostać ponownie skompilowane, w przeciwnym razie zestaw nie zostanie załadowany! Jeśli nie ma silnej nazwy, jeśli nie zostanie jawnie dodany do pliku projektu, nie zostanie skopiowany do katalogu wyjściowego podczas kompilacji, więc można pominąć niektóre zestawy, szczególnie po wyczyszczeniu katalogu wyjściowego.

linquize
źródło
To jest bardzo ciekawe! Czy mógłbyś rozwinąć bit w części „nie zostanie skopiowany do katalogu wyjściowego”? Być może link do miejsca, w którym zdefiniowano to zachowanie. Nigdy nie rozumiałem, dlaczego niektóre pośrednie zależności były czasami kopiowane, ale nie zawsze. To musi być w 100% z tym związane.
julealgon