本文转自:https://docs.microsoft.com/en-us/aspnet/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options

by Mike Wasson

OData defines parameters that can be used to modify an OData query. The client sends these parameters in the query string of the request URI. For example, to sort the results, a client uses the $orderby parameter:

http://localhost/Products?$orderby=Name

The OData specification calls these parameters query options. You can enable OData query options for any Web API controller in your project — the controller does not need to be an OData endpoint. This gives you a convenient way to add features such as filtering and sorting to any Web API application.

Before enabling query options, please read the topic OData Security Guidance.

Enabling OData Query Options

Web API supports the following OData query options:

Option Description
$expand Expands related entities inline.
$filter Filters the results, based on a Boolean condition.
$inlinecount Tells the server to include the total count of matching entities in the response. (Useful for server-side paging.)
$orderby Sorts the results.
$select Selects which properties to include in the response.
$skip Skips the first n results.
$top Returns only the first n the results.

To use OData query options, you must enable them explicitly. You can enable them globally for the entire application, or enable them for specific controllers or specific actions.

To enable OData query options globally, call EnableQuerySupport on the HttpConfiguration class at startup:

C#Copy
public static void Register(HttpConfiguration config)
{
// ... config.EnableQuerySupport(); // ...
}

The EnableQuerySupport method enables query options globally for any controller action that returns an IQueryable type. If you don't want query options enabled for the entire application, you can enable them for specific controller actions by adding the [Queryable] attribute to the action method.

C#Copy
public class ProductsController : ApiController
{
[Queryable]
IQueryable<Product> Get() {}
}

Example Queries

This section shows the types of queries that are possible using the OData query options. For specific details about the query options, refer to the OData documentation at www.odata.org.

For information about $expand and $select, see Using $select, $expand, and $value in ASP.NET Web API OData.

Client-Driven Paging

For large entity sets, the client might want to limit the number of results. For example, a client might show 10 entries at a time, with "next" links to get the next page of results. To do this, the client uses the $top and $skip options.

http://localhost/Products?$top=10&$skip=20

The $top option gives the maximum number of entries to return, and the $skip option gives the number of entries to skip. The previous example fetches entries 21 through 30.

Filtering

The $filter option lets a client filter the results by applying a Boolean expression. The filter expressions are quite powerful; they include logical and arithmetic operators, string functions, and date functions.

Return all products with category equal to "Toys". http://localhost/Products?$filter=Category eq 'Toys'
Return all products with price less than 10. http://localhost/Products?$filter=Price lt 10
Logical operators: Return all products where price >= 5 and price <= 15. http://localhost/Products?$filter=Price ge 5 and Price le 15
String functions: Return all products with "zz" in the name. http://localhost/Products?$filter=substringof('zz',Name)
Date functions: Return all products with ReleaseDate after 2005. http://localhost/Products?$filter=year(ReleaseDate) gt 2005

Sorting

To sort the results, use the $orderby filter.

Sort by price. http://localhost/Products?$orderby=Price
Sort by price in descending order (highest to lowest). http://localhost/Products?$orderby=Price desc
Sort by category, then sort by price in descending order within categories. http://localhost/odata/Products?$orderby=Category,Price desc

Server-Driven Paging

If your database contains millions of records, you don't want to send them all in one payload. To prevent this, the server can limit the number of entries that it sends in a single response. To enable server paging, set the PageSize property in the Queryable attribute. The value is the maximum number of entries to return.

C#Copy
[Queryable(PageSize=10)]
public IQueryable<Product> Get()
{
return products.AsQueryable();
}

If your controller returns OData format, the response body will contain a link to the next page of data:

JSONCopy
{
"odata.metadata":"http://localhost/$metadata#Products",
"value":[
{ "ID":1,"Name":"Hat","Price":"15","Category":"Apparel" },
{ "ID":2,"Name":"Socks","Price":"5","Category":"Apparel" },
// Others not shown
],
"odata.nextLink":"http://localhost/Products?$skip=10"
}

The client can use this link to fetch the next page. To learn the total number of entries in the result set, the client can set the $inlinecount query option with the value "allpages".

http://localhost/Products?$inlinecount=allpages

The value "allpages" tells the server to include the total count in the response:

JSONCopy
{
"odata.metadata":"http://localhost/$metadata#Products",
"odata.count":"50",
"value":[
{ "ID":1,"Name":"Hat","Price":"15","Category":"Apparel" },
{ "ID":2,"Name":"Socks","Price":"5","Category":"Apparel" },
// Others not shown
]
}
Note

Next-page links and inline count both require OData format. The reason is that OData defines special fields in the response body to hold the link and count.

For non-OData formats, it is still possible to support next-page links and inline count, by wrapping the query results in a PageResult<T> object. However, it requires a bit more code. Here is an example:

