Items count in OData v4 WebAPI response

前端 未结 4 1818
野性不改
野性不改 2021-02-14 03:47

How to return number of items in OData v4 HTTP response?

I need this number to pagination, so it should be number of items after filtering, but before \'skip\' and \'top

相关标签:
4条回答
  • 2021-02-14 04:10

    This can also be achieved by an action filter:

    /// <summary>
    /// Use this attribute whenever total number of records needs to be returned in the response in order to perform paging related operations at client side.
    /// </summary>
    public class PagedResultAttribute: ActionFilterAttribute
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="actionExecutedContext"></param>
        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {
            base.OnActionExecuted(actionExecutedContext);
            if (actionExecutedContext.Response != null)
            {                
                dynamic responseContent=null;
                if (actionExecutedContext.Response.Content != null)
                    responseContent = actionExecutedContext.Response.Content.ReadAsAsync<dynamic>().Result;
                var count = actionExecutedContext.Response.RequestMessage.ODataProperties().TotalCount;
                var res = new PageResult<dynamic>() {TotalCount=count,Items= responseContent };
    
                HttpResponseMessage message = new HttpResponseMessage();
                message.StatusCode = actionExecutedContext.Response.StatusCode;
    
                var strMessage = new StringContent(JsonConvert.SerializeObject(res), Encoding.UTF8, "application/json");
                message.Content = strMessage;
                actionExecutedContext.Response = message;               
            }           
        }
    }
    

    And the custom PageResult class is:

    public class PageResult<T>
    {      
        public long? TotalCount { get; set; }
        public T Items { get; set; }
    }
    

    Usage:

    [PagedResult]
    [EnableQuery()]  
    
    0 讨论(0)
  • 2021-02-14 04:25

    For future reference (OData v4):

    First of all $inlinecount it's not supported in OData v4 so you should use $count=true instead.

    Second, if you have a normal ApiController and you return a type like IQueryable<T> this is the way you can attach a count property to the returned result:

    using System.Web.OData;
    using System.Web.OData.Query;
    using System.Web.OData.Extensions;
    
    //[EnableQuery] // -> If you enable globally queries does not require this decorator!
    public IHttpActionResult Get(ODataQueryOptions<People> queryOptions)
    {
        var query = _peopleService.GetAllAsQueryable(); //Abstracted from the implementation of db access. Just returns IQueryable<People>
        var queryResults = (IQueryable<People>)queryOptions.ApplyTo(query);
        return Ok(new PageResult<People>(queryResults, Request.ODataProperties().NextLink, Request.ODataProperties().TotalCount));
    }
    

    Note: OData functionality does not supported by ApiControllers so you cannot have things like count or $metadata. If you choose to use simple ApiController the way above is the one you should use to return a count property.


    For a full support of OData functionality you should implement a ODataController the following way:

    PeopleController.cs

    using System.Web.OData;
    using System.Web.OData.Query;
    
    public class PeopleController : ODataController
    {
        [EnableQuery(PageSize = 10, AllowedQueryOptions = AllowedQueryOptions.All)]
        public IHttpActionResult Get()
        {
            var res = _peopleService.GetAllAsQueryable();
            return Ok(res);
        }
    }
    

    App_Start \ WebApiConfig.cs

    public static void ConfigureOData(HttpConfiguration config)
    {
        //OData Models
        config.MapODataServiceRoute(routeName: "odata", routePrefix: null, model: GetEdmModel(), batchHandler: new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer));
        config.EnsureInitialized();
    }
    
    private static IEdmModel GetEdmModel()
    {
        var builder = new ODataConventionModelBuilder
        {
            Namespace = "Api",
            ContainerName = "DefaultContainer"
        };
        builder.EntitySet<People>("People").EntityType.HasKey(item => item.Id); //I suppose the returning list have a primary key property(feel free to replace the Id key with your key like email or whatever)
        var edmModel = builder.GetEdmModel();
        return edmModel;
    }
    

    Then you access your OData Api this way (example):

    encoded uri:

    http://localhost:<portnumber>/People/?%24count=true&%24skip=1&%24top=3
    

    decoded:

    http://localhost:<portnumber>/People/?$count=true&$skip=1&$top=3
    

    References:

    • How to Use Web API OData to Build an OData V4 Service without Entity Framework
    • Web API OData V4 Pitfalls
    • Create an OData v4 Endpoint Using ASP.NET Web API 2.2
    0 讨论(0)
  • 2021-02-14 04:32

    That's what I am using with oData v4:

    Request.ODataProperties().NextLink, 
    
    Request.ODataProperties().TotalCount
    
    0 讨论(0)
  • 2021-02-14 04:37

    Will you please take a look at the sample service TripPin web api implementation at https://github.com/OData/ODataSamples/blob/master/Scenarios/TripPin. You can follow the code in Airports controller and the service with the code http://services.odata.org/TripPinWebApiService/Airports?$count=true can return the count correctly.

    0 讨论(0)
提交回复
热议问题