Die Versionierung von Assemblies 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 versionsbezogenen Baugruppenattribute:
// 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")]
Vereinbarungsgemäß werden die vier Teile der Fassung als die Hauptversion , Kleinere Version , Bauen Sie y Revision .
El AssemblyFileVersion
dient der eindeutigen Identifizierung eines Builds der Einzelmontage
Normalerweise setzen Sie die Major und Minor AssemblyFileVersion manuell, um die Version der Assembly wiederzugeben, und erhöhen dann die Build und/oder Revision jedes Mal, wenn Ihr Build-System die Assembly kompiliert. Die AssemblyFileVersion sollte es Ihnen ermöglichen, einen Build der Assembly eindeutig zu identifizieren, so dass Sie ihn als Ausgangspunkt für die Fehlersuche bei Problemen verwenden können.
Auf meinem aktuellen Projekt haben wir den Build-Server kodieren die Changelist-Nummer aus unserer Source-Control-Repository in die Build und Revision Teile der AssemblyFileVersion. Dies ermöglicht uns eine direkte Zuordnung von einer Baugruppe zu ihrem Quellcode für jede vom Build-Server erzeugte Baugruppe (ohne Labels oder Zweige in der Versionsverwaltung verwenden zu müssen oder manuell Aufzeichnungen über freigegebene Versionen zu führen).
Diese Versionsnummer wird in der Win32-Versionsressource gespeichert und kann auf den Eigenschaftsseiten des Windows Explorers für die Assembly angezeigt werden.
Die CLR kümmert sich nicht um die AssemblyFileVersion und untersucht sie auch nicht.
El AssemblyInformationalVersion
soll die Version Ihres gesamten Produkts darstellen
Die AssemblyInformationalVersion soll eine kohärente Versionierung des gesamten Produkts ermöglichen, das aus vielen Baugruppen bestehen kann, die unabhängig voneinander versioniert sind, möglicherweise mit unterschiedlichen Versionsrichtlinien, und die möglicherweise von verschiedenen Teams entwickelt wurden.
"Zum Beispiel kann die Version 2.0 eines Produkts mehrere Assemblies enthalten; eine dieser Baugruppen ist markiert als Version 1.0 gekennzeichnet, da es sich um eine neue Baugruppe Baugruppe ist, die nicht in der Version 1.0 des gleichen Produkts ausgeliefert wurde. Normalerweise setzen Sie die Haupt- und Nebenbestandteile dieser Versionsnummer Nummer so, dass sie die öffentliche Version Ihres Produkts. Dann inkrementieren Sie die Teile Build und Revision jedes Mal, wenn wenn Sie ein vollständiges Produkt mit all seinen Baugruppen." - Jeffrey Richter, [CLR via C# (Second Edition)] S. 57
Die CLR kümmert sich nicht um die AssemblyInformationalVersion und untersucht sie auch nicht.
El AssemblyVersion
ist die einzige Version, um die sich die CLR kümmert (aber sie kümmert sich um die gesamte AssemblyVersion
)
Die AssemblyVersion wird von der CLR verwendet, um an stark benannte Assemblies zu binden. Sie wird in der AssemblyDef-Manifest-Metadatentabelle der erstellten Assembly und in der AssemblyRef-Tabelle jeder Assembly, die darauf verweist, gespeichert.
Dies ist sehr wichtig, denn es bedeutet, dass Sie, wenn Sie auf eine streng benannte Baugruppe verweisen, fest an eine bestimmte AssemblyVersion dieser Baugruppe gebunden sind. Die gesamte AssemblyVersion muss genau übereinstimmen, damit die Bindung erfolgreich ist. Wenn Sie beispielsweise zur Build-Zeit auf Version 1.0.0.0 einer streng benannten Assembly verweisen, zur Laufzeit aber nur Version 1.0.0.1 dieser Assembly verfügbar ist, schlägt die Bindung fehl! (Sie müssen dieses Problem dann mit Baugruppenbindung Umlenkung .)
Verwirrung darüber, ob die gesamte AssemblyVersion
muss übereinstimmen. (Ja, das muss sie.)
Es herrscht ein wenig Verwirrung darüber, ob die gesamte AssemblyVersion exakt übereinstimmen muss, damit eine Baugruppe geladen werden kann. Manche Leute glauben, dass nur der Major- und Minor-Teil der AssemblyVersion übereinstimmen müssen, damit die Bindung erfolgreich ist. Dies ist eine vernünftige Annahme, die jedoch letztlich falsch ist (ab .NET 3.5), und es ist trivial, dies für Ihre Version der CLR zu überprüfen. Führen Sie einfach aus dieses Codebeispiel .
Auf meinem Rechner schlägt das zweite Laden der Baugruppe fehl, und aus den letzten beiden Zeilen des Fusionsprotokolls geht klar hervor, 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 Quelle dieser Verwirrung liegt wahrscheinlich darin, dass Microsoft ursprünglich beabsichtigte, bei dieser strengen Abstimmung der vollständigen AssemblyVersion etwas nachsichtiger zu sein und nur die Teile Major und Minor Version abzustimmen:
"Wenn eine Baugruppe geladen wird, findet die CLR automatisch die letzte installierte Wartungsversion, die die mit der Haupt-/Nebenversion der angeforderten Baugruppe entspricht." - Jeffrey Richter, [CLR via C# (Second Edition)] S. 56
Dies war das Verhalten in Beta 1 der CLR 1.0, jedoch wurde diese Funktion vor der Veröffentlichung von 1.0 entfernt und hat es nicht geschafft, in .NET 2.0 wieder aufzutauchen:
"Hinweis: Ich habe gerade beschrieben, wie Sie über Versionsnummern nachdenken sollten. Leider geht die CLR nicht so mit Versionsnummern nicht auf diese Weise. [In .NET 2.0] behandelt die CLR eine Versionsnummer als einen undurchsichtigen Wert, und wenn eine Assembly von der Version 1.2.3.4 einer anderen Assembly abhängt, versucht die CLR, die nur die Version 1.2.3.4 zu laden (es sei denn, eine Umleitung vorhanden ist). Allerdings, Microsoft plant die Änderung des CLR-Loader in einer zukünftigen Version so zu dass er die neueste Build/Revision für eine bestimmte Major/Minor Version einer Baugruppe . Zum Beispiel, in einer zukünftigen Version der CLR, wenn der Lader versucht, die Version 1.2.3.4 einer Assembly zu finden, während die Version 1.2.5.0 existiert, wird der Lader automatisch die neueste Version verwenden. Dies wird eine sehr willkommene Änderung für den CLR-Loader sein - I kann es kaum erwarten." - Jeffrey Richter, [CLR via C# (Second Edition)] S. 164 (Hervorhebung meine)
Da diese Änderung immer noch nicht umgesetzt wurde, kann man wohl davon ausgehen, dass Microsoft diese Absicht wieder rückgängig gemacht hat, und dass es jetzt vielleicht zu spät ist, dies zu ändern. Ich habe versucht, im Internet zu recherchieren, um herauszufinden, was aus diesen Plänen geworden ist, aber ich konnte keine Antworten finden. Trotzdem wollte ich der Sache auf den Grund gehen.
Also habe ich Jeff Richter angemailt und ihn direkt gefragt - ich dachte, wenn jemand weiß, was passiert ist, dann er.
Er antwortete innerhalb von 12 Stunden, und das an einem Samstagmorgen, und stellte klar, dass der .NET 1.0 Beta 1 Loader diesen "automatischen Roll-Forward"-Mechanismus zur Übernahme des letzten verfügbaren Builds und der letzten Revision einer Assembly implementiert hatte, dass dieses Verhalten aber vor der Auslieferung von .NET 1.0 rückgängig gemacht wurde. Später sollte dieser Mechanismus wieder eingeführt werden, aber er wurde nicht vor der Veröffentlichung der CLR 2.0 eingeführt. Dann kam Silverlight, das für das CLR-Team Priorität hatte, so dass sich diese Funktionalität weiter verzögerte. In der Zwischenzeit sind die meisten Leute, die in den Tagen von CLR 1.0 Beta 1 dabei waren, weitergezogen, so dass es unwahrscheinlich ist, dass diese Funktion das Licht der Welt erblicken wird, trotz all der harten Arbeit, die bereits in sie investiert wurde.
Das derzeitige Verhalten scheint zu bleiben.
Es ist auch erwähnenswert, aus meiner Diskussion mit Jeff, dass AssemblyFileVersion wurde nur nach der Beseitigung der "automatischen Roll-forward"-Mechanismus hinzugefügt - weil nach 1.0 Beta 1, jede Änderung der AssemblyVersion war ein brechen Änderung für Ihre Kunden, gab es dann nirgendwo sicher zu speichern Ihre Build-Nummer. AssemblyFileVersion ist dieser sichere Hafen, da es nie automatisch von der CLR untersucht wird. Vielleicht ist es klarer auf diese Weise, mit zwei separaten Versionsnummern, mit separaten Bedeutungen, anstatt zu versuchen, diese Trennung zwischen der Major/Minor (Breaking) und die Build/Revision (non-breaking) Teile der AssemblyVersion zu machen.
Die Quintessenz: Überlegen Sie sorgfältig, wann Sie Ihre AssemblyVersion
Die Moral von der Geschicht' ist, dass Sie, wenn Sie Baugruppen ausliefern, auf die andere Entwickler verweisen werden, extrem vorsichtig sein müssen, wenn Sie die AssemblyVersion dieser Baugruppen ändern (und nicht ändern). Jede Änderung der AssemblyVersion bedeutet, dass Anwendungsentwickler entweder mit der neuen Version neu kompilieren müssen (um die AssemblyRef-Einträge zu aktualisieren) oder Assembly-Bindungsumleitungen verwenden müssen, um die Bindung manuell außer Kraft zu setzen.
- Nicht die AssemblyVersion für eine Wartungsversion ändern, die abwärtskompatibel sein soll.
- Do die AssemblyVersion für eine Version ändern, von der Sie wissen, dass sie bahnbrechende Änderungen enthält.
Schauen Sie sich einfach noch einmal die Versionsattribute von 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 2.0.0.0 festgelegt ist. Jede Änderung der AssemblyVersion würde jede .NET-Anwendung, die mscorlib.dll referenziert, dazu zwingen, mit der neuen Version neu zu kompilieren!