C#Copy
public PageResult<Product> Get(ODataQueryOptions<Product> options)
{
ODataQuerySettings settings = new ODataQuerySettings()
{
PageSize = 5
}; IQueryable results = options.ApplyTo(_products.AsQueryable(), settings); return new PageResult<Product>(
results as IEnumerable<Product>,
Request.GetNextPageLink(),
Request.GetInlineCount());
}

Here is an example JSON response:

JSONCopy
{
"Items": [
{ "ID":1,"Name":"Hat","Price":"15","Category":"Apparel" },
{ "ID":2,"Name":"Socks","Price":"5","Category":"Apparel" }, // Others not shown ],
"NextPageLink": "http://localhost/api/values?$inlinecount=allpages&$skip=10",
"Count": 50
}

Limiting the Query Options

The query options give the client a lot of control over the query that is run on the server. In some cases, you might want to limit the available options for security or performance reasons. The [Queryable] attribute has some built in properties for this. Here are some examples.

Allow only $skip and $top, to support paging and nothing else:

C#Copy
[Queryable(AllowedQueryOptions=
AllowedQueryOptions.Skip | AllowedQueryOptions.Top)]

Allow ordering only by certain properties, to prevent sorting on properties that are not indexed in the database:

C#Copy
[Queryable(AllowedOrderByProperties="Id")] // comma-separated list of properties

Allow the "eq" logical function but no other logical functions:

C#Copy
[Queryable(AllowedLogicalOperators=AllowedLogicalOperators.Equal)]

Do not allow any arithmetic operators:

C#Copy
[Queryable(AllowedArithmeticOperators=AllowedArithmeticOperators.None)]

You can restrict options globally by constructing a QueryableAttribute instance and passing it to the EnableQuerySupport function:

C#Copy
var queryAttribute = new QueryableAttribute()
{
AllowedQueryOptions = AllowedQueryOptions.Top | AllowedQueryOptions.Skip,
MaxTop = 100
}; config.EnableQuerySupport(queryAttribute);

Invoking Query Options Directly

Instead of using the [Queryable] attribute, you can invoke the query options directly in your controller. To do so, add an ODataQueryOptionsparameter to the controller method. In this case, you don't need the [Queryable] attribute.

C#Copy
public IQueryable<Product> Get(ODataQueryOptions opts)
{
var settings = new ODataValidationSettings()
{
// Initialize settings as needed.
AllowedFunctions = AllowedFunctions.AllMathFunctions
}; opts.Validate(settings); IQueryable results = opts.ApplyTo(products.AsQueryable());
return results as IQueryable<Product>;
}

Web API populates the ODataQueryOptions from the URI query string. To apply the query, pass an IQueryable to the ApplyTo method. The method returns another IQueryable.

For advanced scenarios, if you do not have an IQueryable query provider, you can examine the ODataQueryOptions and translate the query options into another form. (For example, see RaghuRam Nadiminti's blog post Translating OData queries to HQL, which also includes a sample.)

Query Validation

The [Queryable] attribute validates the query before executing it. The validation step is performed in the QueryableAttribute.ValidateQuerymethod. You can also customize the validation process.

Also see OData Security Guidance.

First, override one of the validator classes that is defined in the Web.Http.OData.Query.Validators namespace. For example, the following validator class disables the 'desc' option for the $orderby option.

C#Copy
public class MyOrderByValidator : OrderByQueryValidator
{
// Disallow the 'desc' parameter for $orderby option.
public override void Validate(OrderByQueryOption orderByOption,
ODataValidationSettings validationSettings)
{
if (orderByOption.OrderByNodes.Any(
node => node.Direction == OrderByDirection.Descending))
{
throw new ODataException("The 'desc' option is not supported.");
}
base.Validate(orderByOption, validationSettings);
}
}

Subclass the [Queryable] attribute to override the ValidateQuery method.

C#Copy
public class MyQueryableAttribute : QueryableAttribute
{
public override void ValidateQuery(HttpRequestMessage request,
ODataQueryOptions queryOptions)
{
if (queryOptions.OrderBy != null)
{
queryOptions.OrderBy.Validator = new MyOrderByValidator();
}
base.ValidateQuery(request, queryOptions);
}
}

Then set your custom attribute either globally or per-controller:

C#Copy
// Globally:
config.EnableQuerySupport(new MyQueryableAttribute()); // Per controller:
public class ValuesController : ApiController
{
[MyQueryable]
public IQueryable<Product> Get()
{
return products.AsQueryable();
}
}

If you are using ODataQueryOptions directly, set the validator on the options:

C#Copy
public IQueryable<Product> Get(ODataQueryOptions opts)
{
if (opts.OrderBy != null)
{
opts.OrderBy.Validator = new MyOrderByValidator();
} var settings = new ODataValidationSettings()
{
// Initialize settings as needed.
AllowedFunctions = AllowedFunctions.AllMathFunctions
}; // Validate
opts.Validate(settings); IQueryable results = opts.ApplyTo(products.AsQueryable());
return results as IQueryable<Product>;
}
 

[转]Supporting OData Query Options in ASP.NET Web API 2的更多相关文章

  1. Create an OData v4 Endpoint Using ASP.NET Web API 2.2(使用ASP.NET Web API 2.2创建OData v4端点)

    开放数据协议Open Data Protocol(OData)是web的一种数据存取协议,OData通过设置CRUD操作(Create创建.Read读取.Update更新,Delete删除)提供一种统 ...

  2. OData services入门----使用ASP.NET Web API描述

    http://www.cnblogs.com/muyoushui/archive/2013/01/27/2878844.html ODate 是一种应用层协议,设计它的目的在于提供一组通过HTTP的交 ...

  3. 杂项:ASP.NET Web API

    ylbtech-杂项:ASP.NET Web API ASP.NET Web API 是一种框架,用于轻松构建可以访问多种客户端(包括浏览器和移动设备)的 HTTP 服务. ASP.NET Web A ...

  4. [转]ASP.NET Web API对OData的支持

    http://www.cnblogs.com/shanyou/archive/2013/06/11/3131583.html 在SOA的世界中,最重要的一个概念就是契约(contract).在云计算的 ...

  5. [转]ASP.NET web API 2 OData enhancements

    本文转自:https://www.pluralsight.com/blog/tutorials/asp-net-web-api-2-odata-enhancements Along with the ...

  6. [转]Getting started with ASP.NET Web API OData in 3 simple steps

    本文转自:https://blogs.msdn.microsoft.com/webdev/2013/01/29/getting-started-with-asp-net-web-api-odata-i ...

  7. [转]Using $select, $expand, and $value in ASP.NET Web API 2 OData

    本文转自:https://docs.microsoft.com/en-us/aspnet/web-api/overview/odata-support-in-aspnet-web-api/using- ...

  8. 对一个前端AngularJS,后端OData,ASP.NET Web API案例的理解

    依然chsakell,他写了一篇前端AngularJS,后端OData,ASP.NET Web API的Demo,关于OData在ASP.NET Web API中的正删改查没有什么特别之处,但在前端调 ...

  9. ASP.NET Web API基于OData的增删改查,以及处理实体间关系

    本篇体验实现ASP.NET Web API基于OData的增删改查,以及处理实体间的关系. 首先是比较典型的一对多关系,Supplier和Product. public class Product { ...

随机推荐

  1. ajax 跨域访问的解决方案

    ajax 跨域访问的解决方案 一.什么是跨域: 1.什么样的请求属于跨域: 域名,端口有任何一个不相同都属于跨域: 二.跨域的常用几种解决方案: 1.jsonp: 2.iframe: 3.webcon ...

  2. SPOJ distinct subtrings

    题目链接:戳我 后缀自动机模板? 求不同的子串数量. 直接\(\sum t[i].len-t[t[i].ff].len\)即可 代码如下: #include<iostream> #incl ...

  3. Linux/Unix监控工具vmstat命令

    注:内容来之网络 vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况.这个命令是我查看Li ...

  4. python字符串的切片

    # 字符串的切片 """ (5)字符串的切片 :切片就是截取字符串的意思 (1)语法 =>字符串[::] 完整格式:[开始索引:结束索引:间隔值 (2)[:结束索引 ...

  5. “全栈2019”Java第三十九章:构造函数、构造方法、构造器

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  6. windows server2008 r2安装DNS服务器

    1.开始->管理工具->服务器管理器 2.角色->添加角色 3.服务器角色->DNS服务器 4.一直点击下一步,直至安装完成. (确认步骤时会提示,可能会需要重启服务器) 安装 ...

  7. php中模拟post,get请求和接受请求详细讲解

    在php中我们经常用到curl拓展来进行模拟post.get请求,下面就来具体说说怎么模拟: 一.首先模拟post请求: function http_post_data($url, $query_da ...

  8. Mockplus原型设计工具介绍

    一.原型设计工具简介 Mockplus (摹客)  一种快速原型设计工具 官网提供四个平台的下载,通用性很广. 二.原型设计的模板 Mockplus可以为设计者提供以下几种模板 其中在“手机”模板里, ...

  9. Django项目创建与管理

    1.主题 这部分教程主要介绍如何通过Pycharm创建.管理.运行一个Django工程.对于Django模块的相关知识大家可以参考Python社区. 2.准备环境 Django版本为2.0或更高 Py ...

  10. 解决NTFS文件系统下的文件/文件夹属性中没有安全选项卡的问题

    注册表项: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer 键:NoSecurityTab ...