Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
RoslynCodeTaskFactory usa os compiladores Roslyn multiplataforma para gerar assemblies de tarefas na memória para uso como tarefas embutidas.
RoslynCodeTaskFactory as tarefas são direcionadas ao .NET Standard e podem funcionar em runtimes do .NET Framework e do .NET Core, bem como em outras plataformas, como Linux e macOS.
Observação
O RoslynCodeTaskFactory está disponível apenas no MSBuild 15.8 e superior. As versões do MSBuild seguem as versões do Visual Studio, portanto, RoslynCodeTaskFactory está disponível no Visual Studio 2017 versão 15.8 e superior.
A estrutura de uma tarefa embutida com RoslynCodeTaskFactory
RoslynCodeTaskFactory As tarefas embutidas são declaradas usando o UsingTask elemento. A tarefa embutida e o elemento que a UsingTask contém normalmente são incluídos em um .targets arquivo e importados para outros arquivos de projeto, conforme necessário. Aqui está uma tarefa embutida básica. Observe que ele não faz nada.
<Project>
<!-- This simple inline task does nothing. -->
<UsingTask
TaskName="DoNothing"
TaskFactory="RoslynCodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" >
<ParameterGroup />
<Task>
<Reference Include="" />
<Using Namespace="" />
<Code Type="Fragment" Language="cs">
</Code>
</Task>
</UsingTask>
</Project>
O UsingTask elemento no exemplo tem três atributos que descrevem a tarefa e a fábrica de tarefas embutidas que a compila.
O
TaskNameatributo nomeia a tarefa, nesse caso,DoNothing.O
TaskFactoryatributo nomeia a classe que implementa a fábrica de tarefas embutidas.O
AssemblyFileatributo fornece o local da fábrica de tarefas embutidas. Como alternativa, você pode usar oAssemblyNameatributo para especificar o nome totalmente qualificado da classe de fábrica de tarefas embutida, que normalmente está localizada no GAC (cache de assembly global).
Os elementos restantes da DoNothing tarefa estão vazios e são fornecidos para ilustrar a ordem e a estrutura de uma tarefa embutida. Um exemplo mais robusto é apresentado posteriormente neste artigo.
O elemento
ParameterGroupé opcional. Quando especificado, ele declara os parâmetros para a tarefa. Para obter mais informações sobre parâmetros de entrada e saída, consulte Parâmetros de entrada e saída mais adiante neste artigo.O
Taskelemento descreve e contém o código-fonte da tarefa.O
Referenceelemento especifica referências aos assemblies .NET que você está usando em seu código. Isso equivale a adicionar uma referência a um projeto no Visual Studio. OIncludeatributo especifica o caminho do assembly referenciado.O
Usingelemento lista os namespaces que você deseja acessar. Esse elemento se assemelha àusingdiretiva no Visual C#. ONamespaceatributo especifica o namespace a ser incluído.
Reference e Using os elementos são independentes de linguagem. As tarefas embutidas podem ser escritas em qualquer uma das linguagens de CodeDom do .NET com suporte, por exemplo, Visual Basic ou Visual C#.
Observação
Os elementos contidos pelo Task elemento são específicos para a fábrica de tarefas, nesse caso, a fábrica de tarefas de código.
Elemento code
O último elemento filho a ser exibido dentro do Task elemento é o Code elemento. O Code elemento contém ou localiza o código que você deseja que seja compilado em uma tarefa. O que você coloca no Code elemento depende de como você deseja escrever a tarefa.
O Language atributo especifica o idioma no qual o código é escrito. Os valores aceitáveis são cs para C#, vb para Visual Basic.
O Type atributo especifica o tipo de código encontrado no Code elemento.
Se o valor
TypeforClass, o elemento conterá códigoCodepara uma classe derivada da ITask interface.Se o valor
TypeforMethod, o código definirá uma substituição doExecutemétodo da ITask interface.Se o valor
TypeforFragment, o código definirá o conteúdo doExecutemétodo, mas não a assinatura ou a instruçãoreturn.
O próprio código normalmente aparece entre um <![CDATA[ marcador e um ]]> marcador. Como o código está em uma seção CDATA, você não precisa se preocupar com o escape de caracteres reservados, por exemplo, "<" ou ">".
Como alternativa, você pode usar o Source atributo do Code elemento para especificar o local de um arquivo que contém o código para sua tarefa. O código no arquivo de origem deve ser do tipo especificado pelo Type atributo. Se o Source atributo estiver presente, o valor Type padrão será Class. Se Source não estiver presente, o valor padrão será Fragment.
Observação
Se você definir a classe de tarefa em um arquivo de origem, o nome da classe deverá concordar com o TaskName atributo do elemento UsingTask correspondente.
Olá, Mundo
Aqui está uma tarefa embutida mais robusta com RoslynCodeTaskFactory. A tarefa HelloWorld exibe "Olá, mundo!" no dispositivo de log de erros padrão, que normalmente é o console do sistema ou a janela Saída do Visual Studio. O Reference elemento no exemplo é incluído apenas para ilustração.
<Project>
<!-- This simple inline task displays "Hello, world!" -->
<UsingTask
TaskName="HelloWorld"
TaskFactory="RoslynCodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" >
<ParameterGroup />
<Task>
<Reference Include="System.Xml"/>
<Using Namespace="System"/>
<Using Namespace="System.IO"/>
<Code Type="Fragment" Language="cs">
<![CDATA[
// Display "Hello, world!"
Log.LogError("Hello, world!");
]]>
</Code>
</Task>
</UsingTask>
</Project>
Você pode salvar a HelloWorld tarefa em um arquivo chamado HelloWorld.targets e invocá-la de um projeto da seguinte maneira.
<Project>
<Import Project="HelloWorld.targets" />
<Target Name="Hello">
<HelloWorld />
</Target>
</Project>
Parâmetros de entrada e saída
Parâmetros de tarefa embutidos são elementos filho de um ParameterGroup elemento. Cada parâmetro usa o nome do elemento que o define. O código a seguir define o parâmetro Text.
<ParameterGroup>
<Text />
</ParameterGroup>
Os parâmetros podem ter um ou mais desses atributos:
Requiredé um atributo opcional que éfalsepor padrão. Setrue, o parâmetro é necessário e deve receber um valor antes de chamar a tarefa.ParameterTypeé um atributo opcional que éSystem.Stringpor padrão. Ele pode ser definido como qualquer tipo totalmente qualificado que seja um item ou um valor que possa ser convertido de e para uma cadeia de caracteres usando System.Convert.ChangeType. (Em outras palavras, qualquer tipo que possa ser passado de e para uma tarefa externa.)Outputé um atributo opcional que éfalsepor padrão. Setrue, o parâmetro deverá receber um valor antes de retornar do método Execute.
Por exemplo
<ParameterGroup>
<Expression Required="true" />
<Files ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<Tally ParameterType="System.Int32" Output="true" />
</ParameterGroup>
define estes três parâmetros:
Expressioné um parâmetro de entrada necessário do tipo System.String.Filesé um parâmetro de entrada de lista de itens necessário.Tallyé um parâmetro de saída do tipo System.Int32.
Se o Code elemento tiver o Type atributo de Fragment ou Method, em seguida, as propriedades serão criadas automaticamente para cada parâmetro. Em RoslynCodeTaskFactory, se o Code elemento tem o Type atributo de Class, então você não precisa especificar o ParameterGroup, pois ele é inferido do código-fonte (essa é uma diferença de CodeTaskFactory). Caso contrário, as propriedades devem ser declaradas explicitamente no código-fonte da tarefa e devem corresponder exatamente às definições de parâmetro.
Exemplo
A tarefa embutida a seguir registra algumas mensagens e retorna uma cadeia de caracteres.
<Project>
<UsingTask TaskName="MySample"
TaskFactory="RoslynCodeTaskFactory"
AssemblyFile="$(MSBuildBinPath)\Microsoft.Build.Tasks.Core.dll">
<ParameterGroup>
<Parameter1 ParameterType="System.String" Required="true" />
<Parameter2 ParameterType="System.String" />
<Parameter3 ParameterType="System.String" Output="true" />
</ParameterGroup>
<Task>
<Using Namespace="System" />
<Code Type="Fragment" Language="cs">
<![CDATA[
Log.LogMessage(MessageImportance.High, "Hello from an inline task created by Roslyn!");
Log.LogMessageFromText($"Parameter1: '{Parameter1}'", MessageImportance.High);
Log.LogMessageFromText($"Parameter2: '{Parameter2}'", MessageImportance.High);
Parameter3 = "A value from the Roslyn CodeTaskFactory";
]]>
</Code>
</Task>
</UsingTask>
<Target Name="Demo">
<MySample Parameter1="A value for parameter 1" Parameter2="A value for parameter 2">
<Output TaskParameter="Parameter3" PropertyName="NewProperty" />
</MySample>
<Message Text="NewProperty: '$(NewProperty)'" />
</Target>
</Project>
Essas tarefas embutidas podem combinar caminhos e obter o nome do arquivo.
<Project>
<UsingTask TaskName="PathCombine"
TaskFactory="RoslynCodeTaskFactory"
AssemblyFile="$(MSBuildBinPath)\Microsoft.Build.Tasks.Core.dll">
<ParameterGroup>
<Paths ParameterType="System.String[]" Required="true" />
<Combined ParameterType="System.String" Output="true" />
</ParameterGroup>
<Task>
<Using Namespace="System" />
<Code Type="Fragment" Language="cs">
<![CDATA[
Combined = Path.Combine(Paths);
]]>
</Code>
</Task>
</UsingTask>
<UsingTask TaskName="PathGetFileName"
TaskFactory="RoslynCodeTaskFactory"
AssemblyFile="$(MSBuildBinPath)\Microsoft.Build.Tasks.Core.dll">
<ParameterGroup>
<Path ParameterType="System.String" Required="true" />
<FileName ParameterType="System.String" Output="true" />
</ParameterGroup>
<Task>
<Using Namespace="System" />
<Code Type="Fragment" Language="cs">
<![CDATA[
FileName = System.IO.Path.GetFileName(Path);
]]>
</Code>
</Task>
</UsingTask>
<Target Name="Demo">
<PathCombine Paths="$(Temp);MyFolder;$([System.Guid]::NewGuid()).txt">
<Output TaskParameter="Combined" PropertyName="MyCombinedPaths" />
</PathCombine>
<Message Text="Combined Paths: '$(MyCombinedPaths)'" />
<PathGetFileName Path="$(MyCombinedPaths)">
<Output TaskParameter="FileName" PropertyName="MyFileName" />
</PathGetFileName>
<Message Text="File name: '$(MyFileName)'" />
</Target>
</Project>
Fornecer compatibilidade com versões anteriores
RoslynCodeTaskFactory primeiro ficou disponível no MSBuild versão 15.8. Suponha que você queira dar suporte a versões anteriores do Visual Studio e do MSBuild, quando RoslynCodeTaskFactory não estava disponível, mas CodeTaskFactory estava, mas deseja usar o mesmo script de build. Você pode usar um Choose constructo que usa a $(MSBuildVersion) propriedade para decidir no momento da compilação se deseja usar ou RoslynCodeTaskFactory recuar para CodeTaskFactory, como no exemplo a seguir:
<Project Sdk="Microsoft.NET.Sdk" DefaultTargets="RunTask">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<Choose>
<When Condition=" '$(MSBuildVersion.Substring(0,2))' >= 16 Or
('$(MSBuildVersion.Substring(0,2))' == 15 And '$(MSBuildVersion.Substring(3,1))' >= 8)">
<PropertyGroup>
<TaskFactory>RoslynCodeTaskFactory</TaskFactory>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<TaskFactory>CodeTaskFactory</TaskFactory>
</PropertyGroup>
</Otherwise>
</Choose>
<UsingTask
TaskName="HelloWorld"
TaskFactory="$(TaskFactory)"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
<ParameterGroup />
<Task>
<Using Namespace="System"/>
<Using Namespace="System.IO"/>
<Code Type="Fragment" Language="cs">
<![CDATA[
Log.LogError("Using RoslynCodeTaskFactory");
]]>
</Code>
</Task>
</UsingTask>
<Target Name="RunTask" AfterTargets="Build">
<Message Text="MSBuildVersion: $(MSBuildVersion)"/>
<Message Text="TaskFactory: $(TaskFactory)"/>
<HelloWorld />
</Target>
</Project>