Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Prosesor arahan bekerja dengan menambahkan kode ke pembuatan kelas transformasi. Jika Anda memanggil arahan dari templat teks, sisa kode yang Anda tulis di templat teks Anda dapat mengandalkan fungsionalitas yang disediakan oleh arahan.
Anda dapat menulis prosesor direktif kustom Anda sendiri. Ini memungkinkan Anda untuk mengkustomisasi templat teks Anda. Untuk membuat prosesor arahan kustom, buat kelas yang mewarisi dari DirectiveProcessor atau RequiresProvidesDirectiveProcessor.
Tugas yang diilustrasikan dalam panduan ini meliputi yang berikut ini:
Membuat prosesor arahan kustom
Mendaftarkan prosesor arahan
Menguji prosesor arahan
Membuat Prosesor Arahan Kustom
Dalam panduan ini, Anda membuat prosesor arahan kustom. Anda menambahkan arahan kustom yang membaca file XML, menyimpannya dalam XmlDocument variabel, dan mengeksposnya melalui properti. Di bagian "Menguji Prosesor Arahan," Anda menggunakan properti ini dalam templat teks untuk mengakses file XML.
Panggilan ke arahan kustom Anda terlihat seperti berikut ini:
<#@ CoolDirective Processor="CustomDirectiveProcessor" FileName="<Your Path>DocFile.xml" #>
Prosesor arahan kustom menambahkan variabel dan properti ke kelas pembuatan transformasi. Arahan yang Anda tulis menggunakan System.CodeDom kelas untuk membuat kode yang ditambahkan mesin ke kelas transformasi yang dihasilkan. Kelas System.CodeDom membuat kode di Visual C# atau Visual Basic, tergantung pada bahasa yang ditentukan dalam language parameter arahantemplate. Bahasa prosesor arahan dan bahasa templat teks yang mengakses prosesor arahan tidak harus cocok.
Kode yang dibuat arahan terlihat seperti berikut:
private System.Xml.XmlDocument document0Value;
public virtual System.Xml.XmlDocument Document0
{
get
{
if ((this.document0Value == null))
{
this.document0Value = XmlReaderHelper.ReadXml(<FileNameParameterValue>);
}
return this.document0Value;
}
}
Untuk membuat prosesor arahan kustom
Di Visual Studio, buat C# atau proyek pustaka kelas Visual Basic bernama CustomDP.
Catatan
Jika Anda ingin menginstal prosesor arahan di lebih dari satu komputer, lebih baik menggunakan proyek Visual Studio Extension (VSIX) dan menyertakan file .pkgdef dalam ekstensi. Untuk informasi selengkapnya, lihat Menyebarkan Prosesor Arahan Kustom.
Tambahkan referensi ke rakitan ini:
Microsoft.VisualStudio.TextTemplating.*.0
Microsoft.VisualStudio.TextTemplating.Interfaces.*.0
Ganti kode di Kelas1 dengan kode berikut. Kode ini mendefinisikan kelas CustomDirectiveProcessor yang mewarisi dari kelas DirectiveProcessor dan mengimplementasikan metode yang diperlukan.
using System; using System.CodeDom; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Text; using System.Xml; using System.Xml.Serialization; using Microsoft.VisualStudio.TextTemplating; namespace CustomDP { public class CustomDirectiveProcessor : DirectiveProcessor { // This buffer stores the code that is added to the // generated transformation class after all the processing is done. // --------------------------------------------------------------------- private StringBuilder codeBuffer; // Using a Code Dom Provider creates code for the // generated transformation class in either Visual Basic or C#. // If you want your directive processor to support only one language, you // can hard code the code you add to the generated transformation class. // In that case, you do not need this field. // -------------------------------------------------------------------------- private CodeDomProvider codeDomProvider; // This stores the full contents of the text template that is being processed. // -------------------------------------------------------------------------- private String templateContents; // These are the errors that occur during processing. The engine passes // the errors to the host, and the host can decide how to display them, // for example the host can display the errors in the UI // or write them to a file. // --------------------------------------------------------------------- private CompilerErrorCollection errorsValue; public new CompilerErrorCollection Errors { get { return errorsValue; } } // Each time this directive processor is called, it creates a new property. // We count how many times we are called, and append "n" to each new // property name. The property names are therefore unique. // ----------------------------------------------------------------------------- private int directiveCount = 0; public override void Initialize(ITextTemplatingEngineHost host) { // We do not need to do any initialization work. } public override void StartProcessingRun(CodeDomProvider languageProvider, String templateContents, CompilerErrorCollection errors) { // The engine has passed us the language of the text template // we will use that language to generate code later. // ---------------------------------------------------------- this.codeDomProvider = languageProvider; this.templateContents = templateContents; this.errorsValue = errors; this.codeBuffer = new StringBuilder(); } // Before calling the ProcessDirective method for a directive, the // engine calls this function to see whether the directive is supported. // Notice that one directive processor might support many directives. // --------------------------------------------------------------------- public override bool IsDirectiveSupported(string directiveName) { if (string.Compare(directiveName, "CoolDirective", StringComparison.OrdinalIgnoreCase) == 0) { return true; } if (string.Compare(directiveName, "SuperCoolDirective", StringComparison.OrdinalIgnoreCase) == 0) { return true; } return false; } public override void ProcessDirective(string directiveName, IDictionary<string, string> arguments) { if (string.Compare(directiveName, "CoolDirective", StringComparison.OrdinalIgnoreCase) == 0) { string fileName; if (!arguments.TryGetValue("FileName", out fileName)) { throw new DirectiveProcessorException("Required argument 'FileName' not specified."); } if (string.IsNullOrEmpty(fileName)) { throw new DirectiveProcessorException("Argument 'FileName' is null or empty."); } // Now we add code to the generated transformation class. // This directive supports either Visual Basic or C#, so we must use the // System.CodeDom to create the code. // If a directive supports only one language, you can hard code the code. // -------------------------------------------------------------------------- CodeMemberField documentField = new CodeMemberField(); documentField.Name = "document" + directiveCount + "Value"; documentField.Type = new CodeTypeReference(typeof(XmlDocument)); documentField.Attributes = MemberAttributes.Private; CodeMemberProperty documentProperty = new CodeMemberProperty(); documentProperty.Name = "Document" + directiveCount; documentProperty.Type = new CodeTypeReference(typeof(XmlDocument)); documentProperty.Attributes = MemberAttributes.Public; documentProperty.HasSet = false; documentProperty.HasGet = true; CodeExpression fieldName = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), documentField.Name); CodeExpression booleanTest = new CodeBinaryOperatorExpression(fieldName, CodeBinaryOperatorType.IdentityEquality, new CodePrimitiveExpression(null)); CodeExpression rightSide = new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("XmlReaderHelper"), "ReadXml", new CodePrimitiveExpression(fileName)); CodeStatement[] thenSteps = new CodeStatement[] { new CodeAssignStatement(fieldName, rightSide) }; CodeConditionStatement ifThen = new CodeConditionStatement(booleanTest, thenSteps); documentProperty.GetStatements.Add(ifThen); CodeStatement s = new CodeMethodReturnStatement(fieldName); documentProperty.GetStatements.Add(s); CodeGeneratorOptions options = new CodeGeneratorOptions(); options.BlankLinesBetweenMembers = true; options.IndentString = " "; options.VerbatimOrder = true; options.BracingStyle = "C"; using (StringWriter writer = new StringWriter(codeBuffer, CultureInfo.InvariantCulture)) { codeDomProvider.GenerateCodeFromMember(documentField, writer, options); codeDomProvider.GenerateCodeFromMember(documentProperty, writer, options); } } // One directive processor can contain many directives. // If you want to support more directives, the code goes here... // ----------------------------------------------------------------- if (string.Compare(directiveName, "supercooldirective", StringComparison.OrdinalIgnoreCase) == 0) { // Code for SuperCoolDirective goes here... } // Track how many times the processor has been called. // ----------------------------------------------------------------- directiveCount++; } public override void FinishProcessingRun() { this.codeDomProvider = null; // Important: do not do this: // The get methods below are called after this method // and the get methods can access this field. // ----------------------------------------------------------------- // this.codeBuffer = null; } public override string GetPreInitializationCodeForProcessingRun() { // Use this method to add code to the start of the // Initialize() method of the generated transformation class. // We do not need any pre-initialization, so we will just return "". // ----------------------------------------------------------------- // GetPreInitializationCodeForProcessingRun runs before the // Initialize() method of the base class. // ----------------------------------------------------------------- return String.Empty; } public override string GetPostInitializationCodeForProcessingRun() { // Use this method to add code to the end of the // Initialize() method of the generated transformation class. // We do not need any post-initialization, so we will just return "". // ------------------------------------------------------------------ // GetPostInitializationCodeForProcessingRun runs after the // Initialize() method of the base class. // ----------------------------------------------------------------- return String.Empty; } public override string GetClassCodeForProcessingRun() { //Return the code to add to the generated transformation class. // ----------------------------------------------------------------- return codeBuffer.ToString(); } public override string[] GetReferencesForProcessingRun() { // This returns the references that we want to use when // compiling the generated transformation class. // ----------------------------------------------------------------- // We need a reference to this assembly to be able to call // XmlReaderHelper.ReadXml from the generated transformation class. // ----------------------------------------------------------------- return new string[] { "System.Xml", this.GetType().Assembly.Location }; } public override string[] GetImportsForProcessingRun() { //This returns the imports or using statements that we want to //add to the generated transformation class. // ----------------------------------------------------------------- //We need CustomDP to be able to call XmlReaderHelper.ReadXml //from the generated transformation class. // ----------------------------------------------------------------- return new string[] { "System.Xml", "CustomDP" }; } } // ------------------------------------------------------------------------- // The code that we are adding to the generated transformation class // will call this method. // ------------------------------------------------------------------------- public static class XmlReaderHelper { public static XmlDocument ReadXml(string fileName) { XmlDocument d = new XmlDocument(); using (XmlReader reader = XmlReader.Create(fileName)) { try { d.Load(reader); } catch (System.Xml.XmlException e) { throw new DirectiveProcessorException("Unable to read the XML file.", e); } } return d; } } }Hanya untuk Visual Basic, buka menu Proyek, dan klik Properti CustomDP. Pada tab Aplikasi, di akar namespace layanan, hapus nilai default
CustomDP.Pada menu Berkas, klik Simpan Semua.
Pada menu Build, klik Solusi Build.
Bangun Proyek
Bangun proyek. Pada menu Build, klik Solusi Build.
Daftarkan Prosesor Arahan
Sebelum Anda dapat memanggil arahan dari templat teks di Visual Studio, Anda harus menambahkan kunci registri untuk prosesor arahan.
Catatan
Jika Anda ingin menginstal prosesor arahan di lebih dari satu komputer, lebih baik menentukan ekstensi Visual Studio (VSIX) yang menyertakan file .pkgdef bersama dengan rakitan Anda. Untuk informasi selengkapnya, lihat Menyebarkan Prosesor Arahan Kustom.
Kunci untuk prosesor arahan ada di registri di lokasi berikut:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\*.0\TextTemplating\DirectiveProcessors
Untuk sistem 64-bit, lokasi registri adalah:
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\*.0\TextTemplating\DirectiveProcessors
Di bagian ini, Anda menambahkan kunci untuk prosesor arahan kustom Anda ke registri di lokasi yang sama.
Perhatian
Salah mengedit registri bisa sangat merusak sistem Anda. Sebelum Anda membuat perubahan pada registri, buat cadangan data berharga apa pun yang ada di komputer.
Untuk menambahkan kunci registri untuk prosesor arahan
Jalankan perintah
regeditdengan menggunakan menu Mulai atau baris perintah.Telusuri ke lokasi HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\*.0\TextTemplating\DirectiveProcessors, dan klik node.
Pada sistem 64-bit, gunakan HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\*.0\TextTemplating\DirectiveProcessors
Tambahkan kunci baru bernama CustomDirectiveProcessor.
Catatan
Ini adalah nama yang akan Anda gunakan di bidang Prosesor dari arahan kustom Anda. Nama ini tidak perlu sesuai dengan nama arahan, nama kelas prosesor arahan, atau namespace layanan prosesor arahan.
Tambahkan nilai string baru bernama Kelas yang memiliki nilai CustomDP.CustomDirectiveProcessor untuk nama string baru.
Tambahkan nilai string baru bernama CodeBase yang memiliki nilai yang sama dengan jalur CustomDP.dll yang Anda buat sebelumnya dalam panduan ini.
Misalnya, jalurnya mungkin terlihat seperti
C:\UserFiles\CustomDP\bin\Debug\CustomDP.dll.Kunci registri Anda harus memiliki nilai berikut:
Nama Jenis Data (Default) REG_SZ (nilai tidak ditetapkan) Kelas REG_SZ CustomDP.CustomDirectiveProcessor CodeBase REG_SZ <Path to Your Solution>CustomDP\bin\Debug\CustomDP.dll Jika Anda telah menempatkan rakitan di GAC, nilainya akan terlihat seperti berikut ini:
Nama Jenis Data (Default) REG_SZ (nilai tidak ditetapkan) Kelas REG_SZ CustomDP.CustomDirectiveProcessor Rakitan REG_SZ CustomDP.dll Mulai Visual Studio.
Menguji Prosesor Arahan
Untuk menguji prosesor arahan, Anda perlu menulis templat teks yang memanggilnya.
Dalam contoh ini, templat teks memanggil direktif dan meneruskan nama file XML yang berisi dokumentasi untuk file kelas. Templat teks menggunakan properti XmlDocument yang dibuat arahan untuk menavigasi XML dan mencetak komentar dokumentasi.
Untuk membuat file XML untuk digunakan dalam menguji prosesor arahan
Buat file bernama DocFile.xml dengan menggunakan editor teks apa pun (misalnya, Notepad).
Catatan
Anda dapat membuat file ini di lokasi mana pun (misalnya, C:\Test\DocFile.xml).
Tambahkan yang berikut ini ke file XML:
<?xml version="1.0"?> <doc> <assembly> <name>xmlsample</name> </assembly> <members> <member name="T:SomeClass"> <summary>Class level summary documentation goes here.</summary> <remarks>Longer comments can be associated with a type or member through the remarks tag</remarks> </member> <member name="F:SomeClass.m_Name"> <summary>Store for the name property</summary> </member> <member name="M:SomeClass.#ctor"> <summary>The class constructor.</summary> </member> <member name="M:SomeClass.SomeMethod(System.String)"> <summary>Description for SomeMethod.</summary> <param name="s">Parameter description for s goes here</param> <seealso cref="T:System.String">You can use the cref attribute on any tag to reference a type or member and the compiler will check that the reference exists.</seealso> </member> <member name="M:SomeClass.SomeOtherMethod"> <summary>Some other method.</summary> <returns>Return results are described through the returns tag.</returns> <seealso cref="M:SomeClass.SomeMethod(System.String)">Notice the use of the cref attribute to reference a specific method</seealso> </member> <member name="M:SomeClass.Main(System.String[])"> <summary>The entry point for the application.</summary> <param name="args">A list of command line arguments</param> </member> <member name="P:SomeClass.Name"> <summary>Name property</summary> <value>A value tag is used to describe the property value</value> </member> </members> </doc>Simpan dan tutup file.
Untuk membuat templat teks untuk menguji prosesor arahan
Di Visual Studio, buat proyek pustaka kelas C# atau Visual Basic bernama TemplateTest.
Tambahkan file templat teks baru bernama TestDP.tt.
Pastikan bahwa properti Alat Kustom TestDP.tt diatur ke
TextTemplatingFileGenerator.Ubah konten TestDP.tt ke teks berikut.
Catatan
Ganti string
<YOUR PATH>dengan jalur ke file DocFile.xml.Bahasa templat teks tidak harus cocok dengan bahasa prosesor arahan.
<#@ assembly name="System.Xml" #> <#@ template debug="true" #> <#@ output extension=".txt" #> <# // This will call the custom directive processor. #> <#@ CoolDirective Processor="CustomDirectiveProcessor" FileName="<YOUR PATH>\DocFile.xml" #> <# // Uncomment this line if you want to see the generated transformation class. #> <# // System.Diagnostics.Debugger.Break(); #> <# // This will use the results of the directive processor. #> <# // The directive processor has read the XML and stored it in Document0. #> <# XmlNode node = Document0.DocumentElement.SelectSingleNode("members"); foreach (XmlNode member in node.ChildNodes) { XmlNode name = member.Attributes.GetNamedItem("name"); WriteLine("{0,7}: {1}", "Name", name.Value); foreach (XmlNode comment in member.ChildNodes) { WriteLine("{0,7}: {1}", comment.Name, comment.InnerText); } WriteLine(""); } #> <# // You can call the directive processor again and pass it a different file. #> <# // @ CoolDirective Processor="CustomDirectiveProcessor" FileName="<YOUR PATH>\<Your Second File>" #> <# // To use the results of the second directive call, use Document1. #> <# // XmlNode node2 = Document1.DocumentElement.SelectSingleNode("members"); // ... #>Catatan
Dalam contoh ini, nilai parameter
ProcessoradalahCustomDirectiveProcessor. Nilai parameterProcessorharus cocok dengan nama kunci registri prosesor.Pada menu File, pilih Simpan Semua.
Untuk menguji prosesor arahan
Di Penjelajah Solusi, klik kanan TestDP.tt lalu klik Jalankan Alat Kustom.
Untuk pengguna Visual Basic, TestDP.txt mungkin tidak muncul di Penjelajah Solusi secara default. Untuk menampilkan semua file yang ditetapkan ke proyek, buka menu Proyek dan klik Perlihatkan Semua File.
Di Penjelajah Solusi, perluas node TestDP.txt, lalu klik dua kali TestDP.txt untuk membukanya di editor.
Output teks yang dihasilkan muncul. Output akan terlihat seperti berikut ini:
Name: T:SomeClass summary: Class level summary documentation goes here. remarks: Longer comments can be associated with a type or member through the remarks tag Name: F:SomeClass.m_Name summary: Store for the name property Name: M:SomeClass.#ctor summary: The class constructor. Name: M:SomeClass.SomeMethod(System.String) summary: Description for SomeMethod. param: Parameter description for s goes here seealso: You can use the cref attribute on any tag to reference a type or member and the compiler will check that the reference exists. Name: M:SomeClass.SomeOtherMethod summary: Some other method. returns: Return results are described through the returns tag. seealso: Notice the use of the cref attribute to reference a specific method Name: M:SomeClass.Main(System.String[]) summary: The entry point for the application. param: A list of command line arguments Name: P:SomeClass.Name summary: Name property value: A value tag is used to describe the property value
Tambahkan HTML ke Teks yang Dihasilkan
Setelah menguji prosesor arahan kustom, Anda mungkin ingin menambahkan beberapa HTML ke teks yang dihasilkan.
Untuk menambahkan HTML ke teks yang dihasilkan
Ganti kode di TestDP.tt dengan kode berikut. HTML disorot. Pastikan untuk mengganti string
YOUR PATHdengan jalur ke file DocFile.xml.Catatan
Tambahan tag buka <# dan tutup #> memisahkan kode pernyataan dari tag HTML.
<#@ assembly name="System.Xml" #> <#@ template debug="true" #> <#@ output extension=".htm" #> <# // This will call the custom directive processor #> <#@ CoolDirective Processor="CustomDirectiveProcessor" FileName="<YOUR PATH>\DocFile.xml" #> <# // Uncomment this line if you want to see the generated transformation class #> <# // System.Diagnostics.Debugger.Break(); #> <html><body> <# // This will use the results of the directive processor #>. <# // The directive processor has read the XML and stored it in Document0#>. <# XmlNode node = Document0.DocumentElement.SelectSingleNode("members"); foreach (XmlNode member in node.ChildNodes) { #> <h3> <# XmlNode name = member.Attributes.GetNamedItem("name"); WriteLine("{0,7}: {1}", "Name", name.Value); #> </h3> <# foreach (XmlNode comment in member.ChildNodes) { WriteLine("{0,7}: {1}", comment.Name, comment.InnerText); #> <br/> <# } } #> </body></html>Pada menu File, klik Save TestDP.txt.
Untuk melihat output di browser, di Penjelajah Solusi, klik kanan TestDP.htm, dan klik Tampilkan Di Browser.
Output Anda harus sama dengan teks asli, kecuali memiliki format HTML yang diterapkan. Setiap nama item muncul dalam huruf tebal.