如何拥有自动递增版本号(Visual Studio)?

时间:2009-05-05 20:28:03

标签: c# visual-studio versioning

我想存储一组在构建时自动递增的整数:

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

编译时,会自动增加Revision。当我构建安装项目时,它将增加MinorVersion(我可以手动执行此操作)。 MajorVersion只会手动递增。

然后我可以在菜单“帮助/关于”中向用户显示版本号:

  Version: 0.1.92

如何实现这一目标?

这个问题不仅要求如何拥有自动递增的版本号,还要求如何在代码中使用它,这是一个比其他更完整的答案。

9 个答案:

答案 0 :(得分:568)

如果向项目添加AssemblyInfo类并将AssemblyVersion属性修改为以星号结尾,例如:

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

Visual Studio会根据these rules为你增加最终数字(感谢galets,我完全错了!)

要在代码中引用此版本,以便您可以将其显示给用户,您可以使用反射。例如,

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:

同样值得注意的是,如果同时指定AssemblyVersionAssemblyFileVersion,则不会在.exe上看到此内容。

来自@ BrainSlugs83:

仅将第4个数字设置为*可能不好,因为版本不会总是递增。 第3个数字是自2000年以来的天数,第4个数字是自午夜以来的秒数(除以2)[不是随机数]。因此,如果您在一天的最后一天构建解决方案,并在第二天的早些时候构建解决方案,则后一版本将具有较早的版本号。我建议始终使用X.Y.*而不是X.Y.Z.*,因为您的版本号总是会以这种方式增加。

答案 1 :(得分:155)

您可以使用T4 templating mechanism in Visual Studio to generate the required source code from a simple text file

  

我想为某些.NET配置版本信息生成   项目。自从我调查可用以来已经有很长一段时间了   选项,所以我搜索周围希望找到一些简单的方法   这个。我发现的并不是很令人鼓舞:人们写道   Visual Studio加载项和自定义MsBuild任务只是为了获得一个   整数(好吧,也许两个)。这对于一个小的感觉有点过分   个人项目。

     

灵感来自StackOverflow讨论之一   有人建议T4模板可以完成这项工作。而且当然   他们能。该解决方案只需要很少的工作量而且没有Visual Studio   或构建流程定制。这里应该做些什么:

     
      
  1. 创建一个扩展名为“.tt”的文件,并放置将生成AssemblyVersion和AssemblyFileVersion属性的T4模板:
  2.   
<#@ 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;
#>
  

您必须决定版本号生成算法。对于   我自动生成一个设置为的修订号就足够了   自2010年1月1日以来的天数。正如您所看到的那样   版本生成规则是用简单的C#编写的,因此您可以轻松实现   根据您的需要调整它。

     
      
  1. 上述文件应放在其中一个项目中。我用这个单独的文件创建了一个新项目来进行版本管理   技术清晰。当我构建这个项目时(实际上我甚至不需要   构建它:保存文件足以触发Visual Studio   动作),生成以下C#:
  2.   
// 
// 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")]
  

是的,今天是自2010年1月1日起的113天。明天   修订号将改变。

     
      
  1. 下一步是从所有项目中的AssemblyInfo.cs文件中删除AssemblyVersion和AssemblyFileVersion属性   共享相同的自动生成的版本信息。而是选择“添加   现有项目“对于每个项目,导航到带有T4的文件夹   模板文件,选择相应的“.cs”文件并将其添加为链接。   那会的!
  2.         

    我喜欢这种方法,它是轻量级的(没有自定义   MsBuild任务)和自动生成的版本信息未添加到   源控制。当然还使用C#进行版本生成   算法打开任何复杂的算法。

答案 2 :(得分:42)

这是我对T4建议的实现...这将在每次构建项目时增加构建号,无论选择的配置如何(即Debug | Release),每次执行时都会增加修订号。发布版本。您可以通过应用程序➤装配信息...

继续更新主要版本号和次要版本号

为了更详细地解释,这将读取现有的AssemblyInfo.cs文件,并使用正则表达式查找AssemblyVersion信息,然后根据TextTransform.exe的输入增加修订和构建数字。

  1. 删除现有的AssemblyInfo.cs文件。
  2. 在其位置创建一个AssemblyInfo.tt文件。保存T4文件后,Visual Studio应创建AssemblyInfo.cs并将其与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"
    

答案 3 :(得分:31)

如果您为构建和修订版添加星号,Visual Studio将使用自2000年1月1日以来的天数作为内部版本号,并将自午夜以来的秒数除以2作为修订版。

更好的救生解决方案是http://autobuildversion.codeplex.com/

它就像一个魅力,它非常灵活。

答案 4 :(得分:23)

以下是quote on AssemblyInfo.cs from MSDN

  

您可以指定所有值或您   可以接受默认的内部版本号,   修订号,或两者都使用   星号()。例如,   [组件:的AssemblyVersion( “2.3.25.1”)]   表示2为主要版本,3为   次要版本,25作为构建   数字,1作为修订号。   版本号如   [组件:的AssemblyVersion( “1.2 ”)]   指定1为主要版本,2为   次要版本,并接受   默认构建和修订号。一个   版本号如   [组件:的AssemblyVersion( “1.2.15 *”)]   指定1为主要版本,2为   次要版本,15作为构建   数字,并接受默认值   修订号。默认构建   每天增加数量。默认   修订号是随机的

这实际上说,如果你将1.1。*放入汇编信息中,只有内部编号会自动增加,并且不会在每次构建之后发生,而是每天发生。修订号将改变每个构建,但是随机,而不是以递增的方式。

对于大多数用例来说,这可能已经足够了。如果那不是您正在寻找的东西,那么您将不得不编写一个脚本,该脚本会在预构建步骤中自动增加版本#

答案 5 :(得分: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页面或控件,您可以添加&lt; Page&gt;标签,以下内容:

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

(当然用适当的变量替换folderpath。)

我不认为你需要以任何方式为其他类添加编译器选项; App_Code中的所有内容在编译时都应该收到版本信息。

希望有所帮助。

答案 6 :(得分:10)

您可以尝试使用UpdateVersion by Matt Griffith。它现在已经很老了,但效果很好。要使用它,您只需要设置一个指向AssemblyInfo.cs文件的预构建事件,应用程序将根据命令行参数相应地更新版本号。

由于应用程序是开源的,我还创建了一个版本,使用格式(主要版本)增加版本号。(次要版本)。([year] [dayofyear])。(增量)。有关此内容和修订后代码的更多信息,请参阅我的博客文章Assembly Version Numbers and .NET

更新:我已将修改后的UpdateVersion应用程序版本的代码放在GitHub上:https://github.com/munr/UpdateVersion

答案 7 :(得分:10)

  • 版本中的明星(如“2.10.3。*”) - 很简单,但数字太大

  • AutoBuildVersion - 看起来不错,但它在我的VS2010上无效。

  • @ DrewChapin的脚本有效,但我不能在我的工作室为Debug pre-build事件和Release pre-build事件设置不同的模式。

所以我稍微改了一下脚本...... COMMAMD:

"%CommonProgramFiles(x86)%\microsoft shared\TextTemplating\10.0\TextTransform.exe" -a !!$(ConfigurationName)!1 "$(ProjectDir)Properties\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" #>
<#
    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;
#>

答案 8 :(得分:2)

您可以使用Build Versioning

等构建脚本执行更高级的版本控制