ASP.NET Core中自定义路由约束的实现
路由约束
ASP.NETCore中,通过定义路由模板,可以在Url上传递变量,同时可以针对变量提供默认值、可选和约束。
约束的使用方法是在属性路由上添加指定的约束名,用法如下:
//单个使用 [Route("users/{id:int}")] publicUserGetUserById(intid){} //组合使用 [Route("users/{id:int:min(1)}")] publicUserGetUserById(intid){}
框架内部已经提供了一些约束,如下所示:
约束
示例
匹配项示例
说明
int
{id:int}
123456789,-123456789
匹配任何整数
bool
{active:bool}
true,FALSE
匹配true或false(区分大小写)
datetime
{dob:datetime}
2016-12-31,2016-12-317:32pm
匹配有效的DateTime值(位于固定区域性中-查看警告)
decimal
{price:decimal}
49.99,-1,000.01
匹配有效的decimal值(位于固定区域性中-查看警告)
double
{weight:double}
1.234,-1,001.01e8
匹配有效的double值(位于固定区域性中-查看警告)
float
{weight:float}
1.234,-1,001.01e8
匹配有效的float值(位于固定区域性中-查看警告)
guid
{id:guid}
CD2C1638-1638-72D5-1638-DEADBEEF1638,{CD2C1638-1638-72D5-1638-DEADBEEF1638}
匹配有效的Guid值
long
{ticks:long}
123456789,-123456789
匹配有效的long值
minlength(value)
{username:minlength(4)}
Rick
字符串必须至少为4个字符
maxlength(value)
{filename:maxlength(8)}
Richard
字符串不得超过8个字符
length(length)
{filename:length(12)}
somefile.txt
字符串必须正好为12个字符
length(min,max)
{filename:length(8,16)}
somefile.txt
字符串必须至少为8个字符,且不得超过16个字符
min(value)
{age:min(18)}
19
整数值必须至少为18
max(value)
{age:max(120)}
91
整数值不得超过120
range(min,max)
{age:range(18,120)}
91
整数值必须至少为18,且不得超过120
alpha
{name:alpha}
Rick
字符串必须由一个或多个字母字符(a-z,区分大小写)组成
regex(expression)
{ssn:regex(^\d{{3}}-\d{{2}}-\d{{4}}$)}
123-45-6789
字符串必须匹配正则表达式(参见有关定义正则表达式的提示)
required
{name:required}
Rick
用于强制在URL生成过程中存在非参数值
内置的约束能够适用于大部分常见的应用场景,但是有时候我们还是需要去自定义我们想要的效果。
自定义路由约束
自定义约束是要实现IRouteConstraint接口,然后重载Match方法,该方法有四个参数。
第一个参数httpContext是当前请求的上下文
第二个参数route是当前约束所属的路由
第三个参数routeKey是当前检查的变量名,例如文章开头示例中的id
第四个参数values是当前Url匹配的字典值,例如文章开头的示例的路由,如果Url是users/1,那么就有一个字典,其key=id,value=1。当然还有其他的变量的值,比如controller,action等。
第五个参数routeDirection是一个枚举值,代表是web请求的还是用Url.Action等方法生成Url。
举一个实例,我们想要定义一个约束,指定路由传过来的参数必须是指定的枚举值。
我们先定义一个枚举:
publicenumBoolEnum { True, False }
然后定义约束:
publicclassEnumConstraint:IRouteConstraint { privateType_enumType; publicEnumConstraint(stringenumTypeName) { _enumType=Type.GetType(enumTypeName); } publicboolMatch(HttpContexthttpContext,IRouterroute,stringrouteKey,RouteValueDictionaryvalues,RouteDirectionrouteDirection) { varvalue=values[routeKey]; if(value==null) { returnfalse; } if(Enum.TryParse(_enumType,value.ToString(),outobjectresult)) { if(Enum.IsDefined(_enumType,result)) { returntrue; } } returnfalse; } }
在Startup.cs的ConfigureServices方法添加自定义约束:
services.Configure(options=> { options.ConstraintMap.Add("enum",typeof(EnumConstraint)); });
在路由上使用约束:
(WebApplicationTest是当前的namespace)
[Route("api/[controller]")] [ApiController] publicclassTestController:ControllerBase { //GET:api/Test [HttpGet("{bool:enum("+nameof(WebApplicationTest)+"."+nameof(BoolEnum)+")}")] publicstringGet(BoolEnum@bool) { return"bool:"+@bool; } [HttpGet("{id:int:min(2)}",Name="Get")] publicstringGet(intid) { return"id:"+id; } [HttpGet("{name}")] publicstringGet(stringname) { return"name:"+name; } }
{id:int:min(2)}路由必须使用min(2),否则对于id=0或id=1会有冲突。
运行程序,当路由是api/Test/0、api/Test/1、api/Test/True和api/Test/False的时候,匹配我们的自定义约束。
当路由是api/Test/{大于2的整数}的时候,匹配第二个路由。
其他情况匹配第三个路由。
结论
路由约束在某些场景下是非常有用的功能,可以减少controller中校验参数,将部分参数校验的功能使用声明式的attruibute来实现,某些重复的校验可以通过抽取成约束公共使用。
constraint的构造函数可以使用注入,所以可以扩展性十分强,可以通过查询数据库做一些参数校验。
官网上对于路由约束只是简单的提了一下,本文对路由约束的使用提供了具体的示例。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。