/// <summary> /// Invokes this middleware component allowing it to perform its work against the supplied context. /// </summary> /// <param name="context">The context containing the request passed through the pipeline.</param> /// <param name="next">The delegate pointing to the next piece of middleware to be invoked.</param> /// <param name="cancelToken">The cancel token.</param> /// <returns>Task.</returns> public Task InvokeAsync(GraphQueryExecutionContext context, GraphMiddlewareInvocationDelegate <GraphQueryExecutionContext> next, CancellationToken cancelToken) { if (context.QueryPlan == null) { context.Metrics?.StartPhase(ApolloExecutionPhase.PARSING); try { context.SyntaxTree = _parser.ParseQueryDocument(context.Request.QueryText?.AsMemory() ?? ReadOnlyMemory <char> .Empty); } catch (GraphQLSyntaxException syntaxException) { // expose syntax exception messages to the client // the parser is self contained and ensures its exception messages are // related to the text being parsed context.Messages.Critical( syntaxException.Message, Constants.ErrorCodes.SYNTAX_ERROR, syntaxException.Location.AsOrigin()); } finally { context.Metrics?.EndPhase(ApolloExecutionPhase.PARSING); } } return(next(context, cancelToken)); }
/// <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 context 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(GraphQueryExecutionContext context, GraphMiddlewareInvocationDelegate <GraphQueryExecutionContext> next, CancellationToken cancelToken) { context?.Metrics?.Start(); await next(context, cancelToken).ConfigureAwait(false); context?.Metrics?.End(); }
public async Task InvokeAsync(GraphFieldExecutionContext context, GraphMiddlewareInvocationDelegate <GraphFieldExecutionContext> next, CancellationToken cancelToken) { _testService.BeforeNext(nameof(TestMiddleware2)); await next(context, cancelToken); _testService.AfterNext(nameof(TestMiddleware2)); }
public async Task NoItemsOnContext_YieldsNothingPublished() { var nextCalled = false; Task CallNext(GraphQueryExecutionContext context, CancellationToken token) { nextCalled = true; return(Task.CompletedTask); } var next = new GraphMiddlewareInvocationDelegate <GraphQueryExecutionContext>(CallNext); var queue = new SubscriptionEventQueue(); var publisher = new PublishRaisedSubscriptionEventsMiddleware <GraphSchema>(queue); var server = new TestServerBuilder() .Build(); var context = server.CreateQueryContextBuilder() .Build(); await publisher.InvokeAsync(context, next, default); Assert.IsTrue(nextCalled); Assert.AreEqual(0, queue.Count); }
public async Task EmptyCollectionOnContext_YieldsNothingPublished() { var nextCalled = false; Task CallNext(GraphQueryExecutionContext context, CancellationToken token) { nextCalled = true; return(Task.CompletedTask); } var next = new GraphMiddlewareInvocationDelegate <GraphQueryExecutionContext>(CallNext); var queue = new SubscriptionEventQueue(); var publisher = new PublishRaisedSubscriptionEventsMiddleware <GraphSchema>(queue); var server = new TestServerBuilder() .Build(); var context = server.CreateQueryContextBuilder() .Build(); var col = context.Items.GetOrAdd( SubscriptionConstants.RAISED_EVENTS_COLLECTION_KEY, (_) => new List <SubscriptionEventProxy>()); await publisher.InvokeAsync(context, next, default); Assert.IsTrue(nextCalled); Assert.AreEqual(0, queue.Count); }
/// <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) { FieldAuthorizationResult result = FieldAuthorizationResult.Default(); if (context.IsValid) { // execute the authorization pipeline var authRequest = new GraphFieldAuthorizationRequest(context.Request); var authContext = new GraphFieldAuthorizationContext(context, authRequest); await _authPipeline.InvokeAsync(authContext, cancelToken).ConfigureAwait(false); result = authContext.Result ?? FieldAuthorizationResult.Default(); // by default, deny any stati not explicitly declared as "successful" by this component. if (!result.Status.IsAuthorized()) { context.Messages.Critical( $"Access Denied to field {context.Field.Route.Path}", Constants.ErrorCodes.ACCESS_DENIED, context.Request.Origin); } } if (!result.Status.IsAuthorized()) { context.ResolvedSourceItems.AddRange(context.Request.DataSource.Items); context.ResolvedSourceItems.ForEach(x => x.Fail()); } await next(context, cancelToken).ConfigureAwait(false); }
public void CollectionKeyIsNotACollection_ThrowsException() { Task CallNext(GraphQueryExecutionContext context, CancellationToken token) { return(Task.CompletedTask); } var next = new GraphMiddlewareInvocationDelegate <GraphQueryExecutionContext>(CallNext); var queue = new SubscriptionEventQueue(); var publisher = new PublishRaisedSubscriptionEventsMiddleware <GraphSchema>(queue); var server = new TestServerBuilder() .Build(); var context = server.CreateQueryContextBuilder() .Build(); var col = context.Items.GetOrAdd( SubscriptionConstants.RAISED_EVENTS_COLLECTION_KEY, (_) => new object()); Assert.ThrowsAsync <GraphExecutionException>(async() => { await publisher.InvokeAsync(context, next, default); }); }
/// <summary> /// Invoke the action item as an asyncronous operation. /// </summary> /// <param name="context">The context.</param> /// <param name="next">The next.</param> /// <param name="cancelToken">The cancel token.</param> /// <returns>Task.</returns> public async Task InvokeAsync(GraphFieldExecutionContext context, GraphMiddlewareInvocationDelegate <GraphFieldExecutionContext> next, CancellationToken cancelToken = default) { // create a set of validation contexts for every incoming source graph item // to capture and validate every item regardless of it being successfully resolved or failed var validationContexts = context.Request.DataSource.Items.Select( x => new FieldValidationContext(_schema, x, context.Messages)); // begin profiling of this single field of data context.Metrics?.BeginFieldResolution(context); bool fieldShouldBeCanceled = false; if (context.IsValid) { // build a collection of invokable parameters from the supplied context var executionArguments = context .InvocationContext .Arguments .Merge(context.VariableData) .WithSourceData(context.Request.DataSource.Value); // resolve the field var resolutionContext = new FieldResolutionContext(context, context.Request, executionArguments); context.Logger?.FieldResolutionStarted(resolutionContext); var task = context.Field?.Resolver?.Resolve(resolutionContext, cancelToken); await task.ConfigureAwait(false); context.Messages.AddRange(resolutionContext.Messages); this.AssignResults(context, resolutionContext); fieldShouldBeCanceled = resolutionContext.IsCancelled; context.Logger?.FieldResolutionCompleted(resolutionContext); } if (fieldShouldBeCanceled) { context.Cancel(); context.Request.DataSource.Items.ForEach(x => x.Cancel()); } // validate the resolution of the field in whatever manner that means for its current state var completionProcessor = new FieldCompletionRuleProcessor(); completionProcessor.Execute(validationContexts); // end profiling of this single field of data context.Metrics?.EndFieldResolution(context); await next(context, cancelToken).ConfigureAwait(false); // validate the final result after all downstream middleware execute // in the standard pipeline this generally means all child fields have resolved var validationProcessor = new FieldValidationRuleProcessor(); validationProcessor.Execute(validationContexts); }
/// <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="fieldRequest">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 Task InvokeAsync( GraphFieldExecutionContext fieldRequest, GraphMiddlewareInvocationDelegate <GraphFieldExecutionContext> next, CancellationToken cancelToken = default) { Counter++; return(next(fieldRequest, cancelToken)); }
public Task InvokeAsync(GraphFieldExecutionContext context, GraphMiddlewareInvocationDelegate <GraphFieldExecutionContext> next, CancellationToken cancelToken) { if (context.Field.Name.Contains("property1", System.StringComparison.OrdinalIgnoreCase)) { throw new GraphExecutionException("Forced Exception for testing"); } return(next(context, cancelToken)); }
/// <summary> /// Invokes this middleware component allowing it to perform its work against the supplied context. /// </summary> /// <param name="context">The context containing the request passed through the pipeline.</param> /// <param name="next">The delegate pointing to the next piece of middleware 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) { if (context.IsValid && context.Result != null && !context.IsCancelled) { await this.ProcessDownStreamFieldContexts(context, cancelToken).ConfigureAwait(false); } await next(context, cancelToken).ConfigureAwait(false); }
/// <summary> /// Invokes this middleware component allowing it to perform its work against the supplied context. /// </summary> /// <param name="context">The context containing the request passed through the pipeline.</param> /// <param name="next">The delegate pointing to the next piece of middleware to be invoked.</param> /// <param name="cancelToken">The cancel token.</param> /// <returns>Task.</returns> public Task InvokeAsync(GraphFieldExecutionContext context, GraphMiddlewareInvocationDelegate <GraphFieldExecutionContext> next, CancellationToken cancelToken) { // ensure that the data items on teh request match the field they are being executed against var field = context.Field; var expectedFieldGraphType = _schema.KnownTypes.FindGraphType(field); var dataSource = context.Request.DataSource; // ensure the source being supplied // matches the expected source of the field being resolved if (context.InvocationContext.ExpectedSourceType != null) { var expectedSourceType = context.InvocationContext.ExpectedSourceType; var actualSourceType = GraphValidation.EliminateWrappersFromCoreType(dataSource.Value.GetType()); if (expectedSourceType != actualSourceType) { var expectedSourceGraphType = _schema.KnownTypes.FindGraphType(expectedSourceType, TypeKind.OBJECT); var analysis = _schema.KnownTypes.AnalyzeRuntimeConcreteType(expectedSourceGraphType, actualSourceType); if (!analysis.ExactMatchFound) { throw new GraphExecutionException( $"Operation failed. The field execution context for '{field.Route.Path}' was passed " + $"a source item of type '{dataSource.Value.GetType().FriendlyName()}' which could not be coerced " + $"to '{context.InvocationContext.ExpectedSourceType}' as requested by the target graph type '{expectedFieldGraphType.Name}'."); } if (context.Field.Mode == FieldResolutionMode.Batch && !(dataSource.GetType() is IEnumerable)) { throw new GraphExecutionException( $"Operation failed. The field execution context for '{field.Route.Path}' was executed in batch mode " + $"but was not passed an {nameof(IEnumerable)} for its source data."); } } } if (dataSource.Items.Count == 0) { var expected = context.InvocationContext.Field.Mode == FieldResolutionMode.PerSourceItem ? "1" : "at least 1"; throw new GraphExecutionException( $"Operation failed. The field execution context for '{field.Route.Path}' was passed " + $"0 items but expected {expected}. (Field Mode: {field.Mode.ToString()})"); } if (context.InvocationContext.Field.Mode == FieldResolutionMode.PerSourceItem && dataSource.Items.Count != 1) { throw new GraphExecutionException( $"Operation failed. The field execution context for '{field.Route.Path}' was passed " + $"{dataSource.Items.Count} items to resolve but expected 1. (Field Mode: {field.Mode.ToString()})"); } return(next(context, cancelToken)); }
/// <summary> /// Invokes the asynchronous. /// </summary> /// <param name="context">The context.</param> /// <param name="next">The next.</param> /// <param name="cancelToken">The cancel token.</param> /// <returns>Task.</returns> public async Task InvokeAsync(GraphQueryExecutionContext context, GraphMiddlewareInvocationDelegate <GraphQueryExecutionContext> next, CancellationToken cancelToken) { context.Metrics?.StartPhase(ApolloExecutionPhase.EXECUTION); if (context.IsValid && context.QueryOperation != null) { await this.ExecuteOperation(context).ConfigureAwait(false); } await next(context, cancelToken).ConfigureAwait(false); context.Metrics?.EndPhase(ApolloExecutionPhase.EXECUTION); }
/// <summary> /// Initializes a new instance of the <see cref="GraphMiddlewareInvoker{TContext}" /> class. /// </summary> /// <param name="middlewareComponent">The middleware component.</param> /// <param name="next">The next.</param> public GraphMiddlewareInvoker( GraphMiddlewareDefinition <TContext> middlewareComponent, GraphMiddlewareInvocationDelegate <TContext> next = null) { this.ComponentDefinition = Validation.ThrowIfNullOrReturn(middlewareComponent, nameof(middlewareComponent)); _singletonInstance = this.ComponentDefinition.Component; this.Next = next; if (this.Next == null) { this.Next = (_, __) => Task.CompletedTask; } }
/// <summary> /// Invokes this middleware component allowing it to perform its work against the supplied context. /// </summary> /// <param name="context">The context containing the request passed through the pipeline.</param> /// <param name="next">The delegate pointing to the next piece of middleware to be invoked.</param> /// <param name="cancelToken">The cancel token.</param> /// <returns>Task.</returns> public async Task InvokeAsync(GraphFieldAuthorizationContext context, GraphMiddlewareInvocationDelegate <GraphFieldAuthorizationContext> next, CancellationToken cancelToken) { context.Logger?.FieldResolutionSecurityChallenge(context); var result = await this.AuthorizeRequest(context.Request, context.User).ConfigureAwait(false); context.Result = result ?? FieldAuthorizationResult.Default(); context.Logger?.FieldResolutionSecurityChallengeResult(context); await next(context, cancelToken).ConfigureAwait(false); }
/// <summary> /// Invokes this middleware component allowing it to perform its work against the supplied context. /// </summary> /// <param name="context">The context containing the request passed through the pipeline.</param> /// <param name="next">The delegate pointing to the next piece of middleware to be invoked.</param> /// <param name="cancelToken">The cancel token.</param> /// <returns>Task.</returns> public async Task InvokeAsync(GraphQueryExecutionContext context, GraphMiddlewareInvocationDelegate <GraphQueryExecutionContext> next, CancellationToken cancelToken) { if (context.IsValid && context.QueryOperation != null) { var anyFieldFailed = await this.AuthorizeOperation(context, cancelToken).ConfigureAwait(false); if (anyFieldFailed) { context.Cancel(); } } await next(context, cancelToken).ConfigureAwait(false); }
/// <summary> /// Invokes this middleware component allowing it to perform its work against the supplied context. /// </summary> /// <param name="context">The context containing the request passed through the pipeline.</param> /// <param name="next">The delegate pointing to the next piece of middleware to be invoked.</param> /// <param name="cancelToken">The cancel token.</param> /// <returns>Task.</returns> public Task InvokeAsync(GraphQueryExecutionContext context, GraphMiddlewareInvocationDelegate <GraphQueryExecutionContext> next, CancellationToken cancelToken) { // create and attach the result IResponseFieldSet fieldSet = null; if (context.FieldResults != null && context.FieldResults.Any()) { fieldSet = this.CreateFinalDictionary(context); } context.Result = new GraphOperationResult(context.Request, context.Messages, fieldSet, context.Metrics); context.Logger?.RequestCompleted(context); return(next(context, cancelToken)); }
/// <summary> /// Invokes this middleware component allowing it to perform its work against the supplied context. /// </summary> /// <param name="context">The context containing the request passed through the pipeline.</param> /// <param name="next">The delegate pointing to the next piece of middleware to be invoked.</param> /// <param name="cancelToken">The cancel token.</param> /// <returns>Task.</returns> public async Task InvokeAsync(GraphQueryExecutionContext context, GraphMiddlewareInvocationDelegate <GraphQueryExecutionContext> next, CancellationToken cancelToken) { bool planFound = false; string key = null; if (_keyManager != null && _cacheProvider != null && context.Request?.QueryText != null) { key = _keyManager.CreateKey <TSchema>(context.Request.QueryText); planFound = await _cacheProvider.TryGetPlanAsync(key, out var queryPlan).ConfigureAwait(false); if (planFound) { context.QueryPlan = queryPlan; context.Logger?.QueryPlanCacheFetchHit <TSchema>(key); } else { context.Logger?.QueryPlanCacheFetchMiss <TSchema>(key); } } // invoke the rest of the pipeline await next(context, cancelToken).ConfigureAwait(false); if (!planFound && !string.IsNullOrWhiteSpace(key) && context.QueryPlan != null && context.QueryPlan.IsValid) { // calculate the plan's time to live in the cache and cache it DateTimeOffset?absoluteExpiration = null; TimeSpan? slidingExpiration = null; if (_cacheOptions.TimeToLiveInMilliseconds.HasValue) { absoluteExpiration = DateTimeOffset.UtcNow.AddMilliseconds(_cacheOptions.TimeToLiveInMilliseconds.Value); } else if (_cacheOptions.SlidingExpiration.HasValue) { slidingExpiration = _cacheOptions.SlidingExpiration.Value; } var successful = await _cacheProvider.TryCachePlanAsync( key, context.QueryPlan, absoluteExpiration, slidingExpiration).ConfigureAwait(false); if (successful) { context.Logger?.QueryPlanCached(key, context.QueryPlan); } } }
/// <summary> /// Invokes this middleware component allowing it to perform its work against the supplied context. /// </summary> /// <param name="context">The context containing the request passed through the pipeline.</param> /// <param name="next">The delegate pointing to the next piece of middleware to be invoked.</param> /// <param name="cancelToken">The cancel token.</param> /// <returns>Task.</returns> public Task InvokeAsync(GraphQueryExecutionContext context, GraphMiddlewareInvocationDelegate <GraphQueryExecutionContext> next, CancellationToken cancelToken) { if (context.IsValid && context.QueryPlan != null && context.QueryPlan.IsValid) { context.QueryOperation = context.QueryPlan.RetrieveOperation(context.Request.OperationName); if (context.QueryOperation == null) { context.Messages.Critical( $"No operation found with the name '{context.Request.OperationName}'.", Constants.ErrorCodes.BAD_REQUEST); } } return(next(context, cancelToken)); }
/// <summary> /// Invokes this middleware component allowing it to perform its work against the supplied context. /// </summary> /// <param name="context">The context containing the request passed through the pipeline.</param> /// <param name="next">The delegate pointing to the next piece of middleware to be invoked.</param> /// <param name="cancelToken">The cancel token.</param> /// <returns>Task.</returns> public async Task InvokeAsync(GraphQueryExecutionContext context, GraphMiddlewareInvocationDelegate <GraphQueryExecutionContext> next, CancellationToken cancelToken) { if (context.IsValid && context.QueryPlan == null && context.SyntaxTree != null) { context.Metrics?.StartPhase(ApolloExecutionPhase.VALIDATION); context.QueryPlan = await _planGenerator.CreatePlan(context.SyntaxTree).ConfigureAwait(false); context.Messages.AddRange(context.QueryPlan.Messages); context.Metrics?.EndPhase(ApolloExecutionPhase.VALIDATION); if (context.QueryPlan.IsValid) { context.Logger?.QueryPlanGenerated(context.QueryPlan); } } await next(context, cancelToken).ConfigureAwait(false); }
/// <summary> /// Invokes this middleware component allowing it to perform its work against the supplied context. /// </summary> /// <param name="context">The context containing the request passed through the pipeline.</param> /// <param name="next">The delegate pointing to the next piece of middleware to be invoked.</param> /// <param name="cancelToken">The cancel token.</param> /// <returns>Task.</returns> public Task InvokeAsync(GraphQueryExecutionContext context, GraphMiddlewareInvocationDelegate <GraphQueryExecutionContext> next, CancellationToken cancelToken) { if (context is SubcriptionExecutionContext subContext && subContext.IsSubscriptionOperation && subContext.QueryPlan != null && subContext.QueryOperation != null) { subContext.Subscription = new ClientSubscription <TSchema>( subContext.Client, subContext.Request.ToDataPackage(), subContext.QueryPlan, subContext.QueryOperation, subContext.SubscriptionId); return(Task.CompletedTask); } return(next(context, cancelToken)); }
/// <summary> /// Invokes this middleware component allowing it to perform its work against the supplied context. /// </summary> /// <param name="context">The context containing the request passed through the pipeline.</param> /// <param name="next">The delegate pointing to the next piece of middleware to be invoked.</param> /// <param name="cancelToken">The cancel token.</param> /// <returns>Task.</returns> public Task InvokeAsync(GraphFieldExecutionContext context, GraphMiddlewareInvocationDelegate <GraphFieldExecutionContext> next, CancellationToken cancelToken) { // ensure that the data items on teh request match the field they are being executed against var field = context.Field; var dataSource = context.Request.DataSource; if (context.InvocationContext.ExpectedSourceType != null) { var expectedType = context.InvocationContext.ExpectedSourceType; if (context.Field.Mode == FieldResolutionMode.Batch) { expectedType = typeof(List <>).MakeGenericType(expectedType); } if (dataSource.Value.GetType() != expectedType) { throw new GraphExecutionException( $"Operation failed. The field execution context for '{field.Route.Path}' was passed " + $"a source item of type '{dataSource.Value.GetType().FriendlyName()}' but expected '{context.InvocationContext.ExpectedSourceType}'."); } } if (dataSource.Items.Count == 0) { var expected = context.InvocationContext.Field.Mode == FieldResolutionMode.PerSourceItem ? "1" : "at least 1"; throw new GraphExecutionException( $"Operation failed. The field execution context for '{field.Route.Path}' was passed " + $"0 items but expected {expected}. (Field Mode: {field.Mode.ToString()})"); } if (context.InvocationContext.Field.Mode == FieldResolutionMode.PerSourceItem && dataSource.Items.Count != 1) { throw new GraphExecutionException( $"Operation failed. The field execution context for '{field.Route.Path}' was passed " + $"{dataSource.Items.Count} items to resolve but expected 1. (Field Mode: {field.Mode.ToString()})"); } return(next(context, cancelToken)); }
/// <summary> /// Invokes this middleware component allowing it to perform its work against the supplied context. /// </summary> /// <param name="context">The context containing the request passed through the pipeline.</param> /// <param name="next">The delegate pointing to the next piece of middleware to be invoked.</param> /// <param name="cancelToken">The cancel token.</param> /// <returns>Task.</returns> public Task InvokeAsync( GraphQueryExecutionContext context, GraphMiddlewareInvocationDelegate <GraphQueryExecutionContext> next, CancellationToken cancelToken) { if (context?.Items != null && context.IsValid && !context.IsCancelled) { // if a context item for the subscription event key was added by one of the extension methods // inspect it to try and find the events that were registered if (context.Items.ContainsKey(SubscriptionConstants.RAISED_EVENTS_COLLECTION_KEY)) { var collection = context.Items[SubscriptionConstants.RAISED_EVENTS_COLLECTION_KEY] as IList <SubscriptionEventProxy>; if (collection == null) { throw new GraphExecutionException( $"Unable to cast the context item '{SubscriptionConstants.RAISED_EVENTS_COLLECTION_KEY}' into " + $"{typeof(IList<SubscriptionEventProxy>).FriendlyName()}. Published subscription events could not be raised.", SourceOrigin.None); } else { foreach (var proxy in collection) { var eventData = new SubscriptionEvent() { Id = Guid.NewGuid().ToString(), SchemaTypeName = SchemaExtensions.RetrieveFullyQualifiedSchemaTypeName(typeof(TSchema)), Data = proxy.DataObject, DataTypeName = SchemaExtensions.RetrieveFullyQualifiedDataObjectTypeName(proxy.DataObject?.GetType()), EventName = proxy.EventName?.Trim(), }; _eventQueue.Enqueue(eventData); } } } } return(next(context, cancelToken)); }
/// <summary> /// Invokes this middleware component allowing it to perform its work against the supplied context. /// </summary> /// <param name="context">The context containing the request passed through the pipeline.</param> /// <param name="next">The delegate pointing to the next piece of middleware to be invoked.</param> /// <param name="cancelToken">The cancel token.</param> /// <returns>Task.</returns> public Task InvokeAsync(GraphQueryExecutionContext context, GraphMiddlewareInvocationDelegate <GraphQueryExecutionContext> next, CancellationToken cancelToken) { if (context?.ServiceProvider == null) { throw new GraphExecutionException( "No context and/or service provider was supplied on which to process the request", SourceOrigin.None, new InvalidOperationException($"The {nameof(GraphQueryExecutionContext)} governing the execution of the pipeline was provided as null. Operation failed.")); } if (context.Request == null || string.IsNullOrWhiteSpace(context.Request.QueryText)) { // capture execution exceptions, they will relate to the internal processing // of the server and should only be exposed to authorized parties (via exception details) context.Messages.Critical("No query text was provided.", Constants.ErrorCodes.EXECUTION_ERROR); } else { context.Logger?.RequestReceived(context); } return(next(context, cancelToken)); }
/// <summary> /// Builds out the pipeline, in context of the schema, using the components added to this builder. /// </summary> /// <returns>IGraphPipeline<TContext>.</returns> public ISchemaPipeline <TSchema, TContext> Build() { GraphMiddlewareInvocationDelegate <TContext> leadInvoker = null; // walk backwards up the chained middleware, setting up the component creators and their call chain // maintain a list of component names for logging var node = _middleware.Last; var middlewareNameList = new List <string>(); while (node != null) { var invoker = new GraphMiddlewareInvoker <TContext>(node.Value, leadInvoker); if (!string.IsNullOrWhiteSpace(node.Value?.Name)) { middlewareNameList.Insert(0, node.Value.Name); } else if (node.Value.Component != null) { middlewareNameList.Insert(0, node.Value.Component.GetType().FriendlyName()); } else if (node.Value.MiddlewareType != null) { middlewareNameList.Insert(0, node.Value.MiddlewareType.FriendlyName()); } else { middlewareNameList.Insert(0, "-unknown-"); } node = node.Previous; leadInvoker = invoker.InvokeAsync; } return(new GraphSchemaPipeline <TSchema, TContext>(leadInvoker, this.PipelineName, middlewareNameList)); }
public Task InvokeAsync(GraphFieldExecutionContext context, GraphMiddlewareInvocationDelegate <GraphFieldExecutionContext> next, CancellationToken cancelToken) { return(Task.FromException(new TestMiddlewareException())); }
/// <summary> /// Initializes a new instance of the <see cref="GraphSchemaPipeline{TSchema, TContext}" /> class. /// </summary> /// <param name="leadInvoker">The lead invoker.</param> /// <param name="pipelineName">The friendly name of this pipeline.</param> /// <param name="nameList">The name list.</param> public GraphSchemaPipeline(GraphMiddlewareInvocationDelegate <TContext> leadInvoker, string pipelineName, IReadOnlyList <string> nameList) { this.InvokeAsync = Validation.ThrowIfNullOrReturn(leadInvoker, nameof(leadInvoker)); this.MiddlewareComponentNames = nameList ?? new List <string>(); this.Name = pipelineName; }
/// <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 <see cref="T:GraphQL.AspNet.Execution.Pipelining.GraphQLRequestDelegate" /> in the request chain with the provided context. /// </summary> /// <param name="context">The context tracking state for this pipeline invocation.</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 Task InvokeAsync(TContext context, GraphMiddlewareInvocationDelegate <TContext> next, CancellationToken cancelToken) { return(_invocationFunc(context, next, cancelToken)); }
/// <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); } } }
public Task InvokeAsync(GraphFieldExecutionContext context, GraphMiddlewareInvocationDelegate <GraphFieldExecutionContext> next, CancellationToken cancelToken) { _testService.BeforeNext(this.Id); return(next(context, cancelToken)); }