public dependency_inlining() { theAssembly = new GeneratedAssembly(new GenerationRules("Lamar.Generated")); theType = theAssembly.AddType("GeneratedClass", typeof(Message1Handler)); theMethod = theType.MethodFor("Handle"); }
public void CompileWithInlineServices(GeneratedAssembly assembly) { assembly.CompileAll(ServiceGraph); }
public string GenerateCodeWithInlineServices(GeneratedAssembly assembly) { return(assembly.GenerateCode(ServiceGraph)); }
public static void CompileAll(this GeneratedAssembly assembly) { new AssemblyGenerator().Compile(assembly); }
public override Type Generate(Type type) { var entityTypeDetail = TypeAnalyzer.GetTypeDetail(entityType); if (!entityTypeDetail.Attributes.Select(x => x.GetType()).Contains(entityAttributeType)) { throw new Exception($"{nameof(TransactStoreEntityAttribute)} {nameof(entityType)} argument {type.Name} does not inherit {entityAttributeType.Name}"); } var typeDetail = TypeAnalyzer.GetTypeDetail(type); if (!typeDetail.BaseTypes.Contains(dataContextType)) { throw new Exception($"{nameof(TransactStoreEntityAttribute)} is not placed on a {dataContextType.Name}"); } var baseType = TypeAnalyzer.GetGenericType(providerType, type, entityType); var typeSignature = $"{entityType.Name}_{type.Name}_Provider"; var moduleBuilder = GeneratedAssembly.GetModuleBuilder(); var typeBuilder = moduleBuilder.DefineType(typeSignature, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.AutoLayout, baseType); _ = typeBuilder.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName); var properties = new HashSet <Tuple <PropertyInfo, bool> >(); var transactProviderTypeDetails = TypeAnalyzer.GetTypeDetail(baseType); var methods = transactProviderTypeDetails.MethodDetails.Select(x => x.MethodInfo).ToArray(); if (eventLinking.HasValue) { var eventLinkingProperty = transactProviderTypeDetails.GetMember("EventLinking"); properties.Add(new Tuple <PropertyInfo, bool>((PropertyInfo)eventLinkingProperty.MemberInfo, eventLinking.Value)); } if (queryLinking.HasValue) { var queryLinkingProperty = transactProviderTypeDetails.GetMember("QueryLinking"); properties.Add(new Tuple <PropertyInfo, bool>((PropertyInfo)queryLinkingProperty.MemberInfo, queryLinking.Value)); } if (persistLinking.HasValue) { var eventLinkingProperty = transactProviderTypeDetails.GetMember("PersistLinking"); properties.Add(new Tuple <PropertyInfo, bool>((PropertyInfo)eventLinkingProperty.MemberInfo, persistLinking.Value)); } foreach (var prop in properties) { var property = prop.Item1; var value = prop.Item2; var propertyBuilder = typeBuilder.DefineProperty( property.Name, PropertyAttributes.HasDefault, property.PropertyType, null ); var getMethodName = "get_" + property.Name; var getMethod = methods.FirstOrDefault(x => x.Name == getMethodName); var getMethodBuilder = typeBuilder.DefineMethod( getMethodName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.Final, property.PropertyType, Type.EmptyTypes ); var getMethodBuilderIL = getMethodBuilder.GetILGenerator(); if (value) { getMethodBuilderIL.Emit(OpCodes.Ldc_I4_1); } else { getMethodBuilderIL.Emit(OpCodes.Ldc_I4_0); } getMethodBuilderIL.Emit(OpCodes.Ret); typeBuilder.DefineMethodOverride(getMethodBuilder, getMethod); propertyBuilder.SetGetMethod(getMethodBuilder); } var objectType = typeBuilder.CreateTypeInfo(); return(objectType); }
public GeneratedType Build(GeneratedAssembly assembly, DocumentOperations operations) { var selectorType = _selectorTypeSource(operations); return(buildDocumentStorageType(assembly, operations, _typeName, _baseType, selectorType)); }
public Task AddCachedAssembly(string targetAssemblyName, GeneratedAssembly cachedAssembly) { CodeGeneratorManager.AddGeneratedAssembly(targetAssemblyName, cachedAssembly); return(Task.CompletedTask); }
public DocumentProvider <T> Generate <T>() { var assembly = new GeneratedAssembly(new GenerationRules(SchemaConstants.MartenGeneratedNamespace)); var operations = new DocumentOperations(assembly, _mapping, _options); assembly.Namespaces.Add(typeof(CommandExtensions).Namespace); assembly.Namespaces.Add(typeof(Weasel.Core.CommandExtensions).Namespace); assembly.Namespaces.Add(typeof(TenantIdArgument).Namespace); assembly.Namespaces.Add(typeof(NpgsqlCommand).Namespace); var queryOnly = new DocumentStorageBuilder(_mapping, StorageStyle.QueryOnly, x => x.QueryOnlySelector) .Build(assembly, operations); var lightweight = new DocumentStorageBuilder(_mapping, StorageStyle.Lightweight, x => x.LightweightSelector) .Build(assembly, operations); var identityMap = new DocumentStorageBuilder(_mapping, StorageStyle.IdentityMap, x => x.IdentityMapSelector) .Build(assembly, operations); var dirtyTracking = new DocumentStorageBuilder(_mapping, StorageStyle.DirtyTracking, x => x.DirtyCheckingSelector) .Build(assembly, operations); var bulkWriterType = new BulkLoaderBuilder(_mapping).BuildType(assembly); var compiler = new AssemblyGenerator(); var types = new[] { typeof(IDocumentStorage <>), typeof(T), }; foreach (var referencedAssembly in WalkReferencedAssemblies.ForTypes(types)) { compiler.ReferenceAssembly(referencedAssembly); } var providerType = assembly.AddType(ProviderName, typeof(DocumentProvider <>).MakeGenericType(_mapping.DocumentType)); providerType.AllInjectedFields.Clear(); providerType.AllInjectedFields.Add(new InjectedField(typeof(DocumentMapping), "mapping")); var bulkWriterArgType = typeof(IBulkLoader <>).MakeGenericType(_mapping.DocumentType); var bulkWriterArgs = $"new {queryOnly.TypeName}(mapping)"; if (bulkWriterType.AllInjectedFields.Count == 2) { bulkWriterArgs += ", mapping"; } var bulkWriterCode = $"new {bulkWriterType.TypeName}({bulkWriterArgs})"; providerType.BaseConstructorArguments[0] = new Variable(bulkWriterArgType, bulkWriterCode); providerType.BaseConstructorArguments[1] = new CreateFromDocumentMapping(_mapping, typeof(IDocumentStorage <>), queryOnly); providerType.BaseConstructorArguments[2] = new CreateFromDocumentMapping(_mapping, typeof(IDocumentStorage <>), lightweight); providerType.BaseConstructorArguments[3] = new CreateFromDocumentMapping(_mapping, typeof(IDocumentStorage <>), identityMap); providerType.BaseConstructorArguments[4] = new CreateFromDocumentMapping(_mapping, typeof(IDocumentStorage <>), dirtyTracking); try { compiler.Compile(assembly); } catch (Exception e) { if (e.Message.Contains("is inaccessible due to its protection level")) { throw new InvalidOperationException($"Requested document type '{_mapping.DocumentType.FullNameInCode()}' must be either scoped as 'public' or the assembly holding it must use the {nameof(InternalsVisibleToAttribute)} pointing to 'Marten.Generated'", e); } throw; } return((DocumentProvider <T>)Activator.CreateInstance(providerType.CompiledType, _mapping)); }
/// <summary> /// Adds a pre-generated assembly. /// </summary> /// <param name="targetAssemblyName"> /// The name of the assembly the provided <paramref name="generatedAssembly"/> targets. /// </param> /// <param name="generatedAssembly"> /// The generated assembly. /// </param> public void AddGeneratedAssembly(string targetAssemblyName, GeneratedAssembly generatedAssembly) { CompiledAssemblies.TryAdd(targetAssemblyName, new CachedAssembly(generatedAssembly)); }
/// <summary> /// Initializes a new instance of the <see cref="GeneratedAssembly"/> class. /// </summary> /// <param name="other">The other instance.</param> public GeneratedAssembly(GeneratedAssembly other) { this.RawBytes = other.RawBytes; this.DebugSymbolRawBytes = other.DebugSymbolRawBytes; }
/// <summary> /// Given the specified <see cref="BlueprintApiOptions" /> will generate and compile an /// <see cref="IApiOperationExecutor" /> that can be used to execute any operation that /// has been identified by the model of the options passed. /// </summary> /// <param name="options"></param> /// <param name="serviceProvider"></param> /// <returns></returns> public CodeGennedExecutor Build(BlueprintApiOptions options, IServiceProvider serviceProvider) { var model = options.Model; // We have multiple ways in which we work with generated assemblies, depending on context: // // - We are writing unit tests which create many pipelines (within Blueprint itself). Here we // would want to use in-memory compilation and assembly loading only // // - We have deployed an app using generated code. We want to use pre-compiled DLLs loaded as // part of the usual loading process. This is done by creating an assembly and PDB that is // deployed with the application and loaded below (see step 1) // // - We are in development. Here we wish to generate and load a new DLL on application startup and // store in the temp folder of the machine. This means the DLL is _not_ loaded as normal part // of .NET process and therefore we can (re)create at will on startup without worrying about // the existence of an existing DLL // 1. Try and find an already loaded assembly foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { if (assembly.GetName().Name == options.GenerationRules.AssemblyName) { // The assembly exists in the current domain, therefore it has either already been generated in this // process OR it has previously been compiled and loaded as part of normal assembly loading (pre-compiled // as part of dotnet publish) this._logger.LogInformation("Assembly {AssemblyName} already exists, using to create executor.", options.GenerationRules.AssemblyName); return(CreateFromAssembly(options, serviceProvider, model, assembly)); } } // 2. Do we have the DLL stored alongside this application but NOT loaded? var directory = Path.GetDirectoryName(typeof(ApiOperationExecutorBuilder).Assembly.Location); var assemblyPath = Path.Combine(directory, options.GenerationRules.AssemblyName) + ".dll"; if (File.Exists(assemblyPath)) { this._logger.LogInformation( "Assembly {AssemblyName} found at {AssemblyLocation}. Loading and using to create executor.", options.GenerationRules.AssemblyName, assemblyPath); var loadedPipelineDll = AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath); return(CreateFromAssembly(options, serviceProvider, model, loadedPipelineDll)); } // 2. We DO NOT have any existing DLLs. In that case we are going to generate the source code using our configured // middlewares and then hand off to AssemblyGenerator to compile and load the assembly (which may be in-memory, stored // to a temp folder or stored to the project output folder) this._logger.LogInformation("Building Blueprint API operation executor for {0} operations", options.Model.Operations.Count()); using (var serviceScope = serviceProvider.CreateScope()) { foreach (var middleware in options.MiddlewareBuilders) { this.Use(middleware); } var typeToCreationMappings = new Dictionary <Type, Func <Type> >(); // Start the definition for a new generated assembly var assembly = new GeneratedAssembly(options.GenerationRules); foreach (var operation in model.Operations) { this._references.Add(operation.OperationType.Assembly); } foreach (var a in this._references) { this._logger.LogDebug("Referencing assembly {0}", a.FullName); assembly.ReferenceAssembly(a); } foreach (var operation in model.Operations) { this._logger.LogDebug("Generating executor for {0}", operation.OperationType.FullName); var typeName = NormaliseTypeName(operation); var pipelineExecutorType = assembly.AddType( operation.OperationType.Namespace, typeName, typeof(IOperationExecutorPipeline)); // We need to set up a LoggerVariable once, to be shared between methods pipelineExecutorType.AllInjectedFields.Add(new LoggerVariable(typeName)); var executeMethod = pipelineExecutorType.MethodFor(nameof(IOperationExecutorPipeline.ExecuteAsync)); var executeNestedMethod = pipelineExecutorType.MethodFor(nameof(IOperationExecutorPipeline.ExecuteNestedAsync)); this.Generate(options, serviceProvider, executeMethod, operation, model, serviceScope, false); this.Generate(options, serviceProvider, executeNestedMethod, operation, model, serviceScope, true); typeToCreationMappings.Add( operation.OperationType, () => pipelineExecutorType.CompiledType); } this._logger.LogInformation("Compiling {0} pipeline executors", typeToCreationMappings.Count); assembly.CompileAll(serviceProvider.GetRequiredService <IAssemblyGenerator>()); this._logger.LogInformation("Done compiling {0} pipeline executors", typeToCreationMappings.Count); return(new CodeGennedExecutor( serviceProvider, model, assembly, typeToCreationMappings)); } }
public DocumentProvider <T> Generate <T>() { var assembly = new GeneratedAssembly(new GenerationRules(SchemaConstants.MartenGeneratedNamespace)); var operations = new DocumentOperations(assembly, _mapping, _options); assembly.Namespaces.Add(typeof(CommandExtensions).Namespace); assembly.Namespaces.Add(typeof(TenantIdArgument).Namespace); assembly.Namespaces.Add(typeof(NpgsqlCommand).Namespace); var queryOnly = new DocumentStorageBuilder(_mapping, StorageStyle.QueryOnly, x => x.QueryOnlySelector) .Build(assembly, operations); var lightweight = new DocumentStorageBuilder(_mapping, StorageStyle.Lightweight, x => x.LightweightSelector) .Build(assembly, operations); var identityMap = new DocumentStorageBuilder(_mapping, StorageStyle.IdentityMap, x => x.IdentityMapSelector) .Build(assembly, operations); var dirtyTracking = new DocumentStorageBuilder(_mapping, StorageStyle.DirtyTracking, x => x.DirtyCheckingSelector) .Build(assembly, operations); var bulkWriterType = new BulkLoaderBuilder(_mapping).BuildType(assembly); var compiler = new AssemblyGenerator(); compiler.ReferenceAssembly(typeof(IDocumentStorage <>).Assembly); compiler.ReferenceAssembly(typeof(T).Assembly); try { compiler.Compile(assembly); } catch (Exception e) { if (e.Message.Contains("is inaccessible due to its protection level")) { throw new InvalidOperationException($"Requested document type '{_mapping.DocumentType.FullNameInCode()}' must be either scoped as 'public' or the assembly holding it must use the {nameof(InternalsVisibleToAttribute)} pointing to 'Marten.Generated'", e); } throw; } var slot = new DocumentProvider <T> { QueryOnly = (IDocumentStorage <T>)Activator.CreateInstance(queryOnly.CompiledType, _mapping), Lightweight = (IDocumentStorage <T>)Activator.CreateInstance(lightweight.CompiledType, _mapping), IdentityMap = (IDocumentStorage <T>)Activator.CreateInstance(identityMap.CompiledType, _mapping), DirtyTracking = (IDocumentStorage <T>)Activator.CreateInstance(dirtyTracking.CompiledType, _mapping), Operations = operations, QueryOnlyType = queryOnly, LightweightType = lightweight, IdentityMapType = identityMap, DirtyTrackingType = dirtyTracking }; slot.BulkLoader = _mapping.IsHierarchy() ? (IBulkLoader <T>)Activator.CreateInstance(bulkWriterType.CompiledType, slot.QueryOnly, _mapping) : (IBulkLoader <T>)Activator.CreateInstance(bulkWriterType.CompiledType, slot.QueryOnly); slot.BulkLoaderType = bulkWriterType; return(slot); }
/// <summary>Adds a cached assembly to the code generator.</summary> /// <param name="targetAssemblyName">The assembly which the cached assembly was generated for.</param> /// <param name="cachedAssembly">The generated assembly.</param> public void AddCachedAssembly(string targetAssemblyName, GeneratedAssembly cachedAssembly) { CodeGeneratorManager.AddGeneratedAssembly(targetAssemblyName, cachedAssembly, NullLogger.Instance); }
public string GenerateCodeWithInlineServices(GeneratedAssembly assembly) { return(assembly.GenerateCode(new ServiceVariableSource(ServiceGraph))); }
public CachedAssembly(GeneratedAssembly generated) : base(generated) { }
/// <summary> /// Generates and loads code for the specified inputs. /// </summary> /// <param name="inputs">The assemblies to generate code for.</param> public void GenerateAndLoadForAssemblies(params Assembly[] inputs) { if (inputs == null) { throw new ArgumentNullException(nameof(inputs)); } var timer = Stopwatch.StartNew(); foreach (var input in inputs) { RegisterGeneratedCodeTargets(input); TryLoadGeneratedAssemblyFromCache(input); } var grainAssemblies = inputs.Where(ShouldGenerateCodeForAssembly).ToList(); if (grainAssemblies.Count == 0) { // Already up to date. return; } try { // Generate code for newly loaded assemblies. var generatedSyntax = GenerateForAssemblies(grainAssemblies, true); var compiled = default(byte[]); if (generatedSyntax.Syntax != null) { compiled = CompileAndLoad(generatedSyntax); } foreach (var assembly in generatedSyntax.SourceAssemblies) { var generatedAssembly = new GeneratedAssembly { Loaded = true, RawBytes = compiled }; CompiledAssemblies.AddOrUpdate( assembly.GetName().FullName, generatedAssembly, (_, __) => generatedAssembly); } if (Logger.IsVerbose2) { Logger.Verbose2( ErrorCode.CodeGenCompilationSucceeded, "Generated code for {0} assemblies in {1}ms", generatedSyntax.SourceAssemblies.Count, timer.ElapsedMilliseconds); } } catch (Exception exception) { var assemblyNames = string.Join("\n", grainAssemblies.Select(_ => _.GetName().FullName)); var message = $"Exception generating code for input assemblies:\n{assemblyNames}\nException: {LogFormatter.PrintException(exception)}"; Logger.Warn(ErrorCode.CodeGenCompilationFailed, message, exception); throw; } }
void ICodeFile.AssembleTypes(GeneratedAssembly assembly) { EventDocumentStorageGenerator.AssembleTypes(Options, assembly); }