// 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. var 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 !, _queryPlan, _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, 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); } catch { // if there is an error we will just dispose our instrumentation scope // the error is reported in the request level in this case. _subscriptionScope?.Dispose(); _subscriptionScope = null; throw; } finally { operationContext.Result.DropResult(); _operationContextPool.Return(operationContext); } }
public static bool TryComplete( IOperationContext operationContext, MiddlewareContext resolverContext, ISelection selection, Path path, IType fieldType, string responseName, int responseIndex, object?result, List <ResolverTask> bufferedTasks, out object?completedResult) { TypeKind typeKind = fieldType.Kind; if (typeKind is TypeKind.NonNull) { return(TryComplete( operationContext, resolverContext, selection, path, fieldType.InnerType(), responseName, responseIndex, result, bufferedTasks, out completedResult) && completedResult is not null); } if (result is null) { completedResult = null; return(true); } if (typeKind is TypeKind.List) { return(TryCompleteListValue( operationContext, resolverContext, selection, path, fieldType, responseName, responseIndex, result, bufferedTasks, out completedResult)); } if (typeKind is TypeKind.Scalar or TypeKind.Enum) { return(TryCompleteLeafValue( operationContext, resolverContext, selection, path, fieldType, result, out completedResult)); } if (typeKind is TypeKind.Object or TypeKind.Interface or TypeKind.Union) { return(TryCompleteCompositeValue( operationContext, resolverContext, selection, path, fieldType, result, bufferedTasks, out completedResult)); } ReportError( operationContext, resolverContext, selection, UnexpectedValueCompletionError(selection.SyntaxNode, path)); completedResult = null; return(false); }