Reputation: 1880
I have a Web API server (with EF 6.x) and I need to do some post-processing of the result set from OData queries in the controller. On the client-side I use a DevEx grid and their ODataInstantFeedbackSource.
With no post-processing, everything works fine, e.g.:
http://somesite.us/odata/Items/$count
[EnableQuery]
public IHttpActionResult GetItems(ODataQueryOptions<Item> queryOptions)
{
return Ok(Context.Items);
}
It does not work with post-processing (same simple $count query, but without EnableQuery since I am manually applying the query options):
GET 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());
}
This throws an exception:
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)
Note: with ODATA v3, the above works just fine. It is only with v4 that I get an exception when not using [EnableQuery].
If I add back the [EnableQuery] attribute, this simple $count query works with ODATA v4, but with more complex queries, the data returned to the client gets messed up (likely due to $skip, etc. being applied both by me and by the EnableQuery attribute).
For example, this query generated by the DevEx grid when you scroll down: http://somesite.us/odata/Items?$orderby=ItemNo&$skip=300&$top=201
Results in (client-side): Unexpected number of returned keys: 0. Expected: 201
I assume that I need to remove the EnableQuery attribute since I am manually applying the query options, but why am I getting the "could not be converted to a raw string" exception when I do this?
How can I properly implement post-processing in this scenario?
Upvotes: 2
Views: 795
Reputation: 1880
I opened a support request with Microsoft on this, and they eventually determined that it is a bug in ODATA v4 and they created this bug report: https://github.com/OData/WebApi/issues/1586
The workaround is to check if the query is a count query and, if so, return Ok(query.Count());
if (queryOptions.Context.Path?.Segments.LastOrDefault() is CountSegment)
return Ok(query?.Count());
Here is a more complete sample snippet / POC which works fine with 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());
}
Upvotes: 0