다음을 통해 공유


연습: 사용자 지정 텍스트 템플릿 호스트 만들기

텍스트 템플릿 호스트는 텍스트 템플릿 변환 엔진이 실행될 수 있도록 하는 환경을 제공합니다. 호스트는 파일 시스템과 엔진의 상호 작용을 관리합니다. 파일이나 어셈블리가 필요한 엔진이나 지시문 프로세서는 호스트에서 리소스를 요청할 수 있습니다. 그러면 호스트는 디렉터리와 전역 어셈블리 캐시를 검색하여 요청된 리소스를 찾을 수 있습니다. 자세한 내용은 텍스트 템플릿 변환 프로세스를 참조하십시오.

텍스트 템플릿 변환 기능을 외부 Visual Studio에서 사용하거나 해당 기능을 사용자 지정 도구에 통합하려는 경우 사용자 지정 호스트를 작성할 수 있습니다. 사용자 지정 호스트를 만들려면 ITextTemplatingEngineHost에서 상속되는 클래스를 만들어야 합니다. 개별 메서드에 대한 문서를 보려면 ITextTemplatingEngineHost를 참조하십시오.

경고

Visual Studio Extension 또는 패키지를 작성하는 경우 고유 호스트를 만드는 대신 텍스트 템플릿 서비스를 사용하십시오.자세한 내용은 VS 확장에서 텍스트 변환 호출을 참조하십시오.

이 연습에서 수행할 작업은 다음과 같습니다.

  • 사용자 지정 텍스트 템플릿 호스트 만들기

  • 사용자 지정 호스트 테스트

사전 요구 사항

이 연습을 완료하려면 다음이 필요합니다.

  • Visual Studio 2010 이상

  • Visual Studio SDK

사용자 지정 텍스트 템플릿 호스트 만들기

이 연습에서는 명령줄에서 호출할 수 있는 실행 가능한 응용 프로그램에서 사용자 지정 호스트를 만듭니다. 응용 프로그램은 텍스트 템플릿 파일을 인수로 받아들이고 템플릿을 읽으며, 엔진을 호출하여 템플릿을 변환하고 명령 프롬프트 창에서 발생하는 모든 오류를 표시합니다.

