【问题标题】:WebAPI OData $Skip on custom IQueryable double appliedWebAPI OData $Skip on custom IQueryable double apply
【发布时间】:2015-08-16 23:57:57
【问题描述】:

我已经实现了一个通过 WebAPI OData 端点公开的自定义 IQueryable。控制器的 Get() 结构比较标准:

[EnableQuery(
    AllowedQueryOptions = AllowedQueryOptions.Count
                          | AllowedQueryOptions.Filter
                          | AllowedQueryOptions.OrderBy
                          | AllowedQueryOptions.Skip
                          | AllowedQueryOptions.Top)]
[ODataRoute]
public PageResult<Foo> Get(ODataQueryOptions<Foo> queryOptions)
{

    var bars = new QueryableData<Foo>(_provider);

    var result = ((IQueryable<Foo>)queryOptions
        .ApplyTo(bars,
            new ODataQuerySettings(new ODataQuerySettings { EnableConstantParameterization = false, EnsureStableOrdering = false }))).ToList();
    var count = _provider.Count;
    return new PageResult<Foo>(result, null, count);
}

我看到的奇怪行为是,在返回 PageResult 之后应用了查询字符串中的 OData $Skip。例如:

  • 如果查询字符串包含 ?$top=10&$skip=10 将不会返回任何结果。
  • 如果查询字符串包含 ?&top=12&skip=10 将返回 (2) 个结果。

我想要做的是阻止框架将 Skip 应用到我的结果集,因为查询提供程序已经在实现 skip。是否可以设置 ODataQuerySettings 来防止这种双重应用跳过?

编辑: 经过进一步调查,当我按预期从查询字符串跳过(和顶部)函数中删除 $count=true 时。这让我相信我实现 $count=true 的方法是不正确的。从我的调试会话中可以看出,当 $count=true 在查询选项中时,可查询的表达式树应用了两次,一次返回类型为 long,然后再次没有包装 countlong 表达式。我尝试在第一遍返回计数,然后在第二遍中正确查询,但这会导致跳过表达式的延迟应用。这里似乎缺少一些非常基本的东西。

【问题讨论】:

    标签: c# asp.net-web-api odata iqueryable


    【解决方案1】:

    在阅读 Github 问题列表时,我看到了这篇文章:OData PageResult method ignoring count parameter when using EnableQuery attribute #159。问题似乎是 EnableQuery Attribute 和采用 ODataQueryOptions 的参数化 Get 构造函数的组合。使用这两种方法意味着您将实现构造函数查询选项,应用查询表达式,然后框架将根据应用属性的方向应用它可以使用的过滤器;因此双重应用诸如skip、top和orderby之类的东西。

    【讨论】:

    • 太棒了。谢谢你。
    • 对于其他阅读此内容的人感到困惑,这导致我在我的方法中取消 [EnableQuery] 属性,并在我的方法参数中加入 ODataQueryOptions 并且事情开始起作用了。
    【解决方案2】:

    因为我想自己处理跳过,但我仍然想要 EnableQueryAttribute 的其他功能,所以我看了看,发现它是虚拟的。我创建了一个派生类,然后尝试覆盖 ApplyQuery 方法。不幸的是,ODataQueryOptions 的属性只有私有集,所以我忍住了一点思考。 (感觉很脏但是嘿..)

    public override IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions)
    {
        var skipOption = new SkipQueryOption("0", queryOptions.Context);
        typeof(ODataQueryOptions).GetProperty("Skip").SetValue(queryOptions, skipOption, null);
    
        return base.ApplyQuery(queryable, queryOptions);
    }
    

    现在跳过选项为 0,它在构建响应时不会应用它,并且不再有“双跳过蓝调”。

    【讨论】:

      【解决方案3】:

      我发现如果你使用swagger/swashbuckle,把属性全部去掉会导致swashbuckle不生成一些OData选项。创建您自己的属性,覆盖 ApplyQuery 方法,什么都不做,只返回原始查询按预期工作。

          // OData framework's EnableQuery attribute will apply query's again, after we have already applied the query to the result set
          // (So For e.g. you will get Top and Skip applied again on your results that have already had top and skip applied
          // this is a workaround the disables client side queries until this is fixed.
          // https://github.com/OData/WebApi/issues/159
          public class EnableCustomQueryAttribute : EnableQueryAttribute
          {
              public override IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions)
              {
                  return queryable;
              }
          }
      

      【讨论】:

        【解决方案4】:

        根据 slamb2k 的回复,更新了一点:

        public override IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions)
        {
            var parser = typeof(ODataQueryOptions).GetField("_queryOptionParser", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(queryOptions) as ODataQueryOptionParser;
            typeof(ODataQueryOptions).GetProperty("Skip").SetValue(queryOptions, new SkipQueryOption("0", queryOptions.Context, parser), null);
            typeof(ODataQueryOptions).GetProperty("Top").SetValue(queryOptions, new TopQueryOption("0", queryOptions.Context, parser), null);
            typeof(ODataQueryOptions).GetProperty("OrderBy").SetValue(queryOptions, new OrderByQueryOption("0", queryOptions.Context, parser), null);
        
            return base.ApplyQuery(queryable, queryOptions);
        }
        

        【讨论】:

          猜你喜欢
          • 2012-10-09
          • 2013-02-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-04-23
          • 2021-12-01
          • 2015-03-29
          • 2013-04-25
          相关资源
          最近更新 更多