存档

文章标签 ‘route’

在Webform (asp.net)中使用Route 路由之中级实现

2012年9月7日 没有评论

相信经过前面2节文字的介绍,同学们可以快速地实现route路由的目的,并运用在实际的项目中了。在这一节里,我们在讲述一下路由更进一步的实现。

在前面的例子里,我们是把所有的路由信息给放在 Globla.asax.cs 文件里了,这样就产生了一个问题:由于实际业务的变化,每次都需要在该文件里做调整,然后重新编译部署。是不是觉得很麻烦,有没有一种更好的方式,不需要编译是最好啦。

很自然,有经验的同学会想到把路由表放在 web.config 配置文件里,这样的话每次在调整的时候只需要修改 web.config 文件就可以了。我也查询了下网上的资料,由于路由表是一个键值队列,需要在 web.config 里添加自定义节点,并且还需要编写这个自定义节点的实现类。我感觉实现思路有些麻烦,所以下面的一种方式就出来了。

我们把路由表信息放在 xml 文件里而不是 web.config 文件里,即使 web.config 事实上也是个xml。这样做的好处,一来不需要编写自定义节点的实现类;二是把路由表单独抽离出来,避免由于路由表的修改而带来误操作影响全局。

我们新建一个PageRoutes文件,继承 RouteBase 类,并实现其方法。主要有2个方法 GetRouteData 和 GetVirtualPath 。这2个方法是什么意思呢,简单地举例说,如果想从 /u/wave 得到 /user.aspx ,调用的是 GetRouteData 方法,如果是从 user.aspx 里得到 /u/wava , 调用的是 GetVirtualPath  方法。后者在 MVC 里用的非常多,在 webform 中,我这里详细描述 GetRouteData  方法,其它的原理是一样的。

我们来新建一个Route.xml文件用来保存路由信息。
<?xml version=”1.0″ encoding=”utf-8″ ?>
<Route>
<Page virtualPath=”/home” routePage=”~/default.aspx” />
<Page virtualPath=”/about” routePage=”~/about.aspx” />
<Page virtualPath=”/u/{userid}/{noteid}” routePage=”~/notedetail.aspx” />
<Page virtualPath=”/u/{userid}” routePage=”~/notelist.aspx” />
</Route>
接下来,我们把精力放在 GetRouteData 方法上,这个方法会拦截所有的请求,如果没有需要处理的,则返回 null 跳过进行后面的操作。下面的代码有点长,来慢慢地解说,

public IRouteHandler RouteHandler { get; set; }

