Exemple #1
0
        /// <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));
        }
Exemple #2
0
        /// <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();
        }
Exemple #3
0
        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);
            });
        }
Exemple #8
0
        /// <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));
 }
Exemple #10
0
        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));
        }
Exemple #11
0
        /// <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));
        }
Exemple #13
0
        /// <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);
        }
Exemple #14
0
 /// <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;
     }
 }
Exemple #15
0
        /// <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);
        }
Exemple #16
0
        /// <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);
        }
Exemple #17
0
        /// <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);
                }
            }
        }
Exemple #19
0
        /// <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));
        }
Exemple #20
0
        /// <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);
        }
Exemple #21
0
        /// <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));
        }
Exemple #22
0
        /// <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));
        }
Exemple #25
0
        /// <summary>
        /// Builds out the pipeline, in context of the schema, using the components added to this builder.
        /// </summary>
        /// <returns>IGraphPipeline&lt;TContext&gt;.</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()));
 }
Exemple #27
0
 /// <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));
 }
Exemple #29
0
        /// <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));
 }