Написание задач

Задачи содержат код, который выполняется в процессе сборки. Задачи содержатся в целевых объектах. В MSBuild включена библиотека типичных задач, но вы также можете создавать собственные задачи. Дополнительные сведения о библиотеке задач, включенных в MSBuild, см. в статье Справочник по задачам MSBuild.

Задачи

Примеры задач: Copy — копирование одного или нескольких файлов; MakeDir — создание каталога; Csc — компиляция файлов исходного кода C#. Каждая задача реализуется в виде класса платформы .NET, реализующего интерфейс ITask, который определяется в сборке Microsoft.Build.Framework.dll.

Существуют два подхода к реализации задачи:

  • Прямая реализация интерфейса ITask.

  • Произведите класс от вспомогательного класса Task, который определен в сборке Microsoft.Build.Utilities.dll. Задача реализует интерфейс ITask и обеспечивает реализации по умолчанию некоторых элементов ITask. Кроме того, упрощается ведение журнала.

В обоих случаях необходимо добавить в свой класс метод Execute, то есть метод, который вызывается при выполнении задачи. Этот метод не принимает параметров и возвращает значение типа Boolean: true, если задача успешно выполнена, или false, если задачу выполнить не удалось. В приведенном ниже примере показана задача, которая не выполняет никакое действие и успешно завершается, возвращая значение true.

using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace MyTasks
{
    public class SimpleTask : Task
    {
        public override bool Execute()
        {
            return true;
        }
    }
}

Эта задача запускается из следующего файла проекта:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Target Name="MyTarget">
        <SimpleTask />
    </Target>
</Project>

Если свойства .NET создаются в классе задач, то выполняющиеся задачи могут получать входные данные из файла проекта. MSBuild задает эти свойства непосредственно перед вызовом метода Execute задачи. Чтобы создать свойство строки, используйте код задачи следующего вида:

using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace MyTasks
{
    public class SimpleTask : Task
    {
        public override bool Execute()
        {
            return true;
        }

        public string MyProperty { get; set; }
    }
}

Следующий файл проекта запускает эту задачу и присваивает свойству MyProperty указанное значение:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <Target Name="MyTarget">
      <SimpleTask MyProperty="Value for MyProperty" />
   </Target>
</Project>

Регистрация задач

Если проект будет выполнять задачу, для MSBuild нужно указать, как найти сборку, содержащую класс задачи. Задачи регистрируются с помощью элемента UsingTask (MSBuild).

Если в задаче есть зависимости, зависящие от среды выполнения, для MSBuild нужно указать, что задача должна быть запущена в определенной среде, определив Architecture и (или) Runtime в UsingTask.

Файл MSBuild в Microsoft.Common.tasks — это файл проекта, который содержит список элементов UsingTask, регистрирующих все задачи предоставленные в MSBuild. Этот файл включается автоматически при сборке каждого проекта. Если задача, зарегистрированная в Microsoft.Common.tasks, также зарегистрирована в текущем файле проекта, такой файл будет иметь приоритет. Таким образом можно переопределить задачу по умолчанию собственной задачей с тем же именем.

Совет

Чтобы увидеть список задач, предоставляемых с определенной версией MSBuild, просмотрите содержимое файла Microsoft.Common.tasks.

Создание событий из задачи

Если задача является производной от вспомогательного класса Task, вы можете использовать любой из следующих вспомогательных методов класса Task для создания событий, которые будут перехватываться и отображаться зарегистрированными средствами ведения журнала:

public override bool Execute()
{
    Log.LogError("messageResource1", "1", "2", "3");
    Log.LogWarning("messageResource2");
    Log.LogMessage(MessageImportance.High, "messageResource3");
    ...
}

Если задача реализует интерфейс ITask напрямую, вы также можете создавать эти события, но необходимо использовать интерфейс IBuildEngine. В следующем примере показана задача, реализующая интерфейс ITask и создающая пользовательское событие:

public class SimpleTask : ITask
{
    public IBuildEngine BuildEngine { get; set; }

