【问题标题】:Version number in manifest file's dependentAssembly/assemblyIdentity element清单文件的dependentAssembly/assemblyIdentity 元素中的版本号
【发布时间】:2016-03-12 10:35:08
【问题描述】:

我正在使用一个包含非托管客户端 DLL 和托管 COM 服务器 DLL 的应用程序(这本身就是一个挑战:Managed Reg-Free COM Server Won't Activate),现在我想知道保持版本号同步。由于我们正在构建客户端和服务器,并且我们尝试在每次构建时保持所有文件的版本号同步,看起来我需要一个过程来编辑客户端和服务器上的所有清单文件在完整构建发生之前,我所有隔离的 COM 引用结束。有没有更简单的方法?

示例(客户端清单):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
   <assemblyIdentity type="win32" name="globals" version="1.0.0.0" />
   <dependency>
      <dependentAssembly>
         <assemblyIdentity type="win32" name="SoftBrands.FourthShift.FSCulture" version="8.0.0.999" publicKeyToken="541b4aff0f04b60a" />
      </dependentAssembly>
   </dependency>
</assembly>

服务器清单:

<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <assemblyIdentity type="win32" name="SoftBrands.FourthShift.FSCulture" version="8.0.0.999" publicKeyToken="541b4aff0f04b60a" />
   <clrClass   clsid="{23D4FF3D-EEDF-4F68-AD65-749958EE3B2A}"
               name="SoftBrands.FourthShift.FSCulture.FSCulture"
               tlbid="{8D480B22-D603-309F-9A26-EA9E9B020207}">
   </clrClass>
</asmv1:assembly>

我可以在 version="8.0.0.999" 上进行全局搜索并替换为每个构建的当前版本,但我怀疑可能有更好的方法。

【问题讨论】:

  • 您是否考虑过使用自定义 MSBuild 任务来完成这项工作?
  • 没有。我不熟悉自定义 MSBuild 任务。假设它们不会导致其他开发人员的系统崩溃(由于缺少自定义安装),这可能是一个选项。乍一看,似乎需要在每个开发人员的系统上安装另一个程序集。我想我会倾向于在此之前使用全局替换解决方案。
  • 您可以将自定义任务的程序集包含在您的项目中,这样每个人都会拥有它与项目路径相关的内容。我们通常会将这些类型的文件检入我们的源代码存储库,并且对所有开发人员都是透明的。

标签: c# .net com manifest


【解决方案1】:

最好的办法是在编译之前利用自定义 MSBuild 任务来操作项目工件。

任务应该接受三个属性。客户端清单的一个属性,服务器清单的另一个属性和版本的第三个属性。

这是目标文件在 MSBuild 中的样子。

Manifests.targets

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
  <!-- Import Tasks -->
  <!-- Be sure to sue the full namespace of the task to import -->
  <UsingTask TaskName="Full.Namespace.To.UpdateManifestsTask" AssemblyFile="$(MSBuildThisFileDirectory)\MyCustomTasks.dll" />
  <!-- Define the location of the client and server manifest files -->
  <PropertyGroup>
    <ClientManifest><!-- Location of the client manifest --></ClientManifest>
    <ServerManifest><!-- Location of the server manifest --></ServerManifest>
  </PropertyGroup>
  <!-- Define Generate App Config Target -->
  <Target Name="UpdateManifests">
    <UpdateManifests ClientManifest="$(ClientManifest)" ServerManifest="$(ServerManifest)" Version="$(Version)" />
  </Target>
  <!-- Define Before Build Target -->
  <!-- This will ensure the above target gets executed prior to compilation -->
  <Target Name="BeforeBuild">
    <CallTarget Targets="UpdateManifests;" />
  </Target>
</Project>

这是自定义任务的外观 -

UpdateManifestsTask.cs

public class UpdateManifestsTask : Task
{
    public ITaskItem ClientManifest { get; set; }
    public ITaskItem ServerManifest { get; set; }
    public ITaskItem Version { get; set; }

    public override bool Execute()
    {
        var newVersion = string.Format("name=\"SoftBrands.FourthShift.FSCulture\" version=\"{0}\"", this.Version.ItemSpec);
        var clientFile = File.ReadAllText(this.ClientManifest.ItemSpec);
        clientFile = Regex.Replace(clientFile, "name=\"SoftBrands.FourthShift.FSCulture\" version=\"\\d*\\.\\d*\\.\\d*\\.\\d*\"", newVersion);
        File.WriteAllText(this.ClientManifest.ItemSpec, clientFile);
        var serverFile = File.ReadAllText(this.ClientManifest.ItemSpec);
        serverFile = Regex.Replace(clientFile, "name=\"SoftBrands.FourthShift.FSCulture\" version=\"\\d*\\.\\d*\\.\\d*\\.\\d*\"", newVersion);
        File.WriteAllText(this.ServerManifest.ItemSpec, serverFile);

        return true;
    }
}

RegEx 有点草率,因为这是一个快速而肮脏的例子,但这实际上是你做这种事情的方式。

请务必添加对 MSBuild 库的引用。

http://blogs.msdn.com/b/msbuild/archive/2006/01/21/515834.aspx

如果您不想构建自定义任务,您可以编写一个小型控制台应用程序来做同样的事情,但我认为自定义任务更简洁。

如果您决定采用控制台应用程序路线,您可以利用项目文件中的 BeforeBuild 和 AfterBuild 事件。

  <Target Name="BeforeBuild">
      <!-- Invoke console app -->
  </Target>
  <Target Name="AfterBuild">
  </Target>

【讨论】:

  • 您想过自定义任务会做什么吗?我可以想到一些可能性:设置一个 $(ProductVersion) 宏以匹配来自共享 RC 文件的宏(然后在项目链接器设置的清单文件部分中使用该宏);在项目中搜索所有 .manifest 文件并替换包含在 assemblyIdentity 元素中的版本属性;构建后运行 mt.exe 以替换清单中的版本信息...
  • 查看更新后的答案,其中提供了有关如何处理此问题的更多详细信息。
  • 我试图想象它在使用时会是什么样子,我怀疑它会简单地暴露一些额外的项目属性。因此,我不确定这如何简化在构建中跨所有项目同步版本号的过程。是否有某种机制,跨多个解决方案的整个项目树可以共享某些属性的相同属性值?
  • 当然。 MSBuild 允许您执行此操作。只需将您的属性放在 *.properties 文件中,并将其包含在需要这些属性的任何其他 MSBuild 文件中。
  • 属性文件只不过是一个包含属性的 MSBuild 文件。这也适用于 C# 项目。
猜你喜欢
  • 2011-03-22
  • 1970-01-01
  • 1970-01-01
  • 2014-02-11
  • 2011-11-02
  • 1970-01-01
  • 1970-01-01
  • 2013-05-07
  • 2012-05-31
相关资源
最近更新 更多