.Net项目版本号的生成

给.Net项目编译的程序集加入版本号的方式有许多种,包括:

1. 默认的方式,在每个项目的AssemblyInfo.cs文件中指定版本号:

 1 // Version information for an assembly consists of the following four values:
 2 //
 3 //      Major Version
 4 //      Minor Version
 5 //      Build Number
 6 //      Revision
 7 //
 8 // You can specify all the values or you can default the Build and Revision Numbers
 9 // by using the ‘*‘ as shown below:
10 // [assembly: AssemblyVersion("1.0.*")]
11 [assembly: AssemblyVersion("1.0.0.0")]
12 [assembly: AssemblyFileVersion("1.0.0.0")]

2. 使用IDE的插件方式定制版本号增加的方式:

从上图中可以看到,这个插件可以通过根据时间信息来生产每一位的版本号

3. 通过T4模板在每次编译解决方案时更新项目的版本号

T4模板是一种在设计阶段帮助开发人员按照一定规则生产代码的机制,在IDE中可以添加:

具体的介绍可以参考MSDN上面的:
http://msdn.microsoft.com/en-us/library/bb126445(v=VS.100).aspx

我们在这里使用T4模板的目的就是让它根据当前的subversion上的revision number生产版本号

using System.Reflection;

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

其中最后一位是当前的SvnRevisionNumber

具体操作方法如下:

(1)为了使用T4模板,需要安装Visual Studio 2010 SP1 SDK和Visual Studio 2010 SP1 Visualization and Modeling SDK

Visual Studio 2010 SP1 SDK的下载地址:
http://visualstudiogallery.msdn.microsoft.com/25622469-19d8-4959-8e5c-4025d1c9183d

Visual Studio 2010 SP1 Visualization and Modeling SDK的下载地址:
http://www.microsoft.com/en-us/download/details.aspx?id=23025

(2)在需要共享同一个版本号的解决方案中新增一个新的项目

(3)编辑这个项目文件,加入如下内容:

(4)在这个新项目中添加一个T4模板文件

(5)编辑这个扩展名为tt的模板, 内容如下:

 1 <#@ template hostspecific="true" language="C#" #>
 2 <#@ output extension=".cs" #>
 3 <#@ Assembly name="E:\trunk\src\BuildVersion\SSvnEx-1.7002.1998\SharpSvn\SharpSvn.dll" #>
 4 <#@ import namespace="System.IO" #>
 5 <#@ import namespace="SharpSvn" #>
 6 <#
 7     string RevisionNumber = String.Empty;
 8     SvnInfoEventArgs args;
 9     SvnPathTarget target = SvnPathTarget.FromString(@"E:\trunk\src");
10     try
11     {
12         new SvnClient().GetInfo(target, out args);
13         RevisionNumber = args.LastChangeRevision.ToString();
14     }
15     catch (SvnWorkingCopyPathNotFoundException)
16     {
17         RevisionNumber = "0";
18     }
19 #>
20 //
21 // This code was generated by a tool. Any changes made manually will be lost
22 // the next time this code is regenerated.
23 //
24
25 using System.Reflection;
26
27 [assembly: AssemblyVersion("1.0.0.<#= RevisionNumber #>")]
28 [assembly: AssemblyFileVersion("1.0.0.<#= RevisionNumber #>")]

上面的代码使用SharpSvn类库来读取指定目录下的svn信息,并将LastChangeRevision作为最后一位的版本号。


注:
这里的<#@ Assembly name="E:\trunk\src\BuildVersion\SSvnEx-1.7002.1998\SharpSvn\SharpSvn.dll" #>
引用外部dll时,T4模板不能使用相对路径

可以使用如下5中方式指定程序集的引用:

a. 将T4需要引用的模板加入到GAC中,之后在T4中就可以直接写上程序集的名字了:
<#@ Assembly name="SharpSvn.dll" #>

b. 使用绝对路径指定程序集名字:
<#@ Assembly name="E:\trunk\src\BuildVersion\SSvnEx-1.7002.1998\SharpSvn\SharpSvn.dll" #>

c. 将程序集拷贝到Visual Studio的 "Public Assemblies Folder"中,之后在T4中就可以直接写上程序集的名字了:
<#@ Assembly name="SharpSvn.dll" #>

