/// <summary> /// This method will compile the type defined in <paramref name="codeGenerationBuilder"/> /// and return the result types. These types exists in a temp assembly, that will be /// deleted when the app domain is terminated. /// </summary> /// <param name="codeGenerationBuilder"></param> /// <param name="verbose"></param> /// <returns></returns> public static IEnumerable<Type> CompileRuntimeTempTypes(CodeGenerationBuilder codeGenerationBuilder, bool verbose = true) { int t1 = Environment.TickCount; _compositeGeneratedCompiled = false; // When compiling a new type, Composite.Generated.dll should always be recompiled var compilerParameters = new CompilerParameters { GenerateExecutable = false, GenerateInMemory = false, OutputAssembly = Path.Combine(TempAssemblyFolderPath, Guid.NewGuid() + ".dll") }; compilerParameters.ReferencedAssemblies.AddRangeIfNotContained(codeGenerationBuilder.AssemblyLocations.ToArray()); compilerParameters.ReferencedAssemblies.AddRangeIfNotContained(_compiledAssemblies.Select(f => f.Location).ToArray()); compilerParameters.AddAssemblyLocationsFromBin(); var codeCompileUnit = new CodeCompileUnit(); codeCompileUnit.Namespaces.AddRange(codeGenerationBuilder.Namespaces.ToArray()); var compiler = new CSharpCodeProvider(); var compileResult = compiler.CompileAssemblyFromDom(compilerParameters, codeCompileUnit); if (compileResult.Errors.Count == 0) { Assembly resultAssembly = compileResult.CompiledAssembly; AddCompiledAssembly(resultAssembly); Type[] resultTypes = resultAssembly.GetTypes(); int t2 = Environment.TickCount; Log.LogVerbose(LogTitle, string.Format("Compile '{0}' in {1}ms", codeGenerationBuilder.DebugLabel, t2 - t1)); Log.LogVerbose(LogTitle, string.Format("Types from : {0}", compilerParameters.OutputAssembly)); foreach (Type resultType in resultTypes) { _compiledTypesByFullName[resultType.FullName] = resultType; } return resultTypes; } #if OUTPUT_SOURCE_CODE_ON_ERROR using (FileStream file = File.Create(Path.Combine(PathUtil.BaseDirectory, "output.cs"))) { using (var sw = new StreamWriter(file)) { compiler.GenerateCodeFromCompileUnit(codeCompileUnit, sw, new CodeGeneratorOptions()); } } #endif var failedAssemblyLoads = new List<Pair<string, Exception>>(); foreach (string assemblyLocation in compilerParameters.ReferencedAssemblies) { try { Assembly assembly = Assembly.LoadFrom(assemblyLocation); var types = assembly.GetTypes(); // Accessing GetTypes() to iterate classes } catch (Exception ex) { Exception exceptionToLog = ex; var loadException = ex as ReflectionTypeLoadException; if (loadException != null && loadException.LoaderExceptions != null && loadException.LoaderExceptions.Any()) { exceptionToLog = loadException.LoaderExceptions.First(); } failedAssemblyLoads.Add(new Pair<string, Exception>( assemblyLocation, exceptionToLog)); } } var sb = new StringBuilder(); failedAssemblyLoads.ForEach(asm => sb.AppendFormat("Failed to load dll: '{0}' : {1}", asm.First, asm.Second).AppendLine()); sb.AppendLine("Failed building: " + codeGenerationBuilder.DebugLabel); foreach (CompilerError compilerError in compileResult.Errors) { if (compilerError.IsWarning) continue; string entry = "Compile error: " + compilerError.ErrorNumber + "(" + compilerError.Line + ")" + ": " + compilerError.ErrorText.Replace("{", "{{").Replace("}", "}}"); if (verbose) { Log.LogError(LogTitle, entry); } sb.AppendLine(entry); } throw new InvalidOperationException(sb.ToString()); }
private static void Compile(CodeGenerationBuilder builder) { var compilerParameters = new CompilerParameters { GenerateExecutable = false, GenerateInMemory = false, OutputAssembly = CompositeGeneratedAssemblyPath, TempFiles = new TempFileCollection(TempAssemblyFolderPath) }; compilerParameters.ReferencedAssemblies.AddRangeIfNotContained(builder.AssemblyLocations.ToArray()); compilerParameters.AddAssemblyLocationsFromBin(); var codeCompileUnit = new CodeCompileUnit(); codeCompileUnit.Namespaces.AddRange(builder.Namespaces.ToArray()); for (int i = 0; i < NumberOfCompileRetries; i++) { var compiler = new CSharpCodeProvider(); CompilerResults compileResult = compiler.CompileAssemblyFromDom(compilerParameters, codeCompileUnit); if (compileResult.Errors.Count == 0) return; if (i == NumberOfCompileRetries - 1) { #if OUTPUT_SOURCE_CODE_ON_ERROR using (FileStream file = File.Create(Path.Combine(PathUtil.BaseDirectory, "output.cs"))) { using (var sw = new StreamWriter(file)) { compiler.GenerateCodeFromCompileUnit(codeCompileUnit, sw, new CodeGeneratorOptions()); } } #endif var sb = new StringBuilder(); foreach (CompilerError compilerError in compileResult.Errors) { if (compilerError.IsWarning) continue; string entry = "Compile error: " + compilerError.ErrorNumber + "(" + compilerError.Line + ")" + ": " + compilerError.ErrorText.Replace("{", "{{").Replace("}", "}}"); Log.LogError(LogTitle, entry); sb.AppendLine(entry); } throw new InvalidOperationException(sb.ToString()); } } }
private static CompatibilityCheckResult CheckAgainsAppCode(DataTypeDescriptor dataTypeDescriptorToTest, bool includeDataTypeDescriptor) { List<string> filesToCompile = GetAppCodeFiles().ToList(); if (filesToCompile.Count == 0) return new CompatibilityCheckResult(); CSharpCodeProvider csCompiler = new CSharpCodeProvider(); List<Assembly> referencedAssemblies = new List<Assembly>(); Dictionary<string, List<CodeTypeDeclaration>> codeTypeDeclarations = new Dictionary<string, List<CodeTypeDeclaration>>(); foreach (DataTypeDescriptor dataTypeDescriptor in DataMetaDataFacade.GeneratedTypeDataTypeDescriptors) { if (!includeDataTypeDescriptor && (dataTypeDescriptor.DataTypeId == dataTypeDescriptorToTest.DataTypeId)) continue; DataTypeDescriptor dataTypeDescriptorToUse = dataTypeDescriptor; if (includeDataTypeDescriptor && (dataTypeDescriptor.DataTypeId == dataTypeDescriptorToTest.DataTypeId)) dataTypeDescriptorToUse = dataTypeDescriptorToTest; referencedAssemblies.AddRange(InterfaceCodeGenerator.GetReferencedAssemblies(dataTypeDescriptorToUse)); CodeTypeDeclaration codeTypeDeclaration = InterfaceCodeGenerator.CreateCodeTypeDeclaration(dataTypeDescriptorToUse); List<CodeTypeDeclaration> declarations; if (!codeTypeDeclarations.TryGetValue(dataTypeDescriptorToUse.Namespace, out declarations)) { declarations = new List<CodeTypeDeclaration>(); codeTypeDeclarations.Add(dataTypeDescriptorToUse.Namespace, declarations); } declarations.Add(codeTypeDeclaration); string tempFilePath = GetTempFileName(dataTypeDescriptorToUse); filesToCompile.Add(tempFilePath); using (FileStream file = File.Create(tempFilePath)) { using (var sw = new StreamWriter(file)) { CodeNamespace codeNamespace = new CodeNamespace(dataTypeDescriptorToUse.Namespace); codeNamespace.Types.Add(codeTypeDeclaration); csCompiler.GenerateCodeFromNamespace(codeNamespace, sw, new CodeGeneratorOptions()); } StringBuilder sb = new StringBuilder(); using (var sw = new StringWriter(sb)) { csCompiler.GenerateCodeFromMember(codeTypeDeclaration, sw, new CodeGeneratorOptions()); } } } filesToCompile.Sort(); CompilerParameters compilerParameters = new CompilerParameters(); compilerParameters.GenerateExecutable = false; compilerParameters.GenerateInMemory = true; compilerParameters.ReferencedAssemblies.AddRangeIfNotContained(referencedAssemblies.Select(f => f.Location).ToArray()); compilerParameters.ReferencedAssemblies.AddRangeIfNotContained(CodeGenerationManager.CompiledAssemblies.Select(f => f.Location).ToArray()); compilerParameters.AddAssemblyLocationsFromBin(); compilerParameters.AddLoadedAssemblies(false); compilerParameters.AddCommonAssemblies(); compilerParameters.RemoveGeneratedAssemblies(); CodeCompileUnit codeCompileUnit = new CodeCompileUnit(); foreach (var kvp in codeTypeDeclarations) { CodeNamespace codeNamespace = new CodeNamespace(kvp.Key); codeNamespace.Types.AddRange(kvp.Value.ToArray()); codeCompileUnit.Namespaces.Add(codeNamespace); } CSharpCodeProvider compiler = new CSharpCodeProvider(); CompilerResults compileResult = compiler.CompileAssemblyFromFile(compilerParameters, filesToCompile.ToArray()); if (compileResult.Errors.Count == 0) return new CompatibilityCheckResult(); // Checking for a missing assembly error, if it is present, that means that App_Code check isn't applicable due to circular reference foreach (CompilerError error in compileResult.Errors) { if (error.ErrorNumber == "CS0012" && error.ErrorText.Contains("Composite.Generated")) { return new CompatibilityCheckResult(); } } return new CompatibilityCheckResult(compileResult); }