internal CodeGennedExecutor(
            IServiceProvider serviceProvider,
            ApiDataModel dataModel,
            GeneratedAssembly assembly,
            Dictionary <Type, Func <Type> > operationTypeToPipelineType)
        {
            this.DataModel = dataModel;

            this._serviceProvider             = serviceProvider;
            this._operationTypeToPipelineType = operationTypeToPipelineType;

            if (assembly != null)
            {
                // We only need to store the source code for each type. We need to discard the GeneratedAssembly otherwise
                // it holds on to a lot of memory
                this._sourceCodeMappings = new Dictionary <Type, string>();

                foreach (var t in assembly.GeneratedTypes)
                {
                    this._sourceCodeMappings[t.CompiledType] = t.SourceCode;
                }
            }
        }
Exemple #2
0
        private void Generate(
            BlueprintApiOptions options,
            IServiceProvider serviceProvider,
            GeneratedMethod executeMethod,
            ApiOperationDescriptor operation,
            ApiDataModel model,
            IServiceScope serviceScope,
            bool isNested)
        {
            var operationContextVariable = executeMethod.Arguments[0];

            var instanceFrameProvider             = serviceProvider.GetRequiredService <InstanceFrameProvider>();
            var dependencyInjectionVariableSource = new DependencyInjectionVariableSource(executeMethod, instanceFrameProvider);

            var castFrame = new ConcreteOperationCastFrame(operationContextVariable, operation.OperationType);

            var apiOperationContextSource =
                new ApiOperationContextVariableSource(operationContextVariable, castFrame.CastOperationVariable);

            var context = new MiddlewareBuilderContext(
                executeMethod,
                operation,
                model,
                serviceScope.ServiceProvider,
                instanceFrameProvider,
                isNested);

            // For the base Exception type we will add, as the first step, logging to the exception sinks. This frame DOES NOT
            // include a return frame, as we add that after all the other middleware builders have had chance to potentially add
            // more frames to perform other operations on unknown Exception
            context.RegisterUnhandledExceptionHandler(typeof(Exception), e => new Frame[]
            {
                // Exceptions do not escape from a pipeline because we always convert to a result type
                new PushExceptionToActivityFrame(e, false),
            });

            executeMethod.Sources.Add(apiOperationContextSource);
            executeMethod.Sources.Add(dependencyInjectionVariableSource);

            foreach (var source in options.GenerationRules.VariableSources)
            {
                executeMethod.Sources.Add(source);
            }

            var startActivityFrame = ActivityFrame.Start(ActivityKind.Internal, operation.Name + (isNested ? "NestedPipeline" : "Pipeline"));

            executeMethod.Frames.Add(startActivityFrame);

            executeMethod.Frames.Add(castFrame);
            executeMethod.Frames.Add(new ErrorHandlerFrame(context));
            executeMethod.Frames.Add(new BlankLineFrame());

            foreach (var behaviour in this._builders)
            {
                if (isNested && !behaviour.SupportsNestedExecution)
                {
                    continue;
                }

                if (behaviour.Matches(operation))
                {
                    executeMethod.Frames.Add(new CommentFrame(behaviour.GetType().Name));

                    behaviour.Build(context);

                    executeMethod.Frames.Add(new BlankLineFrame());
                }
            }

            // For the base Exception type we will add, as a last frame, a return of an OperationResult.
            context.RegisterUnhandledExceptionHandler(typeof(Exception), e => new[]
            {
                new ReturnFrame(new Variable(typeof(UnhandledExceptionOperationResult), $"new {typeof(UnhandledExceptionOperationResult).FullNameInCode()}({e})")),
            });
        }
Exemple #3
0
        private static CodeGennedExecutor CreateFromAssembly(BlueprintApiOptions options, IServiceProvider serviceProvider, ApiDataModel model, Assembly assembly)
        {
            var typeToCreationMappings = new Dictionary <Type, Func <Type> >();
            var exportedTypes          = assembly.GetExportedTypes();

            foreach (var operation in options.Model.Operations)
            {
                var typeName = NormaliseTypeName(operation);

                var operationType = exportedTypes.SingleOrDefault(
                    t => t.Namespace == operation.OperationType.Namespace && t.Name == typeName);

                if (operationType == null)
                {
                    var assemblyLocation = assembly.IsDynamic ? "in-memory" : $"at {assembly.Location}";

                    throw new InvalidOperationException(
                              @$ "An existing assembly '{options.GenerationRules.AssemblyName}' (found {assemblyLocation}), but is not valid for this builder because it is missing some pipelines. This can happen because:

 * A prebuilt assembly created in a previous run has been placed in to a folder that .NET has automatically loaded in to this AppDomain. Ensure that if you are including an assembly built by Blueprint that is the correct version for the set of operations and configuration. Delete the file if it is out of date.

 * A prebuilt assembly created in a previous run has been placed beside the running application and Blueprint automatically loaded it. Ensure that if you are including an assembly built by Blueprint that is the correct version for the set of operations and configuration. Delete the file if it is out of date.

 * More than one in-memory DLL pipeline (UseInMemoryCompileStrategy) is being created with separate options and operations but the same application and / or assembly name. Ensure that when configuring Blueprint you either call SetApplicationName(...), or Compilation(c => c.AssemblyName(...)) with a unique name.");
                }

                typeToCreationMappings.Add(operation.OperationType, () => operationType);
            }

            return(new CodeGennedExecutor(
                       serviceProvider,
                       model,
                       null,
                       typeToCreationMappings));
        }