You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 12:22:56