zoukankan      html  css  js  c++  java
  • .NET Core中的路由约束

    背景介绍

    上周给大家分享了Nancy in .NET Core学习笔记 - 路由之后, 就一直在考虑.NET Core能否实现和Nancy中一样的路由约束, 最近查阅了一下MSDN及一些国外博客, 发现.NET Core中已经实现了相同的功能,所以这里给大家分享一下。

    路由约束

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

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

    [GET] /api/posts/{id}
    [GET] /api/posts/{name}

    我们希望当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方法中使用

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

    在路由属性中使用

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

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

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

    例:

    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方法来自定义路由约束。

    我们举一个和之前Nancy in .NET Core学习笔记 - 路由中的类似的例子。

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

        [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约束,方法如下:

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

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

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

        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。

    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"。

    本篇源代码

    参考文献

  • 相关阅读:
    zookeeper配置
    redis前端启动和后台启动的区别
    SpringMVC接受JSON参数详解及常见错误总结我改
    SpringMVC @RequestBody接收Json对象字符串
    spring MVC 如何接收前台传入的JSON对象数组
    springMVC 接收json字符串参数
    mysql数据库user表host字段的%问题
    mysql.user表中Host为%的含义
    开店攻略: 零售店铺经营的三大原则
    开店攻略: 如何巧妙接近顾客
  • 原文地址:https://www.cnblogs.com/lwqlun/p/9649774.html
Copyright © 2011-2022 走看看