사용자 지정 호스트를 만들려면

  1. Visual Studio에서 CustomHost라는 새 Visual Basic 또는 C# 콘솔 응용 프로그램을 만듭니다.

  2. 다음 어셈블리에 대한 참조를 추가합니다.

    • Microsoft.VisualStudio.TextTemplating.*.0

    • Microsoft.VisualStudio.TextTemplating.Interfaces.10.0 이상 버전

  3. Program.cs 또는 Module1.vb 파일의 코드를 다음 코드로 바꿉니다.

    using System;
    using System.IO;
    using System.CodeDom.Compiler;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.VisualStudio.TextTemplating;
    
    namespace CustomHost
    {
        //The text template transformation engine is responsible for running 
        //the transformation process.
        //The host is responsible for all input and output, locating files, 
        //and anything else related to the external environment.
        //-------------------------------------------------------------------------
        class CustomCmdLineHost : ITextTemplatingEngineHost
        {
            //the path and file name of the text template that is being processed
            //---------------------------------------------------------------------
            internal string TemplateFileValue;
            public string TemplateFile
            {
                get { return TemplateFileValue; }
            }
            //This will be the extension of the generated text output file.
            //The host can provide a default by setting the value of the field here.
            //The engine can change this value based on the optional output directive
            //if the user specifies it in the text template.
            //---------------------------------------------------------------------
            private string fileExtensionValue = ".txt";
            public string FileExtension
            {
                get { return fileExtensionValue; }
            }
            //This will be the encoding of the generated text output file.
            //The host can provide a default by setting the value of the field here.
            //The engine can change this value based on the optional output directive
            //if the user specifies it in the text template.
            //---------------------------------------------------------------------
            private Encoding fileEncodingValue = Encoding.UTF8;
            public Encoding FileEncoding
            {
                get { return fileEncodingValue; }
            }
            //These are the errors that occur when the engine processes a template.
            //The engine passes the errors to the host when it is done processing,
            //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 CompilerErrorCollection Errors
            {
                get { return errorsValue; }
            }
            //The host can provide standard assembly references.
            //The engine will use these references when compiling and
            //executing the generated transformation class.
            //--------------------------------------------------------------
            public IList<string> StandardAssemblyReferences
            {
                get
                {
                    return new string[]
                    {
                        //If this host searches standard paths and the GAC,
                        //we can specify the assembly name like this.
                        //---------------------------------------------------------
                        //"System"
    
                        //Because this host only resolves assemblies from the 
                        //fully qualified path and name of the assembly,
                        //this is a quick way to get the code to give us the
                        //fully qualified path and name of the System assembly.
                        //---------------------------------------------------------
                        typeof(System.Uri).Assembly.Location
                    };
                }
            }
            //The host can provide standard imports or using statements.
            //The engine will add these statements to the generated 
            //transformation class.
            //--------------------------------------------------------------
            public IList<string> StandardImports
            {
                get
                {
                    return new string[]
                    {
                        "System"
                    };
                }
            }
            //The engine calls this method based on the optional include directive
            //if the user has specified it in the text template.
            //This method can be called 0, 1, or more times.
            //---------------------------------------------------------------------
            //The included text is returned in the context parameter.
            //If the host searches the registry for the location of include files,
            //or if the host searches multiple locations by default, the host can
            //return the final path of the include file in the location parameter.
            //---------------------------------------------------------------------
            public bool LoadIncludeText(string requestFileName, out string content, out string location)
            {
                content = System.String.Empty;
                location = System.String.Empty;
    
                //If the argument is the fully qualified path of an existing file,
                //then we are done.
                //----------------------------------------------------------------
                if (File.Exists(requestFileName))
                {
                    content = File.ReadAllText(requestFileName);
                    return true;
                }
                //This can be customized to search specific paths for the file.
                //This can be customized to accept paths to search as command line
                //arguments.
                //----------------------------------------------------------------
                else
                {
                    return false;
                }
            }
            //Called by the Engine to enquire about 
            //the processing options you require. 
            //If you recognize that option, return an 
            //appropriate value. 
            //Otherwise, pass back NULL.
            //--------------------------------------------------------------------
            public object GetHostOption(string optionName)
            {
            object returnObject;
            switch (optionName)
            {
            case "CacheAssemblies":
                        returnObject = true;
         break;
            default:
            returnObject = null;
            break;
            }
            return returnObject;
            }
            //The engine calls this method to resolve assembly references used in
            //the generated transformation class project and for the optional 
            //assembly directive if the user has specified it in the text template.
            //This method can be called 0, 1, or more times.
            //---------------------------------------------------------------------
            public string ResolveAssemblyReference(string assemblyReference)
            {
                //If the argument is the fully qualified path of an existing file,
                //then we are done. (This does not do any work.)
                //----------------------------------------------------------------
                if (File.Exists(assemblyReference))
                {
                    return assemblyReference;
                }
                //Maybe the assembly is in the same folder as the text template that 
                //called the directive.
                //----------------------------------------------------------------
                string candidate = Path.Combine(Path.GetDirectoryName(this.TemplateFile), assemblyReference);
                if (File.Exists(candidate))
                {
                    return candidate;
                }
                //This can be customized to search specific paths for the file
                //or to search the GAC.
                //----------------------------------------------------------------
                //This can be customized to accept paths to search as command line
                //arguments.
                //----------------------------------------------------------------
                //If we cannot do better, return the original file name.
                return "";
            }
            //The engine calls this method based on the directives the user has 
            //specified in the text template.
            //This method can be called 0, 1, or more times.
            //---------------------------------------------------------------------
            public Type ResolveDirectiveProcessor(string processorName)
            {
                //This host will not resolve any specific processors.
                //Check the processor name, and if it is the name of a processor the 
                //host wants to support, return the type of the processor.
                //---------------------------------------------------------------------
                if (string.Compare(processorName, "XYZ", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    //return typeof();
                }
                //This can be customized to search specific paths for the file
                //or to search the GAC
                //If the directive processor cannot be found, throw an error.
                throw new Exception("Directive Processor not found");
            }
            //A directive processor can call this method if a file name does not 
            //have a path.
            //The host can attempt to provide path information by searching 
            //specific paths for the file and returning the file and path if found.
            //This method can be called 0, 1, or more times.
            //---------------------------------------------------------------------
            public string ResolvePath(string fileName)
            {
                if (fileName == null)
                {
                    throw new ArgumentNullException("the file name cannot be null");
                }
                //If the argument is the fully qualified path of an existing file,
                //then we are done
                //----------------------------------------------------------------
                if (File.Exists(fileName))
                {
                    return fileName;
                }
                //Maybe the file is in the same folder as the text template that 
                //called the directive.
                //----------------------------------------------------------------
                string candidate = Path.Combine(Path.GetDirectoryName(this.TemplateFile), fileName);
                if (File.Exists(candidate))
                {
                    return candidate;
                }
                //Look more places.
                //----------------------------------------------------------------
                //More code can go here...
                //If we cannot do better, return the original file name.
                return fileName;
            }
            //If a call to a directive in a text template does not provide a value
            //for a required parameter, the directive processor can try to get it
            //from the host by calling this method.
            //This method can be called 0, 1, or more times.
            //---------------------------------------------------------------------
            public string ResolveParameterValue(string directiveId, string processorName, string parameterName)
            {
                if (directiveId == null)
                {
                    throw new ArgumentNullException("the directiveId cannot be null");
                }
                if (processorName == null)
                {
                    throw new ArgumentNullException("the processorName cannot be null");
                }
                if (parameterName == null)
                {
                    throw new ArgumentNullException("the parameterName cannot be null");
                }
                //Code to provide "hard-coded" parameter values goes here.
                //This code depends on the directive processors this host will interact with.
                //If we cannot do better, return the empty string.
                return String.Empty;
            }
            //The engine calls this method to change the extension of the 
            //generated text output file based on the optional output directive 
            //if the user specifies it in the text template.
            //---------------------------------------------------------------------
            public void SetFileExtension(string extension)
            {
                //The parameter extension has a '.' in front of it already.
                //--------------------------------------------------------
                fileExtensionValue = extension;
            }
            //The engine calls this method to change the encoding of the 
            //generated text output file based on the optional output directive 
            //if the user specifies it in the text template.
            //----------------------------------------------------------------------
            public void SetOutputEncoding(System.Text.Encoding encoding, bool fromOutputDirective)
            {
                fileEncodingValue = encoding;
            }
            //The engine calls this method when it is done processing a text
            //template to pass any errors that occurred to the host.
            //The host can decide how to display them.
            //---------------------------------------------------------------------
            public void LogErrors(CompilerErrorCollection errors)
            {
                errorsValue = errors;
            }
            //This is the application domain that is used to compile and run
            //the generated transformation class to create the generated text output.
            //----------------------------------------------------------------------
            public AppDomain ProvideTemplatingAppDomain(string content)
            {
                //This host will provide a new application domain each time the 
                //engine processes a text template.
                //-------------------------------------------------------------
                return AppDomain.CreateDomain("Generation App Domain");
                //This could be changed to return the current appdomain, but new 
                //assemblies are loaded into this AppDomain on a regular basis.
                //If the AppDomain lasts too long, it will grow indefintely, 
                //which might be regarded as a leak.
                //This could be customized to cache the application domain for 
                //a certain number of text template generations (for example, 10).
                //This could be customized based on the contents of the text 
                //template, which are provided as a parameter for that purpose.
            }
        }
        //This will accept the path of a text template as an argument.
        //It will create an instance of the custom host and an instance of the
        //text templating transformation engine, and will transform the
        //template to create the generated text output file.
        //-------------------------------------------------------------------------
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    ProcessTemplate(args);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
            static void ProcessTemplate(string[] args)
            {
                string templateFileName = null;
                if (args.Length == 0)
                {
                    throw new System.Exception("you must provide a text template file path");
                }
                templateFileName = args[0];
                if (templateFileName == null)
                {
                    throw new ArgumentNullException("the file name cannot be null");
                }
                if (!File.Exists(templateFileName))
                {
                    throw new FileNotFoundException("the file cannot be found");
                }
                CustomCmdLineHost host = new CustomCmdLineHost();
                Engine engine = new Engine();
                host.TemplateFileValue = templateFileName;
                //Read the text template.
                string input = File.ReadAllText(templateFileName);
                //Transform the text template.
                string output = engine.ProcessTemplate(input, host);
                string outputFileName = Path.GetFileNameWithoutExtension(templateFileName);
                outputFileName = Path.Combine(Path.GetDirectoryName(templateFileName), outputFileName);
                outputFileName = outputFileName + "1" + host.FileExtension;
                File.WriteAllText(outputFileName, output, host.FileEncoding);
    
                foreach (CompilerError error in host.Errors)
                {
                    Console.WriteLine(error.ToString());
                }
            }
        }
    }
    
    Imports System
    Imports System.IO
    Imports System.CodeDom.Compiler
    Imports System.Collections.Generic
    Imports System.Text
    Imports Microsoft.VisualStudio.TextTemplating
    
    Namespace CustomHost
        'The text template transformation engine is responsible for running 
        'the transformation process.
        'The host is responsible for all input and output, locating files, 
        'and anything else related to the external environment.
        '-------------------------------------------------------------------------
        Public Class CustomCmdLineHost
            Implements ITextTemplatingEngineHost
    
            'the path and file name of the text template that is being processed
            '---------------------------------------------------------------------
            Friend TemplateFileValue As String
            Public ReadOnly Property TemplateFile() As String Implements ITextTemplatingEngineHost.TemplateFile
                Get
                    Return TemplateFileValue
                End Get
            End Property
            'This will be the extension of the generated text output file.
            'The host can provide a default by setting the value of the field here.
            'The engine can change this based on the optional output directive
            'if the user specifies it in the text template.
            '---------------------------------------------------------------------
            Private fileExtensionValue As String = ".txt"
            Public ReadOnly Property FileExtension() As String
                Get
                    Return fileExtensionValue
                End Get
            End Property
            'This will be the encoding of the generated text output file.
            'The host can provide a default by setting the value of the field here.
            'The engine can change this value based on the optional output directive
            'if the user specifies it in the text template.
            '---------------------------------------------------------------------
            Private fileEncodingValue As Encoding = Encoding.UTF8
            Public ReadOnly Property fileEncoding() As Encoding
                Get
                    Return fileEncodingValue
                End Get
            End Property
            'These are the errors that occur when the engine processes a template.
            'The engine passes the errors to the host when it is done processing,
            '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 errorsValue As CompilerErrorCollection
            Public ReadOnly Property Errors() As CompilerErrorCollection
                Get
                    Return errorsValue
                End Get
            End Property
            'The host can provide standard assembly references.
            'The engine will use these references when compiling and
            'executing the generated transformation class.
            '--------------------------------------------------------------
            Public ReadOnly Property StandardAssemblyReferences() As IList(Of String) Implements ITextTemplatingEngineHost.StandardAssemblyReferences
                Get
                    'If this host searches standard paths and the GAC,
                    'we can specify the assembly name like this.
                    '---------------------------------------------------------
                    'Return New String() {"System"}
                    'Because this host only resolves assemblies from the 
                    'fully qualified path and name of the assembly,
                    'this is a quick way to get the code to give us the
                    'fully qualified path and name of the System assembly.
                    '---------------------------------------------------------
                    Return New String() {(New System.UriBuilder()).GetType().Assembly.Location}
                End Get
            End Property
            'The host can provide standard imports or imports statements.
            'The engine will add these statements to the generated 
            'transformation class.
            '--------------------------------------------------------------
            Public ReadOnly Property StandardImports() As IList(Of String) Implements ITextTemplatingEngineHost.StandardImports
                Get
                    Return New String() {"System"}
                End Get
            End Property
            ' Called by the Engine to enquire about 
            ' the processing options you require. 
            ' If you recognize that option, return an 
            ' appropriate value. 
            ' Otherwise, pass back NULL.
            '--------------------------------------------------------------------
            Public Function GetHostOption(ByVal optionName As String) As Object Implements ITextTemplatingEngineHost.GetHostOption
                Dim returnObject As Object
                Select Case optionName
                    Case "CacheAssemblies"
                        returnObject = True
                    Case Else
                        returnObject = False
                End Select
                Return returnObject
            End Function
            'The engine calls this method based on the optional include directive
            'if the user has specified it in the text template.
            'This method can be called 0, 1, or more times.
            '---------------------------------------------------------------------
            'The included text is returned in the context parameter.
            'If the host searches the registry for the location of include files
            'or if the host searches multiple locations by default, the host can
            'return the final path of the include file in the location parameter.
            '---------------------------------------------------------------------
            Public Function LoadIncludeText(ByVal requestFileName As String, ByRef content As String, ByRef location As String) As Boolean Implements ITextTemplatingEngineHost.LoadIncludeText
                content = System.String.Empty
                location = System.String.Empty
                'If the argument is the fully qualified path of an existing file,
                'then we are done.
                '----------------------------------------------------------------
                If File.Exists(requestFileName) Then
                    content = File.ReadAllText(requestFileName)
                    Return True
                'This can be customized to search specific paths for the file.
                'This can be customized to accept paths to search as command line
                'arguments.
                '----------------------------------------------------------------
                Else
                    Return False
                End If
            End Function
            'The engine calls this method to resolve assembly references used in
            'the generated transformation class project and for the optional 
            'assembly directive if the user has specified it in the text template.
            'This method can be called 0, 1, or more times.
            '---------------------------------------------------------------------
            Public Function ResolveAssemblyReference(ByVal assemblyReference As String) As String Implements ITextTemplatingEngineHost.ResolveAssemblyReference
                'If the argument is the fully qualified path of an existing file,
                'then we are done. (This does not do any work.)
                '----------------------------------------------------------------
                If File.Exists(assemblyReference) Then
                    Return assemblyReference
                End If
                'Maybe the assembly is in the same folder as the text template that 
                'called the directive.
                '----------------------------------------------------------------
                Dim candidate As String = Path.Combine(Path.GetDirectoryName(Me.TemplateFile), assemblyReference)
                If File.Exists(candidate) Then
                    Return candidate
                End If
                'This can be customized to search specific paths for the file,
                'or to search the GAC.
                '----------------------------------------------------------------
                'This can be customized to accept paths to search as command line
                'arguments.
                '----------------------------------------------------------------
                'If we cannot do better, return the original file name.
                Return ""
            End Function
            'The engine calls this method based on the directives the user has 
            'specified in the text template.
            'This method can be called 0, 1, or more times.
            '---------------------------------------------------------------------
            Public Function ResolveDirectiveProcessor(ByVal processorName As String) As System.Type Implements ITextTemplatingEngineHost.ResolveDirectiveProcessor
                'This host will not resolve any specific processors.
                'Check the processor name, and if it is the name of a processor the 
                'host wants to support, return the type of the processor.
                '---------------------------------------------------------------------
                If String.Compare(processorName, "XYZ", StringComparison.InvariantCultureIgnoreCase) = 0 Then
                    'return typeof()
                End If
                'This can be customized to search specific paths for the file,
                'or to search the GAC.
                'If the directive processor cannot be found, throw an error.
                Throw New Exception("Directive Processor not found")
            End Function
            'A directive processor can call this method if a file name does not 
            'have a path.
            'The host can attempt to provide path information by searching 
            'specific paths for the file and returning the file and path if found.
            'This method can be called 0, 1, or more times.
            '---------------------------------------------------------------------
            Public Function ResolvePath(ByVal fileName As String) As String Implements ITextTemplatingEngineHost.ResolvePath
                If fileName Is Nothing Then
                    Throw New ArgumentNullException("the file name cannot be null")
                End If
                'If the argument is the fully qualified path of an existing file,
                'then we are done.
                '----------------------------------------------------------------
                If File.Exists(fileName) Then
                    Return fileName
                End If
                'Maybe the file is in the same folder as the text template that 
                'called the directive.
                '----------------------------------------------------------------
                Dim candidate As String = Path.Combine(Path.GetDirectoryName(Me.TemplateFile), fileName)
                If File.Exists(candidate) Then
                    Return candidate
                End If
                'Look more places.
                '----------------------------------------------------------------
                'More code can go here...
                'If we cannot do better, return the original file name
                Return fileName
            End Function
            'If a call to a directive in a text template does not provide a value
            'for a required parameter, the directive processor can try to get it
            'from the host by calling this method.
            'This method can be called 0, 1, or more times.
            '---------------------------------------------------------------------
            Public Function ResolveParameterValue(ByVal directiveId As String, ByVal processorName As String, ByVal parameterName As String) As String Implements ITextTemplatingEngineHost.ResolveParameterValue
                If directiveId Is Nothing Then
                    Throw New ArgumentNullException("the directiveId cannot be null")
                End If
                If processorName Is Nothing Then
                    Throw New ArgumentNullException("the processorName cannot be null")
                End If
                If parameterName Is Nothing Then
                    Throw New ArgumentNullException("the parameterName cannot be null")
                End If
                'Code to provide "hard-coded" parameter values goes here.
                'This code depends on the directive processors this host will interact with.
                'If we cannot do better, return the empty string.
                Return String.Empty
            End Function
            'The engine calls this method to change the extension of the 
            'generated text output file based on the optional output directive 
            'if the user specifies it in the text template.
            '---------------------------------------------------------------------
            Public Sub SetFileExtension(ByVal extension As String) Implements ITextTemplatingEngineHost.SetFileExtension
                'The parameter extension has a '.' in front of it already.
                '--------------------------------------------------------
                fileExtensionValue = extension
            End Sub
            'The engine calls this method to change the encoding of the 
            'generated text output file based on the optional output directive 
            'if the user specifies it in the text template.
            '---------------------------------------------------------------------
            Public Sub SetOutputEncoding(ByVal encoding As System.Text.Encoding, ByVal fromOutputDirective As Boolean) Implements ITextTemplatingEngineHost.SetOutputEncoding
                fileEncodingValue = encoding
            End Sub
            'The engine calls this method when it is done processing a text
            'template to pass any errors that occurred to the host.
            'The host can decide how to display them.
            '---------------------------------------------------------------------
            Public Sub LogErrors(ByVal errors As System.CodeDom.Compiler.CompilerErrorCollection) Implements ITextTemplatingEngineHost.LogErrors
                errorsValue = errors
            End Sub
            'This is the application domain that is used to compile and run
            'the generated transformation class to create the generated text output.
            '----------------------------------------------------------------------
            Public Function ProvideTemplatingAppDomain(ByVal content As String) As System.AppDomain Implements ITextTemplatingEngineHost.ProvideTemplatingAppDomain
                'This host will provide a new application domain each time the 
                'engine processes a text template.
                '-------------------------------------------------------------
                Return AppDomain.CreateDomain("Generation App Domain")
                'This could be changed to return the current appdomain, but new 
                'assemblies are loaded into this AppDomain on a regular basis.
                'If the AppDomain lasts too long, it will grow indefintely, 
                'which might be regarded as a leak.
                'This could be customized to cache the application domain for 
                'a certain number of text template generations (for example, 10).
                'This could be customized based on the contents of the text 
                'template, which are provided as a parameter for that purpose.
            End Function
        End Class 'CustomCmdLineHost
        'This will accept the path of a text template as an argument.
        'It will create an instance of the custom host and an instance of the
        'text templating transformation engine. It will also transform the
        'template to create the generated text output file.
        '-------------------------------------------------------------------------
        Class Program
            Shared Sub Main(ByVal args As String())
                Try
                    ProcessTemplate(args)
                Catch ex As Exception
                    Console.WriteLine(ex.Message)
                End Try
            End Sub
            Shared Sub ProcessTemplate(ByVal args As String())
                Dim templateFileName As String = ""
                If args.Length = 0 Then
                    Throw New System.Exception("you must provide a text template file path")
                End If
                templateFileName = args(0)
                If templateFileName Is Nothing Then
                    Throw New ArgumentNullException("the file name cannot be null")
                End If
                If Not File.Exists(templateFileName) Then
                    Throw New FileNotFoundException("the file cannot be found")
                End If
                Dim host As CustomCmdLineHost = New CustomCmdLineHost()
                Dim engine As Engine = New Engine()
                host.TemplateFileValue = templateFileName
                'Read the text template.
                Dim input As String = File.ReadAllText(templateFileName)
                'Transform the text template.
                Dim output As String = engine.ProcessTemplate(input, host)
                Dim outputFileName As String = Path.GetFileNameWithoutExtension(templateFileName)
                outputFileName = Path.Combine(Path.GetDirectoryName(templateFileName), outputFileName)
                outputFileName = outputFileName & "1" & host.FileExtension
                File.WriteAllText(outputFileName, output, host.fileEncoding)
                Dim e As CompilerError
                For Each e In host.Errors
                    Console.WriteLine(e.ToString())
                Next
            End Sub 'ProcessTemplate
        End Class 'Program
    End Namespace
    
  4. Visual Basic의 경우에만 프로젝트 메뉴를 열고 CustomHost 속성을 클릭합니다. 시작 개체 목록에서 CustomHost.Program을 클릭합니다.

  5. 파일 메뉴에서 모두 저장을 클릭합니다.

  6. 빌드 메뉴에서 솔루션 빌드를 클릭합니다.

