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






4.33/5 (13投票s)
本文介绍如何通过 AssemblyInfo.cs 生成的示例来定制 csproj 文件。
引言
每次我们创建一个新的 C# 项目时,Visual Studio 都会为我们生成一个 AssemblyInfo.cs 文件。该文件定义了程序集的元数据,如版本、配置或生产者。在小型解决方案中,我们可以手动编辑这些文件;然而,在大型解决方案中,这项重复而枯燥的任务会变得很麻烦。
解决此问题的常见方法是使用构建脚本,该脚本首先更新所有 AssemblyInfo.cs 文件,然后编译源代码(通常通过调用 MSBuild,并将 sln 或 csproj 文件传递给它)。
在本文中,我想提出一种不同的方法,该方法利用了这样一个事实:(自 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.cs。AssemblyInfo
任务在 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 文档,其顶层包含 PropertyGroup
、ItemGroup
和 Import
部分。导航到 Import
部分,并在其下方插入新行,使片段看起来像
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\Versioning.targets" />
这使得我们之前创建的 targets 文件成为该项目的一部分。请确保该文件已复制到 sln 文件所在的目录(比包含此项目 csproj 的目录高一个级别)。
像这样,您可以根据需要定制任意多个项目。它们都将引用我们 targets 文件的同一副本,这意味着如果我们更改它,所有项目都会受到影响。这使我们能够进一步扩展构建,例如,通过运行单元测试。而且,我们可以确信,无论如何启动构建,我们的自定义 targets 始终会被调用。
关注点
- 扩展 MSBuild 附带的默认脚本,这些脚本在每次构建 C# 项目时都会使用。
- 了解 Visual Studio 构建过程的一些基本工作原理。
历史
- 2008.07.19 - 初始版本。