    public override bool Execute()
    {
        TaskEventArgs taskEvent =
            new TaskEventArgs(BuildEventCategory.Custom,
            BuildEventImportance.High, "Important Message",
           "SimpleTask");
        BuildEngine.LogBuildEvent(taskEvent);
        return true;
    }
}

Обязательные параметры задачи

Некоторые свойства задачи можно пометить как "обязательные", чтобы в любом файле проекта, из которого запускается задача, значения этих свойств должны были быть заданы, чтобы сборка не завершилась сбоем. Примените к свойству .NET в задаче атрибут [Required] следующим образом:

[Required]
public string RequiredProperty { get; set; }

Атрибут [Required] определяется классом RequiredAttribute в пространстве имен Microsoft.Build.Framework.

Как MSBuild вызывает задачу

При вызове задачи MSBuild сначала создает экземпляр класса задачи, а затем вызывает методы задания свойств этого объекта для параметров задачи, указанных в элементе задачи в файле проекта. Если в элементе задачи не указан параметр или если результатом вычисления выражения, указанного в элементе, является пустая строка, метод задания свойства не вызывается.

Например, в проекте

<Project>
 <Target Name="InvokeCustomTask">
  <CustomTask Input1=""
              Input2="$(PropertyThatIsNotDefined)"
              Input3="value3" />
 </Target>
</Project>

вызывается только метод задания для Input3.

Задача не должна зависеть от относительного порядка, в котором вызываются методы задания свойств.

Типы параметров задачи

MSBuild изначально обрабатывает свойства типов string, bool, ITaskItem и ITaskItem[]. Если задача принимает параметр другого типа, MSBuild вызывает ChangeType для преобразования string (со всеми развернутыми свойствами и ссылками на элементы) в целевой тип. Если преобразование для любого входного параметра завершается неудачно, MSBuild выдает ошибку и не вызывает метод Execute() задачи.

Пример 1

Description

В этом классе C# показана задача, производная от вспомогательного класса Task. Эта задача возвращает значение true, указывающее на успешное выполнение.

Код

using System;
using Microsoft.Build.Utilities;

namespace SimpleTask1
{
    public class SimpleTask1: Task
    {
        public override bool Execute()
        {
            // This is where the task would presumably do its work.
            return true;
        }
    }
}

Пример 2

Description

В этом классе C# показана задача, реализующая интерфейс ITask. Эта задача возвращает значение true, указывающее на успешное выполнение.

Код

using System;
using Microsoft.Build.Framework;

namespace SimpleTask2
{
    public class SimpleTask2: ITask
    {
        //When implementing the ITask interface, it is necessary to
        //implement a BuildEngine property of type
        //Microsoft.Build.Framework.IBuildEngine. This is done for
        //you if you derive from the Task class.
        public IBuildEngine BuildEngine { get; set; }

        // When implementing the ITask interface, it is necessary to
        // implement a HostObject property of type object.
        // This is done for you if you derive from the Task class.
        public object HostObject { get; set; }

        public bool Execute()
        {
            // This is where the task would presumably do its work.
            return true;
        }
    }
}

Пример 3

Description

В этом классе C# показана задача, производная от вспомогательного класса Task. В ней задается обязательное строковое свойство и создается событие, отображаемое всеми зарегистрированными средствами ведения журнала.

Код

using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace SimpleTask3
{
    public class SimpleTask3 : Task
    {
        private string myProperty;

        // The [Required] attribute indicates a required property.
        // If a project file invokes this task without passing a value
        // to this property, the build will fail immediately.
        [Required]
        public string MyProperty
        {
            get
            {
                return myProperty;
            }
            set
            {
                myProperty = value;
            }
        }

        public override bool Execute()
        {
            // Log a high-importance comment
            Log.LogMessage(MessageImportance.High,
                "The task was passed \"" + myProperty + "\".");
            return true;
        }
    }
}

Пример 4

Description

В этом примере показан файл проекта, в котором вызывается задача из предыдущего примера (SimpleTask3).

Код

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <UsingTask TaskName="SimpleTask3.SimpleTask3"
        AssemblyFile="SimpleTask3\bin\debug\simpletask3.dll"/>

    <Target Name="MyTarget">
        <SimpleTask3 MyProperty="Hello!"/>
    </Target>
</Project>