Semantisches Versioning (oder kurz SemVer) ist ein Schema zur Softwareversionierung, das dreiteilige Versionsnummern in der Form <haupt>.<neben>.<korrektur> vorschreibt, wie zum Beispiel 1.0.2, mit einer optionalen Prerelease-Endung in der Form -<prerelease>, wie in 1.0.2-beta.

SemVer ist wohl das am weitesten verbreitete Versionsnummerierungsschema heute. Zum Beispiel empfehlen und unterstützen sowohl Nuget als auch npm es, und VS Code verwendet es ebenfalls.

In den meisten GitHub-Repos, die die GitHub Releases-Funktion zur Veröffentlichung von Versionen verwenden, sieht man eine SemVer-Versionsnummer in der neuesten Release-Kachel auf der Startseite, wie im folgenden Screenshot zu sehen ist:

Ich muss häufig eine SemVer-Versionsnummer bei der Erstellung von ASP.NET Core API-Projekten festlegen und diese dann zur Laufzeit lesen oder melden.

Beispielsweise würde ich eine minimale API mit der Versionsnummer 1.0.2-beta erstellen, die über einen /version-Endpunkt von der API gemeldet wird, wie im folgenden Screenshot von Hoppscotch (dies ist ein Postman-ähnliches Tool, das der Bequemlichkeit halber im Browser läuft):

Das Überprüfen der vom bereitgestellten Dienst gemeldeten Version, wie z.B. Webanwendungen und APIs, ist ein entscheidender Bestandteil meiner CD-Pipeline und einer der smoke tests, die ich verwende, um zu bestimmen, ob eine Bereitstellung erfolgreich war.

Eine kleine Komplikation beim Setzen einer SemVer-Versionnummer auf .NET-Assemblys ist, dass .NET ursprünglich vierstellige Versionsnummern wie 1.0.3.212 verwendete und Assemblys diese immer noch haben (Assembly ist der .NET-Terminus für Codeeinheiten, die in .NET-Bytecode kompiliert werden, die typischsten davon sind dll’s und exe’s).

Das andere ist, dass .NET nicht nur eine, sondern viele, leicht unterschiedliche Versionsnummern hat, die in derselben Assembly vorhanden sind.

In diesem Artikel zeige ich Ihnen, wie Sie diese Eigenarten umgehen und eine SemVer-Versionnummer während des Build-Prozesses auf eine .NET-Assembly aufdrücken. Das bedeutet, auf eine kompilierte .exe oder .dll, und wie man sie zur Laufzeit liest.

Inhaltsverzeichnis

Struktur einer SemVer-Versionsnummer

Betrachten wir eine SemVer-Versionsnummer wie 1.0.2 oder 1.0.2-beta. Sie hat die Form <haupt>.<neben>.<korrektur><vorausblick>

Dies ist die Bedeutung der verschiedenen Komponenten:

Der <major>-Bestandteil der Versionsnummer würde nur erhöht, wenn die neue Veröffentlichung eine bestehende (aktuelle) Veröffentlichung brechen würde.

Bei einer UI-Anwendung könnten Kunden als Menschenkunden gemeint sein. Wenn also die neue Veröffentlichung die bestehenden Benutzer-assets wie Arbeitsablauff Definitionen brechen würde, wäre dies ein Grund, die Hauptversionsnummer zu erhöhen. In diesem Fall, wenn die vorherige Veröffentlichung 1.0.2 war, sollte die neue Veröffentlichung 2.0.0 sein (alle untergeordneten Bestandteile der Versionsnummer werden zurückgesetzt).

Bei einer Bibliothek, wie zum Beispiel einer Bibliothekspaket auf Nuget oder NPM, wären die Kunden anderes Code. Wenn also die neue Veröffentlichung bestehenden Client-Code brechen würde, d.h. sie ist nicht abwärtskompatibel mit ihrer eigenen vorherigen Version, dann wird erneut der <major>-Bestandteil erhöht.

<minor> wird erhöht, wenn neue Funktionen hinzugefügt wurden, aber die neue Version ist immer noch abwärtskompatibel. Also von 1.0.2 geht man zu 1.1.0.

<patch> wird erhöht, wenn eine neue Veröffentlichung erforderlich ist, auch wenn kein Bruchänderung vorliegt und keine neue Funktionalität hinzugefügt wurde. Dies könnte zum Beispiel der Fall sein, wenn ein Fehler behoben werden musste, der veröffentlicht werden musste.

-<prerelease>-Suffix ist optional. Es wird typischerweise an eine dreiteilige Versionsnummer angehängt, wenn Software während Vorab-Testphasen wie Alpha und Beta verfügbar gemacht werden muss. Zum Beispiel können Sie vor der allgemeinen Veröffentlichung der Version 1.0.2 Ihrer Software diese Ihren Beta-Testern als 1.0.2-beta verfügbar machen.

Das <prerelease>-Element kann ziemlich任意字符串您的选择,唯一的要求是它要么是一个字母数字标识符,如beta12alpha2(除了数字或字母以外的字符都不允许),或者是由点(.)分隔的多个字母数字标识符,例如development.version

一个.NET程序集的许多版本号

正如Andrew Lock的关于.NET版本化的文章所解释的,一个.NET程序集不只有一个,而是有几个不同的版本号:

  • 程序集版本号(AssemblyVersion):这是一个四部分版本号,例如1.0.2.0。它在运行时用于加载链接的程序集。

  • 文件版本号(FileVersion):这是在Windows资源管理器中右键点击.dll文件并选择属性时报告的版本号。

  • Informationsversion: Wieder eine andere Versionsnummer und, wie die FileVersion, kann im Eigenschaften-dialog angezeigt werden, wenn Sie mit der rechten Maustaste auf die Assembly in Windows klicken und Eigenschaften auswählen. Diese kann Zeichenfolgen enthalten und ist nicht nur auf ganze Zahlen und Punkte beschränkt, wie AssemblyVersion und FileVersion.

  • Paketversion: Wenn das Projekt ein Nuget-Paket ist, wäre dies die Versionsnummer des Pakets, zu dem die Assembly gehört.