d. 使用一个环境变量来代替绝对路径:
<#@ Assembly name="%mylib%\SharpSvn.dll" #>

e. 使用Visual Studio Macro来构建程序集路径:
<#@ Assembly name="$(SolutionDir)lib\SharpSvn.dll" #>

(6)编译这个包含T4模板的项目,或者保存这个模板文件,都会触发T4生成一个cs文件,内容如下:

(7)在其他项目中添加这个生成的cs文件,以link的方式添加:

(8)注释掉这些项目原有的版本信息:

到此为止,所有引用了这个BuildVersion.cs文件的项目都会根据这个文件的内容生产版本号了,而这个版本号是来自于指定svn路径下的revision number。

4. 通过定制一个MSBuild Task,在每次编译时更新版本号信息。
MSBuild提供对复杂编译任务的可定制,我们通过继承代表一次编译任务的Task类,并重写其Execute方法来定制自己的编译任务。

(1)首先,我们需要建立一个Class Library类型的项目,并引用下面的程序集:

(2)继承Task类,并实现自己的Execute方法:

下面的代码通过读取含有版本号信息的cs文件,使用正则表达式解析出四位版本号,并实现我们自己的版本号增加逻辑,这里的逻辑是根据Jenkins的环境变量,将版本号第三位置为Jenkins的BuildNumber,将第四位置为SVN Revison号。
注:这里在处理来自svn的revision number时,当其大于UInt16.MaxValue时,我们舍弃其最高位,因为Assembly Version的值需要在0~UInt16.MaxValue之间。

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using Microsoft.Build.Utilities;
  6 using System.IO;
  7 using System.Text.RegularExpressions;
  8
  9 namespace VersionInfoBuildTask
 10 {
 11     public class AutoIncrementTask : Task
 12     {
 13         private const string AssemlyVersionPattern =
 14         @"\[assembly: AssemblyVersion\(\""(\d{1}).(\d{1}).(\d{1,}).(\d{1,})""\)\]";
 15
 16         private const string AssemlyFileVersionPattern =
 17         @"\[assembly: AssemblyFileVersion\(\""(\d{1}).(\d{1}).(\d{1,}).(\d{1,})""\)\]";
 18
 19         private const string AssemblyInformationalVersionPattern =
 20         @"\[assembly: AssemblyInformationalVersion\(\""(\d{1}).(\d{1}).(\d{1,}).(\d{1,})""\)\]";
 21
 22         public string AssemblyInfoPath { get; set; }
 23
 24         public override bool Execute()
 25         {
 26             try
 27             {
 28                 if (String.IsNullOrEmpty(AssemblyInfoPath))
 29                     throw new ArgumentException("AssemblyInfoPath must have a value");
 30
 31                 string[] content = File.ReadAllLines(AssemblyInfoPath, Encoding.Default);
 32                 var rxForAssemlyVersion = new Regex(AssemlyVersionPattern);
 33                 var rxForFileVersion = new Regex(AssemlyFileVersionPattern);
 34                 var rxForInfoVersion = new Regex(AssemblyInformationalVersionPattern);
 35
 36                 var newContent = new List<string>();
 37                 content.ToList().ForEach(line =>
 38                 {
 39                     if (rxForAssemlyVersion.IsMatch(line))
 40                     {
 41                         line = VersionMatcherForAssemlyVersion(rxForAssemlyVersion.Match(line));
 42                         Console.Out.WriteLine("Match result for assembly version is: " + line);
 43                     }
 44                     else if (rxForFileVersion.IsMatch(line))
 45                     {
 46                         line = VersionMatcherForFileVersion(rxForFileVersion.Match(line));
 47                         Console.Out.WriteLine("Match result for file version is: " + line);
 48                     }
 49                     else if (rxForInfoVersion.IsMatch(line))
 50                     {
 51                         line = VersionMatcherForInfoVersion(rxForInfoVersion.Match(line));
 52                         Console.Out.WriteLine("Match result for info version is: " + line);
 53                     }
 54                     else
 55                     {
 56                         Console.Out.WriteLine(line + " didn‘t match!!");
 57                     }
 58                     newContent.Add(line);
 59                 });
 60
 61                 File.WriteAllLines(AssemblyInfoPath, newContent.ToArray());
 62             }
 63             catch (Exception ex)
 64             {
 65                 Console.Out.WriteLine(ex);
 66                 return false;
 67             }
 68
 69             return true;
 70         }
 71
 72         private string VersionMatcherForFileVersion(Match match)
 73         {
 74             int major = int.Parse(match.Groups[1].Value);
 75             int minor = int.Parse(match.Groups[2].Value);
 76             int build = int.Parse(match.Groups[3].Value);
 77             string revision = match.Groups[4].Value;
 78
 79             Console.WriteLine("AutoIncrement Assembly {0}",
 80                 Path.GetFileName(AssemblyInfoPath));
 81             Console.WriteLine("Current matched version: {0}.{1}.{2}.{3}",
 82                 major, minor, build, revision);
 83
 84             string buildNumber = Environment.GetEnvironmentVariable("BUILD_NUMBER");
 85             if (buildNumber == null) buildNumber = "0";
 86
 87             string revisionNumber = Environment.GetEnvironmentVariable("SVN_REVISION");
 88             if (revisionNumber == null) revisionNumber = "0";
 89             if (long.Parse(revisionNumber) > UInt16.MaxValue)
 90             {
 91                 Console.WriteLine("The revision number is too big");
 92                 long rev = long.Parse(revisionNumber);
 93                 rev = rev % 10000;
 94                 revisionNumber = rev.ToString();
 95             }
 96
 97             Console.WriteLine("Incremented to version: {0}.{1}.{2}.{3}",
 98                 major, minor, build, revision);
 99
100             string result = match.Result
101                 ("[assembly: AssemblyFileVersion(\"$1.$2.{0}.{1}\")]");
102             return String.Format(result, buildNumber, revisionNumber);
103         }
104     }
105 }

