前言

前两篇文章主要总结了CMS系统两个技术点在ASP.NET Core中的应用:

  • 《ASP.NET Core 中的SEO优化(1):中间件实现服务端静态化缓存》

  • 《ASP.NET Core 中的SEO优化(2):中间件中渲染Razor视图》

而本篇文章,继续介绍另一个技术点:自定义路由匹配和生成。

背景

在MVC5时代,默认的路由可能就是简单的约定/{controller}/{action}/{id},第一节对应控制器(Controller)名,第二节对应操作(Action)名,第三节是参数名。
在WebApi和ASP.NET Core时代,有了Route特性来指定相应操作的路由指向,可以很灵活地配置RESTful Api。

但是,路由灵活性在注重SEO的CMS系统中有更苛刻的要求。例如:

  • 栏目的列表 ->/{父栏目名}/{子栏目名}-{页码}/

  • 文章详情页 ->/{栏目名}/{文章名}.html

  • 标签页 ->/{标签名}

这些友好的url链接使用默认的路由约定是很难实现的,当然是可以配置路由规则去传递参数:

  1. app.UseMvc(routes =>

  2. {

  3.    routes.MapRoute(

  4.        name: "article_list",

  5.        template: "{parentCategory}/{category}-{page}/",

  6.        defaults: new { controller = "Article", action = "Index" });

  7.    routes.MapRoute(

  8.        name: "article_detail",

  9.        template: "{category}/{article}.html",

  10.        defaults: new { controller = "Article", action = "Detail" });

  11.    routes.MapRoute(

  12.        name: "tags",

  13.        template: "{tag}/",

  14.        defaults: new { controller = "Article", action = "Tag" });

  15.    });

但是,这样配置很繁琐,也不灵活,如果还要传入更多规则,比如不向下匹配,就显得捉襟见肘了。那有没有更灵活的方案呢?当然有,就是本文接下来要介绍的IRouter接口。

原理

上一节最后介绍的一般路由配置方法,其实是MapRoute方法创建一个个IRouter的实例,添加到IRouteBuilder实例中,具体方法可以看看源码。

所以我们可以实现一个自定义的IRouter,就能不用默认的约定,去实现我们的苛刻需求。

首先要看看IRouter这个接口的定义,源码在aspnet/Routing/src/Microsoft.AspNetCore.Routing.Abstractions/IRouter.cs

  1. namespace Microsoft.AspNetCore.Routing

  2. {

  3.    public interface IRouter

  4.    {

  5.        Task RouteAsync(RouteContext context);

  6.        VirtualPathData GetVirtualPath(VirtualPathContext context);

  7.    }

  8. }

实现

IRouter接口只有两个方法,本文分别给出代码示例来介绍。

RouteAsync

这个方法中实现路由匹配,从路由上下文中获取所需要的数据,存入RouteData字典中,再从控制器取出做相应的处理。

  1. public async Task RouteAsync(RouteContext context)

  2. {

  3.    var requestedUrl = context.HttpContext.Request.Path.Value.TrimStart('/').ToLower();

  4.    var split = requestedUrl.Split('/');

  5.    if (secoend != null && secoend.EndsWith(".html") && split.Length == 2)

  6.    {

  7.        var title = secoend.Replace(".html", "");

  8.        context.RouteData.Values["controller"] = "Article";

  9.        context.RouteData.Values["action"] = "Detail";

  10.        context.RouteData.Values["category"] = first;

  11.        context.RouteData.Values["title"] = title;

  12.    }

  13.    //...对请求路径进行一系列的判断

  14.    //最后注入`MvcRouteHandler`示例执行`RouteAsync`方法,表示匹配成功

  15.    await context.HttpContext.RequestServices.GetService<MvcRouteHandler>().RouteAsync(context);

  16. }

这样,当请求路由为/news/asp.net.html时,就会匹配到上面的规则,请求进入Article控制器中的Detail操作被处理,并且可以从控制器中的RouteData.Values["category"]?.ToString();方法拿到所需的数据。

GetVirtualPath

