/// <summary>
            /// OnEvent is called whenever the event stream yields a payload and triggers an
            /// execution of the subscription query.
            /// </summary>
            /// <param name="payload">
            /// The event stream payload.
            /// </param>
            /// <returns>
            /// Returns a query result which will be enqueued to the response stream.
            /// </returns>
            private async Task <IQueryResult> OnEvent(object payload)
            {
                using IDisposable es             = _diagnosticEvents.OnSubscriptionEvent(new(this, payload));
                using IServiceScope serviceScope = _requestContext.Services.CreateScope();

                OperationContext operationContext = _operationContextPool.Get();

                try
                {
                    var eventServices = serviceScope.ServiceProvider;
                    var dispatcher    = eventServices.GetRequiredService <IBatchDispatcher>();

                    // we store the event payload on the scoped context so that it is accessible
                    // in the resolvers.
                    ImmutableDictionary <string, object?> scopedContext =
                        ImmutableDictionary <string, object?> .Empty
                        .SetItem(WellKnownContextData.EventMessage, payload);

                    // next we resolve the subscription instance.
                    var rootValue = RootValueResolver.Resolve(
                        _requestContext,
                        eventServices,
                        _subscriptionType,
                        ref _cachedRootValue);

                    // last we initialize a standard operation context to execute
                    // the subscription query with the standard query executor.
                    operationContext.Initialize(
                        _requestContext,
                        eventServices,
                        dispatcher,
                        _requestContext.Operation !,
                        _queryPlan,
                        _requestContext.Variables !,
                        rootValue,
                        _resolveQueryRootValue);

                    operationContext.Result.SetContextData(
                        WellKnownContextData.EventMessage,
                        payload);

                    IQueryResult result = await _queryExecutor
                                          .ExecuteAsync(operationContext, scopedContext)
                                          .ConfigureAwait(false);

                    _diagnosticEvents.SubscriptionEventResult(new(this, payload), result);

                    return(result);
                }
                catch (Exception ex)
                {
                    _diagnosticEvents.SubscriptionEventError(new(this, payload), ex);
                    throw;
                }
                finally
                {
                    _operationContextPool.Return(operationContext);
                }
            }
예제 #2
0
            private async Task <IQueryResult> OnEvent(object payload)
            {
                using IServiceScope serviceScope = _requestContext.Services.CreateScope();

                IServiceProvider eventServices = serviceScope.ServiceProvider;
                IBatchDispatcher dispatcher    = eventServices.GetRequiredService <IBatchDispatcher>();

                OperationContext operationContext = _operationContextPool.Get();

                try
                {
                    ImmutableDictionary <string, object?> scopedContext =
                        ImmutableDictionary <string, object?> .Empty
                        .SetItem(WellKnownContextData.EventMessage, payload);

                    object?rootValue = RootValueResolver.Resolve(
                        _requestContext,
                        eventServices,
                        _subscriptionType,
                        ref _cachedRootValue);

                    operationContext.Initialize(
                        _requestContext,
                        eventServices,
                        dispatcher,
                        _requestContext.Operation !,
                        _requestContext.Variables !,
                        rootValue,
                        _resolveQueryRootValue);

                    return(await _queryExecutor
                           .ExecuteAsync(operationContext, scopedContext)
                           .ConfigureAwait(false));
                }
                finally
                {
                    _operationContextPool.Return(operationContext);
                }
            }
예제 #3
0
            // subscribe will use the subscribe resolver to create a source stream that yields
            // the event messages from the underlying pub/sub-system.
            private async ValueTask <ISourceStream> SubscribeAsync()
            {
                OperationContext operationContext = _operationContextPool.Get();

                try
                {
                    // first we will create the root value which essentially
                    // is the subscription object. In some cases this object is null.
                    object?rootValue = RootValueResolver.Resolve(
                        _requestContext,
                        _requestContext.Services,
                        _subscriptionType,
                        ref _cachedRootValue);

                    // next we need to initialize our operation context so that we have access to
                    // variables services and other things.
                    // The subscribe resolver will use a noop dispatcher and all DataLoader are
                    // dispatched immediately.
                    operationContext.Initialize(
                        _requestContext,
                        _requestContext.Services,
                        NoopBatchDispatcher.Default,
                        _requestContext.Operation !,
                        _requestContext.Variables !,
                        rootValue,
                        _resolveQueryRootValue);

                    // next we need a result map so that we can store the subscribe temporarily
                    // while executing the subscribe pipeline.
                    ResultMap  resultMap     = operationContext.Result.RentResultMap(1);
                    ISelection rootSelection = _rootSelections.Selections[0];

                    // we create a temporary middleware context so that we can use the standard
                    // resolver pipeline.
                    var middlewareContext = new MiddlewareContext();
                    middlewareContext.Initialize(
                        operationContext,
                        rootSelection,
                        resultMap,
                        1,
                        rootValue,
                        Path.New(rootSelection.ResponseName),
                        ImmutableDictionary <string, object?> .Empty);

                    // it is important that we correctly coerce the arguments before
                    // invoking subscribe.
                    if (!rootSelection.Arguments.TryCoerceArguments(
                            middlewareContext.Variables,
                            middlewareContext.ReportError,
                            out IReadOnlyDictionary <NameString, ArgumentValue>?coercedArgs))
                    {
                        // the middleware context reports errors to the operation context,
                        // this means if we failed, we need to grab the coercion errors from there
                        // and just throw a GraphQLException.
                        throw new GraphQLException(operationContext.Result.Errors);
                    }

                    // if everything is fine with the arguments we still need to assign them.
                    middlewareContext.Arguments = coercedArgs;

                    // last but not least we can invoke the subscribe resolver which will subscribe
                    // to the underlying pub/sub-system yielding the source stream.
                    ISourceStream sourceStream =
                        await rootSelection.Field.SubscribeResolver !.Invoke(middlewareContext)
                        .ConfigureAwait(false);

                    if (operationContext.Result.Errors.Count > 0)
                    {
                        // again if we have any errors we will just throw them and not opening
                        // any subscription context.
                        throw new GraphQLException(operationContext.Result.Errors);
                    }

                    return(sourceStream);
                }
                finally
                {
                    operationContext.Result.DropResult();
                    _operationContextPool.Return(operationContext);
                }
            }