/// <summary> /// Processes the given <see cref="IGraphDirectiveRequest" /> against this instance /// performing the operation as defined by this entity and generating a response. /// </summary> /// <param name="context">The context containing the necessary data to resolve /// the directive and produce a result.</param> /// <param name="cancelToken">The cancel token monitoring the execution of a graph request.</param> /// <returns>Task<IGraphPipelineResponse>.</returns> public async Task Resolve(DirectiveResolutionContext context, CancellationToken cancelToken = default) { var action = _directiveTemplate.FindMethod(context.Request.LifeCycle); // if no action is found skip processing of this directive if (action == null) { return; } IGraphActionResult result; try { // create a scoped controller instance for this invocation var directive = context .ServiceProvider? .GetService(_directiveTemplate.ObjectType) as GraphDirective; if (directive == null) { result = new RouteNotFoundGraphActionResult( $"The directive '{_directiveTemplate.InternalFullName}' " + "was not found in the scoped service provider."); } else { // invoke the right action method and set a result. var task = directive.InvokeActionAsync(action, context); var returnedItem = await task.ConfigureAwait(false); result = this.EnsureGraphActionResult(returnedItem); } } catch (Exception ex) { // :( result = new InternalServerErrorGraphActionResult("Operation failed.", ex); } // resolve the final graph action output using the provided field context // in what ever manner is appropriate for the result itself await result.Complete(context); }
/// <summary> /// Called by the runtime to invoke the middleware logic. In most cases, the middleware component should return the task /// generated by calling the next delegate in the request chain with the provided context. /// </summary> /// <param name="context">The invocation request governing data in this pipeline run.</param> /// <param name="next">The next delegate in the chain to be invoked.</param> /// <param name="cancelToken">The cancel token.</param> /// <returns>Task.</returns> public async Task InvokeAsync(GraphFieldExecutionContext context, GraphMiddlewareInvocationDelegate <GraphFieldExecutionContext> next, CancellationToken cancelToken) { IEnumerable <IDirectiveInvocationContext> directives = context.Request.InvocationContext.Directives ?? Enumerable.Empty <IDirectiveInvocationContext>(); if (context.IsValid) { // generate requests contexts for each directive to be processed bool cancelPipeline = false; foreach (var directive in directives) { var directiveArguments = directive.Arguments.Merge(context.VariableData); var request = new GraphDirectiveRequest( directive.Directive, directive.Location, directive.Origin, context.Request.Items); var beforeResolutionRequest = request.ForLifeCycle( DirectiveLifeCycle.BeforeResolution, context.Request.DataSource); var directiveContext = new DirectiveResolutionContext(context, beforeResolutionRequest, directiveArguments); await this.ExecuteDirective(directiveContext, cancelToken).ConfigureAwait(false); context.Messages.AddRange(directiveContext.Messages); cancelPipeline = cancelPipeline || directiveContext.IsCancelled; } if (cancelPipeline) { this.CancelPipeline(context); } } // --------------------------------- // continue the pipeline // --------------------------------- await next(context, cancelToken).ConfigureAwait(false); // --------------------------------- // execute after completion directives // --------------------------------- if (context.IsValid) { bool cancelPipeline = false; foreach (var directive in directives) { var directiveArguments = directive.Arguments.Merge(context.VariableData); var request = new GraphDirectiveRequest( directive.Directive, directive.Location, directive.Origin, context.Request.Items); var afterResolutionRequest = request.ForLifeCycle( DirectiveLifeCycle.AfterResolution, context.Request.DataSource); var directiveContext = new DirectiveResolutionContext(context, afterResolutionRequest, directiveArguments); await this.ExecuteDirective(directiveContext, cancelToken).ConfigureAwait(false); context.Messages.AddRange(directiveContext.Messages); cancelPipeline = cancelPipeline || directiveContext.IsCancelled; } if (cancelPipeline) { this.CancelPipeline(context); } } }
/// <summary> /// Executes the directive context allowing hte resolver to process the request and response dictated by their operations. /// </summary> /// <param name="context">The context.</param> /// <param name="cancelToken">The cancel token.</param> /// <returns>An instruction on how to proceed after.</returns> private Task ExecuteDirective( DirectiveResolutionContext context, CancellationToken cancelToken) { return(context.Request.Directive.Resolver.Resolve(context, cancelToken)); }