Как получить автоматически увеличивающийся номер версии (Visual Studio)?

Я хочу сохранить набор целых чисел, которые автоматически увеличиваются во время сборки:

int MajorVersion = 0;
int MinorVersion = 1;
int Revision = 92;

Когда я компилирую, он будет автоматически увеличивать Revision, Когда я собираю проект установки, он будет увеличиваться MinorVersion (Я в порядке с этим вручную). MajorVersion будет увеличиваться только вручную.

Тогда я мог бы отобразить номер версии в меню Справка / О пользователе для пользователя как:

  Версия: 0.1.92

Как этого достичь?

В этом вопросе задается не только вопрос о том, как получить автоматически увеличивающийся номер версии, но и о том, как использовать его в коде, который является более полным ответом, чем другие.

9 ответов

Решение

Если вы добавите класс AssemblyInfo в свой проект и измените атрибут AssemblyVersion, чтобы он заканчивался звездочкой, например:

[assembly: AssemblyVersion("2.10.*")]

Visual studio увеличит итоговое число для вас в соответствии с этими правилами (спасибо, галец, я ошибся!)

Чтобы ссылаться на эту версию в коде, чтобы вы могли отобразить ее пользователю, используйте отражение. Например,

Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
DateTime buildDate = new DateTime(2000, 1, 1)
                        .AddDays(version.Build).AddSeconds(version.Revision * 2);
string displayableVersion = $"{version} ({buildDate})";

Две важные ошибки, которые вы должны знать

От @ashes999:

Стоит также отметить, что если оба AssemblyVersion а также AssemblyFileVersion указаны, вы не увидите это на вашем.exe.

От @BrainSlugs83:

Установка только 4-го числа * может быть плохим, так как версия не всегда увеличивается. 3-е число - это количество дней с 2000 года, а 4-е число - это количество секунд с полуночи (деленное на 2) [ЭТО НЕ СЛУЧАЙНО]. Таким образом, если вы создали решение в конце дня, а в начале дня следующего дня, у более поздней сборки будет более ранний номер версии. Я рекомендую всегда использовать X.Y.* вместо X.Y.Z.* потому что ваш номер версии всегда будет увеличиваться таким образом.

Вы можете использовать механизм шаблонов T4 в Visual Studio для генерации необходимого исходного кода из простого текстового файла:

Я хотел настроить генерацию информации о версии для некоторых проектов.NET. Прошло много времени с тех пор, как я исследовал доступные варианты, поэтому я искал вокруг в надежде найти какой-то простой способ сделать это. То, что я нашел, не выглядело очень обнадеживающим: люди пишут надстройки для Visual Studio и пользовательские задачи MsBuild только для того, чтобы получить одно целое число (хорошо, может быть, два). Это было излишним для небольшого личного проекта.

Вдохновение пришло от одного из обсуждений в Stackru, где кто-то предположил, что шаблоны T4 могут сделать эту работу. И, конечно, они могут. Решение требует минимальных усилий и не требует настройки Visual Studio или процесса сборки. Вот что нужно сделать:

  1. Создайте файл с расширением ".tt" и поместите туда шаблон T4, который будет генерировать атрибуты AssemblyVersion и AssemblyFileVersion:
<#@ template language="C#" #>
// 
// This code was generated by a tool. Any changes made manually will be lost
// the next time this code is regenerated.
// 

using System.Reflection;

[assembly: AssemblyVersion("1.0.1.<#= this.RevisionNumber #>")]
[assembly: AssemblyFileVersion("1.0.1.<#= this.RevisionNumber #>")]
<#+
    int RevisionNumber = (int)(DateTime.UtcNow - new DateTime(2010,1,1)).TotalDays;
#>

Вам придется определиться с алгоритмом генерации номера версии. Для меня было достаточно автоматически сгенерировать номер редакции, который установлен на количество дней с 1 января 2010 года. Как видите, правило генерации версий написано на простом C#, так что вы можете легко настроить его под свои нужды,

  1. Файл выше должен быть размещен в одном из проектов. Я создал новый проект только с этим единственным файлом, чтобы прояснить методику управления версиями. Когда я собираю этот проект (на самом деле мне даже не нужно его создавать: достаточно сохранить файл, чтобы вызвать действие Visual Studio), генерируется следующий C#:
// 
// This code was generated by a tool. Any changes made manually will be lost
// the next time this code is regenerated.
// 

using System.Reflection;

[assembly: AssemblyVersion("1.0.1.113")]
[assembly: AssemblyFileVersion("1.0.1.113")]

Да, сегодня с 1 января 2010 года 113 дней. Завтра номер редакции изменится.

  1. Следующим шагом является удаление атрибутов AssemblyVersion и AssemblyFileVersion из файлов AssemblyInfo.cs во всех проектах, которые должны использовать одну и ту же автоматически сгенерированную информацию о версии. Вместо этого выберите "Добавить существующий элемент" для каждого проекта, перейдите в папку с файлом шаблона T4, выберите соответствующий файл ".cs" и добавьте его в качестве ссылки. Что будет делать!

