我有一个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属性,因为我是手动应用查询选项,但是为什么这样做时却出现“无法转换为原始字符串”异常?
在这种情况下如何正确实施后处理?
答案 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());
}