Die Versionierung von Assemblys in .NET kann verwirrend sein, da es derzeit mindestens drei Möglichkeiten gibt, eine Version für Ihre Assembly anzugeben.
Hier sind die drei wichtigsten versionierungsbezogenen Assembly-Attribute:
// 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")]
Konventionell werden die vier Teile der Version als Hauptversion , Nebenversion , Build und Revision bezeichnet .
Das AssemblyFileVersion
soll einen Aufbau der einzelnen Baugruppe eindeutig identifizieren
In der Regel legen Sie die Haupt- und Neben-AssemblyFileVersion manuell so fest, dass sie die Version der Assembly widerspiegelt, und erhöhen dann die Erstellung und / oder Revision jedes Mal, wenn Ihr Build-System die Assembly kompiliert. Mit der AssemblyFileVersion sollten Sie einen Build der Assembly eindeutig identifizieren können, damit Sie ihn als Ausgangspunkt für das Debuggen von Problemen verwenden können.
In meinem aktuellen Projekt hat der Build-Server die Änderungslistennummer aus unserem Versionsverwaltungs-Repository in die Build- und Revisionsteile der AssemblyFileVersion codiert. Auf diese Weise können wir für jede vom Buildserver generierte Assembly eine direkte Zuordnung von einer Assembly zu ihrem Quellcode vornehmen (ohne Beschriftungen oder Verzweigungen in der Quellcodeverwaltung verwenden oder Aufzeichnungen über freigegebene Versionen manuell führen zu müssen).
Diese Versionsnummer wird in der Win32-Versionsressource gespeichert und kann beim Anzeigen der Windows Explorer-Eigenschaftenseiten für die Assembly angezeigt werden.
Die CLR kümmert sich nicht um die AssemblyFileVersion und untersucht sie auch nicht.
Das AssemblyInformationalVersion
soll die Version Ihres gesamten Produkts darstellen
Die AssemblyInformationalVersion soll eine kohärente Versionierung des gesamten Produkts ermöglichen, die aus vielen Assemblys bestehen kann, die unabhängig voneinander versioniert sind, möglicherweise mit unterschiedlichen Versionsrichtlinien, und möglicherweise von unterschiedlichen Teams entwickelt werden.
„Zum Beispiel kann Version 2.0 eines Produkts mehrere Baugruppen enthalten. Eine dieser Baugruppen ist als Version 1.0 gekennzeichnet, da es sich um eine neue Baugruppe handelt, die nicht in Version 1.0 desselben Produkts geliefert wurde. In der Regel legen Sie die Haupt- und Nebenteile dieser Versionsnummer so fest, dass sie die öffentliche Version Ihres Produkts darstellen. Dann erhöhen Sie die Build- und Revisionsteile jedes Mal, wenn Sie ein komplettes Produkt mit all seinen Baugruppen verpacken. “ - Jeffrey Richter, [CLR über C # (Zweite Ausgabe)] p. 57
Die CLR kümmert sich nicht um die AssemblyInformationalVersion und untersucht sie auch nicht.
Dies AssemblyVersion
ist die einzige Version, die die CLR interessiert (aber sie kümmert sich um die gesamte Version AssemblyVersion
).
Die AssemblyVersion wird von der CLR verwendet, um an stark benannte Assemblys zu binden. Es wird in der AssemblyDef-Manifest-Metadatentabelle der erstellten Assembly und in der AssemblyRef-Tabelle jeder Assembly gespeichert, die darauf verweist.
Dies ist sehr wichtig, da Sie beim Verweisen auf eine stark benannte Assembly eng an eine bestimmte AssemblyVersion dieser Assembly gebunden sind. Die gesamte AssemblyVersion muss genau übereinstimmen, damit die Bindung erfolgreich ist. Wenn Sie beispielsweise zur Erstellungszeit auf Version 1.0.0.0 einer Assembly mit starkem Namen verweisen, zur Laufzeit jedoch nur Version 1.0.0.1 dieser Assembly verfügbar ist, schlägt die Bindung fehl! (Sie müssen dies dann mithilfe der Assembly Binding Redirection umgehen .)
Verwirrung darüber, ob das Ganze AssemblyVersion
übereinstimmen muss. (Ja tut es.)
Es gibt ein wenig Verwirrung darüber, ob die gesamte AssemblyVersion genau übereinstimmen muss, damit eine Assembly geladen werden kann. Einige Menschen glauben fälschlicherweise, dass nur die Haupt- und Nebenteile der AssemblyVersion übereinstimmen müssen, damit die Bindung erfolgreich ist. Dies ist eine vernünftige Annahme, die jedoch letztendlich falsch ist (ab .NET 3.5), und es ist trivial, dies für Ihre Version der CLR zu überprüfen. Führen Sie einfach diesen Beispielcode aus .
Auf meiner Maschine schlägt die zweite Baugruppenlast fehl, und die letzten beiden Zeilen des Fusionsprotokolls machen deutlich, warum:
.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.
Ich denke, die Ursache für diese Verwirrung liegt wahrscheinlich darin, dass Microsoft ursprünglich beabsichtigte, diese strikte Übereinstimmung der vollständigen AssemblyVersion etwas milder zu gestalten, indem nur die Teile der Haupt- und Nebenversion abgeglichen wurden:
"Beim Laden einer Baugruppe findet die CLR automatisch die neueste installierte Wartungsversion, die mit der Haupt- / Nebenversion der angeforderten Baugruppe übereinstimmt." - Jeffrey Richter, [CLR über C # (Zweite Ausgabe)] p. 56
Dies war das Verhalten in Beta 1 der 1.0 CLR. Diese Funktion wurde jedoch vor der 1.0-Version entfernt und konnte in .NET 2.0 nicht wieder auftauchen:
„Hinweis: Ich habe gerade beschrieben, wie Sie sich Versionsnummern vorstellen sollten. Leider behandelt die CLR Versionsnummern nicht so. [In .NET 2.0] behandelt die CLR eine Versionsnummer als undurchsichtigen Wert. Wenn eine Assembly von Version 1.2.3.4 einer anderen Assembly abhängt, versucht die CLR, nur Version 1.2.3.4 zu laden (es sei denn, eine Bindungsumleitung ist vorhanden ). Allerdings
hat Microsoft Pläne den CLR des Laders in einer zukünftigen Version zu ändern , so dass es die neueste Version / Revision für eine bestimmte Major / Minor Version einer Assembly lädt. Wenn der Lader beispielsweise in einer zukünftigen Version der CLR versucht, Version 1.2.3.4 einer Baugruppe zu finden, und Version 1.2.5.0 vorhanden ist, holt der Lader automatisch die neueste Wartungsversion ab. Dies wird eine sehr willkommene Änderung des Laders der CLR sein - ich kann es kaum erwarten. “ - Jeffrey Richter, [CLR über C # (Zweite Ausgabe)] p. 164 (Schwerpunkt Mine)
Da diese Änderung noch nicht implementiert wurde, kann man davon ausgehen, dass Microsoft diese Absicht zurückverfolgt hat, und es ist möglicherweise zu spät, dies jetzt zu ändern. Ich habe versucht, im Internet zu suchen, um herauszufinden, was mit diesen Plänen passiert ist, aber ich konnte keine Antworten finden. Ich wollte immer noch auf den Grund gehen.
Also schrieb ich Jeff Richter eine E-Mail und fragte ihn direkt - ich dachte, wenn jemand wüsste, was passiert ist, wäre er es.
Er antwortete innerhalb von 12 Stunden, nicht weniger an einem Samstagmorgen, und stellte klar, dass der .NET 1.0 Beta 1-Lader diesen "automatischen Roll-Forward" -Mechanismus zum Abrufen des neuesten verfügbaren Builds und der neuesten Revision einer Baugruppe implementiert hat, aber dieses Verhalten war vor dem Versand von .NET 1.0 zurückgesetzt. Es war später beabsichtigt, dies wiederzubeleben, aber es hat es nicht geschafft, bevor die CLR 2.0 ausgeliefert wurde. Dann kam Silverlight, das für das CLR-Team Priorität hatte, sodass sich diese Funktionalität weiter verzögerte. In der Zwischenzeit sind die meisten Leute, die in den Tagen von CLR 1.0 Beta 1 da waren, inzwischen weitergezogen, so dass es unwahrscheinlich ist, dass dies trotz all der harten Arbeit, die bereits in sie gesteckt wurde, das Licht der Welt erblicken wird.
Das derzeitige Verhalten scheint hier zu bleiben.
Aus meiner Diskussion mit Jeff geht auch hervor, dass AssemblyFileVersion erst nach dem Entfernen des automatischen Roll-Forward-Mechanismus hinzugefügt wurde. Nach 1.0 Beta 1 war jede Änderung an AssemblyVersion eine bahnbrechende Änderung für Ihre Kunden Nirgendwo können Sie Ihre Build-Nummer sicher speichern. AssemblyFileVersion ist dieser sichere Hafen, da er von der CLR nie automatisch überprüft wird. Vielleicht ist es auf diese Weise klarer, zwei separate Versionsnummern mit unterschiedlichen Bedeutungen zu haben, als zu versuchen, diese Trennung zwischen den Teilen Major / Minor (Breaking) und Build / Revision (Non-Breaking) der AssemblyVersion vorzunehmen.
Fazit: Überlegen Sie genau, wann Sie Ihre ändern AssemblyVersion
Die Moral lautet: Wenn Sie Assemblys versenden, auf die andere Entwickler verweisen, müssen Sie äußerst vorsichtig sein, wenn Sie die AssemblyVersion dieser Assemblys ändern (und nicht ändern). Alle Änderungen an der AssemblyVersion bedeuten, dass Anwendungsentwickler entweder eine Neukompilierung mit der neuen Version durchführen müssen (um diese AssemblyRef-Einträge zu aktualisieren) oder Assemblybindungsumleitungen verwenden müssen, um die Bindung manuell zu überschreiben.
- Sie nicht die Assemblyversion für eine Wartung Release ändern, die abwärtskompatibel gedacht.
- Sie die Assembly ändern für eine Veröffentlichung , dass Sie wissen Bruch Änderungen hat.
Schauen Sie sich noch einmal die Versionsattribute auf mscorlib an:
// 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")]
Beachten Sie, dass es die AssemblyFileVersion ist, die alle interessanten Wartungsinformationen enthält (es ist der Revisionsteil dieser Version, der Ihnen sagt, auf welchem Service Pack Sie sich befinden), während die AssemblyVersion auf eine langweilige alte Version 2.0.0.0 festgelegt ist. Jede Änderung an der AssemblyVersion würde jede .NET-Anwendung, die auf mscorlib.dll verweist, dazu zwingen, erneut gegen die neue Version zu kompilieren!