Что мне нравится в этом подходе, так это то, что он легкий (без пользовательских задач MsBuild), и автоматически сгенерированная информация о версии не добавляется в систему контроля версий. И, конечно, использование C# для генерации версий открывает алгоритм для алгоритмов любой сложности.

Это моя реализация предложения T4... Это будет увеличивать номер сборки каждый раз, когда вы собираете проект, независимо от выбранной конфигурации (т. Е. Debug|Release), и увеличивать номер редакции каждый раз, когда вы делаете сборку Release. Вы можете продолжить обновлять основной и вспомогательный номера версий через Приложение Information Информация о сборке...

Чтобы объяснить более подробно, это будет читать существующие AssemblyInfo.cs файл, и используйте регулярное выражение, чтобы найти AssemblyVersion информация, а затем увеличить номер ревизии и сборки на основе ввода из TextTransform.exe,

  1. Удалить свой существующий AssemblyInfo.cs файл.
  2. Создать AssemblyInfo.tt файл на своем месте. Visual Studio должен создать AssemblyInfo.cs и сгруппируйте его с файлом T4 после сохранения файла T4.

    <#@ template debug="true" hostspecific="true" language="C#" #>
    <#@ output extension=".cs" #>
    <#@ import namespace="System.IO" #>
    <#@ import namespace="System.Text.RegularExpressions" #>
    <#
        string output = File.ReadAllText(this.Host.ResolvePath("AssemblyInfo.cs"));
        Regex pattern = new Regex("AssemblyVersion\\(\"(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<revision>\\d+)\\.(?<build>\\d+)\"\\)");
        MatchCollection matches = pattern.Matches(output);
        if( matches.Count == 1 )
        {
            major = Convert.ToInt32(matches[0].Groups["major"].Value);
            minor = Convert.ToInt32(matches[0].Groups["minor"].Value);
            build = Convert.ToInt32(matches[0].Groups["build"].Value) + 1;
            revision = Convert.ToInt32(matches[0].Groups["revision"].Value);
            if( this.Host.ResolveParameterValue("-","-","BuildConfiguration") == "Release" )
                revision++;
        }
    #>
    
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Resources;
    
    // General Information
    [assembly: AssemblyTitle("Insert title here")]
    [assembly: AssemblyDescription("Insert description here")]
    [assembly: AssemblyConfiguration("")]
    [assembly: AssemblyCompany("Insert company here")]
    [assembly: AssemblyProduct("Insert product here")]
    [assembly: AssemblyCopyright("Insert copyright here")]
    [assembly: AssemblyTrademark("Insert trademark here")]
    [assembly: AssemblyCulture("")]
    
    // Version informationr(
    [assembly: AssemblyVersion("<#= this.major #>.<#= this.minor #>.<#= this.revision #>.<#= this.build #>")]
    [assembly: AssemblyFileVersion("<#= this.major #>.<#= this.minor #>.<#= this.revision #>.<#= this.build #>")]
    [assembly: NeutralResourcesLanguageAttribute( "en-US" )]
    
    <#+
        int major = 1;
        int minor = 0;
        int revision = 0;
        int build = 0;
    #>
    
  3. Добавьте это к вашему событию перед сборкой:

    "%CommonProgramFiles(x86)%\microsoft shared\TextTemplating\$(VisualStudioVersion)\TextTransform.exe" -a !!BuildConfiguration!$(Configuration) "$(ProjectDir)Properties\AssemblyInfo.tt"
    

Если вы добавите звездочку для сборки и ревизии, то Visual Studio использует число дней с 1 января 2000 года в качестве номера сборки, а количество секунд с полуночи, деленное на 2, в качестве ревизии.

НАМНОГО лучшее решение по спасению жизни - http://autobuildversion.codeplex.com/

Это работает как шарм, и это очень гибкий.

Вот цитата на AssemblyInfo.cs от MSDN:

Вы можете указать все значения или принять номер сборки по умолчанию, номер редакции или оба, используя звездочку (). Например, [assembly:AssemblyVersion("2.3.25.1")] указывает 2 в качестве основной версии, 3 в качестве вспомогательной версии, 25 в качестве номера сборки и 1 в качестве номера редакции. Номер версии, такой как [assembly: AssemblyVersion ("1.2. ")], Задает 1 в качестве основной версии, 2 в качестве вспомогательной версии и принимает номера сборки и ревизии по умолчанию. Номер версии, такой как [assembly:AssemblyVersion("1.2.15.*")], Указывает 1 как основную версию, 2 как вспомогательную версию, 15 как номер сборки и принимает номер версии по умолчанию. Номер сборки по умолчанию увеличивается ежедневно. Номер ревизии по умолчанию является случайным

