Ejemplo n.º 1
0
        /// <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());
        }
Ejemplo n.º 2
0
        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());
                }
            }
        }
Ejemplo n.º 3
0
        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);
        }