[水煮 ASP.NET Web API2 方法论](3-5)路由约束
问题
怎么样限制路由中参数的值。
解决方案
ASP.NET WEB API 允许我们通过 IHttpRouteConstraint 接口设置路由约束。集中式路由和直接式路由都可以使用 IHttpRouteConstraint。
框架提供了 18 个接口,他提供了大部分类型的约束,例如,路由参数长度相关的约束,可以确保值都在定义范围内,或者限制数据类型。当然也可以通过实现接口 IHttpRouteConstraint 来自定义约束逻辑。
工作原理
IHttpRoutConstraint 是一个 HTTP 路由约束接口(如代码片段 3-11),并公开了一个简单的方法 Match,这个方法需要五个参数,HttpRequestMessage 实例,IHttpRoute 实例,string 类型的 parameterName,Idictionary<string,object> 类型的路由 value,HttpRouteDirection 类型的 routeDirection,也是为了保证路由可以基于应用程序的逻辑被匹配到。
代码片段 3-11 IHttpRouteConstraint 定义
public interface IHttpRouteConstraint
{
bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName,
IDictionary<string, object> values, HttpRouteDirection routeDirection);
}
也可以通过使用 CompoundRouteConstraint 进行复合约束,需要通过构造函数添加到 IHttpRouteConstraint 集合中,如表格 3-1 所示,展示内建的约束和基本用法
表格 3-1. ASP.NET WEB API 中 IHttpRouteConstraint 可以用的约束

