// Copyright (c) Microsoft Corporation. Todos los derechos reservados. Licenciado bajo la licencia MIT. Consulte Licencia en la raíz del proyecto para obtener información sobre la licencia. espacio de nombres Microsoft . Graph . ODataTemplateWriter . Procesador de plantilla { usando el sistema ; utilizando System . CodeDom . Compilador ; utilizando System . Colecciones . Genérico ; utilizando System . IO ; utilizando System . Linq ; utilizando System . Texto ; utilizando Microsoft . CSharp ; utilizando Microsoft . Graph . ODataTemplateWriter . Extensiones ; utilizando Microsoft . Graph . ODataTemplateWriter . PathWriters ; utilizando Microsoft . Graph . ODataTemplateWriter . TemplateProcessor . Enums ; utilizando Microsoft . VisualStudio . TextTemplating ; usando Vipr . Core ; usando Vipr . Core . CodeModel ; usando NLog ; TemplateProcessor de clase pública : ITemplateProcessor { privado estático CustomT4Host _host ; privada estática Logger logger = LogManager . GetCurrentClassLogger (); Host CustomT4Host estático protegido ( ITemplateInfo templateInfo , string templatesDirectory , OdcmObject odcmObject , OdcmModel odcmModel ) { // Necesita configurar siempre el host. Normalmente, esto se ejecuta en una única plataforma al generar archivos de código. // En casos de prueba, necesitamos apuntar a múltiples plataformas. Dado que gran parte de este código es estático, debemos asegurarnos // restablece la información proporcionada al procesador de plantillas. Este cambio corrige un error al apuntar // múltiples plataformas en una prueba. _host = new CustomT4Host ( templateInfo , templatesDirectory , odcmObject , odcmModel ); return _host ; } diccionario privado < Subprocesador , Func < ITemplateInfo , IEnumerable < TextFile >>> subprocesadores ; Diccionario privado de solo lectura < String , Func < ITextTemplatingEngineHost , string >> preProcessedTemplates ; protegido Diccionario < Subprocesador , Func < ITemplateInfo , IEnumerable < TextFile >>> Subprocesadores { obtener { si ( este . subprocesadores == nulo ) { esto . InitializeSubprocessors (); } devuelve esto . subprocesadores ; } } protegido vacío InitializeSubprocessors () { esto . subProcesadores = nuevo Diccionario < Subprocesador , Func < ITemplateInfo , IEnumerable < TextFile >>> () { { Subprocesador . EntityType , esto . ProcessEntityTypes }, { Subprocesador . ComplexType , esto . ProcessComplexTypes }, { Subprocesador . EnumType , esto . ProcessEnumTypes }, { Subprocesador . EntityContainer , esto . ProcessEntityContainerType }, { Subprocesador . MediaEntityType , esto . ProcessMediaEntityTypes }, { Subprocesador . Propiedad , esto . ProcessProperties }, { Subprocesador . StreamProperty , esto . ProcessStreamProperties }, { Subprocesador . CollectionProperty , esto . ProcessCollections }, { Subprocesador . NavigationCollectionProperty , esto . ProcessNavigationCollections }, { Subprocesador . CollectionReferenceProperty , esto . ProcessCollectionReferences }, { Subprocesador . EntityReferenceType , esto . ProcessEntityReferenceProperties }, { Subprocesador . Método , este . ProcessMethods }, { Subprocesador . NonCollectionMethod , esto . ProcessNonCollectionMethods }, { Subprocesador . CollectionMethod , este . ProcessCollectionMethods }, { Subprocesador . MethodWithBody , esto . ProcessMethodsWithBody }, { Subprocesador . Otro , este . ProcessTemplate }, }; } Protegido OdcmModel CurrentModel { get ; establecer ; } protegido Microsoft.VisualStudio.TextTemplating. Motor T4Engine { get ; establecer ; } protegido IPathWriter PathWriter { get ; establecer ; } cadena protegida TemplatesDirectory { get ; establecer ; } pública TemplateProcessor ( IPathWriter pathWriter , OdcmModel odcmModel , cadena templatesDirectory ) { esto . T4Engine = nuevo Microsoft . VisualStudio . TextTemplating . Motor (); esto . CurrentModel = odcmModel ; esto . PathWriter = pathWriter ; esto . PathWriter . Modelo = odcmModel ; esto . TemplatesDirectory = templatesDirectory ; esto . preProcessedTemplates = nuevo Diccionario < cadena , Func < ITextTemplatingEngineHost , cadena >> (); } cadena pública GetProcessorVerboseOutput () { // TODO: Marque NullReferenceException porque no hay plantillas cargadas. return _host . TemplateHostStats . ToString (); } pública IEnumerable < archivo de texto > Proceso ( ITemplateInfo templateInfo ) { Func < ITemplateInfo , IEnumerable < TextFile >> subProcessor = this . ProcessTemplate ; esto . Subprocesadores . TryGetValue ( templateInfo . SubprocessorType , fuera subencargado ); registrador . Info ( " Tipo de subprocesador actual: {0} " , templateInfo . SubprocessorType ); return subProcessor ( templateInfo ); } IEnumerable < TextFile > ProcessEntityContainerType virtual protegido ( ITemplateInfo templateInfo ) { rendimiento devuelve esto . ProcessTemplate ( templateInfo , this . CurrentModel . EntityContainer ); } IEnumerable < TextFile > ProcessEnumTypes virtual protegido ( ITemplateInfo templateInfo ) { devuelve esto . ProcessTypes ( templateInfo , this . CurrentModel . GetEnumTypes ); } IEnumerable < TextFile > ProcessComplexTypes virtual protegido ( ITemplateInfo templateInfo ) { devuelve esto . ProcessTypes ( templateInfo , this . CurrentModel . GetComplexTypes ); } IEnumerable < TextFile > ProcessEntityTypes virtual protegido ( ITemplateInfo templateInfo ) { devuelve esto . ProcessTypes ( templateInfo , this . CurrentModel . GetEntityTypes ); } IEnumerable < TextFile > ProcessCollections virtual protegido ( ITemplateInfo templateInfo ) { devuelve esto . ProcessProperties ( templateInfo , this . CollectionProperties ); } IEnumerable < TextFile > ProcessMediaEntityTypes virtual protegido ( ITemplateInfo templateInfo ) { devuelve esto . ProcessTypes ( templateInfo , this . CurrentModel . GetMediaEntityTypes ); } IEnumerable < TextFile > ProcessNavigationCollections virtual protegido ( ITemplateInfo templateInfo ) { devuelve esto . ProcessProperties ( templateInfo , this . NavigationCollectionProperties ); } IEnumerable < TextFile > ProcessCollectionReferences virtual protegido ( ITemplateInfo templateInfo ) { devuelve esto . ProcessProperties ( templateInfo , this . CollectionReferenceProperties ); } IEnumerable < TextFile > ProcessProperties virtual protegido ( ITemplateInfo templateInfo ) { devuelve esto . ProcessProperties ( templateInfo , this . CurrentModel . GetProperties ); } IEnumerable < TextFile > ProcessEntityReferenceProperties virtual protegido ( ITemplateInfo templateInfo ) { devuelve esto . ProcessTypes ( templateInfo , this . CurrentModel . GetEntityReferenceTypes ); } IEnumerable < TextFile > ProcessStreamProperties virtual protegido ( ITemplateInfo templateInfo ) { devuelve esto . ProcessProperties ( templateInfo , this . CurrentModel . GetStreamProperties ); } IEnumerable < TextFile > ProcessMethods virtual protegido ( ITemplateInfo templateInfo ) { devuelve esto . ProcessMethods ( templateInfo , this . CurrentModel . GetMethods ); } IEnumerable < TextFile > ProcessMethodsWithBody virtual protegido ( ITemplateInfo templateInfo ) { devuelve esto . ProcessMethods ( templateInfo , this . MethodsWithBody ); } IEnumerable < TextFile > ProcessCollectionMethods virtual protegido ( ITemplateInfo templateInfo ) { devuelve esto . ProcessMethods ( templateInfo , this . CollectionMethods ); } IEnumerable < TextFile > ProcessNonCollectionMethods virtual protegido ( ITemplateInfo templateInfo ) { devuelve esto . ProcessMethods ( templateInfo , this . NonCollectionMethods ); } privado IEnumerable < archivo de texto > ProcessTypes ( ITemplateInfo templateInfo , Func < IEnumerable < OdcmObject >> modelMethod ) { devuelve esto . FilterOdcmEnumerable ( templateInfo , modelMethod ) . Seleccione ( odcmType => this . ProcessTemplate ( templateInfo , odcmType , className : odcmType . Name )); } Private IEnumerable < TextFile > ProcessProperties ( ITemplateInfo templateInfo , Func < IEnumerable < OdcmObject >> modelMethod ) { devuelve esto . FilterOdcmEnumerable ( templateInfo , modelMethod ) . Seleccione ( propiedad => propiedad como OdcmProperty ) . Seleccione ( odcmProperty => this . ProcessTemplate ( templateInfo , odcmProperty , className : odcmProperty . Clase . nombre , propertyName : odcmProperty . nombre , propertyType : odcmProperty . Proyección . Escriba . Nombre )); } protegidas virtuales IEnumerable < TEXTFILE > ProcessMethods ( ITemplateInfo templateInfo , Func < IEnumerable < OdcmMethod >> métodos ) { devuelve esto . FilterOdcmEnumerable ( templateInfo , métodos ) . Seleccione ( método => método como OdcmMethod ) . Seleccione ( odcmMethod => this . ProcessTemplate ( templateInfo , odcmMethod , className : odcmMethod . Clase . nombre , methodName : odcmMethod . Nombre )); } IEnumerable virtual protegido < OdcmMethod > NonCollectionMethods () { devuelve esto . CurrentModel . GetMethods (). Donde ( método => ! Método . IsCollection ); } IEnumerable virtual protegido < OdcmMethod > MethodsWithBody () { devuelve esto . CurrentModel . GetMethods (). Donde ( método => método . Parámetros ! = Nulo && método . Parámetros . Any () && método . IsAction ()); } IEnumerable virtual protegido < OdcmMethod > CollectionMethods () { métodos var = esto . CurrentModel . GetMethods (). Donde ( método => método . IsCollection && método . Tipo de retorno ! = Nula ). ToList (); métodos de devolución ; } IEnumerable virtual protegido < OdcmProperty > NavigationCollectionProperties () { devuelve esto . CurrentModel . GetProperties (). Donde ( prop => prop . IsCollection && prop . IsNavigation () && ! Prop . IsReference ()); } IEnumerable virtual protegido < OdcmProperty > CollectionReferenceProperties () { devuelve esto . CurrentModel . GetProperties (). Donde ( prop => prop . IsReference () && prop . IsCollection ); } IEnumerable virtual protegido < OdcmProperty > CollectionProperties () { devuelve esto . CurrentModel . GetProperties (). Donde ( prop => prop . IsCollection && ! ( Prop . Proyección . El tipo es OdcmPrimitiveType ) && ! Prop . IsReference ()); } IEnumerable < OdcmObject > FilterOdcmEnumerable virtual protegido ( ITemplateInfo templateInfo , Func < IEnumerable < OdcmObject >> modelMethod ) { var filteredEnum = modelMethod (). Donde ( o => templateInfo . ShouldIncludeObject ( o )); si ( _host ! = nula && ! filteredEnum . Cualquier ()) { _host . TemplateHostStats . RecordProcessedNothing ( templateInfo ); } return filterEnum ; } protegido IEnumerable < TextFile > ProcessTemplate ( ITemplateInfo templateInfo ) { rendimiento devuelve esto . ProcessTemplate ( templateInfo , null , templateInfo . BaseFileName ()); } private const string RuntimeTemplatesNamespace = " RuntimeTemplates " ; privada Func < ITextTemplatingEngineHost , cadena > PreProcessTemplate ( ITemplateInfo templateInfo ) { var templateContent = Archivo . ReadAllText ( templateInfo . FullPath ); lenguaje de cadenas ; referencias de cadena [] ; var className = templateInfo . TemplateName . Reemplazar ( " . " , " _ " ); var dummyHost = new CustomT4Host ( templateInfo , this . TemplatesDirectory , nulo , nulo ); var generateCode = esto . T4Engine . PreprocessTemplate ( templateContent , dummyHost , className , RuntimeTemplatesNamespace , fuera de idioma , fuera de referencias ); var parámetros = nuevos parámetros del compilador { // OutputAssembly = templateInfo.TemplateName + ".dll", GenerateInMemory = verdadero , GenerateExecutable = falso , IncluirDebugInformation = verdadero , }; var assemblyLocations = AppDomain . CurrentDomain . GetAssemblies () . Donde ( un => ! Una . IsDynamic ) . Seleccione ( a => a . Ubicación ); parámetros . Asambleas referenciadas . AddRange ( ubicaciones de ensamblado . ToArray ()); parámetros . TreatWarningsAsErrors = falso ; proveedor var = nuevo CSharpCodeProvider (); var resultados = proveedor . CompileAssemblyFromSource ( parámetros , generateCode ); if ( resultados . Errores . Recuento > 0 ) { var realError = false ; para ( int i = 0 ; i < resultados . Errores . Cuenta ; i ++ ) { if ( ! results . Errores [ i ]. IsWarning ) realError = true ; registrador . Error (( resultados . Errores [ i ]. IsWarning ? " Advertencia " : " Error " ) + " ( " + i . ToString () + " ): " + resultados . Errores [ i ]. ToString ()); Consola . WriteLine (( resultados . Errores [ i ]. IsWarning ? " Advertencia " : " Error " ) + " ( " + i . ToString () + " ): " + resultados . Errores [ i ]. ToString ()); } si ( error real ) { Archivo . WriteAllText ( " __ErrorFile.cs " , generateCode ); lanzar una nueva InvalidOperationException ( " Error de plantilla " ); } } var ensamblaje = resultados . CompiledAssembly ; var templateClassType = ensamblado . GetType ( RuntimeTemplatesNamespace + " . " + ClassName ); dynamic templateClassInstance = Activador . CreateInstance ( templateClassType ); return ( ITextTemplatingEngineHost host ) => { templateClassInstance . Anfitrión = anfitrión ; return templateClassInstance . TransformText (); }; } Privado TextFile ProcessTemplate ( ITemplateInfo templateInfo , OdcmObject odcmObject , string className = " " , string propertyName = " " , string methodName = " " , string propertyType = " " ) { devuelve esto . ProcessTemplate ( templateInfo , odcmObject , templateInfo . BaseFileName ( este . CurrentModel . EntityContainer . Name , className , propertyName , methodName , propertyType )); } Protegido TextFile ProcessTemplate ( ITemplateInfo templateInfo , OdcmObject odcmObject , string fileName ) { registrador . Trace ( $ " Generando archivo { fileName } " ); var host = TemplateProcessor . Host ( templateInfo , this . TemplatesDirectory , odcmObject , this . CurrentModel ); Func < ITextTemplatingEngineHost , string > preProcessedTemplate ; if ( ! this . preProcessedTemplates . TryGetValue ( templateInfo . FullPath , out preProcessedTemplate )) { preProcessedTemplate = esto . PreProcessTemplate ( templateInfo ); esto . preProcessedTemplates . Agregar ( templateInfo . FullPath , preProcessedTemplate ); } var output = preProcessedTemplate ( host ); if ( ! string . IsNullOrEmpty ( host . TemplateName )) { fileName = host . TemplateName ; } if ( host . Errores ! = null && host . Errores . HasErrors ) { var errores = esto . LogErrors ( host , templateInfo ); registrador . Error ( errores ); lanzar una nueva InvalidOperationException ( errores ); } var ruta = esto . PathWriter . WritePath ( templateInfo , fileName ); registrador . Debug ( " Plantilla escrita en la ruta {0} " , ruta ); anfitrión . TemplateHostStats . RecordProcessed ( templateInfo , odcmObject =! Nulo ? OdcmObject . Nombre : cadena . Vacío , camino ); return new TextFile ( ruta , salida ); } pública de cuerda LOGERRORS ( CustomT4Host anfitrión , ITemplateInfo templateInfo ) { var sb = new StringBuilder (); if ( host . Errores == null || host . Errores . Recuento <= 0 ) return sb . ToString (); foreach ( Error de CompilerError en el host . Errores ) { sb . AppendLine ( " ERROR de procesador de plantillas " ). AppendFormat ( @ " Nombre: {0} {1} " , templateInfo . TemplateName , Environment . NewLine ). AppendFormat ( @ " Línea: {0} {1} " , error . Línea , Entorno . Nueva línea ). AppendFormat ( @ " Detalles: {0} {1} " , error . ErrorText , Environment . NewLine ). AppendLine (). AppendLine (); } return sb . ToString (); } } }