Bagikan melalui


Tugas sebaris langsung MSBuild

Tugas MSBuild biasanya dibuat dengan mengkompilasi kelas yang mengimplementasikan ITask antarmuka. Untuk informasi selengkapnya, lihat tugas .

Saat Anda ingin menghindari overhead pembuatan tugas yang dikompilasi, Anda bisa membuat tugas sebaris dalam file proyek atau dalam file yang diimpor. Anda tidak perlu membuat rakitan terpisah untuk menghosting tugas. Menggunakan tugas sebaris memudahkan untuk melacak kode sumber dan lebih mudah untuk menyebarkan tugas. Kode sumber diintegrasikan ke dalam file proyek MSBuild atau file yang diimpor, biasanya file .targets .

Anda membuat tugas sebaris dengan menggunakan pabrik tugas kode. Untuk pengembangan saat ini, pastikan untuk menggunakan RoslynCodeTaskFactory, bukan CodeTaskFactory. CodeTaskFactory hanya mendukung versi C# hingga 4.0.

Tugas sebaris dimaksudkan sebagai kenyamanan untuk tugas kecil yang tidak memerlukan dependensi rumit. Dukungan penelusuran kesalahan untuk tugas sebaris terbatas. Disarankan untuk membuat tugas yang dikompilasi alih-alih tugas sebaris saat Anda ingin menulis kode yang lebih kompleks, mereferensikan paket NuGet, menjalankan alat eksternal, atau melakukan operasi yang dapat menghasilkan kondisi kesalahan. Selain itu, tugas sebaris dikompilasi setiap kali Anda membangun, sehingga mungkin ada dampak nyata pada performa build.

Struktur tugas sebaris

Tugas sebaris dimuat oleh elemen UsingTask . Tugas sebaris dan UsingTask elemen yang berisinya biasanya disertakan dalam .targets file dan diimpor ke file proyek lain sesuai kebutuhan. Berikut adalah tugas sebaris dasar yang tidak melakukan apa-apa, tetapi mengilustrasikan sintaks:

 <!-- 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>

