Exemplo n.º 1
0
        private Evaluator CreateExpressionEvaluator()
        {
            var meta = new ExpressionMeta("VisualBasic");

            // Expressions
            string expression;
            foreach (var candidate in GetPossibleExpressions())
                if (LocalReportsEngineCommon.IsExpression(candidate, out expression))
                    meta.AddExpression(expression);

            // TODO: Extensions
            var extension = new Extension();
            extension.Name = "Parameters";
            extension.Instance = new ReadOnlyParameterCollection(ReportParameters);
            meta.AddExtension(extension);

            // TODO: Async compile in Evaluator

            return meta.Compile();
        }
        /// <summary>
        /// Compiles expression metadata into an assembly. The assembly is then wrapped by an <see cref="Evaluator"/>.
        /// </summary>
        /// <param name="meta">The expression metadata to compile.</param>
        /// <returns>An <see cref="Evaluator"/> capable of evaluating the expressions.</returns>
        public static Evaluator Compile(ExpressionMeta meta)
        {
            if (meta == null) throw new ArgumentNullException("meta");

            string assemblyPath = null;
            AppDomain appDomain = null;

            try
            {
                assemblyPath = CreateAssembly(meta);
                appDomain = CreateAppDomain(assemblyPath);
                var sandbox = CreateSandbox(appDomain, assemblyPath, meta.Extensions);

                return new Evaluator(appDomain, sandbox, assemblyPath);
            }
            catch (Exception)
            {
                if (appDomain != null)
                    AppDomain.Unload(appDomain);

                if (assemblyPath != null)
                    File.Delete(assemblyPath);

                throw;
            }
        }
        /// <summary>
        /// Gets assembly references for the expression metadata based on its language.
        /// </summary>
        /// <param name="meta">The expression metadata for which to get references.</param>
        /// <returns>All relevant assembly references.</returns>
        private static IEnumerable<string> GetReferences(ExpressionMeta meta)
        {
            foreach (var reference in DefaultReferences)
                yield return reference;

            string[] references;
            if (DefaultLanguageReferences.TryGetValue(meta.Language, out references))
                foreach (var reference in references)
                    yield return reference;

            foreach (var reference in meta.References)
                yield return reference;

            foreach (var type in meta.Extensions.Select(e => e.GetExtensionType()))
                yield return type.Assembly.ManifestModule.FullyQualifiedName;
        }
        /// <summary>
        /// Gets namespace imports for the expression metadata based on its language.
        /// </summary>
        /// <param name="meta">The expression metadata for which to get namespace imports.</param>
        /// <returns>All relevant namespace imports.</returns>
        private static IEnumerable<string> GetImports(ExpressionMeta meta)
        {
            foreach (var import in DefaultImports)
                yield return import;

            string[] imports;
            if (DefaultLanguageImports.TryGetValue(meta.Language, out imports))
                foreach (var import in imports)
                    yield return import;

            foreach (var import in meta.Imports)
                yield return import;
        }
        /// <summary>
        /// Creates an abstract model of the compiled expression assembly.
        /// </summary>
        /// <param name="meta">The expression metadata for which to create an abstract model for.</param>
        /// <returns>An abstract model, suitable for compiling with CodeDom.</returns>
        private static CodeCompileUnit CreateModel(ExpressionMeta meta)
        {
            // Class
            var modelClass = new CodeTypeDeclaration();
            modelClass.Name = ClassName;
            modelClass.TypeAttributes = TypeAttributes.Public | TypeAttributes.Class;

            // Class methods
            foreach (var expression in meta.Expressions)
            {
                var modelExpression = new CodeSnippetExpression();
                modelExpression.Value = expression;

                var modelReturn = new CodeMethodReturnStatement();
                modelReturn.Expression = modelExpression;

                var modelMethod = new CodeMemberMethod();
                modelMethod.Name = GetExpressionMethodName(expression);
                modelMethod.Attributes = MemberAttributes.Public;
                modelMethod.ReturnType = new CodeTypeReference(typeof(object));
                modelMethod.Statements.Add(modelReturn);
                modelClass.Members.Add(modelMethod);
            }

            // Class fields
            foreach (var extension in meta.Extensions)
            {
                var modelField = new CodeMemberField();
                modelField.Name = extension.Name;
                modelField.Attributes = MemberAttributes.Public;
                modelField.Type = new CodeTypeReference(extension.GetExtensionType()); // Need to add this as an extra reference
                modelClass.Members.Add(modelField);
            }

            // Namespace
            var modelNamespace = new CodeNamespace();
            modelNamespace.Name = NamespaceName;
            modelNamespace.Types.Add(modelClass);

            // Namespace Imports
            foreach (var import in GetImports(meta).Distinct())
                modelNamespace.Imports.Add(new CodeNamespaceImport(import));

            // Assembly
            var modelAssembly = new CodeCompileUnit();
            modelAssembly.Namespaces.Add(modelNamespace);

            // Assembly References
            foreach (var reference in GetReferences(meta).Distinct())
                modelAssembly.ReferencedAssemblies.Add(reference);

            return modelAssembly;
        }
        /// <summary>
        /// Creates the compiled expressions assembly.
        /// </summary>
        /// <param name="meta">The expression metadata to compile into an assembly.</param>
        /// <returns>The path of the compiled expression assembly.</returns>
        /// <remarks>The caller is responsible for deleting the compiled assembly.</remarks>
        private static string CreateAssembly(ExpressionMeta meta)
        {
            var model = CreateModel(meta);
            var options = new CompilerParameters();
            options.GenerateExecutable = false;
            options.GenerateInMemory = false;

            using (var provider = CodeDomProvider.CreateProvider(meta.Language))
            {
                // Compile the assembly
                var results = provider.CompileAssemblyFromDom(options, model);

                // ...or not
                if (results.Errors.HasErrors)
                    throw new InvalidOperationException(results.Errors[0].ToString());

                return results.PathToAssembly;
            }
        }