OData - ASP.NET Web API 2 中Odata路由约定

原文地址:http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-routing-conventions

本文介绍的是Web API中使用的odata endpoints 的路由约定。

术语

URI:统一资源标识符(Uniform Resource Identifier,或URI)是一个用于标识某一互联网资源名称的字符串。 该种标识允许用户对网络中(一般指万维网)的资源通过特定的协议进行交互操作。URI包括URL和URN。

当Web API得到一个OData请求,它会自动映射到相应的Controller和Action名字。这个映射是基于HTTP方法和URI的。例如:GET /odata/Products(1) 映射到ProductsController.GetProduct.

本文Part 1介绍的是内置的OData路由约定。这些路由约定是专门为OData endpoints设计的,并且他们覆盖了默认的Web API路由系统(当调用MapODataRoute时覆盖将会发生)。

本文Part 2介绍的是如何添加自定义的OData路由约定。目前内置的OData路由约定并没有覆盖到所有的OData URIs,但是你可以扩展他们来处理额外的案例。

内置路由约定

首先下面有些方便理解OData Uri的准备知识:

URI 组成: 服务器根service root,资源路径resource path,查询选项Query options。

针对路由,最重要的部分是Resource Path。Resource Path被分成片段。例如上面的URI例子"Products(1)/Supplier"有三个片段:

  • Products: 代表名为Products的entity set。
  • 1:表示entity的主键,从entity set中短暂单个entity。
  • Supplier:属于导航属性(navigation property),选择相关联entity。

所以上面的例子查询结果:product 1的Supplier。

Controller Name

Controller Name 通常都是衍生于Resource Path根部的entity set。继续上面的例子“Products(1)/Supplier”:Web API查找名为ProductsController的controller。

Action Name

Action Name通常衍生于路径片段加上实体数据模型(EDM: Entity Data Model),如下表中所示。有时候,你有两种Action Name选择,如"Get"和“GetProduct”。

  • 查询entities


请求类型

URI例子

操作名字(Action)

Action例子

GET /entityset

/Products

GetEntitySet or Get

GetProducts

GET /entityset(key)

/Products(1)

GetEntityType or Get

GetProduct

GET /entityset(key)/cast

/Products(1)/Models.Book

GetEntityType or Get

GetBook


更多的资料查看:http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v3/creating-an-odata-endpoint(OData V3)

  • 增、删、改entities



   请求类型

URI例子

操作名字(Action)

Action例子  

POST /entityset()

/Products

PostEntityType or Post

PostProduct

PUT /entityset(key)()

/Products(1)

PutEntityType or Put

PutProduct

PUT /entityset(key)/cast()

/Products(1)/Models.Book

PutEntityType or Put

PutBook

PATCH /entityset(key)()

/Products(1)

PatchEntityType or Patch

PatchProduct

PATCH /entityset(key)/cast()

/Products(1)/Models.Book

PatchEntityType or Patch

PatchBook

DELETE /entityset(key)()

/Products(1)

DeleteEntityType or Delete

DeleteProduct

DELETE /entityset(key)/cast()

/Products(1)/Models.Book

DeleteEntityType or Delete

DeleteBook

  • 查询导航属性( Navigation Property)


请求类型

URI例子

Action Name

Action例子

GET /entityset(key)/navigation

/Products(1)/Supplier

GetNavigationFromEntityType or GetNavigation

GetSupplierFromProduct

GET /entityset(key)/cast/navigation

/Products(1)/Models.Book/Author

GetNavigationFromEntityType or GetNavigation

GetAuthorFromBook

更多信息查看:Working with Entity Relations.

  • 增、删entities之间的联系(links)



请求类型

URI例子

Action Name

POST /entityset(key)/$links/navigation

/Products(1)/$links/Supplier

CreateLink

PUT /entityset(key)/$links/navigation

/Products(1)/$links/Supplier

CreateLink

DELETE /entityset(key)/$links/navigation

/Products(1)/$links/Supplier

DeleteLink

DELETE /entityset(key)/$links/navigation(relatedKey)

/Products/(1)/$links/Suppliers(1)

DeleteLink


更多信息查看:Working with Entity Relations.

  • 属性properties(需要Web API 2)


请求类型

URI例子

Action Name

Action例子

GET /entityset(key)/property

/Products(1)/Name

GetPropertyFromEntityType or GetProperty

GetTitleFromBook

GET /entityset(key)/cast/property

/Products(1)/Models.Book/Author

GetPropertyFromEntityType or GetProperty

GetTitleFromBook


  • 操作Action



请求类型

URI例子

Action Name

Action例子

GET /entityset(key)/ action

/Products(1)/Rate

ActionNameOnEntityType or ActionName

RateOnProduct

GET /entityset(key)/cast/ action

/Products(1)/Models.Book/CheckOut

ActionNameOnEntityType or ActionName

CheckOutOnBook

更多信息查看:OData Actions.

  • 方法签名(Action Signatures)

这里有方法签名的几个规则:

  1. 如果路径中包括主键,action中必须有一个以 主键为名的参数。
  2. 如果路径中包括导航属性中的主键(即关系entity的外键),action中必须有一个以 外键为名的参数。
  3. [FromODataUri]参数来修饰 主键外键参数。
  4. POSTPUT 请求需要有entity中的一个参数。
  5. PATCH请求需要 Delta类型参数,其中 T是entity类型

下面是每个内置Odatal路由约定的方法签名的例子:

public class ProductsController : ODataController
{
    // GET /odata/Products
    public IQueryable<Product> Get()

    // GET /odata/Products(1)
    public Product Get([FromODataUri] int key)

    // GET /odata/Products(1)/ODataRouting.Models.Book
    public Book GetBook([FromODataUri] int key)

    // POST /odata/Products 
    public HttpResponseMessage Post(Product item)

