// merge with prev method InvokeResolverAsync
        private object InvokeResolverFunc(FieldContext fieldContext)
        {
            var propReader = fieldContext.MappedField.Resolver.ResolverFunc;
            var entity     = fieldContext.CurrentParentScope.Entity;
            var result     = propReader(entity);

            return(result);
        }
        internal static void ThrowRequestCancelled(this FieldContext fieldContext)
        {
            var reqCtx = (RequestContext)fieldContext.RequestContext;
            var err    = new GraphQLError($"Request cancelled",
                                          fieldContext.GetFullRequestPath(), fieldContext.SelectionField.SourceLocation, type: "Cancel");

            reqCtx.AddError(err);
            throw new AbortRequestException();
        }
        internal static void ThrowObjectCountExceededQuota(this FieldContext fieldContext)
        {
            var reqCtx = (RequestContext)fieldContext.RequestContext;
            var quota  = reqCtx.Quota;
            var err    = new GraphQLError($"Output object count exceeded maximum ({quota.MaxOutputObjects}) allowed by quota.",
                                          fieldContext.GetFullRequestPath(), fieldContext.SelectionField.SourceLocation, type: "Quota");

            reqCtx.AddError(err);
            throw new AbortRequestException();
        }
Example #4
0
        internal static void ThrowFieldDepthExceededQuota(this FieldContext fieldContext)
        {
            var reqCtx    = (RequestContext)fieldContext.RequestContext;
            var quota     = reqCtx.Quota;
            var sourceLoc = fieldContext.SourceLocation;
            var err       = new GraphQLError($"Query depth exceeded maximum ({quota.MaxDepth}) allowed by quota.",
                                             fieldContext.GetFullRequestPath(), sourceLoc, type: "Quota");

            reqCtx.AddError(err);
            throw new AbortRequestException();
        }
        private async Task ExecuteMappedSelectionSubsetAsync(MappedSelectionSubSet mappedSubSet, IList <ObjectTypeDef> possibleTypes,
                                                             IList <OutputObjectScope> parentScopes)
        {
            foreach (var mappedItem in mappedSubSet.MappedItems)
            {
                if (mappedItem.Item.OnExecuting(_requestContext, out var args) && args.Skip)
                {
                    continue;
                }

                // if it is a fragment spread, make recursive call to process fragment fields
                if (mappedItem.Item.Kind == SelectionItemKind.FragmentSpread)
                {
                    var mappedSpread      = (MappedFragmentSpread)mappedItem;
                    var objTypeDef        = mappedSubSet.Mapping.TypeDef;
                    var fragmSelSubset    = mappedSpread.Spread.Fragment.SelectionSubset;
                    var entType           = mappedSubSet.Mapping.EntityType;
                    var mappedFragmSubset = GetMappedSubset(fragmSelSubset, possibleTypes, entType, mappedSpread.Spread);
                    await ExecuteMappedSelectionSubsetAsync(mappedFragmSubset, possibleTypes, parentScopes); //call self recursively

                    continue;
                }

                // It is a plain field
                var mappedField  = (MappedSelectionField)mappedItem;
                var fieldContext = new FieldContext(_requestContext, this, mappedField, parentScopes);
                var selFieldKey  = mappedField.Field.Key;

                // Process each scope for the field
                foreach (var scope in parentScopes)
                {
                    if (fieldContext.BatchResultWasSet && scope.ContainsKey(selFieldKey))
                    {
                        continue;
                    }
                    fieldContext.SetCurrentParentScope(scope);
                    var    fldDef = fieldContext.FieldDef;
                    object result = await InvokeResolverAsync(fieldContext);

                    // if batched result was not set, save value in scope
                    if (!fieldContext.BatchResultWasSet)
                    {
                        scope.SetValue(selFieldKey, result);
                    }
                } //foreach scope
                // if there are any non-null object-type results, add this field context to this special list
                //   to execute selection subsets in the next round.
                if (mappedField.Field.SelectionSubset != null && fieldContext.AllResultScopes.Count > 0)
                {
                    _executedObjectFieldContexts.Add(fieldContext);
                }
            } //foreach mappedItem
        }     //method
Example #6
0
 private object InvokeFieldReader(FieldContext fieldContext, object parent)
 {
     try {
         var reader = fieldContext.FieldDef.Reader;
         var result = reader(parent);
         return(result);
     } catch (TargetInvocationException tex) {
         // sync call goes here
         var origExc = tex.InnerException ?? tex;
         fieldContext.AddError(origExc, ErrorCodes.ResolverError);
         throw new AbortRequestException();
     }
 }
        public static void AddError(this FieldContext fieldContext, Exception exc, string errorType)
        {
            var reqCtx  = (RequestContext)fieldContext.RequestContext;
            var path    = fieldContext.GetFullRequestPath();
            var err     = new GraphQLError(exc.Message, path, fieldContext.SelectionField.SourceLocation, type: errorType);
            var withDet = reqCtx.Server.Settings.Options.IsSet(GraphQLServerOptions.ReturnExceptionDetails);

            if (withDet)
            {
                err.Extensions["Details"] = exc.ToText();
            }
            reqCtx.AddError(err, exc);
        }
 private async Task <object> InvokeResolverAsync(FieldContext fieldContext)
 {
     try {
         // Invoke resolver
         object result;
         object convResult;
         if (fieldContext.MappedField.Resolver.ResolverFunc != null)
         {
             result = InvokeResolverFunc(fieldContext);
         }
         else
         {
             result = await InvokeResolverMethodAsync(fieldContext);
         }
         // if it was batch result set, and result is null, lookup result from current scope
         //  we still need to return real result
         if (result == null && fieldContext.BatchResultWasSet)
         {
             var fldKey = fieldContext.MappedField.Field.Key;
             fieldContext.CurrentParentScope.TryGetValue(fldKey, out convResult); // value already converted
         }
         else
         {
             convResult = fieldContext.ConvertToOutputValue(result);
         }
         // check for null in non-null field
         if (convResult == null && fieldContext.FieldDef.TypeRef.IsNotNull)
         {
             var selFld = fieldContext.MappedField.Field;
             _requestContext.AddError($"Server error: resolver for non-nullable field '{selFld.Key}' returned null.",
                                      selFld, ErrorCodes.ServerError);
         }
         return(convResult);
     } catch (TargetInvocationException tex) {
         // sync call goes here
         var origExc = tex.InnerException;
         if (origExc is AbortRequestException)
         {
             throw origExc;
         }
         AddError(fieldContext, origExc, ErrorCodes.ResolverError);
         Fail();       // throws
         return(null); //never happens
     } catch (AbortRequestException) {
         throw;
     } catch (Exception ex) {
         AddError(fieldContext, ex, ErrorCodes.ResolverError);
         Fail();
         return(null); //never happens
     }
 }
        public void AddError(FieldContext fieldContext, Exception ex, string errorType)
        {
            _failed = true;
            // fire event
            var eventArgs = new OperationErrorEventArgs(_requestContext, this._mappedOpField.Field, ex);

            _requestContext.Server.Events.OnOperationError(eventArgs);
            if (eventArgs.Exception == null)
            {
                return; // event handler cleared error
            }
            // add error
            fieldContext.AddError(ex, errorType);
        }
        private async Task ExecuteObjectsSelectionSubsetAsync(IList <OutputObjectScope> parentScopes,
                                                              ObjectTypeDef objTypeDef, SelectionSubset subSet)
        {
            var outItemSet   = subSet.MappedItemSets.FirstOrDefault(fi => fi.ObjectTypeDef == objTypeDef);
            var mappedFields = _requestContext.GetIncludedMappedFields(outItemSet);

            // init scopes
            foreach (var scope in parentScopes)
            {
                scope.Init(objTypeDef, mappedFields);
            }

            for (int fldIndex = 0; fldIndex < mappedFields.Count; fldIndex++)
            {
                var mappedField        = mappedFields[fldIndex];
                var returnsComplexType = mappedField.FieldDef.Flags.IsSet(FieldFlags.ReturnsComplexType);
                var fieldContext       = new FieldContext(_requestContext, this, mappedField, fldIndex, parentScopes);
                foreach (var scope in fieldContext.AllParentScopes)
                {
                    if (fieldContext.BatchResultWasSet && scope.HasValue(fldIndex))
                    {
                        continue;
                    }
                    fieldContext.CurrentScope = scope;
                    object result = null;
                    switch (mappedField.FieldDef.ExecutionType)
                    {
                    case FieldExecutionType.Reader:
                        result = InvokeFieldReader(fieldContext, fieldContext.CurrentScope.Entity);
                        break;

                    case FieldExecutionType.Resolver:
                        result = await InvokeResolverAsync(fieldContext);

                        break;
                    }
                    var outValue = fieldContext.ConvertToOuputValue(result);
                    if (!fieldContext.BatchResultWasSet)
                    {
                        scope.SetValue(fldIndex, outValue);
                    }
                } //foreach scope
                // if there are any non-null object-type results, add this field context to this special list
                //   to execute selection subsets in the next round.
                if (returnsComplexType && fieldContext.AllResultScopes.Count > 0)
                {
                    _executedObjectFieldContexts.Add(fieldContext);
                }
            } //foreach fldIndex
        }     //method
        public async Task ExecuteOperationFieldAsync()
        {
            try {
                if (_mappedOpField.Field.OnExecuting(_requestContext, out var args) && args.Skip)
                {
                    Result = DBNull.Value; // it's a signal to skip value in output
                    return;
                }
                var opFieldContext = new FieldContext(_requestContext, this, _mappedOpField);
                opFieldContext.SetCurrentParentScope(_parentScope);
                // We do not save result in parent top-level context: we maybe executing in parallel with other top-level fields;
                // we need synchronization(lock), and also op fields might finish out of order. So we save result in a field, and
                //  RequestHandler will save all results from executers in proper order.
                //_parentScope.SetValue(_mappedOpField.Field.Key, opOutValue); -- do not do this
                this.Result = await InvokeResolverAsync(opFieldContext);

                // for fields returning objects, save for further processing of results
                if (opFieldContext.MappedField.Field.SelectionSubset != null)
                {
                    _executedObjectFieldContexts.Add(opFieldContext);
                }

                // process object field results until no more
                while (_executedObjectFieldContexts.Count > 0)
                {
                    if (_requestContext.CancellationToken.IsCancellationRequested)
                    {
                        opFieldContext.ThrowRequestCancelled();
                    }
                    // save current list, create new one in the field
                    var oldFieldContexts = _executedObjectFieldContexts;
                    _executedObjectFieldContexts = new List <FieldContext>();
                    foreach (var fldCtx in oldFieldContexts)
                    {
                        await ExecuteFieldSelectionSubsetAsync(fldCtx);
                    }
                }//while
            } finally {
                // notify resolvers about end request
                if (_resolverInstances.Count > 0)
                {
                    foreach (var resObj in _resolverInstances)
                    {
                        (resObj as IResolverClass)?.EndRequest(_requestContext);
                    }
                }
            }
        }
