OData $ count does not work with EntitySetController <TEntity, TKey> in web api 4

I use the EntitySetController to create the oData web api controller, and everything works fine, except to get the total number of entries.

The controller is defined as follows:

public class MyODataController : EntitySetController<Entity1, int> where TEntity : class { public override IQueryable<Entity1> Get() { return EntityDatabase.Get(); } } 

when I call the account through:

 http://localhost:44789/oData/MyOData/$count 

I get the error: Invalid action detected. "$ count" is not an action that can be associated with "Collection ([Entity1 Nullable = False])".

+6
source share
5 answers

Unfortunately, the web API does not support counting $ count out of the box, although this should be in a future version. In the meantime, you can still add support by specifying these classes:

 public class CountODataRoutingConvention : EntitySetRoutingConvention { public override string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext, ILookup<string, HttpActionDescriptor> actionMap) { if (controllerContext.Request.Method == HttpMethod.Get && odataPath.PathTemplate == "~/entityset/$count") { if (actionMap.Contains("GetCount")) { return "GetCount"; } } return null; } } public class CountODataPathHandler : DefaultODataPathHandler { protected override ODataPathSegment ParseAtEntityCollection(IEdmModel model, ODataPathSegment previous, IEdmType previousEdmType, string segment) { if (segment == "$count") { return new CountPathSegment(); } return base.ParseAtEntityCollection(model, previous, previousEdmType, segment); } } public class CountPathSegment : ODataPathSegment { public override string SegmentKind { get { return "$count"; } } public override IEdmType GetEdmType(IEdmType previousEdmType) { return EdmCoreModel.Instance.FindDeclaredType("Edm.Int32"); } public override IEdmEntitySet GetEntitySet(IEdmEntitySet previousEntitySet) { return previousEntitySet; } public override string ToString() { return "$count"; } } 

Register with MapODataRoute:

 IList<IODataRoutingConvention> routingConventions = ODataRoutingConventions.CreateDefault(); routingConventions.Insert(0, new CountODataRoutingConvention()); config.Routes.MapODataRoute("OData", "odata", GetModel(), new CountODataPathHandler(), routingConventions); 

And in your controller, adding this method:

 public HttpResponseMessage GetCount(ODataQueryOptions<TEntity> queryOptions) { IQueryable<TEntity> queryResults = queryOptions.ApplyTo(Get()) as IQueryable<TEntity>; int count = queryResults.Count(); HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK); response.Content = new StringContent(count.ToString(), Encoding.UTF8, "text/plain"); return response; } 

In order not to copy GetCount () for each controller, you can define a base class that comes from the EntitySetController that defines GetCount.

+14
source

If you use the following:

 http://localhost:44789/oData/MyOData?$inlinecount=allpages 

then the total amount will be included in your refund.

+7
source

The latest Web API 2.2 package for OData v4.0 has support for counting $.

+2
source

local: .... / $ inlinecount = AllPages & $ skip = 0 & $ top = 0 I think this is a dough. You do not need to add more code.

+2
source

One option is to use $ top = 0 in combination with $ inlinecount = allpages. A bit of a workaround, but I believe that it works great, and I'd rather return an object than a single integer. This works fine with a filter:

 http://localhost:44789/oData/MyOData?$filter=MyFilter&$top=1&$inlinecount=allpages 
0
source

Source: https://habr.com/ru/post/945416/


All Articles