사용자 지정 호스트 테스트

사용자 지정 호스트를 테스트하려면 텍스트 템플릿을 작성한 다음 사용자 지정 호스트를 실행하여 이 호스트에 텍스트 템플릿의 이름을 전달하고 템플릿이 변환되었는지 확인합니다.

텍스트 템플릿을 만들어 사용자 지정 호스트를 테스트하려면

  1. 텍스트 파일을 만들고 TestTemplate.tt로 이름을 지정합니다.

    메모장 등의 모든 텍스트 편집기를 사용하여 파일을 만들 수 있습니다.

  2. 파일에 다음 코드를 추가합니다.

    참고

    텍스트 템플릿의 프로그래밍 언어는 사용자 지정 호스트의 프로그래밍 언어와 일치하지 않아도 됩니다.

    Text Template Host Test
    
    <#@ template debug="true" #>
    
    <# //Uncomment this line to test that the host allows the engine to set the extension. #>
    <# //@ output extension=".htm" #>
    
    <# //Uncomment this line if you want to debug the generated transformation class. #>
    <# //System.Diagnostics.Debugger.Break(); #>
    
    <# for (int i=0; i<3; i++)
       {
           WriteLine("This is a test");
       } 
    #>
    
    Text Template Host Test
    
    <#@ template debug="true" language="VB"#>
    
    <# 'Uncomment this line to test that the host allows the engine to set the extension. #>
    <# '@ output extension=".htm" #>
    
    <# 'Uncomment this line if you want to debug the generated transformation class. #>
    <# 'System.Diagnostics.Debugger.Break() #>
    
    <# Dim i As Integer
       For i = 0 To 2
    
           WriteLine("This is a test")
       Next
    #>
    
  3. 파일을 저장한 후 닫습니다.

