演练:创建内联任务
MSBuild 任务通常是通过编译可实现 ITask 接口的类来创建的。 从 .NET Framework 4 版开始,您可以在项目文件中创建内联任务, 而不必创建单独的程序集来承载任务。 有关更多信息,请参见 MSBuild 内联任务。
本演练演示如何创建和运行以下内联任务:
没有输入或输出参数的任务。
具有一个输入参数,但没有输出参数的任务。
具有两个输入参数,以及一个可返回 MSBuild 属性的输出参数的任务。
具有两个输入参数,以及一个可返回 MSBuild 项的输出参数的任务。
要创建并运行任务,请使用 Visual Studio 和**“Visual Studio 命令提示”**窗口,如下所示:
使用 Visual Studio 创建 MSBuild 项目文件。
在 Visual Studio 中修改项目文件以创建内联任务。
使用**“命令提示符窗口”**生成项目,并检查结果。
创建和修改 MSBuild 项目
Visual Studio 项目系统以 MSBuild 为基础。 因此,可以使用 Visual Studio 来创建生成项目文件。 在本节中,将创建一个 Visual C# 项目文件。 (可以改为创建 Visual Basic 项目文件。 在此教程的上下文中,这两种项目文件的差别很小。)
创建和修改项目文件
在 Visual Studio 中的**“文件”菜单上,单击“新建”,然后单击“项目”**。
在**“新建项目”对话框中,选择 Visual C# 项目类型,再选择“Windows 窗体应用程序”模板。 在“名称”框中键入 InlineTasks。 键入解决方案的“位置”,例如,D:\。 确保“创建解决方案的目录”处于选定状态,“添加到源代码管理”处于清除状态,并且“解决方案名称”**为 InlineTasks。
单击**“确定”**创建项目文件。
在**“解决方案资源管理器”中,右击 InlineTasks 项目节点,然后单击“卸载项目”**。
再次右击该项目节点,然后单击**“编辑 InlineTasks.csproj”**。
此时,该项目文件将出现在代码编辑器中。
添加基本的 Hello 任务
现在,向项目文件中添加一个显示消息“Hello, world!”的基本任务。另外添加一个用于调用该任务的默认 TestBuild 目标。
添加基本的 hello 任务
在根 Project 节点中,将 DefaultTargets 特性更改为 TestBuild。生成的 Project 节点应类似于以下示例:
<Project ToolsVersion="4.0" DefaultTargets="TestBuild" xmlns="https://schemas.microsoft.com/developer/msbuild/2003">
将以下内联任务和目标添加到项目文件中 </Project> 标记的前面。
<UsingTask TaskName="Hello" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" > <ParameterGroup /> <Task> <Code Type="Fragment" Language="cs"> Log.LogMessage("Hello, world!", MessageImportance.High); </Code> </Task> </UsingTask> <Target Name="TestBuild"> <Hello /> </Target>
保存项目文件。
此代码将创建一个内联任务,该任务名为 Hello,并且没有参数、引用或 Using 语句。 Hello 任务只包含一行代码,用于在默认日志记录设备(通常为控制台窗口)上显示 hello 消息。
运行 Hello 任务
使用**“命令提示符窗口”**运行 MSBuild,以构建 Hello 任务并处理调用该任务的 TestBuild 目标。
运行 Hello 任务
依次单击**“开始”、“所有程序”,然后找到“Visual Studio 工具”文件夹并单击“Visual Studio 命令提示”**。
在**“命令提示符窗口”**中,找到包含项目文件的文件夹,本例中为 D:\InlineTasks\InlineTasks\。
键入不带命令开关的 msbuild,然后按 Enter。 默认情况下,此操作将生成 InlineTasks.csproj 文件,并处理调用 Hello 任务的默认目标 TestBuild。
在**“命令提示符窗口”**中检查输出。 您应会看到以下行:
Hello, world!
备注
如果看不到 hello 消息,请尝试再次保存项目文件,然后运行 Hello 任务。
通过交替显示代码编辑器和**“命令提示符窗口”**,您可以更改项目文件并快速查看结果。
定义 Echo 任务
创建一个内联任务,该任务接受字符串参数,并在默认日志记录设备上显示字符串。
定义 Echo 任务
在代码编辑器中,使用以下代码替换 Hello 任务和 TestBuild 目标。
<UsingTask TaskName="Echo" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" > <ParameterGroup> <Text Required="true" /> </ParameterGroup> <Task> <Code Type="Fragment" Language="cs"> Log.LogMessage(Text, MessageImportance.High); </Code> </Task> </UsingTask> <Target Name="TestBuild"> <Echo Text="Greetings!" /> </Target>
在**“命令提示符窗口”**中,键入不带命令开关的 msbuild,然后按 Enter。 默认情况下,此操作将处理调用 Echo 任务的默认目标 TestBuild。
在**“命令提示符窗口”**中检查输出。 您应会看到以下行:
Greetings!
此代码将定义一个内联任务,该任务名为 Echo,并且只有一个必需的输入参数 Text。 默认情况下,参数的类型为 System.String。 Text 参数的值是在 TestBuild 目标调用 Echo 任务时设置的。
定义 Adder 任务
创建一个内联任务,该任务将添加两个整数参数,并将这些参数的和作为 MSBuild 属性发出。
定义 Adder 任务
在代码编辑器中,使用以下代码替换 Echo 任务和 TestBuild 目标。
<UsingTask TaskName="Adder" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" > <ParameterGroup> <A ParameterType="System.Int32" Required="true" /> <B ParameterType="System.Int32" Required="true" /> <C ParameterType="System.Int32" Output="true" /> </ParameterGroup> <Task> <Code Type="Fragment" Language="cs"> C = A + B; </Code> </Task> </UsingTask> <Target Name="TestBuild"> <Adder A="4" B="5"> <Output PropertyName="Sum" TaskParameter="C" /> </Adder> <Message Text="The sum is $(Sum)" Importance="High" /> </Target>
在**“命令提示符窗口”**中,键入不带命令开关的 msbuild,然后按 Enter。 默认情况下,此操作将处理调用 Echo 任务的默认目标 TestBuild。
在**“命令提示符窗口”**中检查输出。 您应会看到以下行:
The sum is 9
此代码将定义一个内联任务,该任务名为 Adder,并具有两个必需的整数输入参数 A 和 B,以及一个整数输出参数 C。 Adder 任务将添加两个输入参数,并在输出参数中返回和。 和将作为 MSBuild 属性 Sum 发出。 输入参数的值是在 TestBuild 目标调用 Adder 任务时设置的。
定义 RegX 任务
创建一个内联任务,该任务接受项组和正则表达式,并返回文件内容与表达式匹配的所有项的列表。
定义 RegX 任务
在代码编辑器中,使用以下代码替换 Adder 任务和 TestBuild 目标。
<UsingTask TaskName="RegX" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" > <ParameterGroup> <Expression Required="true" /> <Files ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" /> <Result ParameterType="Microsoft.Build.Framework.ITaskItem[]" Output="true" /> </ParameterGroup> <Task> <Using Namespace="System.Text.RegularExpressions"/> <Code Type="Fragment" Language="cs"> <![CDATA[ if (Files.Length > 0) { Result = new TaskItem[Files.Length]; for (int i = 0; i < Files.Length; i++) { ITaskItem item = Files[i]; string path = item.GetMetadata("FullPath"); using(StreamReader rdr = File.OpenText(path)) { if (Regex.Match(rdr.ReadToEnd(), Expression).Success) { Result[i] = new TaskItem(item.ItemSpec); } } } } ]]> </Code> </Task> </UsingTask> <Target Name="TestBuild"> <RegX Expression="public|protected" Files="@(Compile)"> <Output ItemName="MatchedFiles" TaskParameter="Result" /> </RegX> <Message Text="Input files: @(Compile)" Importance="High" /> <Message Text="Matched files: @(MatchedFiles)" Importance="High" /> </Target>
在**“命令提示符窗口”**中,键入不带命令开关的 msbuild,然后按 Enter。 默认情况下,此操作将处理调用 RegX 任务的默认目标 TestBuild。
在**“命令提示符窗口”**中检查输出。 您应会看到以下各行:
Input files: Form1.cs;Form1.Designer.cs;Program.cs;Properties\AssemblyInfo.cs;Properties\Resources.Designer.cs;Properties\Settings.Designer.cs
Matched files: Form1.cs;Form1.Designer.cs;Properties\Settings.Designer.cs
此代码将定义一个内联任务,该任务名为 RegX,并且具有以下三个参数:
Expression 是必需的字符串输入参数,其值是要匹配的正则表达式。 在本例中,表达式匹配单词“public”或“protected”。
Files 是必需的项列表输入参数,其值是要针对匹配进行搜索的文件的列表。 在本例中,Files 设置为 Compile 项,该项将列出项目源文件。
Result 是输出参数,其值是内容与正则表达式匹配的文件的列表。
输入参数的值是在 TestBuild 目标调用 RegX 任务时设置的。 RegX 任务将读取每个文件,并返回与正则表达式匹配的文件的列表。 此列表将作为 Result 输出参数返回,后者将以 MSBuild 项 MatchedFiles 的形式发出。
处理保留字符
MSBuild 分析器以 XML 的形式处理内联任务。 系统将检测并处理在 XML 中具有保留意义的字符(例如,“<”和“>”),就好像这些字符是 XML(而不是 .NET 源代码)一样。 要将保留字符包括在诸如 Files.Length > 0 等代码表达式中,请编写 Code 元素以使其内容包含在 CDATA 表达式中,如下所示:
<Code Type="Fragment" Language="cs">
<![CDATA[
// Your code goes here.
]]>
</Code>