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; } }