사용자 지정 호스트를 테스트하려면

  1. 명령 프롬프트 창을 엽니다.

  2. 사용자 지정 호스트에 대한 실행 가능한 파일의 경로를 입력하고 Enter 키를 누르지 않습니다.

    예를 들어 다음과 같이 입력합니다.

    <YOUR PATH>CustomHost\bin\Debug\CustomHost.exe

    참고

    주소를 입력하는 대신 Windows 탐색기에서 CustomHost.exe 파일로 이동한 다음 이 파일을 명령 프롬프트 창으로 끌 수 있습니다.

  3. 공백을 입력합니다.

  4. 텍스트 템플릿 파일의 경로를 입력한 다음 Enter 키를 누릅니다.

    예를 들어 다음과 같이 입력합니다.

    C:\<YOUR PATH>TestTemplate.tt

    참고

    주소를 입력하는 대신 Windows 탐색기에서 TestTemplate.tt 파일로 이동한 다음 이 파일을 명령 프롬프트 창으로 끌 수 있습니다.

    사용자 지정 호스트 응용 프로그램이 실행되어 텍스트 템플릿 변환 프로세스를 완료합니다.

  5. Windows 탐색기에서 TestTemplate.tt 파일이 포함된 폴더로 이동합니다.

    이 폴더에는 TestTemplate1.txt 파일도 포함되어 있습니다.

  6. 이 파일을 열어 텍스트 템플릿 변환의 결과를 확인합니다.

    생성된 텍스트 출력이 다음과 같이 나타납니다.

    Text Template Host Test
    
    
    
    
    This is a test
    This is a test
    This is a test
    

다음 단계

이 연습에서는 기본 변환 기능을 지원하는 텍스트 템플릿 변환 호스트를 만들었습니다. 사용자 지정 또는 생성된 지시문 프로세서를 호출하는 텍스트 템플릿을 지원하도록 호스트를 확장할 수 있습니다. 자세한 내용은 Walkthrough: Connecting a Host to a Generated Directive Processor을 참조하십시오.

참고 항목

참조

ITextTemplatingEngineHost