Alle diese Versionsnummern werden während der Kompilierung als Metadaten in die Assembly eingebettet. Sie können sie sehen, wenn Sie die Assembly mit JetBrains dotPeek (kostenlos) oder Red gate Reflector (nicht kostenlos) oder ähnlichem überprüfen.

FileVersion und Informationsversion können auch im Details-Tab des Eigenschaftendialogs angezeigt werden, der erscheint, wenn Sie mit der rechten Maustaste auf die Assembly-Datei im Windows-Datei-Explorer klicken und Eigenschaften auswählen:

In der obigen Screenshot wird „Product version“ als Beschriftung für InformationVersion verwendet, während „File version“ als Beschriftung für FileVersion dient.

Von den vier oben beschriebenen Arten von Versionsnummern gelten nur die ersten drei für jede Assembly (unabhängig davon, ob die Assembly Teil eines Nuget-Pakets ist).

Bei diesen drei wird AssemblyVersion immer eine 0 an der vierten Stelle hinzufügen, wenn Sie versuchen, eine SemVer-Version mit nur drei Zahlen (plus optionaler Prerelease-Suffix) festzulegen. Zum Beispiel, wenn Sie versuchen, eine SemVer-Version von 1.0.2-beta während des Builds festzulegen und dann den Wert von AssemblyVersion zur Laufzeit in der Assembly zu lesen, wäre es 1.0.2.0.

FileVersion tut dasselbe, wie im obigen Screenshot gezeigt.

InformationalVersion ist die einzige Versionsnummer, die genau auf die Serverversion eingestellt wird, die Sie während des Builds festlegen, wie der obige Screenshot zeigt.

Daher sollte InformationalVersion die Versionsnummer sein, die zur Laufzeit gelesen wird, um die SemVer-Version der Assembly abzurufen.

Wie man eine SemVer-Versionsnummer festlegt

Es gibt zwei Dinge, die Sie tun müssen, um eine SemVer-Versionsnummer während des Builds auf eine Assembly festzulegen.

Erstens, fügen Sie in einem <PropertyGroup>-Element in der csproj-Datei des Projekts das Element <IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion> hinzu:

<PropertyGroup>
 ...
 <IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion> 
</PropertyGroup>

Wie in diesem Thema beschrieben, stellt dies sicher, dass InformationalVersion genau auf die SemVer-Versionsnummer gesetzt wird, die wir angegeben haben, und am Ende keine +<Hashcode> angehängt wird.

Zweitens, übergeben Sie die Versionsnummer als Wert der Eigenschaft Version, die an den Befehl dotnet build übergeben wird, z.B.:

dotnet build --configuration Release -p Version=1.0.2-beta

Dies würde InformationVersion in der kompillierten Assembly (.exe oder .dll-Datei) auf 1.0.2-beta setzen.

Incidentally, es würde auch AssemblyVersion und FileVersion (am Ende von 1.0.2 würde eine zusätzliche 0 hinzugefügt werden) setzen, aber darauf haben wir kein Interesse.

Beachten Sie, dass Sie anstelle des Übergebens des Arguments Version auf der Kommandozeile die MS Build-Eigenschaft <Version>1.0.2-beta</Version> in einem Element <PropertyGroup> in der csproj-Datei setzen können. Der Übermittlung eines Wertes des Parameters Version an den Befehl dotnet build ist jedoch einfacher, da die csproj-Datei nicht jedes Mal geändert werden muss, wenn die Versionsnummer erhöht wird. Dies ist in CD-Pipelines hilfreich. Außerdem haben csproj-Dateien standardmäßig keine Eigenschaften, die mit Versionierung in Verbindung stehen.

Wie man die SemVer-Version einer Assembly zur Laufzeit liest

Der Code, der InformationVersion zur Laufzeit liest, lautet wie folgt:

string? version = Assembly.GetEntryAssembly()?.
  GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.
  InformationalVersion;

In meinen minimalen APIs, um einen /version-Endpunkt hinzuzufügen, wie ich es im obigen Einleitungsteil gezeigt habe, plaziere ich den obigen Codeausschnitt in Program.cs, füge dann den folgenden Codeausschnitt unmittelbar darunter hinzu. Beachten Sie, dass das ganze vor dem Aufruf von builder.Build() auftauchen sollte:

//dieses Objekt eines anonymen Typs wird 
//als JSON im Antwortkörper serialisiert
//wenn es von einem Handler zurückgegeben wird
var objVersion = new { Version = version ?? "" };

//ANDERER CODE
//var app = builder.Build()

Nachdem builder.Build() aufgerufen wurde, erstelle ich den Handler für den /version-Endpunkt:

app.MapGet("/version", () => objVersion);

Wenn ich jetzt das API-Projekt ausführe und den /version-Endpunkt aufrufe, bekomme ich die Versionsnummer zurück, als JSON-Objekt im HTTP-Antwortkörper:

{
  "version": "1.0.2-beta"
}

Das ist das, was das Hoppscotch-Screenshot im Einleitungsteil gezeigt hat.

Schlussfolgerung

Dieser Artikel hat Ihnen gezeigt, wie Sie eine SemVer-Versionsnummer in Ihren .NET-Assemblys, Bibliotheken oder Apps festlegen.

Er hat Ihnen auch gezeigt, wie Sie die Versionsnummer während der Laufzeit lesen können.