利用ASP.NET3.5 的路由功能创建搜索引擎友好的URL

.NET技术    2010-01-20 00:12  

  ASP.NET 3.5 SP1中提供了一种路由技术。ASP.NET 路由是一种能够使我们在ASP.NET应用程序中利用一种可描述的、对搜索引擎和用户很友好的URL访问资源的技术。这种URL不必物理地映射到真正的资源。比如:

  http://dotnet.aspx.cc/Article.aspx?articleId=8d01fd5e-b2c1-40f5-8cea-bc2197fb9bd8

  这个 URL 实际上是映射到网站根目录下的一个Article.aspx文件。使用ASP.NET路由技术,可以使用类似下面的URL进行访问:

  http://dotnet.aspx.cc/article/8d01fd5e-b2c1-40f5-8cea-bc2197fb9bd8/read.aspx

  实现这种URL,有两种技术可以做到:URL重写和 URL路由:

  1,URL 重写通过在将请求发送到网页之前实际更改 URL 来处理传入请求。例如,一个使用 URL 重写的应用程序可能会将 URL 从 /article/8d01fd5e-b2c1-40f5-8cea-bc2197fb9bd8/read.aspx 更改为 /Article.aspx?articleId=8d01fd5e-b2c1-40f5-8cea-bc2197fb9bd8。此外,URL 重写通常没有相应的 API 来创建基于模式的 URL。在 URL 重写中,如果更改了 URL 模式,则必须手动更新包含原始 URL 的所有超链接。

  2,由于 ASP.NET 路由可以从 URL 提取值,所以处理传入请求时不更改 URL。如果必须创建一个 URL,则将参数值传递到为您生成 URL 的方法中。若要更改 URL 模式,请在某位置更改该模式,您在应用程序中创建的基于该模式的所有链接将自动使用新模式。

  若要启用路由,必须更改应用程序的配置文件来注册路由程序集,并添加 UrlRoutingModule 类作为模块。还必须为路由创建一个自定义路由处理程序。该处理程序实现IRouteHandler 接口并创建 Web 窗体(.aspx 文件)的一个实例,该实例将为请求的实际终结点。

  下面我们就以完整的例子来简单说明如何在网站发布系统中使用这项技术。

  1、首先创建表 Article 用来存储文章数据内容,从 SQL Server 2000 创建脚本功能创建出SQL语句:

   

  


REATE TABLE [Article] (
[ArticleId] [int] IDENTITY (1, 1) NOT NULL ,
[Title] [nvarchar] (255) COLLATE Chinese_PRC_CI_AS NOT NULL ,
[CreateDate] [datetime] NOT NULL CONSTRAINT [DF_Article_CreateDate] DEFAULT (getdate()),
[Content] [ntext] COLLATE Chinese_PRC_CI_AS NOT NULL ,
CONSTRAINT [PK_Article] PRIMARY KEY CLUSTERED
(
[ArticleId]
) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

   

  2、在VS2008SP1或者VS2010中,新建一个ASP.NET网站,添加对System.Web.Routing的引用;

  3、创建自定义路由处理程序,在网站工程中添加新项“类”,命名为ArticleRouteHandler.cs,类的网站内容如下:

   

  


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.Routing;
using System.Web.Compilation;
/// <summary>
///ArticleRouteHandler 的摘要说明
/// </summary>
public class ArticleRouteHandler : IRouteHandler
{
public ArticleRouteHandler()
{
//
//TODO: 在此处添加构造函数逻辑
//
}
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
string ArticleGuid = requestContext.RouteData.Values["ArticleGuid"] as string;
HttpContext context = HttpContext.Current;
context.Items.Add("ArticleGuid", ArticleGuid);
string action = (requestContext.RouteData.Values["Action"] as string).ToLower();
if (action.Equals("read"))
return BuildManager.CreateInstanceFromVirtualPath("~/ArticleShow.aspx", typeof(Page)) as Page;
else if (action.Equals("new"))
return BuildManager.CreateInstanceFromVirtualPath("~/ArticleAdd.aspx", typeof(Page)) as Page;
else if (action.Equals("edit"))
return BuildManager.CreateInstanceFromVirtualPath("~/ArticleEdit.aspx", typeof(Page)) as Page;
else if (action.Equals("comment"))
return BuildManager.CreateInstanceFromVirtualPath("~/ArticleComment.aspx", typeof(Page)) as Page;
else if (action.Equals("print"))
return BuildManager.CreateInstanceFromVirtualPath("~/ArticlePrint.aspx", typeof(Page)) as Page;
else
return BuildManager.CreateInstanceFromVirtualPath("~/ArticleList.aspx", typeof(Page)) as Page;
}
}

   

  注意:

   

  


