ASP.NET MVC URL重写与优化(进阶篇)-继承RouteBase玩转URL
http://www.cnblogs.com/John-Connor/archive/2012/05/03/2478821.html
引言--
在初级篇中,我们介绍了如何利用基于ASP.NET MVC的Web程序中的Global文件来简单的重写路由。也介绍了它本身的局限性-依赖于路由信息中的键值对:
如果键值对中没有的值,我们无法将其利用凑出我们想要的URL表达式。
初级篇传送门:使用Global路由表定制URL
在进阶篇中,我们将介绍ASP.NET 路由相关类的基类-抽象类RouteBase,并演示如何通过继承它,让URL重写和优化变成Free Style。
一,老板的需求
假设我们是手机销售网站的一名程序猿(承接初级篇),经过第一次的URL重写之后,我们的手机分类页面的URL的改变:
http://www.xxx.com/category/showcategory?categoryid=0001&view=list&orderby=price&page=1=>http://www.xxx.com/category/0001
现在老板又提出了新的需求,URL的语义化,从而更好的反应网站的结构:
http://www.xxx.com/ca-categoryname
比如Nokia是一个分类,那么对应URL为 /ca-nokia,如果是iPhone分类,URL则对应 /ca-iphone。ca前缀的意思是分类category。
对于这个需求简单的配置Global文件是无法做到的。首先我们来介绍一下ASP.NET 路由的所有类的基类RouteBase。
二,RouteBase类简介与运行机制
1. RouteBase类位于System.Web.Routing命名空间,结构如下:
public abstract class RouteBase{protected RouteBase();public abstract RouteData GetRouteData(HttpContextBase httpContext);public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);}
- GetRouteData:根据Http请求信息返回一个对象-包含路由定义的值(如果该路由与当前请求匹配)或 null(如果该路由与请求不匹配)。
- GetVirtualPath:检查路由值是否与某个规则匹配,返回一个对象(包含生成的 URL 和有关路由的信息)或 null(如果路由与 values 不匹配)。
- RouteBase:初始化该类供继承的类实例使用。此构造函数只能由继承的类调用。
看完以上定义,可能大家会晕忽忽。我们来弄一个简单的例子说明这几个方法是如何运作的。
首先我们新建一个类库JohnConnor.Routing,并且继承抽象类RouteBase:
![](/assets/blank.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text;using System.Web.Mvc;//需要添加引用,请使用3.0以上版本 using System.Web.Routing; using JohnConnor.Models; namespace JohnConnor.Routing {public class CategoryUrlProvider:RouteBase{public override RouteData GetRouteData(System.Web.HttpContextBase httpContext){return null;//断点1}public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values){return null;//断点2}} }
![](/assets/blank.gif)
这样CategoryUrlProvider类就包含了用来处理路由映射的方法。
首先我们需要在Web程序中添加JohnConnor.Routing类库的引用,然后我们把CategoryUrlProvider类注册到Global文件的路由表中。
public static void RegisterRoutes(RouteCollection routes){ routes.IgnoreRoute("{resource}.axd/{*pathInfo}");routes.Add(new JohnConnor.Routing.CategoryUrlProvider());//分类规则 routes.MapRoute("Home", "", new { controller = "Home", action = "Index"});//主页 }
这里相当于添加了一条新的路由规则。重新生成一下Web程序在CategoryUrlProvider中打好断点,F5启动。
2. GetRouteData()方法
这时候相当与你在浏览器输入了http//localhost:1234/<假设本地端口号是1234>,此时程序需要判断这个URL匹配的是哪个路由值。
自上而下的匹配,首先会尝试匹配我们新增的分类路由规则,此时会命中GetRouteData()方法中的断点。
因为我们返回了null,意味着该请求与我们新增的分类路由规则不匹配,那程序将在路由表中继续自上而下的进行匹配。
直到在主页这一条规则中与其URL表达式匹配,获取了对应的路由值-调用HomeController.Index()方法。
如果你把GetRouteData()方法修改一下:
![](/assets/blank.gif)
public override RouteData GetRouteData(System.Web.HttpContextBase httpContext){var data = new RouteData(this, new MvcRouteHandler());data.Values.Add("controller", "Home");data.Values.Add("action", "Index");return data;}
![](/assets/blank.gif)
你就会发现,无论你在http//localhost:1234/后面输入任何相对URL,都会被定向到HomeController.Index()方法。
因为返回的是路由值而不是null,表示已经找到匹配项,就不会再往下匹配了。<这条规则覆盖了后面所有的规则>
当然,请不要这样写。。。
由此可以推断出GetRouteData()方法在路由映射中担任的角色:处理请求中的URL,返回相应的路由值,不处理或不匹配则返回null。
3. VirtualPathData()方法
如果你在Razor页面有这样一段通过指定路由值来获取URL的代码
<a href="@Url.Action("Index", "Home")">首页</a>
当视图引擎渲染页面到这句代码时,HomeController.Index()方法会被解析为一个RouteValueDictionary类型的不分大小写的键值对<假设键值对对象为values>:
values["controller"]="Home"; values["action"]="Index";
这个键值对表示了一个路由值。
同样是在路由表中自上而下的匹配这个路由值,尝试第一条分类规则时,就会命中VirtualPathData()方法中的断点。
我们返回一个null,表示不匹配,则程序进行下一个规则的匹配。
直到找到主页规则的路由值与之匹配时,构造出相应的相对URL"",并返回该URL。
显示为:
<a href="http://localhost:1234/">首页</a>
如果我们也改写一下VirtualPathData()方法:
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values){return new VirtualPathData(this, "This-is-a-Test-URL");}
结果是你通过上述方法构造的URL不论请求来自哪里,全部都会显示成http://localhost:1234/This-is-a-Test-URL
因为我们返回的是一个相对路径,而不是null,表示已经找到匹配项,则匹配不会往下继续。<同上这条规则覆盖了后面所有的规则>
再一次提示,请不要这样写。。。
由此可看出,VirtualPathData()在路由映射中的活:处理请求与路由键值对,生成相应URL,不处理或不匹配则返回null。
4.方法重写的规则
在上文中,我一再的用红色字体提示,请不要这样写。因为每一个URL的重写类,建议仅仅处理尽可能少的路由映射。
比如CategoryUrlProvider仅处理CategoryController.Show(string categoeyid)这一个Action方法的映射。凡是不是这个方法相关的映射,都返回null。
继续去匹配别的规则。
三,开始动手把~
为了最快的说明问题,我们简化了网站的内容。以下内容有助于理解后面的程序,如果时间充裕,还是自己构建一个网站来尝试以下。
首先我们在JohnConnor.Routing类库中创建Category.cs来保存分类模型,并把所有的分类显示的保存在List<Category>中,
![](/assets/blank.gif)
![](/assets/blank.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Web;namespace JohnConnor.Models {//分类模型public class Category{public string CategoeyID { get; set; }public string CategoeyName { get; set; }}public static class CategoryManager{//这里只显示创建了三个分类作为示例,实际中AllCategories可以从数据源读取。public static readonly List<Category> AllCategories = new List<Category>{new Category(){ CategoeyID="001", CategoeyName="Nokia"},new Category(){ CategoeyID="002", CategoeyName="iPhone"},new Category(){ CategoeyID="003", CategoeyName="Anycall"}};} }
![](/assets/blank.gif)
假设我们网站的CategoryController是这样的。
![](/assets/blank.gif)
![](/assets/blank.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using JohnConnor.Models; namespace JohnConnor.Web.Controllers {public class CategoryController : Controller{public ActionResult ShowCategory(string id){var category = CategoryManager.AllCategories.Find(c => c.CategoeyID == id);return View(category);}} }
![](/assets/blank.gif)
首先我们建议,VirtualPathData()和GetRouteData()方法是成双成对出现的。一旦你制定了一条路由规则,比如分类规则/ca-categoryname,那么:
- GetRouteData()必须处理与这条规则匹配的每一条URL,返回相同的路由值;放弃与之不匹配的URL,返回null,让匹配继续。
- VirtualPathData()必须处理与这条规则匹配的每一次路由请求,返回相同的URL;放弃与之不匹配的请求,返回null,让匹配继续。
!!!两者相辅相成的完成了路由值和URL的相互映射,漏掉一个,就不能构成一个完成的路由规则。直接结果是出现404或生成URL地址错误。
GetRouteData()的代码:
VirtualPathData()的代码
至此,我们就把这条路由规则的映射处理完整了。如果你掌握了上述技术,任何的URL重写和优化需求,我相信你都能Hold住。
如果我们的主页页面是这样<Razor视图引擎>:
![](/assets/blank.gif)
![](/assets/blank.gif)
@model List<JohnConnor.Models.Category> @{ViewBag.Title = "主页"; }<h2><a href="@Url.Action("Index", "Home")">首页</a></h2> <p> @foreach (var item in Model) {<a href="@Url.Action("ShowCategory", "Category", new { id = item.CategoeyID })">@item.CategoeyName</a> } </p>
![](/assets/blank.gif)
三个分类连接会得到这样的结果
<a href="/ca-nokia">Nokia</a> <a href="/ca-iphone">iPhone</a> <a href="/ca-anycall">Anycall</a>
点击每一个连接都会先进入我们的处理程序,生成相应的路由值-调用CategoryController.Showcategory(string id)方法根据id显示相应的分类页面。
------------------------------------------------------进阶篇完---------------------------------------------------
这一篇我花费了不少时间去构思如何用简单的例子讲述继承RouteBase来进行URL重写与优化。
希望能帮助到有用的人。
需要程序源代码朋友点这里:JohnConnor.UrlRewrite.rar
如有任何问题,欢迎指正和讨论。
转载于:https://www.cnblogs.com/zcm123/p/4751878.html
ASP.NET MVC URL重写与优化(进阶篇)-继承RouteBase玩转URL相关推荐
- ASP.NET MVC URL重写与优化(进阶篇)-继承RouteBase玩转URL(转)
http://www.cnblogs.com/John-Connor/archive/2012/05/03/2478821.html 引言-- 在初级篇中,我们介绍了如何利用基于ASP.NET MVC ...
- [转载]ASP.NET MVC URL重写与优化(进阶篇)-继承RouteBase玩转URL
引言-- 在初级篇中,我们介绍了如何利用基于ASP.NET MVC的Web程序中的Global文件来简单的重写路由.也介绍了它本身的局限性-依赖于路由信息中的键值对: 如果键值对中没有的值,我们无法将 ...
- ASP.NET MVC URL重写与优化(初级篇)-使用Global路由表定制URL
ASP.NET MVC URL重写与优化(初级篇)-使用Global路由表定制URL 引言--- 在现今搜索引擎制霸天下的时代,我们不得不做一些东西来讨好爬虫,进而提示网站的排名来博得一个看得过去的流 ...
- ASP.NET MVC ETag Cache等优化方法
背景 最近有一个项目是用SmartAdmin + Jquery + EasyUI 一个ASP.NET MVC5的项目,一直存在一个性能问题,加载速度比较慢,第一次加载需要(在没有cache的情况下)需 ...
- [转]Asp.net mvc 网站之速度优化 -- 页面缓存
网站速度优化的一般方法 由于网站最重要的用户体验就是速度,特别是对于电子商务网站而言. 一般网站速度优化会涉及到几个方面: 1. 数据库优化 - 查询字段简历索引,使用数据库连接池和持久化,现在还有种 ...
- 《从零开始学习ASP.NET MVC 1.0》-开天辟地入门篇
<从零开始学习ASP.NET MVC 1.0> 文章导航 (一) 开天辟地入门篇 (二) 识别URL的Routing组件 (三) Controller/Action 深入解析与应用实例 ( ...
- 学习 ASP.NET MVC (第二回)实战篇
上篇简单的了解了ASP.NET MVC的基本概念和基本流程,接下来的几篇将通过简单的实例,来看看如何通过ASP.NET MVC创建应用程序.Demo很简单也很基础,高手绕过. 闲话少说,直接进入正 ...
- Asp.net Mvc Codeplex Preview 5 第三篇 实现Action参数传递繁杂类型 【转】
本文的环境是Asp.net Mvc Codeplex Preview 5 前文提到我们可以使用 Controller中的UpdateModel来获取 繁杂类型 例如 1 UpdateModel(x, ...
- 百度创意采集工具_百度SEM竞价高级优化进阶篇:让你玩转百度竞价轻松月赚几万元...
主要讲解账户优化与调整策略,如何出价与控价技术.质量度提高与创意撰写批量操作技术.提高着陆页转化要点以及跟踪监控转化.知识问答营销等转化攻略等内容,让你轻松玩转百度竞价,月入万元到几万元,完全没任何问 ...
- php 分页 url重写 分页问题,解决千古难题,wordpress分页URL问题,wordpress给分页加链接...
原本的wordpress文章如果分页会成如下的结构: http://www.xyqzmt.cn/1.html/2 通常固定链接都是这样的结构,设为/%postname%.html或者/%post_id ...
最新文章
- 最新组合式模型量化方法,实现FPGA最高硬件利用率,准确率-推理速度达到SOTA...
- 第二课.初识机器学习
- java oracle exp_java中使用oracle的exp/imp导出、导入数据
- 1.2.4 在Python中使用向量化的技巧和注意事项
- hashCode和equals方法的关系
- 6工程文件夹作用_MCUXpresso IDE下SDK工程导入与workspace管理机制
- mac下安装mysql-pyhon_mac下安装MySQL-python模块
- Linux系统管理(7)——Linux单用户模式详解 及应用场景
- 低代码和零代码火了,十大利器推荐!
- (工作中)Apache常见配置
- 使用PyQt打包命令pyinstall的几个问题
- 10 个迅速提升你 Git 水平的提示
- ASP .Net Core系统部署到 CentOS7 64 具体方案
- 【Citrix】XenCenter更新VM内存属性
- win10将Capslock变为Ctrl
- 教育机构:用数字化赋能教育
- LVS (Linux Virtual Server) 负载均衡
- win7用友u8安装教程_技术编辑教你在win7系统中安装用友u8的方案?
- 用c语言编程点菜系统,基于C语言实现点菜系统.pdf
- Android AOA协议Android端 流程总结