ASP.NET Core 之路由相关
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"));