GraphQL.ExecutionError: Error trying to resolve

Viewed 1132

Summary:

My GraphQL ExecuteAsync returns a result that contains. According to the stackTrace provided below, the system cannot resolve my custom type remitsGeneralSearch. The remitsGeneralSearch resolver can return a type called ClaimPaymentOrCheckSearchGraphType which is a UnionGraphType.

StackTrace: ["GraphQL.ExecutionError: Error trying to resolve remitsGeneralSearch.\n ---> System.InvalidOperationException: Unexpected type: \n at GraphQL.Execution.ExecutionStrategy.BuildExecutionNode(ExecutionNode parent, IGraphType graphType, Field field, FieldType fieldDefinition, String[] path)\n at GraphQL.Execution.ExecutionStrategy.SetSubFieldNodes(ExecutionContext context, ObjectExecutionNode parent, Dictionary`2 fields)\n at GraphQL.Execution.ExecutionStrategy.SetSubFieldNodes(ExecutionContext context, ObjectExecutionNode parent)\n at GraphQL.Execution.ExecutionStrategy.ExecuteNodeAsync(ExecutionContext context, ExecutionNode node)\n --- End of inner exception stack trace ---"]4008305)

GraphQL Version: 2.4.0

FrameWork: .Net

OS: MacOS Catalina

Links Referenced: https://github.com/graphql-dotnet/graphql-dotnet/issues/964

CODE SNIPPETS:

RESOLVER:

    FieldAsync<ClaimPaymentOrCheckSearchGraphType>(
                "remitsGeneralSearch",
                resolve: async context =>
    {
        var securityFilter = await GetUserRemitFilters(context);
        var range = context.GetRange();
        var sortFields = context.GetArgument<List<SortField>>("sort") ?? Enumerable.Empty<SortField>();
        var whereClaimPayment = context.GetArgument<ClaimPaymentSearchFilter>("whereClaimPayment");
    
   Connection<ClaimPaymentSearchRow> claimPaymentSearchRowResult;
    
        try
        {
                using (LogContext.PushProperty("where", whereClaimPayment, true))
                                                {
              //claimPaymentSearchRowResult = await DMAQueryService.GetRemitReadersAsync(context);
            var whereArguments = context.Arguments["whereClaimPayment"] as Dictionary<string, object>;
            claimPaymentSearchRowResult = await DMAQueryService.GetRemitReadersAsync(
                                range,
                                whereClaimPayment,
                                whereArguments,
                                sortFields,
                                securityFilter,
                                context.CancellationToken
                );
            }
        }
        catch (Exception e)
        {
            _logger.LogInformation("Exception occurred {e}", e);
            throw e;
        }
    
        var userRemitFilters = context.UserContext as Services.DMA.UserRemitFilters;
    
    if (claimPaymentSearchRowResult.EdgeCount > 0)
    {
        return claimPaymentSearchRowResult;
    }
    
    var _whereCheckSearch = context.GetArgument<CheckSearchFilter>("whereCheck");
    
    try
    {
        Connection<CheckSearchRow> checkSearchRowResult;
        using (LogContext.PushProperty("whereCheck", _whereCheckSearch, true))
        {
          checkSearchRowResult = await DMAQueryService.GetCheckReadersAsync(context);
          return checkSearchRowResult;
        }
    }
    catch (Exception e)
    {
       throw e;
    }
  },arguments: queryArguments
 );
}
catch (Exception e)
{
   throw e;
}

Custom GraphType:

[Transient]
    public class ClaimPaymentOrCheckSearchGraphType : UnionGraphType
    {
        private readonly ILogger<ClaimPaymentOrCheckSearchGraphType> _logger;
        public ClaimPaymentOrCheckSearchGraphType(
            ILogger<ClaimPaymentOrCheckSearchGraphType> logger,
            ConnectionGraphType<ClaimPaymentSearchGraphType> claimPaymentSearchGraphType,
            ConnectionGraphType<CheckSearchGraphType> checkSearchGraphType
        )
        {
            _logger = logger;
            Type<ConnectionGraphType<ClaimPaymentSearchGraphType>>();
            Type<ConnectionGraphType<CheckSearchGraphType>>();

            ResolveType = obj =>
            {
                try
                {
                    if (obj is Connection<ClaimPaymentSearchRow>)
                    {
                        return claimPaymentSearchGraphType;
                    }

                    if (obj is Connection<CheckSearchRow>)
                    {
                        return checkSearchGraphType;
                    }

                    throw new ArgumentOutOfRangeException($"Could not resolve graph type for {obj.GetType().Name}");
                }
                catch (Exception e)
                {
                    _logger.LogInformation("ClaimPaymentOrCheckSearchGraphType Exception {e}: ", e);
                    throw e;
                }

            };
        }
    }
1 Answers

Link to answer found here: https://github.com/graphql-dotnet/graphql-dotnet/issues/2674Try replacing this:

Type<ConnectionGraphType<ClaimPaymentSearchGraphType>>();
Type<ConnectionGraphType<CheckSearchGraphType>>();

with this:

AddPossibleType(claimPaymentSearchGraphType);
AddPossibleType(checkSearchGraphType);

I'm thinking that if you're registering these types as transients, then the copy that gets registered to the schema initialization code is a different copy that gets returned from ResolveType. Because of that, its fields' ResolvedType properties was never set, and so null is passed into BuildExecutionNode for the graphType instead of a resolved type.

If the ResolveType method could return a type rather than an instance, there wouldn't be an issue, but unfortunately that's not the way it works. Or you could register the type as a singleton.

Related