public override RouteData GetRouteData (HttpContextBase httpContext)         {

string xmlPath = httpContext.Server.MapPath (“~”) + “Route.xml”;

if (!File.Exists (xmlPath)) { return null; } //如果配置文件不存在则直接返回

XmlDocument doc = new XmlDocument ( );

doc.Load (xmlPath);

XmlNodeList list = doc.GetElementsByTagName (“Page”);

string virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(1).ToLower();

foreach (XmlNode node in list)          {

string n = node.Attributes[“virtualPath”].Value.ToLower();

//第一步,直接比对,优先级最高

if (n== virtualPath) {

var data = new RouteData();

data.RouteHandler = new PageRoute(node.Attributes[“routePage”].Value);

return data; }

//第二步,带 {userId}的参数比对

string v=n;

string o=new Regex(“{(\\w|\\W)+?}”).Replace(v,”(\\w|\\W)+”);

Regex reg = new Regex(o);

if (reg.IsMatch(virtualPath)){

var data = new RouteData();

data.RouteHandler = new PageRoute(node.Attributes[“routePage”].Value);

string[] a = n.Split(new char[] { ‘/’, ‘.’ });

string[] b = virtualPath.Split(new char[] { ‘/’, ‘.’ });

for (int i = 0, j = a.Length; i < j; i++) {

if (a[i].StartsWith(“{“))  {

string d = a[i].Replace(“{“, “”).Replace(“}”, “”);

data.Values[d] = b[i]; }}

return data; }}

return null; }

程序首先是检查xml文件是否存在,如果存在就加载并生成列表,使用当前的 url 在列表里遍历,如果找到了就返回信息。对于有参数的,则找到参数部分,看是否符合要求,符合的话先把参数填充进去,再返回信息。最后,如果都没有找到,则返回 null 跳过进行后面的。

现在,我们只需要在 Global 文件里添加 routes.Add(new PageRoutes()); 这一行就可以了。以后需要调整的时候直接修改 Route.xml 文件即可。至此,webform 中使用 Route 的文章基本上就写完了。

写在后面的话,其实这么写有一个潜在的性能问题,就是每次访问都需要加载 xml 文件,比较好的实现方式是把请求的路由信息放在缓存里,缓存依赖设置为文件类型的,这样的话每当xml有修改的话,缓存就自动失效重新加载 xml 。这个不是很难,就留给各位同学们去实现了。

而对于 GetVirtualPath 方法,我这里并没有去提及,一是对于传统的 webform 来说,用到的机会比较少;二是需要根据具体的项目来定义,这里以通用例子来讲解有误导嫌疑;三是给大家个锻炼的机会。

祝大家编码愉快。

分类: 日常 标签: , ,

在Webform (asp.net)中使用Route 路由之初级扩展

2012年9月7日 没有评论

在上一节,我们分享了如何实现基本的路由,可以满足很多的场景。

对于asp.net 稍微熟悉的同学一定不会对 Ashx 文件陌生,这是一个只具有代码逻辑的页面,通常用在验证码显示、文件下载等几乎没有用户界面的情况下。我就非常地喜欢使用这样的文件。

有的同学在对这样的文件进行路由的时候,会是这么来写代码,routes.MapPageRoute (“data”, “data”, “~/handler.ashx”); 编译一运行,我瓷熬,居然报错了。报错信息是什么呢?大致是这样的一条错误信息:类型“WebSite.Handler”不从“System.Web.UI.Page”继承。原因就在于常见的 aspx 和 ashx 虽然都实现了 IHttpHandler 接口,但是又不完全一样。

为了解决这个问题,其实这个问题也是我写这几篇文章最初的出发点,网上的代码基本上和上一节的差不多,并没有解决本节的问题。

我们在项目中新建一个类,取名 PageRoute,继承自 IRouteHandler 。在这个类里,我们只需要实现 IRouteHandler 接口就可以了。不多说,上代码。
#region IRouteHandler 成员

public string RoutePath { get; private set; }

public PageRoute (string routePath){RoutePath = routePath;}

public IHttpHandler GetHttpHandler (RequestContext requestContext)
{
if (!RoutePath.Contains (“.ashx”))
{
return BuildManager.CreateInstanceFromVirtualPath (RoutePath, typeof (Page)) as IHttpHandler;
}
else
{
return BuildManager.CreateInstanceFromVirtualPath (RoutePath, typeof (IHttpHandler)) as IHttpHandler;
}
}

#endregion

从代码里,可以清楚地看到,在 GetHttpHandler 方法里分别对 aspx 和 ashx 文件进行了处理,虽然返回的都是 IHttpHandler ,但是在转换的时候,设置的 typeof  是不一样的。

接下来,在 Global.asax.cs 里这么来写 routes.Add (“getdata”, new Route (“data”, new PageRoute (“~/handler.ashx”))); 各位同学们要记住这里的写法和上一节里的写法不一样喔。这样就可以实现对 ashx 文件的路由了,当然对于 aspx 文件,使用2种方式都可以的,例如 routes.Add (“user”, new Route (“u/{userid}”, new PageRoute (“~/userlist.aspx”))); 这样

是不是很神奇呀?

在这一节里,我们就完全解决了传统 webform 的路由实现问题,特别是不从“System.Web.UI.Page”继承这个问题。下一节我们来提一提再高级一点的用法。

分类: 日常 标签: , ,

在Webform (asp.net)中使用Route 路由之基本实现

2012年9月7日 没有评论

路由这个东西其实很早前就出现了,更多的是出现前其它的平台/语言中,对于 .Net 来说比较晚。那时很羡慕只需要在 apache 、ngix 中配置下就可以使用了。

我记得第一次近距离的使用是在门楼网里,那个时候屈屈把 Route 的这部分代码给剥离出来单独给我看过,使用了一个第三方组件,并且需要修改 IIS 的设置才能生效,缺点就是会接管所有的请求包括图片、样式等等。后来把代码消化后,用在了学校的新闻网里,没有想到5年多过去了这部分代码还在继续为师生们服务着。

再后来,微软推出了 MVC,到现在已经是第4个版本了。在 MVC 中,.Net 终于原生支持 Route了,但是在最开始还只是为 MVC 来服务的,网上也很多教程都是针对 MVC 系列的,我们这里就来讨论下如何在 webform 上来实现。

首先,需要在项目里添加 Global.asax 文件,在这个文件里要做的事情就是在应用启动的时候,添加路由注册信息到里面。

protected void Application_Start (object sender, EventArgs e) { RegisterRoutes (RouteTable.Routes);  }

然后在protected void RegisterRoutes (RouteCollection routes){routes.MapPageRoute (“default”, “home”, “~/default.aspx”);}里方法是这样的,什么意思,就是说你访问 /home 的话,路由会直接帮你转向到 default.aspx 页面去。

上面的方式可以满足最基本的需求,可是事实上很多情况下,url 地址里是有带有参数的,如何提交参数呢。可以这么来,routes.MapPageRoute (“notedetail”, “note/{userid}/{noteid}”, “~/note.aspx”); 从代码里可以发现,url 里附加了2个参数,分别为 userid 和 noteid ,它们用大括号给括起来了。看起来是不是有点像存储过程里的参数呢,哈哈。这个冷笑话一点都不好玩。

回到正题,再添加了上面的代码后,如果用户访问 /note/wave/1346 ,那么会被路由到 note.aspx 这个页面里去,在页面里接收参数可以这么来使用 string userId=Page.RouteData.Values[“userid”]; 就不再是传统的 QueryString 方法了。

至此,我们就实现了在 webform 中使用 Route 的基本功能呢了。下一节,我们来进行扩展。

分类: 日常 标签: , ,