HotChocolate GraphQL子列表为Null时触发参数空引用错误求助
HotChocolate GraphQL 空列表字段引发的
Value cannot be null 异常解决 问题场景
执行以下GraphQL查询时:
{ name, userList { firstName, lastName } }
当返回的数百个对象中存在一个userList(列表类型)为Null的对象时,系统抛出异常:
Value cannot be null. (Parameter 'source')
即使已将userList属性标记为可空,问题依然存在。异常堆栈追踪如下:
at System.Linq.ThrowHelper.ThrowArgumentNullException(ExceptionArgument argument) at System.Linq.Enumerable.Select[TSource,TResult](IEnumerable`1 source, Func`2 selector) at lambda_method961(Closure, OrganizationResponse) at System.Linq.Enumerable.SelectIPartitionIterator`2.GetCount(Boolean onlyIfCheap) at System.Linq.EnumerableExecutor`1.Execute() at System.Linq.EnumerableQuery`1.System.Linq.IQueryProvider.Execute[TElement](Expression expression) at HotChocolate.Types.Pagination.QueryableOffsetPagingHandler`1.<>c__DisplayClass3_0.<ResolveAsync>b__0() at System.Threading.Tasks.Task`1.InnerInvoke() at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state) --- End of stack trace from previous location --- at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) --- End of stack trace from previous location --- at HotChocolate.Types.Pagination.QueryableOffsetPagingHandler`1.ResolveAsync(IResolverContext context, IQueryable`1 source, OffsetPagingArguments arguments, CancellationToken cancellationToken) at HotChocolate.Types.Pagination.OffsetPagingHandler.HotChocolate.Types.Pagination.IPagingHandler.SliceAsync(IResolverContext context, Object source) at HotChocolate.Types.Pagination.PagingMiddleware.InvokeAsync(IMiddlewareContext context) at HotChocolate.Utilities.MiddlewareCompiler`1.ExpressionHelper.AwaitTaskHelper(Task task) at HotChocolate.Execution.Processing.Tasks.ResolverTask.ExecuteResolverPipelineAsync(CancellationToken cancellationToken) at HotChocolate.Execution.Processing.Tasks.ResolverTask.TryExecuteAsync(CancellationToken cancellationToken)
问题原因
从堆栈信息可以看出,异常触发于QueryableOffsetPagingHandler的分页处理逻辑中。HotChocolate的自动分页中间件会尝试对列表字段执行Linq查询操作,当userList为Null时,Linq的Select方法接收到空的数据源,直接抛出参数空引用异常——即使字段标记为可空,分页逻辑仍会直接操作Null值而非跳过。
解决方案
1. 在Resolver中将Null转为空列表
在userList字段的Resolver方法里,显式将Null替换为空的Enumerable,避免分页逻辑处理空数据源:
public IEnumerable<User>? GetUserList(OrganizationResponse organization) { // 若userList为Null,返回空列表而非Null return organization.UserList ?? Enumerable.Empty<User>(); }
2. 数据映射层提前处理Null
如果使用AutoMapper等工具做数据转换,在映射规则中配置将Null列表转为空列表:
public class OrganizationProfile : Profile { public OrganizationProfile() { CreateMap<OrganizationDbModel, OrganizationResponse>() .ForMember(dest => dest.UserList, opt => opt.MapFrom(src => src.UserList ?? new List<User>())); } }
3. 禁用该字段的自动分页(可选)
如果该字段不需要分页功能,可以直接禁用HotChocolate的自动分页,避免分页逻辑介入:
[GraphQLIgnorePaging] public IEnumerable<User>? UserList { get; set; }
4. 自定义分页Handler(复杂场景)
如果必须保留分页且需要处理Null场景,可以自定义分页Handler,在处理前检查数据源是否为Null:
public class NullSafeOffsetPagingHandler : OffsetPagingHandler { protected override Task<IPage> SliceAsync(IResolverContext context, object source, CancellationToken cancellationToken) { // 若数据源为Null,返回空分页结果 if (source == null) { return Task.FromResult<IPage>(new OffsetPage(Enumerable.Empty<object>(), 0, 0)); } return base.SliceAsync(context, source, cancellationToken); } }
然后在字段配置中指定使用该Handler:
descriptor.Field(t => t.UserList) .UsePaging<UserType>() .Handler<NullSafeOffsetPagingHandler>();
内容的提问来源于stack exchange,提问作者Anthony
相关产品推荐
相关产品推荐