(3)准备一个proj文件,这个文件是运行msbuild时需要指定的,主要是告知msbuild实现定制任务的程序集在哪里,和定制任务的输入文件在哪里:

1 <?xml version="1.0" encoding="utf-8" ?>
2 <Project ToolsVersion="4.0" DefaultTargets="IncrementBuild"
3     xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
4     <UsingTask AssemblyFile="VersionInfoBuildTask.dll" TaskName="AutoIncrementTask" />
5     <Target Name="IncrementBuild">
6         <AutoIncrementTask AssemblyInfoPath="SharedAssemblyInfo.cs" />
7     </Target>
8 </Project>

(4)准备一个包含程序集版本信息的文件,这里的SharedAssemblyInfo.cs就是将要传给定制来任务处理的文件,内容如下:

(5)将SharedAssemblyInfo.cs文件加入到解决方案中,其中的所有项目都使用Add as link方式加入这个文件,以达到共享版本信息的目的 :

(6)将编译好的VersionInfoBuildTask.dll文件,与这个proj文件都放到Jenkins的workspace目录中:

并使用下面的命令来运行这个定制的Task:
msbuild BuildTask.proj /t:IncrementBuild

运行之后,查看SharedAssemblyInfo.cs的内容,发现版本号已经发生了改变:

好了,下面就可以使用msbuild来编译整个解决方案了,之后我们查看编译出来的程序集的版本号:

版本号最后两位对应Jenkins上的build number和revision number(舍去最高位),这样做是方便查询每个版本所对应的代码变更信息:

时间: 2024-10-13 18:11:52

.Net项目版本号的生成的相关文章

新版本ADT创建Android项目无法自动生成R文件解决办法

本人使用的是ADT是Version 23.0.2,支持Android 6.0之后的系统环境,最高版本23,在创建Android项目的时候,每次创建项目选择“Compile With”低于6.0版本的时候,都无法自动生成R文件,这个时候MainActivity文件报错,反复点击项目后执行“Clean”后,错误无法解 决,按照之前不生成R文件的办法解决不了,那怎么办呢?先分析错误产生的原因. 案例参考:新版本ADT创建Android项目无法自动生成R文件解决办法 | TeachCourse