这个方法实现路由生成,可以从路由上下文中获取RouteData字典中的数据,进行虚拟路径(区别与真实目录)的生成。

  1. public VirtualPathData GetVirtualPath(VirtualPathContext context)

  2. {

  3.    var path = string.Empty;

  4.    var hasController = context.Values.TryGetValue("controller", out var controller);

  5.    var hasAction = context.Values.TryGetValue("action", out var action);

  6.    var hasCategory = context.Values.TryGetValue("category", out var category);

  7.    var hasTitle = context.Values.TryGetValue("title", out var title);

  8.    if (hasController && hasAction && hasCategory && hasTitle)

  9.    {

  10.        path = $"/{category/{title}.html";

  11.    }

  12.    return path != string.Empty ? new VirtualPathData(this, path) : null;

  13. }

这样,当调用路径生成方法@Url.Action("Detail","Article",new { title="asp.net", category="news" }),就会生成”/news/asp.net.html”这样的路径来。

IRouter的设置生效

自定义实现的IRouter如何设置到原有的MVC项目中呢?方法很简单,上面已经简单说道了,其实app.UseMvc这个方法就有添加IRouter的方法:

  1. app.UseMvc(routes =>

  2. {

  3.    //添加 自定义路由匹配与url生成组件

  4.    routes.Routes.Add(new RouteProvider());

  5. });

这里RouteProviderIRouter的实现,这样自定义的路由提供对象就生效啦!

相关小技巧

  1. SEO中会有一条铁规则,就是不是有效链接的情况下只能返回404,比如,手动输入了一个路径,能匹配到文章详情的操作(action),如果数据库中查不出文章,本来应该不能匹配的,但是,如果在匹配的时候查询数据库确认是否存在的话,会加大系统的压力,所以,可以放在操作(action)中查询,查不到再返回NotFound,让上一篇文章《ASP.NET Core 中的SEO优化(2):中间件中渲染Razor视图》中介绍的中间件一并处理输出404页面。

  2. 站内链接如果使用带域名的绝对路径,能够提高优化效果,我们可以自己写一个UrlHelper的扩展方法:

  1. public static class UrlHelperExtensions

  2. {

  3.    public static string AbsoluteAction(

  4.        this IUrlHelper helper,

  5.        string actionName,

  6.        string controllerName,

  7.        object routeValues = null)

  8.    {

  9.        string scheme = helper.ActionContext.HttpContext.Request.Scheme;

  10.        return helper.Action(actionName, controllerName, routeValues, scheme);

  11.    }

  12.    public static string AbsoluteContent(

  13.        this IUrlHelper helper,

  14.        string contentPath)

  15.    {

  16.        return new Uri(helper.ActionContext.HttpContext.Request.GetUri(), helper.Content(contentPath)).ToString();

  17.    }

  18.    public static string AbsoluteRouteUrl(

  19.        this IUrlHelper helper,

  20.        string routeName,

  21.        object routeValues = null)

  22.    {

  23.        string scheme = helper.ActionContext.HttpContext.Request.Scheme;

  24.        return helper.RouteUrl(routeName, routeValues, scheme);

  25.    }

  26. }

总结

本文主要介绍了自定义路由匹配和生成的解决方案,把路由相关的处理集中到一个类中,避免分散在各个视图进行维护。下篇文章,将会介绍自定义视图搜索目录及主题切换。

原文:https://yangshunjie.com/A-Middleware-Implement-For-Customized-Routing-In-AspNetCore.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com 