    // PUT /odata/Products(1)
    public HttpResponseMessage Put([FromODataUri] int key, Product item)

    // PATCH /odata/Products(1)
    public HttpResponseMessage Patch([FromODataUri] int key, Delta<Product> item)

    // DELETE /odata/Products(1)
    public HttpResponseMessage Delete([FromODataUri] int key)

    // PUT /odata/Products(1)/ODataRouting.Models.Book
    public HttpResponseMessage PutBook([FromODataUri] int key, Book item)

    // PATCH /odata/Products(1)/ODataRouting.Models.Book
    public HttpResponseMessage PatchBook([FromODataUri] int key, Delta<Book> item)

    // DELETE /odata/Products(1)/ODataRouting.Models.Book
    public HttpResponseMessage DeleteBook([FromODataUri] int key)

    //  GET /odata/Products(1)/Supplier
    public Supplier GetSupplierFromProduct([FromODataUri] int key)

    // GET /odata/Products(1)/ODataRouting.Models.Book/Author
    public Author GetAuthorFromBook([FromODataUri] int key)

    // POST /odata/Products(1)/$links/Supplier
    public HttpResponseMessage CreateLink([FromODataUri] int key, 
        string navigationProperty, [FromBody] Uri link)

    // DELETE /odata/Products(1)/$links/Supplier
    public HttpResponseMessage DeleteLink([FromODataUri] int key, 
        string navigationProperty, [FromBody] Uri link)

    // DELETE /odata/Products(1)/$links/Parts(1)
    public HttpResponseMessage DeleteLink([FromODataUri] int key, string relatedKey, string navigationProperty)

    // GET odata/Products(1)/Name
    // GET odata/Products(1)/Name/$value
    public HttpResponseMessage GetNameFromProduct([FromODataUri] int key)

    // GET /odata/Products(1)/ODataRouting.Models.Book/Title
    // GET /odata/Products(1)/ODataRouting.Models.Book/Title/$value
    public HttpResponseMessage GetTitleFromBook([FromODataUri] int key)
}

自定义路由约定

可以通过实现IODataRoutingConvention接口来自定义路由约定,以添加其他可能OData URIs。该接口有两个方法:

string SelectController(ODataPath odataPath, HttpRequestMessage request);//返回Controller名字
string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext, 
    ILookup<string, HttpActionDescriptor> actionMap);//返回Action名字

两个方法,当该约定不应用于某个请求,则都是返回null。

直接给出一个例子吧:/odata/Products(1)/Suppliers(1)

以下是自定义约定来实现的query。

using System.Web.OData.Routing;
using System.Web.OData.Routing.Conventions;
using System.Linq;
using System.Net.Http;
using System.Web.Http.Controllers;
using Microsoft.OData.Edm;

namespace ODataRouting
{
    public class NavigationIndexRoutingConvention : EntitySetRoutingConvention
    {
        //返回Action名字
        public override string SelectAction(ODataPath odataPath, HttpControllerContext context,
            ILookup<string, HttpActionDescriptor> actionMap)
        {
            if (context.Request.Method == HttpMethod.Get &&
                odataPath.PathTemplate == "~/entityset/key/navigation/key")
            {
                NavigationPathSegment navigationSegment = odataPath.Segments[2] as NavigationPathSegment;
                IEdmNavigationProperty navigationProperty = navigationSegment.NavigationProperty.Partner;
                IEdmEntityType declaringType = navigationProperty.DeclaringType as IEdmEntityType;

                string actionName = "Get" + declaringType.Name;
                if (actionMap.Contains(actionName))
                {
                    // Add keys to route data, so they will bind to action parameters.
                    KeyValuePathSegment keyValueSegment = odataPath.Segments[1] as KeyValuePathSegment;
                    context.RouteData.Values[ODataRouteConstants.Key] = keyValueSegment.Value;

                    KeyValuePathSegment relatedKeySegment = odataPath.Segments[3] as KeyValuePathSegment;
                    context.RouteData.Values[ODataRouteConstants.RelatedKey] = relatedKeySegment.Value;

                    return actionName;
                }
            }
            // Not a match.
            return null;
        }
    }
}


要点:

  1. 派生于EntitySetRoutingConvention,因为在这个类中SelectController方法适用于新的路由约定,不需要重写SelectController。
  2. 这个约定只适用于Get请求,而且只有当路径模式是:“~/entityset/key/navigation/key”。
  3. action名字是“Get{EntityType}”,其中{EntityType}是导航属性集合中类型。如:GetSupplier。你可以使用任何命名约定,只要Controller名字匹配上。
  4. action有key和relatekey两个参数。(ODataRouteConstants.

下一步将新约定加入到路由约定。(WebApiConfig.cs)

using ODataRouting.Models;
using System.Web.Http;
using System.Web.Http.OData.Builder;
using System.Web.Http.OData.Routing;
using System.Web.Http.OData.Routing.Conventions;

namespace ODataRouting
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
            // Create EDM (not shown).

            // Create the default collection of built-in conventions.
            var conventions = ODataRoutingConventions.CreateDefault();
            // Insert the custom convention at the start of the collection.
            conventions.Insert(0, new NavigationIndexRoutingConvention());

            config.Routes.MapODataRoute(routeName: "ODataRoute",
                routePrefix: "odata",
                model: modelBuilder.GetEdmModel(),
                pathHandler: new DefaultODataPathHandler(),
                routingConventions: conventions);

        }
    }
}

其他有用相关例子:










    
    • 0
      点赞
    • 0
      收藏
      觉得还不错? 一键收藏
    • 0
      评论

    “相关推荐”对你有帮助么?

    • 非常没帮助
    • 没帮助
    • 一般
    • 有帮助
    • 非常有帮助
    提交
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值