OData v4 Web API响应中的项目计数

时间:2014-12-18 11:12:04

标签: count odata asp.net-web-api

如何返回OData v4 HTTP响应中的项目数?

我需要这个数字来分页,所以它应该是过滤后的项目数,但是在'skip'和'top'之前。

我已经尝试在url(https://damienbod.wordpress.com/2014/06/13/web-api-and-odata-v4-queries-functions-and-attribute-routing-part-2/ - “$ count的示例”)的查询选项中传递'$ inlinecount = allpages'和'$ count = true'参数,但我的WebAPI响应总是只有查询结果(集合) - 整个响应看起来像:

[
    {
        "Name":"name1", 
        "age":5
    }, 
    {
        "Name":"name2", 
        "age":15
    }
]

回复中没有类似“odata.count”的内容。

我还尝试在我的WebAPI控制器操作中返回PageResult而不是IQueryable(如此处所述:http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options#server-paging),但不推荐使用Request.GetInlineCount(),其值始终为null。

有什么想法吗?

[更新]我刚刚发现了同样的问题:WebApi with Odata NextPage and Count not appearing in the JSON response我删除了[EnableQuery]属性,现在我的回复如下:

{
    "Items":
    [
        {
            "Name":"name1", 
            "age":5
        }, 
        {
            "Name":"name2", 
            "age":15
        }
    ],
    "NextPageLink":null,
    "Count":null
}

但仍然“Count”始终为null。 :(

<小时/> 编辑:调试并在我的控制器中的Request属性中搜索计数值后,我发现正确的Count值位于名为“System.Web.OData.TotalCount”的属性中。所以现在我从该请求属性中提取此值,我的控制器看起来像这样:

public PageResult<People> Get(ODataQueryOptions<People> queryOptions)
{
    var query = _context.People.OrderBy(x => x.SomeProperty);
    var queryResults = (IQueryable<People>)queryOptions.ApplyTo(query);
    long cnt = 0;
    if (queryOptions.Count != null)
        cnt = long.Parse(Request.Properties["System.Web.OData.TotalCount"].ToString());

    return new PageResult<People>(queryResults, null, cnt);
}

它工作正常,但我仍然不知道为什么我必须使用这样的解决方法。

4 个答案:

答案 0 :(得分:8)

供将来参考(OData v4):

首先$inlinecount OData v4不支持$count=true,因此您应该使用ApiController

其次,如果你有一个正常的IQueryable<T>,并且你返回类似count的类型,这就是你可以将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)); } 属性附加到返回结果的方式:

ApiController
  

注意:   count s不支持OData功能   不能包含$metadataApiController之类的内容。如果你选择   使用简单count上面的方法是你应该使用的方式   返回ODataController属性。

要完全支持OData功能,您应该通过以下方式实现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); } }

<强> PeopleController.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;
}

App_Start \ WebApiConfig.cs

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

然后以这种方式访问​​您的OData Api(示例):

编码的uri:

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

解码:

CREATE TABLE public.portfolio (
  id INTEGER PRIMARY KEY NOT NULL DEFAULT nextval('portfolio_id_seq'::regclass),
  name CHARACTER VARYING(80) NOT NULL,
  path CHARACTER VARYING(80) NOT NULL
);
CREATE UNIQUE INDEX portfolio_path_key ON portfolio USING BTREE ("4");
CREATE UNIQUE INDEX portfolio_name_key ON portfolio USING BTREE (name);

参考文献:

答案 1 :(得分:2)

这就是我使用的oData v4:

Request.ODataProperties().NextLink, 

Request.ODataProperties().TotalCount

答案 2 :(得分:0)

请您在https://github.com/OData/ODataSamples/blob/master/Scenarios/TripPin查看示例服务TripPin web api实施。您可以按照机场控制器中的代码和代码http://services.odata.org/TripPinWebApiService/Airports的服务进行操作?$ count = true可以正确返回计数。

答案 3 :(得分:0)

这也可以通过动作过滤器来实现:

/// <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;               
        }           
    }
}

自定义PageResult类是:

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

用法:

[PagedResult]
[EnableQuery()]