ASP.NET Core 之路由相关

发布时间 2023-12-31 11:23:35作者: JohnYang819

ASP.NET Core中路由的过程:routing middleware把传入的url与一系列模板进行比对,选择相应的endpoint handler,并将其记录在HttpContext上的request上。endpoint middleware执行选择的endpoint hander,并返回response.
在routing middleware之前的路由器并不知道传入的request对应的endpoint handler是哪一个,例如把static file middleware放在routing middleware之前,staic file middleware并不知道对应的endpoint handler是哪一个,只是去检查是否在wwwroot中是否存在请求的文件,如果有,直接返回,如果没有,则直接忽略,传入下一个中间件。这也解释了为什么把static file middleware放在routing middleware之前要合理些,因为如果放在之后,那么routing middleware就要去多作一个判断,选择。

路由模板语法

/product/{category}/{name},不带花括号的是字面量,带花括号的是必须路由参数。
/product/{category}/{name=all}/{id?},category是必须路由参数,name是默认路由参数,id是可选路由参数。
需要注意的是,id不能在没有category和name的情况下,单独指定。id也只能放到模板最后。

对模板参数的约束

加冒号,如{qty:int},就表示必须是int,否则判定为不匹配。

{id:guid},{cost:decimal},{age:min(18)},
{name:length(16)},{qty:int?}
也可以组合起来,如{qty:int:max(10)?}
app.MapGet("/match/{idStr}", (string idStr) => Results.Ok($"it is string {idStr}"));
app.MapGet("/match/{id:int}", (int id) => Results.Ok($"it is int {id}"));



一般来说,要避免这种模板重载。

匹配任意参数,catch-all parameters

app.MapGet("/catchall/{**all}", (string all) => Results.Ok(all));

从路由参数产生URL

LinkGenerator

该过程正好是路由过程的逆过程。一般两步:(1)给既定的endpoint 添加名称,用WithName,然后在endpoint 处理函数里面,用LinkGenerator的GetPathByName()方法,即可。

app.MapGet("/product", () => Results.Ok($"product name ")).WithName("product");
app.MapGet("/links", (LinkGenerator links) =>//可以这么做的原因是,该对象已经被依赖注入。
{
    string link = links.GetPathByName("product", new { name = "big-widget" },options:new LinkOptions
    {
        LowercaseUrls=false,

    });
    return link;
});



值得注意的是,当传入的参数在既定的endpoint handler function中不存在的时候,自动转为query string.
还可以通过RouteOptions来控制,产生的URL的样子,比如末尾带不带"",是否大小写。而设置也有全局设置和局部设置。
全局设置,是通过builder.Services.Configure<RouteOptions>(o=>{...})实现的,而局部就是LinkGenerator的GetPathByName中的options参数控制。

直接跳转

如果不需要显式产生url,只希望跳转,那么用Results.RedirectToRoute或者Results.Redirect即可。
前者跳转到既定的endpoint handler中,所以还是两步:(1)给既定endpoint handler 加WithName(2) 调用Results.RedirectToRoute(该name)
后者非常随意,甚至可以跳转到外部url,如Results.Redirect("https://www.baidu.com").

app.MapGet("/test", () => "hello,lucky!").WithName("test");
app.MapGet("/redirect-me", () => Results.RedirectToRoute("test",permanent:false,preserveMethod:false));
app.MapGet("/redirect-mee", () => Results.Redirect("https://wwww.baidu.com"));