住房和城乡建设部网站质保金,企业手机网站建设效果,网站有什么优势,合肥网站建设哪家公司好http://www.cnblogs.com/John-Connor/archive/2012/05/03/2478821.html 引言-- 在初级篇中#xff0c;我们介绍了如何利用基于ASP.NET MVC的Web程序中的Global文件来简单的重写路由。也介绍了它本身的局限性-依赖于路由信息中的键值对: 如果键值对中没有的值#xff0c;我们无…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?categoryid0001viewlistorderbypricepage1http://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 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}}
} 这样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()方法修改一下: 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;} 你就会发现无论你在http//localhost:1234/后面输入任何相对URL都会被定向到HomeController.Index()方法。 因为返回的是路由值而不是null表示已经找到匹配项就不会再往下匹配了。这条规则覆盖了后面所有的规则 当然请不要这样写。。。 由此可以推断出GetRouteData()方法在路由映射中担任的角色处理请求中的URL返回相应的路由值不处理或不匹配则返回null。 3. VirtualPathData()方法 如果你在Razor页面有这样一段通过指定路由值来获取URL的代码 a hrefUrl.Action(Index, Home)首页/a 当视图引擎渲染页面到这句代码时HomeController.Index()方法会被解析为一个RouteValueDictionary类型的不分大小写的键值对假设键值对对象为values: values[controller]Home
values[action]Index 这个键值对表示了一个路由值。 同样是在路由表中自上而下的匹配这个路由值尝试第一条分类规则时就会命中VirtualPathData()方法中的断点。 我们返回一个null,表示不匹配则程序进行下一个规则的匹配。 直到找到主页规则的路由值与之匹配时构造出相应的相对URL并返回该URL。 显示为: a hrefhttp://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来保存分类模型并把所有的分类显示的保存在ListCategory中 View Code 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 ListCategory AllCategories new ListCategory{new Category(){ CategoeyID001, CategoeyNameNokia},new Category(){ CategoeyID002, CategoeyNameiPhone},new Category(){ CategoeyID003, CategoeyNameAnycall}};}
} 假设我们网站的CategoryController是这样的。 View Code 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);}}
} 首先我们建议VirtualPathData()和GetRouteData()方法是成双成对出现的。一旦你制定了一条路由规则比如分类规则/ca-categoryname,那么: GetRouteData()必须处理与这条规则匹配的每一条URL返回相同的路由值放弃与之不匹配的URL返回null让匹配继续。VirtualPathData()必须处理与这条规则匹配的每一次路由请求返回相同的URL;放弃与之不匹配的请求返回null让匹配继续。 两者相辅相成的完成了路由值和URL的相互映射漏掉一个就不能构成一个完成的路由规则。直接结果是出现404或生成URL地址错误。 GetRouteData()的代码: public override RouteData GetRouteData(System.Web.HttpContextBase httpContext){var virtualPath httpContext.Request.AppRelativeCurrentExecutionFilePath httpContext.Request.PathInfo;//获取相对路径virtualPath virtualPath.Substring(2).Trim(/);//此时URL会是/ca-categoryname截取后面的ca-categorynameif (!virtualPath.StartsWith(ca-))//判断是否是我们需要处理的URL不是则返回null匹配将会继续进行。return null;var categoryname virtualPath.Split(-).Last();//截取ca-前缀后的分类名称//尝试根据分类名称获取相应分类忽略大小写var category CategoryManager.AllCategories.Find(c c.CategoeyName.Equals(categoryname,StringComparison.OrdinalIgnoreCase));if (category null)//如果分类是null可能不是我们要处理的URL返回null让匹配继续进行return null;//至此可以肯定是我们要处理的URL了var data new RouteData(this, new MvcRouteHandler());//声明一个RouteData添加相应的路由值data.Values.Add(controller, Category);data.Values.Add(action, ShowCategory);data.Values.Add(id, category.CategoeyID);return data;//返回这个路由值将调用CategoryController.ShowCategory(category.CategoeyID)方法。匹配终止} VirtualPathData()的代码 public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values){//判断请求是否来源于CategoryController.Showcategory(string id),不是则返回null,让匹配继续var categoryId values[id] as string;if (categoryId null)//路由信息中缺少参数id不是我们要处理的请求返回nullreturn null;//请求不是CategoryController发起的不是我们要处理的请求返回nullif (!values.ContainsKey(controller) || !values[controller].ToString().Equals(category,StringComparison.OrdinalIgnoreCase))return null;//请求不是CategoryController.Showcategory(string id)发起的不是我们要处理的请求返回nullif (!values.ContainsKey(action) || !values[action].ToString().Equals(showcategory, StringComparison.OrdinalIgnoreCase))return null;//至此我们可以确定请求是CategoryController.Showcategory(string id)发起的生成相应的URL并返回var category CategoryManager.AllCategories.Find(c c.CategoeyID categoryId);if (category null)throw new ArgumentNullException(category);//找不到分类抛出异常var path ca- category.CategoeyName.Trim();//生成URLreturn new VirtualPathData(this, path.ToLowerInvariant());} 至此我们就把这条路由规则的映射处理完整了。如果你掌握了上述技术任何的URL重写和优化需求我相信你都能Hold住。 如果我们的主页页面是这样Razor视图引擎 View Code model ListJohnConnor.Models.Category
{ViewBag.Title 主页;
}h2a hrefUrl.Action(Index, Home)首页/a/h2
p
foreach (var item in Model)
{a hrefUrl.Action(ShowCategory, Category, new { id item.CategoeyID })item.CategoeyName/a
}
/p 三个分类连接会得到这样的结果 a href/ca-nokiaNokia/a
a href/ca-iphoneiPhone/a
a href/ca-anycallAnycall/a 点击每一个连接都会先进入我们的处理程序生成相应的路由值-调用CategoryController.Showcategory(string id)方法根据id显示相应的分类页面。 ------------------------------------------------------进阶篇完--------------------------------------------------- 这一篇我花费了不少时间去构思如何用简单的例子讲述继承RouteBase来进行URL重写与优化。 希望能帮助到有用的人。 需要程序源代码朋友点这里:JohnConnor.UrlRewrite.rar 如有任何问题欢迎指正和讨论。转载于:https://www.cnblogs.com/tonykan/archive/2012/12/18/2824045.html