属性路由,是通过 DefaultInlineConstraintResolver 来映射嵌入约束的版本和实际类型。当调用 MapHttpAtrributeRoute 的时候,ASP.NET WEB API 会使用解析器转换嵌入约束为相关 IHttpRouteConstraint 实例。为了采用某些约束处理自定义约束,也可以修改 DefaultInlineConstraintResolver 或者自己实现全部的 IInineConstraintReslover 接口。不管怎么样,都需要传一个他的实例给方法 MapHttpAttributeRoute。
OptionalRouteConstraint 是被用来提供可选参数功能的,如上一篇 3-4 介绍的,还提供了常见的约束功能。如果路由参数不是 RouteParameter.Optional 的,OptionalRouteConstraint 就只会计算约束。
代码演示
对于集中式路由,约束是作为 MapHttpRoute 方法的第三个参数传进来的。与默认值类似,已经在 3-3 部分介绍过,这个参数的类型是 Idictionary<string,object>,但是,框架的设计也是可以传匿名对象,这个方法签名的实际类型就是一个简单对象。约束参数的名称必须和路由模板以及 Action 的签名一致。
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "orders/{text}",
constraints: new {text = new AlphaRouteConstraint()},
defaults: null
);
使用集中式路由,也可以定义一个字符串的嵌入正则表达式,不必使用任何 IHttpRouteConstarint 接口。在下面的李子中,“id”就是一个数字约束嵌入正则表达式。
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "size/{id}",
constraints: new {id = "\d+"},
defaults: null
);
集中式路由也可以约束 HTTP 方法,只要通过一个预定义的 httpMethod 键并赋值 HttpMethodConstrtin 就可以。
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "size/{id}",
constraints: new {httpMethod = new HttpMethodConstraint(HttpMethod.Get)},
defaults: null
);
对于直接式路由,可以通过在参数加上冒号再加上约束条件。
[Route("orders/{text:alpha}")]
public HttpResponseMessage Get(string text){}
对于复合路由的定义,集中式路由需要通过 CompoundRouteConstraint 转换。
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "orders/{text}",
constraints: new
{
text = new CompoundRouteConstraint(new List<IHttpRouteConstraint>
{new AlphaRouteConstraint(), new MaxLengthRouteConstraint()}
},
defaults: null
);
对于属性路由,可以通过冒号将不同的约束链起来;框架会在内部使用 CompoundRouteConstraint 构建复合约束。
[Route("orders/{text:alpha:maxlength(5)}")]
public HttpResponseMessage Get(string text){}
一个简单的自定义路由约束,确保参数是一个合法的 email 格式,如代码片段 3-12 所示。因为路由值是 IDictionary<string.object>,再验证约束之前需要转换成期望的类型(这里就是 string)。
public class EmailRouteConstraint : IHttpRouteConstraint
{
public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName,
IDictionary<string, object> values, HttpRouteDirection routeDirection)
{
object value;
if (values.TryGetValue(parameterName, out value) && value != null)
{
var stringValue = value as string;
if (stringValue == null) return false;
try
{
var email = new MailAddress(stringValue);
return true;
}
catch (FormatException)
{
return false;
}
}
return false;
}
}
直接在集中式路由中,像使用内置约束一样使用这个约束。
config.Routes.MapHttpRoute(
name: "Email",
routeTemplate: "{controller}/email/{text}",
constraints: new {text = new EmailRouteConstraint()},
defaults: null
);
然而,使用属性路由的时候,可以使用别名来代替,但是在 EmailRouteConstraint 类没有这样的定义。因为,别名和约束类型是通过 DefaultInlineConstraintReslover 来完成映射的,ASP.NET WEB API 使用这个来解析这个约束,我们需要执行如下步骤
var constraintResolver = new DefaultInlineConstraintResolver();
constraintResolver.ConstraintMap.Add("email", typeof (EmailRouteConstraint));
config.MapHttpAttributeRoutes(constraintResolver);
这样,就可以像使用框架提供的约束一样,使用上面定义的 email 约束。
[Route("orders/client/{text:email}")]
public HttpResponseMessage GetByClient(string text) { }
注意 如果没有额外的映射步骤,约束就不会有任何反应,但是,ASP.NET WEB API 的整个属性路由可能有问题。
[水煮 ASP.NET Web API2 方法论](3-5)路由约束的更多相关文章
- [水煮 ASP.NET Web API2 方法论](3-9)空气路由的设置
阅读导航 问题 解决方案 工作原理 代码演示 在此解释一下,空气路由,是本人臆想出来,觉着更能表达 IgnoreRoute 的意图,如果看着辣眼睛^^,请见谅. 问题 我们在之定义过集中式路由,集中式 ...
- [水煮 ASP.NET Web API2 方法论](3-4)设置路由可选项
问题 怎么样创建一个路由,不管客户端传不传这个参数,都可以被成功匹配. 解决方案 ASP.NET WEB API 的集中式路由和属性路由都支持路由声明可选参数. 在用集中式路由中可以通过 RouteP ...
- [水煮 ASP.NET Web API2 方法论](3-1)集中式路由
问题 怎样集中的定义路由 解决方案 通过调用 HttpRouteCollectionExtension 类中的 MapHttpRoute 扩展方法在 HttpRouteCollection 中定义路由 ...
- [水煮 ASP.NET Web API2 方法论](1-1)在MVC 应用程序中添加 ASP.NET Web API
问题 怎么样将 Asp.Net Web Api 加入到现有的 Asp.Net MVC 项目中 解决方案 在 Visual Studio 2012 中就已经把 Asp.Net Web Api 自动地整合 ...
- [水煮 ASP.NET Web API2 方法论](1-5)ASP.NET Web API Scaffolding(模板)
问题 我们想快速启动一个 ASP.NET Web API 解决方案. 解决方案 APS.NET 模板一开始就支持 ASP.NET Web API.使用模板往我们的项目中添加 Controller,在我 ...
- [水煮 ASP.NET Web API2 方法论](3-8)怎样给指定路由配置处理器
阅读导航 问题 解决方案 工作原理 代码演示 问题 如果仅仅针对指定的路由进行某些特定的消息处理,而不是应用于所有路由,我们应该怎么做呢? 解决方案 ASP.NET WEB API 的很多功能都内建了 ...
- [水煮 ASP.NET Web API2 方法论](3-7)默认 Action 请求方式以及 NonActionAttribute
问题 在 Controller 中有一个 public 的方法,但是又不想将这个 publlic 方法暴露成为一个 API. 解决方案 ASP.NET Web API 中,正常是通过 HTTP 谓词来 ...
- [水煮 ASP.NET Web API2 方法论](3-6)万能路由
问题 定义什么样的路由,可以不会受请求参数类型和数量的限制,而被全部捕获? 解决方案 在路由模板中,给参数添加一个"*"前缀,例如 {*param},只要请求的 URL 能够和路由 ...
- [水煮 ASP.NET Web API2 方法论](3-3)路由默认值
问题 如何为路由中参数设置默认值. 解决方案 不管使用属性路由还是集中式路由,ASP.NET WEB API 都可以很方便的为路由定义默认参数.在每次客户端请求的时候,如果客户端没有传这些参数,框架会 ...
随机推荐
- [转] The program can't start because api-ms-win-crt-runtime-l1-1-0.dll is missing
https://www.smartftp.com/support/kb/the-program-cant-start-because-api-ms-win-crt-runtime-l1-1-0dll- ...
- Discuz! 的编码规范
http://open.discuz.net/?ac=document&page=dev_coderule 前言 本规范由编程原则组成,融合并提炼了开发人员长时间积累下来的成熟经验,意在帮助形 ...
- 延长Toast显示时间
---恢复内容开始--- 由于Toast的显示时间只有两种: Toast.LENGTH_SHORT: 2秒 Toast.LENGTH_LONG: 3.5秒 而且是写死的,没给开发者自定义时间的权利,所 ...
- LoadRunner AJAX TruClient协议Tips and Tricks
LoadRunner AJAX TruClient协议Tips and Trickshttp://automationqa.com/forum.php?mod=viewthread&tid=2 ...
- 使用linux mint 安装无线网卡驱动
新买了个笔记本Thinkpad E440,用了两天发现无线网非常不稳定,有时候能搜到wifi却连不上,有时候连上了却连不上互联网,于是决定重新安装个网卡驱动. 首先看看自己显卡的型号: lspci : ...
- apache 配置反向代理服务器
前几天实验了下 nginx 配置反向代理服务器.虽然 nginx 的安装很麻烦,但是用起来倒是很简单.不过组里没人用过 nginx,apache 服务器大家倒是蛮熟,为了减少 ops team 的工作 ...
- SetHandleInformation设置内核对象标志
当父进程创建子进程时,子进程将继承父进程的内核对象.这时如果要控制子进程使用父进程的内核对象.可以使用 SetHandleInformation设置. BOOL SetHandleInformatio ...
- jQuery easyui 之 expend row
http://www.jeasyui.com/tutorial/datagrid/datagrid21.php
- ubuntu14.04服务版/etc/init.d/smbd restart无效的解决方法
刚装的ubuntu14.04配置完smbd发现service或者/etc/init.d/smbd restart都不显示任何输出,也没起作用 echo $?输出1,查看脚本发现 if init_is_ ...
- pidgin修改来消息字体大小
vi ~/.gtkrc-2.0写入如下内容设置自己想要的字体大小 style "imhtml-fix"{ font_name = "Sans 14"} w ...