OData v4结果的后处理(适用于v3,不适用于v4)

时间:2018-08-12 15:36:16

标签: entity-framework asp.net-web-api odata

我有一个Web API服务器(带有EF 6.x),我需要对控制器中OData查询的结果集进行一些后处理。在客户端,我使用DevEx网格及其ODataInstantFeedbackSource。

没有后处理功能,一切正常,例如:

http://somesite.us/odata/Items/ $ count

[EnableQuery]
public IHttpActionResult GetItems(ODataQueryOptions<Item> queryOptions)
{
    return Ok(Context.Items);
}

它不能用于后处理(相同的$ count查询,但是没有EnableQuery,因为我是手动应用查询选项)

获取http://somesite.us/odata/Items/ $ count

//[EnableQuery]
public IHttpActionResult GetItems(ODataQueryOptions<Item> queryOptions)
{
    queryOptions.Validate(_validationSettings);
    var query = queryOptions.ApplyTo(Context.Items, new ODataQuerySettings()) as IQueryable<Item>;
    var resultList = new List<Item>();
    foreach (var item in query)
    {
        item.OrdStat = "asf"; // Some post-processing
        resultList.Add(item);
    }
    return Ok(resultList.AsQueryable());
}

这引发异常:

Microsoft.OData.ODataException
  HResult=0x80131509
  Message=The value of type 'System.Linq.EnumerableQuery`1[[SomeService.Model.Item, SomeService.Model, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' could not be converted to a raw string.
  Source=Microsoft.OData.Core
  StackTrace:
   at Microsoft.OData.RawValueWriter.WriteRawValue(Object value)

注意:对于ODATA v3,上面的方法就可以了。不使用[EnableQuery]时,只有v4出现异常。

如果我重新添加[EnableQuery]属性,则此简单的$ count查询可与ODATA v4一起使用,但对于更复杂的查询,返回给客户端的数据会被弄乱(可能是由于$ skip等导致两者均被应用)由我和EnableQuery属性)。

例如,当您向下滚动时,此查询由DevEx网格生成: http://somesite.us/odata/Items?$ orderby = ItemNo&$ skip = 300&$ top = 201

(客户端)结果:意外的返回键数:0。预期:201

我假设我需要删除EnableQuery属性,因为我是手动应用查询选项,但是为什么这样做时却出现“无法转换为原始字符串”异常?

在这种情况下如何正确实施后处理?

1 个答案:

答案 0 :(得分:0)

我就此向Microsoft提出了支持请求,他们最终确定这是ODATA v4中的错误,并创建了此错误报告: https://github.com/OData/WebApi/issues/1586

解决方法是检查查询是否为计数查询,如果是,则返回Ok(query.Count());

if (queryOptions.Context.Path?.Segments.LastOrDefault() is CountSegment)
    return Ok(query?.Count());

这是更完整的示例代码段/ POC,可与ODATA v4配合使用:

private static ODataValidationSettings _validationSettings = new ODataValidationSettings();

[ODataRoute("Customers")]
public IHttpActionResult Get(ODataQueryOptions<CustomerLookup> queryOptions)
{
    queryOptions.Validate(_validationSettings);
    var query = queryOptions.ApplyTo(Context.CustomerLookup) as IQueryable<CustomerLookup>;
    if (queryOptions.Context.Path?.Segments.LastOrDefault() is CountSegment)
        return Ok(query?.Count());

    var resultList = new List<CustomerLookup>();
    foreach (var customer in query)
    {
        customer.Address = "1234_" + customer.Address;
        resultList.Add(customer);
    }

    return Ok(resultList.AsQueryable());
}