前言

之前有提过, MVC 和 Razor Pages 最大的区别就在 Routing 上.

Razor Pages 的结构是 route, page, model

route match to page, page declare model (route > page > model)

route 是怎样 match to page 的呢? ASP.NET Core 有一套机制. 这篇主要就是介绍这个和如果修改它.

参考:

Razor Pages Routing

默认 route 匹配

创建一个 Razor Pages 项目

dotnet new webapp -o TestRazorPagesRouting
dotnet watch run

打开游览器访问

https://localhost:7194 (首页)

https://localhost:7194/Privacy (Privacy 页面)

它们对应的 Page 是

看的出来, 匹配方式是 file name, 然后 Index 可以忽略

Privary.cshtml = /Privary

Index.cshtml = /

那么 https://localhost:7194/Index 也可以访问首页面?

答案是可以的.

multiple layer

按照它的思路, 应该就是把 path 加长. 没错!

Mac/Compare.cshtml = /Mac/Compare

结论

Razor Page Routing 的机制是

先去 root folder "Pages"

找到所有带有 @page 的 .cshtml

依据 file 的所在位置 (folder) 和它的 file name 作为 URL path.

而 Index 可以被忽略 (要写也是可以)

Index.cshtml = /

Index.cshtml = /Index

Privary.cshtml = /Privary

Mac/Compare.cshtml = /Mac/Compare

默认 route 匹配的问题

这个默认匹配方式不是很直观, 它有一下问题:

1. Case Style, URL 通常是 kebab-case. 但 folder 和 file name 却是 PascalCase. 而它竟然没有做任何转换.

2. Index 不应该被访问. 有见过 /index.html 这样访问的, 但没有见过 /Index 这样访问的...

3. 整体 Structure 没有顾虑到 CSS 和 JS

下面这个才是正常网站的 folder structure

html, js, css 一定是在同一个 folder 里的, 表示一个页面. 嵌套也是一样.

虽然它默认的匹配不太理想, 但是一个好的框架不是评价它的默认, 而是它是否允许自定义.

幸好, 在自定义方面, ASP.NET Core 还是提供了接口.

Area

在讲解修改默认匹配之前, 先看看 Area (因为我没有用, 所以大概记入一下就好)

当有很多 pages 以后, 想给它们分类就可以用 Area

结构长这样

匹配的 URL 是

/Adminstration/Reports

/Production

Extend Route Match

默认匹配只能 cover 简单的场景, 真实项目中, 通常会需要 extend.

Extend Path

extend product name

花括弧是 dynamic value, 问号是可有可无的意思.

RouteData 是用来获取 dynamic value 的

它匹配

/ProductDetail

/ProductDetail/whatever

这样就可以做 dynamic page 了.

Add extra route match

builder.Services.AddRazorPages(options =>
{
options.Conventions.AddPageRoute("/ProductDetail", "/product-detail");
options.Conventions.AddPageRoute("/ProductDetail", "/product-information");
});

注: 它是 extend 不是 override 哦

它可以 match URL:

/ProductDetail

/product-detail

/product-information

有时候 URL 换了, 可以用这招来做 301 redirect.

Override Route Match

这个结构默认匹配是

/Product/iPhone

/Product/iPhone/Index

通过 @page "/YourRootPath" 就可以完全覆盖默认匹配了

修改后的匹配是 /iPhone

注: 开头是 "/" 才表示 override 哦, 不然就是 extend 了

Modify Default Route Match Pattern

虽然可以 extend 和 override, 但是底层的问题还是得通过修改底层去解决.

modify root folder

默认是 /Pages

builder.Services.AddRazorPages(options =>
{
options.RootDirectory = "/Web";
});

to kebab-case

参考: stackoverflow – Automatically generate lowercase dashed routes in ASP.NET Core

builder.Services.AddRazorPages(options =>
{
options.RootDirectory = "/Web";
options.Conventions.Add(new PageRouteTransformerConvention(new KebabCaseTransformer()));
});

KebabCaseTrasformer

public class KebabCaseTransformer : IOutboundParameterTransformer
{
public string? TransformOutbound(object? value)
{
if (value == null) return null;
if (value.ToString()! == "") return ""; return ToKebabCase(value.ToString()!); string ToKebabCase(string value)
{
return value == "AboutUs" ? "about-us" : value;
}
}
}

ASP.NET Core 在创建 route mapping 时会遍历所有的 @page .cshtml