Elemen UsingTask dalam contoh memiliki tiga atribut yang menjelaskan tugas dan pabrik tugas sebaris yang mengkompilasinya.

  • Atribut TaskName menamai tugas, dalam hal ini, DoNothing.

  • Atribut menamai TaskFactory kelas yang mengimplementasikan pabrik tugas sebaris.

  • Atribut AssemblyFile memberikan lokasi pabrik tugas sebaris. Atau, Anda dapat menggunakan AssemblyName atribut untuk menentukan nama yang sepenuhnya memenuhi syarat dari kelas pabrik tugas sebaris, yang biasanya terletak di $(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll.

Elemen DoNothing tugas yang tersisa kosong dan disediakan untuk mengilustrasikan urutan dan struktur tugas sebaris. Contoh lengkap disajikan nanti dalam artikel ini.

  • Elemen ParameterGroup adalah opsional. Ketika ditentukan, ia mendeklarasikan parameter untuk tugas. Untuk informasi selengkapnya tentang parameter input dan output, lihat Parameter input dan output nanti di artikel ini.

  • Elemen menjelaskan Task dan berisi kode sumber tugas.

  • Elemen Reference menentukan referensi ke rakitan .NET yang Anda gunakan dalam kode Anda. Menggunakan elemen ini setara dengan menambahkan referensi ke proyek di Visual Studio. Atribut Include menentukan jalur rakitan yang dirujuk. Rakitan dalam mscorlib, .NET Standard, Microsoft.Build.Framework, dan Microsoft.Build.Utilities.Core, serta beberapa rakitan yang direferensikan secara transitif sebagai dependensi, tersedia tanpa Reference.

  • Elemen mencantumkan Using namespace yang ingin Anda akses. Elemen ini setara dengan direktif using dalam C#. Atribut Namespace menentukan namespace layanan yang akan disertakan. Ini tidak berfungsi untuk menempatkan using direktif dalam kode sebaris, karena kode tersebut dimasukkan ke dalam isi metode, di mana using arahan tidak diizinkan.

Reference elemen dan Using bersifat agnostik bahasa. Tugas sebaris dapat ditulis dalam Visual Basic atau C#.

Nota

Elemen yang dimuat oleh Task elemen khusus untuk pabrik tugas, dalam hal ini, pabrik tugas kode.

Elemen kode

Elemen turunan terakhir yang muncul dalam Task elemen adalah Code elemen . Elemen Code berisi atau menemukan kode yang ingin Anda kompilasi ke dalam tugas. Apa yang Anda masukkan ke Code dalam elemen tergantung pada bagaimana Anda ingin menulis tugas.

Atribut Language menentukan bahasa tempat kode Anda ditulis. Nilai yang dapat diterima adalah cs untuk C#, vb untuk Visual Basic.

Atribut Type menentukan jenis kode yang ditemukan dalam Code elemen .

  • Jika nilainya Type adalah Class, maka Code elemen berisi kode untuk kelas yang berasal dari ITask antarmuka.

  • Jika nilainya Type adalah Method, maka kode mendefinisikan penimpaan ExecuteITask metode antarmuka.

  • Jika nilai Type adalah Fragment, maka kode mendefinisikan konten Execute metode , tetapi bukan tanda tangan atau return pernyataan.

Kode itu sendiri biasanya muncul antara <![CDATA[ penanda dan ]]> penanda. Karena kode berada di bagian CDATA, Anda tidak perlu khawatir tentang melarikan diri dari karakter yang dipesan, misalnya, "<" atau ">".

Atau, Anda dapat menggunakan Source atribut Code elemen untuk menentukan lokasi file yang berisi kode untuk tugas Anda. Kode dalam file sumber harus dari jenis yang ditentukan oleh Type atribut . Source Jika atribut ada, nilai Type defaultnya adalah Class. Jika Source tidak ada, nilai defaultnya adalah Fragment.

Nota

Saat menentukan kelas tugas dalam file sumber, nama kelas harus setuju dengan TaskName atribut elemen UsingTask yang sesuai.

HelloWorld

Berikut adalah contoh tugas sebaris sederhana. Tugas HelloWorld menampilkan "Halo, dunia!" pada perangkat pengelogan kesalahan default, yang biasanya merupakan konsol sistem atau jendela Output Visual Studio.

<Project>
  <!-- This simple inline task displays "Hello, world!" -->
  <UsingTask
    TaskName="HelloWorld"
    TaskFactory="RoslynCodeTaskFactory"
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" >
    <ParameterGroup />
    <Task>
      <Using Namespace="System"/>
      <Using Namespace="System.IO"/>
      <Code Type="Fragment" Language="cs">
<![CDATA[
// Display "Hello, world!"
Log.LogError("Hello, world!");
]]>
      </Code>
    </Task>
  </UsingTask>
</Project>

Anda dapat menyimpan tugas HelloWorld dalam file bernama HelloWorld.targets, lalu memanggilnya dari proyek sebagai berikut.

<Project>
  <Import Project="HelloWorld.targets" />
  <Target Name="Hello">
    <HelloWorld />
  </Target>
</Project>

Parameter input dan output

Parameter tugas sebaris adalah elemen turunan dari ParameterGroup sebuah elemen. Setiap parameter mengambil nama elemen yang mendefinisikannya. Kode berikut mendefinisikan parameter Text.

<ParameterGroup>
  <Text />
</ParameterGroup>

Parameter mungkin memiliki satu atau beberapa atribut ini:

  • Required adalah atribut opsional yang secara false default. Jika true, maka parameter diperlukan dan harus diberi nilai sebelum memanggil tugas.
  • ParameterType adalah atribut opsional yang secara System.String default. Ini dapat diatur ke jenis yang sepenuhnya memenuhi syarat yang merupakan item atau nilai yang dapat dikonversi ke dan dari string dengan menggunakan ChangeType. (Dengan kata lain, jenis apa pun yang dapat diteruskan ke dan dari tugas eksternal.)
  • Output adalah atribut opsional yang secara false default. Jika true, maka parameter harus diberi nilai sebelum dikembalikan dari metode Jalankan.

Contohnya,

<ParameterGroup>
  <Expression Required="true" />
  <Files ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
  <Tally ParameterType="System.Int32" Output="true" />
</ParameterGroup>

mendefinisikan ketiga parameter ini:

  • Expression adalah parameter input yang diperlukan dari jenis System.String.

  • Files adalah parameter input daftar item yang diperlukan.

  • Tally adalah parameter output dari jenis System.Int32.

Code Jika elemen memiliki Type atribut Fragment atau Method, maka properti secara otomatis dibuat untuk setiap parameter. Jika tidak, properti harus dideklarasikan secara eksplisit dalam kode sumber tugas, dan harus sama persis dengan definisi parameternya.

Men-debug tugas sebaris

MSBuild menghasilkan file sumber tugas sebaris dan menulis output ke file teks dengan nama file GUID di folder file sementara, AppData\Local\Temp\MSBuildTemp. Output biasanya dihapus, tetapi untuk mempertahankan file output ini, Anda dapat mengatur variabel MSBUILDLOGCODETASKFACTORYOUTPUT lingkungan ke 1.

Contoh 1

Tugas sebaris berikut menggantikan setiap kemunculan token dalam file yang diberikan dengan nilai yang diberikan.

<Project>

  <UsingTask TaskName="TokenReplace" TaskFactory="RoslynCodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.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="Target.config" Token="$MyToken$" Replacement="MyValue"/>
  </Target>
</Project>

Contoh 2

Tugas sebaris berikut menghasilkan output berseri. Contoh ini menunjukkan penggunaan parameter output dan referensi.

<Project>
  <PropertyGroup>
    <RoslynCodeTaskFactoryAssembly Condition="$(RoslynCodeTaskFactoryAssembly) == ''">$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll</RoslynCodeTaskFactoryAssembly>
  </PropertyGroup>

    <UsingTask 
    TaskName="MyInlineTask" 
    TaskFactory="RoslynCodeTaskFactory" 
    AssemblyFile="$(RoslynCodeTaskFactoryAssembly)">
    <ParameterGroup>
      <Input ParameterType="System.String" Required="true" />
      <Output ParameterType="System.String" Output="true" />
    </ParameterGroup>
    <Task>
      <Reference Include="System.Text.Json" /> <!-- Reference an assembly -->
      <Using Namespace="System.Text.Json" />   <!-- Use a namespace -->
      <Code Type="Fragment" Language="cs">
        <![CDATA[
          Output = JsonSerializer.Serialize(new { Message = Input });
        ]]>
      </Code>
    </Task>
  </UsingTask>

  <Target Name="RunInlineTask">
    <MyInlineTask Input="Hello, Roslyn!" >
      <Output TaskParameter="Output" PropertyName="SerializedOutput" />
    </MyInlineTask>
    <Message Text="Serialized Output: $(SerializedOutput)" />
  </Target>
</Project>