graphql-dotnet: GraphQL.ExecutionError: Error trying to resolve remitsGeneralSearch.

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;
				}

			};
		}
	}

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 15 (9 by maintainers)

Most upvoted comments

Try 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.