• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
皇图霸业谈笑间
更高、更快、更强
博客园    首页    新随笔    联系   管理    订阅  订阅
ASP.NET Web API对OData的支持

在SOA的世界中,最重要的一个概念就是契约(contract)。在云计算的世界中,有关通信的最重要的概念也是契约。XML具有强大对数据的描 述能力,Atom格式和AtomPub都建立在XML之上,在Google和微软的推动下,也已经成为标准。但是,Atom/AtomPub和ODBC /OLEDB这样的真正数据交互协议相比较,还有着根本上的欠缺:缺乏数据类型的具体描述,降低了交互性能。缺乏对数据查询的控制能力,比如返回特定的数 据集合的区间,或者说分页能力等等。微软基于EDM模型释出了:OData,这里也可以看出Entity Framework对于NHibernate这样的ORM的工具不同的战略考虑。

在.NET中,早期是用Remoting/Webservice来处理所有程序间的通信,从.NET 3.0开始使用WCF统一了通信模型,ASP.NET MVC4的推出,形成大的One ASP.NET战略,增加了WebAPI和SingalR作为通信服务:

oneaspnet

开放数据协议(OData)是 一个查询和更新数据的Web协议。OData应用了web技术如HTTP、Atom发布协议(AtomPub)和JSON等来提供对不同应用程序,服务和 存储的信息访问。除了提供一些基本的操作(像增删改查),也提供了一些高级的操作类似过滤数据和实体的导航。OData扩展了上述的协议但是不是取代他 们。他可以被XML(ATOM)或者JSON取代但是OData的重要在于它符合REST原则。在某种意义上,它建立在'简单'的REST HTTP 服务上,并且有着清晰的目标——简化和标准化我们操作和查询数据的方式。如果你过去在给你的REST服务创建搜索、过滤、或者分页API的时候感觉很麻 烦,那么OData将是一个不错的选择。

目前很多接口,无论是基于SOAP、REST还是别的都在交换数据时使用不同的模式。这种方法随后返回一大堆客户记录。你随后可以决定添加分页支持。你希望将结果捆绑在一个网格中,并对数据排序。最后,决定想要查询的东西,通过比如邮政编码来查询。

  首先是,没有创建泛型客户端的途径,而这些和API紧密联系,因为它不知道参数的顺序或者模式被使用的顺序。因为不能创建泛型客户端,你必须为 每一个你希望暴露的API创建客户端。简单的基础HTTP API可以实现,但其仍旧很昂贵。逐渐增多的多样性客户端与这些API通信加剧了这个问题。

  这种模式的第二个问题是它迫使开发人员进行很艰难的权衡。我应该暴露多少个查询?你必要在暴露每一个你能想到内容和少暴露一些,从而削弱服务之 间协调。前者导致API 需要管理的界面的增加,后者会导致我们通常所说的“数据竖井”,也就是关键数据在特定模式中锁定,其他应用不能够简单应用,因为它没有以一种需要的方式暴 露给这个应用。服务试图比单一应用要获得更长久一些,因此你需要以一种方式设计API,使其能够持久,所以如果你发现你需要添加服务借口的新版本可不太好 办,比如创建新的客户端。在很多案例中,服务开发者和客户端开发者并不是同一个人,因而改变服务接口简直就是不可能的事情。

  通过OData,我们采取不同的方法。取代创建客户端签名和参数,我们问了如下的问题:“如果你将数据集作为源处理,并为最频繁使用的操作定义 模式,像查询、分页、排序、新建、删除和更新,服务接口因该是什么样子的?” 这也就导致OData的创建。OData解决了上面提到的关键服务设计挑战。

我们来看一下启用OData协议的WebAPI的例子:

http://localhost:8080/api/meetings

http://localhost:8080/api/meetings?$filter=(Leader eq ‘Mark Nichols’)

http://localhost:8080/api/meetings?$top=2

http://localhost:8080/api/meetings?$filter=MeetingDate eq datetime’2013-01-17′

在项目中启用OData查询,首先在项目加入Web API的OData支持,通过Nuget 查找ASP.NET Web API OData

image

Microsoft.AspNet.WebApi.OData提供可一系列的类扩展了Web API。

在项目中启用OData查询:

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

如果是使用self-hosting方式,在HttpSelfHostConfiguration上启用EnableQuerySupport():

var config = new HttpSelfHostConfiguration(new Uri("http://localhost:8080"));
config.EnableQuerySupport();

