2023年2月

Sqlite数据库,在很多场合已经用得比较多,由于我的代码生成工具的需要,需要把Sqlite的表、字段、视图等信息获取出来,以便实现各种数据库快速生成项目工程的操作。这里就需要利用C#获取Sqlite数据库的元数据了,和其他数据库一样。

为了获取Sqlite的数据库对象数据,我做了一个测试的例子来获取他的相关信息,其实它的元数据还是和Access的操作方式很接近。首先我们先通过Sqlite的数据库管理工具或者Visual Studio来打开创建一些表,如下所示。

首先我们先来看看通过C#代码获取到数据库对象的操作界面,如下所示。

获取表的元数据界面效果如下所示,视图和这个也查不多,很有意思的一点,就是它把创建的脚本的显示出来了,呵呵。

获取的表字段信息效果如下所示。

有了这些数据,我就很方便在我的代码生成工具Database2Sharp里面实现代码生成操作了。

现在我们来看看以上实现的后台代码是如何的,来了解Sqlite的数据库获取元数据的操作。

        string connectionString = "";

        public Form1()
        {
            InitializeComponent();

            connectionString = string.Format(@"Data Source={0}\OrderWater.db;Version=3;", Application.StartupPath);
        }

        private void btnGetSchema_Click(object sender, EventArgs e)
        {
            using (SQLiteConnection conn = new SQLiteConnection(connectionString))
            {
                conn.Open();
                DataTable schemaTable = conn.GetSchema("TABLES");
                this.dataGridView1.DataSource = schemaTable;
            }
        }

获取表字段的操作代码如下所示。

        private void btnGetColumns_Click(object sender, EventArgs e)
        {
            using (SQLiteConnection conn = new SQLiteConnection(connectionString))
            {
                conn.Open();
                DataTable table = conn.GetSchema("TABLES");
                if (table != null && table.Rows.Count > 0)
                {
                    string tableName = table.Rows[0]["TABLE_NAME"].ToString();

                    DataTable schemaTable = GetReaderSchema(tableName, conn);
                    this.dataGridView1.DataSource = schemaTable;
                }
            }
        }

        private DataTable GetReaderSchema(string tableName, SQLiteConnection connection)
        {
            DataTable schemaTable = null;
            IDbCommand cmd = new SQLiteCommand();
            cmd.CommandText = string.Format("select * from [{0}]", tableName);
            cmd.Connection = connection;

            using (IDataReader reader = cmd.ExecuteReader(CommandBehavior.KeyInfo | CommandBehavior.SchemaOnly))
            {
                schemaTable = reader.GetSchemaTable();
            }
            return schemaTable;
        }

为了实现和我代码生成工具中的数据库字段信息绑定,需要通过获取设置Sqlite的属性为对应的ColumnInfo对象,如下所示。

            using (SQLiteConnection conn = new SQLiteConnection(ConnectString))
            {
                conn.Open();
                DataTable schemaTable = GetReaderSchema(tableName, conn);

                foreach (DataRow dr in schemaTable.Rows)
                {
                    ColumnInfo info = new ColumnInfo();
                    info.Name = new NameElement(dr["ColumnName"].ToString());
                    info.Ordinal = Convert.ToInt32(dr["ColumnOrdinal"].ToString());
                    info.AllowDBNull = (bool)dr["AllowDBNull"];
                    info.MaxLength = Convert.ToInt32(dr["ColumnSize"].ToString());
                    info.DataTypeId = Convert.ToInt32(dr["ProviderType"].ToString());
                    info.DataType = dr["DataTypeName"].ToString().Trim();
                    info.AutoIncrement = (bool)dr["IsAutoIncrement"];
                    info.IsPrimaryKey = (bool)dr["IsKey"];
                    info.Unique = (bool)dr["IsUnique"];
                    info.IsReadOnly = (bool)dr["IsReadOnly"];
                    string netType = dr["DataType"].ToString();

                    list.Add(info.Name.Name.ToString(), info);
                }

                conn.Close();
            }

代码生成工具中,这些数据库的元数据实体类信息是可以提供访问的,方便我们定制代码生成工具的模板,代码生成工具关于这些数据库对象的帮助如下所示。

这样,在代码生成工具中,就可以利用Sqlite的数据库对象数据,来生成和Oracle数据库、SqlServer数据库、Access数据库、MySql等数据库一样的项目工程代码了,获取甚至可以在自定义的模板代码模块中,添加自己的处理逻辑。

快速生成的代码如下所示。

本文通过介绍获取Sqlite的数据库元数据库,并在代码生成工具中的应用为例,给大家提供一个使用元数据进行程序开发的一个思路,希望大家可以同这种方式实现更多自定义模板或者逻辑的引用。

天下虽大同,一直在努力,孜孜不倦,终有所获。

我的WCF开发框架推出很久了,一直有不少的朋友支持及提供良好的完善意见,随着利用这种基于Winform界面的WCF开发框架开发了不同类型的项目,各种WCF对象的调用及处理逐渐稳定及统一化,因此是时候让我的开发伴侣(代码生成工具Database2Sharp)来做更多更有技术性的工作了---提供基于我的WCF开发框架模式创建的项目工程及调用WCF的Winform界面处理代码。这样在WCF快速开发框架中,有了更强更高效率的支持,整个项目的开发,就更加是水到渠成,闲庭散步了。

因此,代码生成工具生成框架代码,结合我的WCF开发框架上基础项目代码,已经能覆盖的范围达到了90%以上了。

有了这一切,无论是开发传统的Winform项目还是基于C/S的WCF开发项目,做起来就是非常惬意、高效很多。

基于WCF框架开发新的项目,其实和我的Winform开发框架一样,有很多东西可以重用,包括主界面布局、登录、闪屏、界面继承组件、通用字典、权限管理、图片附件管理、报表管理等等,这样,在基于已有东西的基础上,只需要扩展自己的业务模块即可。


利用代码生成工具,可以生成基于Winform开发框架和WCF开发框架的项目业务代码,如下所示。

下一步选定数据库和表后,就进入项目生成的界面了,这里可以指定是否生成基于WCF的服务项目框架。

一般来说,为了方便客户部署需要,我们推荐使用VS2010来开发基于.NET4.0的项目,因为.net3.5的项目,客户端需要安装300多M的环境框架,而基于4.0的,只需要40多M即可,方便很多。因此本代码生成工具生成的WCF项目,所有工程,包括实体类(Contract)、数据接口层、数据访问层、业务逻辑层、WCF服务器接口层,均生成基于VS2010项目格式, .NET4.0的项目工程。

当然,如果不勾选,默认生成的是Winform项目代码,是基于VS2008的.NET2.0 的项目工程。

最后生成的WCF项目代码如下所示,目录文件如下所示。

完成后,我们打开项目工程,系统提示IIS创建一个基于Asp.NET4.0 的Web项目,这个项目就是MisService项目了,其中可以放置我们的各种WCF服务接口及实现。代码生成的WCF项目代码已经是继承关系弄好的,并且在基类实现了普通的增删改查等基本接口,扩展的只需要增加自己的业务逻辑即可。

除了以上底层的项目及代码外,代码生成工具还为你考虑如何在Winform界面中调用WCF服务的逻辑代码,基本的处理如下所示。

生成的代码如下所示,基于列表显示的和数据编辑处理的界面后台逻辑处理代码。

最后呈上基于这种模式,我的WCF开发框架界面效果,它是有效利用Winform界面的丰富体验,WCF分布式数据技术,发挥两种技术有点的WCF开发框架。


俗话说,一个好汉十个帮,众人拾柴火焰高等都说明一个道理,有更多的资源,更丰富的积累,都是助你走向成功,走向顶峰的推动力。

本篇的公用类库的介绍主题是程序开发中多线程操作环境中,常用到的线程安全的各类同步集合、字典等对象,这些辅助类通过封装及继承关系,获得更加丰富完善的集合类,并且增加了线程锁,实现多线程访问的集合类。本篇随笔介绍包含有有序字典集合、同步字典集合、有序同步字典集合、同步列表、同步先进先出队列等对象。

本篇继续继续整理优化已有的共用类库,并继续发表随笔介绍公用类库的接口方法以及详细使用操作,力求给自己继续优化,积攒更丰富的公用类库资源,加深了解的同时,也给大家展现公用类库好的方面。

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(9)----各种常用辅助类
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(8)----非对称加密、BASE64加密、MD5等常用加密处理

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(7)-----声音播放、硬件信息、键盘模拟及钩子、鼠标模拟及钩子等设备相关
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(6)----全屏截图、图标获取、图片打印、页面预览截屏、图片复杂操作等

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(5)----热键、多线程、窗体动画冻结等窗体操作

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(4)----CSV、Excel、INI文件、独立存储等文件相关

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(3)----数据库相关操作

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(2)----常用操作

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(1)----开篇总结

1、有序的字典集合 OrderedDictionary。

实现效果

1) 本辅助类主要是用来方便实现有序的字典集合操作。 一个有序的字典是一个集合类,它里面的项目可以通过其索引或他们的键进行操作。。
2) 有序集合对象,特点是查找非常高效率,并且提供了强类型的数据操作,不过由于其需要额外在列表中存储数据,因此尽量减少插入或者删除集合对象。
3) 有序的字典集合,虽然存在一些缺点,但是提供了一个非常灵活和用户友好数据结构,允许通过键值或索引进行访问。

实现代码

1)辅助类提供的方法接口如下所示:

/// <summary>
///判断字典<see cref="System.Collections.Generic.Dictionary{TKey, TValue}"></see>是否包含指定的值。
/// </summary>
/// <param name="value">待判断的值,如果值为引用类型,则可以为null</param>
/// <returns>
///如果字典包含项目,则返回true,否则为false。
/// </returns>
public virtual bool ContainsValue(TValue value)

/// <summary>
///判断字典是否包含指定键的元素
/// </summary>
/// <param name="key">在字典中查找的键.</param>
/// <returns>
///如果字典中包含指定键的元素,返回true,否则为false
/// </returns>
/// <exception cref="System.ArgumentNullException">键为空</exception>
public virtual bool ContainsKey(TKey key)

/// <summary>
///在字典中添加一个元素,根据提供的键和值
/// </summary>
/// <param name="key">作为待添加元素的键</param>
/// <param name="value">作为待添加元素的值.</param>
/// <exception cref="System.NotSupportedException">字典对象为只读</exception>
/// <exception cref="System.ArgumentException">含有相同键的元素已经存在字典中</exception>
/// <exception cref="System.ArgumentNullException">键为空.</exception>
public virtual void Add(TKey key, TValue value)

/// <summary>
///在指定的索引插入元素
/// </summary>
/// <param name="index">插入位置,从零开始的索引</param>
/// <param name="key">作为待插入元素的键</param>
/// <param name="value">作为待插入元素的值</param>
/// <exception cref="T:System.NotSupportedException">集合为只读</exception>
/// <exception cref="T:System.ArgumentOutOfRangeException">指定索引在<see cref="T:System.Collections.Generic.IList`1"></see>中为无效索引.</exception>
public void Insert(int index, TKey key, TValue value)

/// <summary>
///获取指定键的元素索引
/// </summary>
/// <param name="key">待查找的键</param>
/// <returns>
///如果列表中发现则为项目的索引,否则为-1。
/// </returns>
public int IndexOf(TKey key)

/// <summary>
///获取指定键的元素索引
/// </summary>
/// <param name="value">待查找的键</param>
/// <returns>
///如果列表中发现则为项目的索引,否则为-1。
/// </returns>
public int IndexOf(TValue value)

/// <summary>
///获取或设置与指定键的值。
/// </summary>
public virtual TValue this[TKey key]

/// <summary>获取或设置指定索引相关联的值</summary>
/// <returns>返回指定索引中关联的值, 如果指定的索引为无效,获取或设置操作将抛出<see cref="ArgumentOutOfRangeException"></see>
/// </returns>
/// <param name="index">获取或设置值的索引</param>
/// <exception cref="ArgumentOutOfRangeException">索引大于集合数量或者小于0</exception>
public virtual TValue this[int index]

/// <summary>
///复制集合元素到数组中, 以数组的索引开始.
/// </summary>
/// <param name="array">一维数组<see cref="System.Array"></see>,它是从集合中复制的目标。数组对象必须是从零开始的索引。</param>
/// <param name="arrayIndex">Array中的从零开始的索引,位于复制开始。</param>
/// <exception cref="System.ArgumentOutOfRangeException">arrayIndex 小于0</exception>
/// <exception cref="System.ArgumentNullException">array 为null</exception>
/// <exception cref="System.ArgumentException">
///数组为多维;或arrayIndex等于或大于数组的长度;
///或源集合中元素的数量大于arrayIndex到目标数组结束间可用空间。
///或者TKey的类型不能自动转换为目标数组的类型。</exception>
public virtual void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)

/// <summary>
///创建一个新的对象,它是当前实例的一个副本
/// </summary>
/// <returns>
///一个新的对象,此实例的一个副本。
/// </returns>
public OrderedDictionary<TKey, TValue> Clone()

2)辅助类OrderedDictionary的使用例子代码如下所示,由于OrderedDictionary在检索的时候效率很高,而且可以通过索引和键进行定位,提供了较好的操作性和方便性。
输出结果如下所示,我们看到,他们虽然可以通过键和索引进行访问,但是他们的顺序不会发生变化。

OrderedDictionary<string, string> syncDict = new OrderedDictionary<string, string>();
syncDict.Add("A", "testA");
syncDict.Add("C", "testC");
syncDict.Add("B", "TestB");

//通过键访问
StringBuilder sb = new StringBuilder();
foreach (string key in syncDict.Keys)
{
sb.AppendFormat("{0}:{1}\r\n", key, syncDict[key]);
}
sb.AppendLine();

//通过索引访问
for (int i = 0; i < syncDict.Keys.Count; i++)
{
sb.AppendFormat("{0}:{1}\r\n", i, syncDict[i]);
}
MessageUtil.ShowTips(sb.ToString());

3)  辅助类OrderedDictionary和.NET框架内置SortedDictionary不同,他虽然都支持泛型类型,不过键和索引方式访问,后者只是对键进行排序的字典类,并未提供以索引方式进行取值的。

//框架内置的排序字典
SortedDictionary<string, string> sortDict = new SortedDictionary<string, string>();
sortDict.Add("A", "testA");
sortDict.Add("C", "testC");
sortDict.Add("B", "TestB");

sb = new StringBuilder();
foreach (string key in sortDict.Keys)
{
sb.AppendFormat("{0}:{1}\r\n", key, sortDict[key]);
}
MessageUtil.ShowTips(sb.ToString());

而SortedDictionary例子的输出结果如下所示,从中我们可以看到,遍历键的时候,它们已经经过了字母从大到小进行排序了。

2、同步的字典集合 SyncDictionary。

实现效果

1) 现同步的字典集合操作。 一个同步的字典提供一个线程安全的字典集合。
2) 同步字典对象,提供了多线程之间线程安全的访问机制,使你不必担心发送多线程之间的添加、移除、访问等的冲突,放心使用。
3) SyncDictionary类继承了CDictionary类,CDictionary继承了框架的Dictionary类,CDictionary并实现了一些克隆及序列化的接口。SyncDictionary类具有Dictionary类的一切特点,另外他还具备线程安全的特点。

实现代码

1)辅助类提供的方法接口如下所示:

/// <summary>
///获取指定键的关联值
/// </summary>
/// <param name="key">字典键</param>
/// <param name="value">当此方法返回值时,如果找到该键,便会返回与指定的键相关联的值;否则,则会返回 value 参数的类型默认值。该参数未经初始化即被传递。</param>
/// <returns>如果字典对象包含具有指定键的元素,则为 true;否则为false.</returns>
public new bool TryGetValue(TKey key, out TValue value)

/// <summary>获取或设置指定键的值</summary>
/// <returns>与指定键关联的值。如果没有找到指定键,KeyNotFoundException将抛出,操作创建一个有指定键的新元素。</returns>
/// <param name="key">设定值的键</param>
/// <exception cref="System.ArgumentNullException">键位空</exception>
/// <exception cref="System.Collections.Generic.KeyNotFoundException">属性检索和键在集合不存在。</exception>
public new TValue this[TKey key]

/// <summary>获取字典对象的键集合</summary>
public new KeyCollection Keys

/// <summary>获取字典中值的对象集合</summary>
public new ValueCollection Values

/// <summary>获取<see cref="System.Collections.Generic.IEqualityComparer{TKey}"></see>对象,该对象用来比较字典表键的相等</summary>
/// <returns>对象<see cref="System.Collections.Generic.IEqualityComparer{TKey}"></see>通用接口,用来判断当前对象<see cref="T:System.Collections.Generic.Dictionary`2"></see>的相等性,
///并提供键的哈希值.</returns>
public new IEqualityComparer<TKey> Comparer

/// <summary>
///获取字典集合中包含键值对的数量
/// </summary>
/// <value></value>
/// <returns>字典集合中所含元素的数目</returns>
public new virtual int Count

/// <summary>在集合中移除指定键的元素</summary>
/// <returns>如果元素被移除返回true,否则为false。如果原始集合中没有发现指定键的元素,也返回false。</returns>
/// <param name="key">待移除元素的键</param>
/// <exception cref="System.ArgumentNullException">键为空</exception>
public new bool Remove(TKey key)

/// <summary>获取迭代结合的枚举器.</summary>
public new Enumerator GetEnumerator()

/// <summary>
///初始化SyncDictionary对象实例
/// </summary>
/// <param name="dictionary">字典对象</param>
public SyncDictionary(CDictionary<TKey, TValue> dictionary)

/// <summary>
///初始化SyncDictionary对象实例
/// </summary>
public SyncDictionary()

/// <summary>
///为字典表添加指定的键值
/// </summary>
/// <param name="key">待添加元素的键</param>
/// <param name="value">待添加元素的值. 该值可以是空引用类型.</param>
/// <exception cref="System.ArgumentException">一个具有相同键的元素已经存在于字典</exception>
/// <exception cref="System.ArgumentNullException">键为空</exception>
public new void Add(TKey key, TValue value)

/// <summary>
///获取一个值,指出对集合的存取是否同步(线程安全)
/// </summary>
/// <value>如果词典的访问是同步的(线程安全)则为True,否则为false。默认为false。</value>
public override bool IsSynchronized

/// <summary>
///从字典中移除所有的键值
/// </summary>
public new void Clear()

/// <summary>
///实现<see cref="System.Runtime.Serialization"></see>接口并返回需要序列化字典<see cref="System.Collections.Generic.Dictionary{TKey, TValue}"></see>实例的数据。
/// </summary>
/// <param name="info">一个 SerializationInfo 对象,它包含序列化Dictionary所需的信息。</param>
/// <param name="context">StreamingContext 结构,该结构包含与 Dictionary相关联的序列化流的源和目标。</param>
/// <exception cref="System.ArgumentNullException">info为空引用</exception>
[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
public override void GetObjectData(SerializationInfo info, StreamingContext context)

/// <summary>
///初始化SyncDictionary对象实例
/// </summary>
/// <param name="info"><see cref="System.Runtime.Serialization.SerializationInfo"></see>对象包含序列化<see cref="System.Collections.Generic.Dictionary{TKey, TValue}"></see>的必要信息。</param>
/// <param name="context">A<see cref="System.Runtime.Serialization.StreamingContext"></see>含有与序列化流<see cref="System.Collections.Generic.Dictionary{TKey, TValue}"></see>的源和目标的结构。</param>
internal SyncDictionary(SerializationInfo info, StreamingContext context): base(info, context)

/// <summary>
///把ICollection的元素复制到一个KeyValuePair类型的数组,在指定的阵列索引开始。
/// </summary>
/// <param name="array">一维数组类型KeyValuePair是从ICollection复制KeyValuePair元素的目标。该数组必须具有从零开始的索引。</param>
/// <param name="index">array中的从零开始的索引,位于复制开始</param>
public new void CopyTo(KeyValuePair<TKey, TValue>[] array, int index)

/// <summary>
///实现<see cref="System.Runtime.Serialization.ISerializable"></see>接口并抛出反序列化事件,当反序列化完成的时候。
/// </summary>
/// <param name="sender">反序列化事件的源对象</param>
/// <exception cref="T:System.Runtime.Serialization.SerializationException">在当前字典中关联的该对象为无效对象.</exception>
public override void OnDeserialization(object sender)

/// <summary>
///确定指定的键是否包含关键。
/// </summary>
/// <param name="key"></param>
/// <returns>
///如果包含指定的键返回True,否则false。
/// </returns>
public new bool ContainsKey(TKey key)

/// <summary>
///判断<see cref="System.Collections.Generic.Dictionary{TKey, TValue}"></see>是否包含指定的值
/// </summary>
/// <param name="value">在字典中待查找的值,如果值是引用类型则可以为null。</param>
/// <returns>
///如果<see cref="System.Collections.Generic.Dictionary{TKey, TValue}"></see>包含指定值的元素返回true,否则返回false.
/// </returns>
public new bool ContainsValue(TValue value)



2)本辅助类主要是用来方便实辅助类SyncDictionary的使用例子代码如下所示,由于SyncDictionary线程安全,非常适合在多线程的环境下进行操作,如Socket服务器处理、后台线程数据处理等环境下。

SyncDictionary<string, string> syncDict = new SyncDictionary<string, string>();
syncDict.Add("A", "testA");
syncDict.Add("C", "testC");
syncDict.Add("B", "TestB");

//通过键访问
StringBuilder sb = new StringBuilder();
foreach (string key in syncDict.Keys)
{
sb.AppendFormat("{0}:{1}\r\n", key, syncDict[key]);
}
sb.AppendLine();
MessageUtil.ShowTips(sb.ToString());

输出结果如下所示,我们看到,他们虽然可以通过键和索引进行访问,但是他们的顺序不会发生变化。

3) 另外它的线程安全,使得其多线程之间的操作也是非常安全、高效的。

SyncDictionary<string, string> syncDict = new SyncDictionary<string, string>();
private void btnSyncTest_Click(object sender, EventArgs e)
{
for (int i = 0; i < 5; i++)
{
Thread thread = new Thread(new ThreadStart(AddSyncDict));
thread.Start();
thread.Join();//等待线程完成才返回主线程
}

StringBuilder sb = new StringBuilder();
foreach (string key in syncDict.Keys)
{
sb.AppendFormat("Key:{0} Value:{1} \r\n", key, syncDict[key]);
}
MessageUtil.ShowTips(sb.ToString());
}

private void AddSyncDict()
{
string key = new Random().Next().ToString();
if (!syncDict.ContainsKey(key))
{
syncDict.Add(key, DateTime.Now.ToString());
}
Thread.Sleep(100);
}

多线程之间操作的运行效果如下所示

3、同步、有序的字典集合 SyncOrderedDictionary。

实现效果

1)本辅助类主要是用来方便实现同步、有序的字典集合操作。 一个同步的字典提供一个线程安全的字典集合;一个有序的字典是一个集合类,它里面的项目可以通过其索引或他们的键进行操作。。
2) 同步字典对象,提供了多线程之间线程安全的访问机制,使你不必担心发送多线程之间的添加、移除、访问等的冲突,放心使用。
3) 有序集合对象,特点是查找非常高效率,并且提供了强类型的数据操作,不过由于其需要额外在列表中存储数据,因此尽量减少插入或者删除集合对象。
4) 有序的字典集合,虽然存在一些缺点,但是提供了一个非常灵活和用户友好数据结构,允许通过键值或索引进行访问。
5) SyncOrderedDictionary类继承了OrderedDictionary类,具有OrderedDictionary类的一切特点,另外他还具备线程安全的特点。

实现代码

1)辅助类提供的方法接口如下所示:

接口综合了以上两种(同步、有序)字典类的特点,接口代码不在粘贴出来。

2)辅助类SyncOrderedDictionary的使用例子代码如下所示,由于SyncOrderedDictionary在检索的时候效率很高,而且可以通过索引和键进行定位,提供了较好的操作性和方便性。另外由于线程安全,非常适合在多线程的环境下进行操作,如Socket服务器处理、后台线程数据处理等环境下。

SyncOrderedDictionary<string, string> syncDict = new SyncOrderedDictionary<string, string>();
syncDict.Add("A", "testA");
syncDict.Add("C", "testC");
syncDict.Add("B", "TestB");

//通过键访问
StringBuilder sb = new StringBuilder();
foreach (string key in syncDict.Keys)
{
sb.AppendFormat("{0}:{1}\r\n", key, syncDict[key]);
}
sb.AppendLine();

//通过索引访问
for (int i = 0; i < syncDict.Keys.Count; i++)
{
sb.AppendFormat("{0}:{1}\r\n", i, syncDict[i]);
}
MessageUtil.ShowTips(sb.ToString());

输出结果如下所示,我们看到,他们虽然可以通过键和索引进行访问,但是他们的顺序不会发生变化。

4、同步的列表集合 SyncList。

实现效果

1) 本辅助类主要是用来方便实现同步列表集合操作。 一个同步的列表集合提供一个线程安全的列表集合;
2)同步字典对象,提供了多线程之间线程安全的访问机制,使你不必担心发送多线程之间的添加、移除、访问等的冲突,放心使用。

实现代码

1)辅助类提供的方法接口如下所示,该类继承一个自定义的CList,CList实现了克隆等一些接口,SyncList的函数接口定义如下:

/// <summary>
///初始化一个同步列表对象实例
/// </summary>
public SyncList()

/// <summary>
///初始化一个同步列表对象实例
/// </summary>
/// <param name="list">The list.</param>
public SyncList(CList<T> list)

/// <summary>
///获取一个值,判断<see cref="System.Collections.ICollection"></see>是否为同步的(线程安全).
/// </summary>
/// <value>如果为同步(线程安全)的,返回true,否则false. 默认为false</value>
/// <returns>如果为同步(线程安全)的,返回true,否则false</returns>
public override bool IsSynchronized

/// <summary>添加一个对象到<see cref="System.Collections.Generic.List<T>"></see>末尾.</summary>
/// <param name="item">待添加的对象. 值可以为空引用类型。</param>
public new void Add(T item)

/// <summary>添加一个集合到<see cref="System.Collections.Generic.List<T>"></see>末尾</summary>
/// <param name="collection">其集合元素待添加到<see cref="System.Collections.Generic.List<T>"></see>末尾的集合.
///集合本身不能为空,但如果类型TKey是一个引用类型,则它包含的元素可以为空</param>
/// <exception cref="System.ArgumentNullException">集合为空</exception>
public new void AddRange(IEnumerable<T> collection)

/// <summary>
///为当前集合返回一个只读的<see cref="System.Collections.Generic.IList<T>"></see>包装类。
/// </summary>
public new ReadOnlyCollection<T> AsReadOnly()

/// <summary>
///<see cref="System.Collections.Generic.List<T>"></see>集合中移除所有对象。
/// </summary>
public new void Clear()

/// <summary>判定指定的元素是否在<see cref="System.Collections.Generic.List<T>"></see>中.</summary>
/// <returns>如果元素在<see cref="System.Collections.Generic.List<T>"></see>中存在返回true,否则返回false.</returns>
/// <param name="item">待查找的元素,如果值为引用类型则可以为null</param>
public new bool Contains(T item)

/// <summary>
///转换当前<see cref="System.Collections.Generic.List<T>"></see>的元素到另外的类型,并返回包含转换后的元素列表。
/// </summary>
/// <returns>一个<see cref="System.Collections.Generic.List<T>"></see>集合,包含当前集合转换后的元素。</returns>
/// <param name="converter">每个元素从一种类型到另一种类型的转换委托</param>
/// <exception cref="System.ArgumentNullException">converter 为 null.</exception>
public new CList<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter)

/// <summary>复制整个<see cref="System.Collections.Generic.List<T>"></see>到一个一维数组中</summary>
/// <param name="array">一维数组,从列表中复制元素的目标对象。该数组必须具有从零开始的索引。</param>
/// <exception cref="System.ArgumentException">源列表中元素的数量大于目标数组能容纳的数量</exception>
/// <exception cref="System.ArgumentNullException">array 为 null.</exception>
public new void CopyTo(T[] array)

/// <summary>复制整个<see cref="System.Collections.Generic.List<T>"></see>到一个一维数组中</summary>
/// <param name="array">一维数组,从列表中复制元素的目标对象。该数组必须具有从零开始的索引。</param>
/// <param name="arrayIndex">array中的从零开始的索引,位于复制开始。</param>
/// <exception cref="System.ArgumentException">arrayIndex 大于或等于array数组长度;或源列表的元素数量大于目标array数组从arrayIndex到结束的可用空间</exception>
/// <exception cref="System.ArgumentOutOfRangeException">arrayIndex 小于等于 0.</exception>
/// <exception cref="System.ArgumentNullException">array 为 null.</exception>
public new void CopyTo(T[] array, int arrayIndex)

/// <summary>
///从列表中复制一个范围内的元素到一个相容的一维数组中。以指定的目标索引开始。
/// </summary>
/// <param name="index">在从零开始的索引,位于复制开始的源。</param>
/// <param name="array">一维数组,从列表中复制元素的目标对象。该数组必须具有从零开始的索引。</param>
/// <param name="arrayIndex">array中的从零开始的索引,位于复制开始。</param>
/// <param name="count">待复制的元素数量.</param>
/// <exception cref="System.ArgumentNullException">array 为 null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">index 小于 0;或者arrayIndex 小于0;或者count 小于 0.</exception>
/// <exception cref="System.ArgumentException">index 大于或等于源列表的数量。或者arrayIndex 大于或等于数组array的长度。或者从index到源列表结束的元素数量大于从 arrayIndex 到数组array结束的可用空间。</exception>
public new void CopyTo(int index, T[] array, int arrayIndex, int count)

/// <summary>
///判定<see cref="System.Collections.Generic.List<T>"></see>是否包含符合定义在指定predicate的条件中包含有元素。</summary>
/// <returns>如果列表中包含指定条件的元素,返回true,否则为false。</returns>
/// <param name="match">定义元素的条件来搜索对象的委托</param>
/// <exception cref="System.ArgumentNullException">match 为 null.</exception>
public new bool Exists(Predicate<T> match)

/// <summary>根据定义条件查询一个元素,并返回第一个在整个列表中出现的元素.</summary>
/// <returns>根据查询条件,第一个在整个列表中出现的元素,如果没有找到,返回Tkey类型的默认值。</returns>
/// <param name="match">定义元素的条件来搜索的委托</param>
/// <exception cref="System.ArgumentNullException">match 为 null.</exception>
public new T Find(Predicate<T> match)

/// <summary>获取指定Predicate定义的条件相匹配的所有元素。</summary>
/// <returns>如果遭到元素,返回指定Predicate定义的条件相匹配的所有元素列表,否则返回一个空列表。</see>.</returns>
/// <param name="match">定义元素的条件来搜索的委托</param>
/// <exception cref="System.ArgumentNullException">match 为 null.</exception>
public new CList<T> FindAll(Predicate<T> match)
。。。。。。。。。。。。。。。。。

2)辅助类SyncList的使用例子代码如下所示,由于线程安全,非常适合在多线程的环境下进行操作,如Socket服务器处理、后台线程数据处理等环境下。

SyncList<string> syncList = new SyncList<string>();
private void btnSyncTest_Click(object sender, EventArgs e)
{
for (int i = 0; i < 5; i++)
{
Thread thread = new Thread(new ThreadStart(AddSyncList));
thread.Start();
thread.Join();//等待线程完成才返回主线程
}

StringBuilder sb = new StringBuilder();
foreach (string item in syncList)
{
sb.AppendFormat("item:{0} \r\n", item);
}
MessageUtil.ShowTips(sb.ToString());
}

private void AddSyncList()
{
string key = new Random().Next().ToString();
syncList.Add(key);
Thread.Sleep(100);
}

输出结果如下所示。


5、线程安全的先进先出队列辅助类 Fifo。

实现效果

1) 本辅助类主要是用来方便实现线程安全的先进先出队列操作。
2)线程安全的先进先出队列,提供了多线程之间线程安全的访问机制,使你不必担心发送多线程之间的进队、出队等的冲突,放心使用。
3)Fifo类组合了先进先出的Queue类,提供了线程安全的操作,称为队列或环形缓冲区,这是一种采用先进先出结构(FIFO)的数据结构。现实生活中这种结构应用得非常广泛。比如某些公司的货仓管理系统,要求将先生产的货物先出货,后生产的货物后出货。另外一种场景就是Socket数据包处理的时候,我们一般是把他放到Fifo队列里面,实现先进先出的合理处理。

实现代码

1)辅助类提供的方法接口如下所示:

/// <summary>
///队列中目前存在个数
/// </summary>
public int Count

/// <summary>
///队列的最大容量
/// </summary>
public int MaxCount

/// <summary>
///重新设置队列的最大容量
/// </summary>
/// <param name="MaxCount">大于1的整数</param>
public void ResetMaxCount(int MaxCount)

/// <summary>
///元素进队, 将指定的对象值添加到队列的尾部
/// </summary>
/// <param name="obj">T 型的参数</param>
public void Append(T obj)

/// <summary>
///元素出队,即移除队列中开始的元素,按先进先出(FIFO)的规则,从前向后移除元素。
/// </summary>
/// <returns></returns>
public T Pop()

2)辅助类Fifo的使用例子代码如下所示,由于Fifo线程安全,非常适合在多线程的环境下进行操作,如Socket服务器处理、后台线程数据处理等环境下。

/// <summary>
///组包后数据的队列(先进先出)
/// </summary>
protected Fifo<PreData> _preDataFifo = new Fifo<PreData>(50000);

/// <summary>
///接收处理数据
/// </summary>
/// <param name="data">包体</param>
public void AppendPreData(PreData data)
{
this._preDataFifo.Append(data);
}

/// <summary>
///数据处理
/// </summary>
protected virtual void PreDataHandle()
{
try
{
while (true)
{
PreData data = _preDataFifo.Pop();
if (data != null)
{
PreDataHandle(data);
}
}
}
catch(Exception ex)
{
string message = string.Format("[{0}.PreDataHandle] desc:接收器处理异常->{1}", this._Name, ex.ToString());
Log.WriteError(message, ex.ToString(), true);
}
}

/// <summary>
///对每一个包体的数据进行处理
/// </summary>
/// <param name="data">包体</param>
public virtual void PreDataHandle(PreData data)
{
}


6、各种常用数组排序操作辅助类 SortHelper

实现效果

1) 本辅助类主要是用来方便实现各种常用数组排序操作,包括冒泡排序法、插入排序法、选择排序法、希尔排序法、快速排序法。

2) 本辅助类提供一些常用的排序操作,也可以作为学习排序的基础教程。

实现代码

1)辅助类提供的方法接口如下所示:

/// <summary>
///冒泡排序法
/// </summary>
/// <param name="list">待排序数组</param>
public static void BubbleSort(int[] list)

/// <summary>
///插入排序法
/// </summary>
/// <param name="list">待排序数组</param>
public static void InsertionSort(int[] list)

/// <summary>
///选择排序法
/// </summary>
/// <param name="list">待排序数组</param>
public static void SelectionSort(int[] list)

/// <summary>
///希尔排序法
/// </summary>
/// <param name="list">待排序数组</param>
public static void ShellSort(int[] list)

/// <summary>
///快速排序法
/// </summary>
/// <param name="list">待排序数组</param>
/// <param name="low">低位</param>
/// <param name="high">高位</param>
public static void QuickSort(int[] list, int low, int high)

2)辅助类SortHelper的使用例子代码如下所示。

private void btnSort_Click(object sender, EventArgs e)
{
//冒泡排序法
int[] list = new int[10] { 0, 1, 2, 3, 4, 9, 8, 7, 6, 5 };
SortHelper.BubbleSort(list);
StringBuilder sb = new StringBuilder();
foreach (int i in list)
{
sb.AppendFormat("{0},", i);
}
MessageUtil.ShowTips(sb.ToString());

//插入排序法
list = new int[10] { 0, 1, 2, 3, 4, 9, 8, 7, 6, 5 };
SortHelper.InsertionSort(list);
sb = new StringBuilder();
foreach (int i in list)
{
sb.AppendFormat("{0},", i);
}
MessageUtil.ShowTips(sb.ToString());
}

其他的接口排序差不多也是如此调用和结果的,只是在排序效率上有所差异。

俗话说,一个好汉十个帮,众人拾柴火焰高等都说明一个道理,有更多的资源,更丰富的积累,都是助你走向成功,走向顶峰的推动力。

本篇的公用类库的介绍主题是程序开发中多线程操作环境中,常用到的线程相关类,本篇随笔介绍包含单件创建辅助类、Timer定时器、委托处理辅助类、队列的线程处理服务辅助类、可以取消执行操作的线程池辅助类、线程池辅助类、线程辅助类等对象,这些辅助类覆盖了多线程开发中绝大多数的应用。良好的封装及操作,给我们提供非常方便、高效的线程操作处理。

本篇继续继续整理优化已有的共用类库,并继续发表随笔介绍公用类库的接口方法以及详细使用操作,力求给自己继续优化,积攒更丰富的公用类库资源,加深了解的同时,也给大家展现公用类库好的方面。

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(10)---各种线程同步的集合类
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(9)----各种常用辅助类
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(8)----非对称加密、BASE64加密、MD5等常用加密处理

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(7)-----声音播放、硬件信息、键盘模拟及钩子、鼠标模拟及钩子等设备相关
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(6)----全屏截图、图标获取、图片打印、页面预览截屏、图片复杂操作等

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(5)----热键、多线程、窗体动画冻结等窗体操作

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(4)----CSV、Excel、INI文件、独立存储等文件相关

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(3)----数据库相关操作

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(2)----常用操作

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(1)----开篇总结

1、单件操作辅助类 Singleton。

实现效果

1) 本辅助类主要是用来方便实现类对象的单件实例操作,减少重复写单件实现代码的繁琐,简化类的代码。

2)创建一个类对象的单件实例,类对象的构造函数不能为Public修饰符的,一般为private。

实现代码

1)辅助类提供的方法源码如下所示:

/// <summary>
///创建一个类对象的单件实例,类对象的构造函数不能为Public修饰符的,一般为private。
/// </summary>
/// <typeparam name="T">待创建的对象类</typeparam>
public static class Singleton<T> where T : class
{
static volatile T _instance;
static object _lock = new object();

static Singleton()
{
}

/// <summary>
///创建/获取一个可以new的类对象的单件实例
/// </summary>
public static T Instance
{
get
{
if (_instance == null)
lock (_lock)
{
if (_instance == null)
{
ConstructorInfo constructor = null;

try
{
//构造函数不包含public修饰符的
constructor = typeof(T).GetConstructor(BindingFlags.Instance |
BindingFlags.NonPublic, null, new Type[0], null);
}
catch (Exception exception)
{
throw new InvalidOperationException(exception.Message, exception);
}

if (constructor == null || constructor.IsAssembly)
{
throw new InvalidOperationException(string.Format("在'{0}'里面没有找到private或者protected的构造函数。", typeof(T).Name));
}

_instance = (T)constructor.Invoke(null);
}
}

return _instance;
}
}

2)辅助类Singleton的使用例子代码如下所示

/// <summary>
///单件测试类
/// </summary>
public class TestSingletonClass
{
/// <summary>
///私有构造函数
/// </summary>
private TestSingletonClass()
{
}

public void ShowMessage()
{
MessageUtil.ShowTips("单件实例测试函数");
}
}

private void btnSingleton_Click(object sender, EventArgs e)
{
//单件辅助类使用代码
Singleton<TestSingletonClass>.Instance.ShowMessage();
}


如果没有使用单件辅助类,那么单件的测试类将会需要这样书写,很明显多了很多行代码,如果每个想单件处理的类都要这样写,代码量还是很可观的,而且比较繁琐。

/// <summary>
///单件测试类
/// </summary>
public class TestSingletonClass
{
private static TestSingletonClass m_Instance;

/// <summary>
///单件实例
/// </summary>
public static TestSingletonClass Instance
{
get
{
if (m_Instance == null)
{
m_Instance = new TestSingletonClass();
}
return m_Instance;
}
}

/// <summary>
///私有构造函数
/// </summary>
private TestSingletonClass()
{
}

public void ShowMessage()
{
MessageUtil.ShowTips("单件实例测试函数");
}
}

2、定期执行某些任务的定时器辅助类Timer。

实现效果

1)  本辅助类主要是用来方便实现定时器辅助类,功能和另外一个定时器辅助类TimerHelper差不多。

2) 定时器操作,都通过对象锁以及在运行处理事件的时候,动态改变间隔事件为无限等待,处理完成后修改为间隔时间的方式,实现对定时器的正常、安全执行,不会发生运行一半又跳到下一个的处理过程中。

3).NET提供了3种定时器实现,他们的特点如下所示。该Timer辅助类是基于Threading.Timer的定时器实现。

Server Timers System.Timers.Timer 基于服务器的计时器,位于"工具箱"的“组件”选项卡上
Thread Timers System.Threading.Timer 在编程时使用的线程计时器
Windows Timers System.Windows.Forms.Timer 基于 Windows 的标准计时器,"工具箱"的"Windows 窗体"选项卡上;

实现代码

1)辅助类提供的方法接口如下所示:

#region 事件或属性

/// <summary>
///按定时器周期定期引发的事件
/// </summary>
public event EventHandler Elapsed;

/// <summary>
///定时器任务间隔(毫秒)
/// </summary>
public int Period { get; set; }

/// <summary>
///指示是否在方法开始的时候,启动定时器Elapsed事件一次。默认为false。
/// </summary>
public bool RunOnStart { get; set; }

#endregion

#region 构造函数

/// <summary>
///创建一个定时器
/// </summary>
/// <param name="period">定时器间隔 (毫秒)</param>
public Timer(int period) : this(period, false)

/// <summary>
///创建一个定时器
/// </summary>
/// <param name="period">定时器间隔 (毫秒)</param>
/// <param name="runOnStart">指示是否在方法开始的时候,启动定时器Elapsed事件一次</param>
public Timer(int period, bool runOnStart)

#endregion

#region 方法

/// <summary>
///启动定时器
/// </summary>
public void Start()

/// <summary>
///停止定时器
/// </summary>
public void Stop()

/// <summary>
///等待定时器停止
/// </summary>
public void WaitToStop()


#endregion

2)辅助类Timer 的使用例子代码如下所示

private void btnTimer_Click(object sender, EventArgs e)
{
WHC.OrderWater.Commons.Threading.Timer timer = new WHC.OrderWater.Commons.Threading.Timer(1000, true);
timer.Elapsed += new EventHandler(timer_Elapsed);
timer.Start();
}

void timer_Elapsed(object sender, EventArgs e)
{
if (!this.InvokeRequired)
return;

this.Invoke(new MethodInvoker(delegate()
{
this.btnTimer.Text = DateTime.Now.ToLongTimeString();
}));
}

3、定时器辅助类TimerHelper,可指定运行间隔、延迟启动时间等操作。

实现效果

1) 本辅助类主要是用来方便实现定时器辅助类,可指定运行间隔、延迟启动时间等操作。功能和另外一个定时器辅助类Timer差不多。

2)定时器操作,都通过对象锁以及在运行处理事件的时候,动态改变间隔事件为无限等待,处理完成后修改为间隔时间的方式,实现对定时器的正常、安全执行,不会发生运行一半又跳到下一个的处理过程中。

实现代码

1)辅助类提供的方法接口如下所示:

/// <summary>
///定时器执行操作的函数原型
/// </summary>
public delegate void TimerExecution();

/// <summary>
///定时器执行时调用的操作
/// </summary>
public event TimerExecution Execute;

/// <summary>
///创建一个指定时间间隔的定时器,并在指定的延迟后开始启动。(默认间隔为100毫秒)
/// </summary>
public TimerHelper()

/// <summary>
///创建一个指定时间间隔的定时器,并在指定的延迟后开始启动。
/// </summary>
/// <param name="interval">定时器执行操作的间隔时间(毫秒)</param>
/// <param name="startDelay">指定的延迟时间(毫秒)</param>
public TimerHelper(long interval, int startDelay)

/// <summary>
///创建一个指定时间间隔的定时器
/// </summary>
/// <param name="interval">定时器执行操作的间隔时间(毫秒)</param>
/// <param name="start">是否启动</param>
public TimerHelper(long interval, bool start)

/// <summary>
///启动定时器并指定延迟时间(毫秒)
/// </summary>
/// <param name="delayBeforeStart">指定延迟时间(毫秒)</param>
public void Start(int delayBeforeStart)

/// <summary>
///立即启动定时器
/// </summary>
public void Start()

/// <summary>
///暂停定时器
///注意:运行中的线程不会被停止
/// </summary>
public void Pause()

/// <summary>
///停止定时器
///注意:运行中的线程不会被停止
/// </summary>
public void Stop()

/// <summary>
///定时器的处理时间
/// </summary>
/// <param name="obj"></param>
public void Tick(object obj)

/// <summary>
///定时器的状态
/// </summary>
public TimerState State

/// <summary>
///获取或设置定时器的运行间隔
/// </summary>
public long Interval

2)辅助类
TimerHelper
的使用例子代码如下所示

public FrmNewHouse()
{
InitializeComponent();

if (!this.DesignMode)
{
this.winGridViewPager1.OnPageChanged += new EventHandler(winGridViewPager1_OnPageChanged);
this.winGridViewPager1.OnStartExport += new EventHandler(winGridViewPager1_OnStartExport);
this.winGridViewPager1.OnRefresh += new EventHandler(winGridViewPager1_OnRefresh);
this.winGridViewPager1.OnGridViewMouseDoubleClick += new EventHandler(winGridViewPager1_OnGridViewMouseDoubleClick);
this.winGridViewPager1.ShowLineNumber = true;
this.winGridViewPager1.PagerInfo.PageSize = 20;
this.winGridViewPager1.BestFitColumnWith = true;
this.winGridViewPager1.AppendedMenu = this.contextMenuStrip1;
this.winGridViewPager1.gridView1.RowCellStyle += new DevExpress.XtraGrid.Views.Grid.RowCellStyleEventHandler(gridView1_RowCellStyle);

//使用定时器,定时刷新窗体的数据,并提示客户更新情况
int interval = Portal.gc.GetRefreshSecond();//获取定时间隔时间
TimerHelper timer = new TimerHelper(interval, true);
timer.Execute += new TimerHelper.TimerExecution(timer_Execute);
}
}

//通过Invoke来实现跨线程间的调用
void timer_Execute()
{
if (!this.InvokeRequired)
return;

this.Invoke(new MethodInvoker(delegate()
{
NotifyNewHouse();
}));
}


4、提供一个队列的线程处理服务辅助类 QueueServer。

实现效果

1)  本辅助类主要是用来方便实现提供一个队列的线程处理服务操作。QueueServer是一个先入先出(FIFO)的队列处理服务。

实现代码

1)辅助类提供的方法接口如下所示:

#region  属性方法

/// <summary>
///是否是背景线程
/// </summary>
public bool IsBackground

/// <summary>
///执行队列
/// </summary>
public T[] Items

/// <summary>
///队列数量
/// </summary>
public int QueueCount

/// <summary>
///将对象加到队列结尾
/// </summary>
/// <param name="item"></param>
public void EnqueueItem(T item)

/// <summary>
///清除队列
/// </summary>
public void ClearItems()

#endregion

#region 线程处理

/// <summary>
///处理单个元素
/// </summary>
/// <param name="item">元素项目</param>
protected virtual void OnProcessItem(T item)

/// <summary>
///处理函数
/// </summary>
public event Action<T> ProcessItem;

#endregion

2)辅助类QueueServer的使用例子代码如下所示

 private void btnQueneServer_Click(object sender, EventArgs e)
{
QueueServer<PreDataInfo> queueServer = new QueueServer<PreDataInfo>();
queueServer.IsBackground = true;
queueServer.ProcessItem += new Action<PreDataInfo>(queueServer_ProcessItem);

//循环入队
for (int i = 0; i < 100; i++)
{
queueServer.EnqueueItem(new PreDataInfo(i.ToString(), DateTime.Now.ToString()));
Thread.Sleep(10);
}
}

/// <summary>
///处理每个出队的操作
/// </summary>
void queueServer_ProcessItem(PreDataInfo obj)
{
Console.WriteLine("{0} : {1}", obj.Key, obj.Data);
}
}

public class PreDataInfo
{
public string Key;
public string Data;

public PreDataInfo()
{
}

public PreDataInfo(string key, string data)
{
this.Key = key;
this.Data = data;
}
}


5、可以取消执行操作的线程池辅助类 AbortableThreadPool。

实现效果

1) 本辅助类主要是用来方便实现可以取消执行操作的线程池操作。

2)AbortableThreadPool线程辅助类可以使用常用的多线程处理环境中,也可以使用在有些在运行过程中可能需要取消的线程处理环境中。

实现代码

1)辅助类提供的方法接口如下所示:

/// <summary>
///把执行操作放到队列中。当线程池的线程可用的时候,方法执行。
/// </summary>
/// <param name="callback">一个代表将要执行方法的WaitCallback对象</param>
public static WorkItem QueueUserWorkItem(WaitCallback callback)

/// <summary>
///把执行操作放到队列中,并指定了一个对象,它包含将要执行方法的数据。
///当线程池的线程可用的时候,方法执行。
/// </summary>
/// <param name="callback">一个代表将要执行方法的WaitCallback对象</param>
/// <param name="state">一个对象,它包含将要执行方法的数据</param>
public static WorkItem QueueUserWorkItem(WaitCallback callback, object state)

/// <summary>
///取消指定的队列中的工作项。
/// </summary>
/// <param name="item">线程池中取消的项目</param>
/// <param name="allowAbort">如果设置为<see langword="true"/>则允许终止线程</param>
/// <returns>项目队列的状态</returns>
public static WorkItemStatus Cancel(WorkItem item, bool allowAbort)

/// <summary>
///获取指定队列中工作项的状态
/// </summary>
/// <param name="item">线程池中工作项</param>
/// <returns>工作项的状态</returns>
public static WorkItemStatus GetStatus(WorkItem item)

/// <summary>
///取消所有任务
/// </summary>
/// <param name="allowAbort">线程是否终止</param>
public static void CancelAll(bool allowAbort)

/// <summary>
///类似Thread.Join,等待AbortableThreadPool执行完成
/// </summary>
public static void Join()

/// <summary>
///类似Thread.Join,等待AbortableThreadPool执行完成
/// </summary>
/// <param name="millisecondsTimeout">等待的毫秒数</param>
/// <returns></returns>
public static bool Join(int millisecondsTimeout)

/// <summary>
///类似Thread.Join,等待AbortableThreadPool执行完成
/// </summary>
/// <param name="timeout">等待的时间范围</param>
/// <returns></returns>
public static bool Join(TimeSpan timeout)

/// <summary>
///在队列中,还未执行处理的数量
/// </summary>
public static int QueueCount

/// <summary>
///在执行中的线程数量
/// </summary>
public static int WorkingCount

2)辅助类AbortableThreadPool的使用例子代码如下所示

private void btnAbortableThreadPool_Click(object sender, EventArgs e)
{
Console.WriteLine(string.Format("QueueCount:{0},WorkingCount:{1}", AbortableThreadPool.QueueCount, AbortableThreadPool.WorkingCount));

WorkItem workItem1 = AbortableThreadPool.QueueUserWorkItem(new WaitCallback(Test));
Console.WriteLine(string.Format("QueueCount:{0},WorkingCount:{1}", AbortableThreadPool.QueueCount, AbortableThreadPool.WorkingCount));

WorkItem workItem2 = AbortableThreadPool.QueueUserWorkItem(new WaitCallback(Test));
WorkItem workItem3 = AbortableThreadPool.QueueUserWorkItem(new WaitCallback(Test));
WorkItem workItem4 = AbortableThreadPool.QueueUserWorkItem(new WaitCallback(Test));
WorkItem workItem5 = AbortableThreadPool.QueueUserWorkItem(new WaitCallback(Test));
Console.WriteLine(string.Format("QueueCount:{0},WorkingCount:{1}", AbortableThreadPool.QueueCount, AbortableThreadPool.WorkingCount));
Thread.Sleep(1000);

Console.WriteLine(AbortableThreadPool.Cancel(workItem1, false));
Console.WriteLine(string.Format("QueueCount:{0},WorkingCount:{1}", AbortableThreadPool.QueueCount, AbortableThreadPool.WorkingCount));
Thread.Sleep(1000);

Console.WriteLine(AbortableThreadPool.Cancel(workItem1, true));
Console.WriteLine(string.Format("QueueCount:{0},WorkingCount:{1}", AbortableThreadPool.QueueCount, AbortableThreadPool.WorkingCount));
Thread.Sleep(1000);

//AbortableThreadPool.CancelAll(true);//可取消所有任务
AbortableThreadPool.Join(); //等待所有任务退出
Console.WriteLine(string.Format("QueueCount:{0},WorkingCount:{1}", AbortableThreadPool.QueueCount, AbortableThreadPool.WorkingCount));
}

static void Test(object state)
{
int i = 100;
while (i-- > 0)
{
Console.WriteLine(i);
Thread.Sleep(new Random((int)DateTime.Now.Ticks).Next(100));
}
}



6、委托处理辅助类DelegateHelper。

实现效果

1) 本辅助类主要是用来方便实现委托的处理。

2)使用委托处理辅助类DelegateHelper,可以快速执行或者取消一些委托方法的执行。

实现代码

1)辅助类提供的方法接口如下所示:

/// <summary>
///执行委托操作
/// </summary>
/// <param name="target">目标委托对象</param>
/// <param name="args">参数</param>
public static WorkItem InvokeDelegate(Delegate target, params object[] args)

/// <summary>
///执行委托操作
/// </summary>
/// <param name="target">目标委托对象</param>
public static WorkItem InvokeDelegate(Delegate target)

/// <summary>
///中止指定的队列中委托
/// </summary>
/// <param name="target">目标委托对象</param>
/// <returns>项目队列中止操作的状态</returns>
public static WorkItemStatus AbortDelegate(WorkItem target)

2)辅助类DelegateHelper的使用例子代码如下所示

private void btnDelegeteHelper_Click(object sender, EventArgs e)
{
//无参数的委托
DelegateHelper.InvokeDelegate(new UpdateTextDelegate(this.UpdateText));

//有参数的委托
DelegateHelper.InvokeDelegate(new UpdateTextDelegate2(this.UpdateText), 100);

}
private delegate void UpdateTextDelegate();
private delegate void UpdateTextDelegate2(int count);
private void UpdateText()
{
for (int i = 0; i < 1000; i++)
{
Thread.Sleep(100);
}
}
private void UpdateText(int count)
{
for (int i = 0; i < count; i++)
{
Thread.Sleep(100);
}
}


7、线程池辅助操作类 ThreadPoolHelper。

实现效果

1) 本辅助类主要是用来方便实现线程池辅助操作。。

实现代码

1)辅助类提供的方法接口如下所示:

/// <summary>
///方法委托
/// </summary>
public delegate void WaitCallbackNew();

/// <summary>
///把执行方法放到队列中。
///当线程池线程变为可用的时候,方法执行。
/// </summary>
/// <param name="callback">委托对象</param>
public static bool QueueUserWorkItem(WaitCallbackNew callback)

/// <summary>
///把执行方法放到队列中。
///当线程池线程变为可用的时候,方法执行。
/// </summary>
/// <param name="proc">委托对象数组</param>
/// <returns></returns>
public static bool QueueUserWorkItems(params WaitCallbackNew[] proc)

/// <summary>
///等待指定数组中所有元素收到信号
/// </summary>
public static bool WaitAll()

/// <summary>
///等待指定数组中任何一个元素收到信号
/// </summary>
/// <returns>满足等待的对象数组索引</returns>
public static int WaitAny()

2)辅助类ThreadPoolHelper的使用例子代码如下所示

private void UpdateText()
{
for (int i = 0; i < 50; i++)
{
Thread.Sleep(100);
}
}

private void btnThreadPool_Click(object sender, EventArgs e)
{
ThreadPoolHelper.QueueUserWorkItem(new ThreadPoolHelper.WaitCallbackNew(UpdateText));
ThreadPoolHelper.WaitAny(); //阻塞主界面线程,到5秒循环结束后,主界面可以操作
}


8、线程操作辅助类ThreadHelper。

实现效果

1) 本辅助类主要是用来方便实现线程的各种操作,包括设置线程名称、优先级等及把执行方法放到队列中执行等基础性的线程操作。

实现代码

1)辅助类提供的方法接口如下所示:

/// <summary>
///线程名称,最长不超过10个字符!
/// </summary>
/// <param name="name">线程名称</param>
public static void SetThreadName(string name)

/// <summary>
///设置线程优先级
/// </summary>
/// <param name="priority">线程优先级</param>
public static void SetThreadPriority(ThreadPriority priority)

/// <summary>
///设置主线程的UI Culture
/// </summary>
/// <param name="cultureName"></param>
public static void SetMainThreadUICulture(string cultureName)

/// <summary>
///把执行方法放到队列中,并指定了一个对象,它包含使用该方法的数据。
///当线程池线程变为可用的时候,方法执行。
/// </summary>
/// <param name="callBack">工作项(WaitCallback)对象</param>
/// <param name="threadName">线程名称,最长不超过10个字符!</param>
/// <param name="priority">线程优先级</param>
public static bool Queue(WaitCallback callBack, string threadName, ThreadPriority priority)

/// <summary>
///把执行方法放到队列中,并指定了一个对象,它包含使用该方法的数据。
///当线程池线程变为可用的时候,方法执行。
/// </summary>
/// <param name="callBack">工作项(WaitCallback)对象</param>
/// <param name="threadName">线程名称,最长不超过10个字符!</param>
/// <param name="state">执行方法的数据</param>
/// <param name="priority">线程优先级</param>
public static bool Queue(WaitCallback callBack, string threadName, object state, ThreadPriority priority)

/// <summary>
///线程休眠一段毫秒时间
/// </summary>
/// <param name="millisecondsTimeout">一段毫秒时间</param>
public static void Sleep(int millisecondsTimeout)

/// <summary>
///线程休眠一段时间
/// </summary>
/// <param name="timeOut"></param>
public static void Sleep(TimeSpan timeOut)

2)辅助类ThreadHelper的使用例子代码如下所示

CHM帮助文档持续更新中,统一下载地址是:
http://www.iqidi.com/download/commonshelp.rar

最新公用类库DLL+XML注释文件下载地址是:
https://files.cnblogs.com/wuhuacong/WHC.OrderWater.Commons.rar

俗话说,一个好汉十个帮,众人拾柴火焰高等都说明一个道理,有更多的资源,更丰富的积累,都是助你走向成功,走向顶峰的推动力。

本篇的公用类库的介绍主题是程序开发中多线程操作环境中,常用到的网络操作相关类,本篇随笔介绍包含邮件发送辅助类(包含附件、嵌入图片等)、获取网页数据辅助类库、管理文档服务器类、网络相关操作辅助类、IE代理设置辅助类等对象,这些辅助类覆盖了网络编程开发中多数的应用。良好的封装及操作,给我们提供非常方便、高效的辅助类库操作体验。

本篇继续继续整理优化已有的共用类库,并继续发表随笔介绍公用类库的接口方法以及详细使用操作,力求给自己继续优化,积攒更丰富的公用类库资源,加深了解的同时,也给大家展现公用类库好的方面。

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(11)---各种线程相关操作类
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(10)---各种线程同步的集合类
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(9)----各种常用辅助类
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(8)----非对称加密、BASE64加密、MD5等常用加密处理

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(7)-----声音播放、硬件信息、键盘模拟及钩子、鼠标模拟及钩子等设备相关
厚积薄发,丰富的公用类库积累,助你高效进行系统开发(6)----全屏截图、图标获取、图片打印、页面预览截屏、图片复杂操作等

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(5)----热键、多线程、窗体动画冻结等窗体操作

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(4)----CSV、Excel、INI文件、独立存储等文件相关

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(3)----数据库相关操作

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(2)----常用操作

厚积薄发,丰富的公用类库积累,助你高效进行系统开发(1)----开篇总结

1、发送邮件的辅助类 EmailHelper。

实现效果

1)  本辅助类主要是用来方便实现发送邮件操作,可以发送附件、嵌入图片、HTML等内容邮件。使用底层SMTP协议指令进行发送,成功率较高。

2)邮件发送可以用在客户反馈,信息推广,客户沟通,员工交流等方面业务需要。

实现代码

1)辅助类提供的方法源码如下所示:

/// <summary>
///设定语言代码,默认设定为GB2312,如不需要可设置为""
/// </summary>
public string Charset = "GB2312";

/// <summary>
///邮箱服务器
/// </summary>
public string MailServer

/// <summary>
///邮件服务器端口号,默认端口为25
/// </summary>
public int MailServerPort

/// <summary>
///SMTP认证时使用的用户名
/// </summary>
public string MailServerUsername

/// <summary>
///SMTP认证时使用的密码
/// </summary>
public string MailServerPassword

/// <summary>
///发件人地址
/// </summary>
public string From

/// <summary>
///发件人姓名
/// </summary>
public string FromName

/// <summary>
///回复邮件地址
/// </summary>
public string ReplyTo = "";

/// <summary>
///邮件主题
/// </summary>
public string Subject = "";

/// <summary>
///是否Html邮件
/// </summary>
public bool IsHtml = false;

/// <summary>
///收件人是否发送收条
/// </summary>
public bool ReturnReceipt = false;

/// <summary>
///邮件正文
/// </summary>
public string Body = "";

/// <summary>
///邮件发送优先级,可设置为"High","Normal","Low"或"1","3","5"
/// </summary>
public string Priority

/// <summary>
///错误消息反馈
/// </summary>
public string ErrorMessage

/// <summary>
///收件人姓名
/// </summary>
public string RecipientName = "";

/// <summary>
///默认构造函数
/// </summary>
public EmailHelper()

/// <summary>
///待邮箱发送配置参数的构造函数
/// </summary>
/// <param name="mailServer">邮件服务器</param>
/// <param name="username">用户名</param>
/// <param name="password">用户密码</param>
public EmailHelper(string mailServer, string username, string password)

/// <summary>
///待邮箱发送配置参数的构造函数
/// </summary>
/// <param name="mailServer">邮件服务器</param>
/// <param name="username">用户名</param>
/// <param name="password">用户密码</param>
/// <param name="mailServerPort">邮箱服务器端口</param>
public EmailHelper(string mailServer, string username, string password, int port)

/// <summary>
///添加一个附件,需使用绝对路径
/// </summary>
public bool AddAttachment(string path)

/// <summary>
///添加一个收件人
/// </summary>
/// <param name="str">收件人地址</param>
public bool AddRecipient(string str)

/// <summary>
///添加一个抄送收件人
/// </summary>
/// <param name="str">收件人地址</param>
public bool AddRecipientCC(string str)

/// <summary>
///添加一个密件收件人
/// </summary>
/// <param name="str">收件人地址</param>
public bool AddRecipientBCC(string str)

/// <summary>
///清空收件人列表
/// </summary>
public void ClearRecipient()

/// <summary>
///发送邮件
/// </summary>
public bool SendEmail()

2)辅助类EmailHelper的使用例子代码如下所示

EmailHelper email = new EmailHelper("smtp.163.com", "wuhuacong2013@163.com", "password");
email.Subject = "伍华聪的普通测试邮件";
email.Body = string.Format("测试邮件正文内容");
email.IsHtml = true;
email.From = "wuhuacong2013@163.com";
email.FromName = "wuhuacong2013";
email.AddRecipient("6966254@qq.com");
try
{
bool success = email.SendEmail();
MessageUtil.ShowTips(success ? "发送成功" : "发送失败");
}
catch (Exception ex)
{
MessageUtil.ShowError(ex.Message);
}

3)如果使用发送附件、发送嵌入图片(正文中有图片显示内容的)方式,则例子代码如下所示。

EmailHelper email = new EmailHelper("smtp.163.com", "wuhuacong2013@163.com", "password");
email.Subject = "伍华聪的图片附件测试邮件";
string embedFile = Path.Combine(Application.StartupPath, "cityroad.jpg");
email.Body = string.Format("测试邮件正文内容<img src=\"{0}\" title='测试图片' />", embedFile);
email.IsHtml = true;
email.From = "wuhuacong2013@163.com";
email.FromName = "wuhuacong2013";
email.AddRecipient("6966254@qq.com");
email.AddAttachment(Path.Combine(Application.StartupPath, "ringin.wav"));//.AddAttachment("C:\\test.txt");

try
{
bool success = email.SendEmail();
MessageUtil.ShowTips(success ? "发送成功" : "发送失败");
}
catch (Exception ex)
{
MessageUtil.ShowError(ex.Message);
}

2、获取网页数据辅助类库 HttpHelper。

实现效果

1)  本辅助类主要是用来方便实现获取网页数据的操作,可以通过GET、POST方式获取网页内容,获取验证码等图片资源,是网络编程不可或缺的强大辅助类库。

2) 该辅助类库在我的QQ搜通天系列软件、QQ群成员提取工具、易博搜搜等网络应用软件上,辅助类主要是用于网页数据采集和分析操作。

实现代码

1)辅助类提供的方法源码如下所示:

#region 属性

/// <summary>
///内容类型,默认为"application/x-www-form-urlencoded"
/// </summary>
public string ContentType

/// <summary>
///Accept值,默认支持各种类型
/// </summary>
public string Accept

/// <summary>
///UserAgent,默认支持Mozilla/MSIE等
/// </summary>
public string UserAgent

/// <summary>
///Cookie容器
/// </summary>
public CookieContainer CookieContainer

/// <summary>
///获取网页源码时使用的编码
/// </summary>
/// <value></value>
public Encoding Encoding

/// <summary>
///网络延时
/// </summary>
public int NetworkDelay

/// <summary>
///最大尝试次数
/// </summary>
public int MaxTry

#endregion

#region 构造函数

/// <summary>
///构造函数
/// </summary>
public HttpHelper()

/// <summary>
///构造函数
/// </summary>
/// <param name="cc">指定CookieContainer的值</param>
public HttpHelper(CookieContainer cc)

/// <summary>
///构造函数
/// </summary>
/// <param name="contentType">内容类型</param>
/// <param name="accept">Accept类型</param>
/// <param name="userAgent">UserAgent内容</param>
public HttpHelper(string contentType, string accept, string userAgent)

/// <summary>
///构造函数
/// </summary>
/// <param name="cc">指定CookieContainer的值</param>
/// <param name="contentType">内容类型</param>
/// <param name="accept">Accept类型</param>
/// <param name="userAgent">UserAgent内容</param>
public HttpHelper(CookieContainer cc, string contentType, string accept, string userAgent)

#endregion

#region 公共方法

/// <summary>
///获取指定页面的HTML代码
/// </summary>
/// <param name="url">指定页面的路径</param>
/// <param name="cookieContainer">Cookie集合</param>
/// <param name="postData">回发的数据</param>
/// <param name="isPost">是否以post方式发送请求</param>
/// <returns></returns>
public string GetHtml(string url, CookieContainer cookieContainer, string postData, bool isPost)

/// <summary>
///获取指定页面的HTML代码
/// </summary>
/// <param name="url">指定页面的路径</param>
/// <param name="cookieContainer">Cookie集合对象</param>
/// <param name="postData">回发的数据</param>
/// <param name="isPost">是否以post方式发送请求</param>
/// <param name="referer">页面引用</param>
/// <returns></returns>
public string GetHtml(string url, CookieContainer cookieContainer, string postData, bool isPost, string referer)

/// <summary>
///获取指定页面的HTML代码
/// </summary>
/// <param name="url">指定页面的路径</param>
/// <param name="cookieContainer">Cookie集合</param>
/// <param name="reference">页面引用</param>
/// <returns></returns>
public string GetHtml(string url, CookieContainer cookieContainer, string reference)

/// <summary>
///获取指定页面的HTML代码
/// </summary>
/// <param name="url">指定页面的路径</param>
/// <returns></returns>
public string GetHtml(string url)

/// <summary>
///获取指定页面的HTML代码
/// </summary>
/// <param name="url">指定页面的路径</param>
/// <param name="reference">页面引用</param>
/// <returns></returns>
public string GetHtml(string url, string reference)

/// <summary>
///获取指定页面的HTML代码
/// </summary>
/// <param name="url">指定页面的路径</param>
/// <param name="postData">回发的数据</param>
/// <param name="isPost">是否以post方式发送请求</param>
/// <returns></returns>
public string GetHtml(string url, string postData, bool isPost)

/// <summary>
///获取指定页面的Stream
/// </summary>
/// <param name="url">指定页面的路径</param>
/// <param name="cookieContainer">Cookie集合对象</param>
/// <returns></returns>
public Stream GetStream(string url, CookieContainer cookieContainer)

/// <summary>
///获取指定页面的Stream
/// </summary>
/// <param name="url">指定页面的路径</param>
/// <param name="cookieContainer">Cookie对象</param>
/// <param name="reference">页面引用</param>
public Stream GetStream(string url, CookieContainer cookieContainer, string reference)

/// <summary>
///根据Cookie字符串获取Cookie的集合
/// </summary>
/// <param name="cookieString">Cookie字符串</param>
/// <returns></returns>
public CookieCollection GetCookieCollection(string cookieString)

/// <summary>
///获取HTML页面内容指定隐藏域Key的Value内容
/// </summary>
/// <param name="html">待操作的HTML页面内容</param>
/// <param name="key">隐藏域的名称</param>
/// <returns></returns>
public string GetHiddenKeyValue(string html, string key)

/// <summary>
///获取网页的编码格式
/// </summary>
/// <param name="url">网页地址</param>
/// <returns></returns>
public string GetEncoding(string url)

/// <summary>
///判断URL是否有效
/// </summary>
/// <param name="url">待判断的URL,可以是网页以及图片链接等</param>
/// <returns>200为正确,其余为大致网页错误代码</returns>
public int GetUrlError(string url)

/// <summary>
///移除Html标记
/// </summary>
public string RemoveHtml(string content)

/// <summary>
///返回 HTML 字符串的编码结果
/// </summary>
/// <param name="inputData">字符串</param>
/// <returns>编码结果</returns>
public static string HtmlEncode(string inputData)

/// <summary>
///返回 HTML 字符串的解码结果
/// </summary>
/// <param name="str">字符串</param>
/// <returns>解码结果</returns>
public static string HtmlDecode(string str)

#endregion

2)辅助类HttpHelper的使用例子代码如下所示,下面的是最为简单的获取页面内容的操作。

public void GetQQLog()
{
string qq = this.txtQQ.Text;
string json = "";

string url = string.Format("http://b.qzone.qq.com/cgi-bin/blognew/blog_get_titlelist?direct=1&numperpage=100&uin={0}", qq);
HttpHelper helper = new HttpHelper();
helper.Encoding = Encoding.Default;
json = helper.GetHtml(url);
..............
}

实际操作可能更多的是要记录Cookie信息,方便下一次的调用,还有可能需要获取验证码等等,复杂一点的例子代码如下所示。

string uin = e.Argument.ToString();
HttpHelper httpHelper = new HttpHelper();
string refUrl = "http://qzone.qq.com/";
string url = string.Format("http://ptlogin2.qq.com/check?uin={0}&appid=46000101&r=0.5454333601416937", uin);
string checkHtml = httpHelper.GetHtml(url, Portal.gc.cookieZone, refUrl);
//ptui_checkVC('1','56443c908b8be83dc4435e253e6b43ad99eab4fe0846930d');
Regex re = new Regex("ptui_checkVC\\('\\d+','(.*?)'\\);", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace);
Match mc = re.Match(checkHtml);
if (!mc.Success)
{
return;
}

string vc_type = re.Matches(checkHtml)[0].Groups[1].Value;
string imageUrl = string.Format("http://captcha.qq.com/getimage?aid=46000101&r=0.2758570793854393&uin={0}&vc_type={1}", uin, vc_type);
using (Stream s = httpHelper.GetStream(imageUrl, Portal.gc.cookieZone))
{
if (s == null)
{
MessageExUtil.ShowWarning("获取登陆码错误,请检查您的网络!");
return;
}
e.Result = Image.FromStream(s);
}

上面的操作都是使用GET方式获取页面内容或者数据的,另外还有一种方式就是使用POST方式提交数据,并获取页面内容的,如下例子所示。

#region 构造提交参数
StringBuilder sb = new StringBuilder();
sb.AppendFormat("callCount=1");
sb.AppendFormat("&page=/{0}/members/", urlName);
sb.AppendFormat("&httpSessionId=");
sb.AppendFormat("&scriptSessionId=D4DAC4AD9C3BF9B71C82802BDDBA0C25369");
sb.AppendFormat("&c0-scriptName=CircleBean");
sb.AppendFormat("&c0-methodName=getNewCircleUsers");
sb.AppendFormat("&c0-id=0");//保留字符
sb.AppendFormat("&c0-param0=number:{0}", circleId);//11
sb.AppendFormat("&c0-param1=number:{0}", pageSize);//数量
sb.AppendFormat("&c0-param2=number:{0}", pageSize * i);//0,30,60
sb.AppendFormat("&c0-param3=boolean:true");
sb.AppendFormat("&batchId={0}", i);
i++;

//callCount=1
//page=/dnkxin/members/
//httpSessionId=
//scriptSessionId=D4DAC4AD9C3BF9B71C82802BDDBA0C25369
//c0-scriptName=CircleBean
//c0-methodName=getNewCircleUsers
//c0-id=0
//c0-param0=number:15057666666//(<body onload="MembersPage.init('15057666666', '/style/pinkstar/','http://blog.163.com','')">)
//c0-param1=number:10
//c0-param2=number:0
//c0-param3=boolean:true
//batchId=0
#endregion

string content = "";
try
{
httpHelper.ContentType = "text/plain";
content = httpHelper.GetHtml(url, cookie, sb.ToString(), true, refUrl);//使用Post方式提交内容,并返回页面结果
re = new Regex(circleReg.ToString(), RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace);
mc = re.Match(content);
}
catch (Exception ex)
{
LogTextHelper.WriteLine(ex.ToString());
break;
}

下面是一些具体应用的例子截图,主要就是通过该辅助类获取、分析网页的处理结果。

3、管理文档服务器类,提供文件上传、下载、删除等功能辅助类 FileServerManage。

实现效果

1) 本辅助类主要是用来方便实现管理文档服务器类,提供文件上传、下载、删除等功能。 不过注意,由于IIS操作限制,可能一些后缀名的文件不支持访问。

2)FileServerManage 主要是通过IIS网站方式上传管理文件附件的,要使用该辅助类库的功能,需要为指定的目录(一般在文件服务器上一个目录)建立一个虚拟网站,指定端口等参数,该辅助类库的构造函数,使用的是虚拟网站的URL地址以及文件服务器的登录账号和密码(本机则使用本机的账号密码)。
3)另外使用IIS作为文件上传操作,除了需要用到当前机器的账号密码登录外,还需要在IIS管理中开通/启用WebDev的功能。

实现代码

1)辅助类提供的方法源码如下所示:

/// <summary>
///构造函数
/// </summary>
public FileServerManage()

/// <summary>
///构造函数
/// </summary>
/// <param name="url">指定URL地址</param>
/// <param name="username">指定用户名</param>
/// <param name="password">指定密码</param>
public FileServerManage(string url, string username, string password)

/// <summary>
///上传文件
/// </summary>
/// <param name="inputStream">流对象</param>
/// <param name="fileName">保存文件名,可包含文件夹(test/test.txt)</param>
/// <returns>bool[true:成功,false:失败]</returns>
public bool UploadFile(Stream inputStream, string fileName)

/// <summary>
///上传文件
/// </summary>
/// <param name="fileUrl">上传地址</param>
/// <param name="fileName">上传文件名称,可包含文件夹(test/test.txt)</param>
/// <returns>bool[true:成功,false:失败]</returns>
public bool UploadFile(string fileUrl, string fileName)

/// <summary>
///删除文件
/// </summary>
/// <param name="fileName">文件名称,可包含文件夹(test/test.txt)</param>
/// <returns>bool[true:成功,false:失败]</returns>
public bool DeleteFile(string fileName)

/// <summary>
///判断文件是否存在
/// </summary>
/// <param name="fileName">文件名称,可包含文件夹(test/test.txt)</param>
/// <returns>bool[true:存在,false:否]</returns>
public bool IsFileExist(string fileName)

/// <summary>
///通过HttpResponse方式读取文件,Web开发才可以使用
/// </summary>
/// <param name="newFileName">新文件名称,可包含文件夹(test/test.txt)</param>
/// <param name="oldFileName">原文件名称</param>
/// <returns></returns>
public string ReadFile(string newFileName, string oldFileName)

/// <summary>
///读取服务器文件到字节数据中
/// </summary>
/// <param name="fileName">文件名称,可包含文件夹(test/test.txt)</param>
/// <returns></returns>
public byte[] ReadFileBytes(string fileName)

2)辅助类FileServerManage的使用例子代码如下所示

private void btnWebFile_Click(object sender, EventArgs e)
{
WHC.OrderWater.Commons.Web.FileServerManage file = new WHC.OrderWater.Commons.Web.FileServerManage("http://192.168.1.30:8009", "administrator", "123456789");
try
{
//上传文件
bool first = false;
using (FileStream fs = new FileStream("C:\\test.txt", FileMode.Open))
{
first = file.UploadFile(fs, "test.txt");
}

//利用子目录上传,需要服务器手动创建目录
bool second = file.UploadFile("C:\\test.txt", "Bridge/test.txt");

MessageUtil.ShowTips(string.Format("第一次上传:{0} 第二次上传{1}", first, second));

byte[] fileBytes = file.ReadFileBytes("test.txt");
if (fileBytes != null)
{
MessageUtil.ShowTips(string.Format("File Bytes:{0}", fileBytes.Length));
}

//删除文件
first = file.DeleteFile("test.txt");
bool third = file.IsFileExist("Bridge/test.txt");
second = file.DeleteFile("Bridge/test.txt");
MessageUtil.ShowTips(string.Format("删除文件:{0}、{1} 文件存在:{2}", first, second, third));

}
catch (Exception ex)
{
MessageUtil.ShowError(ex.Message);
}
}

4、网络相关操作辅助类 NetworkUtil

实现效果

1) 本辅助类主要是用来方便实现网络相关操作,可以对IP或者域名进行相互解析,基于Socket的TCP/UDP相关操作,检测本机是否联网等相关的网络操作。

实现代码

1)辅助类提供的方法源码如下所示:

/// <summary>
///获取本地机器IP地址
/// </summary>
/// <returns></returns>
public static string GetLocalIP()

/// <summary>
///检查设置的IP地址是否正确,并返回正确的IP地址,无效IP地址返回"-1"。
/// </summary>
/// <param name="ip">设置的IP地址</param>
/// <returns>非法IP 则返回 -1</returns>
public static string GetValidIP(string ip)

/// <summary>
///检查设置的端口号是否正确,并返回正确的端口号,无效端口号返回-1。
/// </summary>
/// <param name="port">设置的端口号</param>
public static int GetValidPort(string port)

/// <summary>
///将字符串形式的IP地址转换成IPAddress对象
/// </summary>
/// <param name="ip">字符串形式的IP地址</param>
public static IPAddress StringToIPAddress(string ip)

/// <summary>
///获取本机的计算机名
/// </summary>
public static string LocalHostName

/// <summary>
///获取本机的局域网IP
/// </summary>
public static string LANIP

/// <summary>
///获取本机在Internet网络的广域网IP
/// </summary>
public static string WANIP

/// <summary>
///获取远程客户机的IP地址
/// </summary>
/// <param name="clientSocket">客户端的socket对象</param>
public static string GetClientIP(Socket clientSocket)

/// <summary>
///创建一个IPEndPoint对象
/// </summary>
/// <param name="ip">IP地址</param>
/// <param name="port">端口号</param>
public static IPEndPoint CreateIPEndPoint(string ip, int port)

/// <summary>
///创建一个自动分配IP和端口的TcpListener对象
/// </summary>
public static TcpListener CreateTcpListener()

/// <summary>
///创建一个TcpListener对象
/// </summary>
/// <param name="ip">IP地址</param>
/// <param name="port">端口</param>
public static TcpListener CreateTcpListener(string ip, int port)

/// <summary>
///创建一个基于TCP协议的Socket对象
/// </summary>
public static Socket CreateTcpSocket()

/// <summary>
///创建一个基于UDP协议的Socket对象
/// </summary>
public static Socket CreateUdpSocket()

#region 获取TcpListener对象的本地终结点
/// <summary>
///获取TcpListener对象的本地终结点
/// </summary>
/// <param name="tcpListener">TcpListener对象</param>
public static IPEndPoint GetLocalPoint(TcpListener tcpListener)

/// <summary>
///获取TcpListener对象的本地终结点的IP地址
/// </summary>
/// <param name="tcpListener">TcpListener对象</param>
public static string GetLocalPoint_IP(TcpListener tcpListener)

/// <summary>
///获取TcpListener对象的本地终结点的端口号
/// </summary>
/// <param name="tcpListener">TcpListener对象</param>
public static int GetLocalPoint_Port(TcpListener tcpListener)

#endregion

#region 获取Socket对象的本地终结点

/// <summary>
///获取Socket对象的本地终结点
/// </summary>
/// <param name="socket">Socket对象</param>
public static IPEndPoint GetLocalPoint(Socket socket)

/// <summary>
///获取Socket对象的本地终结点的IP地址
/// </summary>
/// <param name="socket">Socket对象</param>
public static string GetLocalPoint_IP(Socket socket)

/// <summary>
///获取Socket对象的本地终结点的端口号
/// </summary>
/// <param name="socket">Socket对象</param>
public static int GetLocalPoint_Port(Socket socket)

#endregion

/// <summary>
///绑定终结点
/// </summary>
/// <param name="socket">Socket对象</param>
/// <param name="endPoint">要绑定的终结点</param>
public static void BindEndPoint(Socket socket, IPEndPoint endPoint)

/// <summary>
///绑定终结点
/// </summary>
/// <param name="socket">Socket对象</param>
/// <param name="ip">服务器IP地址</param>
/// <param name="port">服务器端口</param>
public static void BindEndPoint(Socket socket, string ip, int port)

/// <summary>
///指定Socket对象执行监听,默认允许的最大挂起连接数为100
/// </summary>
/// <param name="socket">执行监听的Socket对象</param>
/// <param name="port">监听的端口号</param>
public static void StartListen(Socket socket, int port)

/// <summary>
///指定Socket对象执行监听
/// </summary>
/// <param name="socket">执行监听的Socket对象</param>
/// <param name="port">监听的端口号</param>
/// <param name="maxConnection">允许的最大挂起连接数</param>
public static void StartListen(Socket socket, int port, int maxConnection)

/// <summary>
///指定Socket对象执行监听
/// </summary>
/// <param name="socket">执行监听的Socket对象</param>
/// <param name="ip">监听的IP地址</param>
/// <param name="port">监听的端口号</param>
/// <param name="maxConnection">允许的最大挂起连接数</param>
public static void StartListen(Socket socket, string ip, int port, int maxConnection)

/// <summary>
///连接到基于TCP协议的服务器,连接成功返回true,否则返回false
/// </summary>
/// <param name="socket">Socket对象</param>
/// <param name="ip">服务器IP地址</param>
/// <param name="port">服务器端口号</param>
public static bool Connect(Socket socket, string ip, int port)

/// <summary>
///以同步方式向指定的Socket对象发送消息
/// </summary>
/// <param name="socket">socket对象</param>
/// <param name="msg">发送的消息</param>
public static void SendMsg(Socket socket, byte[] msg)

/// <summary>
///使用UTF8编码格式以同步方式向指定的Socket对象发送消息
/// </summary>
/// <param name="socket">socket对象</param>
/// <param name="msg">发送的消息</param>
public static void SendMsg(Socket socket, string msg)

/// <summary>
///以同步方式接收消息
/// </summary>
/// <param name="socket">socket对象</param>
/// <param name="buffer">接收消息的缓冲区</param>
public static void ReceiveMsg(Socket socket, byte[] buffer)

/// <summary>
///以同步方式接收消息,并转换为UTF8编码格式的字符串,使用5000字节的默认缓冲区接收。
/// </summary>
/// <param name="socket">socket对象</param>
public static string ReceiveMsg(Socket socket)

/// <summary>
///关闭基于Tcp协议的Socket对象
/// </summary>
/// <param name="socket">要关闭的Socket对象</param>
public static void Close(Socket socket)


/// <summary>
///检测本机是否联网
/// </summary>
/// <returns></returns>
public static bool IsConnectedInternet()

/// <summary>
///检测本机是否联网的连接属性
/// </summary>
public static InternetConnectionStatesType CurrentState

/// <summary>
///检测本机是否联网(互联网)
/// </summary>
/// <returns></returns>
public static bool IsOnline()

/// <summary>
///转换主机域名DNS到IP地址
/// </summary>
/// <param name="hostname">主机域名DNS</param>
/// <returns></returns>
public static string ConvertDnsToIp(string hostname)

/// <summary>
///转换主机IP地址到DNS域名
/// </summary>
/// <param name="ipAddress">主机IP地址</param>
/// <returns></returns>
public static string ConvertIpToDns(string ipAddress)

/// <summary>
///根据IP端点获取主机名称
/// </summary>
/// <param name="ipEndPoint">IP端点</param>
/// <returns></returns>
public static string GetHostName(IPEndPoint ipEndPoint)

/// <summary>
///根据主机IP地址对象获取主机名称
/// </summary>
/// <param name="ip">主机IP地址对象</param>
/// <returns></returns>
public static string GetHostName(IPAddress ip)

/// <summary>
///根据主机IP获取主机名称
/// </summary>
/// <param name="hostIP">主机IP</param>
/// <returns></returns>
public static string GetHostName(string hostIP)

/// <summary>
///得到一台机器的EndPoint端点
/// </summary>
/// <param name="entry">主机实体</param>
/// <returns></returns>
public static EndPoint GetNetworkAddressEndPoing(IPHostEntry entry)

/// <summary>
///主机名是否存在
/// </summary>
/// <param name="host">主机名</param>
/// <returns></returns>
public static bool IsHostAvailable(string host)


/// <summary>
///在主机名解析到一个IP主机实体
/// </summary>
/// <param name="hostname">主机名</param>
/// <returns></returns>
public static IPHostEntry ResolveHost(string host)

2)辅助类NetworkUtil的使用例子代码如下所示。

private void btnNetWork_Click(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("本机IP:{0} \r\n", NetworkUtil.GetLocalIP());
sb.AppendFormat("检测本机是否联网:{0} \r\n", NetworkUtil.IsConnectedInternet());
sb.AppendFormat("www.iqid.com域名IP:{0} \r\n", NetworkUtil.ConvertDnsToIp("www.iqidi.com"));
sb.AppendFormat("本机LocalHostName:{0} \r\n", NetworkUtil.LocalHostName);
sb.AppendFormat("本机局域网IP:{0} \r\n", NetworkUtil.LANIP);
sb.AppendFormat("本机广域网IP:{0} \r\n", NetworkUtil.WANIP);

Socket socket = NetworkUtil.CreateTcpSocket();
Socket udpsocket = NetworkUtil.CreateUdpSocket();
TcpListener listen = NetworkUtil.CreateTcpListener("127.0.0.1", 9900);
listen.Start(100);

MessageUtil.ShowTips(sb.ToString());
}

5、IE代理设置辅助类 ProxyHelper。

实现效果

1) 本辅助类主要是用来方便实现IE代理设置操作。

实现代码

1)辅助类提供的方法源码如下所示:

/// <summary>
///IE代理设置辅助类
/// </summary>
public class ProxyHelper
{
#region IE代理设置

/// <summary>
///让IE支持WAP
/// </summary>
public static void SetIESupportWap()

/// <summary>
///设置代理
/// </summary>
/// <param name="ProxyServer">代理服务器</param>
/// <param name="EnableProxy">设置代理可用</param>
/// <returns></returns>
public static string SetIEProxy(string ProxyServer, int EnableProxy)


#endregion

#region 其他操作

/// <summary>
///测试代理配置
/// </summary>
/// <param name="setting">代理信息</param>
/// <param name="te">测试信息</param>
public static bool TestProxy(ProxySettingEntity setting, TestEntity te)

/// <summary>
///代理设置
/// </summary>
/// <param name="request">Web请求</param>
/// <param name="Proxy">代理设置</param>
public static void SetProxySetting(WebRequest request, ProxySettingEntity Proxy)

#endregion
}

/// <summary>
///测试信息
/// </summary>
[Serializable]
public class TestEntity
{
/// <summary>
///测试网站地址
/// </summary>
public string TestUrl

/// <summary>
///测试网站Title
/// </summary>
public string TestWebTitle

/// <summary>
///Web编码
/// </summary>
public string TestWebEncoding
}

/// <summary>
///代理设置
/// </summary>
[Serializable]
public class ProxySettingEntity
{
/// <summary>
///编号
/// </summary>
public int Id

/// <summary>
///代理服务器IP
/// </summary>
public string Ip

/// <summary>
///代理服务器端口
/// </summary>
public int Port

/// <summary>
///代理用户名
/// </summary>
public string UserName

/// <summary>
///代理密码
/// </summary>
public string Password

/// <summary>
///代理类型
/// </summary>
public int ProxyType
}

2)辅助类ProxyHelper的使用例子代码如下所示

CHM帮助文档持续更新中,统一下载地址是:
http://www.iqidi.com/download/commonshelp.rar

最新公用类库DLL+XML注释文件下载地址是:
https://files.cnblogs.com/wuhuacong/WHC.OrderWater.Commons.rar