Это говорит о том, что если вы добавите 1.1.* В информацию о сборке, только номер сборки будет автоматически инкрементен, и это будет происходить не после каждой сборки, а ежедневно. Номер ревизии будет меняться при каждой сборке, но не случайно, а постепенно.

Этого, вероятно, достаточно для большинства случаев использования. Если это не то, что вы ищете, вы застряли с необходимостью написать скрипт, который будет автоматически инкорпорировать версию # на этапе предварительной сборки

Используйте AssemblyInfo.cs

Создайте файл в App_Code: и заполните следующее или используйте Google для других возможностей атрибутов / свойств.

AssemblyInfo.cs

using System.Reflection;

[assembly: AssemblyDescription("Very useful stuff here.")]
[assembly: AssemblyCompany("companyname")]
[assembly: AssemblyCopyright("Copyright © me 2009")]
[assembly: AssemblyProduct("NeatProduct")]
[assembly: AssemblyVersion("1.1.*")]

AssemblyVersion - это то, что вам действительно нужно.

Затем, если вы работаете на веб-сайте, на любой странице aspx или в элементе управления, вы можете добавить в тег следующее:

CompilerOptions="<folderpath>\App_Code\AssemblyInfo.cs"

(замена пути к папке с соответствующей переменной, конечно).

Я не верю, что вам нужно каким-либо образом добавлять опции компилятора для других классов; все те в App_Code должны получить информацию о версии, когда они скомпилированы.

Надеюсь, это поможет.

  • Звездочка в версии (например, "2.10.3.*") - это просто, но цифры слишком велики

  • AutoBuildVersion - выглядит великолепно, но не работает на моем VS2010.

  • Сценарий @DrewChapin работает, но я не могу установить в своей студии различные режимы для событий предварительной отладки и события предварительной сборки выпуска.

поэтому я немного изменил сценарий... commamd:

"%CommonProgramFiles(x86)%\microsoft shared\TextTemplating\10.0\TextTransform.exe" -a !!$(ConfigurationName)!1 "$(ProjectDir)Properties\AssemblyInfo.tt"

и скрипт (это работает для конфигураций "Debug" и "Release"):

<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Windows.Forms" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#
    int incRevision = 1;
    int incBuild = 1;

    try { incRevision = Convert.ToInt32(this.Host.ResolveParameterValue("","","Debug"));} catch( Exception ) { incBuild=0; }
    try { incBuild = Convert.ToInt32(this.Host.ResolveParameterValue("","","Release")); } catch( Exception ) { incRevision=0; }
    try {
        string currentDirectory = Path.GetDirectoryName(Host.TemplateFile);
        string assemblyInfo = File.ReadAllText(Path.Combine(currentDirectory,"AssemblyInfo.cs"));
        Regex pattern = new Regex("AssemblyVersion\\(\"\\d+\\.\\d+\\.(?<revision>\\d+)\\.(?<build>\\d+)\"\\)");
        MatchCollection matches = pattern.Matches(assemblyInfo);
        revision = Convert.ToInt32(matches[0].Groups["revision"].Value) + incRevision;
        build = Convert.ToInt32(matches[0].Groups["build"].Value) + incBuild;
    }
    catch( Exception ) { }
#>
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Game engine. Keys: F2 (Debug trace), F4 (Fullscreen), Shift+Arrows (Move view). ")]
[assembly: AssemblyProduct("Game engine")]
[assembly: AssemblyDescription("My engine for game")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyCopyright("Copyright © Name 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type. Only Windows
// assemblies support COM.
[assembly: ComVisible(false)]

// On Windows, the following GUID is for the ID of the typelib if this
// project is exposed to COM. On other platforms, it unique identifies the
// title storage container when deploying this assembly to the device.
[assembly: Guid("00000000-0000-0000-0000-000000000000")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
[assembly: AssemblyVersion("0.1.<#= this.revision #>.<#= this.build #>")]
[assembly: AssemblyFileVersion("0.1.<#= this.revision #>.<#= this.build #>")]

<#+
    int revision = 0;
    int build = 0;
#>

Вы можете попробовать использовать UpdateVersion от Мэтта Гриффита. Сейчас оно довольно старое, но работает хорошо. Чтобы использовать его, вам просто нужно настроить событие перед сборкой, которое указывает на ваш файл AssemblyInfo.cs, и приложение обновит номера версий соответственно в соответствии с аргументами командной строки.

Поскольку приложение имеет открытый исходный код, я также создал версию для увеличения номера версии с использованием формата (Основная версия).(Малая версия).([Год][день года]).(Приращение). Больше информации об этом и пересмотренном коде доступно в моей записи блога, Номера версий сборки и.NET.

Обновление: я разместил код моей модифицированной версии приложения UpdateVersion на GitHub: https://github.com/munr/UpdateVersion

Вы можете выполнять более сложные версии с помощью сценариев сборки, таких как создание версий сборки

Другие вопросы по тегам