然后将Controls上的Action的返回结果更改为IQueryable,并打上标签[Queryable()]:

        // GET api/Meeting
        [Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
        public IQueryable<Meeting> Get()
        {
            return _scheduledMeetings.AsQueryable();
        }
需要添加 using System.Web.Http.OData.Query; 我们下AllowedQueryOptions 看支持那些OData的类型:
   // Summary:
    //     OData query options to allow for querying.
    [Flags]
    public enum AllowedQueryOptions
    {
        // Summary:
        //     A value that corresponds to allowing no query options.
        None = 0,
        //
        // Summary:
        //     A value that corresponds to allowing the $filter query option.
        Filter = 1,
        //
        // Summary:
        //     A value that corresponds to allowing the $expand query option.
        Expand = 2,
        //
        // Summary:
        //     A value that corresponds to allowing the $select query option.
        Select = 4,
        //
        // Summary:
        //     A value that corresponds to allowing the $orderby query option.
        OrderBy = 8,
        //
        // Summary:
        //     A value that corresponds to allowing the $top query option.
        Top = 16,
        //
        // Summary:
        //     A value that corresponds to allowing the $skip query option.
        Skip = 32,
        //
        // Summary:
        //     A value that corresponds to allowing the $inlinecount query option.
        InlineCount = 64,
        //
        // Summary:
        //     A value that corresponds to the default query options supported by System.Web.Http.QueryableAttribute.
        Supported = 121,
        //
        // Summary:
        //     A value that corresponds to allowing the $format query option.
        Format = 128,
        //
        // Summary:
        //     A value that corresponds to allowing the $skiptoken query option.
        SkipToken = 256,
        //
        // Summary:
        //     A value that corresponds to allowing all query options.
        All = 511,
    }

上面有个Format,我们可以进行格式化输出。使用下面的代码对Format进行数据格式化:

public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
           

config.Formatters.JsonFormatter.AddQueryStringMapping("$format", "json", "application/json"); config.Formatters.XmlFormatter.AddQueryStringMapping("$format", "xml", "application/xml");

            config.EnableQuerySupport();
        }

另外需要注意的一点是OData查询是大小写敏感的。

我将使用Fiddler去测试这个服务

image

image

我们没有写任何一个特别的逻辑去支持这些功能,全部都由框架来提供的。是不是OData为你的搜索、过滤、或者分页API的时候提供了一个很好的选项。

然而,如果要向组织外部公开可查询的操作,可以利用查询验证添加一个保护层以保护我们的服务。微软的程序经理Hongmei Ge介绍了几种在Queryable API中添加验证的场景。

Hongmei指出的第一个场景是,使用AllowedQueryOptions属性,只允许包含$top和$skip的查询。如下所示:

[Queryable(AllowedQueryOptions = AllowedQueryOptions.Skip | AllowedQueryOptions.Top)]
public IQueryable Get(int projectId)

还可以使用MaxTop和MaxSkip属性将$top和$skip的最大值限制在100和200:

[Queryable(MaxTop = 100)]
public IQueryable Get(int projectId)

[Queryable(MaxSkip = 200)]
public IQueryable Get(int projectId)

利用AllowedOrderByProperties,可以将结果按Id属性排序,因为按其他属性排序可能会很慢:

[Queryable(AllowedOrderByProperties = "Id")]
public IQueryable Get(int projectId)

如果允许客户端在$filter内使用相等比较,应该使用AllowedLogicalOperators对其进行验证:

[Queryable(AllowedLogicalOperators = AllowedLogicalOperators.Equal)]
public IQueryable Get(int projectId)

将AllowedArithmeticOperators设置为None,就可以关闭$filter中的算术操作:

[Queryable(AllowedArithmeticOperators = AllowedArithmeticOperators.None)]
public IQueryable Get(int projectId)

你还可以使用AllowedFunctions属性来限制$filter中的函数使用:

[Queryable(AllowedFunctions = AllowedFunctions.StartsWith)]
public IQueryable Get(int projectId)

上面的代码意味着只能在$filter中使用StartsWith函数。

Hongmei还演示了高级场景中的查询验证,如为$skip、$top、$orderby、$filter自定义默认验证逻辑,以及使用ODataQueryOptions来验证查询。

 

 

常用的 OData 指令:

$top:同 T-SQL 的 TOP,指定取得数据的前几笔。
$orderby:同 T-SQL 的 ORDER BY,可指定想排序的字段。
$skip:略过的笔数,可用于数据分页查询。
$filter:过滤条件,额外区分 eg (等于)、ne (不等于) 、lt (小于)、le (小于等于)、gt (大于)、ge (大于等于)。

Operator

Description

C#         equivalent

eq

equals

==

ne

not equal

!=

gt

greater than

>

ge

greater than or equal

>=

lt

less than

<

le

less than or equal

<=

and

and

&&

or

or

||

()

grouping

()

 

 


 

 

posted on 2014-10-21 15:44  布颜书  阅读(232)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3