public async Task ExecuteAsync() { if (!ParseBuildRequest()) { return; } AssignRequestOperation(); if (_requestContext.Failed) { return; } // signal to prepare/deserialize variables; in http/web scenario, we cannot parse variables immediately - // we do not know variable types yet. Now that we have parsed and prepared query, we have var types; // we fire this event, parent GraphQLHttpServer will handle it and deserializer variables. _server.Events.OnRequestPrepared(_requestContext); BuildOperationVariables(); if (_requestContext.Failed) { return; } BuildDirectiveContexts(); var opMapping = _requestContext.Operation.OperationTypeDef.Mappings[0]; var topScope = new OutputObjectScope(new RequestPath(), null, opMapping); _requestContext.Response.Data = topScope; await ExecuteOperationAsync(_requestContext.Operation, topScope); }
private async Task ExecuteOperationAsync(GraphQLOperation op, OutputObjectScope topScope) { var mappedTopSubset = op.SelectionSubset.MappedSubSets[0]; var topMappedItems = mappedTopSubset.MappedItems; var parallel = _parallelQueryEnabled && op.OperationType == OperationType.Query && op.SelectionSubset.Items.Count > 1; var executers = new List <OperationFieldExecuter>(); foreach (var mappedItem in topMappedItems) { switch (mappedItem) { case MappedFragmentSpread mfs: _requestContext.AddInputError($"Top selection items may not be fragments", mfs.Spread); return; case MappedSelectionField mappedField: var opExecuter = new OperationFieldExecuter(_requestContext, mappedField, topScope); executers.Add(opExecuter); break; } } if (parallel) { await ExecuteAllParallel(executers); } else { await ExecuteAllNonParallel(executers); } // Save results from op fields into top scope; we do it here, after all threads finished, to avoid concurrency issues // and preserve output field order foreach (var ex in executers) { topScope.SetValue(ex.ResultKey, ex.Result); } }