如何通过GraphQL访问继承IList的IPagedList成员属性?
问题原因
- GraphQL的类型系统默认会将继承自
IEnumerable<T>/IList<T>的类型识别为列表类型,只会暴露列表中的元素,不会自动解析接口或类中额外的分页属性。 - 你的Query方法返回的是
IPagedList<Book>接口类型,GraphQL默认不会主动扫描接口的成员来生成Schema字段,只会处理它继承的IList<T>的列表行为。
可行解决办法
方法1:修改返回类型为具体类PagedList<T>(最小工作量)
直接把Query方法的返回类型从Task<IPagedList<Book>>改成Task<PagedList<Book>>,同时调整ToPagedListAsync的返回类型,让GraphQL能直接反射具体类的所有公共属性(包括分页成员和列表元素):
修改Query方法
public async Task<PagedList<Book>> Books(int pageIndex, int pageSize) { var data = new List<Book>() { new() { Title = "C# in depth.", Author = new Author { Name = "Jon Skeet" } }, new() { Title = "How to cook Phở", Author = new Author { Name = "Nam Vo" } }, new() { Title = "How to cook Phở2", Author = new Author { Name = "Nam Vo" } }, new() { Title = "How to cook Phở3", Author = new Author { Name = "Nam Vo" } } }; return await data.ToPagedListAsync(pageIndex, pageSize, data.Count); }
修改ToPagedListAsync方法
public static async Task<PagedList<T>> ToPagedListAsync<T>(this IEnumerable<T> source, int pageIndex, int pageSize, int totalCount) { if (source == null) return new PagedList<T>(new List<T>(), pageIndex, pageSize); pageSize = Math.Max(pageSize, 1); var data = await source.Skip(pageIndex * pageSize) .Take(pageSize) .ToAsyncEnumerable() .ToListAsync(); return new PagedList<T>(data, pageIndex, pageSize, totalCount); }
方法2:显式配置GraphQL接口类型(适合保留接口返回的场景)
如果不想修改返回类型,可以在GraphQL的Schema配置中,为IPagedList<T>接口显式声明字段。以HotChocolate为例:
编写接口类型扩展
public class IPagedListTypeExtension<T> : ObjectTypeExtension<IPagedList<T>> { protected override void Configure(IObjectTypeDescriptor<IPagedList<T>> descriptor) { descriptor.Name($"IPagedList{typeof(T).Name}"); descriptor.Field(x => x.PageIndex).Type<IntType>(); descriptor.Field(x => x.PageSize).Type<IntType>(); descriptor.Field(x => x.TotalCount).Type<IntType>(); descriptor.Field(x => x.TotalPages).Type<IntType>(); descriptor.Field(x => x.HasPreviousPage).Type<BooleanType>(); descriptor.Field(x => x.HasNextPage).Type<BooleanType>(); // 暴露列表元素 descriptor.Field("items") .Type<ListType<ObjectType<T>>>() .Resolver(ctx => ctx.Parent<IPagedList<T>>()); } }
注册扩展类型
builder.Services.AddGraphQLServer() .AddQueryType<Query>() .AddTypeExtension<IPagedListTypeExtension<Book>>();
方法3:用匿名类型临时包装(兼容现有接口)
如果不想修改现有结构,可在Query方法中将IPagedList<T>包装成匿名类型,让GraphQL自动识别所有属性:
public async Task<object> Books(int pageIndex, int pageSize) { var data = new List<Book>() { new() { Title = "C# in depth.", Author = new Author { Name = "Jon Skeet" } }, new() { Title = "How to cook Phở", Author = new Author { Name = "Nam Vo" } }, new() { Title = "How to cook Phở2", Author = new Author { Name = "Nam Vo" } }, new() { Title = "How to cook Phở3", Author = new Author { Name = "Nam Vo" } } }; var pagedList = await data.ToPagedListAsync(pageIndex, pageSize, data.Count); return new { Items = pagedList, pagedList.PageIndex, pagedList.PageSize, pagedList.TotalCount, pagedList.TotalPages, pagedList.HasPreviousPage, pagedList.HasNextPage }; }
内容的提问来源于stack exchange,提问作者nam vo
相关产品推荐
相关产品推荐

