ASP.NET实现URL映射

随着Internet的发展规律, 许多网站开始越来越注重URL的语义性. 即URL符合人们的理解习惯. 比如我要查看某个用户的博客地址:
http://kimiya25/spaces.live.com?type=archive&year=2007&month=12这样的URL可读性较差, 因为一般用户并不完全理解. 如果URL是 http://kimiya25/spaces.live.com/archive/2007/12/ 则可读性变强, 用户知道如何查看2007年12月份的文章. 显然我们不能为某个这样的情况都创建一个符合规则的页面, 所有这样复杂的情况依然使用同一个规则. 通过Url Mapping来进行所谓的匹配处理.
ASP.NET默认提供了UrlMapping, 我们在可以Web.config的System.web中定义urlMappings配置节.
现在如果我访问自己的本地站点. 只要输入相应的域名/Default/2007/09就等同于/Default.aspx?year=2007&month=09
ASP.NET应用程序的HttpApplication对象被创建后会读取urlMapping节中的信息, 再用UrlMappingSection类分析出映射的地址列表. 如果匹配成功, 则调用HttpContext.RewritePath方法重写路径. 以达到映射目的, 但它有一个缺点就是只能够一条路径一条的对应, 却不可以以一种一种的方式. 如果当需要映射的规则相待复杂时, 根本无法面对需求.
解决的方法就是自己编写实现IHttpModule的自定义HttpModule. 并且编写自定义的ConfigurationSection来读取自定义的映射规则. 通过为HttpContext.BeginRequest添加世家处理来完成Url映射.
以下为实现工程:
RegxUrlMappingModule实现了IHttpModule接口, 读取相应的配置结, 通过RegexUrlMappingsSection进行管理. 然后通过正则匹配决定是否重写Url. RegexUrlMapping为基本配置元素的实现, RegexUrlMappingCollection则是相应的集合实现.
RegexUrlMapping提供两个配置属性, url 和 mappedUrl, 它派生于ConfigurationElement. 继承关系可以参照以下图:
关于配置节的创建小弟也不多说了, 相对比较简单, 你只需要继承相应的配置类, 然后实现一些必要的方法就可以. 然后在Web.config中注册相应的配置节与程序集信息. (配置节名称和类型)
然后配置相应的正则匹配规则.
因为在编写Section时我们指定了DefaultCollection, 所以对于以上的配置信息, 其实调用了我们编写的Collection, 对于Add里面则调用了RegexUrlMapping的构造函数.
new ConfigurationProperty(null, typeof(RegexUrlMappingCollection), null, ConfigurationPropertyOptions.IsDefaultCollection);
在Section中编写实现了方法HttpResolveMapping, 它遍历节点调用RegexUrlMapping的MatchAndReplace方法判断是否匹配. 匹配则修改传递引用的path.
public string HttpResolveMapping(string path){
     foreach (RegexUrlMapping mapper in UrlMappings){
          if (mapper.MatchAndReplace(ref path))
               break;
     }
     return path;
}
最后来看RegexUrlMappingModule的核心实现.
通过ConfigurationManager的GetSection方法获得自定义的配置节.
ConfigurationManager.GetSection(RegexUrlMappingsSection.SECTION_NAME) as RegexUrlMappingsSection;
在Init时为HttpApplication.BeginRequet绑定事件
public void Init(HttpApplication context){
     context.BeginRequest += new EventHandler(context_BeginRequest);
}
context_BeginRequest负责调用Section的HttpResolveMapping进行当前url的匹配处理, 然后比较是否和原来的url相同, 如果不同则调用HttpContext的RewritePath方法进行了重写.
以上面为例, 现在我输入/2007/10/Default.aspx默认就是等于访问/Default.aspx?year=2007&month=10.
 
以下为所有实现代码:
Disposable.cs
 
using System;
namespace Beyondbit.App.UrlMappings
{
    public abstract class Disposable : MarshalByRefObject, IDisposable{
        private volatile bool _isDisposed = false;
        public bool IsDisposed{
            get{ return _isDisposed; }
        }
        protected virtual void Dispose(bool disposing){
            if (!_isDisposed) {
                _isDisposed = true;
                if (disposing) GC.SuppressFinalize(this);
            }           
        }
        /*protected void Free(){
            if (_isDisposed)
                throw new ObjectDisposedException(GetType().FullName);   
        }*/
        void IDisposable.Dispose(){
            Dispose(true);
        }
        public void Dispose(){
            Dispose(true);
        }
    }
}
 
RegexUrlMapping.cs
 
