private static void ProcessXamlFile(string sourceFileWithAbsolutePath, string destinationFileWithAbsolutePath, string csprojFilePath, string tempFolder, ReflectionOnSeparateAppDomainHandler reflectionOnSeparateAppDomain, ILogger logger) { // Read XAML file: using (StreamReader sr = new StreamReader(sourceFileWithAbsolutePath)) { String xaml = sr.ReadToEnd(); // Convert XAML to CS: string generatedCode = ConvertingXamlToCSharp.Convert(xaml, sourceFileWithAbsolutePath, "", "", reflectionOnSeparateAppDomain, isFirstPass: false, isSLMigration: false, outputRootPath: "", outputAppFilesPath: "", outputLibrariesPath: "", outputResourcesPath: "", logger: logger); //todo: fill the missing arguments //todo: support first and second pass? // Save output: using (StreamWriter outfile = new StreamWriter(destinationFileWithAbsolutePath + ".g.cs")) { outfile.Write(generatedCode); } } //File.Copy(sourceFileWithAbsolutePath, destinationFileWithAbsolutePath + ".g.cs", true); }
public static bool Execute(string sourceFile, string outputFile, string fileNameWithPathRelativeToProjectRoot, string assemblyNameWithoutExtension, string coreAssemblyFiles, bool isSecondPass, bool isSLMigration, ILogger logger, string activationAppPath, string cSharpXamlForHtml5OutputType, bool overrideOutputOnlyIfSourceHasChanged, string outputRootPath, string outputAppFilesPath, string outputLibrariesPath, string outputResourcesPath, string flagsString, bool isBridgeBasedVersion, string nameOfAssembliesThatDoNotContainUserCode) { string passNumber = (isSecondPass ? "2" : "1"); string operationName = string.Format("C#/XAML for HTML5: XamlPreprocessor (pass {0})", passNumber); try { using (var executionTimeMeasuring = new ExecutionTimeMeasuring()) { // Validate input strings: if (string.IsNullOrEmpty(sourceFile)) { throw new Exception(operationName + " failed because the source file argument is invalid."); } if (string.IsNullOrEmpty(outputFile)) { throw new Exception(operationName + " failed because the output file argument is invalid."); } if (string.IsNullOrEmpty(fileNameWithPathRelativeToProjectRoot)) { throw new Exception(operationName + " failed because the FileNameWithPathRelativeToProjectRoot argument is invalid."); } if (string.IsNullOrEmpty(assemblyNameWithoutExtension)) { throw new Exception(operationName + " failed because the AssemblyNameWithoutExtension argument is invalid."); } if (string.IsNullOrEmpty(coreAssemblyFiles)) { throw new Exception(operationName + " failed because the core assembly file argument is invalid."); } HashSet <string> flags = (flagsString != null ? new HashSet <string>(flagsString.Split(';')) : new HashSet <string>()); #if REQUIRE_ACTIVATION_FOR_SILVERLIGHT_MIGRATION #if SILVERLIGHTCOMPATIBLEVERSION #if !BRIDGE //------- Check SL Migration license (unless we are compiling a class library, in which case we do not want to check so that it is more convenient for developing Extensions that work with any CSHTML5 edition) ------- if (cSharpXamlForHtml5OutputType == null || cSharpXamlForHtml5OutputType.ToLower() != "library") { if (!CheckSLMigrationLicense(logger, activationAppPath, flags)) { return(false); } } #endif #endif #endif //------- DISPLAY THE PROGRESS ------- logger.WriteMessage(operationName + " started for file \"" + sourceFile + "\". Output file: \"" + outputFile + "\". FileNameWithPathRelativeToProjectRoot: \"" + fileNameWithPathRelativeToProjectRoot + "\". AssemblyNameWithoutExtension: \"" + assemblyNameWithoutExtension + "\". Core assembly files: \"" + coreAssemblyFiles + "\". IsSecondPass: "******"\"."); //todo: do not display the output file location? // Read the XAML file: using (StreamReader sr = new StreamReader(sourceFile)) { String xaml = sr.ReadToEnd(); // Determine if the file should be processed or if there is no need to process it again (for example if the XAML has not changed and we are in design-time, we don't want to re-process the XAML): bool shouldTheFileBeProcessed = DetermineIfTheXamlFileNeedsToBeProcessed(xaml, outputFile, overrideOutputOnlyIfSourceHasChanged, isSecondPass); if (shouldTheFileBeProcessed) { // The "ReflectionOnSeparateAppDomainHandler" class lets us use a separate AppDomain to resolve the types so that the types can be unloaded when done (when disposed, it frees any hook on the user application DLL's): ReflectionOnSeparateAppDomainHandler reflectionOnSeparateAppDomain = ReflectionOnSeparateAppDomainHandler.Current; // Note: this is not supposed to be null because it was instantiated in the "BeforeXamlPreprocessor" task. We use a static instance to avoid reloading the assemblies for each XAML file that is processed. // Make sure that the reference is not null: if (reflectionOnSeparateAppDomain == null) { throw new Exception("ReflectionOnSeparateAppDomainHandler.Current is null. It should not be null because it was supposed to be populated by the 'BeforeXamlPreprocessor' task. Please verify that the MSBuild Targets are up to date."); } // Convert XAML to CS: string generatedCode = ConvertingXamlToCSharp.Convert(xaml, sourceFile, fileNameWithPathRelativeToProjectRoot, assemblyNameWithoutExtension, reflectionOnSeparateAppDomain, isFirstPass: !isSecondPass, isSLMigration: isSLMigration, outputRootPath: outputRootPath, outputAppFilesPath: outputAppFilesPath, outputLibrariesPath: outputLibrariesPath, outputResourcesPath: outputResourcesPath, logger: logger); // Add the header that contains the file hash so as to avoid re-processing the file if not needed: generatedCode = CreateHeaderContainingHash(generatedCode, xaml, isSecondPass) + Environment.NewLine + Environment.NewLine + generatedCode; // Create output directory: Directory.CreateDirectory(Path.GetDirectoryName(outputFile)); // Save output: using (StreamWriter outfile = new StreamWriter(outputFile)) { outfile.Write(generatedCode); } } } //------- DISPLAY THE PROGRESS ------- logger.WriteMessage(operationName + " completed in " + executionTimeMeasuring.StopAndGetTimeInSeconds() + " seconds."); return(true); } } catch (Exception ex) { //----------------------------------------------------- // Dispose the static instance of the "ReflectionOnSeparateAppDomainHandler": //----------------------------------------------------- /* * We dispose the static instance of the "ReflectionOnSeparateAppDomainHandler" * that was created in the "BeforeXamlPreprocessor" task, in order to free any * hooks on the user app DLL's. * Note: this is normally done in the task named "AfterXamlPreprocessor", but * since we are going to cancel the Build process, that task will never be * executed, resulting in potential hooks to the DLL not being freed (causing * issues when the user recompiles his application). So we free them now. */ ReflectionOnSeparateAppDomainHandler.Current.Dispose(); // Note: this is not supposed to be null because it was instantiated in the "BeforeXamlPreprocessor" task. //----------------------------------------------------- // Display the error and cancel the Build process: //----------------------------------------------------- string message = $"{operationName} failed: {ex.Message}\nNote: the XAML editor sometimes raises errors that are misleading. To see only real non-misleading errors, make sure to close all the XAML editor windows/tabs before compiling."; if (ex is wpf::System.Windows.Markup.XamlParseException) { int lineNumber = ((wpf::System.Windows.Markup.XamlParseException)ex).LineNumber; logger.WriteError(message, file: sourceFile, lineNumber: lineNumber); } else { logger.WriteError(message, file: sourceFile); } return(false); } }