自定义路由匹配和生成相关推荐

  1. Flask 正则路由匹配——转换器

    给路由传参 有时我们需要将同一类 URL 映射到同一个视图函数处理,比如:使用同一个视图函数来显示不同用户的个人信息. 路由传递参数 @app.route('/user/<user_id> ...

  2. c# mvc html.beginform,asp.net-mvc – 使用Html.BeginForm()与自定义路由

    这是你一定知道的默认路由: routes.MapRoute( "Default",// Route name "{controller}/{action}/{id}&qu ...

  3. 千亿流量拦截控制处理技术-Nginx(安装 命令 路由匹配 负载均衡 常用配置)

    千亿流量拦截控制处理技术-Nginx Nginx使用与配置 1 什么是nginx 1.1 可大量并行处理 1.2 与 Apache 相比 1.2.1 Apache VS Nginx 1.2.2 常用w ...

  4. [ASP.NET MVC2 系列] ASP.NET MVC 之如何创建自定义路由约束

     [ASP.NET MVC2 系列]      [ASP.NET MVC2 系列] ASP.Net MVC教程之<在15分钟内用ASP.Net MVC创建一个电影数据库应用程序>      ...

  5. spring boot 跨域请求_SpringBoot 系列教程 web 篇之自定义请求匹配条件 RequestCondition...

    191222-SpringBoot 系列教程 web 篇之自定义请求匹配条件 RequestCondition 在 spring mvc 中,我们知道用户发起的请求可以通过 url 匹配到我们通过@R ...

  6. SpringCloud Gateway配置自定义路由404坑

    一.场景复现 微服务自定义路由,返回404页面. ①如图: (1)springcloud-gateway的路由设置 @Configuration public class RouteConfig {@ ...

  7. MVC源码分析 - 路由匹配

    上一篇 说到了路由事件注册以及路由表的生成, 前面 也解析到了, 管道事件的建立, 那么接下来, 肯定就是要调用执行这些事件了, 这些就不表了, 我已经得到我想要的部分了, 接下来, 在执行这些管道事 ...

  8. 互联网技术-alibaba-gateway网关中routers路由匹配规则

    gateway的主要功能之一是转发请求,转发规则的定义主要包含三个部分 组成 描述 路由 Route 路由是网关的基本单元, 由ID.URI.一组Predicate.一组Filter组成,根据Pred ...

  9. vue路由匹配实现包容性_开发更具包容性的肤色范围

    vue路由匹配实现包容性 Nadia Fawaz | Research Scientist & Tech Lead, Applied Science, Bhawna Juneja | Soft ...

最新文章

  1. layui数据表格自定义复选框表头_解决LayUI数据表格复选框不居中显示的问题
  2. 写一下这两天的生活吧!开学了,也没有多少时间了
  3. 5.1.8 缓冲区管理
  4. 公网IP的判断和获取
  5. (pytorch-深度学习系列)ResNet残差网络的理解-学习笔记
  6. bootstrap table 怎么实现前两列固定冻结?
  7. uniapp 表单提交图片跟其他填写数据_记录第一次实现表单数据提交到数据库
  8. python爬虫什么意思-Python爬虫是什么意思有啥用 python爬虫原理实例介绍
  9. matlab数据变成一列数据,用MATLAB处理EXCEL中一列共100000个数据,请问如何将数据导入并将数据做正态曲线拟合...
  10. Altium Designer——AD画PCB图步骤总结
  11. Java:等额本息还款计算
  12. 人世轮回,无人相怜--观《艺妓回忆录》有感
  13. Verilog HDL
  14. SpringBoot初级学习笔记--稀客大大
  15. CREO6.0装配工程图总重添加。
  16. 2019游戏培训要花多少钱?
  17. 清除挖矿病毒solr记录
  18. KETTLE读取api接口(rest接口)数据
  19. 三菱880彩铅和uni的区别_彩铅工具测评 篇十八:新手想要花卉/多肉更有层次感?来试试三菱uni880彩铅!...
  20. 【VScode安装】

热门文章

  1. 如何关闭Struts2的webconsole.html
  2. linux(centos) NET模式网络配置
  3. LVM基本应用 扩展及缩减实现
  4. java集合学习笔记 ---Collections类对集合的处理
  5. .net framework3.0_
  6. Windows Phone 7Silverlight控件之--Panorama
  7. OAuth 2.0 的探险之旅
  8. Dapr + .NET 实战(十三)跨语言开发
  9. NET问答: C# 中是否有最高效的方式对大文件做 checksum ?
  10. 杨中科.NET5视频教程更新了:DI、配置系统、Logging、EF Core等