MSBuild 内联任务
MSBuild 任务通常是通过编译可实现 ITask 接口的类来创建的。 有关详细信息,请参阅MSBuild 任务。
开始于 .NET Framework 4 版本,您可以在项目文件中创建内联任务。 而不必创建单独的程序集来承载任务。 这样,将能够更为轻松地跟踪源代码,并更为轻松地部署任务。 源代码集成在脚本中。
内联任务的结构
内联任务包含在 UsingTask 元素内。 内联任务以及包含该任务的 UsingTask 元素通常包括在 .targets 文件中,并将根据需要导入到其他项目文件中。 下面是一个基本内联任务。 请注意,该任务不执行任何操作。
<Project ToolsVersion="12.0" xmlns="https://schemas.microsoft.com/developer/msbuild/2003">
<!-- This simple inline task does nothing. -->
<UsingTask
TaskName="DoNothing"
TaskFactory="CodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v12.0.dll" >
<ParameterGroup />
<Task>
<Reference Include="" />
<Using Namespace="" />
<Code Type="Fragment" Language="cs">
</Code>
</Task>
</UsingTask>
</Project>
示例中的 UsingTask 元素具有三个特性,这些特性描述任务,以及用于编译该任务的内联任务工厂。
TaskName 特性为任务命名,在本例中,将命名为 DoNothing。
TaskFactory 特性为实现内联任务工厂的类命名。
AssemblyFile 特性指定内联任务工厂的位置。 或者,可以使用 AssemblyName 特性指定内联任务工厂类的完全限定名,该类通常位于全局程序集缓存 (GAC) 中。
DoNothing 任务的其余元素为空,提供这些元素的目的是为了阐释内联任务的顺序和结构。 本主题后面提供了一个功能更为全面的示例。
ParameterGroup 元素是可选的。 如果指定该元素,它将声明任务的参数。 有关输入和输出参数的更多信息,请参见本主题后面的“输入和输出参数”。
Task 元素描述并包含任务源代码。
Reference 元素指定对代码中所使用的 .NET 程序集的引用。 这相当于在 Visual Studio 中添加对项目的引用。 Include 特性指定所引用的程序集的路径。
Using 元素列出您希望访问的命名空间。 这类似于 Visual C# 中的 Using 语句。 Namespace 特性指定要包括的命名空间。
Reference 和 Using 元素与语言无关。 可以用任何一种支持的 .NET CodeDom 语言(例如,Visual Basic、Visual C# 或 JScript)编写内联任务。
备注
Task 元素中包含的元素特定于任务工厂(本例中为代码任务工厂)。
Code 元素
要出现在 Task 元素内的最后一个子元素是 Code 元素。 Code 元素包含或查找要编译到任务中的代码。 放在 Code 元素的内容取决于您希望如何编写任务。
Language 特性指定编写代码所采用的语言。 可接受的值为 C# 中的cs,Visual Basic 中的 VB 。
Type 特性指定在 Code 元素中找到的代码的类型。
如果 Type 的值为 Class,则 Code 元素包含派生自 ITask 接口的类的代码。
如果 Type 的值为 Method,则代码定义 ITask 接口的 Execute 方法的重写。
如果 Type 的值为 Fragment,则代码定义 Execute 方法的内容,但不定义签名或 return 语句。
代码本身通常出现在 <![CDATA[ 标记和 ]]> 标记之间。 由于代码位于 CDATA 部分中,因此您不必担心转义保留字符(例如,"<" 或 ">")。
或者,您可以使用 Code 元素的 Source 特性指定包含任务代码的文件的位置。 源文件中代码的类型必须为 Type 特性所指定的类型。 如果存在 Source 特性,则 Type 的默认值为 Class。 如果 Source 不存在,则默认值为 Fragment。
备注
在源文件中定义任务类时,类名必须与对应 UsingTask 元素的 TaskName 特性一致。
Hello World
下面是一个功能更全面的内联任务。 HelloWorld 任务在默认的错误日志记录设备(通常为系统控制台或 Visual Studio 的**“输出”**窗口)上显示“Hello, World!”。 示例中包括的 Reference 元素仅供阐释之用。
<Project ToolsVersion="12.0" xmlns="https://schemas.microsoft.com/developer/msbuild/2003">
<!-- This simple inline task displays "Hello, world!" -->
<UsingTask
TaskName="HelloWorld"
TaskFactory="CodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >
<ParameterGroup />
<Task>
<Reference Include="System.Xml.dll"/>
<Using Namespace="System"/>
<Using Namespace="System.IO"/>
<Code Type="Fragment" Language="cs">
<![CDATA[
// Display "Hello, world!"
Log.LogError("Hello, world!");
]]>
</Code>
</Task>
</UsingTask>
</Project>
可以将 HelloWorld 任务保存在名为 HelloWorld.targets 的文件中,然后按如下方式从项目中调用该任务。
<Project ToolsVersion="4.0" xmlns="https://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="HelloWorld.targets" />
<Target Name="Hello">
<HelloWorld />
</Target>
</Project>
输入和输出参数
内联任务参数是 ParameterGroup 元素的子元素。 每个参数都采用定义该参数的元素的名称。 下面的代码定义参数 Text。
<ParameterGroup>
<Text />
</ParameterGroup>
参数可能具有一个或多个以下特性:
Required 为可选特性,默认值为 false。 如果为 true,则参数为必需,并且必须在调用任务之前为参数指定值。
ParameterType 为可选特性,默认值为 System.String。 该特性可设置为作为项或值的完全限定类型,可以使用 System.Convert.ChangeType 将该项或值转换为字符串,以及从字符串进行转换。(换言之,可以将任何类型传递到外部任务,以及从外部任务传递任何类型。)
Output 为可选特性,默认值为 false。 如果为 true,则必须在从 Execute 方法返回之前为参数指定值。
例如,
<ParameterGroup>
<Expression Required="true" />
<Files ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<Tally ParameterType="System.Int32" Output="true" />
</ParameterGroup>
定义以下三个参数:
Expression 是必需的输入参数,类型为 System.String。
Files 是必需的项列表输入参数。
Tally 是输出参数,类型为 System.Int32。
如果 Code 元素具有 Type 特性 Fragment 或 Method,则会为每个参数自动创建属性。 否则,必须在任务源代码中显式地声明属性,并且属性必须与其参数定义完全匹配。
示例
以下内联任务将给定文件中出现的每处标记替换为给定值。
<Project xmlns='https://schemas.microsoft.com/developer/msbuild/2003' ToolsVersion="12.0">
<UsingTask TaskName="TokenReplace" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v12.0.dll">
<ParameterGroup>
<Path ParameterType="System.String" Required="true" />
<Token ParameterType="System.String" Required="true" />
<Replacement ParameterType="System.String" Required="true" />
</ParameterGroup>
<Task>
<Code Type="Fragment" Language="cs"><![CDATA[
string content = File.ReadAllText(Path);
content = content.Replace(Token, Replacement);
File.WriteAllText(Path, content);
]]></Code>
</Task>
</UsingTask>
<Target Name='Demo' >
<TokenReplace Path="C:\Project\Target.config" Token="$MyToken$" Replacement="MyValue"/>
</Target>
</Project>