然后依据 folder file name 做 route, 这时拦截它就可以替换掉它的机制.

Conventions 就是拦截点.

Transformer 是一个比较具体的替换方式, 如果想换的更复杂一点就要直接使用 IPageRouteModelConvention

PageRouteTransformerConvention 就是继承了 IPageRouteModelConvention.

Fully Customize

添加 Convention, Convention 是可以多个的, 类似 middleware 那样.

builder.Services.AddRazorPages(options =>
{
options.RootDirectory = "/Web";
options.Conventions.Add(new MyPageRouteModelConvention());
});

MyPageRouteModelConvention

public class MyPageRouteModelConvention : IPageRouteModelConvention
{
public void Apply(PageRouteModel model)
{
var path = model.ViewEnginePath; // /FolderName/FileName e.g. /Mac/Compare/Index
if (path.Contains("AboutUs"))
{
model.RouteParameterTransformer = new KebabCaseTransformer(); // 就是这里换 transform 的
model.Selectors.Clear(); // selectors 就是关键. 把原本的 clear 到完
model.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Template = "/about-us"
}
});
}
}
}

从 model 里面获取信息, 然后修改 Selectors (它就是最终的匹配)

我们来看看原本的 Selectors, 这样就大概知道要怎么改了

 

默认它生成了 2 个 Selectors

 

第一个是 AboutUs/Index, 第 2 个是 AboutUs

Index suppress link generation = true, 所有 link generation 不会 generate 出这样的 path.

IsAbsoluteTemplate 指的是 template 是否 start with slash "/"

我们加上 extend 和 override path 看看

EndpointMetadata 可以获取到 RouteTemplate, 如果没有就是 null, 但 EndpointMetadata 是一定会有的

总结

要想完全控制最终的 route mapping 就需要添加 Convention

通过 model.ViewEnginePath 获取到 folder 和 file name

通过 model.Selectors 获取原本的 Selectors info, 最重要的是 EndpointMetadata 可以获取到 RouteTemplate

最后通过 add/edit/delete Selectors 来达成最终的 mapping override.

我自己的做法是:

1. kebab-case

2. remove 掉 Index 访问

3. 支持多语言 /zh-hans/about-us, /jp/about-us

关于 Link Generation

tag helper 可以通过 PageName (folder file name) 自动生成 URL

<a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>

也可以在代码中调用

当 URL 换了以后, 不需要全场找 anchor 替换. 这个出发点是好的. 但是目前的 Link Generation 不是很给力.

几年前我就有提过 issue, 但最后不了了之. 而现阶段也还有很多待加强的地方 Link generation improvements issue

所以呢, 如果你有修改很多 default route 机制的话, 不建议使用 link generation 来管理. hardcode URL 就可以了. 毕竟 URL 也不是随随便便可以换的丫, SEO 不用管吗 ?不需要 301 redirect ?

ASP.NET Core – Razor Pages Routing的更多相关文章

  1. ASP.NET Core Razor Pages

    Razor 页面是Asp.Net Core2.0新增的一个功能.Razor 页面是 ASP.NET Core MVC 的一个新特性,它可以使基于页面的编码方式更简单高效. 环境:vs2017 .net ...

  2. ASP.NET Core Razor Pages 初探

    最近新建 Asp.net Core MVC 项目的时候不小心选错了个模板,发现了一种新的项目模板.它使用cshtml视图模板,但是没有Controller文件夹.后来才发现这是ASP.NET Core ...

  3. ASP.NET Core - Razor页面之Handlers处理方法

    简介 在前一篇文章中,我们讨论了Razor页面.今天我们来谈谈处理方法(Handlers). 我们知道可以将代码和模型放在 .cshtml 文件里面或与 .cshtml 匹配的 .cshtml.cs ...

  4. ASP.NET Core:Pages

    ylbtech-ASP.NET Core:Pages 1.返回顶部 1._Layout.cshtm <!DOCTYPE html> <html> <head> &l ...

  5. .NET Core Razor Pages中ajax get和post的使用

    ASP.NET Core Razor Pages Web项目大部分情况下使用继承与PageModel中的方法直接调用就可以(asp-page),但是有些时候需要使用ajax调用,更方便些.那么如何使用 ...

  6. C# -- HttpWebRequest 和 HttpWebResponse 的使用 C#编写扫雷游戏 使用IIS调试ASP.NET网站程序 WCF入门教程 ASP.Net Core开发(踩坑)指南 ASP.Net Core Razor+AdminLTE 小试牛刀 webservice创建、部署和调用 .net接收post请求并把数据转为字典格式

    C# -- HttpWebRequest 和 HttpWebResponse 的使用 C# -- HttpWebRequest 和 HttpWebResponse 的使用 结合使用HttpWebReq ...

  7. ASP.NET Core - Razor 页面简介

    简介 随着ASP.NET Core 2 即将来临,最热门的新事物是Razor页面.在之前的一篇文章中,我们简要介绍了ASP.NET Core Razor 页面. Razor页面是ASP.NET Cor ...

  8. ASP.NET Core Razor中处理Ajax请求

    如何ASP.NET Core Razor中处理Ajax请求 在ASP.NET Core Razor(以下简称Razor)刚出来的时候,看了一下官方的文档,一直没怎么用过.今天闲来无事,准备用Rozor ...

  9. 学习ASP.NET Core Razor 编程系列一

    一. 概述 .NET Core 1.0发布的时候就想进行学习的,不过根据微软的以往的发布规律1.0版可以认为是大众测试版,2.0才算稳定.现在2.1都已经发布了预览版,之前对其"不稳定&qu ...

  10. 学习ASP.NET Core Razor 编程系列四——Asp.Net Core Razor列表模板页面

    学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...