using System;
using System.Configuration;
using System.Web;
using System.Web.Util;
using System.Text.RegularExpressions;
namespace Beyondbit.App.UrlMappings
{
    /// <summary>
    /// 正则UrlMapping元素
    /// </summary>
    public class RegexUrlMapping : ConfigurationElement{
        static readonly ConfigurationProperty _propMappedUrl;
        static readonly ConfigurationProperty _propUrl;
        static readonly WhiteSpaceTrimStringConverter _trimConverter = new WhiteSpaceTrimStringConverter();
        static readonly StringValidator _nonEmptyStringValidator = new StringValidator(1);
        static ConfigurationPropertyCollection _properties;
        static RegexUrlMapping(){
            _propUrl = new ConfigurationProperty("url", typeof(string), null, _trimConverter, _nonEmptyStringValidator, ConfigurationPropertyOptions.IsKey | ConfigurationPropertyOptions.IsRequired);
            _propMappedUrl = new ConfigurationProperty("mappedUrl", typeof(string));
            _properties = new ConfigurationPropertyCollection();
            _properties.Add(_propUrl);
            _properties.Add(_propMappedUrl);
        }
        public RegexUrlMapping(){ }
        public RegexUrlMapping(string url, string mappedUrl){
            base[_propUrl] = url;
            base[_propMappedUrl] = mappedUrl;
        }
        [ConfigurationProperty("url", IsRequired = true, IsKey = true)]
        public string Url{
            get { return base[_propUrl] as string; }
        }
        [ConfigurationProperty("mappedUrl", IsRequired = true)]
        public string MappedUrl{
            get { return base[_propMappedUrl] as string; }
        }
        protected override ConfigurationPropertyCollection Properties{
            get { return _properties; }
        }
        /// <summary>
        /// 匹配url
        /// 替换引用的path值
        /// </summary>
        public bool MatchAndReplace(ref string path){
            bool flag = false;
            Regex regex = new Regex(this.Url, RegexOptions.Compiled | RegexOptions.IgnoreCase);
            if (regex.IsMatch(path)){
                path = regex.Replace(path, MappedUrl);
                flag = true;
            }
            return flag;
        }
        /*static void ValidateUrl(Object value){
            _nonEmptyStringValidator.Validate(value);
            string url = value as string;
            if (!IsAppRelativePath(url)){
                throw new ConfigurationErrorsException("只允许应用程序相对 URL (~/url)。");
            }
        }
        static bool IsAppRelativePath(string path){
            if (path == null){
                return false;
            }
            int num1 = path.Length;
            if (num1 == 0){
                return false;
            }
            if (path[0] != '~'){
                return false;
            }
            if ((num1 != 1) && (path[1] != '\\')){
                return (path[1] == '/');
            }
            return true;
        }*/
    }
}
RegexUrlMappingCollection.cs
 
using System;
using System.Configuration;
using System.Reflection;
using System.Web.Util;
namespace Beyondbit.App.UrlMappings
{
    /// <summary>
    /// 正则UrlMapping元素集合
    /// </summary>
    public class RegexUrlMappingCollection : ConfigurationElementCollection{
        private static readonly ConfigurationPropertyCollection _properties;
        static RegexUrlMappingCollection(){
            _properties = new ConfigurationPropertyCollection();
        }
        public RegexUrlMappingCollection()
            : base(StringComparer.OrdinalIgnoreCase){
        }
        public string[] AllKeys {
            get { return ObjectArrayToStringArray(base.BaseGetAllKeys()); }
        }
        public RegexUrlMapping this[int index] {
            get { return (RegexUrlMapping)base.BaseGet(index); }
            set {
                if (base.BaseGet(index) != null){
                    base.BaseRemoveAt(index);
                }
                this.BaseAdd(index, value);
            }
        }
        public new RegexUrlMapping this[string name] {
            get { return base.BaseGet(name) as RegexUrlMapping; }
        }
        protected override ConfigurationPropertyCollection Properties {
            get { return _properties; }
        }
        /// <summary>
        /// 添加元素
        /// </summary>
        public void Add(RegexUrlMapping urlMapping){
            this.BaseAdd(urlMapping);
        }
        /// <summary>
        /// 清除
        /// </summary>
        public void Clear(){
            base.BaseClear();
        }
        /// <summary>
        /// 创建配置节点
        /// </summary>
        protected override ConfigurationElement CreateNewElement(){
            return new RegexUrlMapping();
        }
        /// <summary>
        /// 获得元素键
        /// </summary>
        protected override object GetElementKey(ConfigurationElement element){
            return (element as RegexUrlMapping).Url;
        }
        /// <summary>
        /// 获得键
        /// </summary>
        public string GetKey(int index){
            return base.BaseGetKey(index) as string;
        }
        /// <summary>
        /// 移除
        /// </summary>
        public void Remove(string name){
            base.BaseRemove(name);
        }
        /// <summary>
        /// 键移除
        /// </summary>
        public void Remove(RegexUrlMapping urlMapping){
            base.BaseRemove(GetElementKey(urlMapping));
        }
        /// <summary>
        /// 索引移除
        /// </summary>
        public void RemoveAt(int index){
            base.BaseRemoveAt(index);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="objectArray"></param>
        static string[] ObjectArrayToStringArray(object[] objectArray){
            string[] textArray1 = new string[objectArray.Length];
            objectArray.CopyTo(textArray1, 0);
            return textArray1;
        }
    }
}
RegexUrlMappingsSection.cs
 
using System;
using System.Configuration;
using System.Web.Util;
using System.Text.RegularExpressions;
namespace Beyondbit.App.UrlMappings
{
    /// <summary>
    /// 正则UrlMapping配置节
    /// </summary>
    public class RegexUrlMappingsSection : ConfigurationSection{
        public const string SECTION_NAME = "RegexUrlMappings";
        static readonly ConfigurationProperty _propEnabled;
        /// <summary>
        /// 是否重置虚拟路径
        /// </summary>
        static readonly ConfigurationProperty _propRebaseClientPath; 
        static readonly ConfigurationProperty _propMappings;
        static ConfigurationPropertyCollection _properties;
       
