27

I am using the out of the box ValuesController in a ASP.NET Web API application

 public class ValuesController : ApiController
 {
     // GET api/values
     [Queryable(PageSize = 1)]
     public IQueryable<string> Get()
     {
         return new string[] { "value1", "value2", "value3", "value4", "value5" }.AsQueryable();
     }
 }

When I get http://localhost/api/values?$inlinecount=allpages

This is the response

<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>value1</string>
</ArrayOfString>

I have uncommented config.EnableQuerySupport();

Filtering, sorting work fine.

If I try get http://localhost/api/values?$inlinecount=XXXXX I get an exception, so it seems the Web API application knows about inlinecount

<Message>The query specified in the URI is not valid.</Message>
<ExceptionMessage>'xxx' is not a valid value for $inlinecount.</ExceptionMessage> 
<ExceptionType>Microsoft.Data.OData.ODataException</ExceptionType>

I definitely have the Microsoft.AspNet.WebApi.OData package - here is the output of the Package Manager Console

PM> Install-Package Microsoft.AspNet.WebApi.OData 
Attempting to resolve dependency 'Microsoft.Net.Http (= 2.0.20710.0 && < 2.1)'.
Attempting to resolve dependency 'Microsoft.AspNet.WebApi.Client (= 4.0.20710.0 && < 4.1)'.
Attempting to resolve dependency 'Newtonsoft.Json (= 4.5.6)'.
Attempting to resolve dependency 'Microsoft.AspNet.WebApi.Core (= 4.0.20710.0 && < 4.1)'.
Attempting to resolve dependency 'Microsoft.Data.OData (= 5.2.0 && < 5.3.0)'.
Attempting to resolve dependency 'System.Spatial (= 5.2.0)'.
Attempting to resolve dependency 'Microsoft.Data.Edm (= 5.2.0)'.
'Microsoft.AspNet.WebApi.OData 4.0.0' already installed.
WebServicesProject already has a reference to 'Microsoft.AspNet.WebApi.OData 4.0.0'.

Any suggestions?

Boghyon Hoffmann
  • 17,103
  • 12
  • 72
  • 170
tom
  • 1,822
  • 4
  • 25
  • 43

2 Answers2

27

Great question.

$inlinecount out of the box only works when you're sending back OData responses. The reason for this is that OData defines special fields in the data that XML and JSON don't define. So in OData a response might look like this:

{
  "odata.metadata":"http://localhost:12345/odata/$metadata#Customers",
  "odata.count":"4",
  "value":[ ... ]
}

Notice the wrapper with the "odata.count" property. This is different from the way the default XML and JSON formatters write out data because they don't have wrappers for this additional information. So other formatters are by default unchanged.

Now you have several options:

You could choose to use the OData format. For this, you'll want to follow the instructions in this blog post:

http://blogs.msdn.com/b/webdev/archive/2013/01/29/getting-started-with-asp-net-webapi-odata-in-3-simple-steps.aspx

You could also choose to instead return a PageResult<T>. This looks like this:

public PageResult<Customer> Get(ODataQueryOptions<Customer> queryOptions)
{
    IQueryable results = queryOptions.ApplyTo(_customers.AsQueryable());
    return new PageResult<Customer>(results as IEnumerable<Customer>, Request.GetNextPageLink(), Request.GetInlineCount());
}

This should work fine for OData, JSON, and XML by adding a wrapper object for XML and JSON that can include the Count and the next page link.

Youssef Moussaoui
  • 12,187
  • 2
  • 41
  • 37
  • 1
    From reading the MS docs on this http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options, it sounds like it should work out of the box, like filtering and sorting? – tom Mar 15 '13 at 15:47
  • 3
    The doc is wrong in this case. The difference is that filtering doesn't need to change the "shape" of the data, but adding an inline count and a next page link do. So filtering works out of the box for other formatters, but $inlinecount doesn't. – Youssef Moussaoui Mar 15 '13 at 16:04
  • Take a look at breezejs.com. The latest version works with all of the MS OData syntax and all supports inlinecount, select and expand. – Jay Traband Mar 15 '13 at 18:35
  • Hi @YoussefMoussaoui, I am returning a `PageResult` exactly as you specified here, yet i'm still just receiving a `List` without the odata count, next page link etc. in my JSON response, any ideas?? My PageResult is a custom POCO named `ListOfProduct`, as I expose a different set of properties to that of my `Product` API POCO object. – GONeale Apr 19 '13 at 02:02
  • 2
    @GONeale Request.GetNextPageLink() and GetInlineCount() are both null by default. GetInlineCount() will contain the count if the request uri has '?$inlinecount=allpages' in the query string, and GetNextPageLink() will contain a next page link only if you set ODataQuerySettings.PageSize when you call ApplyTo (use the overload that takes a query settings object) and if there are more results than the page size that you set. Does that make sense? – Youssef Moussaoui Apr 23 '13 at 00:56
  • It does, but it turns out my issue was the fact I was using ServiceStack.Text, instead of standard NewtsonSoft.Json formatter. I don't know why. https://aspnetwebstack.codeplex.com/workitem/1003 – GONeale Apr 24 '13 at 04:22
  • 3
    Fyi, the link you in your answer (Getting Started with Odata in 3 simple steps) implement ODataController / EntitySetController which still have the sample problem raised by the OP. $inlinecount still not working. – stack247 Jun 13 '13 at 23:00
  • Returning PageResult worked great for me, considering I have to use ODataQueryOptions anyway because I have a more advance situation. In other words, the simpler option of just using an attribute wouldn't work for me. – Josh Mouch Oct 14 '14 at 13:27
10

In OData v4, $inlinecount=allpages has been replaced by $count=true.

$count just works with returning an IQueryable in the recent versions of aspnet mvc.

Jim Argeropoulos
  • 413
  • 1
  • 5
  • 11