ASP.NETCore中的SEO优化(3):自定义路由匹配和生成

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

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

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

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

  • 栏目的列表 ->/{父栏目名}/{子栏目名}-{页码}/
  • 文章详情页 ->/{栏目名}/{文章名}.html
  • 标签页 ->/{标签名}

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

app.UseMvc(routes => { routes.MapRoute( name: "article_list", template: "{parentCategory}/{category}-{page}/", defaults: new { controller = "Article", action = "Index" }); routes.MapRoute( name: "article_detail", template: "{category}/{article}.html", defaults: new { controller = "Article", action = "Detail" }); routes.MapRoute( name: "tags", template: "{tag}/", defaults: new { controller = "Article", action = "Tag" }); }); 

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

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

namespace Microsoft.AspNetCore.Routing { public interface IRouter { Task RouteAsync(RouteContext context); VirtualPathData GetVirtualPath(VirtualPathContext context); } } 

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

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

public async Task RouteAsync(RouteContext context) { var requestedUrl = context.HttpContext.Request.Path.Value.TrimStart('/').ToLower(); var split = requestedUrl.Split('/'); if (secoend != null && secoend.EndsWith(".html") && split.Length == 2) { var title = secoend.Replace(".html", ""); context.RouteData.Values["controller"] = "Article"; context.RouteData.Values["action"] = "Detail"; context.RouteData.Values["category"] = first; context.RouteData.Values["title"] = title; } //...对请求路径进行一系列的判断 //最后注入`MvcRouteHandler`示例执行`RouteAsync`方法,表示匹配成功 await context.HttpContext.RequestServices.GetService<MvcRouteHandler>().RouteAsync(context); } 

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

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

public VirtualPathData GetVirtualPath(VirtualPathContext context) { var path = string.Empty; var hasController = context.Values.TryGetValue("controller", out var controller); var hasAction = context.Values.TryGetValue("action", out var action); var hasCategory = context.Values.TryGetValue("category", out var category); var hasTitle = context.Values.TryGetValue("title", out var title); if (hasController && hasAction && hasCategory && hasTitle) { path = $"/{category/{title}.html"; } return path != string.Empty ? new VirtualPathData(this, path) : null; } 

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

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

app.UseMvc(routes => { //添加 自定义路由匹配与url生成组件 routes.Routes.Add(new RouteProvider()); }); 

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

相关小技巧

public static class UrlHelperExtensions { public static string AbsoluteAction( this IUrlHelper helper, string actionName, string controllerName, object routeValues = null) { string scheme = helper.ActionContext.HttpContext.Request.Scheme; return helper.Action(actionName, controllerName, routeValues, scheme); } public static string AbsoluteContent( this IUrlHelper helper, string contentPath) { return new Uri(helper.ActionContext.HttpContext.Request.GetUri(), helper.Content(contentPath)).ToString(); } public static string AbsoluteRouteUrl( this IUrlHelper helper, string routeName, object routeValues = null) { string scheme = helper.ActionContext.HttpContext.Request.Scheme; return helper.RouteUrl(routeName, routeValues, scheme); } } 

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

原文链接:https://www.cnblogs.com/ElderJames/p/A-Middleware-Implement-For-Customized-Routing-In-AspNetCore.html

原创文章,作者:优速盾-小U,如若转载,请注明出处:https://www.cdnb.net/bbs/archives/21446

(0)
上一篇 2024年1月6日 05:00
下一篇 2024年1月6日

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

优速盾注册领取大礼包www.cdnb.net
/sitemap.xml