.NET 路由约束

路由约束

路由约束是路由中的一种设置,可以帮助我们限制Url中的参数类型,只有当参数符合约束条件的时候,action才会被激活并触发。

比如我们现在有以下2个Url

[GET] /api/posts/{id}

[GET] /api/posts/

我们希望当Posts后面的参数是int类型的时候触发第一个Url所指向action, 参数是string类型的时候触发第二个Url所指向的action。

在这种场景下,我们就需要使用路由约束。

如何添加路由约束

在.NET Core中有2种添加路由约束的方法。

  • 行内约束(Inline Constraint)
  • 使用MapRoute方法带Constraint参数的重载

当路由引擎发现当前的请求Url符合某个路由设置之后,就会去触发当前路由设置中的所有路由约束,当所有的约束都返回true, 这个路由对应的action就会被激活。

行内约束(Inline Constraint)

所谓的行内约束,即在路由Url模板中直接定义。定义的方式是在参数后面加冒号,并制定约束类型。

例:

"/api/posts/{id:int}"

所以该方式既可以在MapRoute方法中使用,也可以在路由属性中使用。

在MapRoute方法中使用

arduino 复制代码
routes.MapRoute("default", "{controller=Home}/{action=Index}/{id:int}");

在路由属性中使用

csharp 复制代码
[Route("Home/Index/{id:int}")]
public string Index(int id)
{
    return "I got " + id.ToString();
}

使用MapRoute方法带Constraint参数的重载

除了行内约束,我们还可以在Startup.cs的中通过app.UseMvc()方法来添加约束。

例:

ini 复制代码
using Microsoft.AspNetCore.Routing.Constraints;
 
app.UseMvc(routes =>
{
    routes.MapRoute("default",
                    "{controller}/{action}/{id}",
                     new { controller = "Home", action = "Index" },
                     new { id = new IntRouteConstraint() });
});

.NET Core内置的路由约束

.NET Core已经提供了很多基础的路由约束,总体上分为3种类型。

  • 检查数据类型的约束
  • 检查数据的值/长度/范围的约束
  • 正则表达式约束

检查数据类型的约束

约束 行内 Constraint类 说明
int {id:int} IntRouteConstraint 只允许int32整数
alpha {id:alpha} AlphaRouteConstraint 只能包含大小写字母
bool {id:bool} BoolRouteConstraint 只允许布尔类型
datetime {id:datetime} DateTimeRouteConstraint 只允许日期格式
decimal {id:decimal} DecimalRouteConstraint 只允许decimal类型
double {id:double} DoubleRouteConstraint 只允许double类型
float {id:float} FloatRouteConstraint 只允许float类型
guid {id:guid} GuidRouteConstraint 只允许guid类型

检查数据的值/长度/范围的约束

约束 行内 Constraint类 说明
length(length) {id:length(12)} LengthRouteConstraint 字符串长度限制
maxlength(value) {id:maxlength(8)} MaxLengthRouteConstraint 字符串最大长度限制
minlength(value) {id:minlength(4)} MinLengthRouteConstraint 字符串最小长度限制
range(min,max) {id:range(18,120)} RangeRouteConstraint 数值范围限制
min(value) {id:min(18)} MinRouteConstraint 最小数值限制
max(value) {id:max(120)} MaxRouteConstraint 最大数值限制

正则表达式约束

约束 行内 Constraint类 说明
regex(expression) {ssn:regex(^\d{{3}}-\d{{2}}-\d{{4}}$)}/ RegexRouteConstraint 正则表达式约束

自定义路由约束

和Nancy一样,.NET Core也支持自定义路由约束,我们可以通过实现IRouteConstraint接口的Match方法来自定义路由约束。

当前我们有一个PostController类,代码如下:

csharp 复制代码
    [ApiController]
    public class PostController : ControllerBase
    {
        [HttpGet]
        [Route("~/api/posts/{id:int}")]
        public IActionResult GetPostById(int id)
        {
            return Content("Coming from GetPostById");
        }

        [HttpGet]
        [Route("~/api/posts/{name:alpha}")]
        public IActionResult GetPostByName(string name)
        {
            return Content("Coming from GetPostByName");
        }
    }

这时候我们添加新的action方法GetPostByEmail, 并追加一个email约束,方法如下:

csharp 复制代码
    [HttpGet]
    [Route("~/api/posts/{email:email}")]
    public IActionResult GetPostByEmail(string email)
    {
        return Content("Coming from GetPostByEmail");
    }

我们希望当posts后面的参数是email格式的时候,显示"Coming from GetPostByEmail"。

这里我们首先添加一个EmailConstraint类,并实现IRouteConstraint接口的Match方法

csharp 复制代码
    public class EmailConstraint : IRouteConstraint
    {
        public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
        {
            if (httpContext == null)
                throw new ArgumentNullException(nameof(httpContext));

            if (route == null)
                throw new ArgumentNullException(nameof(route));

            if (routeKey == null)
                throw new ArgumentNullException(nameof(routeKey));

            if (values == null)
                throw new ArgumentNullException(nameof(values));

            object routeValue;

            if (values.TryGetValue(routeKey, out routeValue))
            {
                var parameterValueString = Convert.ToString(routeValue, CultureInfo.InvariantCulture);

                return parameterValueString.Contains("@");
            }

            return false;
        }
    }

其中values.TryGetValue(routeKey, out routeValue)是尝试从路由参数列表中,取出当前参数的值, 如果当前值中包含@, 我们就简单的认为这个Email约束通过, 并返回true。


上述代码完成之后,我们打开Startup.cs文件, 在ConfigureServices方法中, 我们将这个自定义的路由约束添加到约束列表中,并指定当前的约束名称是email。

csharp 复制代码
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    services.Configure<RouteOptions>(routeOptions =>
    {
        routeOptions.ConstraintMap.Add("email", typeof(EmailConstraint));
    });
}

最后我们看一下效果, 页面中正确显示除了"Coming from GetPostByEmail"。

相关推荐
豌豆花下猫11 分钟前
REST API 已经 25 岁了:它是如何形成的,将来可能会怎样?
后端·python·ai
喔喔咿哈哈24 分钟前
【手撕 Spring】 -- Bean 的创建以及获取
java·后端·spring·面试·开源·github
夏微凉.35 分钟前
【JavaEE进阶】Spring AOP 原理
java·spring boot·后端·spring·java-ee·maven
不会编程的懒洋洋2 小时前
Spring Cloud Eureka 服务注册与发现
java·笔记·后端·学习·spring·spring cloud·eureka
NiNg_1_2343 小时前
SpringSecurity入门
后端·spring·springboot·springsecurity
Lucifer三思而后行3 小时前
YashanDB YAC 入门指南与技术详解
数据库·后端
王二端茶倒水4 小时前
大龄程序员兼职跑外卖第五周之亲身感悟
前端·后端·程序员
夜色呦5 小时前
现代电商解决方案:Spring Boot框架实践
数据库·spring boot·后端
爱敲代码的小冰5 小时前
spring boot 请求
java·spring boot·后端
java小吕布7 小时前
Java中的排序算法:探索与比较
java·后端·算法·排序算法