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

361

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

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

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

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

  Version: 0.1.92

Как это можно достичь?

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

  • 2
    несмотря на то, что на вопрос уже есть ответ, ответ Ноэля Кеннеди и Матье более полезен, чем другой вопрос / ответ
Теги:
visual-studio
versioning

9 ответов

505
Лучший ответ

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

  • 46
    Также стоит отметить, что если указаны и AssemblyVersion и AssemblyFileVersion , вы не увидите этого в вашем .exe
  • 146
    Установка только 4-го числа в «*» может быть плохой, так как версия не всегда увеличивается. 3-е число - это количество дней с 2000 года, а 4-е число - это количество секунд с полуночи (деленное на 2) [ЭТО НЕ СЛУЧАЙНО]. Таким образом, если вы создали решение в конце дня, а в начале дня следующего дня, у более поздней сборки будет более ранний номер версии. Я рекомендую всегда использовать «XY *» вместо «XYZ *», потому что номер вашей версии ВСЕГДА будет увеличиваться (если только вы не компилируете код изнутри вашего ТАРДИС - в таком случае, я могу прийти?).
Показать ещё 22 комментария
144

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

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

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

  • Создайте файл с расширением ".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 года. Как вы можете видеть, правило генерации версий написано на простом С#, поэтому вы можете легко отрегулируйте его в соответствии с вашими потребностями.

  1. Файл, указанный выше, должен быть помещен в один из проектов. Я создал новый проект только с одним файлом для управления версиями техника четкая. Когда я создаю этот проект (на самом деле мне даже не нужно для его создания: сохранения файла достаточно, чтобы вызвать Visual Studio action), генерируется следующий С#:
// 
// 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")]

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

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

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

  • 2
    Я думаю, что это отличное решение, потому что оно обладает гибкостью надстроек и пользовательских исполняемых файлов, но является чистым готовым решением Visual Studio.
  • 1
    Работал хорошо для моих нужд, используя bzr revno для заполнения части информации о версии
Показать ещё 10 комментариев
27

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

БОЛЬШЕ лучшее решение для спасения жизни http://autobuildversion.codeplex.com/

Он работает как шарм, и он ОЧЕНЬ гибкий.

  • 1
    не работает на VS2013.
26

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

Для более подробного объяснения это будет читать существующий файл AssemblyInfo.cs и использовать регулярное выражение для поиска информации AssemblyVersion, а затем увеличивать числа ревизий и сборки на основе ввода из TextTransform.exe. Обратите внимание, что номера сборки и/или ревизии будут только увеличиваться при обработке с TextTransform.exe. Если вы сохраните файл .tt или щелкните его правой кнопкой мыши и нажмите "Запустить пользовательский инструмент", он оставит файл AssemblyInfo.cs неповрежденным. Также обратите внимание, что если AssemblyInfo.cs не существует, то он создаст его со значением 0 для сборки и ревизии.

Замените файл AssemblyInfo.cs на этот AssemblyInfo.tt файл:

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

<#
    bool incRevision = false;
    bool incBuild = false;

    try { incRevision = Convert.ToBoolean(this.Host.ResolveParameterValue("","","revision")); } catch( Exception ) { }
    try { incBuild = Convert.ToBoolean(this.Host.ResolveParameterValue("","","build")); } catch( Exception ) { }
    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?1:0);
        build = Convert.ToInt32(matches[0].Groups["build"].Value) + (incBuild?1:0);
    }
    catch( Exception ) { }
#>

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("1.0.<#= this.revision #>.<#= this.build #>")]
[assembly: AssemblyFileVersion("1.0.<#= this.revision #>.<#= this.build #>")]
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]

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

Добавьте это в свое предварительное событие отладки:

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

Добавьте это к событию Pre-build Release:

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

Если вы используете проект веб-приложения, добавьте его в событие предварительной сборки:

if $(Configuration) == Debug "%CommonProgramFiles(x86)%\microsoft shared\TextTemplating\10.0\TextTransform.exe" -a !!build!true "$(ProjectDir)Properties\AssemblyInfo.tt"
if $(Configuration) == Release "%CommonProgramFiles(x86)%\microsoft shared\TextTemplating\10.0\TextTransform.exe" -a !!revision!true -a !!build!true "$(ProjectDir)Properties\AssemblyInfo.tt"



Обратите внимание, что вам, возможно, придется отрегулировать некоторые вещи, такие как путь к вашему файлу AssemblyInfo.tt, и в зависимости от вашей версии Visual Studio вам также придется настроить путь к TextTransform.exe.

  • 1
    Можно ли переопределить номер версии в нескольких сборках?
  • 1
    @Tanya, да, просто отредактируйте файл AssemblyInfo.cs вручную перед сборкой. Введите число на один меньше, чем вы хотите. Итак, если вы хотите 5 , то введите 4 .
Показать ещё 6 комментариев
20

Здесь quote на AssemblyInfo.cs из MSDN:

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

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

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

  • 28
    Это увеличивается случайно? Они издеваются надо мной?
  • 25
    Согласно комментарию, оставленному на msdn.microsoft.com/en-us/library/… номер редакции не является случайным, но вместо этого это число секунд с 12:00, деленное на 2, что, на мой взгляд, не так уж плохо ,
Показать ещё 2 комментария
14

Используйте 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 или в элементе управления, вы можете добавить в <Page> тег:

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

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

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

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

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

  • AutoBuildVersion - отлично смотрится, но его не работает на моем VS2010.

  • druciferre script работает, но я не могу в своей студии установить разные режимы для события предварительной сборки Debug и события Pre-build Release.

поэтому я немного изменил script... commamd:

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

и script (это работает с конфигурациями "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;
#>
  • 0
    Я использовал этот метод, но обнаружил, что символ авторского права изменился на знак вопроса при создании нового assimblyinfo.cs. Есть идеи как это исправить?
  • 0
    @TheKing использует кодовую точку Unicode вместо литерального символа.
8

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

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

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

  • 3
    code.mattgriffith.net/UpdateVersion не работает для меня с кодом ошибки 403.6
  • 1
    @Kiquenet: модифицированную версию Мана можно найти здесь . Ссылка на исходную страницу кажется мертвой.
1

Вы можете выполнить более расширенное управление версиями, используя скрипты сборки, такие как Build Versioning

Ещё вопросы

Сообщество Overcoder
Наверх
Меню