private static void BuildForSingleHandler(MiddlewareBuilderContext context) { // We only have a single handler, return the result of that var allHandlers = context.Descriptor.Handlers; var handler = allHandlers.Single(); var apmFrame = ActivityFrame.Start(ActivityKind.Internal, handler.HandlerType.NameInCode()); context.AppendFrames(apmFrame); var returnVariable = handler.Build(context, ExecutorReturnType.Return); if (returnVariable == null && context.Descriptor.RequiresReturnValue) { throw new InvalidOperationException( $@"Unable to build an executor for the operation {context.Descriptor} because the single handler registered, {handler}, did not return a variable but the operation has {nameof(context.Descriptor.RequiresReturnValue)} set to true. This can happen if an the only registered handler for an operation is one that is NOT of the same type (for example a handler IApiOperationHandler<ConcreteClass> for the operation IOperationInterface) where it cannot be guaranteed that the handler will be executed."); } if (returnVariable != null) { returnVariable.OverrideName("handlerResult"); context.AppendFrames(new OperationResultCastFrame(returnVariable)); } context.AppendFrames(apmFrame.Complete()); }
private static void BuildForMultipleHandlers(MiddlewareBuilderContext context) { if (context.Descriptor.RequiresReturnValue) { throw new InvalidOperationException( $@"Unable to build an executor for the operation {context.Descriptor} because multiple handlers have been registered but the operation has {nameof(context.Descriptor.RequiresReturnValue)} set to true. When {nameof(context.Descriptor.RequiresReturnValue)} is true multiple handlers cannot be used as there is not one, obvious, return value that could be used. Handlers found: - {string.Join("\n - ", context.Descriptor.Handlers)} "); } foreach (var handler in context.Descriptor.Handlers) { var apmFrame = ActivityFrame.Start(ActivityKind.Internal, handler.HandlerType.NameInCode()); context.AppendFrames(apmFrame); handler.Build(context, ExecutorReturnType.NoReturn); context.AppendFrames(apmFrame.Complete()); } }
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})")), }); }