OData v4 WebAPI 响应中的项目计数

Posted

技术标签:

【中文标题】OData v4 WebAPI 响应中的项目计数【英文标题】:Items count in OData v4 WebAPI response 【发布时间】:2015-02-17 03:49:24 【问题描述】:

如何在 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/ - "Example of $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

但“计数”始终为空。 :(


编辑:在我的控制器的请求属性中调试和搜索计数值后,我发现正确的计数值位于名为“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);

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

【问题讨论】:

如果您可以附加您为获取实体集而编写的控制器方法会很有帮助。 【参考方案1】:

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

【讨论】:

它适用于 TripPin,但它仍然无法在我的应用程序中运行。 :( 在我的控制器的请求属性中调试和搜索计数值后,我发现正确的计数值在名为“System.Web.OData.TotalCount”的属性中。所以现在我从该请求属性中提取这个值:@ 987654323@(有关此解决方法的更多信息在我上面编辑的帖子中) 是否可以在服务器级别设置默认的$count=true?【参考方案2】:

这就是我在 oData v4 中使用的:

Request.ODataProperties().NextLink, 

Request.ODataProperties().TotalCount

【讨论】:

你能提供一个更详细的例子吗?【参考方案3】:

供将来参考(OData v4):

首先$inlinecount不支持OData v4,所以你应该改用$count=true

其次,如果你有一个普通的ApiController 并且你返回一个像IQueryable&lt;T&gt; 这样的类型,你可以将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));

注意: ApiControllers 不支持 OData 功能,因此您 不能有count$metadata 之类的东西。如果你选择 使用简单的ApiController 上面的方式是你应该使用的方式 返回 count 属性。


要完全支持 OData 功能,您应该通过以下方式实现 ODataController

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;

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

编码的 uri:

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

解码:

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

参考资料:

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

【讨论】:

如需进一步参考 ASP.NET Core,可在Request.ODataFeature().NextLink找到下一个链接【参考方案4】:

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

/// <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()]  

【讨论】:

以上是关于OData v4 WebAPI 响应中的项目计数的主要内容,如果未能解决你的问题,请参考以下文章

WebAPI 2.2 中没有命名空间的 OData v4 自定义函数

Web Api 2.2 OData V4 函数路由

WebAPI OData v4 查询不是异步的?

如何只获取没有价值的 Odata.Count

使用 OData 响应 Owin Self-Host 忽略 Web Api 中的 Null 属性/值

我们可以使用OData客户端为syncfusion网格创建我们的请求但是使用正常响应(Reqular WebAPI)