Example #12
0
 private async Task <object> InvokeResolverAsync(FieldContext fieldContext)
 {
     try {
         if (fieldContext.ResolverClassInstance == null)
         {
             AssignResolverClassInstance(fieldContext);
         }
         if (fieldContext.ArgValues == null)
         {
             BuildResolverArguments(fieldContext);
         }
         // we might have encountered errors when evaluating args; if so, abort all
         this.AbortIfFailed();
         // set current parentEntity arg
         if (fieldContext.Flags.IsSet(FieldFlags.HasParentArg))
         {
             fieldContext.ArgValues[1] = fieldContext.CurrentScope.Entity;
         }
         var resolver = fieldContext.FieldDef.Resolver;
         var result   = resolver.Method.Invoke(fieldContext.ResolverClassInstance, fieldContext.ArgValues);
         if (fieldContext.Flags.IsSet(FieldFlags.ReturnsTask))
         {
             result = await UnwrapTaskResultAsync(fieldContext, (Task)result);
         }
         Interlocked.Increment(ref _requestContext.Metrics.ResolverCallCount);
         // Note: result might be null, but batched result might be set.
         return(result);
     } catch (TargetInvocationException tex) {
         // sync call goes here
         var origExc = tex.InnerException;
         if (origExc is AbortRequestException)
         {
             throw origExc;
         }
         fieldContext.AddError(origExc, ErrorCodes.ResolverError);
         Fail();
         return(null); //never happens
     } catch (AbortRequestException) {
         throw;
     } catch (Exception ex) {
         fieldContext.AddError(ex, ErrorCodes.ResolverError);
         Fail();
         return(null); //never happens
     }
 }
 private object SafeEvaluateArg(FieldContext fieldContext, MappedArg arg)
 {
     try {
         var value     = arg.Evaluator.GetValue(_requestContext);
         var convValue = _requestContext.ValidateConvert(value, arg.ArgDef.TypeRef, arg.Anchor);
         return(convValue);
     } catch (AbortRequestException) {
         return(null);
     } catch (InvalidInputException bvEx) {
         _requestContext.AddInputError(bvEx);
         _failed = true;
         return(null); //continue evaluating args; it will be aborted after all args are done
     } catch (Exception ex) {
         _requestContext.AddInputError($"Failed to evaluate argument {arg.ArgDef.Name}: {ex.Message}", arg.Anchor);
         _failed = true;
         return(null); // continue to next arg
     }
 }
        private void BuildResolverArguments(FieldContext fieldContext)
        {
            var mappedArgs = fieldContext.MappedField.Field.MappedArgs;
            var argValues  = new List <object>();

            // special arguments: context, parent
            argValues.Add(fieldContext);
            if (!fieldContext.FieldDef.Flags.IsSet(FieldFlags.Static))
            {
                argValues.Add(fieldContext.CurrentParentScope.Entity);
            }
            //regular arguments
            for (int i = 0; i < mappedArgs.Count; i++)
            {
                var arg      = mappedArgs[i];
                var argValue = SafeEvaluateArg(fieldContext, arg);
                argValues.Add(argValue);
            }
            fieldContext.ArgValues = argValues.ToArray();
        }
        public async Task ExecuteOperationFieldAsync()
        {
            try {
                var opFieldContext = new FieldContext(_requestContext, this, _operationField, _fieldIndex);
                opFieldContext.CurrentScope = _parentScope;
                var result = await InvokeResolverAsync(opFieldContext);

                var opOutValue = opFieldContext.ConvertToOuputValue(result);
                _parentScope.SetValue(_fieldIndex, opOutValue);
                // for fields returning objects, save for further processing of results
                if (opFieldContext.Flags.IsSet(FieldFlags.ReturnsComplexType))
                {
                    _executedObjectFieldContexts.Add(opFieldContext);
                }

                // process object field results until no more
                while (_executedObjectFieldContexts.Count > 0)
                {
                    if (_requestContext.CancellationToken.IsCancellationRequested)
                    {
                        opFieldContext.ThrowRequestCancelled();
                    }
                    // save current list, create new one in the field
                    var oldFieldContexts = _executedObjectFieldContexts;
                    _executedObjectFieldContexts = new List <FieldContext>();
                    foreach (var fldCtx in oldFieldContexts)
                    {
                        await ExecuteFieldSelectionSubsetAsync(fldCtx);
                    }
                }//while
            } finally {
                // notify resolvers about end request
                if (_resolverInstances.Count > 0)
                {
                    foreach (var resObj in _resolverInstances)
                    {
                        (resObj as IResolverClass)?.EndRequest(_requestContext);
                    }
                }
            }
        }
        // gets cached resolver class instance or creates new one
        private void AssignResolverClassInstance(FieldContext fieldCtx, FieldResolverInfo fieldResolver)
        {
            var    resClassType = fieldResolver.ResolverMethod.ResolverClass.Type;
            object resInstance  = null;

            if (_resolverInstances.Count == 1 && _resolverInstances[0].GetType() == resClassType) // fast track
            {
                resInstance = _resolverInstances[0];
            }
            else
            {
                resInstance = _resolverInstances.FirstOrDefault(r => r.GetType() == resClassType);
            }
            if (resInstance == null)
            {
                resInstance = Activator.CreateInstance(resClassType);
                if (resInstance is IResolverClass iRes)
                {
                    iRes.BeginRequest(_requestContext);
                }
                _resolverInstances.Add(resInstance);
            }
            fieldCtx.ResolverClassInstance = resInstance;
        }
Example #17
0
 internal static void ThrowFatal(this FieldContext fieldContext, string message)
 {
     throw new FatalServerException(message);
 }