65.9K
CodeProject 正在变化。 阅读更多。
Home

定制 csproj 文件自动生成 AssemblyInfo.cs

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (13投票s)

2008 年 7 月 19 日

CPOL

4分钟阅读

viewsIcon

113381

downloadIcon

868

本文介绍如何通过 AssemblyInfo.cs 生成的示例来定制 csproj 文件。

引言

每次我们创建一个新的 C# 项目时,Visual Studio 都会为我们生成一个 AssemblyInfo.cs 文件。该文件定义了程序集的元数据,如版本、配置或生产者。在小型解决方案中,我们可以手动编辑这些文件;然而,在大型解决方案中,这项重复而枯燥的任务会变得很麻烦。

解决此问题的常见方法是使用构建脚本,该脚本首先更新所有 AssemblyInfo.cs 文件,然后编译源代码(通常通过调用 MSBuild,并将 slncsproj 文件传递给它)。

在本文中,我想提出一种不同的方法,该方法利用了这样一个事实:(自 VS.NET 2005 起) csproj 文件只是 MSBuild 脚本,并且是高度可定制的。通过对 csproj 文件进行微小修改,我们可以轻松解决 AssemblyInfo.cs 问题,并为进一步的定制奠定基础。

必备组件

在开始之前,请安装 MSBuild Community Tasks,可从 此处 下载。它们包含所介绍脚本使用的自定义任务。

创建自定义 targets 文件

我们将首先创建一个 targets 文件,该文件将包含版本控制功能,并将被我们的 C# 项目引用。(按惯例,targets 扩展用于为其他脚本提供某些功能的 MSBuild 脚本(可以将其与 C 或 C++ 中的头文件进行比较)。

该文件的最小结构是

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>

现在,在 Project 元素内部,我们将放置此行

<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\
                                       MSBuild.Community.Tasks.Targets"/>

它告诉 MSBuild 该脚本使用指定文件中定义的外部任务。

接下来是以下部分

<PropertyGroup>
    <My-Producer Condition=" $(My-Producer) == '' ">The Producer</My-Producer>
    <My-Copyright Condition=" $(My-Copyright) == '' ">Copyright (C) 2008 
                                The Producer</My-Copyright>
    <My-Major Condition=" $(My-Major) == '' ">1</My-Major>
    <My-Minor Condition=" $(My-Minor) == '' ">0</My-Minor>
    <My-Build Condition=" $(My-Build) == '' "></My-Build>
    <My-Revision Condition=" $(My-Revision) == '' ">0</My-Revision>
</PropertyGroup>

它指定了我们将要定制的所有项目的某些属性。如果我们想与多个解决方案共享该脚本,则不应在其中嵌入版本信息。但这超出了本文的范围。

接下来,我们定义 target

<Target Name="My-ConfigureVersionNumber">
    <CreateProperty Value="$(My-Major).$(My-Minor).$(My-Build).$(My-Revision)">
      <Output PropertyName="My-VersionNumber" TaskParameter="Value" />
    </CreateProperty>
</Target>

它将 My-ConfigureVersionNumber 属性设置为完整的版本号。

然后,我们添加

  <PropertyGroup>
    <My-PropertiesDir>Properties</My-PropertiesDir>
  </PropertyGroup>

  <ItemGroup>
    <My-AssemblyInfo Include="$(My-PropertiesDir)\AssemblyInfo.cs" />
    <Compile Include="@(My-AssemblyInfo)" />
  </ItemGroup>

上面的 XML 定义了 AssemblyInfo.cs 文件的位置。其中最有趣的部分是 Compile 项。它指示 MSBuild 将 AssemblyInfo.cs 文件传递给 C# 编译器。此行的存在将允许我们从项目中删除 AssemblyInfo.cs,但稍后将详细介绍。

接下来是两个利用我们之前定义的属性和项的目标

  <Target Name="My-CreateAssemblyInfo"
          DependsOnTargets="My-ConfigureVersionNumber">
    <MakeDir Directories="$(My-PropertiesDir)" />
    <AssemblyInfo OutputFile="@(My-AssemblyInfo)"
                      CodeLanguage="CS"
                      AssemblyCompany="$(My-Producer)"
                      AssemblyConfiguration="$(Configuration)"
                      AssemblyCopyright="$(My-Copyright)"
                      AssemblyFileVersion="$(My-VersionNumber)"
                      AssemblyInformationalVersion="$(My-VersionNumber)"
                      AssemblyTitle="$(AssemblyName)"
                      AssemblyVersion="$(My-VersionNumber)"
                      />
  </Target>

  <Target Name="My-DeleteAssemblyInfo">
    <Delete Files="@(My-AssemblyInfo)" />
  </Target>

这些目标分别负责创建和删除 AssemblyInfo.csAssemblyInfo 任务在 MSBuild Community Tasks 项目中定义。

请注意,第一个目标已设置了依赖项。这是为了确保 My-VersionNumber 属性始终被初始化。

最后,最后一部分

  <PropertyGroup>
    <BuildDependsOn>My-ConfigureVersionNumber;My-CreateAssemblyInfo;
                    $(BuildDependsOn)</BuildDependsOn>
    <CleanDependsOn>My-DeleteAssemblyInfo;$(CleanDependsOn)</CleanDependsOn>
  </PropertyGroup>

在这里,我们更新由 C# 项目的默认 MSBuild 脚本使用的两个属性的值。这些属性决定了在构建或清理项目时调用哪些目标。上面的部分将我们的自定义目标添加到默认目标的前面。这确保了我们的目标始终被调用——无论应用程序是从 IDE 内部还是从命令行(或 CI 服务器)编译的。

就这样——targets 文件已完成,应保存,我们很快就会用到它。

定制 csproj 文件

现在我们有了 targets 文件,我们可以修改我们的 C# 项目。

为了使演示更简单,我们将从一个空的项目类型为类库的 C# 项目开始(当然,此方法也适用于其他项目类型)。请启动 Visual Studio 并创建解决方案和项目。现在,在解决方案资源管理器中,导航到项目,展开 Properties 文件夹,然后删除 AssemblyInfo.cs 文件。我们不再需要它了。

现在,请在 Visual Studio 之外打开 csproj 文件——使用记事本即可(因为 Visual Studio 不允许您手动编辑该文件)。该文件是一个 XML 文档,其顶层包含 PropertyGroupItemGroupImport 部分。导航到 Import 部分,并在其下方插入新行,使片段看起来像

  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <Import Project="..\Versioning.targets" />

这使得我们之前创建的 targets 文件成为该项目的一部分。请确保该文件已复制到 sln 文件所在的目录(比包含此项目 csproj 的目录高一个级别)。

像这样,您可以根据需要定制任意多个项目。它们都将引用我们 targets 文件的同一副本,这意味着如果我们更改它,所有项目都会受到影响。这使我们能够进一步扩展构建,例如,通过运行单元测试。而且,我们可以确信,无论如何启动构建,我们的自定义 targets 始终会被调用。

关注点

  • 扩展 MSBuild 附带的默认脚本,这些脚本在每次构建 C# 项目时都会使用。
  • 了解 Visual Studio 构建过程的一些基本工作原理。

历史

  • 2008.07.19 - 初始版本。
© . All rights reserved.