Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EnableLowerCamelCase causes Skiptoken to fail to generate on second page of query when using orderby desc #1061

Closed
jsangco opened this issue Sep 29, 2023 Discussed in #1059 · 6 comments
Assignees

Comments

@jsangco
Copy link

jsangco commented Sep 29, 2023

Discussed in #1059

Originally posted by jsangco September 22, 2023
Using Microsoft.AspNetCore.OData version 8.2.3, the framework will properly generate the skiptoken for the first API call, but it fails to generate a nextLink on subsequent calls when using a orderby=id desc query.

Here is an example of the output I see when executing the following queries with a max page size of 3 and 100 customers

> curl https://localhost:7187/odata/customers?orderby=id%20desc
{
  "value": [{"id": 100},{"id": 99},{"id": 98}],
  "@odata.nextLink": "https://localhost:7187/odata/customers?orderby=id%20desc&$skiptoken=id-97"
}

> curl https://localhost:7187/odata/customers?orderby=id%20desc&$skiptoken=id-97
{
  "value": [{"id": 97},{"id": 96},{"id": 95}],
}

Note: The second query does not contain the @odata.nextLink property.

This query was working in version 8.0.11, however, in that version, skipToken does not work with select queries.
Please advise.

@ElizabethOkerio
Copy link
Contributor

ElizabethOkerio commented Oct 3, 2023

@jsangco..This is what I've tried to repro the issue:
controller

        [HttpGet]
        [EnableQuery(PageSize = 3)]
        public IActionResult Get()
        {
            return Ok(_context.Products);
        }
https://localhost:44392/odata/Products?$orderby=Id%20desc

Response

{
  "@odata.context": "https://localhost:44392/odata/$metadata#Products",
  "value": [
    {
      "Id": 99
    },
    {
      "Id": 98
    },
    {
      "Id": 97
    }
  ],
  "@odata.nextLink": "https://localhost:44392/odata/Products?orderby=Id%20desc&$skiptoken=Id-97"
}
https://localhost:44392/odata/Products?orderby=Id%20desc&$skiptoken=Id-97

Response

{
  "@odata.context": "https://localhost:44392/odata/$metadata#Products",
  "value": [
    {
      "Id": 96
    },
    {
      "Id": 95
    },
    {
      "Id": 94
    }
  ],
  "@odata.nextLink": "https://localhost:44392/odata/Products?orderby=Id%20desc&$skiptoken=Id-94"
}

I seem to get the skiptoken on subsequent calls.Could it be possible that there's no more data to be fetched in the subsequent call in your case? Please share a repro to help us debug this.

@gathogojr
Copy link
Contributor

@jsangco An attempt to reproduce the issue was unsuccessful. Kindly share with us a simple repro to help with troubleshooting

@gathogojr
Copy link
Contributor

Hi @jsangco. Are you able to provide us with more details to help us troubleshoot the issue?

@jsangco
Copy link
Author

jsangco commented Oct 10, 2023

Yes, I've started working on a cleaner way to reproduce the issue.

@jsangco
Copy link
Author

jsangco commented Oct 10, 2023

Looks like the issue is caused by ODataConventionModelBuilderExtensions.EnableLowerCamelCase, and the issue does not exist in the previous 8.0.11 version of the assembly.

I've updated the title of the thread.

Code below will reproduce the issue:

// Program.cs
using Microsoft.AspNetCore.OData;
using Microsoft.OData.Edm;
using Microsoft.OData.ModelBuilder;
using SkipTokenFail;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSwaggerGen();
builder.Services.AddControllers()
    .AddOData(options => 
    {
        options.EnableQueryFeatures();
        options.AddRouteComponents("v1", CreateEdmModel());
    });

static IEdmModel CreateEdmModel()
{
    var builder = new ODataConventionModelBuilder();
    builder.EnableLowerCamelCase(); // <-- This line causes skip token to fail; remove it and it will work.

    builder.EntitySet<Product>("products").EntityType
    .HasKey(e => e.Id)
    .Page(10, 10);

    return builder.GetEdmModel();
}

var app = builder.Build();
app.UseRouting();
app.MapControllers();

app.Run();
// ProductsController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using Microsoft.AspNetCore.OData.Routing.Controllers;

namespace SkipTokenFail;

[ApiController]
[Route("v1/products")]
public class ProductsController : ODataController
{
    [EnableQuery()]
    [HttpGet]
    public IQueryable<Product> Get()
    {
        var products = Enumerable.Range(0, 1000).Select(i => new Product() { Id = i }).AsQueryable();
        return products;
    }
}

public class Product
{
    public int Id { get; set; }
}
<!-- SkipTokenFail.csproj -->
<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <InvariantGlobalization>true</InvariantGlobalization>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0-rc.1.23421.29" />
    <!-- The issue does not occur in version 8.0.11 -->
    <!-- <PackageReference Include="Microsoft.AspNetCore.OData" Version="8.0.11" /> -->
    <PackageReference Include="Microsoft.AspNetCore.OData" Version="8.2.3" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
  </ItemGroup>

</Project>

@jsangco jsangco changed the title Skiptoken fails to generate on second page query when using orderby desc EnableLowerCamelCase causes Skiptoken to fail to generate on second page of query when using orderby desc Oct 10, 2023
@gathogojr
Copy link
Contributor

@jsangco This issue was recently fixed in this pull request and should be in our next release.

If you can, kindly test against the nightly build at this location

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants