<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_Kudy's Tech Blog</title><subtitle type="text">我不去想身后会不会袭来寒风冷雨 既然目标是地平线,留给世界的只能是背影! </subtitle><id>http://feed.cnblogs.com/blog/u/98198/rss</id><updated>2012-05-24T03:34:48Z</updated><author><name>Kudy</name><uri>http://www.cnblogs.com/kudy/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kudy/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/98198/rss"/><entry><id>http://www.cnblogs.com/kudy/archive/2012/03/31/2427249.html</id><title type="text">【jUploader】1.0版 基于jQuery文件无刷新上传插件下载及介绍</title><summary type="text">【jUploader】介绍 花了1天多写了个上传插件，功能比较简单，但是很实用。这个只是单文件上传，以后有时间再写个多文件ajax上传插件，而且还会基于这个插件写个头像剪裁的插件，喜欢它的朋友别忘了点一下推荐支持一下下，３Ｑ【jUploader】下载Download: jquery.jUploader-1.0.js 10.10kbDownload: jquery.jUploader-1.0.min.js 4.25kbDownload: jquery.jUploader-1.0-demo.rar 1.83mbSupported in IE6+, FF3.6+, Chrome6+, Safari.</summary><published>2012-03-31T08:38:00Z</published><updated>2012-03-31T08:38:00Z</updated><author><name>Kudy</name><uri>http://www.cnblogs.com/kudy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kudy/archive/2012/03/31/2427249.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kudy/archive/2012/03/31/2427249.html"/><content type="html">&lt;p&gt;&lt;strong&gt;【jUploader】介绍&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;花了1天多写了个上传插件，功能比较简单，但是很实用。这个只是单文件上传，以后有时间再写个多文件ajax上传插件，而且还会基于这个插件写个头像剪裁的插件，喜欢它的朋友别忘了点一下&lt;strong&gt;推荐&lt;/strong&gt;支持一下下，３Ｑ&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;【jUploader】下载&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Download: &lt;a href="http://www.kudystudio.com/downloads/jquery.jUploader-1.0.js"&gt;jquery.jUploader-1.0.js&lt;/a&gt; 10.10kb&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Download: &lt;a href="http://www.kudystudio.com/downloads/jquery.jUploader-1.0.min.js"&gt;jquery.jUploader-1.0.min.js&lt;/a&gt; 4.25kb&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Download: &lt;a href="http://www.kudystudio.com/downloads/jquery.jUploader-1.0-demo.rar"&gt;jquery.jUploader-1.0-demo.rar&lt;/a&gt; 1.83mb&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Supported in IE6+, FF3.6+, Chrome6+, Safari4+. More info go to &lt;a href="http://www.kudystudio.com/" target="_blank"&gt;www.kudystudio.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;大家也可以去看看在线的实例：&lt;a href="http://www.kudystudio.com/jUploader/index.html"&gt;http://www.kudystudio.com/jUploader/index.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&amp;nbsp;全局设置:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;下面的为下面的实例写的设置。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/100869/2012033116133433.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;实例（一）:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;这个实例是放个预览图片，上传完后设置上传后的地址。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/100869/2012033116162313.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/100869/2012033116165048.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;实例（二）:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;这个实例是放个预览图片和loading图片，上传过程显示loading图片，上传完后给预览图片设置上传后的地址交显示。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/100869/2012033116180232.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/100869/2012033116184242.jpg" alt="" /&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/100869/2012033116191132.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;实例（三）:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;这个实例是放个预览图片，在上传按钮旁边放个span来提示上传信息。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/100869/2012033116200328.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/100869/2012033116204252.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;实例（四）:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;这个实例是放个预览图片，用&lt;a href="http://www.kudystudio.com/jbox/jbox-demo.html" target="_blank"&gt;jBox&lt;/a&gt;来显示上传提示。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/100869/2012033116214357.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/100869/2012033116225783.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/100869/2012033116305555.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;参数说明：&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;下面是插件的可用参数说明。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/100869/2012033116312214.jpg" alt="" /&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/kudy/aggbug/2427249.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kudy/archive/2012/03/31/2427249.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/kudy/archive/2011/12/28/2305198.html</id><title type="text">怎么设计个性化、灵活、实时更新的配置管理器？讲讲实现思路</title><summary type="text">有些天没写文章了，今晚给大家分享一下我对配置管理的实现思路。这个实现主要适合中小应用程序（Web或Winform），如果你的网站需要负载均衡，那这个方案就不适用了，这时建议配置保存在数据库或分布式缓存里，如果你有更好的想法，欢迎指点。这个配置设计在09年开发SNS网站时就完成了，那时看了Discuz!的.net开源版本，觉得它的配置管理不够灵活才想到用泛型来实现自己的配置管理组件。今天要讲的实现比09初版本多了两点功能：配置路径的迟加载和自定义配置序列化。其中路径迟加载是在看到汤姆大叔一个配置管理文章想到的，其实这个小功能不需要.Net4.0的Lazy就可以轻松实现，因为，需求太简单了。这里所</summary><published>2011-12-28T13:31:00Z</published><updated>2011-12-28T13:31:00Z</updated><author><name>Kudy</name><uri>http://www.cnblogs.com/kudy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kudy/archive/2011/12/28/2305198.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kudy/archive/2011/12/28/2305198.html"/><content type="html">&lt;p&gt;有些天没写文章了，今晚给大家分享一下我对配置管理的实现思路。这个实现主要适合中小应用程序（Web或Winform），如果你的网站需要负载均衡，那这个方案就不适用了，这时建议配置保存在数据库或分布式缓存里，如果你有更好的想法，欢迎指点。这个配置设计在09年开发SNS网站时就完成了，那时看了Discuz!的.net开源版本，觉得它的配置管理不够灵活才想到用泛型来实现自己的配置管理组件。今天要讲的实现比09初版本多了两点功能：配置路径的迟加载和自定义配置序列化。其中路径迟加载是在看到汤姆大叔一个配置管理文章想到的，其实这个小功能不需要.Net4.0的Lazy就可以轻松实现，因为，需求太简单了。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;这里所说的个性化、灵活、实时更新的定义？&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;个性化&lt;/strong&gt;，是指你可以随意定义自己想要的配置结构、保存格式、存放位置等等。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;灵活&lt;/strong&gt;，是指可以方便的对配置进行读、写操作，并可以很容易实现任意多个配置管理器。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;实时更新&lt;/strong&gt;，是指在配置发生改变时可以实时的更新，且不会重启Web应用程序。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;IFileConfigManager&amp;lt;T&amp;gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;下面开始讲解设计。既然是配置管理器，那还是先定义好接口吧，请看IFileConfigManager&amp;lt;T&amp;gt;：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    /// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// Interface containing all properties and methods to be implemented&lt;br/&gt;    /// by file configuration manager.&lt;br/&gt;    /// &amp;lt;/summary&amp;gt;&lt;br/&gt;    /// &amp;lt;typeparam name="T"&amp;gt;The type of config entity.&amp;lt;/typeparam&amp;gt;&lt;br/&gt;    public interface IFileConfigManager&amp;lt;T&amp;gt; : IDisposable &lt;br/&gt;        where T : class, new()&lt;br/&gt;    {&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// Gets the path of the config file.&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        string Path { get; }&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// Gets the encoding to read or write the config file.&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        Encoding Encoding { get; }&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// Gets the serializer of the config manager for loading or saving the config file.&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        FileConfigSerializer&amp;lt;T&amp;gt; Serializer { get; }&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// Gets the current config entity.&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;        T GetConfig();&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// Saves the current config entity to file.&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        void SaveConfig();&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// Saves a specified config entity to file.&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        /// &amp;lt;param name="config"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;        void SaveConfig(T config);&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// Backups the current config entity to a specified path.&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        /// &amp;lt;param name="backupPath"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;        void BackupConfig(string backupPath);&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// Restores config entity from a specified path and saves to the current path.&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        /// &amp;lt;param name="restorePath"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;        void RestoreConfig(string restorePath);&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;T参数当然就是定义的配置类型了，而且必须是引用类型，有无参数构造函数。Path是配置文件的完整路径，Encoding是读取和保存配置时用的编码，Serializer是处理配置序列化和反序列化的具体实现，GetConfig()是获取当前配置，SaveConfig()是保存当前配置，SaveConfig(T config)是保存指定的配置，BackupConfig(string backupPath)备份配置到指定路径，RestoreConfig(string restorePath)从指定路径还原配置。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;strong&gt;FileConfigSerializer&amp;lt;T&amp;gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;接口IFileConfigManager&amp;lt;T&amp;gt;中定义的Serializer是用于支持自定义配置序列化功能的，下面看看&lt;strong&gt;FileConfigSerializer&amp;lt;T&amp;gt;&lt;/strong&gt;的实现：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    public abstract class FileConfigSerializer&amp;lt;T&amp;gt; &lt;br/&gt;        where T : class, new()&lt;br/&gt;    {&lt;br/&gt;        #region Fields&lt;br/&gt;&lt;br/&gt;        // XML格式&lt;br/&gt;        public static readonly FileConfigSerializer&amp;lt;T&amp;gt; Xml = new XmlFileConfigSerializer();&lt;br/&gt;&lt;br/&gt;        // 二进制格式&lt;br/&gt;        public static readonly FileConfigSerializer&amp;lt;T&amp;gt; Binary = new BinaryFileConfigSerializer();&lt;br/&gt;&lt;br/&gt;        #endregion&lt;br/&gt;&lt;br/&gt;        #region Methods&lt;br/&gt;&lt;br/&gt;        // 从配置文件反序列化，使用指定的编码&lt;br/&gt;        public abstract T DeserializeFromFile(string path, Encoding encoding);&lt;br/&gt;&lt;br/&gt;        // 序列化到配置文件，使用指定的编码&lt;br/&gt;        public abstract void SerializeToFile(T config, string path, Encoding encoding);&lt;br/&gt;&lt;br/&gt;        #endregion&lt;br/&gt;&lt;br/&gt;        #region XmlFileConfigSerializer&lt;br/&gt;&lt;br/&gt;        // 实现默认的Xml序列化类&lt;br/&gt;        private sealed class XmlFileConfigSerializer : FileConfigSerializer&amp;lt;T&amp;gt; &lt;br/&gt;        {&lt;br/&gt;            public override T DeserializeFromFile(string path, Encoding encoding)&lt;br/&gt;            {&lt;br/&gt;                return SerializationUtil.DeserializeFromXmlFile&amp;lt;T&amp;gt;(path, encoding);&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            public override void SerializeToFile(T config, string path, Encoding encoding)&lt;br/&gt;            {&lt;br/&gt;                SerializationUtil.SerializeToXmlFile(config, path, encoding);&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        #endregion&lt;br/&gt;&lt;br/&gt;        #region BinaryFileConfigSerializer&lt;br/&gt;&lt;br/&gt;        // 实现默认的二进制序列化类&lt;br/&gt;        private sealed class BinaryFileConfigSerializer : FileConfigSerializer&amp;lt;T&amp;gt;&lt;br/&gt;        {&lt;br/&gt;            public override T DeserializeFromFile(string path, Encoding encoding)&lt;br/&gt;            {&lt;br/&gt;                return SerializationUtil.DeserializeFromBinaryFile&amp;lt;T&amp;gt;(path, encoding);&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            public override void SerializeToFile(T config, string path, Encoding encoding)&lt;br/&gt;            {&lt;br/&gt;                SerializationUtil.SerializeToBinaryFile(config, path, encoding);&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        #endregion&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;FileConfigSerializer&amp;lt;T&amp;gt;定义为抽象类，是为了方便默认的使用和扩展，里面使用的SerializationUtil类，是本人为了方便写的一个简单的序列化助手类，相信大家对对象的序列化操作不会陌生了，无非使用了System.Xml.Serialization.XmlSerializer、System.Runtime.Serialization.Formatters.Binary.BinaryFormatter、System.Runtime.Serialization.Json.DataContractJsonSerializer和System.Runtime.Serialization.NetDataContractSerializer来处理。如果不想用它们，你还可以实现FileConfigSerializer&amp;lt;T&amp;gt;进行完全的自己定义配置的加载与保存方式。对于json序列化推荐大家使用&lt;a href="http://www.codeplex.com/json/"&gt;http://www.codeplex.com/json/&lt;/a&gt;　。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;strong&gt;序列化用到的四个函数实现如下：&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;        public static void SerializeToXmlFile(object obj, string path, Encoding encoding)&lt;br/&gt;        {&lt;br/&gt;            using (var sw = new StreamWriter(path, false, encoding))&lt;br/&gt;            {&lt;br/&gt;                new XmlSerializer(obj.GetType()).Serialize(sw, obj);&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        public static object DeserializeFromXmlFile(string path, Type type, Encoding encoding)&lt;br/&gt;        {&lt;br/&gt;            object obj = null;&lt;br/&gt;&lt;br/&gt;            using (var sr = new StreamReader(path, encoding))&lt;br/&gt;            {&lt;br/&gt;                using (var xtr = new XmlTextReader(sr))&lt;br/&gt;                {&lt;br/&gt;                    xtr.Normalization = false;&lt;br/&gt;                    obj = new XmlSerializer(type).Deserialize(xtr);&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            return obj;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        public static void SerializeToBinaryFile(object obj, string path, Encoding encoding)&lt;br/&gt;        {&lt;br/&gt;            byte[] bytes = null;&lt;br/&gt;            using (var ms = new MemoryStream())&lt;br/&gt;            {&lt;br/&gt;                new BinaryFormatter().Serialize(ms, obj);&lt;br/&gt;                ms.Position = 0;&lt;br/&gt;                bytes = new Byte[ms.Length];&lt;br/&gt;                ms.Read(bytes, 0, bytes.Length);&lt;br/&gt;&lt;br/&gt;                using (var fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write))&lt;br/&gt;                {&lt;br/&gt;                    using (var bw = new BinaryWriter(fs, encoding))&lt;br/&gt;                    {&lt;br/&gt;                        bw.Write(bytes);&lt;br/&gt;                    }&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        public static object DeserializeFromBinaryFile(string path, Encoding encoding)&lt;br/&gt;        {&lt;br/&gt;            using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))&lt;br/&gt;            {&lt;br/&gt;                using (var br = new BinaryReader(fs, encoding))&lt;br/&gt;                {&lt;br/&gt;                    byte[] bytes = new byte[fs.Length];&lt;br/&gt;                    br.Read(bytes, 0, (int)fs.Length);&lt;br/&gt;&lt;br/&gt;                    using (var ms = new MemoryStream())&lt;br/&gt;                    {&lt;br/&gt;                        ms.Write(bytes, 0, bytes.Length);&lt;br/&gt;                        ms.Position = 0;&lt;br/&gt;                        return new BinaryFormatter().Deserialize(ms);&lt;br/&gt;                    }&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&amp;nbsp;实时更新&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;好了，大家已经知道了接口的定义了，下面来讲讲实时更新配置功能有哪些方法可以实现。我们知道，如果利用Web.config来配置的话，第一：如果配置内容多而杂，那会很乱；第二：如果手动修改配置，会导致Web重启（而我们并不希望它重启），所以，如果要解决上面两点问题，我们就要思考点什么了。上面我提到了Discuz!论坛的.net开源版本里配置管理，它是使用Timer来定时查检配置是否有修改，如果有修改就重新加载的，恩，这是一个可行的方案。还有其它方法吗？必须是有的，只要你肯去思考，下面列出本人想到的几个比较容易想到的方案：&lt;/p&gt;&lt;p&gt;&lt;span style="color: #800000;"&gt;方法１：使用Timer（.net库里有三个timer，请自行选择），每隔一秒就查检一下配置文件修改时间，如果文件被修改了，正更新最后修改时间并重新加载配置内容；&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #800000;"&gt;方法２：使用System.IO.FileSystemWatcher，可以实时监控配置文件，一发生改变即重新加载配置内容；&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #800000;"&gt;方法３：使用System.Web.Caching.Cache，加上缓存依赖，文件更改后缓存会失效，同样可以实时重新加载配置内容。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;这三种方法中，方法３是本人比较推荐的，因为它的开销最小，而且可以实时更新配置，实现起来也是最简单的。对于新手可能看到这还不知道实现，下面再贴出本人实现上面接口的四个类，一个是默认管理器类，没有实时更新的功能，其它三个就是实现上面三种方法的管理器类了。&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    internal class DefaultFileConfigManager&amp;lt;T&amp;gt; : DisposableObject, IFileConfigManager&amp;lt;T&amp;gt;&lt;br/&gt;        where T : class, new()&lt;br/&gt;    {&lt;br/&gt;        #region Fields&lt;br/&gt;&lt;br/&gt;        private string path = null;&lt;br/&gt;        private Func&amp;lt;string&amp;gt; pathCreator = null;&lt;br/&gt;&lt;br/&gt;        #endregion&lt;br/&gt;&lt;br/&gt;        #region Constructors&lt;br/&gt;&lt;br/&gt;        public DefaultFileConfigManager(Func&amp;lt;string&amp;gt; pathCreator, FileConfigSerializer&amp;lt;T&amp;gt; serializer, Encoding encoding)&lt;br/&gt;        {&lt;br/&gt;            pathCreator.ThrowsIfNull("pathCreator");&lt;br/&gt;            serializer.ThrowsIfNull("serializer");&lt;br/&gt;&lt;br/&gt;            this.pathCreator = pathCreator;&lt;br/&gt;            this.Encoding = encoding;&lt;br/&gt;            this.Serializer = serializer;&lt;br/&gt;            this.SyncRoot = new object();&lt;br/&gt;            this.Config = null;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        #endregion&lt;br/&gt;&lt;br/&gt;        #region Properties&lt;br/&gt;&lt;br/&gt;        public string Path&lt;br/&gt;        {&lt;br/&gt;            get&lt;br/&gt;            {&lt;br/&gt;                if (this.path == null)&lt;br/&gt;                {&lt;br/&gt;                    string path = this.pathCreator();&lt;br/&gt;&lt;br/&gt;                    path.ThrowsIfNull("The path returned form pathCreator is null.");&lt;br/&gt;&lt;br/&gt;                    this.path = path;&lt;br/&gt;                    this.LazyInitialize();&lt;br/&gt;                }&lt;br/&gt;&lt;br/&gt;                return this.path;&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        public Encoding Encoding&lt;br/&gt;        {&lt;br/&gt;            get;&lt;br/&gt;            protected set;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        public FileConfigSerializer&amp;lt;T&amp;gt; Serializer&lt;br/&gt;        {&lt;br/&gt;            get;&lt;br/&gt;            protected set;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        protected object SyncRoot&lt;br/&gt;        {&lt;br/&gt;            get;&lt;br/&gt;            set;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        protected virtual T Config&lt;br/&gt;        {&lt;br/&gt;            get;&lt;br/&gt;            set;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        #endregion&lt;br/&gt;&lt;br/&gt;        #region Methods&lt;br/&gt;&lt;br/&gt;        public virtual T GetConfig()&lt;br/&gt;        {&lt;br/&gt;            if (this.Config == null)&lt;br/&gt;            {&lt;br/&gt;                lock (this.SyncRoot)&lt;br/&gt;                {&lt;br/&gt;                    if (this.Config == null)&lt;br/&gt;                    {&lt;br/&gt;                        FileInfo file = new FileInfo(this.Path);&lt;br/&gt;                        if (!file.Exists)&lt;br/&gt;                        {&lt;br/&gt;                            // make sure the existence of the config directory&lt;br/&gt;                            if (!file.Directory.Exists)&lt;br/&gt;                            {&lt;br/&gt;                                file.Directory.Create();&lt;br/&gt;                            }&lt;br/&gt;                            // save the default config to file&lt;br/&gt;                            this.Config = new T();&lt;br/&gt;                            this.Serializer.SerializeToFile(this.Config, this.Path, this.Encoding);&lt;br/&gt;                        }&lt;br/&gt;                        else&lt;br/&gt;                        {&lt;br/&gt;                            // else, loads from the specified path&lt;br/&gt;                            this.Config = this.Serializer.DeserializeFromFile(this.Path, this.Encoding);&lt;br/&gt;                        }&lt;br/&gt;                    }&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            return this.Config;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        public void SaveConfig()&lt;br/&gt;        {&lt;br/&gt;            this.SaveConfig(this.GetConfig());&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        public virtual void SaveConfig(T config)&lt;br/&gt;        {&lt;br/&gt;            config.ThrowsIfNull("config");&lt;br/&gt;&lt;br/&gt;            lock (this.SyncRoot)&lt;br/&gt;            {&lt;br/&gt;                FileInfo file = new FileInfo(this.Path);&lt;br/&gt;&lt;br/&gt;                // make sure the existence of the config directory&lt;br/&gt;                if (!file.Directory.Exists)&lt;br/&gt;                {&lt;br/&gt;                    file.Directory.Create();&lt;br/&gt;                }&lt;br/&gt;&lt;br/&gt;                this.Config = config;&lt;br/&gt;                this.Serializer.SerializeToFile(this.Config, this.Path, this.Encoding);&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        public void BackupConfig(string backupPath)&lt;br/&gt;        {&lt;br/&gt;            backupPath.ThrowsIfNull("backupPath");&lt;br/&gt;&lt;br/&gt;            T config = this.GetConfig();&lt;br/&gt;            this.Serializer.SerializeToFile(config, backupPath, this.Encoding);&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        public void RestoreConfig(string restorePath)&lt;br/&gt;        {&lt;br/&gt;            restorePath.ThrowsIfNull("restorePath");&lt;br/&gt;&lt;br/&gt;            T config = this.Serializer.DeserializeFromFile(restorePath, this.Encoding);&lt;br/&gt;            this.SaveConfig(config);&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        // this method is provided to subclasses to initialize their data&lt;br/&gt;        protected virtual void LazyInitialize()&lt;br/&gt;        {&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        #endregion&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    internal sealed class FileConfigManagerWithTimer&amp;lt;T&amp;gt; : DefaultFileConfigManager&amp;lt;T&amp;gt;&lt;br/&gt;        where T : class, new()&lt;br/&gt;    {&lt;br/&gt;        private Timer timer = null;&lt;br/&gt;        private DateTime lastWriteTime = DateTime.MinValue; // a flag to notify us of the change config&lt;br/&gt;&lt;br/&gt;        public FileConfigManagerWithTimer(Func&amp;lt;string&amp;gt; pathCreator, FileConfigSerializer&amp;lt;T&amp;gt; serializer, Encoding encoding)&lt;br/&gt;            : base(pathCreator, serializer, encoding)&lt;br/&gt;        {&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        protected override void LazyInitialize()&lt;br/&gt;        {&lt;br/&gt;            base.LazyInitialize();&lt;br/&gt;&lt;br/&gt;            // initializes the timer, with it's interval of 1000 milliseconds&lt;br/&gt;            this.timer = new Timer(1000);&lt;br/&gt;            this.timer.Enabled = true;&lt;br/&gt;            this.timer.AutoReset = true;&lt;br/&gt;            this.timer.Elapsed += new ElapsedEventHandler(Timer_Elapsed);&lt;br/&gt;            this.timer.Start();&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        protected override void Dispose(bool disposing)&lt;br/&gt;        {&lt;br/&gt;            if (disposing)&lt;br/&gt;            {&lt;br/&gt;                // disposes the timer&lt;br/&gt;                this.timer.Dispose();&lt;br/&gt;                this.timer = null;&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        private void Timer_Elapsed(object sender, ElapsedEventArgs e)&lt;br/&gt;        {&lt;br/&gt;            if (!File.Exists(this.Path))&lt;br/&gt;            {&lt;br/&gt;                // the file has been deleted&lt;br/&gt;                return;&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            var tempWriteTime = File.GetLastWriteTime(this.Path);&lt;br/&gt;&lt;br/&gt;            // if equals to the initial value, update it and return&lt;br/&gt;            if (this.lastWriteTime == DateTime.MinValue)&lt;br/&gt;            {&lt;br/&gt;                this.lastWriteTime = tempWriteTime;&lt;br/&gt;                return;&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            // if no equals to new write time, update it and reload config&lt;br/&gt;            if (this.lastWriteTime != tempWriteTime)&lt;br/&gt;            {&lt;br/&gt;                this.lastWriteTime = tempWriteTime;&lt;br/&gt;&lt;br/&gt;                lock (this.SyncRoot)&lt;br/&gt;                {&lt;br/&gt;                    this.Config = this.Serializer.DeserializeFromFile(this.Path, this.Encoding);&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    internal sealed class FileConfigManagerWithFileWatcher&amp;lt;T&amp;gt; : DefaultFileConfigManager&amp;lt;T&amp;gt;&lt;br/&gt;        where T : class, new()&lt;br/&gt;    {&lt;br/&gt;        private FileWatcher watcher = null;&lt;br/&gt;&lt;br/&gt;        public FileConfigManagerWithFileWatcher(Func&amp;lt;string&amp;gt; pathCreator, FileConfigSerializer&amp;lt;T&amp;gt; serializer, Encoding encoding)&lt;br/&gt;            : base(pathCreator, serializer, encoding)&lt;br/&gt;        {&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        protected override void LazyInitialize()&lt;br/&gt;        {&lt;br/&gt;            base.LazyInitialize();&lt;br/&gt;&lt;br/&gt;            // when the path is created, the watcher should be initialize at the same time&lt;br/&gt;            watcher = new FileWatcher(this.Path, FileChanged);&lt;br/&gt;            // just start watching the file&lt;br/&gt;            watcher.StartWatching();&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        protected override void Dispose(bool disposing)&lt;br/&gt;        {&lt;br/&gt;            if (disposing)&lt;br/&gt;            {&lt;br/&gt;                // disposes the watcher&lt;br/&gt;                this.watcher.Dispose();&lt;br/&gt;                this.watcher = null;&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            base.Dispose(disposing);&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        private void FileChanged(object sender, FileSystemEventArgs args)&lt;br/&gt;        {&lt;br/&gt;            lock (this.SyncRoot)&lt;br/&gt;            {&lt;br/&gt;                this.watcher.StopWatching();&lt;br/&gt;                try&lt;br/&gt;                {&lt;br/&gt;                    // note: here making the cuurent thread sleeping a litle while to avoid exception throwed by watcher&lt;br/&gt;                    Thread.Sleep(10);&lt;br/&gt;                    // reload the config from file&lt;br/&gt;                    this.Config = this.Serializer.DeserializeFromFile(this.Path, this.Encoding);&lt;br/&gt;                }&lt;br/&gt;                catch (Exception)&lt;br/&gt;                {&lt;br/&gt;                    // ignore it&lt;br/&gt;                }&lt;br/&gt;                finally&lt;br/&gt;                {&lt;br/&gt;                    this.watcher.StartWatching();&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    internal sealed class FileConfigManagerWithCacheDependency&amp;lt;T&amp;gt; : DefaultFileConfigManager&amp;lt;T&amp;gt;&lt;br/&gt;        where T : class, new()&lt;br/&gt;    {&lt;br/&gt;        const string KeyPrefix = "FileConfig:";&lt;br/&gt;&lt;br/&gt;        public FileConfigManagerWithCacheDependency(Func&amp;lt;string&amp;gt; pathCreator, FileConfigSerializer&amp;lt;T&amp;gt; serializer, Encoding encoding)&lt;br/&gt;            : base(pathCreator, serializer, encoding)&lt;br/&gt;        {&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        protected override T Config&lt;br/&gt;        {&lt;br/&gt;            get&lt;br/&gt;            {&lt;br/&gt;                return HttpRuntime.Cache[KeyPrefix + this.Path] as T;&lt;br/&gt;            }&lt;br/&gt;            set&lt;br/&gt;            {&lt;br/&gt;                // if not null, update the cache value&lt;br/&gt;                if (value != null)&lt;br/&gt;                {&lt;br/&gt;                    HttpRuntime.Cache.Insert(KeyPrefix + this.Path, value, new CacheDependency(this.Path), DateTime.Now.AddYears(1), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;这里值得讲一下的是，默认管理器DefaultFileConfigManager&amp;lt;T&amp;gt;的Func&amp;lt;string&amp;gt; pathCreator参数，这个是为了实现配置文件的迟加载的，有了它，就不需要在静态构造函数或Global.asax里初始化管理器实例了，另外为了方便使用，本人还另写了个类为返回创建的管理器实例，这个就没什么好说的了，这也就是为什么上面几个类的访问范围是程序集内部的。&lt;strong&gt;到此，整个实现的思路和大部分的代码实现都讲完了，希望对大家有所帮助：） 更多请关注：&lt;a href="http://www.cnblogs.com/kudy/archive/2011/12/19/2293753.html" target="_blank"&gt;&lt;strong&gt;&amp;nbsp;KudyStudio文章目录&lt;/strong&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;有兴趣的朋友还可以下载这个例子看看各种方法下的效果&amp;nbsp;：&amp;nbsp;&lt;a href="http://files.cnblogs.com/kudy/FileConfigWeb.rar"&gt;FileConfigWeb.rar&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/kudy/aggbug/2305198.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kudy/archive/2011/12/28/2305198.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/kudy/archive/2011/12/21/2295354.html</id><title type="text">又失恋了。程序员，你的爱情在哪里？</title><summary type="text">在这个寂寞的夜晚，我们的心在繁华都市孤独游荡。爱情是如此美丽令人向往，却喜欢拿枯燥无聊的程序员开玩笑。青春转瞬即逝，上帝啊，求求你告诉我：我们的爱情什么时候会到来？生活又是如此公平，生活在问我们：你付出了什么？体会了什么？思考了什么？ ——《电脑报》资深编辑 黄旭那一天我不得已上路为不安分的心为自尊的生存为自我的证明路上的辛酸已融进我的眼睛心灵的困境已化作我的坚定在路上 用我心灵的呼声在路上 只为伴着我的人在路上 是我生命的远行在路上 只为温暖我的人温暖我的人上面是《在路上》的歌词，又一次选择了创业，每次听《在路上》都有点小冲动，因为这次更多的动力是为了我爱的人，才开始了三个月时间，今晚她却和</summary><published>2011-12-20T18:24:00Z</published><updated>2011-12-20T18:24:00Z</updated><author><name>Kudy</name><uri>http://www.cnblogs.com/kudy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kudy/archive/2011/12/21/2295354.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kudy/archive/2011/12/21/2295354.html"/><content type="html">&lt;p&gt;在这个寂寞的夜晚，我们的心在繁华都市孤独游荡。爱情是如此美丽令人向往，却喜欢拿枯燥无聊的程序员开玩笑。青春转瞬即逝，上帝啊，求求你告诉我：我们的爱情什么时候会到来？生活又是如此公平，生活在问我们：你付出了什么？体会了什么？思考了什么？ &amp;mdash;&amp;mdash;《电脑报》资深编辑 黄旭&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;那一天&lt;br /&gt;我不得已上路&lt;br /&gt;为不安分的心&lt;br /&gt;为自尊的生存&lt;br /&gt;为自我的证明&lt;br /&gt;路上的辛酸已融进我的眼睛&lt;br /&gt;心灵的困境已化作我的坚定&lt;br /&gt;&lt;br /&gt;在路上 用我心灵的呼声&lt;br /&gt;在路上 只为伴着我的人&lt;br /&gt;在路上 是我生命的远行&lt;br /&gt;在路上 只为温暖我的人&lt;br /&gt;温暖我的人&lt;br /&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;上面是《在路上》的歌词，又一次选择了创业，每次听《在路上》都有点小冲动，因为这次更多的动力是为了我爱的人，才开始了三个月时间，今晚她却和我说要和前男友下个月结婚了...令我纠结的原因不好直接说，下面这段代码来描述了我的心情，我都不敢运行：&lt;/p&gt;&lt;p&gt;补充一点吧，其实还是我不够细心，只顾忙自己的工作，程序员就这样子了，女人的心思我还真不会猜，我和她的关系还是有点复杂，这里不说出来了，那baby可能成为我心中永远的迷，不管她选择的是对还是错，我还是祝福她。有女友的同志们，有时间还是多点了解一下女人吧，这样才好维持两人的爱情。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    class Program&lt;br/&gt;    {&lt;br/&gt;        static void Main(string[] args)&lt;br/&gt;        {&lt;br/&gt;            Random rd = new Random();&lt;br/&gt;&lt;br/&gt;            string[] fathers = new string[2]{"kudy", "other"};&lt;br/&gt;&lt;br/&gt;            Princess.Instance.Baby = new Baby() { Father = fathers[rd.Next(0, 2)] };&lt;br/&gt;&lt;br/&gt;            Console.WriteLine(GetMood(Princess.Instance.Baby));&lt;br/&gt;&lt;br/&gt;            Console.ReadKey();&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        static Mood GetMood(Baby baby)&lt;br/&gt;        {&lt;br/&gt;            switch (baby.Father)&lt;br/&gt;            {&lt;br/&gt;                case "other":&lt;br/&gt;                    return Mood.Sad;&lt;br/&gt;                case "kudy":&lt;br/&gt;                    return Mood.Sadder;&lt;br/&gt;                default:&lt;br/&gt;                    throw new InvalidOperationException();&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    public enum Mood&lt;br/&gt;    {&lt;br/&gt;        Sad,&lt;br/&gt;        Sadder&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    public class Baby&lt;br/&gt;    {&lt;br/&gt;        public string Father { get; set; }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    public sealed class Princess&lt;br/&gt;    {&lt;br/&gt;        public static readonly Princess Instance = new Princess();&lt;br/&gt;&lt;br/&gt;        private Princess() { }&lt;br/&gt;&lt;br/&gt;        public Baby Baby { get; set; }&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;明天找个MM唱K去，发泄一下，生活不容易呀&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/kudy/aggbug/2295354.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kudy/archive/2011/12/21/2295354.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/kudy/archive/2011/12/20/2294762.html</id><title type="text">关键字过虑实现的思路及Aho–Corasick高效字符串匹配算法应用</title><summary type="text">在本人昨晚发的强大灵活的脏字过虑：1万字文章过虑1万关键词用时只要1毫秒（包括扩展的高亮功能）文章中，只是介绍过虑的功能和性能，这个文章主要讲一下实现的思路，另外给大家看一下Aho–Corasick算法的C#实现。既然是要过虑，那就要先查找，如果是直接的一个字符一个字符的匹配，那是很耗时的，因为时间花在不需要匹配的工作，有不少人会用正则去解决过虑，我09年的时候也这样，但后来发现大量关键词下性能确实极低下，所以才会另想它法。上一文中的过虑主要思想是这样的，开始会先用一个字典保存保存所有关键词，同一个字母开头的会另放在一个子字典里，这样一来，扫描的范围就大大的缩小了，然后再考虑到脏字一般是2个</summary><published>2011-12-20T08:22:00Z</published><updated>2011-12-20T08:22:00Z</updated><author><name>Kudy</name><uri>http://www.cnblogs.com/kudy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kudy/archive/2011/12/20/2294762.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kudy/archive/2011/12/20/2294762.html"/><content type="html">&lt;p&gt;在本人昨晚发的&lt;a id="ctl02_TitleUrl" class="postTitle2" href="http://www.cnblogs.com/kudy/archive/2011/12/19/2293781.html"&gt;强大灵活的脏字过虑：1万字文章过虑1万关键词用时只要1毫秒（包括扩展的高亮功能）&lt;/a&gt;　文章中，只是介绍过虑的功能和性能，这个文章主要讲一下实现的思路，另外给大家看一下Aho&amp;ndash;Corasick算法的C#实现。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;既然是要过虑，那就要先查找，如果是直接的一个字符一个字符的匹配，那是很耗时的，因为时间花在不需要匹配的工作，有不少人会用正则去解决过虑，我09年的时候也这样，但后来发现大量关键词下性能确实极低下，所以才会另想它法。上一文中的过虑主要思想是这样的，开始会先用一个字典保存保存所有关键词，同一个字母开头的会另放在一个子字典里，这样一来，扫描的范围就大大的缩小了，然后再考虑到脏字一般是2个字的占了很大的比例，所以再在第二个字母做判断，如果不存在就不需要再扫描下去了，至于可跳字符，就是在直接需要扫描的时候一一判断的，没技巧可讲，另外一点值得注意的是，大小写敏感的情况下，在判断时需要转换大小写，大量关键词影响不小，所以就初始化时再保存了一分小写的，所以在扫描的时候就不需要转换了，所以是否大小写的两个情况性能上不会有什么变化，基本的思路就这样了。如果说，你想要很准确的过虑，那就要用到分词了（判断可以人性化），我的方法只能处理比较简单匹配与过虑。实现过程并没有使用Aho&amp;ndash;Corasick算法。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;在查找资料的时候还了解到&lt;a href="http://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_string_matching_algorithm" target="_blank"&gt;Aho&amp;ndash;Corasick&lt;/a&gt;算法，它可以帮助我们快速的找出多个子字符串。可以到这里了解算法：&lt;a href="http://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_string_matching_algorithm"&gt;http://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_string_matching_algorithm&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;５点有约会，先直接上实现代码了（从一老外的例子里小改的），本人测试过我上面的方法和使用&lt;a href="http://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_string_matching_algorithm" target="_blank"&gt;Aho&amp;ndash;Corasick&lt;/a&gt;过虑用的时候差不了多少：&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    /// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// 表示一个查找结果&lt;br/&gt;    /// &amp;lt;/summary&amp;gt;&lt;br/&gt;    public struct KeywordSearchResult&lt;br/&gt;    {&lt;br/&gt;        private int index;&lt;br/&gt;        private string keyword;&lt;br/&gt;        public static readonly KeywordSearchResult Empty = new KeywordSearchResult(-1, string.Empty);&lt;br/&gt;&lt;br/&gt;        public KeywordSearchResult(int index, string keyword)&lt;br/&gt;        {&lt;br/&gt;            this.index = index; &lt;br/&gt;            this.keyword = keyword;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// 位置&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        public int Index&lt;br/&gt;        {&lt;br/&gt;            get { return index; }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// 关键词&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        public string Keyword&lt;br/&gt;        {&lt;br/&gt;            get { return keyword; }&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;    /// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// Aho-Corasick算法实现&lt;br/&gt;    /// &amp;lt;/summary&amp;gt;&lt;br/&gt;    public class KeywordSearch&lt;br/&gt;    {&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// 构造节点&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        private class Node&lt;br/&gt;        {&lt;br/&gt;            private Dictionary&amp;lt;char, Node&amp;gt; transDict;&lt;br/&gt;&lt;br/&gt;            public Node(char c, Node parent)&lt;br/&gt;            {&lt;br/&gt;                this.Char = c;&lt;br/&gt;                this.Parent = parent;&lt;br/&gt;                this.Transitions = new List&amp;lt;Node&amp;gt;();&lt;br/&gt;                this.Results = new List&amp;lt;string&amp;gt;();&lt;br/&gt;&lt;br/&gt;                this.transDict = new Dictionary&amp;lt;char, Node&amp;gt;();&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            public char Char&lt;br/&gt;            {&lt;br/&gt;                get;&lt;br/&gt;                private set;&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            public Node Parent&lt;br/&gt;            {&lt;br/&gt;                get;&lt;br/&gt;                private set;&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            public Node Failure&lt;br/&gt;            {&lt;br/&gt;                get;&lt;br/&gt;                set;&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            public List&amp;lt;Node&amp;gt; Transitions&lt;br/&gt;            {&lt;br/&gt;                get;&lt;br/&gt;                private set;&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            public List&amp;lt;string&amp;gt; Results&lt;br/&gt;            {&lt;br/&gt;                get;&lt;br/&gt;                private set;&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            public void AddResult(string result)&lt;br/&gt;            {&lt;br/&gt;                if (!Results.Contains(result))&lt;br/&gt;                {&lt;br/&gt;                    Results.Add(result);&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            public void AddTransition(Node node)&lt;br/&gt;            {&lt;br/&gt;                this.transDict.Add(node.Char, node);&lt;br/&gt;                this.Transitions = this.transDict.Values.ToList();&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            public Node GetTransition(char c)&lt;br/&gt;            {&lt;br/&gt;                Node node;&lt;br/&gt;                if (this.transDict.TryGetValue(c, out node))&lt;br/&gt;                {&lt;br/&gt;                    return node;&lt;br/&gt;                }&lt;br/&gt;&lt;br/&gt;                return null;&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            public bool ContainsTransition(char c)&lt;br/&gt;            {&lt;br/&gt;                return GetTransition(c) != null;&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        private Node root; // 根节点&lt;br/&gt;        private string[] keywords; // 所有关键词&lt;br/&gt;&lt;br/&gt;        public KeywordSearch(IEnumerable&amp;lt;string&amp;gt; keywords)&lt;br/&gt;        {&lt;br/&gt;            this.keywords = keywords.ToArray();&lt;br/&gt;            this.Initialize();&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// 根据关键词来初始化所有节点&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        private void Initialize()&lt;br/&gt;        {&lt;br/&gt;            this.root = new Node(' ', null);&lt;br/&gt;&lt;br/&gt;            // 添加模式&lt;br/&gt;            foreach (string k in this.keywords)&lt;br/&gt;            {&lt;br/&gt;                Node n = this.root;&lt;br/&gt;                foreach (char c in k)&lt;br/&gt;                {&lt;br/&gt;                    Node temp = null;&lt;br/&gt;                    foreach (Node tnode in n.Transitions)&lt;br/&gt;                    {&lt;br/&gt;                        if (tnode.Char == c)&lt;br/&gt;                        {&lt;br/&gt;                            temp = tnode; break; &lt;br/&gt;                        }&lt;br/&gt;                    }&lt;br/&gt;&lt;br/&gt;                    if (temp == null)&lt;br/&gt;                    {&lt;br/&gt;                        temp = new Node(c, n);&lt;br/&gt;                        n.AddTransition(temp);&lt;br/&gt;                    }&lt;br/&gt;                    n = temp;&lt;br/&gt;                }&lt;br/&gt;                n.AddResult(k);&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            // 第一层失败指向根节点&lt;br/&gt;            List&amp;lt;Node&amp;gt; nodes = new List&amp;lt;Node&amp;gt;();&lt;br/&gt;            foreach (Node node in this.root.Transitions)&lt;br/&gt;            {&lt;br/&gt;                // 失败指向root&lt;br/&gt;                node.Failure = this.root;&lt;br/&gt;                foreach (Node trans in node.Transitions)&lt;br/&gt;                {&lt;br/&gt;                    nodes.Add(trans);&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;            // 其它节点 BFS&lt;br/&gt;            while (nodes.Count != 0)&lt;br/&gt;            {&lt;br/&gt;                List&amp;lt;Node&amp;gt; newNodes = new List&amp;lt;Node&amp;gt;();&lt;br/&gt;                foreach (Node nd in nodes)&lt;br/&gt;                {&lt;br/&gt;                    Node r = nd.Parent.Failure;&lt;br/&gt;                    char c = nd.Char;&lt;br/&gt;&lt;br/&gt;                    while (r != null &amp;amp;&amp;amp; !r.ContainsTransition(c))&lt;br/&gt;                    {&lt;br/&gt;                        r = r.Failure;&lt;br/&gt;                    }&lt;br/&gt;&lt;br/&gt;                    if (r == null)&lt;br/&gt;                    {&lt;br/&gt;                        // 失败指向root&lt;br/&gt;                        nd.Failure = this.root;&lt;br/&gt;                    }&lt;br/&gt;                    else&lt;br/&gt;                    {&lt;br/&gt;                        nd.Failure = r.GetTransition(c);&lt;br/&gt;                        foreach (string result in nd.Failure.Results)&lt;br/&gt;                        {&lt;br/&gt;                            nd.AddResult(result);&lt;br/&gt;                        }&lt;br/&gt;                    }&lt;br/&gt;&lt;br/&gt;                    foreach (Node child in nd.Transitions)&lt;br/&gt;                    {&lt;br/&gt;                        newNodes.Add(child);&lt;br/&gt;                    }&lt;br/&gt;                }&lt;br/&gt;                nodes = newNodes;&lt;br/&gt;            }&lt;br/&gt;            // 根节点的失败指向自己&lt;br/&gt;            this.root.Failure = this.root;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// 找出所有出现过的关键词&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        /// &amp;lt;param name="text"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;        /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;        public List&amp;lt;KeywordSearchResult&amp;gt; FindAllKeywords(string text)&lt;br/&gt;        {&lt;br/&gt;            List&amp;lt;KeywordSearchResult&amp;gt; list = new List&amp;lt;KeywordSearchResult&amp;gt;();&lt;br/&gt;&lt;br/&gt;            Node current = this.root;&lt;br/&gt;            for (int index = 0; index &amp;lt; text.Length; ++index)&lt;br/&gt;            {&lt;br/&gt;                Node trans;&lt;br/&gt;                do&lt;br/&gt;                {&lt;br/&gt;                    trans = current.GetTransition(text[index]);&lt;br/&gt;&lt;br/&gt;                    if (current == this.root)&lt;br/&gt;                        break;&lt;br/&gt;&lt;br/&gt;                    if (trans == null)&lt;br/&gt;                    {&lt;br/&gt;                        current = current.Failure;&lt;br/&gt;                    }&lt;br/&gt;                } while (trans == null);&lt;br/&gt;&lt;br/&gt;                if (trans != null)&lt;br/&gt;                {&lt;br/&gt;                    current = trans;&lt;br/&gt;                }&lt;br/&gt;&lt;br/&gt;                foreach (string s in current.Results)&lt;br/&gt;                {&lt;br/&gt;                    list.Add(new KeywordSearchResult(index - s.Length + 1, s));&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            return list;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// 简单地过虑关键词&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        /// &amp;lt;param name="text"&amp;gt;&amp;lt;/param&amp;gt;&lt;br/&gt;        /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;br/&gt;        public string FilterKeywords(string text)&lt;br/&gt;        {&lt;br/&gt;            StringBuilder sb = new StringBuilder();&lt;br/&gt;&lt;br/&gt;            Node current = this.root;&lt;br/&gt;            for (int index = 0; index &amp;lt; text.Length; index++)&lt;br/&gt;            {&lt;br/&gt;                Node trans;&lt;br/&gt;                do&lt;br/&gt;                {&lt;br/&gt;                    trans = current.GetTransition(text[index]);&lt;br/&gt;&lt;br/&gt;                    if (current == this.root)&lt;br/&gt;                        break;&lt;br/&gt;&lt;br/&gt;                    if (trans == null)&lt;br/&gt;                    {&lt;br/&gt;                        current = current.Failure;&lt;br/&gt;                    }&lt;br/&gt;&lt;br/&gt;                } while (trans == null);&lt;br/&gt;&lt;br/&gt;                if (trans != null)&lt;br/&gt;                {&lt;br/&gt;                    current = trans;&lt;br/&gt;                }&lt;br/&gt;&lt;br/&gt;                // 处理字符&lt;br/&gt;                if (current.Results.Count &amp;gt; 0)&lt;br/&gt;                {&lt;br/&gt;                    string first = current.Results[0];&lt;br/&gt;                    sb.Remove(sb.Length - first.Length + 1, first.Length -1);// 把匹配到的替换为**&lt;br/&gt;                    sb.Append(new string('*', current.Results[0].Length));&lt;br/&gt;&lt;br/&gt;                }&lt;br/&gt;                else&lt;br/&gt;                {&lt;br/&gt;                    sb.Append(text[index]);&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            return sb.ToString();&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;测试结果：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011122016152748.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;下载源码：&lt;a href="http://files.cnblogs.com/kudy/KeywordSearch.rar"&gt;http://files.cnblogs.com/kudy/KeywordSearch.rar&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/kudy/aggbug/2294762.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kudy/archive/2011/12/20/2294762.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/kudy/archive/2011/12/19/2293781.html</id><title type="text">强大灵活的脏字过虑：1万字文章过虑1万关键词用时只要1毫秒</title><summary type="text">这几天刚整理完Kudy.Net项目中关键词过虑的功能。关键词过虑在网站开发中也算是比较常见的需求了，特别是在SNS社区网站。在网上找的相关文章都达不到我的要求，所以就自己根据过虑的特点专门写了个KeywordFilter，可能满足基本的过虑要求，性能也不错。它有如下特点：一、允许你自定义匹配到关键词时返回的结果，例如匹配到“日你”，你可以在原文中显示例如：“”、“**”、“[已过虑]”...二、允许你按关键词或者关键词的使用频率的排序的优先顺序进行过虑。三、允许大小写是否敏感（性能上几乎不变），可设置关键词中可跳过的字符，例如设置可跳字符为“▇☆”，关键词里有“我爱你”，那么“我▇爱☆☆你”也</summary><published>2011-12-19T13:12:00Z</published><updated>2011-12-19T13:12:00Z</updated><author><name>Kudy</name><uri>http://www.cnblogs.com/kudy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kudy/archive/2011/12/19/2293781.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kudy/archive/2011/12/19/2293781.html"/><content type="html">&lt;p&gt;这几天刚整理完Kudy.Net项目中关键词过虑的功能。关键词过虑在网站开发中也算是比较常见的需求了，特别是在SNS社区网站。在网上找的相关文章都达不到我的要求，所以就自己根据过虑的特点专门写了个KeywordFilter，可能满足基本的过虑要求，性能也不错。它有如下特点：&lt;/p&gt;&lt;p&gt;&lt;span style="color: #800000;"&gt;一、允许你自定义匹配到关键词时返回的结果，例如匹配到&amp;ldquo;日你&amp;rdquo;，你可以在原文中显示例如：&amp;ldquo;&amp;rdquo;、&amp;ldquo;**&amp;rdquo;、&amp;ldquo;[已过虑]&amp;rdquo;...&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #800000;"&gt;二、允许你按关键词或者关键词的使用频率的排序的优先顺序进行过虑。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #800000;"&gt;三、允许大小写是否敏感（性能上几乎不变），可设置关键词中可跳过的字符，例如设置可跳字符为&amp;ldquo;▇☆&amp;rdquo;，关键词里有&amp;ldquo;我爱你&amp;rdquo;，那么&amp;ldquo;我▇爱☆☆你&amp;rdquo;也会被成功过虑。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;备注：如果设置了可跳字符，只会过虑有关键词出现的地方，例如上面&amp;ldquo;▇我▇爱☆☆你▇&amp;rdquo;过虑后只有&amp;ldquo;▇▇&amp;rdquo;。（哈哈，发现博客园的过虑并没有这功能）&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #ff0000;"&gt;既然是简单的处理过虑，里面当然没有做分词的处理，所以有些句子可能会被误报，只要设置重要的敏感禁用词即可。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #ff0000;"&gt;实现思路：&lt;a id="ctl02_TitleUrl" class="postTitle2" href="http://www.cnblogs.com/kudy/archive/2011/12/20/2294762.html"&gt;关键字过虑实现的思路及Aho&amp;ndash;Corasick高效字符串匹配算法应用（附算法C#实现和测试）&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;另在一文中看到的过虑效率也不错，请到这里看&lt;a href="http://www.cnblogs.com/yeerh/archive/2011/10/20/2219035.html"&gt;http://www.cnblogs.com/yeerh/archive/2011/10/20/2219035.html&lt;/a&gt;，测试了它的速度是本人的约1.5倍，但是它并没有不区分大小写、可跳字符、关键词排序和多样化自定义关键词替换的功能，我更关心的是功能上的实用和灵活性。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;更多请关注：&lt;a href="http://www.cnblogs.com/kudy/archive/2011/12/19/2293753.html" target="_blank"&gt;&lt;strong&gt;&amp;nbsp;KudyStudio文章目录&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;功能实现的相关成员有：Keyword、KeywordOrder、KeywordFormatter、KeywordFilterResult、KeywordFilter、HighlightFormatter、Highlighter。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;１.Keyword类，主要有两个属性，Text和Frequency，分别表示关键词文本与它的使用频率（这个属性是可选的），如果从文本中转换为关键词列表，那文本格式是这样的：&lt;/p&gt;&lt;p&gt;Keyword1&lt;/p&gt;&lt;p&gt;Keyword2&lt;/p&gt;&lt;p&gt;或&lt;/p&gt;&lt;p&gt;Keyword1｜Frequency1&lt;/p&gt;&lt;p&gt;Keyword2｜Frequency2&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    [Serializable]&lt;br/&gt;    public sealed class Keyword&lt;br/&gt;    {&lt;br/&gt;        public Keyword(string text);&lt;br/&gt;        public Keyword(string text, int frequency);&lt;br/&gt;&lt;br/&gt;        public static implicit operator string(Keyword keyword);&lt;br/&gt;        public static implicit operator Keyword(string keyword);&lt;br/&gt;&lt;br/&gt;        public string Text { get; }&lt;br/&gt;        public int Frequency { get; set; }&lt;br/&gt;&lt;br/&gt;        public override bool Equals(object obj);&lt;br/&gt;        public override int GetHashCode();&lt;br/&gt;        public override string ToString();&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;２.KeywordOrder枚举，表示过虑时匹配的顺序，允许你按文本或使用频率排序，定义如下：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    [Serializable]&lt;br/&gt;    public enum KeywordOrder&lt;br/&gt;    {&lt;br/&gt;        None = 0,&lt;br/&gt;        Ascending = 1,&lt;br/&gt;        Descending = 2,&lt;br/&gt;        ByFrequencyAscending = 3,&lt;br/&gt;        ByFrequencyDescending = 4,&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;３.KeywordFormatter类，这个是抽象类，它的作用就是在匹配到关键词时怎么格式化关键词并返回，里面默认实现了常量和重复字符的Formatter，如果还需要特殊的格式化需求，只要继承KeywordFormatter并实现Format(string keyword)方法即可，下面提到的HighlightFormatter就是其中一个例子。&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    public abstract class KeywordFormatter&lt;br/&gt;    {&lt;br/&gt;        public static readonly KeywordFormatter ToEmpty;&lt;br/&gt;        public static readonly KeywordFormatter ToIterantStar;&lt;br/&gt;&lt;br/&gt;        public static KeywordFormatter CreateConstFormatter(char replacement);&lt;br/&gt;        public static KeywordFormatter CreateConstFormatter(string replacement);&lt;br/&gt;        public static KeywordFormatter CreateIterantCharFormatter(char replacement);&lt;br/&gt;&lt;br/&gt;        public abstract string Format(string keyword);&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;４.KeywordFilterResult类，它表示过虑结果，包括过虑后的字符串和被过虑的关键词列表，定义如下：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    public sealed class KeywordFilterResult&lt;br/&gt;    {&lt;br/&gt;        public KeywordFilterResult(string result, IEnumerable&amp;lt;Keyword&amp;gt; keywords);&lt;br/&gt;&lt;br/&gt;        public string Result { get; }&lt;br/&gt;        public List&amp;lt;Keyword&amp;gt; Keywords { get; }&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;５.KeywordFilter类，这个类是重点，它是实现过虑的核心，其它类只是功能需求上的辅助成员。要注意的是，它的初始化是需要一定的开销的（关键词量大的时候），所以对于大量的关键词，建议不要使用它的静态方法来进行过虑，而是先初始化实例，再重复的调用实例的方法来过虑。里面还有个方法ContainsAny让你快速判断里面是否包括有关键词。&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    public sealed class KeywordFilter&lt;br/&gt;    {&lt;br/&gt;        public KeywordFilter(IEnumerable&amp;lt;Keyword&amp;gt; keywords);&lt;br/&gt;        public KeywordFilter(IEnumerable&amp;lt;string&amp;gt; keywords);&lt;br/&gt;        public KeywordFilter(IEnumerable&amp;lt;Keyword&amp;gt; keywords, IEnumerable&amp;lt;char&amp;gt; skipChars);&lt;br/&gt;        public KeywordFilter(IEnumerable&amp;lt;string&amp;gt; keywords, IEnumerable&amp;lt;char&amp;gt; skipChars);&lt;br/&gt;&lt;br/&gt;        public ReadOnlyCollection&amp;lt;Keyword&amp;gt; Keywords { get; }&lt;br/&gt;        public ReadOnlyCollection&amp;lt;char&amp;gt; SkipChars { get; }&lt;br/&gt;&lt;br/&gt;        public bool ContainsAny(string original);&lt;br/&gt;        public bool ContainsAny(string original, bool ignoreCase);&lt;br/&gt;        public bool ContainsAny(string original, KeywordOrder order);&lt;br/&gt;        public bool ContainsAny(string original, KeywordOrder order, bool ignoreCase);&lt;br/&gt;&lt;br/&gt;        public KeywordFilterResult Filter(string original);&lt;br/&gt;        public KeywordFilterResult Filter(string original, KeywordFormatter formatter);&lt;br/&gt;        public KeywordFilterResult Filter(string original, KeywordFormatter formatter, bool ignoreCase);&lt;br/&gt;        public KeywordFilterResult Filter(string original, KeywordFormatter formatter, KeywordOrder order);&lt;br/&gt;        public KeywordFilterResult Filter(string original, KeywordFormatter formatter, KeywordOrder order, bool ignoreCase);&lt;br/&gt;&lt;br/&gt;        public static KeywordFilterResult Filter(string original, IEnumerable&amp;lt;Keyword&amp;gt; keywords);&lt;br/&gt;        public static KeywordFilterResult Filter(string original, IEnumerable&amp;lt;string&amp;gt; keywords);&lt;br/&gt;        public static KeywordFilterResult Filter(string original, IEnumerable&amp;lt;Keyword&amp;gt; keywords, KeywordFormatter formatter);&lt;br/&gt;        public static KeywordFilterResult Filter(string original, IEnumerable&amp;lt;string&amp;gt; keywords, KeywordFormatter formatter);&lt;br/&gt;        public static KeywordFilterResult Filter(string original, IEnumerable&amp;lt;Keyword&amp;gt; keywords, KeywordFormatter formatter, bool ignoreCase);&lt;br/&gt;        public static KeywordFilterResult Filter(string original, IEnumerable&amp;lt;Keyword&amp;gt; keywords, KeywordFormatter formatter, KeywordOrder order);&lt;br/&gt;        public static KeywordFilterResult Filter(string original, IEnumerable&amp;lt;string&amp;gt; keywords, KeywordFormatter formatter, bool ignoreCase);&lt;br/&gt;        public static KeywordFilterResult Filter(string original, IEnumerable&amp;lt;string&amp;gt; keywords, KeywordFormatter formatter, KeywordOrder order);&lt;br/&gt;        public static KeywordFilterResult Filter(string original, IEnumerable&amp;lt;Keyword&amp;gt; keywords, KeywordFormatter formatter, KeywordOrder order, bool ignoreCase);&lt;br/&gt;        public static KeywordFilterResult Filter(string original, IEnumerable&amp;lt;string&amp;gt; keywords, KeywordFormatter formatter, KeywordOrder order, bool ignoreCase);&lt;br/&gt;        public static KeywordFilterResult Filter(string original, IEnumerable&amp;lt;Keyword&amp;gt; keywords, IEnumerable&amp;lt;char&amp;gt; skipChars, KeywordFormatter formatter, KeywordOrder order, bool ignoreCase);&lt;br/&gt;        public static KeywordFilterResult Filter(string original, IEnumerable&amp;lt;string&amp;gt; keywords, IEnumerable&amp;lt;char&amp;gt; skipChars, KeywordFormatter formatter, KeywordOrder order, bool ignoreCase);&lt;br/&gt;&lt;br/&gt;        public static List&amp;lt;Keyword&amp;gt; LoadKeywords(string filePath);&lt;br/&gt;        public static List&amp;lt;Keyword&amp;gt; LoadKeywords(string filePath, Encoding encoding);&lt;br/&gt;        public static List&amp;lt;Keyword&amp;gt; ParseKeywords(string keywordsText);&lt;br/&gt;        public static void SaveKeywords(IEnumerable&amp;lt;Keyword&amp;gt; keywords, string filePath);&lt;br/&gt;        public static void SaveKeywords(IEnumerable&amp;lt;string&amp;gt; keywords, string filePath);&lt;br/&gt;        public static void SaveKeywords(IEnumerable&amp;lt;Keyword&amp;gt; keywords, string filePath, Encoding encoding);&lt;br/&gt;        public static void SaveKeywords(IEnumerable&amp;lt;string&amp;gt; keywords, string filePath, Encoding encoding);&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;到此，过虑功能成员介绍完了，下面还有两个成员是在KeywordFilter基础上实现的高亮功能HighlightFormatter和Highlighter。&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    public sealed class HighlightFormatter : KeywordFormatter&lt;br/&gt;    {&lt;br/&gt;        public static readonly HighlightFormatter Html;&lt;br/&gt;&lt;br/&gt;        public HighlightFormatter(string prefix, string postfix);&lt;br/&gt;&lt;br/&gt;        public string Postfix { get; }&lt;br/&gt;        public string Prefix { get; }&lt;br/&gt;&lt;br/&gt;        public static KeywordFormatter Create(string prefix, string postfix);&lt;br/&gt;&lt;br/&gt;        public override string Format(string keyword);&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    public static class Highlighter&lt;br/&gt;    {&lt;br/&gt;        public static string Highlight(string original, IEnumerable&amp;lt;Keyword&amp;gt; keywords, HighlightFormatter formatter);&lt;br/&gt;        public static string Highlight(string original, IEnumerable&amp;lt;string&amp;gt; keywords, HighlightFormatter formatter);&lt;br/&gt;        public static string Highlight(string original, IEnumerable&amp;lt;Keyword&amp;gt; keywords, HighlightFormatter formatter, bool ignoreCase);&lt;br/&gt;        public static string Highlight(string original, IEnumerable&amp;lt;Keyword&amp;gt; keywords, HighlightFormatter formatter, KeywordOrder order);&lt;br/&gt;        public static string Highlight(string original, IEnumerable&amp;lt;string&amp;gt; keywords, HighlightFormatter formatter, bool ignoreCase);&lt;br/&gt;        public static string Highlight(string original, IEnumerable&amp;lt;string&amp;gt; keywords, HighlightFormatter formatter, KeywordOrder order);&lt;br/&gt;        public static string Highlight(string original, IEnumerable&amp;lt;Keyword&amp;gt; keywords, HighlightFormatter formatter, KeywordOrder order, bool ignoreCase);&lt;br/&gt;        public static string Highlight(string original, IEnumerable&amp;lt;string&amp;gt; keywords, HighlightFormatter formatter, KeywordOrder order, bool ignoreCase);&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;ＯＫ，下面开始测试了。&lt;/p&gt;&lt;p&gt;关键词为："SB|法_轮_功（博客园过虑了）|日你|日你大爷"&lt;/p&gt;&lt;p&gt;可跳字符："▇☆"&lt;/p&gt;&lt;p&gt;原文本：....有博客园要过虑的词，不贴出来了，请看下面的测试结果，最后一组过虑变成了【关键词】，是因为用了自定义的Formatter。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011121921095221.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011121920512369.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;上面只是功能上的测试，下面是&lt;strong&gt;1000词/1000字文章/300可跳字符&lt;/strong&gt;和&lt;strong&gt;10000词/10000字文章/300可跳字符&lt;/strong&gt;性能上的测试结果，可以看到，小量关键词里，KeywordFilter实例化时间很少，但是达到1万关键词时用了252ms，而过虑所用时间只是从前面的0ms变为1ms，关键词&lt;strong&gt;达10万&lt;/strong&gt;时也只用了11ms（本人电脑的配置情况），可见过虑的高效。大家有兴趣的话请下载测试源码来自己看。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011121920581459.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011121920582878.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;是否过虑成功？那是必须的，一词不漏：&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011121920594337.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;高亮在KeywordFilter的基础上就简单实现了，只是实现了个HighlightFormatter，怎么高亮主要看前缀和后缀，下面是测试html高亮的结果：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011121921043960.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;至此，文章结束，大家帮忙点一下&lt;strong&gt;推荐&lt;/strong&gt;哦，提供测试源码下载：&lt;a href="http://files.cnblogs.com/kudy/KudyStudioFilteringTest.rar"&gt;KudyStudioFilteringTest.rar&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;更多请关注：&lt;a href="http://www.cnblogs.com/kudy/archive/2011/12/19/2293753.html" target="_blank"&gt;&lt;strong&gt;&amp;nbsp;KudyStudio文章目录&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/kudy/aggbug/2293781.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kudy/archive/2011/12/19/2293781.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/kudy/archive/2011/12/19/2293753.html</id><title type="text">KudyStudio文章目录</title><summary type="text">Kudy.Net项目的相关文章：【推荐】基于WebActivator的改进版本KudyStudio.Web.Activating讲解与源码下载 【推荐】强大灵活的脏字过虑：1万字文章过虑1万关键词用时只要 1ms（包括扩展的高亮功能）关键字过虑实现的思路及Aho–Corasick高效字符串匹配算法应用（附算法C#实现和测试）怎么设计个性化、灵活、实时更新的配置管理器？给大家讲讲实现思路，欢迎讨论Jbox插件相关：【jBox】2.3正式版 多功能jQuery对话框插件下载及常见使用问题解答 关于KudyStudio企业类库：本人为公司写的一个功能性类库（主要Web方向，轻量的，Winfor...</summary><published>2011-12-19T11:12:00Z</published><updated>2011-12-19T11:12:00Z</updated><author><name>Kudy</name><uri>http://www.cnblogs.com/kudy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kudy/archive/2011/12/19/2293753.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kudy/archive/2011/12/19/2293753.html"/><content type="html">&lt;p&gt;Kudy.Net项目的相关文章：&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kudy/archive/2011/12/15/KudyStudio_Web_Activating.html" target="_blank"&gt;【推荐】基于WebActivator的改进版本KudyStudio.Web.Activating讲解与源码下载 &lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a class="titlelink" href="http://www.cnblogs.com/kudy/archive/2011/12/15/KudyStudio_Web_Activating.html"&gt;【推荐】&lt;/a&gt;&lt;a id="ctl02_TitleUrl" class="postTitle2" href="http://www.cnblogs.com/kudy/archive/2011/12/19/2293781.html"&gt;强大灵活的脏字过虑：1万字文章过虑1万关键词用时只要 1ms（包括扩展的高亮功能）&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a id="ctl02_TitleUrl" class="postTitle2" href="http://www.cnblogs.com/kudy/archive/2011/12/20/2294762.html"&gt;关键字过虑实现的思路及Aho&amp;ndash;Corasick高效字符串匹配算法应用（附算法C#实现和测试）&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;a href="http://www.cnblogs.com/kudy/archive/2011/12/28/2305198.html" target="_blank"&gt;怎么设计个性化、灵活、实时更新的配置管理器？给大家讲讲实现思路，欢迎讨论&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Jbox插件相关：&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kudy/archive/2011/11/12/2246118.html" target="_blank"&gt;【jBox】2.3正式版 多功能jQuery对话框插件下载及常见使用问题解答 &lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&amp;nbsp;　&lt;strong&gt;关于KudyStudio企业类库&lt;/strong&gt;：本人为公司写的一个功能性类库（主要Web方向，轻量的，Winform程序也可以使用），它主要包括网站开发中的常用功能如常用集合类、数据缓存（包括Memcached和Membase客户端）、数据库操作、自己定义配置管理、日志处理、数据压缩、数据加密、方法扩展、关键字过虑、简单图片处理、地址重写、各种功能性小框架(例如Web表示层框架、依赖注入框架、WCF服务框架)等等等，远不止这些，目前还在整理完善中，大约在2012年底在公司项目完善时稳定初版本应该就会发布了，它可以免费提供给大家个人或商业使用。在最近一年内的开发整理中发布的关于KudyStudio的文章会或多或少提供一些源码与分析，如果你想关注和使用此类库，请关注本博客。&lt;/p&gt;&lt;p&gt;工作室网站：&lt;a href="http://www.kudystudio.com"&gt;www.kudystudio.com&lt;/a&gt; （未完成）&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/kudy/aggbug/2293753.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kudy/archive/2011/12/19/2293753.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/kudy/archive/2011/12/15/KudyStudio_Web_Activating.html</id><title type="text">基于WebActivator的改进版本KudyStudio.Web.Activating讲解与下载</title><summary type="text">前天刚发过文章介绍了KudyStudio.Web.Activating，今天再次作了修改，并提供源码给大家。 KudyStudio.Web.Activating下提供了两个属性分别是ActivationAttribute、ActivationMethodAttribute，利用它们可以灵活地随时在你的程序集中注册一个或多个Appilcation_Start()前/后触发和Appilcation_End()前触发的处理事件。 KudyStudio文章目录 下载源码KudyStudio.Web.Activating.rar（.Net4.0） 可触发的函数目标定义如下： /// &lt;s...</summary><published>2011-12-15T12:50:00Z</published><updated>2011-12-15T12:50:00Z</updated><author><name>Kudy</name><uri>http://www.cnblogs.com/kudy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kudy/archive/2011/12/15/KudyStudio_Web_Activating.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kudy/archive/2011/12/15/KudyStudio_Web_Activating.html"/><content type="html">&lt;p&gt;前天刚发过文章介绍了KudyStudio.Web.Activating，今天再次作了修改，并提供源码给大家。&lt;/p&gt;&lt;p&gt;KudyStudio.Web.Activating下提供了两个属性分别是ActivationAttribute、ActivationMethodAttribute，利用它们可以灵活地随时在你的程序集中注册&lt;strong&gt;一个或多个&lt;/strong&gt;Appilcation_Start()前/后触发和Appilcation_End()前触发的处理事件。&lt;a href="http://www.cnblogs.com/kudy/archive/2011/12/19/2293753.html" target="_blank"&gt;&lt;strong&gt; KudyStudio文章目录&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;下载源码&lt;a href="http://files.cnblogs.com/kudy/KudyStudio.Web.Activating.rar"&gt;KudyStudio.Web.Activating.rar&lt;/a&gt;（.Net4.0）&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011121523162564.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;可触发的函数目标定义如下：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    /// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// Specifies the targets to use for invoking activation methods.&lt;br/&gt;    /// &amp;lt;/summary&amp;gt;&lt;br/&gt;    [Serializable]&lt;br/&gt;    public enum ActivationMethodTarget&lt;br/&gt;    {&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// Provides expanded support for ASP.NET application pre-start.&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        PreApplicationStart = 0x0,&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// Provides expanded support for ASP.NET application post-start.&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        PostApplicationStart,&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// Provides expanded support for before ASP.NET application shutdown.&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        PreApplicationEnd&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;先介绍ActivationMethodAttribute，这个属性允许你以&lt;strong&gt;静态方法方式&lt;/strong&gt;来向程序集注册&lt;strong&gt;一个或多个&lt;/strong&gt;触发函数，并指定触发&lt;strong&gt;函数的目标&lt;/strong&gt;与&lt;strong&gt;执行顺序&lt;/strong&gt;，它的定义如下：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    /// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// Provides expanded support for application activation.&lt;br/&gt;    /// &amp;lt;/summary&amp;gt;&lt;br/&gt;    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple=true)]&lt;br/&gt;    public sealed class ActivationMethodAttribute : OrderableAttribute&lt;br/&gt;    {&lt;br/&gt;        #region Constructors&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// Initializes a new instance of the ActivationMethodAttribute class.&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        /// &amp;lt;param name="type"&amp;gt;An object that describes the type of the activation method.&amp;lt;/param&amp;gt;&lt;br/&gt;        /// &amp;lt;param name="methodName"&amp;gt;An empty parameter signature that has no return value.&amp;lt;/param&amp;gt;&lt;br/&gt;        public ActivationMethodAttribute(Type type, string methodName)&lt;br/&gt;            :this(type, methodName, ActivationMethodTarget.PreApplicationStart)&lt;br/&gt;        {&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// Initializes a new instance of the ActivationMethodAttribute class.&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        /// &amp;lt;param name="type"&amp;gt;An object that describes the type of the activation method.&amp;lt;/param&amp;gt;&lt;br/&gt;        /// &amp;lt;param name="methodName"&amp;gt;An empty parameter signature that has no return value.&amp;lt;/param&amp;gt;&lt;br/&gt;        /// &amp;lt;param name="methodTarget"&amp;gt;The method target for the associated activation method&amp;lt;/param&amp;gt;&lt;br/&gt;        public ActivationMethodAttribute(Type type, string methodName, ActivationMethodTarget methodTarget)&lt;br/&gt;        {&lt;br/&gt;            type.ThrowsIfNull("type");&lt;br/&gt;            methodName.ThrowsIfNullOrEmpty("methodName");&lt;br/&gt;            if (!Enum.IsDefined(typeof(ActivationMethodTarget), methodTarget))&lt;br/&gt;            {&lt;br/&gt;                throw new ArgumentException("The methodTarget is undefined.");&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            this.Type = type;&lt;br/&gt;            this.MethodName = methodName;&lt;br/&gt;            this.MethodTarget = methodTarget;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        #endregion&lt;br/&gt;&lt;br/&gt;        #region Properties&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// Gets the type that is returned by the associated activation method.&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        public Type Type&lt;br/&gt;        {&lt;br/&gt;            get;&lt;br/&gt;            private set;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// Gets the associated activation method.&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        public string MethodName&lt;br/&gt;        {&lt;br/&gt;            get;&lt;br/&gt;            private set;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// Gets or sets the method target for the associated activation method.&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        public ActivationMethodTarget MethodTarget&lt;br/&gt;        {&lt;br/&gt;            get;&lt;br/&gt;            set;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        #endregion&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;有了ActivationMethodAttribute属性其实可以满足基本需求了，但是ActivationAttribute属性能让你的代码组织更清晰，怎么说？因为注册触发函数时不需要传入函数名称，而且方便每个程式元件建立自己的实现类（实现IPreApplicationStart、IPostApplicationStart、IPreApplicationEnd中的一个或多个接口）而不和其它程式元件的注册事务混在一起。ActivationAttribute属性这个允许你以&lt;strong&gt;实现接口方式&lt;/strong&gt;来向程序集注册&lt;strong&gt;一个或多个&lt;/strong&gt;触发函数，并指定触发函数的&lt;strong&gt;执行顺序&lt;/strong&gt;，定义如下：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;    /// &amp;lt;summary&amp;gt;&lt;br/&gt;    /// Provides expanded support for application activation(s).&lt;br/&gt;    /// &amp;lt;/summary&amp;gt;&lt;br/&gt;    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple=true)]&lt;br/&gt;    public sealed class ActivationAttribute : OrderableAttribute&lt;br/&gt;    {&lt;br/&gt;        #region Constructors&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// Initializes a new instance of the ActivationAttribute class.&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        /// &amp;lt;param name="type"&amp;gt;&lt;br/&gt;        /// An object that implements any activation interface (&amp;lt;see cref="IPreApplicationStart"/&amp;gt;, &lt;br/&gt;        /// &amp;lt;see cref="IPostApplicationStart"/&amp;gt;, &amp;lt;see cref="IPreApplicationEnd"/&amp;gt;).&lt;br/&gt;        /// &amp;lt;/param&amp;gt;&lt;br/&gt;        public ActivationAttribute(Type type)&lt;br/&gt;        {&lt;br/&gt;            type.ThrowsIfNull("type");&lt;br/&gt;&lt;br/&gt;            this.Type = type;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        #endregion&lt;br/&gt;&lt;br/&gt;        #region Properties&lt;br/&gt;&lt;br/&gt;        /// &amp;lt;summary&amp;gt;&lt;br/&gt;        /// Gets the type that implements any activation interface.&lt;br/&gt;        /// &amp;lt;/summary&amp;gt;&lt;br/&gt;        public Type Type&lt;br/&gt;        {&lt;br/&gt;            get;&lt;br/&gt;            private set;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        #endregion&lt;br/&gt;    }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;重点的实现就是ActivationManager类的InvokeActivationMethods方法，代码如下：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;        private static void InvokeActivationMethods(ActivationMethodTarget target)&lt;br/&gt;        {&lt;br/&gt;            List&amp;lt;OrderableAttribute&amp;gt; allAttributes = new List&amp;lt;OrderableAttribute&amp;gt;();&lt;br/&gt;            // get all attributes&lt;br/&gt;            foreach (Assembly assembly in AppAssemblies.Concat(GetCodeAssemblies(target)))&lt;br/&gt;            {&lt;br/&gt;                allAttributes.AddRange(GetAttributes&amp;lt;ActivationMethodAttribute&amp;gt;(assembly).Cast&amp;lt;OrderableAttribute&amp;gt;());&lt;br/&gt;                allAttributes.AddRange(GetAttributes&amp;lt;ActivationAttribute&amp;gt;(assembly).Cast&amp;lt;OrderableAttribute&amp;gt;());&lt;br/&gt;            }&lt;br/&gt;            // handle all ordered attributes&lt;br/&gt;            foreach (OrderableAttribute attribute in allAttributes.OrderBy(attr =&amp;gt; attr.Order))&lt;br/&gt;            {&lt;br/&gt;                // invokes static method activations&lt;br/&gt;                ActivationMethodAttribute methodAttribute = attribute as ActivationMethodAttribute;&lt;br/&gt;                if (methodAttribute != null &amp;amp;&amp;amp; methodAttribute.MethodTarget == target)&lt;br/&gt;                {&lt;br/&gt;                    MethodInfo method = methodAttribute.Type.GetMethod(methodAttribute.MethodName, StaticMethodBindingFlags);&lt;br/&gt;                    if (method != null)&lt;br/&gt;                    {&lt;br/&gt;                        method.Invoke(null, null);&lt;br/&gt;                        continue; // continue next target&lt;br/&gt;                    }&lt;br/&gt;                    // method not found&lt;br/&gt;                    throw new ApplicationException(string.Format("The type {0} doesn't have a static method named {1}.", methodAttribute.Type, methodAttribute.MethodName));&lt;br/&gt;                }&lt;br/&gt;&lt;br/&gt;                // try next case:&lt;br/&gt;                // invokes activations of activation classes that implements any activation interface&lt;br/&gt;                ActivationAttribute classAttribute = attribute as ActivationAttribute;&lt;br/&gt;                if (classAttribute != null)&lt;br/&gt;                {&lt;br/&gt;                    Type type = classAttribute.Type;&lt;br/&gt;&lt;br/&gt;                    object activation = null;&lt;br/&gt;                    if (IsValidActivationType(type))&lt;br/&gt;                    {&lt;br/&gt;                        try&lt;br/&gt;                        {&lt;br/&gt;                            activation = Activator.CreateInstance(type);&lt;br/&gt;                        }&lt;br/&gt;                        catch(Exception ex)&lt;br/&gt;                        {&lt;br/&gt;                            throw new ApplicationException(string.Format("Fail to create instance of type {0}.", methodAttribute.Type), ex);&lt;br/&gt;                        }&lt;br/&gt;                    }&lt;br/&gt;                    else&lt;br/&gt;                    {&lt;br/&gt;                        // invalid activation class&lt;br/&gt;                        throw new ApplicationException(string.Format("The type {0} is not a valid activation class.", type.FullName));&lt;br/&gt;                    }&lt;br/&gt;&lt;br/&gt;                    if (activation != null)&lt;br/&gt;                    {&lt;br/&gt;                        if (target == ActivationMethodTarget.PreApplicationStart &amp;amp;&amp;amp; (activation is IPreApplicationStart))&lt;br/&gt;                        {&lt;br/&gt;                            (activation as IPreApplicationStart).PreApplicationStart();&lt;br/&gt;                        }&lt;br/&gt;                        else if (target == ActivationMethodTarget.PostApplicationStart &amp;amp;&amp;amp; (activation is IPostApplicationStart))&lt;br/&gt;                        {&lt;br/&gt;                            (activation as IPostApplicationStart).PostApplicationStart();&lt;br/&gt;                        }&lt;br/&gt;                        else if (target == ActivationMethodTarget.PreApplicationEnd &amp;amp;&amp;amp; (activation is IPreApplicationEnd))&lt;br/&gt;                        {&lt;br/&gt;                            (activation as IPreApplicationEnd).PreApplicationEnd();&lt;br/&gt;                        }&lt;br/&gt;                    }&lt;br/&gt;                }&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;.NET 4.0版本新增了一个 &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.preapplicationstartmethodattribute.aspx" target="_blank"&gt;PreApplicationStartMethodAttribute&lt;/a&gt; 类只提供了一个开始的前触发支持，那怎么实现开始后触发和结束前触发呢？.Net4.0中提供了一个叫DynamicModuleUtility的类（位于Microsoft.Web.Infrastructure.dll程序集），里面只有一个方法RegisterModule(Type moduleType)，利用它可以动态的添加HttpModule。WebActivator的作者就是巧妙的利用了动态注册HttpModule。在第一个处理触发事件的HttpModule初始化时触发PostApplicationStart，最后一个HttpModule销毁时触发PreApplicationEnd，核心原理就这么两点，比较简单，KudyStudio.Web.Activating里的源码并没有作优化，因为在应用程序周期只触发一次各个事件，没必要刻意的去代码加载速度什么的。&lt;span style="color: #ff0000;"&gt;另外提醒一下，WebActivator1.5版本里的触发顺序只在每个独立程序集有效（不知道是不是作者故意的），KudyStudio.Web.Activating的触发顺序是在整个应用程序的全部程序集都有效的（有效是指排序的范围），感兴趣的朋友请下载源码分析。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&amp;nbsp;下载&lt;a href="http://files.cnblogs.com/kudy/KudyStudio.Web.Activating.rar"&gt;KudyStudio.Web.Activating.rar&lt;/a&gt;（.Net4.0）&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011121520305856.png" alt="" /&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&amp;nbsp;在此再附上测试实例说明吧，ActivatingWeb网站项目中ActivatingTest.cs里写了触发函数的实现与注册，Global.asax是用于辅助测试的。运行网站的结果如下：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011121520344178.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;所有触发函数都按指定的顺序执行了，打开Web.config后点击保存，查看网站根目录下的ActivatingTest.txt内容为：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011121520363595.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;可以看到PreApplicationEnd触发函数也正常的按顺序执行了。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;文章到此结束了，如果本文对你有帮助请&lt;span style="color: #ff0000;"&gt;点击推荐&lt;/span&gt;表示支持，谢谢，转载时请务必写明出处。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/kudy/aggbug/2289353.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kudy/archive/2011/12/15/KudyStudio_Web_Activating.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/kudy/archive/2011/12/05/2276995.html</id><title type="text">利用Nginx实现最简单的防盗链</title><summary type="text">一、文件的防盗链：location ~* \.(gif|jpg|png|swf|flv)$ {valid_referers none blocked www.kudystudio.com kudystudio.com;if ($invalid_referer) {rewrite ^/ http://www.kudystudio.com/403.html;#return 403;}}第一行：gif|jpg|png|swf|flv 表示对gif、jpg、png、swf、flv后缀的文件实行防盗链第二行： 表示对www.kudystudio.com kudystudio.com这2个来路进行判断if</summary><published>2011-12-05T11:54:00Z</published><updated>2011-12-05T11:54:00Z</updated><author><name>Kudy</name><uri>http://www.cnblogs.com/kudy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kudy/archive/2011/12/05/2276995.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kudy/archive/2011/12/05/2276995.html"/><content type="html">&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;一、文件的防盗链：&lt;/p&gt;&lt;p&gt;location ~* \.(gif|jpg|png|swf|flv)$ {&lt;br /&gt;&amp;nbsp;valid_referers none blocked &lt;a href="http://www.kudystudio.com/"&gt;www.kudystudio.com&lt;/a&gt; kudystudio.com;&lt;br /&gt;&amp;nbsp;if ($invalid_referer) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;rewrite ^/ &lt;a href="http://www.kudystudio.com/403.html"&gt;http://www.kudystudio.com/403.html&lt;/a&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;#return 403;&lt;br /&gt;&amp;nbsp;}&lt;br /&gt;}&lt;/p&gt;&lt;p&gt;第一行：gif|jpg|png|swf|flv 表示对gif、jpg、png、swf、flv后缀的文件实行防盗链&lt;br /&gt;第二行： 表示对&lt;a href="http://www.kudystudio.com/"&gt;www.kudystudio.com&lt;/a&gt; kudystudio.com这2个来路进行判断&lt;br /&gt;if{}里面内容的意思是，如果来路不是指定来路就跳转到&lt;a href="http://www.kudystudio.com/403.html"&gt;http://www.kudystudio.com/403.html&lt;/a&gt;页面，当然直接返回403也是可以的。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;二、目录的防盗链：&lt;/p&gt;&lt;p&gt;location /images/ {&lt;br /&gt;&amp;nbsp;alias /data/images/;&lt;br /&gt;&amp;nbsp;valid_referers none blocked server_names *.kudystudio.com kudystudio.com;&lt;br /&gt;&amp;nbsp;if ($invalid_referer) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;return 403;&lt;br /&gt;&amp;nbsp;}&lt;br /&gt;}&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;a href="http://nginx.org/en/download.html"&gt;下载nginx1.0&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/kudy/aggbug/2276995.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kudy/archive/2011/12/05/2276995.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/kudy/archive/2011/12/03/2274945.html</id><title type="text">10分钟采集凡客最新的省、市、区、邮政编码和电话区号（附源码）</title><summary type="text">最近的开发的项目需要用到省、市、区数据，因为要开发的项目也是电子商务网站，在参考凡客的用户体验时，发现它连深圳最新分离出来的光明新区都有了，拍拍网都没有更新数据，看来凡客在数据更新方面还是挺负责的，所以了解了一下它的数据格式，然后花了点时间写了个小程序来抽取最新的省、市、区、邮政编码和电话区号，邮政编码和电话区号是在用户选择数据后推荐给用户选择的，免得用户再花时间去查，如下界面：下载程序源码一共有三个地址是返回数据的： private string GetCityDataUrl(string province) { string url =...</summary><published>2011-12-03T12:48:00Z</published><updated>2011-12-03T12:48:00Z</updated><author><name>Kudy</name><uri>http://www.cnblogs.com/kudy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kudy/archive/2011/12/03/2274945.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kudy/archive/2011/12/03/2274945.html"/><content type="html">&lt;p&gt;最近的开发的项目需要用到省、市、区数据，因为要开发的项目也是电子商务网站，在参考凡客的用户体验时，发现它连深圳最新分离出来的光明新区都有了，拍拍网都没有更新数据，看来凡客在数据更新方面还是挺负责的，所以了解了一下它的数据格式，然后花了点时间写了个小程序来抽取最新的省、市、区、邮政编码和电话区号，邮政编码和电话区号是在用户选择数据后推荐给用户选择的，免得用户再花时间去查，如下界面：&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;a href="http://files.cnblogs.com/kudy/GetVanclData.rar"&gt;下载程序源码&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011120320340887.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;一共有三个地址是返回数据的：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;        private string GetCityDataUrl(string province)&lt;br/&gt;        {&lt;br/&gt;            string url = "http://my.vancl.com/DeliveryAddress/GetCityData?povinceId={0}&amp;amp;r={1}";&lt;br/&gt;&lt;br/&gt;            return string.Format(url, JScriptUtil.Escape(province), GetRandom());&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        private string GetDistrictDataUrl(string province, string city)&lt;br/&gt;        {&lt;br/&gt;            string url = "http://my.vancl.com/DeliveryAddress/GetAreaData?cityId={0}&amp;amp;povinceId={1}&amp;amp;r={2}";&lt;br/&gt;&lt;br/&gt;            return string.Format(url, JScriptUtil.Escape(city), JScriptUtil.Escape(province), GetRandom());&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        private string GetPostCodeUrl(string province, string city, string district)&lt;br/&gt;        {&lt;br/&gt;            string url = "http://my.vancl.com/DeliveryAddress/GetPostalCode?povince={0}&amp;amp;city={1}&amp;amp;area={2}&amp;amp;r={3}";&lt;br/&gt;&lt;br/&gt;            return string.Format(url, Utils.UrlEncode(province), Utils.UrlEncode(city), Utils.UrlEncode(district), GetRandom());&lt;br/&gt;        }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;核心函数：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;        // 抽取凡客数据&lt;br/&gt;        private void DoGetVanclData()&lt;br/&gt;        {&lt;br/&gt;            string[] provinces = Util.Provinces.Split('|');&lt;br/&gt;            for (int i = 0; i &amp;lt; provinces.Length; i++)&lt;br/&gt;            {&lt;br/&gt;                string theP = provinces[i].Trim();&lt;br/&gt;&lt;br/&gt;                this.Invoke(new MethodInvoker(() =&amp;gt;&lt;br/&gt;                {&lt;br/&gt;                    this.label1.Text = theP + "...";&lt;br/&gt;                }));&lt;br/&gt;&lt;br/&gt;                // 增加省份&lt;br/&gt;                int pid = GetNewId("Province");&lt;br/&gt;                this.Invoke(new MethodInvoker(() =&amp;gt;&lt;br/&gt;                {&lt;br/&gt;                    if (pid == 1)&lt;br/&gt;                        this.textBox1.Text += "insert into [Db_MoMoMate].[dbo].[Province]([Id],[Name])\r\nSELECT " + pid.ToString() + ", '" + theP + "'\r\n";&lt;br/&gt;                    else&lt;br/&gt;                        this.textBox1.Text += "union\r\nSELECT " + pid.ToString() + ", '" + theP + "'\r\n";&lt;br/&gt;                }));&lt;br/&gt;&lt;br/&gt;                // 获取城市数据&lt;br/&gt;                string[] cityData = WebRequestHelper.HttpGet(GetCityDataUrl(theP), "", Encoding.UTF8).Split('$');&lt;br/&gt;                Thread.Sleep(10);&lt;br/&gt;&lt;br/&gt;                foreach (string city in cityData)&lt;br/&gt;                {&lt;br/&gt;                    string theC = city.Split(',')[1].Trim();&lt;br/&gt;&lt;br/&gt;                    // 城市id&lt;br/&gt;                    int cid = GetNewId("City");&lt;br/&gt;                    string AreaCode = null;&lt;br/&gt;&lt;br/&gt;                    // 获取区数据&lt;br/&gt;                    string[] districtData = WebRequestHelper.HttpGet(GetDistrictDataUrl(theP, theC), "", Encoding.UTF8).Split('$');&lt;br/&gt;                    Thread.Sleep(10);&lt;br/&gt;&lt;br/&gt;                    foreach (string district in districtData)&lt;br/&gt;                    {&lt;br/&gt;                        string theD = district.Split(',')[1].Trim();&lt;br/&gt;&lt;br/&gt;                        // 区id&lt;br/&gt;                        int did = GetNewId("District");&lt;br/&gt;                        string[] postData = WebRequestHelper.HttpGet(GetPostCodeUrl(theP, theC, theD), "", Encoding.UTF8).Split('$');&lt;br/&gt;&lt;br/&gt;                        if (AreaCode == null)&lt;br/&gt;                        {&lt;br/&gt;                            AreaCode = postData[4];&lt;br/&gt;                        }&lt;br/&gt;&lt;br/&gt;                        string postCode = postData[3];&lt;br/&gt;&lt;br/&gt;                        Thread.Sleep(10);&lt;br/&gt;                        // 增加区&lt;br/&gt;                        this.Invoke(new MethodInvoker(() =&amp;gt;&lt;br/&gt;                        {&lt;br/&gt;                            if (did == 1)&lt;br/&gt;                                this.textBox3.Text += "insert into [Db_MoMoMate].[dbo].[District]([Id],[CityId],[Name],[PostCode])\r\nSELECT " + did.ToString() + ", " + cid.ToString() + ", '" + theD + "', '" + postCode + "'\r\n";&lt;br/&gt;                            else&lt;br/&gt;                                this.textBox3.Text += "union\r\nSELECT " + did.ToString() + ", " + cid.ToString() + ", '" + theD + "', '" + postCode + "'\r\n";&lt;br/&gt;                        }));&lt;br/&gt;                    }&lt;br/&gt;&lt;br/&gt;                    // 增加城市&lt;br/&gt;                    this.Invoke(new MethodInvoker(() =&amp;gt;&lt;br/&gt;                    {&lt;br/&gt;                        if (cid == 1)&lt;br/&gt;                            this.textBox2.Text += "insert into [Db_MoMoMate].[dbo].[City]([Id],[ProvinceId],[Name],[AreaCode])\r\nSELECT " + cid.ToString() + ", " + pid.ToString() + ", '" + theC + "', '" + AreaCode + "'\r\n";&lt;br/&gt;                        else&lt;br/&gt;                            this.textBox2.Text += "union\r\nSELECT " + cid.ToString() + ", " + pid.ToString() + ", '" + theC + "', '" + AreaCode + "'\r\n";&lt;br/&gt;                    }));&lt;br/&gt;                }&lt;br/&gt;&lt;br/&gt;                this.Invoke(new MethodInvoker(() =&amp;gt;&lt;br/&gt;                {&lt;br/&gt;                    if (i == provinces.Length - 1)&lt;br/&gt;                    {&lt;br/&gt;                        this.label1.Text = "done";&lt;br/&gt;                        this.button1.Enabled = true;&lt;br/&gt;                    }&lt;br/&gt;                }));&lt;br/&gt;            }&lt;br/&gt;        }&lt;br/&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;最终运行效果如下：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011120320374438.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;本公司项目中还需要大学数据，那是09年开发大学SNS网站的老数据了，把数据都放进数据库：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011120320395834.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011120320402425.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;需要抽取省、市、区数据的朋友可以下载程序源码来使用：&lt;a href="http://files.cnblogs.com/kudy/GetVanclData.rar"&gt;点击下载&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/kudy/aggbug/2274945.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kudy/archive/2011/12/03/2274945.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/kudy/archive/2011/11/27/2263752.html</id><title type="text">【分享】通用强大的主数据管理系统（最终分享版本）架构分析及源码下载</title><summary type="text">之前已发个文章分享刚完成的版本（http://www.cnblogs.com/kudy/archive/2011/11/07/2237802.html），这个是最近对MSH重构后的调整版本，修正了之前存在的几个小bug，也是最后分享出来给大家学习的版本。特别说明：源码分享出来主要不是让大家直接用，而是从中学习某方面值得你学习的，另一个目的是让大家对MSH进一步的了解，因为此系统使用了它提供数据访问。 主数据管理系统（Master Data Management System），本人开发它的目的是用来管理/整合公司内部所有子系统，包括用户、角色、权限（权限管理，授权与验权基础实现），同域名...</summary><published>2011-11-27T14:50:00Z</published><updated>2011-11-27T14:50:00Z</updated><author><name>Kudy</name><uri>http://www.cnblogs.com/kudy/</uri></author><link rel="alternate" href="http://www.cnblogs.com/kudy/archive/2011/11/27/2263752.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/kudy/archive/2011/11/27/2263752.html"/><content type="html">&lt;p&gt;之前已发个文章分享刚完成的版本（&lt;a href="http://www.cnblogs.com/kudy/archive/2011/11/07/2237802.html"&gt;http://www.cnblogs.com/kudy/archive/2011/11/07/2237802.html&lt;/a&gt;），这个是最近对MSH重构后的调整版本，修正了之前存在的几个小bug，也是最后分享出来给大家学习的版本。特别说明：&lt;strong&gt;源码分享出来主要不是让大家直接用，而是从中学习某方面值得你学习的，另一个目的是让大家对&lt;a href="http://www.cnblogs.com/kudy/archive/2011/11/23/2258245.html" target="_blank"&gt;MSH&lt;/a&gt;进一步的了解，因为此系统使用了它提供数据访问。&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;主数据管理系统（Master Data Management System），本人开发它的目的是用来管理/整合公司内部所有子系统，包括用户、角色、权限（权限管理，授权与验权基础实现），同域名情况的单点登录，等等主要数据的管理。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;a href="http://files.cnblogs.com/kudy/Mdms_Shared_Final.rar"&gt;点击下载最终分享版&lt;/a&gt; （&lt;strong&gt;VS2008/VS2010、.Net 3.5&lt;/strong&gt;）&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;下载后必须要了解的：&lt;/p&gt;&lt;p&gt;&lt;span style="color: #ff6600;"&gt;一、数据库创建与初始化数据&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #ff6600;"&gt;在SQL server 2005/2008 下新建名为　Db_Mdms　的数据库，&lt;/span&gt;&lt;span style="color: #ff6600;"&gt;然后&lt;span style="color: #800000;"&gt;&lt;strong&gt;按顺序&lt;/strong&gt;&lt;/span&gt;执行目录 Documents\Mdms.Documents\DB 1.0\Scripts 里的sql&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #ff6600;"&gt;1_tables.sql&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #ff6600;"&gt;2_functions.sql&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #ff6600;"&gt;3_stored-procedures.sql&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #ff6600;"&gt;4_init_data.sql&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;span style="color: #ff6600;"&gt;二、修改数据库连接信息&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #ff6600;"&gt;在目录 build\Mdms.Msh 里修改 Mdms.MSH.exe.config 的配置节点 Mdms.Db_ConnectionString 的值为你自己的数据库连接&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #ff6600;"&gt;三、&lt;/span&gt;&lt;span style="color: #ff6600;"&gt;在vs2010中运行Web项目 Mdms.Web 或右键选择 default.aspx 页面点击在浏览器中浏览，然后打开目录 build\Mdms.MSH，双击Mdms.MSH.exe运行之&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;span style="color: #ff6600;"&gt;这时，你可以用默认用户/密码 admin/admin888 登录系统了&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;在线demo:&amp;nbsp; &lt;a href="http://mdms.kudystudio.com/" target="_blank"&gt;http://mdms.kudystudio.com/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;用户/密码：test1/test1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; test2/test2&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; （注：同一用户在另一浏览器登录，另一用户在session失效后会被逼下线）&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;span style="color: #800000;"&gt;demo站放在一个香港的VPS主机上，配置比较低，速度慢也是正常的，主要也放自己的个人网站。&lt;/span&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011112520304270.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011112520330363.jpg" alt="" width="988" height="532" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011112520332640.jpg" alt="" width="986" height="520" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;下面对整个解决方案的项目进行简要说明。系统是多层架构+WCF服务+MTV表现层完成的；其中WCF服务使用了MSH来托管，当然你也可以自己另写程序来托管WCF服务；MTV表现层框架是本人写的一个使用习惯和MVC差不多的框架，功能比较简单，如果你想用MVC，转换也不麻烦，因为使用上都差不多。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;了解MSH请看这篇文章： &lt;a href="http://www.cnblogs.com/kudy/archive/2011/11/23/2258245.html" target="_blank"&gt;【MSH】一个轻量级但很实用的WCF模块服务框架+WCF模块服务托管程序MSH[开篇] &lt;/a&gt;&lt;/p&gt;&lt;p&gt;因为MTV框架还没完善，只在本人公司里使用，等功能完善了，基本扩展性也完成了会另写文章对它进行介绍。&lt;/p&gt;&lt;p&gt;在另一文章里还专门对此系统的权限管理进行了解说： &lt;a href="http://www.cnblogs.com/kudy/archive/2011/11/10/2243810.html" target="_blank"&gt;如何给多个子系统设计一个简单通用的权限管理方案？&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;另外还使用了本人写的一个js窗口插件： &lt;a href="http://www.cnblogs.com/kudy/archive/2011/11/12/2246118.html" target="_blank"&gt;【jBox】2.3正式版 多功能jQuery对话框插件下载及常见使用问题解答 &lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011112718185087.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;1.项目 Core/&lt;strong&gt;Mdms.Utility&lt;/strong&gt; 是整个项目的公共功能库。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;2.项目 Core/&lt;strong&gt;Mdms.Model&lt;/strong&gt; 是整个项目要使用的数据模型类库，其中DbModels里放的是与数据库的表一一对应的数据模型，其它的是为业务层需要写的扩展性模型。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011112520112186.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;3.Msh/Db 下的三个项目相信大家都很容易理解，&lt;strong&gt;Mdms.Data&lt;/strong&gt;为数据访问库，根据配置创建数据实现对象并返回接口，&lt;strong&gt;Mdms.IDataProvider&lt;/strong&gt;为数据接口定义库，&lt;strong&gt;Mdms.SqlServerProvider&lt;/strong&gt;为SqlServer的数据接口实现库，是提供给Msh/Modules 下的模块服务使用的，因为采用上用WCF来提供数据访问。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011112520145315.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;4.项目 Msh/&lt;strong&gt;Mdms.Msh&lt;/strong&gt; 是使用MSH而写的基本功能库，方便Msh/Modules下的模块服务开发。而&lt;strong&gt;Mdms.BusinessBase&lt;/strong&gt;项目是所有子系统都要使用的业务基础，里面主要实现了同域名下的单点登录，还有权限验证需要的基本功能使用。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011112520253410.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;5.Web 目录下的三个项目主要就是业务的封装和表现层的东东了。项目&lt;strong&gt;Mdms.Business&lt;/strong&gt;是系统的业务封装，项目&lt;strong&gt;Mdms.Web&lt;/strong&gt;是网站，项目&lt;strong&gt;Mdms.Web.Mtv&lt;/strong&gt;是使用MTV框架需要的模块类与过虑器（和MVC里的控制器和过虑器相对应）。&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2011/100869/2011112520241571.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;a href="http://files.cnblogs.com/kudy/Mdms_Shared_Final.rar"&gt;http://files.cnblogs.com/kudy/Mdms_Shared_Final.rar&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;简介完毕，希望能给大家带来帮助：）&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/kudy/aggbug/2263752.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/kudy/archive/2011/11/27/2263752.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