eclipse或adt-bundle创建的android项目没有自动生成MainActivity.java和activity_main.xml等文件解决办法

以前我电脑一直以来都是用的eclipse3.7来开发android项目的,创建android项目也能正常生成MainActivity.java和activity_main.xml等文件.后来不知道什么原因,电脑几个盘上的文件很多打开都显示乱码.找了很多方法都无法解决,所以就把硬盘给格式化重装了系统. 重装系统后,重新配置了eclipse的android开发环境,但发现创建的android项目不能正常生成MainActivity.java和activity_main.xml等文件,网上找了很多方法

C#dll版本号默认生成规则

原文:C#dll版本号默认生成规则 1.版本号自动生成方法 只需把 AssemblyInfo.cs文件中的[assembly: AssemblyVersion("1.0.0.0")]改成[assembly: AssemblyVersion("1.0.*")],另外还需要把[assembly: AssemblyFileVersion("1.0.0.0")]注释屏蔽掉.这样再生成的程序集就是自动版本号了. 2.按照这个格式出来的版本号,内部修订版本号

用于对项目中密码生成MD5摘要和加盐的工具类

import java.security.MessageDigest; /** * 用于对项目中密码生成MD5摘要和加盐的工具类 * @author 彭锋 */ public final class MD5Util { private static final char[] hexadecimal = {'0','1','2','3','4','5','6', '7','8','9','a','b','c','d','e','f'}; /** * 根据指定的字符串,返回对应的MD5摘要结果 *

在Vue项目中动态生成二维码 阿星小栈

一.使用jquery.qrcode生成二维码 1.首先在页面中加入jquery库文件和qrcode插件 <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript" src="jquery.qrcode.min.js"></script> 2.在页面中需要显示二维码的

Unity3D游戏开发之从Unity3D项目版本号控制说起

??各位朋友.大家好.欢迎大家关注我的博客,我是秦元培,我的独立博客地址是http://qinyuanpei.com.CSDN博客地址是http://blog.csdn.net/qinyuanpei. 今天我想和大家聊聊Unity3D游戏项目的版本号控制. 1.为什么要进行版本号控制? ??当我一个人写代码的时候,在我的脑海中是不存在版本号控制这个概念的.由于我对整个项目的代码如数家珍. 但是当我和一群人在一起写代码的时候.我可能并不会清楚团队中有谁改动了哪一行代码,即使是一个变量的名称或者是一

软件项目版本号的命名规则及格式

转载:http://blog.csdn.net/rovast/article/details/52083073 转载:http://blog.csdn.net/mfcing/article/details/12969059 版本控制比较普遍的 3 种命名格式 : 一.GNU 风格的版本号命名格式 :主版本号 . 子版本号 [. 修正版本号 [. 编译版本号 ]]Major_Version_Number.Minor_Version_Number[.Revision_Number[.Build_Nu

[转]软件项目版本号的命名规则、格式介绍及管理策略

转自:http://www.flighty.cn/html/net/20121029_163.html 轻狂注:各种软件的版本号经常搞得使用者云里雾里,不知道软件的开发者到底是如果定义自己软件的版本的,所以,有必要把软件版本号命名规则方面的常识列一下. 版本控制比较普遍的 3 种命名格式 : 一.GNU 风格的版本号命名格式 : 主版本号 . 子版本号 [. 修正版本号 [. 编译版本号 ]] 英文对照 : Major_Version_Number.Minor_Version_Number[.R

Visual Studio 2013环境下操作vc6/vc7/vc8等低版本平台项目【编译|生成|调试】

现代化的开发环境,微软一直在推出更新换代,我们所处的技术环境在日新月异的变化:不过在中国多数人们一边疲惫的追赶着时代的步伐,一边坚守着自己所获悉所掌握的那些紧吧吧的知本.对技术工具的掌握并非他们所想要,人人都是想借助工具作用以实现目标.所以,对于一段时间来而言,谁赶出了作品,谁就赢得了先机从此吸聚一大批人力来驱动其事业的成长.只是不过,如果只是赶出了一时间的作品,而从此只就其上迭代运作而不再从外吸纳新鲜的技术气氛,那可能解体终有一日. 从VC6到VC2008,再到2010.2013,到现在已经是