using System.Web.UI;
using System.Web.Routing;
using System.Web.Compilation;

   

  这3行代码是新加的。

  在这里,我们将URL地址中的占位符参数放到 HttpContext.Current 对象中,以便在真正的处理页面中进行获取,然后执行相应的操作。关键的代码是这几句:

   

  


string ArticleGuid = requestContext.RouteData.Values["ArticleGuid"] as string;
HttpContext context = HttpContext.Current;
context.Items.Add("ArticleGuid", ArticleGuid);

   

  4、在Global里注册路由,其代码为:

   

  


<%@ Application Language="C#" %>
<%@ Import Namespace="System.Web.Routing" %>
<mce:script RunAt="server"><!--
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.Add("ArticleRoute", new Route
(
"Article/{ArticleGuid}/{Action}.aspx",
new ArticleRouteHandler()
)
);
}

// --></mce:script>

   

  这里,作为例子,只定义了一条URL规则,Article/{ArticleGuid}/{Action}.aspx。

  5、按照自定义路由处理程序中定义的实际处理程序,分别添加ArticleShow.aspx、ArticleAdd.aspx、 ArticleEdit.aspx、ArticleComment.aspx、ArticlePrint.aspx和ArticleList.aspx等真正的处理程序。 作为例子,这里列出ArticleShow.aspx、ArticleAdd.aspx和ArticleList.aspx的源代码分别如下:

  ArticleAdd.aspx

   

  


<%@ Page Language="C#" ValidateRequest="false" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<mce:script runat="server"><!--
protected void Button1_Click(object sender, EventArgs e)
{
String ConnectionString = "Data Source=(local);Initial Catalog=ArticleDev;User ID=sa;Password=sa";
SqlConnection cn = new SqlConnection(ConnectionString);
cn.Open();
String sql = "Insert Into Article(Title,Content) Values(@Title,@Content)";
SqlCommand cmd = new SqlCommand(sql, cn);
cmd.Parameters.AddWithValue("@Title", TextBox1.Text);
cmd.Parameters.AddWithValue("@Content", TextBox2.Text);
int ret = cmd.ExecuteNonQuery();
if (ret == 1)
{
Label1.Text = "添加成功。";
}
else
{
Label1.Text = "添加失败。";
}
cn.Dispose();
}
// --></mce:script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>文章标题:<asp:TextBox ID="TextBox1" runat="server" Width="767px"></asp:TextBox></div>
<div>文章内容:<br />
<asp:TextBox ID="TextBox2" runat="server" Width="845px" Height="319px" TextMode="MultiLine">
</asp:TextBox></div>
<asp:Button ID="Button1" runat="server" Text="添加文章" OnClick="Button1_Click" />
<asp:Label ID="Label1" runat="server" Text=""></asp:Label>
</form>
</body>
</html>

   

  ArticleShow.aspx

   

  


<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<mce:script runat="server"><!--
protected void Page_Load(object sender, EventArgs e)
{
int ArticleGuid = 0;
HttpContext context = HttpContext.Current;
if (context.Items["ArticleGuid"] != null)
{
Int32.TryParse(context.Items["ArticleGuid"].ToString(), out ArticleGuid);
}
if (ArticleGuid < 1)
{
ArticleTitle.InnerHtml = "加载文章错误";
ArticleContent.InnerHtml = "指定的 标识 无效!";
ArticleContent.Style["color"] = "#f00";
}
else
{
String ConnectionString = "Data Source=(local);Initial Catalog=ArticleDev;User ID=sa;Password=sa";
SqlConnection cn = new SqlConnection(ConnectionString);
cn.Open();
String sql = "Select * From Article Where ArticleId = @ArticleId";
SqlCommand cmd = new SqlCommand(sql, cn);
cmd.Parameters.AddWithValue("@ArticleId", ArticleGuid);
SqlDataReader dr = cmd.ExecuteReader();
if (dr.Read())
{
ArticleTitle.InnerHtml = dr["Title"].ToString();
ArticleContent.InnerHtml = dr["Content"].ToString();
}
else
{
ArticleTitle.InnerHtml = "加载文章错误";
ArticleContent.InnerHtml = "指定的文章不存在!";
ArticleContent.Style["color"] = "#f00";
}
cn.Dispose();
}
}
// --></mce:script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<h2 id="ArticleTitle" runat="server" style="text-align:center" mce_style="text-align:center">
</h2>
<hr />
<div id="ArticleContent" runat="server">
</div>
</form>
</body>
</html>

   

  这段代码中,我们从自定义路由处理程序中添加的 HttpContext 对象中取出参数 context.Items["ArticleGuid"],然后进行处理。

  ArticleList.aspx

   

  


<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<mce:script runat="server"><!--
protected void Page_Load(object sender, EventArgs e)
{
String ConnectionString = "Data Source=(local);Initial Catalog=ArticleDev;User ID=sa;Password=sa";
SqlConnection cn = new SqlConnection(ConnectionString);
cn.Open();
String sql = "Select * From Article Order By ArticleId DESC";
SqlCommand cmd = new SqlCommand(sql, cn);
SqlDataReader dr = cmd.ExecuteReader();
GridView1.DataSource = dr;
GridView1.DataBind();
cn.Dispose();
}
// --></mce:script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:HyperLinkField DataNavigateUrlFields="ArticleId" DataTextField="Title"
DataNavigateUrlFormatString="~/Article/{0}/read.aspx" HeaderText="标题" />
<asp:BoundField DataField="CreateDate" HtmlEncode="false" HeaderText="发布日期"
DataFormatString="{0:yyyy-MM-dd HH:mm:ss}" />
</Columns>
</asp:GridView>
</form>
</body>
</html>

   

  6、如果IIS里设置的ASP.NET版本是 ASP.NET 4.0,无需配置以下的配置,如果是ASP.NET 2.0,则需要在web.config里配置路由。 在应用程序的 Web.config 文件中,将 ASP.NET 路由程序集添加到 assemblies 元素

   

  


<assemblies>
<add assembly="System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</assemblies>

   

  如果应用程序在 IIS 6.0 或 IIS 7.0 经典模型下运行,则将 UrlRoutingModule 类添加到 httpModules 元素

   

  


<httpModules>
<add name="UrlRoutingModule"
type="System.Web.Routing.UrlRoutingModule,
System.Web.Routing,
Version=3.5.0.0,
Culture=neutral,
PublicKeyToken=31BF3856AD364E35"/>
</httpModules>

   

  下面就可以使用下面的地址进行访问了。当然,这里只是一个例子,更多的功能处理有待于我们在实践中加以处理。

   

  


http://dotnet.aspx.cc/article/8d01fd5e-b2c1-40f5-8cea-bc2197fb9bd8/comment.aspx
http://dotnet.aspx.cc/article/8d01fd5e-b2c1-40f5-8cea-bc2197fb9bd8/new.aspx
http://dotnet.aspx.cc/article/8d01fd5e-b2c1-40f5-8cea-bc2197fb9bd8/edit.aspx
http://dotnet.aspx.cc/article/8d01fd5e-b2c1-40f5-8cea-bc2197fb9bd8/read.aspx
http://dotnet.aspx.cc/article/8d01fd5e-b2c1-40f5-8cea-bc2197fb9bd8/print.aspx

   

  以上例子只是简单地进行了说明,实际应用中,还有更多的东西需要考虑,更多的信息可以参考如下的链接:

  ASP.NET 路由(http://msdn.microsoft.com/zh-cn/library/cc668201.aspx

在线留言

我要留言