问题

怎么样限制路由中参数的值。

 

解决方案

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(5)}
    },
    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 API 2 方法论] 目 录


[水煮 ReSharper] 高效开发—十个实用的快捷键

分类: Web Api


延伸阅读

告别“老顽固”-Java培训,做最负责任的教育,学习改变命运,软件学习,再就业,大学生如何就业,帮大学生找到好工作,lphotoshop培训,电脑培训,电脑维修培训,移动软件开发培训,网站设计培训,网站建设培训告别“老顽固”