        static RegexUrlMappingsSection(){
            _propEnabled = new ConfigurationProperty("enabled", typeof(bool), true, ConfigurationPropertyOptions.None);
            _propRebaseClientPath = new ConfigurationProperty("rebaseClientPath", typeof(bool), true, ConfigurationPropertyOptions.None);
            _propMappings = new ConfigurationProperty(null, typeof(RegexUrlMappingCollection), null, ConfigurationPropertyOptions.IsDefaultCollection);
            _properties = new ConfigurationPropertyCollection();
            _properties.Add(_propEnabled);
            _properties.Add(_propRebaseClientPath);
            _properties.Add(_propMappings);
        }
        [ConfigurationProperty("enabled", DefaultValue = true)]
        public bool IsEnabled{
            get { return (bool)base[_propEnabled]; }
            set { base[_propEnabled] = value; }
        }
        [ConfigurationProperty("rebaseClientPath", DefaultValue = true)]
        public bool RebaseClientPath{
            get { return (bool)base[_propRebaseClientPath]; }
            set { base[_propRebaseClientPath] = value; }
        }
        protected override ConfigurationPropertyCollection Properties{
            get { return _properties; }
        }
        [ConfigurationProperty("", IsDefaultCollection = true)]
        public RegexUrlMappingCollection UrlMappings{
            get { return base[_propMappings] as RegexUrlMappingCollection; }
        }
        public string HttpResolveMapping(string path){
            foreach (RegexUrlMapping mapper in UrlMappings){
                if (mapper.MatchAndReplace(ref path))
                    break;
            }
            return path;
        }
    }
}
RegexUrlMappingModule.cs
 
using System;
using System.Configuration;
using System.Web;
namespace Beyondbit.App.UrlMappings
{
    public class RegexUrlMappingModule : IHttpModule{
        static RegexUrlMappingsSection _settings = null;
        static bool _retrieved = false; //是否检索过
        RegexUrlMappingsSection Settings{
            get {
                if (!_retrieved){
                    _settings = ConfigurationManager.GetSection(RegexUrlMappingsSection.SECTION_NAME) as RegexUrlMappingsSection;
                    _retrieved = true;
                }
                return _settings;
            }
        }
        #region IHttpModule 成员
        public void Dispose(){ }
        public void Init(HttpApplication context){
            context.BeginRequest += new EventHandler(context_BeginRequest);
        }
        /// <summary>
        /// BeginRequest事件
        /// 根据Web.config中的Url映射规则重写HTTP请求的地址
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void context_BeginRequest(object sender, EventArgs e){
            HttpApplication application = sender as HttpApplication;
            HttpContext context = application.Context;
            string currentPath = context.Request.Url.PathAndQuery;
            if (this.Settings != null){
                if (_settings.IsEnabled){
                    string modifiedPath = Settings.HttpResolveMapping(currentPath);
                    if (!String.Equals(currentPath, modifiedPath)){
                        context.RewritePath(modifiedPath, _settings.RebaseClientPath);
                    }
                }
            }
        }
        #endregion
    }
}

转载于:https://www.cnblogs.com/thx-bj/archive/2008/06/16/1223266.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值