随机推荐

  1. 解决方案 | Citrix Receiver无法正常启动的多种解决方案

    下面是个人在实践过程中总结的解决办法: 方案1:卸载Citrix Receiver(一般通过控制面板卸载,如果正常无法卸载则需要通过官方卸载软件ReceiverCleanupUtility软件卸载), ...

  2. Vue项目刷新页面 IE/360 浏览器 input输入框不清空问题处理

    本人在项目开发中,遇到IE/360关于input输入框的兼容问题, 背景介绍:html中直接引用vue.js,及相关组件,input内容不为空时,刷新页面,chrome,Firefox显示正常,IE/ ...

  3. MySQL之DQL

    *****DQL -- 数据查询语言   查询不会修改数据库表记录! 一. 基本查询 1. 字段(列)控制 1) 查询所有列  SELECT * FROM 表名;  SELECT * FROM emp ...

  4. JMeter Sampler-http请求之KeepAlive使用总结

    Sampler-http请求之KeepAlive使用总结 测试环境 apache-jmeter-2.13 KeepAlive使用介绍 说明: 1.Use KeepAlive 勾上,则表示为求连接设置请 ...

  5. 如何让SQL Server像MySQL一样拥有慢查询日志(Slow Query Log慢日志)

    如何让SQL Server像MySQL一样拥有慢查询日志(Slow Query Log慢日志) SQL Server一直以来被人诟病的一个问题是缺少了像MySQL的慢日志功能,程序员和运维无法知道数据 ...

  6. 百度翻译network里没有sug(文章发布时间2022年10月)

    百度翻译已经更新,现在的百度翻译分为两个阶段翻译,第一个阶段识别你的翻译字符是什么类型语言 第二阶段生成随机sign加携带token以post表单方式上传数据,返回json数据 尚硅谷在B站发布的的爬 ...

  7. 加油,为Vue3提供一个可媲美Angular的ioc容器

    为什么要为Vue3提供ioc容器 Vue3因其出色的响应式系统,以及便利的功能特性,完全胜任大型业务系统的开发.但是,我们不仅要能做到,而且要做得更好.大型业务系统的关键就是解耦合,从而减缓shi山代 ...

  8. 【Spring Data JPA】10 对象导航查询

    定义: 查询一个记录时,也就是查询这个对象,通过这个对象查询他的关联对象 [说白了不就是从我们设置好的集合中获取不就完了吗] 环境搭建: INSERT INTO `jpa`.`cst_customer ...

  9. 自然语言处理:通过API调用各大公司的机器翻译开放平台

    国内大公司做机器翻译做的比较好的有讯飞和百度,这里给出这两个公司机器翻译的开放平台API的介绍: 讯飞开放平台: 链接:https://www.xfyun.cn/doc/nlp/xftrans_new ...

  10. 乌克兰学者的学术图谱case3

    ============================================ 背景: 弗兰采维奇材料问题研究是欧洲最大的材料科研院所,在核电.航空.航天.军工及其他装备制造领域的先进材料研 ...