您的位置:首页 > 编程语言 > ASP

[水煮 ASP.NET Web API2 方法论](12-2)管理 OData 路由

2016-11-21 08:45 465 查看
问题

如何控制 OData 路由

解决方案

为了注册路由,可以使用 HttpConfigurationExtension 类中 MapODataServiceRoute 的扩展方法。对于单一路由这样做足以,其余的处理由实体数据模型来处理。

config.MapODataServiceRoute("OData", "OData", builder.GetEdmModel());


从 ASP.NET Web API 2.2 开始支持 OData 直接声明路由,在 Action 上使用 ODataRouteAttribute。这和常规的属性路由一样,可以通过 ODataRoutePrefixAttribute 在 Controller 级别设置路由前缀.

[ODataRoute("Players")]

public IQueryable<Player> GetAllPlayers()

{

// 忽略

}


工作原理

OData 在 Web API 中路由是通过 ODataRoute 类实现的,其实,他是 HttpRoute 的一个子类。定制路由需要支持 ODataPathRouteConstraint,他是 OData 制定的,是IHttpRouteConstrain 的实现类,是为了确保所有的 OData 属性或 OData 路由约定在路由匹配后能够设置到 HttpRequestMessage 上。

ODataPath 类是用来包装转换 OData 资源路径,并以强类型的方式公开段(segment)。按约定,ASP.NET Web API 使用资源路径(URI 的一部分,例如,/Player),他是基于实体数据模型来映射到相应的 Controller。然后,动词依据动作选择在 Controller 中找到相应的 Action。此外,在 Web API 中 OData 可以使用自定义路由,这些路由都会影响动作选择。

小提示 更多关于 OData 路由约定的信息,请戳这里

https://www.asp.net/web-api/overview/OData-support-in-aspnet-web-api/OData-routing-conventions

我们可以通过我们自己的 IODataRoutingConvertion 重写 OData 路由行为、实现自定义 OData Controller、实现动作选择,如清单 12-3 所示

清单 12-3 IODataRoutingConvention 定义

public interface IODataRoutingConvention

{

string SelectController(ODataPath ODataPath, HttpRequestMessage request);

string SelectAction(ODataPath ODataPath, HttpControllerContext controllerContext,

ILookup<string, HttpActionDescriptor> actionMap);

}


当我们定义 OData 路由时,可以通过 MapODataServiceRoue 扩展方法来自定义路由约定;其中个的一个重载方法就是 使用 IODataRoutingConvention 的集合作为参数的方法。如果没有传值(例如,在使用 MapODataServiceRoute),那么,Web API 将在内部调用静态的 ODataRoutingConventions。CreateDefaultWithAttributeRouting 只使用默认的内建路由约定。

在 OData 中属性路由是 IDataRoutingConvention 的另一个版本-AttributeRoutingCinvention。他会查找所有 ODataRouteAttribute 的用法,使用 Dictionary<ODataPathTemplate,HttpActionDescriptot> 的形式建立适当的映射关系。如果进来的请求与当前 HTTP 请求的 ODataPath 匹配,那么,与此相关的 HttpActionDescriptor Controller 将会被选翻牌子来处理请求。

属性路由对于非标准路由来说是不错的选择,例如,使用非绑定的 OData 功能或 Action 的时候。尝试使用集中路由的方式进行路由,就需要自定义路由约定,然而,属性路由可以使用 ODataRouteAttribute 相关方法,用很简单的声明方式直接完成。

需要注意的是属性路由与常规路由不同,他是默认启用的。也就是说,除非我们重写默认的 IODataRoutingConventions,否则,Web API 会调用 ODataRoutingConvents。无论什么时候使用 MapODataServiceRoute 方法,CreateDefaultWithAttributeRouting 内部都会确保被 Web API OData 使用的 AttributeRoutingConvention 包含在约定的集合中。如清单 12-4 所示,摘录自 Web API 源码。

清单 12-4 ODataRoutingConvrention 类,确保 AttributeRoutingConvention 被包含。

public static class ODataRoutingConventions

{

public static IList<IODataRoutingConvention> CreateDefaultWithAttributeRouting(

HttpConfiguration configuration,

IEdmModel model)

{

if (configuration == null)

{

throw Error.ArgumentNull("configuration");

}

if (model == null)

{

throw Error.ArgumentNull("model");

}

IList<IODataRoutingConvention> routingConventions = CreateDefault();

AttributeRoutingConvention routingConvention = new AttributeRoutingConvention(model,

configuration);

routingConventions.Insert(0, routingConvention);

return routingConventions;

}

public static IList<IODataRoutingConvention> CreateDefault()

{

return new List<IODataRoutingConvention>()

{

new MetadataRoutingConvention(),

new EntitySetRoutingConvention(),

new SingletonRoutingConvention(),

new EntityRoutingConvention(),

new NavigationRoutingConvention(),

new PropertyRoutingConvention(),

new RefRoutingConvention(),

new ActionRoutingConvention(),

new FunctionRoutingConvention(),

new UnmappedRequestRoutingConvention()

};

}

}


结果就是,在应用程序启动,不在需要调用任何其他的方法通知框架扫描所有的路由属性。事实上,只有这样,才能在最开始的地方获取属性路由并调用 MapODataServiceRoute.

代码演示

为了介绍 OData Web API 的集中路由,我们只需要在 HttpConfiguration 中调用 MapODataServiceRoute 和传路由前缀,以及我们的 IEdmModel。一个完整的启动类列子,使用简单的 OData 实体和集中路由,如清单 12-5 所示,使用 Player 实体。

清单 12-5. 声明一个基本的 OData 路由启动类

public class Startup

{

public void Configuration(IAppBuilder builder)

{

var ODataBuilder = new ODataConventionModelBuilder();

ODataBuilder.EntitySet<Player>("Players");

var edm = ODataBuilder.GetEdmModel();

var config = new HttpConfiguration();

config.MapODataServiceRoute("Default OData", "OData", edm);

builder.UseWebApi(config);

}

}

public class Player

{

public int Id { get; set; }

public string Name { get; set; }

public string Team { get; set; }

}


允许我们使用所有默认的内建路由约定,例如,

• myapi.com/OData/Players

• myapi.com/OData/Players(key)

• myapi.com/OData/Players(key)/{navigation property | property}

• myapi.com/OData/Players(key)/{function | action}

注意 默认的 Web API OData 路由约定使用了 key 的概念,不是 ID,所以我们 Controller 的 Action 应该接收一个叫做 Key 的参数。

清单 12-6 展示了 ODataController 使用两个 Action 方法。这两个方法都是通过属性路由的方式声明了 OData 路由。

清单 12-6. OData Controller 使用属性路由的例子

[ODataRoutePrefix("Players")]

public class PlayersController : ODataController

{

private readonly PlayersContext _players = new PlayersContext();

[EnableQuery]

[ODataRoute]

public IQueryable<Player> GetAllPlayers()

{

return _players.AsQueryable();

}

[EnableQuery]

[ODataRoute("({key})")]

public SingleResult<Player> GetSinglePlayers(int key)

{

return SingleResult.Create(_players.Where(x => x.Id == key).AsQueryable());

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: