Url
重写可以提升用户体验,所以我们一直在追求,呵呵,先来一句广告语。
我这里是用HttpHandlerFactory和在Web.config中添加一个配置节来实现重写的,举个例子先:
原始Url:abc.aspx?aid=121&bid=321&mid=9
重写Url:abc-121-321-9.shtml
原始Url:xyz.aspx?type=a 或者xyz.aspx?type=b
重写Url:xyz-a.shtml或者xyz-b.shtml
而且这里希望一劳永逸的实现Url参数类型千变万化的形式的重写。
先看我们需要什么样的配置:
对于每一种重写我们都需要写出要重写成的Url的正则表达式的匹配形式,然后我们还需要配置原始Url的aspx路径,再就需要配置每一个参数在重写成的Url中怎么提取出来成为查询字符串,让原始的aspx去读取,说到这里,请看下面具体的配置节。
<
configSections
>
<
section
name
="handlerSettings"
type
="book.Provider.ConfigHandler, book"
/>
</
configSections
>
<!--
配置Url路径重写参数,如有任何疑问联系赵玉开
-->
<
handlerSettings
>
<!--
一个handler代表一中url的映射
regex是用来匹配Url的,如果匹配就使用对应的aspxPath中映射的handler
aspxPath需要是一个可以经过Server.MapPath转换的aspx文件的虚拟路径
params是在url中包含参数的设置
param的两个属性:name是连接字符串的名字,valueRegexGroupName是正则表达式中匹配的对应名字的查询字符串的值的正则表达式组名字
-->
<
handler
name
="news"
>
<
regex
>
/(?
<
id
>
[\d]+).shtml
</
regex
>
<
aspxPath
>
detail.aspx
</
aspxPath
>
<
params
>
<
param
name
="id"
valueRegexGroupName
="id"
/>
</
params
>
</
handler
>
</
handlerSettings
>
请大家看配置里面的注释。
有了配置节,我们就需要解析配置的类了,如下ConfigHandler用来读取配置节的信息,并将所有的配置信息实例化成ConfigItem 数组,然后放在这个类的一个静态数组中。

public class ConfigHandler:System.Configuration.IConfigurationSectionHandler

{
protected ConfigHandler()

{
}

static private ConfigItem[] _handlerConfigArray;
[System.Xml.Serialization.XmlArrayItem("handler",typeof(ConfigItem))]
static public ConfigItem[] HandlerConfigArray

{

get
{return _handlerConfigArray;}
}


IConfigurationSectionHandler 成员#region IConfigurationSectionHandler 成员

public object Create(object parent, object configContext, System.Xml.XmlNode section)

{
XmlNodeList nodeList = section.SelectNodes("handler");
ArrayList configList = new ArrayList();
foreach(XmlNode node in nodeList)

{
ConfigItem item = new ConfigItem();
item.Name = node.Attributes["name"].Value;
XmlNode regexNode = node.SelectSingleNode("regex");
item.GlobalRegex = regexNode.InnerText;

XmlNode aspxNode = node.SelectSingleNode("aspxPath");
item.AspxPath = aspxNode.InnerText;

XmlNode paramsNode = node.SelectSingleNode("params");
if(paramsNode != null)

{
XmlNodeList paramNodeList = paramsNode.SelectNodes("param");

ArrayList list = new ArrayList();
foreach(XmlNode paramNode in paramNodeList)

{
ConfigParam p = new ConfigParam();
p.Name = paramNode.Attributes["name"].Value;
p.ValueRegexGroupName = paramNode.Attributes["valueRegexGroupName"].Value;

list.Add(p);
}

item.Params = (ConfigParam[])list.ToArray(typeof(ConfigParam));
}
configList.Add(item);
}

_handlerConfigArray = (ConfigItem[])configList.ToArray(typeof(ConfigItem));

return null;
}

#endregion
}

public class ConfigItem

{

public ConfigItem()
{}

private string _name;
public string Name

{

get
{return _name;}

set
{_name = value;}
}

private string _globalRegex;

public string GlobalRegex

{

get
{return _globalRegex;}

set
{_globalRegex = value;}
}

public string _aspxPath;
public string AspxPath

{

get
{return _aspxPath;}

set
{_aspxPath = value;}
}

private ConfigParam[] _params;
public ConfigParam[] Params

{

get
{return _params;}

set
{_params = value;}
}
}

public class ConfigParam

{
private string _name;

public string Name

{

get
{return _name;}

set
{_name = value;}
}

private string _valueRegexGroupName;
public string ValueRegexGroupName

{

get
{return _valueRegexGroupName;}

set
{_valueRegexGroupName = value;}
}
}
解析出了重写的配置信息,我们的主角就该出场了,从IHttpHandlerFactory 继承的HanderFactory类

HandlerFactory
public class HandlerFactory:IHttpHandlerFactory

{
public HandlerFactory()

{
}


IHttpHandlerFactory 成员#region IHttpHandlerFactory 成员

public void ReleaseHandler(IHttpHandler handler)

{
}

public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)

{
url = url.ToLower();

foreach(ConfigItem ci in ConfigHandler.HandlerConfigArray)

{
Regex regex = new Regex(ci.GlobalRegex,RegexOptions.IgnoreCase);
Match match = regex.Match(url);
if(match.Success)

{
string queryString = string.Empty;

if(ci.Params != null)

foreach(ConfigParam cp in ci.Params)
{
queryString += string.Format("{0}={1}&",cp.Name,match.Groups[cp.ValueRegexGroupName].Value);
}

foreach(string queryKey in context.Request.QueryString.AllKeys)

{
if(queryString.IndexOf("&" + queryKey + "=") == -1 && queryString.IndexOf(queryKey + "=") == -1)

{
queryString += string.Format("{0}={1}&",queryKey,context.Request.QueryString[queryKey]);
}
}
queryString = queryString.TrimEnd('&');

context.RewritePath(url,"",queryString);

return PageParser.GetCompiledPageInstance(url, context.Server.MapPath(ci.AspxPath), context);
}

}

ErrorHandler.RedirectFor400();

return null;
}

#endregion
}
我们只实现了接口的GetHandler方法首先我们需要逐个的用配置中的正则表达式去匹配传进来的Url,如果改配置项匹配了Url,那么就开始根据配置的参数项,提取url中的查询字符串的值,并组成一个查询字符串,需要注意的是查询字符串并不只是这一部分因为xxx.shtml还可能带有查询字符串的,所以我们还需要把这一部分的查询字符串附加到提取出来的查询字符串的后面,最后我们使用PageParser.GetCompiledPageInstance返回一个IHttpHandler的实例,到这儿基本上就结束了。
当然我们还少不了要配置一下iis让.net去处理指定扩展名的请求。配置Web.config中的httpHandlers配置节。
不过由于iis的先天问题,我们在使用虚拟服务器的时候就没有办法用Url重写了,郁闷ing,大家有没有什么好办法?