欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

ASP.NET Core中自定义路由约束的实现

程序员文章站 2023-11-20 21:40:22
路由约束 asp.net core中,通过定义路由模板,可以在url上传递变量,同时可以针对变量提供默认值、可选和约束。 约束的使用方法是在属性路由上添加指定的约束...

路由约束

asp.net core中,通过定义路由模板,可以在url上传递变量,同时可以针对变量提供默认值、可选和约束。

约束的使用方法是在属性路由上添加指定的约束名,用法如下:

// 单个使用
[route("users/{id:int}")]
public user getuserbyid(int id) { }
// 组合使用
[route("users/{id:int:min(1)}")]
public user getuserbyid(int id) { }

框架内部已经提供了一些约束,如下所示:

约束 示例 匹配项示例 说明
int {id:int} 123456789, -123456789 匹配任何整数
bool {active:bool} true, false 匹配 true或 false(区分大小写)
datetime {dob:datetime} 2016-12-31, 2016-12-31 7: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。

举一个实例,我们想要定义一个约束,指定路由传过来的参数必须是指定的枚举值。

我们先定义一个枚举:

public enum boolenum
{
  true,
  false
}

然后定义约束:

public class enumconstraint : irouteconstraint
{
  private type _enumtype;

  public enumconstraint(string enumtypename)
  {
    _enumtype = type.gettype(enumtypename);
  }

  public bool match(httpcontext httpcontext, irouter route, string routekey, routevaluedictionary values, routedirection routedirection)
  {
    var value = values[routekey];
    if (value == null)
    {
      return false;
    }

    if (enum.tryparse(_enumtype, value.tostring(), out object result))
    {
      if (enum.isdefined(_enumtype, result))
      {
        return true;
      }
    }

    return false;
  }
}

在 startup.cs 的 configureservices 方法添加自定义约束:

services.configure<routeoptions>(options =>
{
  options.constraintmap.add("enum", typeof(enumconstraint));
});

在路由上使用约束:

( webapplicationtest 是当前的 namespace )

[route("api/[controller]")]
[apicontroller]
public class testcontroller : controllerbase
{
  // get: api/test
  [httpget("{bool:enum(" + nameof(webapplicationtest) + "." + nameof(boolenum) + ")}")]
  public string get(boolenum @bool)
  {
    return "bool: " + @bool;
  }

  [httpget("{id:int:min(2)}", name = "get")]
  public string get(int id)
  {
    return "id: " + id;
  }

  [httpget("{name}")]
  public string get(string name)
  {
    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 的构造函数可以使用注入,所以可以扩展性十分强,可以通过查询数据库做一些参数校验。

官网上对于路由约束只是简单的提了一下,本文对路由约束的使用提供了具体的示例。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。