.NET 7 Web API中OData PageResult<T>序列化异常问题求助
问题
基于.NET 7开发Web API,计划将OData作为部分GET请求的查询框架,使用PageResult<TObj>向前端返回count值。当前存在以下问题:
- 无OData查询参数时,返回的
PageResult<TObj>包含正确的items和count属性; - 使用
$filter、$skip/$top等参数后,仅返回items内的纯数据数组,丢失外层的PageResult包装结构。
相关代码如下:
Program.cs中OData注册代码
JsonConvert.DefaultSettings = () => new JsonSerializerSettings { Formatting = Formatting.Indented, ContractResolver = new CamelCasePropertyNamesContractResolver(), Converters = new List<JsonConverter> { stringEnumConverter, }, }; services.AddControllers().AddOData(options => { options.EnableQueryFeatures(100); });
测试用模拟数据方法
private IQueryable<StaticMailReceiversEntity> GetStaticMailReceiver() { return new List<StaticMailReceiversEntity> { new () { Email = "test1@sergo.de", FirstName = "Test1", LastName = "Last1", OnlyNotification = false, Templates = new List<string> { "template1", "template2", "template3", }, }, new () { Email = "test2@sergo.de", FirstName = "Test2", LastName = "Last2", OnlyNotification = false, Templates = new List<string> { "template1", "template2", "template3", }, }, new () { Email = "test3@sergo.de", FirstName = "Test3", LastName = "Last3", OnlyNotification = false, Templates = new List<string> { "template1", "template2", "template3", }, }, }.AsQueryable(); }
控制器测试方法
[AllowAnonymous] [HttpGet("odatatest1")] [EnableQuery] public async Task<ActionResult<StaticMailReceiversEntity>> GetODataOptions1Async(ODataQueryOptions<StaticMailReceiversEntity> options) { var plainQueryable = GetStaticMailReceiver(); var queryable = options.ApplyTo(plainQueryable); var typedQueryable = queryable.Cast<StaticMailReceiversEntity>(); var fileResult = new PageResult<StaticMailReceiversEntity>( typedQueryable, null, plainQueryable.Count()); return Ok(fileResult); } [AllowAnonymous] [HttpGet("odatatest2")] [EnableQuery] public async Task<ActionResult<StaticMailReceiversEntity>> GetODataOptions2Async() { var queryable = GetStaticMailReceiver(); var fileResult = new PageResult<StaticMailReceiversEntity>( queryable, null, queryable.Count()); return Ok(fileResult); }
解决方案
1. 调整EnableQuery特性参数,禁用自动结果拆解
[EnableQuery]默认会自动处理返回的IQueryable,直接提取数组返回。修改特性配置,让中间件保留原始返回结构:
[EnableQuery(HandleNullPropagation = HandleNullPropagationOption.False)]
2. 修改控制器方法的返回类型
将返回类型从ActionResult<StaticMailReceiversEntity>改为ActionResult<PageResult<StaticMailReceiversEntity>>,明确告知框架返回的是分页包装结构,避免被OData中间件拆解。
3. 优化控制器方法逻辑
手动执行OData查询并包装成PageResult,同时注意异步执行查询提升性能:
[AllowAnonymous] [HttpGet("odatatest1")] [EnableQuery(HandleNullPropagation = HandleNullPropagationOption.False)] public async Task<ActionResult<PageResult<StaticMailReceiversEntity>>> GetODataOptions1Async(ODataQueryOptions<StaticMailReceiversEntity> options) { var plainQueryable = GetStaticMailReceiver(); // 获取总条数(EF Core场景建议用CountAsync避免同步阻塞) var totalCount = await plainQueryable.CountAsync(); // 应用OData查询 var queryable = options.ApplyTo(plainQueryable) as IQueryable<StaticMailReceiversEntity>; var items = await queryable.ToListAsync(); var pageResult = new PageResult<StaticMailReceiversEntity>( items, null, // 可根据当前请求生成nextLink totalCount); return Ok(pageResult); } [AllowAnonymous] [HttpGet("odatatest2")] [EnableQuery(HandleNullPropagation = HandleNullPropagationOption.False)] public async Task<ActionResult<PageResult<StaticMailReceiversEntity>>> GetODataOptions2Async() { var queryable = GetStaticMailReceiver(); var totalCount = await queryable.CountAsync(); var items = await queryable.ToListAsync(); var pageResult = new PageResult<StaticMailReceiversEntity>( items, null, totalCount); return Ok(pageResult); }
4. 完善OData服务配置
在Program.cs中显式启用所需的OData查询选项,确保分页和count功能正常:
services.AddControllers().AddOData(options => { options.EnableQueryFeatures(100) .Select().Filter().OrderBy().Expand().Count().SkipToken(); });
内容的提问来源于stack exchange,提问作者kdennis
相关产品推荐
相关产品推荐

