懒得勤快 8 years ago
parent
commit
dbdb2f6d9d
38 changed files with 14811 additions and 0 deletions
  1. 67 0
      Masuit.Tools.Core/Database/DataExt.cs
  2. 379 0
      Masuit.Tools.Core/Database/DataTableHelper.cs
  3. 417 0
      Masuit.Tools.Core/DateTimeExt/CCalendarData.xml
  4. 972 0
      Masuit.Tools.Core/DateTimeExt/CNCalendar.cs
  5. 162 0
      Masuit.Tools.Core/DateTimeExt/ChineseCalendar.cs
  6. 124 0
      Masuit.Tools.Core/DateTimeExt/DateTimeHelper.cs
  7. 358 0
      Masuit.Tools.Core/DateTimeExt/DateUtil.cs
  8. 442 0
      Masuit.Tools.Core/DateTimeExt/TimeHelper.cs
  9. 1547 0
      Masuit.Tools.Core/Extensions.cs
  10. 170 0
      Masuit.Tools.Core/Files/FileExt.cs
  11. 89 0
      Masuit.Tools.Core/Files/INIFile.cs
  12. 931 0
      Masuit.Tools.Core/Html/HtmlHelper.cs
  13. 1635 0
      Masuit.Tools.Core/Html/HtmlTools.cs
  14. 226 0
      Masuit.Tools.Core/Logging/LogManager.cs
  15. 20 0
      Masuit.Tools.Core/Masuit.Tools.Core.csproj
  16. 64 0
      Masuit.Tools.Core/Models/BaiduIP.cs
  17. 147 0
      Masuit.Tools.Core/Models/Email.cs
  18. 16 0
      Masuit.Tools.Core/Models/IspInfo.cs
  19. 191 0
      Masuit.Tools.Core/Models/PhysicsAddress.cs
  20. 52 0
      Masuit.Tools.Core/Models/TaobaoIP.cs
  21. 650 0
      Masuit.Tools.Core/Net/FtpClient.cs
  22. 550 0
      Masuit.Tools.Core/Net/SocketClient.cs
  23. 145 0
      Masuit.Tools.Core/NoSQL/RedisConnectionHelp.cs
  24. 990 0
      Masuit.Tools.Core/NoSQL/RedisHelper.cs
  25. 194 0
      Masuit.Tools.Core/Reflection/ReflectHelper.cs
  26. 404 0
      Masuit.Tools.Core/Reflection/ReflectionUtil.cs
  27. 1510 0
      Masuit.Tools.Core/Security/Encrypt.cs
  28. 38 0
      Masuit.Tools.Core/Security/HashEncode.cs
  29. 373 0
      Masuit.Tools.Core/Security/RSACrypt.cs
  30. 180 0
      Masuit.Tools.Core/Systems/EnumExt.cs
  31. 71 0
      Masuit.Tools.Core/Win32/WindowsCommand.cs
  32. 7 0
      Masuit.Tools.NoSQL.MongoDBClient.Core/Masuit.Tools.NoSQL.MongoDBClient.Core.csproj
  33. 789 0
      Masuit.Tools.NoSQL.MongoDBClient.Core/MongoDbClient.cs
  34. 58 0
      Masuit.Tools.NoSQL.MongoDBClient/Masuit.Tools.NoSQL.MongoDBClient.csproj
  35. 789 0
      Masuit.Tools.NoSQL.MongoDBClient/MongoDbClient.cs
  36. 36 0
      Masuit.Tools.NoSQL.MongoDBClient/Properties/AssemblyInfo.cs
  37. 11 0
      Masuit.Tools.NoSQL.MongoDBClient/app.config
  38. 7 0
      Masuit.Tools.NoSQL.MongoDBClient/packages.config

+ 67 - 0
Masuit.Tools.Core/Database/DataExt.cs

@@ -0,0 +1,67 @@
+using System;
+using System.Data;
+using System.Data.SqlClient;
+using System.Reflection;
+
+namespace Masuit.Tools.Core.Database
+{
+    /// <summary>
+    /// SqlDataReader扩展类
+    /// </summary>
+    public static class DataExt
+    {
+        /// <summary>
+        /// 根据SqlDataReader映射到实体模型
+        /// </summary>
+        /// <typeparam name="T">实体模型</typeparam>
+        /// <param name="reader">SqlDataReader</param>
+        /// <returns>映射后的实体模型</returns>
+        public static T MapEntity<T>(this SqlDataReader reader) where T : class
+        {
+            T obj = Assembly.GetAssembly(typeof(T)).CreateInstance(typeof(T).FullName) as T;
+            Type type = typeof(T);
+            PropertyInfo[] properties = type.GetProperties();
+            foreach (PropertyInfo p in properties)
+            {
+                p.SetValue(obj, reader[p.Name]);
+            }
+            return obj;
+        }
+
+        /// <summary>
+        /// 根据DataRow映射到实体模型
+        /// </summary>
+        /// <typeparam name="T">实体模型</typeparam>
+        /// <param name="row">数据行</param>
+        /// <returns>映射后的实体模型</returns>
+        public static T MapEntity<T>(this DataRow row) where T : class
+        {
+            T obj = Assembly.GetAssembly(typeof(T)).CreateInstance(typeof(T).FullName) as T;
+            Type type = typeof(T);
+            PropertyInfo[] properties = type.GetProperties();
+            foreach (PropertyInfo p in properties)
+            {
+                p.SetValue(obj, row[p.Name]);
+            }
+            return obj;
+        }
+
+        /// <summary>
+        /// 根据DataReader映射到实体模型
+        /// </summary>
+        /// <typeparam name="T">实体模型</typeparam>
+        /// <param name="dr">IDataReader</param>
+        /// <returns>映射后的实体模型</returns>
+        public static T MapEntity<T>(this IDataReader dr) where T : class
+        {
+            T obj = Assembly.GetAssembly(typeof(T)).CreateInstance(typeof(T).FullName) as T;
+            Type type = typeof(T);
+            PropertyInfo[] properties = type.GetProperties();
+            foreach (PropertyInfo p in properties)
+            {
+                p.SetValue(obj, dr[p.Name]);
+            }
+            return obj;
+        }
+    }
+}

+ 379 - 0
Masuit.Tools.Core/Database/DataTableHelper.cs

@@ -0,0 +1,379 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Data;
+using System.Reflection;
+
+namespace Masuit.Tools.Database
+{
+    /// <summary>
+    /// DataTable帮助类
+    /// </summary>
+    public static class DataTableHelper
+    {
+        /// <summary>
+        /// 给DataTable增加一个自增列
+        /// 如果DataTable 存在 identityid 字段  则 直接返回DataTable 不做任何处理
+        /// </summary>
+        /// <param name="dt">DataTable</param>
+        /// <returns>返回Datatable 增加字段 identityid </returns>
+        /// <exception cref="DuplicateNameException">The collection already has a column with the specified name. (The comparison is not case-sensitive.) </exception>
+        public static DataTable AddIdentityColumn(this DataTable dt)
+        {
+            if (!dt.Columns.Contains("identityid"))
+            {
+                dt.Columns.Add("identityid");
+                for (int i = 0; i < dt.Rows.Count; i++)
+                {
+                    dt.Rows[i]["identityid"] = (i + 1).ToString();
+                }
+            }
+            return dt;
+        }
+
+        /// <summary>
+        /// 检查DataTable 是否有数据行
+        /// </summary>
+        /// <param name="dt">DataTable</param>
+        /// <returns>是否有数据行</returns>
+        public static bool IsHaveRows(this DataTable dt)
+        {
+            if (dt?.Rows.Count > 0)
+                return true;
+
+            return false;
+        }
+
+        /// <summary>
+        /// DataTable转换成实体列表
+        /// </summary>
+        /// <typeparam name="T">实体 T </typeparam>
+        /// <param name="table">datatable</param>
+        /// <returns>强类型的数据集合</returns>
+        public static IList<T> DataTableToList<T>(this DataTable table) where T : class
+        {
+            if (!IsHaveRows(table))
+                return new List<T>();
+
+            IList<T> list = new List<T>();
+            foreach (DataRow dr in table.Rows)
+            {
+                var model = Activator.CreateInstance<T>();
+
+                foreach (DataColumn dc in dr.Table.Columns)
+                {
+                    object drValue = dr[dc.ColumnName];
+                    PropertyInfo pi = model.GetType().GetProperty(dc.ColumnName);
+
+                    if (pi != null && pi.CanWrite && (drValue != null && !Convert.IsDBNull(drValue)))
+                    {
+                        pi.SetValue(model, drValue, null);
+                    }
+                }
+                list.Add(model);
+            }
+            return list;
+        }
+
+        /// <summary>
+        /// 实体列表转换成DataTable
+        /// </summary>
+        /// <typeparam name="T">实体</typeparam>
+        /// <param name="list"> 实体列表</param>
+        /// <returns>映射为数据表</returns>
+        /// <exception cref="OverflowException">The array is multidimensional and contains more than <see cref="F:System.Int32.MaxValue" /> elements.</exception>
+        public static DataTable ListToDataTable<T>(this IList<T> list) where T : class
+        {
+            if (list == null || list.Count <= 0)
+            {
+                return null;
+            }
+            var dt = new DataTable(typeof(T).Name);
+            PropertyInfo[] myPropertyInfo = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
+            int length = myPropertyInfo.Length;
+            bool createColumn = true;
+            foreach (T t in list)
+            {
+                if (t == null)
+                {
+                    continue;
+                }
+                var row = dt.NewRow();
+                for (int i = 0; i < length; i++)
+                {
+                    PropertyInfo pi = myPropertyInfo[i];
+                    string name = pi.Name;
+                    if (createColumn)
+                    {
+                        var column = new DataColumn(name, pi.PropertyType);
+                        dt.Columns.Add(column);
+                    }
+                    row[name] = pi.GetValue(t, null);
+                }
+                if (createColumn)
+                {
+                    createColumn = false;
+                }
+                dt.Rows.Add(row);
+            }
+            return dt;
+        }
+
+        /// <summary>
+        /// 将泛型集合类转换成DataTable
+        /// </summary>
+        /// <typeparam name="T">集合项类型</typeparam>
+        /// <param name="list">集合</param>
+        /// <returns>数据集(表)</returns>
+        public static DataTable ToDataTable<T>(this IList<T> list)
+        {
+            return ToDataTable<T>(list, null);
+        }
+
+        /// <summary>
+        /// 将泛型集合类转换成DataTable
+        /// </summary>
+        /// <typeparam name="T">集合项类型</typeparam>
+        /// <param name="list">集合</param>
+        /// <param name="propertyName">需要返回的列的列名</param>
+        /// <returns>数据集(表)</returns>
+        public static DataTable ToDataTable<T>(this IList<T> list, params string[] propertyName)
+        {
+            List<string> propertyNameList = new List<string>();
+            if (propertyName != null)
+                propertyNameList.AddRange(propertyName);
+            DataTable result = new DataTable();
+            if (list.Count > 0)
+            {
+                PropertyInfo[] propertys = list[0].GetType().GetProperties();
+                propertys.ForEach(pi =>
+                {
+                    if (propertyNameList.Count == 0)
+                    {
+                        result.Columns.Add(pi.Name, pi.PropertyType);
+                    }
+                    else
+                    {
+                        if (propertyNameList.Contains(pi.Name))
+                        {
+                            result.Columns.Add(pi.Name, pi.PropertyType);
+                        }
+                    }
+                });
+                list.ForEach(item =>
+                {
+                    ArrayList tempList = new ArrayList();
+                    foreach (PropertyInfo pi in propertys)
+                    {
+                        if (propertyNameList.Count == 0)
+                        {
+                            object obj = pi.GetValue(item, null);
+                            tempList.Add(obj);
+                        }
+                        else
+                        {
+                            if (propertyNameList.Contains(pi.Name))
+                            {
+                                object obj = pi.GetValue(item, null);
+                                tempList.Add(obj);
+                            }
+                        }
+                    }
+                    object[] array = tempList.ToArray();
+                    result.LoadDataRow(array, true);
+                });
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// 根据nameList里面的字段创建一个表格,返回该表格的DataTable
+        /// </summary>
+        /// <param name="nameList">包含字段信息的列表</param>
+        /// <returns>DataTable</returns>
+        public static DataTable CreateTable(this List<string> nameList)
+        {
+            if (nameList.Count <= 0)
+                return null;
+            var myDataTable = new DataTable();
+            foreach (string columnName in nameList)
+            {
+                myDataTable.Columns.Add(columnName, typeof(string));
+            }
+            return myDataTable;
+        }
+
+        /// <summary>
+        /// 通过字符列表创建表字段,字段格式可以是:<br/>
+        /// 1) a,b,c,d,e<br/>
+        /// 2) a|int,b|string,c|bool,d|decimal<br/>
+        /// </summary>
+        /// <param name="dt"></param>
+        /// <param name="nameString">字符列表</param>
+        /// <returns>内存表</returns>
+        public static DataTable CreateTable(this DataTable dt, string nameString)
+        {
+            string[] nameArray = nameString.Split(',', ';');
+            foreach (string item in nameArray)
+            {
+                if (!string.IsNullOrEmpty(item))
+                {
+                    string[] subItems = item.Split('|');
+                    if (subItems.Length == 2)
+                    {
+                        dt.Columns.Add(subItems[0], ConvertType(subItems[1]));
+                    }
+                    else
+                    {
+                        dt.Columns.Add(subItems[0]);
+                    }
+                }
+            }
+            return dt;
+        }
+
+        /// <summary>
+        /// 根据类型名返回一个Type类型
+        /// </summary>
+        /// <param name="typeName">类型的名称</param>
+        /// <returns>Type对象</returns>
+        private static Type ConvertType(string typeName)
+        {
+            typeName = typeName.ToLower().Replace("system.", "");
+            Type newType = typeof(string);
+            switch (typeName)
+            {
+                case "boolean":
+                case "bool":
+                    newType = typeof(bool);
+                    break;
+                case "int16":
+                case "short":
+                    newType = typeof(short);
+                    break;
+                case "int32":
+                case "int":
+                    newType = typeof(int);
+                    break;
+                case "long":
+                case "int64":
+                    newType = typeof(long);
+                    break;
+                case "uint16":
+                case "ushort":
+                    newType = typeof(ushort);
+                    break;
+                case "uint32":
+                case "uint":
+                    newType = typeof(uint);
+                    break;
+                case "uint64":
+                case "ulong":
+                    newType = typeof(ulong);
+                    break;
+                case "single":
+                case "float":
+                    newType = typeof(float);
+                    break;
+
+                case "string":
+                    newType = typeof(string);
+                    break;
+                case "guid":
+                    newType = typeof(Guid);
+                    break;
+                case "decimal":
+                    newType = typeof(decimal);
+                    break;
+                case "double":
+                    newType = typeof(double);
+                    break;
+                case "datetime":
+                    newType = typeof(DateTime);
+                    break;
+                case "byte":
+                    newType = typeof(byte);
+                    break;
+                case "char":
+                    newType = typeof(char);
+                    break;
+            }
+            return newType;
+        }
+
+        /// <summary>
+        /// 获得从DataRowCollection转换成的DataRow数组
+        /// </summary>
+        /// <param name="drc">DataRowCollection</param>
+        /// <returns>DataRow数组</returns>
+        public static DataRow[] GetDataRowArray(this DataRowCollection drc)
+        {
+            int count = drc.Count;
+            DataRow[] drs = new DataRow[count];
+            for (int i = 0; i < count; i++)
+            {
+                drs[i] = drc[i];
+            }
+            return drs;
+        }
+
+        /// <summary>
+        /// 将DataRow数组转换成DataTable,注意行数组的每个元素须具有相同的数据结构,
+        /// 否则当有元素长度大于第一个元素时,抛出异常
+        /// </summary>
+        /// <param name="rows">行数组</param>
+        /// <returns>将内存行组装成内存表</returns>
+        public static DataTable GetTableFromRows(this DataRow[] rows)
+        {
+            if (rows.Length <= 0)
+            {
+                return new DataTable();
+            }
+            DataTable dt = rows[0].Table.Clone();
+            dt.DefaultView.Sort = rows[0].Table.DefaultView.Sort;
+            for (int i = 0; i < rows.Length; i++)
+            {
+                dt.LoadDataRow(rows[i].ItemArray, true);
+            }
+            return dt;
+        }
+
+        /// <summary>
+        /// 排序表的视图
+        /// </summary>
+        /// <param name="dt">原内存表</param>
+        /// <param name="sorts">排序方式</param>
+        /// <returns>排序后的内存表</returns>
+        public static DataTable SortedTable(this DataTable dt, params string[] sorts)
+        {
+            if (dt.Rows.Count > 0)
+            {
+                string tmp = "";
+                for (int i = 0; i < sorts.Length; i++)
+                {
+                    tmp += sorts[i] + ",";
+                }
+                dt.DefaultView.Sort = tmp.TrimEnd(',');
+            }
+            return dt;
+        }
+
+        /// <summary>
+        /// 根据条件过滤表的内容
+        /// </summary>
+        /// <param name="dt">原内存表</param>
+        /// <param name="condition">过滤条件</param>
+        /// <returns>过滤后的内存表</returns>
+        public static DataTable FilterDataTable(this DataTable dt, string condition)
+        {
+            if (condition.Trim().Length == 0)
+            {
+                return dt;
+            }
+            var newdt = dt.Clone();
+            DataRow[] dr = dt.Select(condition);
+            dr.ForEach(t => newdt.ImportRow(t));
+            return newdt;
+        }
+    }
+}

+ 417 - 0
Masuit.Tools.Core/DateTimeExt/CCalendarData.xml

@@ -0,0 +1,417 @@
+<?xml version="1.0" encoding="gb2312" ?>
+<HELLO>
+
+  <!-- 公历节日开始 -->
+  <AD>
+    <feast day="0101" name="元旦" sayhello="yes">
+      <hello>新年好!祝您在新的一年里身体健康,事业进步!</hello>
+      <!-- 从网站根目录算起 -->
+      <img>./img/theme/0101.gif</img>
+    </feast>
+    <feast day="0202" name="世界湿地日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0210" name="国际气象节" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0214" name="情人节" sayhello="yes">
+      <hello>祝天下有情人终成眷属!</hello>
+      <img></img>
+    </feast>
+    <feast day="0301" name="世界图书日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0303" name="全国爱耳日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0305" name="学雷锋纪念日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0308" name="妇女节" sayhello="yes">
+      <hello>妇女能顶半边天,谁说女子不如男!</hello>
+      <img></img>
+    </feast>
+    <feast day="0312" name="植树节" sayhello="yes">
+      <hello>植树造林,功德无量。</hello>
+      <img>./img/theme/0312.gif</img>
+    </feast>
+    <feast day="0314" name="国际警察日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0315" name="消费者权益日" sayhello="no">
+      <img>./img/theme/temp.gif</img>
+      <hello></hello>
+    </feast>
+    <feast day="0316" name="手拉手情系贫困地区全国行动日" sayhello="no">
+      <img>./img/theme/temp.gif</img>
+      <hello></hello>
+    </feast>
+    <feast day="0317" name="国际航海日" sayhello="no">
+      <img>./img/theme/temp.gif</img>
+      <hello></hello>
+    </feast>
+    <feast day="0318" name="全国科技人才活动日" sayhello="no">
+      <img>./img/theme/temp.gif</img>
+      <hello></hello>
+    </feast>
+    <feast day="0321" name="世界睡眠日 世界森林日 世界儿歌日 消除种族歧视国际日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0322" name="世界水日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0323" name="世界气象日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0324" name="世界防治结核病日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0401" name="愚人节" sayhello="no">
+      <img>./img/theme/temp.gif</img>
+      <hello></hello>
+    </feast>
+    <feast day="0407" name="世界卫生日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0422" name="世界地球日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0425" name="国际秘书节" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0501" name="劳动节" sayhello="yes">
+      <hello>今天是劳动节,怎么,您还在劳动吗?</hello>
+      <img>./img/theme/temp.gif</img>
+    </feast>
+    <feast day="0504" name="青年节" sayhello="yes">
+      <hello>美哉,我少年中国,与天不老!壮哉,我中国少年,与国无疆!</hello>
+      <img>./img/theme/temp.gif</img>
+    </feast>
+    <feast day="0505" name="全国碘缺乏病日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0508" name="世界红十字日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0512" name="护士节" sayhello="no">
+      <hello></hello>
+      <img>./img/theme/temp.gif</img>
+    </feast>
+    <feast day="0515" name="国际家庭日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0517" name="世界电信日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0518" name="国际博物馆日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0519" name="全国助残日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0520" name="全国学生营养日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0522" name="国际生物多样性日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0523" name="国际牛奶日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0531" name="世界无烟日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0601" name="儿童节" sayhello="yes">
+      <hello>祝您儿童节快乐!</hello>
+      <img>./img/theme/0601.gif</img>
+    </feast>
+    <feast day="0605" name="世界环境日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0606" name="全国爱眼日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0617" name="防治荒漠化和干旱日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0623" name="国际奥林匹克日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0625" name="全国土地日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0626" name="国际禁毒日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0701" name="建党节 香港回归纪念" sayhello="yes">
+      <hello>庆祝中国共产党成立_YEARS_周年!</hello>
+      <startyear>1921</startyear>
+      <img>./img/theme/temp.gif</img>
+    </feast>
+    <feast day="0707" name="七七卢沟桥事变" sayhello="yes">
+      <hello>1937年7月7日,卢沟桥事变,全面抗战开始。</hello>
+      <startyear>1937</startyear>
+      <img>./img/theme/temp.gif</img>
+    </feast>
+    <feast day="0711" name="世界人口日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0801" name="建军节" sayhello="no">
+      <hello></hello>
+      <img>./img/theme/temp.gif</img>
+    </feast>
+    <feast day="0908" name="国际扫盲日 国际新闻工作者团体日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0909" name="毛泽东逝世纪念" sayhello="yes">
+      <hello>伟大领袖毛泽东主席逝世_YEARS_周年。</hello>
+      <startyear>1976</startyear>
+      <img>./img/theme/temp.gif</img>
+    </feast>
+    <feast day="0910" name="中国教师节" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0916" name="国际臭氧层保护日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0918" name="九一八事变" sayhello="yes">
+      <img></img>
+      <hello>1931年9月18日,日本帝国主义对我国沈阳北大营的中国驻军发动武装进攻,接着对我国东北地区进行大规模武装侵略。</hello>
+    </feast>
+    <feast day="0920" name="全国爱牙日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0921" name="国际和平日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0927" name="世界旅游日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="0928" name="国际聋人日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="1001" name="国庆节" sayhello="yes">
+      <hello>热烈庆祝中华人民共和国成立_YEARS_周年!</hello>
+      <startyear>1949</startyear>
+      <img>./img/theme/1001.gif</img>
+    </feast>
+    <feast day="1001" name="老人节" sayhello="no">
+      <hello></hello>
+      <img>./img/theme/temp.gif</img>
+    </feast>
+    <feast day="1001" name="国际音乐日" sayhello="no">
+      <hello></hello>
+      <img></img>
+    </feast>
+    <feast day="1004" name="世界动物日" sayhello="no">
+      <hello></hello>
+      <img></img>
+    </feast>
+    <feast day="1008" name="全国高血压日" sayhello="no">
+      <hello></hello>
+      <img></img>
+    </feast>
+    <feast day="1009" name="世界邮政日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="1010" name="世界精神卫生日" sayhello="no">
+      <hello></hello>
+      <img></img>
+    </feast>
+    <feast day="1014" name="世界标准日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="1015" name="国际盲人节" sayhello="no">
+      <hello></hello>
+      <img></img>
+    </feast>
+    <feast day="1016" name="世界粮食日" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="1017" name="世界消除贫困日" sayhello="no">
+      <hello></hello>
+      <img></img>
+    </feast>
+    <feast day="1022" name="世界传统医药日" sayhello="no">
+      <hello></hello>
+      <img></img>
+    </feast>
+    <feast day="1024" name="联合国日" sayhello="no">
+      <hello></hello>
+      <img>./img/theme/temp.gif</img>
+    </feast>
+    <feast day="1031" name="万圣节" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="1108" name="中国记者日" sayhello="no">
+      <hello></hello>
+      <img></img>
+    </feast>
+    <feast day="1109" name="消防宣传日" sayhello="no">
+      <hello></hello>
+      <img></img>
+    </feast>
+    <feast day="1112" name="孙中山诞辰纪念" sayhello="no">
+      <hello></hello>
+      <img>./img/theme/temp.gif</img>
+    </feast>
+    <feast day="1114" name="世界糖尿病日" sayhello="no">
+      <hello></hello>
+      <img></img>
+    </feast>
+    <feast day="1117" name="国际大学生节" sayhello="no">
+      <img></img>
+      <hello></hello>
+    </feast>
+    <feast day="1201" name="世界艾滋病日" sayhello="no">
+      <hello></hello>
+      <img>./img/theme/temp.gif</img>
+    </feast>
+    <feast day="1203" name="世界残疾人日" sayhello="no">
+      <hello></hello>
+      <img></img>
+    </feast>
+    <feast day="1209" name="世界足球日" sayhello="no">
+      <hello></hello>
+      <img></img>
+    </feast>
+    <feast day="1213" name="南京大屠杀纪念日" sayhello="yes">
+      <hello>南京大屠杀_YEARS_周年。1937年12月13日,日军占领南京,进行长达6周的血腥大屠杀,杀害我军民30余万人。</hello>
+      <startyear>1937</startyear>
+      <img></img>
+    </feast>
+    <feast day="1220" name="澳门回归纪念" sayhello="no">
+      <hello></hello>
+      <img></img>
+    </feast>
+    <feast day="1224" name="圣诞节平安夜" sayhello="yes">
+      <hello>We wish you a merry christmas。</hello>
+      <img>./img/theme/1225.gif</img>
+    </feast>
+    <feast day="1225" name="圣诞节" sayhello="yes">
+      <hello>圣诞快乐。</hello>
+      <img>./img/theme/1225.gif</img>
+    </feast>
+  </AD>
+  <!-- 公历节日结束 -->
+
+  <!-- 农历节日开始 -->
+  <LUNAR>
+    <feast day="0101" name="春节" sayhello="yes">
+      <hello>恭喜发财!新年进步!万事如意!</hello>
+      <img>./img/theme/spring.gif</img>
+    </feast>
+    <feast day="0115" name="元宵节" sayhello="yes">
+      <hello>年年元夜时,花市灯如昼。月上柳梢头,人约黄昏后。</hello>
+      <img>./img/theme/temp.gif</img>
+    </feast>
+    <feast day="0505" name="端午节" sayhello="no">
+      <hello></hello>
+      <img>./img/theme/temp.gif</img>
+    </feast>
+    <feast day="0707" name="七夕情人节" sayhello="no">
+      <hello></hello>
+      <img>./img/theme/temp.gif</img>
+    </feast>
+    <feast day="0715" name="中元节" sayhello="no">
+      <hello></hello>
+      <img>./img/theme/temp.gif</img>
+    </feast>
+    <feast day="0815" name="中秋节" sayhello="yes">
+      <hello>海上升明月 天涯共此时</hello>
+      <img>./img/theme/c815.gif</img>
+    </feast>
+    <feast day="0909" name="重阳节" sayhello="yes">
+      <hello>人生易老天难老,岁岁重阳。今又重阳,战地黄花分外香。</hello>
+      <img>./img/theme/temp.gif</img>
+    </feast>
+    <feast day="1208" name="腊八节" sayhello="yes">
+      <hello>谁愿意跟我去侠客岛喝腊八粥?</hello>
+      <img>./img/theme/temp.gif</img>
+    </feast>
+    <feast day="0100" name="除夕" sayhello="yes">
+      <hello>炮竹声中一岁除,春风送暖入屠苏。千家万户瞳瞳日,总把新桃换旧符。</hello>
+      <img>./img/theme/temp.gif</img>
+    </feast>
+  </LUNAR>
+  <!-- 农历节日结束 -->
+
+  <!-- 普通日子开始 -->
+  <NORMAL>
+    <day time1="2301" time2="2359" sayhello="yes">
+      <hello>深夜了!您应该休息了。</hello>
+      <img>./img/theme/latenight.gif</img>
+    </day>
+    <day time1="1901" time2="2300" sayhello="yes">
+      <hello>晚上好!还在工作吗?</hello>
+      <img>./img/theme/night.gif</img>
+    </day>
+    <day time1="1801" time2="1900" sayhello="yes">
+      <hello>傍晚好!是时候吃晚饭了。</hello>
+      <img>./img/theme/dusk.gif</img>
+    </day>
+    <day time1="1301" time2="1800" sayhello="yes">
+      <hello>下午好!要振作精神哦!</hello>
+      <img>./img/theme/afternoon.gif</img>
+    </day>
+    <day time1="1201" time2="1300" sayhello="yes">
+      <hello>中午好!吃过午饭了吗?</hello>
+      <img>./img/theme/midday.gif</img>
+    </day>
+    <day time1="0901" time2="1200" sayhello="yes">
+      <hello>上午好!努力工作哦!</hello>
+      <img>./img/theme/ackemma.gif</img>
+    </day>
+    <day time1="0601" time2="0900" sayhello="yes">
+      <hello>早上好!休息得好吗?</hello>
+      <img>./img/theme/morning.gif</img>
+    </day>
+    <day time1="0000" time2="0600" sayhello="yes">
+      <hello>深夜了!您应该休息了。</hello>
+      <img>./img/theme/latenight.gif</img>
+    </day>
+  </NORMAL>
+  <!-- 普通日子结束 -->
+
+</HELLO>

+ 972 - 0
Masuit.Tools.Core/DateTimeExt/CNCalendar.cs

@@ -0,0 +1,972 @@
+using System;
+using System.IO;
+using System.Reflection;
+using System.Xml;
+
+namespace Masuit.Tools.DateTimeExt
+{
+    /// <summary>
+    /// 日历操作
+    /// </summary>
+    public static class CNCalendar
+    {
+        /// <summary>
+        /// 格式化日期
+        /// </summary>
+        /// <param name="m">月份</param>
+        /// <param name="d">日期</param>
+        /// <returns>x月x日</returns>
+        private static string FormatDate(int m, int d)
+        {
+            return $"{m:00}{d:00}";
+        }
+
+        /// <summary>
+        /// 从嵌入资源中读取文件内容(e.g: xml).
+        /// </summary>
+        /// <param name="fileWholeName">嵌入资源文件名,包括项目的命名空间.</param>
+        /// <returns>资源中的文件内容.</returns>
+        public static string ReadFileFromEmbedded(string fileWholeName)
+        {
+            //文件属性-生成操作-嵌入的资源
+            using (TextReader reader = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream(fileWholeName)))
+            {
+                return reader.ReadToEnd();
+            }
+        }
+
+        #region 结构、日期对象
+
+        /// <summary>
+        /// 结构、日期对象
+        /// </summary>
+        private struct structDate
+        {
+            public int year;
+            public int month;
+            public int day;
+            public bool isLeap; //是否闰月
+            public int yearCyl; //年干支
+            public int monthCyl; //月干支
+            public int dayCyl; //日干支
+        }
+
+        #endregion
+
+        #region 结构、完整的日期对象
+
+        /// <summary>
+        /// 结构、完整的日期对象
+        /// </summary>
+        public struct StructDateFullInfo
+        {
+            /// <summary>
+            /// 公历年
+            /// </summary>
+            public int Year;
+
+            /// <summary>
+            /// 公历月
+            /// </summary>
+            public int Month;
+
+            /// <summary>
+            /// 公历日
+            /// </summary>
+            public int Day;
+
+            /// <summary>
+            /// 是否闰月
+            /// </summary>
+            public bool IsLeap; //是否闰月
+
+            /// <summary>
+            /// 农历年
+            /// </summary>
+            public int Cyear; //农历年
+
+            /// <summary>
+            /// 农历年名称
+            /// </summary>
+            public string Scyear; //农历年名称
+
+            /// <summary>
+            /// 干支年
+            /// </summary>
+            public string CyearCyl; //干支年
+
+            /// <summary>
+            /// 农历月
+            /// </summary>
+            public int Cmonth; //农历月
+
+            /// <summary>
+            /// 农历月名称
+            /// </summary>
+            public string Scmonth; //农历月名称
+
+            /// <summary>
+            /// 干支月
+            /// </summary>
+            public string CmonthCyl; //干支月
+
+            /// <summary>
+            /// 农历日
+            /// </summary>
+            public int Cday; //农历日
+
+            /// <summary>
+            /// 农历日名称
+            /// </summary>
+            public string Scday; //农历日名称
+
+            /// <summary>
+            /// 干支日
+            /// </summary>
+            public string CdayCyl; //干支日
+
+            /// <summary>
+            /// 农历属象
+            /// </summary>
+            public string cnAnm;
+
+            /// <summary>
+            /// 节气
+            /// </summary>
+            public string solarterm; //节气
+
+            /// <summary>
+            /// 星期几
+            /// </summary>
+            public string DayInWeek; //星期几
+
+            /// <summary>
+            /// 节日
+            /// </summary>
+            public string Feast; //节日
+
+            /// <summary>
+            /// 完整的日期信息
+            /// </summary>
+            public string Fullinfo; //完整的日期信息
+
+            /// <summary>
+            /// 阴历节日
+            /// </summary>
+            public string cnFtvl;
+
+            /// <summary>
+            /// 阳历节日
+            /// </summary>
+            public string cnFtvs;
+
+            /// <summary>
+            /// 系统问候语
+            /// </summary>
+            public string Info; //系统问候语
+
+            /// <summary>
+            /// 主题图片
+            /// </summary>
+            public string Image; //主题图片
+
+            /// <summary>
+            /// 有特别的问候语吗
+            /// </summary>
+            public bool SayHello; //有特别的问候语吗?
+        }
+
+        #endregion
+
+        #region 私有
+
+        #region  农历月份信息
+
+        /// <summary>
+        /// 农历月份信息
+        /// </summary>
+        private static readonly int[] lunarInfo =
+        {
+            0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2,
+            0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977,
+            0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970,
+            0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950,
+            0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557,
+            0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5d0, 0x14573, 0x052d0, 0x0a9a8, 0x0e950, 0x06aa0,
+            0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0,
+            0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0, 0x195a6,
+            0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570,
+            0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0,
+            0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5,
+            0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930,
+            0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530,
+            0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45,
+            0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0
+        };
+
+        #endregion
+
+        /// <summary>
+        /// 农历月份名字
+        /// </summary>
+        private static readonly string[] cMonthName = { "", "正月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月" };
+
+        //农历日子
+        private static readonly string[] nStr1 = { "日", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十" };
+        private static readonly string[] nStr2 = { "初", "十", "廿", "卅", " " };
+        //公历月份名称
+        private static string[] monthName = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
+
+        /// <summary>
+        /// 天干
+        /// </summary>
+        private static readonly string[] gan = { "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" };
+
+        /// <summary>
+        /// 地支
+        /// </summary>
+        private static readonly string[] zhi = { "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" };
+
+        /// <summary>
+        /// 生肖
+        /// </summary>
+        private static readonly string[] animals
+            =
+            {
+                "鼠", "牛", "虎", "兔",
+                "龙", "蛇", "马", "羊",
+                "猴", "鸡", "狗", "猪"
+            };
+
+        /// <summary>
+        /// 节气
+        /// </summary>
+        private static readonly string[] solarTerm
+            =
+            {
+                "小寒", "大寒", "立春", "雨水",
+                "惊蛰", "春分", "清明", "谷雨",
+                "立夏", "小满", "芒种", "夏至",
+                "小暑", "大暑", "立秋", "处暑",
+                "白露", "秋分", "寒露", "霜降",
+                "立冬", "小雪", "大雪", "冬至"
+            };
+
+        /// <summary>
+        /// 节气对应数值?
+        /// </summary>
+        private static readonly int[] solarTermInfo =
+        {
+            0, 21208, 42467, 63836, 85337, 107014, 128867, 150921, 173149, 195551, 218072
+            , 240693, 263343, 285989, 308563, 331033, 353350, 375494, 397447, 419210, 440795
+            , 462224, 483532, 504758
+        };
+
+        #region 节日信息
+
+        private static readonly string[] lFtv = { "0101农历春节", "0202 龙抬头节", "0115 元宵节", "0505 端午节", "0707 七夕情人节", "0815 中秋节", "0909 重阳节", "1208 腊八节", "1114 李君先生生日", "1224 小年", "0100除夕" };
+        /// <summary>
+        /// 节假日信息
+        /// </summary>
+        private static readonly string[] sFtv =
+        {
+            "0101 新年元旦",
+            "0202 世界湿地日",
+            "0207 国际声援南非日",
+            "0210 国际气象节",
+            "0214 情人节",
+            "0301 国际海豹日",
+            "0303 全国爱耳日",
+            "0308 国际妇女节",
+            "0312 植树节 孙中山逝世纪念日",
+            "0314 国际警察日",
+            "0315 国际消费者权益日",
+            "0317 中国国医节 国际航海日",
+            "0321 世界森林日 消除种族歧视国际日",
+            "0321 世界儿歌日",
+            "0322 世界水日",
+            "0323 世界气象日",
+            "0324 世界防治结核病日",
+            "0325 全国中小学生安全教育日",
+            "0330 巴勒斯坦国土日",
+            "0401 愚人节 全国爱国卫生运动月(四月) 税收宣传月(四月)",
+            "0407 世界卫生日",
+            "0422 世界地球日",
+            "0423 世界图书和版权日",
+            "0424 亚非新闻工作者日",
+            "0501 国际劳动节",
+            "0504 中国五四青年节",
+            "0505 碘缺乏病防治日",
+            "0508 世界红十字日",
+            "0512 国际护士节",
+            "0515 国际家庭日",
+            "0517 世界电信日",
+            "0518 国际博物馆日",
+            "0520 全国学生营养日",
+            "0523 国际牛奶日",
+            "0531 世界无烟日",
+            "0601 国际儿童节",
+            "0605 世界环境日",
+            "0606 全国爱眼日",
+            "0617 防治荒漠化和干旱日",
+            "0623 国际奥林匹克日",
+            "0625 全国土地日",
+            "0626 国际反毒品日",
+            "0701 中国共产党建党日 世界建筑日",
+            "0702 国际体育记者日",
+            "0707 中国人民抗日战争纪念日",
+            "0711 世界人口日",
+            "0730 非洲妇女日",
+            "0801 中国建军节",
+            "0808 中国男子节(爸爸节)",
+            "0815 日本正式宣布无条件投降日",
+            "0908 国际扫盲日 国际新闻工作者日",
+            "0910 教师节",
+            "0914 世界清洁地球日",
+            "0916 国际臭氧层保护日",
+            "0918 九·一八事变纪念日",
+            "0920 全国爱牙日",
+            "0927 世界旅游日",
+            "1001 国庆节 世界音乐日 国际老人节",
+            "1001 国际音乐日",
+            "1002 国际和平与民主自由斗争日",
+            "1004 世界动物日",
+            "1008 全国高血压日",
+            "1008 世界视觉日",
+            "1009 世界邮政日 万国邮联日",
+            "1010 辛亥革命纪念日 世界精神卫生日",
+            "1013 世界保健日 国际教师节",
+            "1014 世界标准日",
+            "1015 国际盲人节(白手杖节)",
+            "1016 世界粮食日",
+            "1017 世界消除贫困日",
+            "1022 世界传统医药日",
+            "1024 联合国日 世界发展信息日",
+            "1031 世界勤俭日",
+            "1107 十月社会主义革命纪念日",
+            "1108 中国记者日",
+            "1109 全国消防安全宣传教育日",
+            "1110 世界青年节",
+            "1111 国际科学与和平周(本日所属的一周)",
+            "1112 孙中山诞辰纪念日",
+            "1114 世界糖尿病日",
+            "1117 国际大学生节 世界学生节",
+            "1121 世界问候日 世界电视日",
+            "1129 国际声援巴勒斯坦人民国际日",
+            "1201 世界艾滋病日",
+            "1203 世界残疾人日",
+            "1205 国际经济和社会发展志愿人员日",
+            "1208 国际儿童电视日",
+            "1209 世界足球日",
+            "1210 世界人权日",
+            "1212 西安事变纪念日",
+            "1213 南京大屠杀(1937年)纪念日!紧记血泪史!",
+            "1221 国际篮球日",
+            "1224 平安夜",
+            "1225 圣诞节",
+            "1226 毛主席诞辰",
+            "1229 国际生物多样性日"
+        };
+
+        #endregion
+
+        #endregion
+
+        #region 私有方法
+
+        /// <summary>
+        /// 传回农历y年的总天数
+        /// </summary>
+        /// <param name="y">公元年</param>
+        private static int GetLYearDays(int y)
+        {
+            int sum = 348;
+
+            for (int i = 0x8000; i > 0x8; i >>= 1)
+                sum += (lunarInfo[y - 1900] & i) > 0 ? 1 : 0;
+
+            return sum + GetLeapDays(y);
+        }
+
+        /// <summary>
+        /// 传回农历y年闰月的天数
+        /// </summary>
+        /// <param name="y">公元年</param>
+        private static int GetLeapDays(int y)
+        {
+            if (GetLeapMonth(y) > 0)
+                return (lunarInfo[y - 1900] & 0x10000) > 0 ? 30 : 29;
+            return 0;
+        }
+
+        /// <summary>
+        /// 传回农历y年闰哪个月 1-12 , 没闰传回 0
+        /// </summary>
+        /// <param name="y">公元年</param>
+        private static int GetLeapMonth(int y)
+        {
+            return lunarInfo[y - 1900] & 0xf;
+        }
+
+        /// <summary>
+        /// 传回农历y年m月的总天数
+        /// </summary>
+        /// <param name="y">公元年</param>
+        /// <param name="m">月份</param> 
+        private static int GetLMonthDays(int y, int m)
+        {
+            return (lunarInfo[y - 1900] & (0x10000 >> m)) > 0 ? 30 : 29;
+        }
+
+        /// <summary>
+        /// 传回农历y年的生肖
+        /// </summary>
+        /// <param name="y">公元年</param>
+        private static string AnimalsYear(int y)
+        {
+            return animals[(y - 4) % 12];
+        }
+
+        /// <summary>
+        ///传入月日的offset 传回天干地支, 0=甲子
+        /// </summary>
+        /// <param name="num">月日的偏差</param>
+        private static string Cyclical(int num)
+        {
+            return gan[num % 10] + zhi[num % 12];
+        }
+
+        /// <summary>
+        /// 传入offset 传回干支, 0=甲子
+        /// </summary>
+        /// <param name="y">公元年</param>
+        private static string cyclical(int y)
+        {
+            int num = y - 1900 + 36;
+            return Cyclical(num);
+        }
+
+        #region 得到农历日期、年月日的天干地址及是否闰月
+
+        #region  返回一个农历日期结构体
+
+        /// <summary>
+        /// 返回一个农历日期结构体
+        /// </summary>
+        /// <param name="date">日期对象</param>
+        /// <returns>农历日期结构体</returns>
+        private static structDate GetLunar(DateTime date)
+        {
+            structDate sd;
+
+            int i = 0, leap = 0, temp = 0;
+            DateTime baseDate = new DateTime(1900, 1, 31); //基准时间
+
+            int offset = (date - baseDate).Days; //与基准时间相隔天数
+
+            sd.dayCyl = offset + 40;
+            sd.monthCyl = 14;
+
+            for (i = 1900; (i < 2050) && (offset > 0); i++)
+            {
+                temp = GetLYearDays(i);
+                offset -= temp;
+                sd.monthCyl += 12;
+            }
+            if (offset < 0)
+            {
+                offset += temp;
+                i--;
+                sd.monthCyl -= 12;
+            }
+
+            sd.year = i;
+            sd.yearCyl = i - 1864;
+
+            //闰哪个月
+            leap = GetLeapMonth(i);
+            sd.isLeap = false;
+            for (i = 1; (i < 13) && (offset > 0); i++)
+            {
+                //闰月 
+                if ((leap > 0) && (i == leap + 1) && (!sd.isLeap))
+                {
+                    --i;
+                    sd.isLeap = true;
+                    temp = GetLeapDays(sd.year);
+                }
+                else
+                {
+                    temp = GetLMonthDays(sd.year, i);
+                }
+                //解除闰月 
+                if (sd.isLeap && (i == leap + 1))
+                    sd.isLeap = false;
+                offset -= temp;
+                if (!sd.isLeap)
+                    sd.monthCyl++;
+            }
+            if ((offset == 0) && (leap > 0) && (i == leap + 1))
+            {
+                if (sd.isLeap)
+                {
+                    sd.isLeap = false;
+                }
+                else
+                {
+                    sd.isLeap = true;
+                    --i;
+                    --sd.monthCyl;
+                }
+            }
+
+            if (offset < 0)
+            {
+                offset += temp;
+                --i;
+                --sd.monthCyl;
+            }
+
+            sd.month = i;
+            sd.day = offset + 1;
+
+            return sd;
+        }
+
+        #endregion
+
+        #region 传出y年m月d日对应的农历 [0].year [1].month [2].day2 [3].yearCyl [4].monCyl [5].dayCyl [6].isLeap
+
+        /// <summary>
+        /// 传出y年m月d日对应的农历[0].year [1].month [2].day2 [3].yearCyl [4].monCyl [5].dayCyl [6].isLeap
+        /// </summary>
+        /// <param name="y">年</param>
+        /// <param name="m">月</param>
+        /// <param name="d">日</param>
+        private static long[] calElement(int y, int m, int d)
+        {
+            long[] nongDate = new long[7];
+
+            int i = 0, temp = 0, leap = 0;
+            DateTime baseDate = new DateTime(1900, 1, 31);
+
+            DateTime objDate = new DateTime(y, m, d);
+            TimeSpan ts = objDate - baseDate;
+
+            long offset = (long)ts.TotalDays;
+            nongDate[5] = offset + 40;
+            nongDate[4] = 14;
+
+            for (i = 1900; (i < 2050) && (offset > 0); i++)
+            {
+                temp = GetLYearDays(i);
+                offset -= temp;
+                nongDate[4] += 12;
+            }
+            if (offset < 0)
+            {
+                offset += temp;
+                i--;
+                nongDate[4] -= 12;
+            }
+            nongDate[0] = i;
+            nongDate[3] = i - 1864;
+            leap = GetLeapMonth(i); // 闰哪个月
+            nongDate[6] = 0;
+
+            for (i = 1; (i < 13) && (offset > 0); i++)
+            {
+                // 闰月
+                if ((leap > 0) && (i == leap + 1) && (nongDate[6] == 0))
+                {
+                    --i;
+                    nongDate[6] = 1;
+                    temp = GetLeapDays((int)nongDate[0]);
+                }
+                else
+                {
+                    temp = GetLMonthDays((int)nongDate[0], i);
+                }
+
+                // 解除闰月
+                if ((nongDate[6] == 1) && (i == leap + 1))
+                    nongDate[6] = 0;
+                offset -= temp;
+                if (nongDate[6] == 0)
+                    nongDate[4]++;
+            }
+
+            if ((offset == 0) && (leap > 0) && (i == leap + 1))
+            {
+                if (nongDate[6] == 1)
+                {
+                    nongDate[6] = 0;
+                }
+                else
+                {
+                    nongDate[6] = 1;
+                    --i;
+                    --nongDate[4];
+                }
+            }
+
+            if (offset < 0)
+            {
+                offset += temp;
+                --i;
+                --nongDate[4];
+            }
+            nongDate[1] = i;
+            nongDate[2] = offset + 1;
+            return nongDate;
+        }
+
+        #endregion
+
+        #endregion
+
+        /// <summary>
+        /// 将值转成农历汉字日子
+        /// </summary>
+        /// <param name="d">农历日</param>
+        /// <returns>中文表示</returns>
+        private static string GetCDay(int d)
+        {
+            string s = "";
+
+            switch (d)
+            {
+                case 10:
+                    s = "初十";
+                    break;
+                case 20:
+                    s = "二十";
+                    break;
+                case 30:
+                    s = "三十";
+                    break;
+                default:
+                    s = nStr2[(int)Math.Floor((double)d / 10)];
+                    s += nStr1[d % 10];
+                    break;
+            }
+            return s;
+        }
+
+        /// <summary>
+        ///  某年的第n个节气为几日(从0,即小寒起算)
+        ///	n:节气下标
+        /// </summary>
+        /// <param name="y">年</param>
+        /// <param name="n">节气</param>
+        /// <returns>日期时间</returns>
+        private static DateTime GetSolarTermDay(int y, int n)
+        {
+            //按分钟起计算
+            double minutes = (525948.766245 * (y - 1900)) + solarTermInfo[n - 1];
+            //1900年1月6日:小寒 
+            DateTime baseDate = new DateTime(1900, 1, 6, 2, 5, 0);
+            DateTime veryDate = baseDate.AddMinutes(minutes);
+            return veryDate;
+            //按毫秒起计算
+            //double ms = 31556925974.7 * (y - 1900);
+            // double ms1 = solarTermInfo[n];
+            // DateTime baseDate = new DateTime(1900, 1, 6, 2, 5, 0);
+            // baseDate = baseDate.AddMilliseconds(ms);
+            // baseDate = baseDate.AddMinutes(ms1);
+        }
+
+        #endregion
+
+        #region 公有方法
+
+        #region 得到精简日期信息(不含节日)
+
+        /// <summary>
+        /// 得到精简日期信息(不含节日)
+        /// </summary>
+        /// <param name="d">待检查的日子</param>
+        /// <returns>日期信息</returns>
+        public static StructDateFullInfo GetDateTidyInfo(this DateTime d)
+        {
+            var dayinfo = new StructDateFullInfo();
+            structDate day = GetLunar(d);
+            dayinfo.IsLeap = day.isLeap;
+            dayinfo.Year = d.Year;
+            dayinfo.Cyear = day.year;
+            dayinfo.Scyear = animals[(day.year - 4) % 12];
+            dayinfo.CyearCyl = Cyclical(day.yearCyl); //干支年
+            dayinfo.Month = d.Month;
+            dayinfo.Cmonth = day.month;
+            dayinfo.Scmonth = cMonthName[day.month];
+            dayinfo.CmonthCyl = Cyclical(day.monthCyl); //干支月
+            dayinfo.Day = d.Day;
+            dayinfo.Cday = day.day;
+            dayinfo.Scday = GetCDay(day.day); //日子
+            dayinfo.CdayCyl = Cyclical(day.dayCyl); //干支日
+            switch (d.DayOfWeek)
+            {
+                case DayOfWeek.Sunday:
+                    dayinfo.DayInWeek = "星期日";
+                    break;
+                case DayOfWeek.Monday:
+                    dayinfo.DayInWeek = "星期一";
+                    break;
+                case DayOfWeek.Tuesday:
+                    dayinfo.DayInWeek = "星期二";
+                    break;
+                case DayOfWeek.Wednesday:
+                    dayinfo.DayInWeek = "星期三";
+                    break;
+                case DayOfWeek.Thursday:
+                    dayinfo.DayInWeek = "星期四";
+                    break;
+                case DayOfWeek.Friday:
+                    dayinfo.DayInWeek = "星期五";
+                    break;
+                case DayOfWeek.Saturday:
+                    dayinfo.DayInWeek = "星期六";
+                    break;
+                default:
+                    dayinfo.DayInWeek = "星期?";
+                    break;
+            }
+
+            dayinfo.Info = "";
+            dayinfo.Feast = "";
+            dayinfo.Image = "";
+            dayinfo.SayHello = false;
+
+            //节气
+            //每个月有两个节气
+            int d1 = GetSolarTermDay(d.Year, (d.Month * 2) - 1).Day;
+            int d2 = GetSolarTermDay(d.Year, d.Month * 2).Day;
+            if (dayinfo.Day == d1)
+            {
+                if (solarTerm.Length > d.Month * 2 - 2) dayinfo.solarterm = solarTerm[d.Month * 2 - 2];
+            }
+            else if (dayinfo.Day == d2)
+            {
+                dayinfo.solarterm = solarTerm[d.Month * 2 - 1];
+            }
+            else
+            {
+                dayinfo.solarterm = "";
+            }
+
+            dayinfo.Fullinfo = dayinfo.Year + "年" + dayinfo.Month + "月" + dayinfo.Day + "日";
+            dayinfo.Fullinfo += " " + dayinfo.DayInWeek;
+            dayinfo.Fullinfo += " 农历" + dayinfo.CyearCyl + "(" + dayinfo.Scyear + ")年";
+            if (dayinfo.IsLeap)
+                dayinfo.Fullinfo += "闰";
+            dayinfo.Fullinfo += dayinfo.Scmonth + dayinfo.Scday;
+            if (dayinfo.solarterm != "")
+                dayinfo.Fullinfo += " " + dayinfo.solarterm;
+
+            return dayinfo;
+        }
+
+        #endregion
+
+        #region    得到日期信息
+
+        /// <summary>
+        /// 得到日期信息
+        /// </summary>
+        /// <param name="d">待检查的日子</param>
+        /// <returns>日期信息</returns>
+        public static StructDateFullInfo GetDateInfo(this DateTime d)
+        {
+            // xml文件属性-生成操作-嵌入的资源
+            string calendarXmlData = ReadFileFromEmbedded("Core.Common" + "CCalendarData.xml");
+
+            StructDateFullInfo dayinfo = new StructDateFullInfo();
+            structDate day = GetLunar(d);
+
+            dayinfo.IsLeap = day.isLeap;
+
+            dayinfo.Year = d.Year;
+            dayinfo.Cyear = day.year;
+            dayinfo.Scyear = animals[(day.year - 4) % 12];
+            dayinfo.CyearCyl = Cyclical(day.yearCyl); //干支年
+
+            dayinfo.Month = d.Month;
+            dayinfo.Cmonth = day.month;
+            dayinfo.Scmonth = cMonthName[day.month];
+            dayinfo.CmonthCyl = Cyclical(day.monthCyl); //干支月
+
+            dayinfo.Day = d.Day;
+            dayinfo.Cday = day.day;
+            dayinfo.Scday = GetCDay(day.day); //日子
+            dayinfo.CdayCyl = Cyclical(day.dayCyl); //干支日
+
+            switch (d.DayOfWeek)
+            {
+                case DayOfWeek.Sunday:
+                    dayinfo.DayInWeek = "星期日";
+                    break;
+                case DayOfWeek.Monday:
+                    dayinfo.DayInWeek = "星期一";
+                    break;
+                case DayOfWeek.Tuesday:
+                    dayinfo.DayInWeek = "星期二";
+                    break;
+                case DayOfWeek.Wednesday:
+                    dayinfo.DayInWeek = "星期三";
+                    break;
+                case DayOfWeek.Thursday:
+                    dayinfo.DayInWeek = "星期四";
+                    break;
+                case DayOfWeek.Friday:
+                    dayinfo.DayInWeek = "星期五";
+                    break;
+                case DayOfWeek.Saturday:
+                    dayinfo.DayInWeek = "星期六";
+                    break;
+                default:
+                    dayinfo.DayInWeek = "星期?";
+                    break;
+            }
+
+            //节气
+            //每个月有两个节气
+            int d1 = GetSolarTermDay(d.Year, d.Month * 2 - 1).Day;
+            int d2 = GetSolarTermDay(d.Year, d.Month * 2).Day;
+            if (dayinfo.Day == d1)
+                dayinfo.solarterm = solarTerm[d.Month * 2 - 2];
+            else if (dayinfo.Day == d2)
+                dayinfo.solarterm = solarTerm[d.Month * 2 - 1];
+            else
+                dayinfo.solarterm = "";
+
+            //节日及问候语
+            dayinfo.Info = "";
+            dayinfo.Feast = "";
+            dayinfo.Image = "";
+            dayinfo.SayHello = false;
+            XmlDocument feastdoc = new XmlDocument();
+            feastdoc.LoadXml(calendarXmlData);
+
+            //公历
+            XmlNodeList nodeList = feastdoc.SelectNodes("descendant::AD/feast[@day='" + d.ToString("MMdd") + "']");
+            foreach (XmlNode root in nodeList)
+            {
+                dayinfo.Feast += root.Attributes["name"].InnerText + " ";
+                if (root.Attributes["sayhello"].InnerText == "yes")
+                {
+                    //需要显示节日问候语
+                    dayinfo.Info = root["hello"].InnerText;
+                    //看看是否需要计算周年
+                    if (root["startyear"] != null)
+                    {
+                        int startyear = Convert.ToInt32(root["startyear"].InnerText);
+                        dayinfo.Info = dayinfo.Info.Replace("_YEARS_", (d.Year - startyear).ToString());
+                    }
+                    dayinfo.Image = root["img"].InnerText;
+                    dayinfo.SayHello = true;
+                }
+            }
+
+            //农历
+            string smmdd = "";
+            smmdd = dayinfo.Cmonth.ToString().Length == 2 ? dayinfo.Cmonth.ToString() : "0" + dayinfo.Cmonth;
+            smmdd += dayinfo.Cday.ToString().Length == 2 ? dayinfo.Cday.ToString() : "0" + dayinfo.Cday;
+            XmlNode feast = feastdoc.SelectSingleNode("descendant::LUNAR/feast[@day='" + smmdd + "']");
+            if (feast != null)
+            {
+                dayinfo.Feast += feast.Attributes["name"].InnerText;
+
+                if (feast.Attributes["sayhello"].InnerText == "yes")
+                {
+                    //需要显示节日问候语
+                    dayinfo.Info += feast["hello"].InnerText;
+                    dayinfo.Image = feast["img"].InnerText;
+                    dayinfo.SayHello = true;
+                }
+            }
+            //普通日子或没有庆贺语
+            if (dayinfo.Info?.Length == 0)
+            {
+                feast = feastdoc.SelectSingleNode("descendant::NORMAL/day[@time1<'" + d.ToString("HHmm") + "']");
+                if (feast != null)
+                {
+                    dayinfo.Info = feast["hello"].InnerText;
+                    dayinfo.Image = feast["img"].InnerText;
+                }
+            }
+
+            dayinfo.Fullinfo = dayinfo.Year + "年" + dayinfo.Month + "月" + dayinfo.Day + "日";
+            dayinfo.Fullinfo += dayinfo.DayInWeek;
+            dayinfo.Fullinfo += " 农历" + dayinfo.CyearCyl + "[" + dayinfo.Scyear + "]年";
+            if (dayinfo.IsLeap)
+                dayinfo.Fullinfo += "闰";
+            dayinfo.Fullinfo += dayinfo.Scmonth + dayinfo.Scday;
+            if (dayinfo.solarterm != "")
+                dayinfo.Fullinfo += "  " + dayinfo.solarterm;
+
+            return dayinfo;
+        }
+
+        #endregion
+
+        /// <summary>
+        /// 获取农历
+        /// </summary>
+        /// <param name="dt">阳历日期</param>
+        public static StructDateFullInfo getChinaDate(this DateTime dt)
+        {
+            StructDateFullInfo cd = new StructDateFullInfo();
+            int year = dt.Year;
+            int month = dt.Month;
+            int date = dt.Day;
+            long[] l = calElement(year, month, date);
+            cd.Cyear = (int)l[0];
+            cd.Cmonth = (int)l[1];
+            cd.Cday = (int)l[2];
+            cd.Scyear = cyclical(year);
+            cd.cnAnm = AnimalsYear(year);
+            cd.Scmonth = nStr1[(int)l[1]];
+            cd.Scday = GetCDay((int)l[2]);
+            string smd = dt.ToString("MMdd");
+
+            string lmd = FormatDate(cd.Cmonth, cd.Cday);
+            for (int i = 0; i < solarTerm.Length; i++)
+            {
+                string s1 = GetSolarTermDay(dt.Year, i).ToString("MMdd");
+                if (s1.Equals(dt.ToString("MMdd")))
+                {
+                    cd.solarterm = solarTerm[i];
+                    break;
+                }
+            }
+            foreach (string s in sFtv)
+            {
+                string s1 = s.Substring(0, 4);
+                if (s1.Equals(smd))
+                {
+                    cd.cnFtvs = s.Substring(4, s.Length - 4);
+                    break;
+                }
+            }
+            foreach (string s in lFtv)
+            {
+                string s1 = s.Substring(0, 4);
+                if (s1.Equals(lmd))
+                {
+                    cd.cnFtvl = s.Substring(4, s.Length - 4);
+                    break;
+                }
+            }
+            dt = dt.AddDays(1);
+            year = dt.Year;
+            month = dt.Month;
+            date = dt.Day;
+            l = calElement(year, month, date);
+            lmd = FormatDate((int)l[1], (int)l[2]);
+            if (lmd.Equals("0101")) cd.cnFtvl = "除夕";
+            return cd;
+        }
+
+        #endregion
+    }
+}

+ 162 - 0
Masuit.Tools.Core/DateTimeExt/ChineseCalendar.cs

@@ -0,0 +1,162 @@
+using System;
+using System.Globalization;
+
+namespace Masuit.Tools.DateTimeExt
+{
+    /// <summary>
+    /// 中国农历年处理类用net自带类
+    /// </summary>
+    public static class ChineseCalendar
+    {
+        /// <summary>
+        /// 实例化一个  ChineseLunisolarCalendar
+        /// </summary>
+        private static ChineseLunisolarCalendar cCalendar = new ChineseLunisolarCalendar();
+
+        /// <summary>
+        /// 获取农历当前日期
+        /// </summary>
+        /// <returns>当前农历日期</returns>
+        public static string GetChineseDateTimeNow(this DateTime dt) => GetChineseDateTime(dt);
+
+        /// <summary>
+        /// 根据公历获取农历日期
+        /// </summary>
+        /// <param name="datetime">公历日期</param>
+        /// <returns>公历日期的字符串形式</returns>
+        public static string GetChineseDateTime(this DateTime datetime)
+        {
+            int lyear = cCalendar.GetYear(datetime);
+            int lmonth = cCalendar.GetMonth(datetime);
+            int lday = cCalendar.GetDayOfMonth(datetime);
+            //获取闰月, 0 则表示没有闰月
+            int leapMonth = cCalendar.GetLeapMonth(lyear);
+            bool isleap = false;
+            if (leapMonth > 0)
+            {
+                if (leapMonth == lmonth)
+                {
+                    //闰月
+                    isleap = true;
+                    lmonth--;
+                }
+                else if (lmonth > leapMonth)
+                {
+                    lmonth--;
+                }
+            }
+            return string.Concat(GetLunisolarYear(lyear), "年", isleap ? "闰" : string.Empty, GetLunisolarMonth(lmonth), "月", GetLunisolarDay(lday));
+        }
+
+        /// <summary>
+        /// 返回农历日期
+        /// </summary>
+        public static string Now => DateTime.Now.GetChineseDateTimeNow();
+
+        /// <summary>
+        /// 最大支持日期
+        /// </summary>
+        public static DateTime MaxSupportedDateTime => cCalendar.MaxSupportedDateTime;
+
+        /// <summary>
+        /// 最小支持日期
+        /// </summary>
+        public static DateTime MinSupportedDateTime { get; } = cCalendar.MinSupportedDateTime;
+
+        /// <summary>
+        /// 返回生肖
+        /// </summary>
+        /// <param name="datetime">公历日期</param>
+        /// <returns>生肖</returns>
+        public static string GetShengXiao(this DateTime datetime) => shengxiao[cCalendar.GetTerrestrialBranch(cCalendar.GetSexagenaryYear(datetime)) - 1];
+
+        #region 农历年
+
+        /// <summary>
+        /// 十天干
+        /// </summary>
+        private static string[] tiangan = { "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" };
+
+        /// <summary>
+        /// 十二地支
+        /// </summary>
+        private static string[] dizhi = { "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" };
+
+        /// <summary>
+        /// 十二生肖
+        /// </summary>
+        private static string[] shengxiao = { "鼠", "牛", "虎", "免", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪" };
+
+        /// <summary>
+        /// 返回农历天干地支年
+        /// </summary>
+        /// <param name="year">农历年</param>
+        /// <exception cref="ArgumentOutOfRangeException"></exception>
+        /// <returns>天干地支年</returns>
+        public static string GetLunisolarYear(int year)
+        {
+            if (year > 3)
+            {
+                int tgIndex = (year - 4) % 10;
+                int dzIndex = (year - 4) % 12;
+                return string.Concat(tiangan[tgIndex], dizhi[dzIndex], "[", shengxiao[dzIndex], "]");
+            }
+            throw new ArgumentOutOfRangeException("无效的年份!");
+        }
+
+        #endregion
+
+        #region 农历月
+
+        /// <summary>
+        /// 农历月
+        /// </summary>
+        private static string[] months = { "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二(腊)" };
+
+        /// <summary>
+        /// 返回农历月
+        /// </summary>
+        /// <param name="month">月份</param>
+        /// <exception cref="ArgumentOutOfRangeException"></exception>
+        /// <returns>农历月</returns>
+        public static string GetLunisolarMonth(int month)
+        {
+            if (month < 13 && month > 0)
+            {
+                return months[month - 1];
+            }
+            throw new ArgumentOutOfRangeException("无效的月份!");
+        }
+
+        #endregion
+
+        #region 农历日
+        private static string[] days1 = { "初", "十", "廿", "三" };
+
+        /// <summary>
+        /// 日
+        /// </summary>
+        private static string[] days = { "一", "二", "三", "四", "五", "六", "七", "八", "九", "十" };
+
+        /// <summary>
+        /// 返回农历日
+        /// </summary>
+        /// <param name="day">阳历日</param>
+        /// <exception cref="ArgumentOutOfRangeException"></exception>
+        /// <returns>农历日</returns>
+        public static string GetLunisolarDay(int day)
+        {
+            if (day > 0 && day < 32)
+            {
+                if (day != 20 && day != 30)
+                {
+                    return string.Concat(days1[(day - 1) / 10], days[(day - 1) % 10]);
+                }
+                return string.Concat(days[(day - 1) / 10], days1[1]);
+            }
+            throw new ArgumentOutOfRangeException("无效的日!");
+        }
+
+        #endregion
+    }
+}

+ 124 - 0
Masuit.Tools.Core/DateTimeExt/DateTimeHelper.cs

@@ -0,0 +1,124 @@
+using System;
+using System.Globalization;
+using System.Runtime.InteropServices;
+
+namespace Masuit.Tools.DateTimeExt
+{
+    /// <summary>
+    /// 日期时间帮助类
+    /// </summary>
+    public static class DateTimeHelper
+    {
+        /// <summary>
+        /// 获取某一年有多少周
+        /// </summary>
+        /// <param name="_"></param>
+        /// <param name="year">年份</param>
+        /// <returns>该年周数</returns>
+        public static int GetWeekAmount(this DateTime _, int year)
+        {
+            var end = new System.DateTime(year, 12, 31); //该年最后一天
+            var gc = new GregorianCalendar();
+            return gc.GetWeekOfYear(end, CalendarWeekRule.FirstDay, DayOfWeek.Monday); //该年星期数
+        }
+
+        /// <summary>
+        /// 返回年度第几个星期   默认星期日是第一天
+        /// </summary>
+        /// <param name="date">时间</param>
+        /// <returns>第几周</returns>
+        public static int WeekOfYear(this DateTime date)
+        {
+            var gc = new GregorianCalendar();
+            return gc.GetWeekOfYear(date, CalendarWeekRule.FirstDay, DayOfWeek.Sunday);
+        }
+
+        /// <summary>
+        /// 返回年度第几个星期
+        /// </summary>
+        /// <param name="date">时间</param>
+        /// <param name="week">一周的开始日期</param>
+        /// <returns>第几周</returns>
+        public static int WeekOfYear(this DateTime date, DayOfWeek week)
+        {
+            var gc = new GregorianCalendar();
+            return gc.GetWeekOfYear(date, CalendarWeekRule.FirstDay, week);
+        }
+
+        /// <summary>
+        /// 得到一年中的某周的起始日和截止日
+        /// 年 nYear
+        /// 周数 nNumWeek
+        /// 周始 out dtWeekStart
+        /// 周终 out dtWeekeEnd
+        /// </summary>
+        /// <param name="_"></param>
+        /// <param name="nYear">年份</param>
+        /// <param name="nNumWeek">第几周</param>
+        /// <param name="dtWeekStart">开始日期</param>
+        /// <param name="dtWeekeEnd">结束日期</param>
+        public static void GetWeekTime(this DateTime _, int nYear, int nNumWeek, out DateTime dtWeekStart, out DateTime dtWeekeEnd)
+        {
+            var dt = new DateTime(nYear, 1, 1);
+            dt += new TimeSpan((nNumWeek - 1) * 7, 0, 0, 0);
+            dtWeekStart = dt.AddDays(-(int)dt.DayOfWeek + (int)DayOfWeek.Monday);
+            dtWeekeEnd = dt.AddDays((int)DayOfWeek.Saturday - (int)dt.DayOfWeek + 1);
+        }
+
+        /// <summary>
+        /// 得到一年中的某周的起始日和截止日    周一到周五  工作日
+        /// </summary>
+        /// <param name="_"></param>
+        /// <param name="nYear">年份</param>
+        /// <param name="nNumWeek">第几周</param>
+        /// <param name="dtWeekStart">开始日期</param>
+        /// <param name="dtWeekeEnd">结束日期</param>
+        public static void GetWeekWorkTime(this DateTime _, int nYear, int nNumWeek, out System.DateTime dtWeekStart, out System.DateTime dtWeekeEnd)
+        {
+            var dt = new DateTime(nYear, 1, 1);
+            dt += new TimeSpan((nNumWeek - 1) * 7, 0, 0, 0);
+            dtWeekStart = dt.AddDays(-(int)dt.DayOfWeek + (int)DayOfWeek.Monday);
+            dtWeekeEnd = dt.AddDays((int)DayOfWeek.Saturday - (int)dt.DayOfWeek + 1).AddDays(-2);
+        }
+
+        #region P/Invoke 设置本地时间
+
+        [DllImport("kernel32.dll")]
+        private static extern bool SetLocalTime(ref SYSTEMTIME time);
+
+        [StructLayout(LayoutKind.Sequential)]
+        private struct SYSTEMTIME
+        {
+            public short year;
+            public short month;
+            public short dayOfWeek;
+            public short day;
+            public short hour;
+            public short minute;
+            public short second;
+            public short milliseconds;
+        }
+
+        /// <summary>
+        /// 设置本地计算机时间
+        /// </summary>
+        /// <param name="dt">DateTime对象</param>
+        public static void SetLocalTime(this DateTime dt)
+        {
+            SYSTEMTIME st;
+
+            st.year = (short)dt.Year;
+            st.month = (short)dt.Month;
+            st.dayOfWeek = (short)dt.DayOfWeek;
+            st.day = (short)dt.Day;
+            st.hour = (short)dt.Hour;
+            st.minute = (short)dt.Minute;
+            st.second = (short)dt.Second;
+            st.milliseconds = (short)dt.Millisecond;
+
+            SetLocalTime(ref st);
+        }
+
+        #endregion
+    }
+}

+ 358 - 0
Masuit.Tools.Core/DateTimeExt/DateUtil.cs

@@ -0,0 +1,358 @@
+using System;
+using Masuit.Tools.Logging;
+
+namespace Masuit.Tools.DateTimeExt
+{
+    /// <summary>
+    /// 日期操作工具类
+    /// </summary>
+    public static class DateUtil
+    {
+        /// <summary>
+        /// 返回相对于当前时间的相对天数
+        /// </summary>
+        /// <param name="dt"></param>
+        /// <param name="relativeday">相对天数</param>
+        public static string GetDateTime(this DateTime dt, int relativeday)
+        {
+            return dt.AddDays(relativeday).ToString("yyyy-MM-dd HH:mm:ss");
+        }
+
+        /// <summary>
+        /// 返回标准时间格式string
+        /// </summary>
+        public static string GetDateTimeF(this DateTime dt) => dt.ToString("yyyy-MM-dd HH:mm:ss:fffffff");
+
+        /// <summary>
+        /// 返回标准时间 
+        /// </summary>
+        /// <param name="fDateTime">日期时间字符串</param>
+        /// <param name="formatStr">格式</param>
+        public static string GetStandardDateTime(this string fDateTime, string formatStr)
+        {
+            if (fDateTime == "0000-0-0 0:00:00")
+            {
+                return fDateTime;
+            }
+            var s = Convert.ToDateTime(fDateTime);
+            return s.ToString(formatStr);
+        }
+
+        /// <summary>
+        /// 返回标准时间 yyyy-MM-dd HH:mm:ss
+        /// </summary>
+        /// <param name="fDateTime">日期时间字符串</param>
+        public static string GetStandardDateTime(this string fDateTime)
+        {
+            return GetStandardDateTime(fDateTime, "yyyy-MM-dd HH:mm:ss");
+        }
+
+        /// <summary>
+        /// 获取该时间相对于1970-01-01 00:00:00的秒数
+        /// </summary>
+        /// <param name="dt"></param>
+        /// <returns></returns>
+        public static double GetTotalSeconds(this DateTime dt) => (dt - DateTime.Parse("1970-01-01 00:00:00")).TotalSeconds;
+
+        /// <summary>
+        /// 获取该时间相对于1970-01-01 00:00:00的毫秒数
+        /// </summary>
+        /// <param name="dt"></param>
+        /// <returns></returns>
+        public static double GetTotalMilliseconds(this DateTime dt) => (dt - DateTime.Parse("1970-01-01 00:00:00")).TotalMilliseconds;
+
+        /// <summary>
+        /// 获取该时间相对于1970-01-01 00:00:00的分钟数
+        /// </summary>
+        /// <param name="dt"></param>
+        /// <returns></returns>
+        public static double GetTotalMinutes(this DateTime dt) => (dt - DateTime.Parse("1970-01-01 00:00:00")).TotalMinutes;
+
+        /// <summary>
+        /// 获取该时间相对于1970-01-01 00:00:00的小时数
+        /// </summary>
+        /// <param name="dt"></param>
+        /// <returns></returns>
+        public static double GetTotalHours(this DateTime dt) => (dt - DateTime.Parse("1970-01-01 00:00:00")).TotalHours;
+
+        /// <summary>
+        /// 获取该时间相对于1970-01-01 00:00:00的天数
+        /// </summary>
+        /// <param name="dt"></param>
+        /// <returns></returns>
+        public static double GetTotalDays(this DateTime dt) => (dt - DateTime.Parse("1970-01-01 00:00:00")).TotalDays;
+
+        /// <summary>
+        /// 返回本年有多少天
+        /// </summary>
+        /// <param name="_"></param>
+        /// <param name="iYear">年份</param>
+        /// <returns>本年的天数</returns>
+        public static int GetDaysOfYear(this DateTime _, int iYear)
+        {
+            int cnt;
+            if (IsRuYear(iYear))
+            {
+                //闰年多 1 天 即:2 月为 29 天
+                cnt = 366;
+            }
+            else
+            {
+                //非闰年少1天 即:2 月为 28 天
+                cnt = 365;
+            }
+            return cnt;
+        }
+
+        /// <summary>本年有多少天</summary>
+        /// <param name="dt">日期</param>
+        /// <returns>本天在当年的天数</returns>
+        public static int GetDaysOfYear(this DateTime dt)
+        {
+            //取得传入参数的年份部分,用来判断是否是闰年
+            int n = dt.Year;
+            if (IsRuYear(n))
+            {
+                //闰年多 1 天 即:2 月为 29 天
+                return 366;
+            }
+            else
+            {
+                //--非闰年少1天 即:2 月为 28 天
+                return 365;
+            }
+        }
+
+        /// <summary>本月有多少天</summary>
+        /// <param name="_"></param>
+        /// <param name="iYear">年</param>
+        /// <param name="month">月</param>
+        /// <returns>天数</returns>
+        public static int GetDaysOfMonth(this DateTime _, int iYear, int month)
+        {
+            int days = 0;
+            switch (month)
+            {
+                case 1:
+                    days = 31;
+                    break;
+                case 2:
+                    if (IsRuYear(iYear))
+                    {
+                        //闰年多 1 天 即:2 月为 29 天
+                        days = 29;
+                    }
+                    else
+                    {
+                        //--非闰年少1天 即:2 月为 28 天
+                        days = 28;
+                    }
+
+                    break;
+                case 3:
+                    days = 31;
+                    break;
+                case 4:
+                    days = 30;
+                    break;
+                case 5:
+                    days = 31;
+                    break;
+                case 6:
+                    days = 30;
+                    break;
+                case 7:
+                case 8:
+                    days = 31;
+                    break;
+                case 9:
+                    days = 30;
+                    break;
+                case 10:
+                    days = 31;
+                    break;
+                case 11:
+                    days = 30;
+                    break;
+                case 12:
+                    days = 31;
+                    break;
+            }
+            return days;
+        }
+
+        /// <summary>本月有多少天</summary>
+        /// <param name="dt">日期</param>
+        /// <returns>天数</returns>
+        public static int GetDaysOfMonth(this DateTime dt)
+        {
+            //--------------------------------//
+            //从dt中取得当前的年,月信息  --//
+            //--------------------------------//
+            int month, days = 0;
+            var year = dt.Year;
+            month = dt.Month;
+
+            //--利用年月信息,得到当前月的天数信息。
+            switch (month)
+            {
+                case 1:
+                    days = 31;
+                    break;
+                case 2:
+                    if (IsRuYear(year))
+                    {
+                        //闰年多 1 天 即:2 月为 29 天
+                        days = 29;
+                    }
+                    else
+                    {
+                        //--非闰年少1天 即:2 月为 28 天
+                        days = 28;
+                    }
+
+                    break;
+                case 3:
+                    days = 31;
+                    break;
+                case 4:
+                    days = 30;
+                    break;
+                case 5:
+                    days = 31;
+                    break;
+                case 6:
+                    days = 30;
+                    break;
+                case 7:
+                    days = 31;
+                    break;
+                case 8:
+                    days = 31;
+                    break;
+                case 9:
+                    days = 30;
+                    break;
+                case 10:
+                    days = 31;
+                    break;
+                case 11:
+                    days = 30;
+                    break;
+                case 12:
+                    days = 31;
+                    break;
+            }
+
+            return days;
+        }
+
+        /// <summary>返回当前日期的星期名称</summary>
+        /// <param name="idt">日期</param>
+        /// <returns>星期名称</returns>
+        public static string GetWeekNameOfDay(this DateTime idt)
+        {
+            string week = "";
+
+            var dt = idt.DayOfWeek.ToString();
+            switch (dt)
+            {
+                case "Mondy":
+                    week = "星期一";
+                    break;
+                case "Tuesday":
+                    week = "星期二";
+                    break;
+                case "Wednesday":
+                    week = "星期三";
+                    break;
+                case "Thursday":
+                    week = "星期四";
+                    break;
+                case "Friday":
+                    week = "星期五";
+                    break;
+                case "Saturday":
+                    week = "星期六";
+                    break;
+                case "Sunday":
+                    week = "星期日";
+                    break;
+            }
+            return week;
+        }
+
+        /// <summary>返回当前日期的星期编号</summary>
+        /// <param name="idt">日期</param>
+        /// <returns>星期数字编号</returns>
+        public static string GetWeekNumberOfDay(this DateTime idt)
+        {
+            string week = "";
+
+            var dt = idt.DayOfWeek.ToString();
+            switch (dt)
+            {
+                case "Mondy":
+                    week = "1";
+                    break;
+                case "Tuesday":
+                    week = "2";
+                    break;
+                case "Wednesday":
+                    week = "3";
+                    break;
+                case "Thursday":
+                    week = "4";
+                    break;
+                case "Friday":
+                    week = "5";
+                    break;
+                case "Saturday":
+                    week = "6";
+                    break;
+                case "Sunday":
+                    week = "7";
+                    break;
+            }
+            return week;
+        }
+
+        /// <summary>判断当前年份是否是闰年,私有函数</summary>
+        /// <param name="iYear">年份</param>
+        /// <returns>是闰年:True ,不是闰年:False</returns>
+        private static bool IsRuYear(int iYear)
+        {
+            //形式参数为年份
+            //例如:2003
+            var n = iYear;
+
+            if ((n % 400 == 0) || (n % 4 == 0 && n % 100 != 0))
+            {
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// 判断是否为合法日期,必须大于1800年1月1日
+        /// </summary>
+        /// <param name="strDate">输入日期字符串</param>
+        /// <returns>True/False</returns>
+        public static bool IsDateTime(this string strDate)
+        {
+            try
+            {
+                DateTime oDate = DateTime.Parse(strDate);
+                if (oDate.CompareTo(DateTime.Parse("1800-1-1")) > 0) return true;
+                return false;
+            }
+            catch (Exception e)
+            {
+                return false;
+            }
+        }
+    }
+}

+ 442 - 0
Masuit.Tools.Core/DateTimeExt/TimeHelper.cs

@@ -0,0 +1,442 @@
+using System;
+using System.Globalization;
+using Masuit.Tools.Logging;
+
+namespace Masuit.Tools.DateTimeExt
+{
+    /// <summary>
+    /// 时间相关操作帮助类
+    /// </summary>
+    public static class TimeHelper
+    {
+        #region 返回每月的第一天和最后一天
+
+        /// <summary>
+        ///  返回每月的第一天和最后一天
+        /// </summary>
+        /// <param name="_"></param>
+        /// <param name="month">月份</param>
+        /// <param name="firstDay">第一天</param>
+        /// <param name="lastDay">最后一天</param>
+        public static void ReturnDateFormat(this DateTime _, int month, out string firstDay, out string lastDay)
+        {
+            int year = DateTime.Now.Year + month / 12;
+            if (month != 12) month %= 12;
+            switch (month)
+            {
+                case 1:
+                    firstDay = DateTime.Now.ToString($"{year}-0{month}-01");
+                    lastDay = DateTime.Now.ToString($"{year}-0{month}-31");
+                    break;
+                case 2:
+                    firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
+                    if (DateTime.IsLeapYear(DateTime.Now.Year)) lastDay = DateTime.Now.ToString(year + "-0" + month + "-29");
+                    else lastDay = DateTime.Now.ToString(year + "-0" + month + "-28");
+                    break;
+                case 3:
+                    firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
+                    lastDay = DateTime.Now.ToString("yyyy-0" + month + "-31");
+                    break;
+                case 4:
+                    firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
+                    lastDay = DateTime.Now.ToString(year + "-0" + month + "-30");
+                    break;
+                case 5:
+                    firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
+                    lastDay = DateTime.Now.ToString(year + "-0" + month + "-31");
+                    break;
+                case 6:
+                    firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
+                    lastDay = DateTime.Now.ToString(year + "-0" + month + "-30");
+                    break;
+                case 7:
+                    firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
+                    lastDay = DateTime.Now.ToString(year + "-0" + month + "-31");
+                    break;
+                case 8:
+                    firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
+                    lastDay = DateTime.Now.ToString(year + "-0" + month + "-31");
+                    break;
+                case 9:
+                    firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
+                    lastDay = DateTime.Now.ToString(year + "-0" + month + "-30");
+                    break;
+                case 10:
+                    firstDay = DateTime.Now.ToString(year + "-" + month + "-01");
+                    lastDay = DateTime.Now.ToString(year + "-" + month + "-31");
+                    break;
+                case 11:
+                    firstDay = DateTime.Now.ToString(year + "-" + month + "-01");
+                    lastDay = DateTime.Now.ToString(year + "-" + month + "-30");
+                    break;
+                default:
+                    firstDay = DateTime.Now.ToString(year + "-" + month + "-01");
+                    lastDay = DateTime.Now.ToString(year + "-" + month + "-31");
+                    break;
+            }
+        }
+
+        #endregion
+
+        #region  将时间格式化成 年月日 的形式,如果时间为null,返回当前系统时间
+
+        /// <summary>
+        /// 将时间格式化成 年月日 的形式,如果时间为null,返回当前系统时间
+        /// </summary>
+        /// <param name="dt">年月日分隔符</param>
+        /// <param name="separator">分隔符</param>
+        /// <returns>xxxx年xx月xx日</returns>
+        public static string GetFormatDate(this DateTime dt, char separator)
+        {
+            if (dt != null && !dt.Equals(DBNull.Value))
+            {
+                string tem = $"yyyy{separator}MM{separator}dd";
+                return dt.ToString(tem);
+            }
+            return GetFormatDate(DateTime.Now, separator);
+        }
+
+        #endregion
+
+        #region 将时间格式化成 时分秒 的形式,如果时间为null,返回当前系统时间
+
+        /// <summary>
+        /// 将时间格式化成 时分秒 的形式,如果时间为null,返回当前系统时间
+        /// </summary>
+        /// <param name="dt">当前日期时间对象</param>
+        /// <param name="separator">分隔符</param>
+        /// <returns> xx时xx分xx秒 </returns>
+        public static string GetFormatTime(this DateTime dt, char separator)
+        {
+            if (dt != null && !dt.Equals(DBNull.Value))
+            {
+                string tem = string.Format("hh{0}mm{1}ss", separator, separator);
+                return dt.ToString(tem);
+            }
+            return GetFormatDate(DateTime.Now, separator);
+        }
+
+        #endregion
+
+        #region  把秒转换成分钟
+
+        /// <summary>
+        /// 把秒转换成分钟
+        /// </summary>
+        /// <param name="_"></param>
+        /// <param name="second">秒数</param>
+        /// <returns>分钟数</returns>
+        public static int SecondToMinute(this DateTime _, int second)
+        {
+            decimal mm = second / (decimal)60;
+            return Convert.ToInt32(Math.Ceiling(mm));
+        }
+
+        #endregion
+
+        #region 返回某年某月最后一天
+
+        /// <summary>
+        /// 返回某年某月最后一天
+        /// </summary>
+        /// <param name="_"></param>
+        /// <param name="year">年份</param>
+        /// <param name="month">月份</param>
+        /// <returns>日</returns>
+        public static int GetMonthLastDate(this DateTime _, int year, int month)
+        {
+            DateTime lastDay = new DateTime(year, month, new GregorianCalendar().GetDaysInMonth(year, month));
+            int day = lastDay.Day;
+            return day;
+        }
+
+        #endregion
+
+        #region 获得两个日期的间隔
+
+        /// <summary>
+        /// 获得两个日期的间隔
+        /// </summary>
+        /// <param name="dateTime1">日期一。</param>
+        /// <param name="dateTime2">日期二。</param>
+        /// <returns>日期间隔TimeSpan。</returns>
+        /// <exception cref="OverflowException">The return value is less than <see cref="F:System.TimeSpan.MinValue" /> or greater than <see cref="F:System.TimeSpan.MaxValue" />. </exception>
+        public static TimeSpan DateDiff2(this DateTime dateTime1, DateTime dateTime2)
+        {
+            TimeSpan ts1 = new TimeSpan(dateTime1.Ticks);
+            TimeSpan ts2 = new TimeSpan(dateTime2.Ticks);
+            TimeSpan ts = ts1.Subtract(ts2).Duration();
+            return ts;
+        }
+
+        #endregion
+
+        #region 格式化日期时间
+
+        /// <summary>
+        /// 格式化日期时间
+        /// </summary>
+        /// <param name="dateTime1">日期时间</param>
+        /// <param name="dateMode">显示模式</param>
+        /// <returns>0-9种模式的日期</returns>
+        public static string FormatDate(this DateTime dateTime1, string dateMode)
+        {
+            switch (dateMode)
+            {
+                case "0": return dateTime1.ToString("yyyy-MM-dd");
+                case "1": return dateTime1.ToString("yyyy-MM-dd HH:mm:ss");
+                case "2": return dateTime1.ToString("yyyy/MM/dd");
+                case "3": return dateTime1.ToString("yyyy年MM月dd日");
+                case "4": return dateTime1.ToString("MM-dd");
+                case "5": return dateTime1.ToString("MM/dd");
+                case "6": return dateTime1.ToString("MM月dd日");
+                case "7": return dateTime1.ToString("yyyy-MM");
+                case "8": return dateTime1.ToString("yyyy/MM");
+                case "9": return dateTime1.ToString("yyyy年MM月");
+                default: return dateTime1.ToString(CultureInfo.CurrentCulture);
+            }
+        }
+
+        #endregion
+
+        #region 得到随机日期
+
+        /// <summary>
+        /// 得到随机日期
+        /// </summary>
+        /// <param name="time1">起始日期</param>
+        /// <param name="time2">结束日期</param>
+        /// <returns>间隔日期之间的 随机日期</returns>
+        public static DateTime GetRandomTime(this DateTime time1, DateTime time2)
+        {
+            Random random = new Random();
+            DateTime minTime;
+            TimeSpan ts = new TimeSpan(time1.Ticks - time2.Ticks);
+            // 获取两个时间相隔的秒数
+            double dTotalSecontds = ts.TotalSeconds;
+            int iTotalSecontds;
+            if (dTotalSecontds > int.MaxValue) iTotalSecontds = int.MaxValue;
+            else if (dTotalSecontds < int.MinValue) iTotalSecontds = int.MinValue;
+            else iTotalSecontds = (int)dTotalSecontds;
+            if (iTotalSecontds > 0)
+            {
+                minTime = time2;
+            }
+            else if (iTotalSecontds < 0)
+            {
+                minTime = time1;
+            }
+            else
+            {
+                return time1;
+            }
+            int maxValue = iTotalSecontds;
+            if (iTotalSecontds <= int.MinValue) maxValue = int.MinValue + 1;
+            int i = random.Next(Math.Abs(maxValue));
+            return minTime.AddSeconds(i);
+        }
+
+        #endregion
+
+        #region Rss日期时间转换,将时间全部转换为GMT时间
+
+        /// <summary> 
+        /// Rss日期时间转换,将时间全部转换为GMT时间 
+        /// </summary> 
+        /// <param name="strDateTime">Rss中读取的时间</param> 
+        /// <returns>处理后的标准时间格式</returns> 
+        public static string DateConvert(this string strDateTime)
+        {
+            strDateTime = strDateTime.Replace("+0000", "GMT");
+            strDateTime = strDateTime.Replace("+0100", "GMT");
+            strDateTime = strDateTime.Replace("+0200", "GMT");
+            strDateTime = strDateTime.Replace("+0300", "GMT");
+            strDateTime = strDateTime.Replace("+0400", "GMT");
+            strDateTime = strDateTime.Replace("+0500", "GMT");
+            strDateTime = strDateTime.Replace("+0600", "GMT");
+            strDateTime = strDateTime.Replace("+0700", "GMT");
+            strDateTime = strDateTime.Replace("+0800", "GMT");
+            strDateTime = strDateTime.Replace("-0000", "GMT");
+            strDateTime = strDateTime.Replace("-0100", "GMT");
+            strDateTime = strDateTime.Replace("-0200", "GMT");
+            strDateTime = strDateTime.Replace("-0300", "GMT");
+            strDateTime = strDateTime.Replace("-0400", "GMT");
+            strDateTime = strDateTime.Replace("-0500", "GMT");
+            strDateTime = strDateTime.Replace("-0600", "GMT");
+            strDateTime = strDateTime.Replace("-0700", "GMT");
+            strDateTime = strDateTime.Replace("-0800", "GMT");
+            DateTime dt = DateTime.Parse(strDateTime, null, DateTimeStyles.AdjustToUniversal);
+            return dt.ToString();
+        }
+
+        #endregion
+
+        #region 时间相关操作类
+
+        /// <summary>
+        /// 获得一段时间内有多少小时
+        /// </summary>
+        /// <param name="dtStar">起始时间</param>
+        /// <param name="dtEnd">终止时间</param>
+        /// <returns>小时差</returns>
+        public static string GetTimeDelay(this DateTime dtStar, DateTime dtEnd)
+        {
+            long lTicks = (dtEnd.Ticks - dtStar.Ticks) / 10000000;
+            string sTemp = (lTicks / 3600).ToString().PadLeft(2, '0') + ":";
+            sTemp += (lTicks % 3600 / 60).ToString().PadLeft(2, '0') + ":";
+            sTemp += (lTicks % 3600 % 60).ToString().PadLeft(2, '0');
+            return sTemp;
+        }
+
+        /// <summary>
+        /// 获得8位时间整型数字
+        /// </summary>
+        /// <param name="dt">当前的日期时间对象</param>
+        /// <returns>8位时间整型数字</returns>
+        public static string GetDateString(this DateTime dt)
+        {
+            return dt.Year + dt.Month.ToString().PadLeft(2, '0') + dt.Day.ToString().PadLeft(2, '0');
+        }
+
+        #endregion
+
+        #region 返回时间差
+
+        /// <summary>
+        /// 返回时间差
+        /// </summary>
+        /// <param name="dateTime1">时间1</param>
+        /// <param name="dateTime2">时间2</param>
+        /// <returns>时间差</returns>
+        public static string DateDiff(this DateTime dateTime1, DateTime dateTime2)
+        {
+            string dateDiff = null;
+            try
+            {
+                TimeSpan ts = dateTime2 - dateTime1;
+                if (ts.Days >= 1)
+                {
+                    dateDiff = dateTime1.Month + "月" + dateTime1.Day + "日";
+                }
+                else
+                {
+                    if (ts.Hours > 1) dateDiff = ts.Hours + "小时前";
+                    else dateDiff = ts.Minutes + "分钟前";
+                }
+            }
+            catch (Exception e)
+            {
+                LogManager.Error(e);
+            }
+            return dateDiff;
+        }
+
+        /// <summary>
+        /// 时间差
+        /// </summary>
+        /// <param name="beginTime">开始时间</param>
+        /// <param name="endTime">结束时间</param>
+        /// <returns>时间差</returns>
+        public static string GetDiffTime(this DateTime beginTime, DateTime endTime)
+        {
+            int i = 0;
+            return GetDiffTime(beginTime, endTime, ref i);
+        }
+
+        /// <summary>
+        /// 计算2个时间差
+        /// </summary>
+        /// <param name="beginTime">开始时间</param>
+        /// <param name="endTime">结束时间</param>
+        /// <param name="mindTime">中间的时间</param>
+        /// <returns>时间差</returns>
+        public static string GetDiffTime(this DateTime beginTime, DateTime endTime, ref int mindTime)
+        {
+            string strResout = string.Empty;
+            //获得2时间的时间间隔秒计算
+            TimeSpan span = endTime.Subtract(beginTime);
+            int iTatol = Convert.ToInt32(span.TotalSeconds);
+            int iMinutes = 1 * 60;
+            int iHours = iMinutes * 60;
+            int iDay = iHours * 24;
+            int iMonth = iDay * 30;
+            int iYear = iMonth * 12;
+
+            //提醒时间,到了返回1,否则返回0
+            if (mindTime > iTatol && iTatol > 0) mindTime = 1;
+            else mindTime = 0;
+
+            if (iTatol > iYear)
+            {
+                strResout += iTatol / iYear + "年";
+                iTatol %= iYear; //剩余
+            }
+            if (iTatol > iMonth)
+            {
+                strResout += iTatol / iMonth + "月";
+                iTatol %= iMonth;
+            }
+            if (iTatol > iDay)
+            {
+                strResout += iTatol / iDay + "天";
+                iTatol %= iDay;
+            }
+            if (iTatol > iHours)
+            {
+                strResout += iTatol / iHours + "小时";
+                iTatol %= iHours;
+            }
+            if (iTatol > iMinutes)
+            {
+                strResout += iTatol / iMinutes + "分";
+                iTatol %= iMinutes;
+            }
+            strResout += iTatol + "秒";
+            return strResout;
+        }
+
+        #endregion
+
+        #region 时间其他转换静态方法
+
+        /// <summary>
+        /// C#的时间到Javascript的时间的转换
+        /// </summary>
+        /// <param name="TheDate">C#的时间</param>
+        /// <returns>Javascript的时间</returns>
+        public static long CsharpTime2JavascriptTime(this DateTime TheDate)
+        {
+            DateTime d1 = new DateTime(1970, 1, 1);
+            DateTime d2 = TheDate.ToUniversalTime();
+            TimeSpan ts = new TimeSpan(d2.Ticks - d1.Ticks);
+            return (long)ts.TotalMilliseconds;
+        }
+
+        /// <summary>
+        /// PHP的时间转换成C#中的DateTime
+        /// </summary>
+        /// <param name="_"></param>
+        /// <param name="time">php的时间</param>
+        /// <returns>C#的时间</returns>
+        public static DateTime PhpTime2CsharpTime(this DateTime _, long time)
+        {
+            DateTime timeStamp = new DateTime(1970, 1, 1); //得到1970年的时间戳
+            long t = (time + 8 * 60 * 60) * 10000000 + timeStamp.Ticks;
+            return new DateTime(t);
+        }
+
+        /// <summary>
+        ///  C#中的DateTime转换成PHP的时间
+        /// </summary>
+        /// <param name="time">C#时间</param>
+        /// <returns>php时间</returns>
+        public static long CsharpTime2PhpTime(this DateTime time)
+        {
+            DateTime timeStamp = new DateTime(1970, 1, 1); //得到1970年的时间戳
+                                                           //注意这里有时区问题,用now就要减掉8个小时
+            return (DateTime.UtcNow.Ticks - timeStamp.Ticks) / 10000000;
+        }
+
+        #endregion
+    }
+}

+ 1547 - 0
Masuit.Tools.Core/Extensions.cs

@@ -0,0 +1,1547 @@
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+
+namespace Masuit.Tools
+{
+    /// <summary>
+    /// 扩展方法
+    /// </summary>
+    public static class Extensions
+    {
+        #region SyncForEach
+
+        /// <summary>
+        /// 遍历数组
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <param name="action">回调方法</param>
+        public static void ForEach(this object[] objs, Action<object> action)
+        {
+            foreach (var o in objs)
+            {
+                action(o);
+            }
+        }
+
+        /// <summary>
+        /// 遍历IEnumerable
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <param name="action">回调方法</param>
+        public static void ForEach(this IEnumerable<dynamic> objs, Action<object> action)
+        {
+            foreach (var o in objs)
+            {
+                action(o);
+            }
+        }
+
+        /// <summary>
+        /// 遍历集合
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <param name="action">回调方法</param>
+        public static void ForEach(this IList<dynamic> objs, Action<object> action)
+        {
+            foreach (var o in objs)
+            {
+                action(o);
+            }
+        }
+
+        /// <summary>
+        /// 遍历数组
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <param name="action">回调方法</param>
+        /// <typeparam name="T"></typeparam>
+        public static void ForEach<T>(this T[] objs, Action<T> action)
+        {
+            foreach (var o in objs)
+            {
+                action(o);
+            }
+        }
+
+        /// <summary>
+        /// 遍历IEnumerable
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <param name="action">回调方法</param>
+        /// <typeparam name="T"></typeparam>
+        public static void ForEach<T>(this IEnumerable<T> objs, Action<T> action)
+        {
+            foreach (var o in objs)
+            {
+                action(o);
+            }
+        }
+
+        /// <summary>
+        /// 遍历List
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <param name="action">回调方法</param>
+        /// <typeparam name="T"></typeparam>
+        public static void ForEach<T>(this IList<T> objs, Action<T> action)
+        {
+            foreach (var o in objs)
+            {
+                action(o);
+            }
+        }
+
+        /// <summary>
+        /// 遍历数组并返回一个新的List
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <param name="action">回调方法</param>
+        /// <returns></returns>
+        public static IEnumerable<T> ForEach<T>(this object[] objs, Func<object, T> action)
+        {
+            foreach (var o in objs)
+            {
+                yield return action(o);
+            }
+        }
+
+        /// <summary>
+        /// 遍历IEnumerable并返回一个新的List
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <param name="action">回调方法</param>
+        /// <typeparam name="T"></typeparam>
+        /// <returns></returns>
+        public static IEnumerable<T> ForEach<T>(this IEnumerable<dynamic> objs, Func<object, T> action)
+        {
+            foreach (var o in objs)
+            {
+                yield return action(o);
+            }
+        }
+
+        /// <summary>
+        /// 遍历List并返回一个新的List
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <param name="action">回调方法</param>
+        /// <typeparam name="T"></typeparam>
+        /// <returns></returns>
+        public static IEnumerable<T> ForEach<T>(this IList<dynamic> objs, Func<object, T> action)
+        {
+            foreach (var o in objs)
+            {
+                yield return action(o);
+            }
+        }
+
+
+        /// <summary>
+        /// 遍历数组并返回一个新的List
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <param name="action">回调方法</param>
+        /// <typeparam name="T"></typeparam>
+        /// <returns></returns>
+        public static IEnumerable<T> ForEach<T>(this T[] objs, Func<T, T> action)
+        {
+            foreach (var o in objs)
+            {
+                yield return action(o);
+            }
+        }
+
+        /// <summary>
+        /// 遍历IEnumerable并返回一个新的List
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <param name="action">回调方法</param>
+        /// <typeparam name="T"></typeparam>
+        /// <returns></returns>
+        public static IEnumerable<T> ForEach<T>(this IEnumerable<T> objs, Func<T, T> action)
+        {
+            foreach (var o in objs)
+            {
+                yield return action(o);
+            }
+        }
+
+        /// <summary>
+        /// 遍历List并返回一个新的List
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <param name="action">回调方法</param>
+        /// <typeparam name="T"></typeparam>
+        /// <returns></returns>
+        public static IEnumerable<T> ForEach<T>(this IList<T> objs, Func<T, T> action)
+        {
+            foreach (var o in objs)
+            {
+                yield return action(o);
+            }
+        }
+
+        #endregion
+
+        #region AsyncForEach
+
+        /// <summary>
+        /// 遍历数组
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <param name="action">回调方法</param>
+        public static async void ForEachAsync(this object[] objs, Action<object> action)
+        {
+            await Task.Run(() =>
+            {
+                foreach (var o in objs)
+                {
+                    action(o);
+                }
+            });
+        }
+
+        /// <summary>
+        /// 遍历IEnumerable
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <param name="action">回调方法</param>
+        public static async void ForEachAsync(this IEnumerable<dynamic> objs, Action<object> action)
+        {
+            await Task.Run(() =>
+            {
+                foreach (var o in objs)
+                {
+                    action(o);
+                }
+            });
+        }
+
+        /// <summary>
+        /// 遍历集合
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <param name="action">回调方法</param>
+        public static async void ForEachAsync(this IList<dynamic> objs, Action<object> action)
+        {
+            await Task.Run(() =>
+            {
+                foreach (var o in objs)
+                {
+                    action(o);
+                }
+            });
+        }
+
+        /// <summary>
+        /// 遍历数组
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <param name="action">回调方法</param>
+        /// <typeparam name="T"></typeparam>
+        public static async void ForEachAsync<T>(this T[] objs, Action<T> action)
+        {
+            await Task.Run(() =>
+            {
+                foreach (var o in objs)
+                {
+                    action(o);
+                }
+            });
+        }
+
+        /// <summary>
+        /// 遍历IEnumerable
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <param name="action">回调方法</param>
+        /// <typeparam name="T"></typeparam>
+        public static async void ForEachAsync<T>(this IEnumerable<T> objs, Action<T> action)
+        {
+            await Task.Run(() =>
+            {
+                foreach (var o in objs)
+                {
+                    action(o);
+                }
+            });
+        }
+
+        /// <summary>
+        /// 遍历List
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <param name="action">回调方法</param>
+        /// <typeparam name="T"></typeparam>
+        public static async void ForEachAsync<T>(this IList<T> objs, Action<T> action)
+        {
+            await Task.Run(() =>
+            {
+                foreach (var o in objs)
+                {
+                    action(o);
+                }
+            });
+        }
+
+        #endregion
+
+        #region Map
+
+        /// <summary>
+        /// 映射到目标类型(浅克隆)
+        /// </summary>
+        /// <param name="source">源</param>
+        /// <typeparam name="TDestination">目标类型</typeparam>
+        /// <returns>目标类型</returns>
+        public static TDestination MapTo<TDestination>(this object source) where TDestination : new()
+        {
+            TDestination dest = new TDestination();
+            dest.GetType().GetProperties().ForEach(p => { p.SetValue(dest, source.GetType().GetProperty(p.Name)?.GetValue(source)); });
+            return dest;
+        }
+
+        /// <summary>
+        /// 映射到目标类型(浅克隆)
+        /// </summary>
+        /// <param name="source">源</param>
+        /// <typeparam name="TDestination">目标类型</typeparam>
+        /// <returns>目标类型</returns>
+        public static async Task<TDestination> MapToAsync<TDestination>(this object source) where TDestination : new()
+        {
+            return await Task.Run(() =>
+            {
+                TDestination dest = new TDestination();
+                dest.GetType().GetProperties().ForEach(p => { p.SetValue(dest, source.GetType().GetProperty(p.Name)?.GetValue(source)); });
+                return dest;
+            });
+        }
+
+        /// <summary>
+        /// 映射到目标类型(深克隆)
+        /// </summary>
+        /// <param name="source">源</param>
+        /// <typeparam name="TDestination">目标类型</typeparam>
+        /// <returns>目标类型</returns>
+        public static TDestination Map<TDestination>(this object source) where TDestination : new() => JsonConvert.DeserializeObject<TDestination>(JsonConvert.SerializeObject(source));
+
+        /// <summary>
+        /// 映射到目标类型(深克隆)
+        /// </summary>
+        /// <param name="source">源</param>
+        /// <typeparam name="TDestination">目标类型</typeparam>
+        /// <returns>目标类型</returns>
+        public static async Task<TDestination> MapAsync<TDestination>(this object source) where TDestination : new() => await Task.Run(() => JsonConvert.DeserializeObject<TDestination>(JsonConvert.SerializeObject(source)));
+
+        /// <summary>
+        /// 复制一个新的对象
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="source"></param>
+        /// <returns></returns>
+        public static T Copy<T>(this T source) where T : new()
+        {
+            T dest = new T();
+            dest.GetType().GetProperties().ForEach(p => { p.SetValue(dest, source.GetType().GetProperty(p.Name)?.GetValue(source)); });
+            return dest;
+        }
+
+        /// <summary>
+        /// 复制一个新的对象
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="source"></param>
+        /// <returns></returns>
+        public static async Task<T> CopyAsync<T>(this T source) where T : new() => await Task.Run(() =>
+        {
+            T dest = new T();
+            dest.GetType().GetProperties().ForEach(p => { p.SetValue(dest, source.GetType().GetProperty(p.Name)?.GetValue(source)); });
+            return dest;
+        });
+
+        /// <summary>
+        /// 映射到目标类型的集合
+        /// </summary>
+        /// <param name="source">源</param>
+        /// <typeparam name="TDestination">目标类型</typeparam>
+        /// <returns>目标类型集合</returns>
+        public static IEnumerable<TDestination> ToList<TDestination>(this object[] source) where TDestination : new()
+        {
+            foreach (var o in source)
+            {
+                var dest = new TDestination();
+                dest.GetType().GetProperties().ForEach(p => { p.SetValue(dest, source.GetType().GetProperty(p.Name)?.GetValue(o)); });
+                yield return dest;
+            }
+        }
+
+        /// <summary>
+        /// 映射到目标类型的集合
+        /// </summary>
+        /// <param name="source">源</param>
+        /// <typeparam name="TDestination">目标类型</typeparam>
+        /// <returns>目标类型集合</returns>
+        public static async Task<IEnumerable<TDestination>> ToListAsync<TDestination>(this object[] source) where TDestination : new()
+        {
+            return await Task.Run(() =>
+            {
+                IList<TDestination> list = new List<TDestination>();
+                foreach (var o in source)
+                {
+                    var dest = new TDestination();
+                    dest.GetType().GetProperties().ForEach(p => { p.SetValue(dest, source.GetType().GetProperty(p.Name)?.GetValue(o)); });
+                    list.Add(dest);
+                }
+                return list;
+            });
+        }
+
+        /// <summary>
+        /// 映射到目标类型的集合
+        /// </summary>
+        /// <param name="source">源</param>
+        /// <typeparam name="TDestination">目标类型</typeparam>
+        /// <returns>目标类型集合</returns>
+        public static IEnumerable<TDestination> ToList<TDestination>(this IList<dynamic> source) where TDestination : new()
+        {
+            foreach (var o in source)
+            {
+                var dest = new TDestination();
+                dest.GetType().GetProperties().ForEach(p => { p.SetValue(dest, source.GetType().GetProperty(p.Name)?.GetValue(o)); });
+                yield return dest;
+            }
+        }
+
+        /// <summary>
+        /// 映射到目标类型的集合
+        /// </summary>
+        /// <param name="source">源</param>
+        /// <typeparam name="TDestination">目标类型</typeparam>
+        /// <returns>目标类型集合</returns>
+        public static async Task<IEnumerable<TDestination>> ToListAsync<TDestination>(this IList<dynamic> source) where TDestination : new()
+        {
+            return await Task.Run(() =>
+            {
+                IList<TDestination> list = new List<TDestination>();
+                foreach (var o in source)
+                {
+                    var dest = new TDestination();
+                    dest.GetType().GetProperties().ForEach(p => { p.SetValue(dest, source.GetType().GetProperty(p.Name)?.GetValue(o)); });
+                    list.Add(dest);
+                }
+                return list;
+            });
+        }
+
+        /// <summary>
+        /// 映射到目标类型的集合
+        /// </summary>
+        /// <param name="source">源</param>
+        /// <typeparam name="TDestination">目标类型</typeparam>
+        /// <returns>目标类型集合</returns>
+        public static IEnumerable<TDestination> ToList<TDestination>(this IEnumerable<dynamic> source) where TDestination : new()
+        {
+            foreach (var o in source)
+            {
+                var dest = new TDestination();
+                dest.GetType().GetProperties().ForEach(p => { p.SetValue(dest, source.GetType().GetProperty(p.Name)?.GetValue(o)); });
+                yield return dest;
+            }
+        }
+
+        /// <summary>
+        /// 映射到目标类型的集合
+        /// </summary>
+        /// <param name="source">源</param>
+        /// <typeparam name="TDestination">目标类型</typeparam>
+        /// <returns>目标类型集合</returns>
+        public static async Task<IEnumerable<TDestination>> ToListAsync<TDestination>(this IEnumerable<dynamic> source) where TDestination : new()
+        {
+            return await Task.Run(() =>
+            {
+                IList<TDestination> list = new List<TDestination>();
+                foreach (var o in source)
+                {
+                    var dest = new TDestination();
+                    dest.GetType().GetProperties().ForEach(p => { p.SetValue(dest, source.GetType().GetProperty(p.Name)?.GetValue(o)); });
+                    list.Add(dest);
+                }
+                return list;
+            });
+        }
+
+        #endregion
+
+        /// <summary>
+        /// 转换成json字符串
+        /// </summary>
+        /// <param name="source"></param>
+        /// <returns></returns>
+        public static string ToJsonString(this object source) => JsonConvert.SerializeObject(source);
+
+        /// <summary>
+        /// 转换成json字符串
+        /// </summary>
+        /// <param name="source"></param>
+        /// <returns></returns>
+        public static async Task<string> ToJsonStringAsync(this object source) => await Task.Run(() => JsonConvert.SerializeObject(source));
+
+        #region UBB、HTML互转
+
+        /// <summary>
+        /// UBB代码处理函数
+        /// </summary>
+        /// <param name="ubbStr">输入UBB字符串</param>
+        /// <returns>输出html字符串</returns>
+        public static string UbbToHtml(this string ubbStr)
+        {
+            Regex r;
+            Match m;
+
+            #region 处理空格
+
+            ubbStr = ubbStr.Replace(" ", "&nbsp;");
+
+            #endregion
+
+            #region 处理&符
+
+            ubbStr = ubbStr.Replace("&", "&amp;");
+
+            #endregion
+
+            #region 处理单引号
+
+            ubbStr = ubbStr.Replace("'", "’");
+
+            #endregion
+
+            #region 处理双引号
+
+            ubbStr = ubbStr.Replace("\"", "&quot;");
+
+            #endregion
+
+            #region html标记符
+
+            ubbStr = ubbStr.Replace("<", "&lt;");
+            ubbStr = ubbStr.Replace(">", "&gt;");
+
+            #endregion
+
+            #region 处理换行
+
+            //处理换行,在每个新行的前面添加两个全角空格
+            r = new Regex(@"(\r\n((&nbsp;)| )+)(?<正文>\S+)", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch()) ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<BR>  " + m.Groups["正文"]);
+            //处理换行,在每个新行的前面添加两个全角空格
+            ubbStr = ubbStr.Replace("\r\n", "<BR>");
+
+            #endregion
+
+            #region 处[b][/b]标记
+
+            r = new Regex(@"(\[b\])([ \S\t]*?)(\[\/b\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch()) ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<B>" + m.Groups[2] + "</B>");
+
+            #endregion
+
+            #region 处[i][/i]标记
+
+            r = new Regex(@"(\[i\])([ \S\t]*?)(\[\/i\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch()) ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<I>" + m.Groups[2] + "</I>");
+
+            #endregion
+
+            #region 处[u][/u]标记
+
+            r = new Regex(@"(\[U\])([ \S\t]*?)(\[\/U\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch()) ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<U>" + m.Groups[2] + "</U>");
+
+            #endregion
+
+            #region 处[p][/p]标记
+
+            //处[p][/p]标记
+            r = new Regex(@"((\r\n)*\[p\])(.*?)((\r\n)*\[\/p\])", RegexOptions.IgnoreCase | RegexOptions.Singleline);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch()) ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<P class=\"pstyle\">" + m.Groups[3] + "</P>");
+
+            #endregion
+
+            #region 处[sup][/sup]标记
+
+            //处[sup][/sup]标记
+            r = new Regex(@"(\[sup\])([ \S\t]*?)(\[\/sup\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch()) ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<SUP>" + m.Groups[2] + "</SUP>");
+
+            #endregion
+
+            #region 处[sub][/sub]标记
+
+            //处[sub][/sub]标记
+            r = new Regex(@"(\[sub\])([ \S\t]*?)(\[\/sub\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch()) ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<SUB>" + m.Groups[2] + "</SUB>");
+
+            #endregion
+
+            #region 处标记
+
+            //处标记
+            r = new Regex(@"(\[url\])([ \S\t]*?)(\[\/url\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch())
+            {
+                ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<A href=\"" + m.Groups[2] + "\" target=\"_blank\">" + m.Groups[2] + "</A>");
+            }
+
+            #endregion
+
+            #region 处[url=xxx][/url]标记
+
+            //处[url=xxx][/url]标记
+            r = new Regex(@"(\[url=([ \S\t]+)\])([ \S\t]*?)(\[\/url\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch())
+            {
+                ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<A href=\"" + m.Groups[2] + "\" target=\"_blank\">" + m.Groups[3] + "</A>");
+            }
+
+            #endregion
+
+            #region 处[email][/email]标记
+
+            //处[email][/email]标记
+            r = new Regex(@"(\[email\])([ \S\t]*?)(\[\/email\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch())
+            {
+                ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<A href=\"mailto:" + m.Groups[2] + "\" target=\"_blank\">" + m.Groups[2] + "</A>");
+            }
+
+            #endregion
+
+            #region 处[email=xxx][/email]标记
+
+            //处[email=xxx][/email]标记
+            r = new Regex(@"(\[email=([ \S\t]+)\])([ \S\t]*?)(\[\/email\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch())
+            {
+                ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<A href=\"mailto:" + m.Groups[2] + "\" target=\"_blank\">" + m.Groups[3] + "</A>");
+            }
+
+            #endregion
+
+            #region 处[size=x][/size]标记
+
+            //处[size=x][/size]标记
+            r = new Regex(@"(\[size=([1-7])\])([ \S\t]*?)(\[\/size\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch())
+            {
+                ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<FONT SIZE=" + m.Groups[2] + ">" + m.Groups[3] + "</FONT>");
+            }
+
+            #endregion
+
+            #region 处[color=x][/color]标记
+
+            //处[color=x][/color]标记
+            r = new Regex(@"(\[color=([\S]+)\])([ \S\t]*?)(\[\/color\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch())
+            {
+                ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<FONT COLOR=" + m.Groups[2] + ">" + m.Groups[3] + "</FONT>");
+            }
+
+            #endregion
+
+            #region 处[font=x][/font]标记
+
+            //处[font=x][/font]标记
+            r = new Regex(@"(\[font=([\S]+)\])([ \S\t]*?)(\[\/font\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch())
+            {
+                ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<FONT FACE=" + m.Groups[2] + ">" + m.Groups[3] + "</FONT>");
+            }
+
+            #endregion
+
+            #region 处理图片链接
+
+            //处理图片链接
+            r = new Regex("\\[picture\\](\\d+?)\\[\\/picture\\]", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch())
+            {
+                ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<A href=\"ShowImage.aspx?Type=ALL&Action=forumImage&ImageID=" + m.Groups[1] + "\" target=\"_blank\"><IMG border=0 Title=\"点击打开新窗口查看\" src=\"ShowImage.aspx?Action=forumImage&ImageID=" + m.Groups[1] + "\"></A>");
+            }
+
+            #endregion
+
+            #region 处理[align=x][/align]
+
+            //处理[align=x][/align]
+            r = new Regex(@"(\[align=([\S]+)\])([ \S\t]*?)(\[\/align\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch())
+            {
+                ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<P align=" + m.Groups[2] + ">" + m.Groups[3] + "</P>");
+            }
+
+            #endregion
+
+            #region 处[H=x][/H]标记
+
+            //处[H=x][/H]标记
+            r = new Regex(@"(\[H=([1-6])\])([ \S\t]*?)(\[\/H\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch())
+            {
+                ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<H" + m.Groups[2] + ">" + m.Groups[3] + "</H" + m.Groups[2] + ">");
+            }
+
+            #endregion
+
+            #region 处理[list=x][*][/list]
+
+            //处理[list=x][*][/list]
+            r = new Regex(@"(\[list(=(A|a|I|i| ))?\]([ \S\t]*)\r\n)((\[\*\]([ \S\t]*\r\n))*?)(\[\/list\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch())
+            {
+                string strLi = m.Groups[5].ToString();
+                Regex rLi = new Regex(@"\[\*\]([ \S\t]*\r\n?)", RegexOptions.IgnoreCase);
+                Match mLi;
+                for (mLi = rLi.Match(strLi); mLi.Success; mLi = mLi.NextMatch()) strLi = strLi.Replace(mLi.Groups[0].ToString(), "<LI>" + mLi.Groups[1]);
+                ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<UL TYPE=\"" + m.Groups[3] + "\"><B>" + m.Groups[4] + "</B>" + strLi + "</UL>");
+            }
+
+            #endregion
+
+            #region 处[SHADOW=x][/SHADOW]标记
+
+            //处[SHADOW=x][/SHADOW]标记
+            r = new Regex(@"(\[SHADOW=)(\d*?),(#*\w*?),(\d*?)\]([\S\t]*?)(\[\/SHADOW\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch())
+            {
+                ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<TABLE WIDTH=" + m.Groups[2] + "STYLE=FILTER:SHADOW(COLOR=" + m.Groups[3] + ",STRENGTH=" + m.Groups[4] + ")>" + m.Groups[5] + "</TABLE>");
+            }
+
+            #endregion
+
+            #region 处[glow=x][/glow]标记
+
+            //处[glow=x][/glow]标记
+            r = new Regex(@"(\[glow=)(\d*?),(#*\w*?),(\d*?)\]([\S\t]*?)(\[\/glow\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch())
+            {
+                ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<TABLE WIDTH=" + m.Groups[2] + "  STYLE=FILTER:GLOW(COLOR=" + m.Groups[3] + ", STRENGTH=" + m.Groups[4] + ")>" + m.Groups[5] + "</TABLE>");
+            }
+
+            #endregion
+
+            #region 处[center][/center]标记
+
+            r = new Regex(@"(\[center\])([ \S\t]*?)(\[\/center\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch()) ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<CENTER>" + m.Groups[2] + "</CENTER>");
+
+            #endregion
+
+            #region 处[ IMG][ /IMG]标记
+
+            r = new Regex(@"(\[IMG\])(http|https|ftp):\/\/([ \S\t]*?)(\[\/IMG\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch()) ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<br><a onfocus=this.blur() href=" + m.Groups[2] + "://" + m.Groups[3] + " target=_blank><IMG SRC=" + m.Groups[2] + "://" + m.Groups[3] + " border=0 alt=按此在新窗口浏览图片 onload=javascript:if(screen.width-333<this.width)this.width=screen.width-333></a>");
+
+            #endregion
+
+            #region 处[em]标记
+
+            r = new Regex(@"(\[em([\S\t]*?)\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch()) ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<img src=pic/em" + m.Groups[2] + ".gif border=0 align=middle>");
+
+            #endregion
+
+            #region 处[flash=x][/flash]标记
+
+            //处[mp=x][/mp]标记
+            r = new Regex(@"(\[flash=)(\d*?),(\d*?)\]([\S\t]*?)(\[\/flash\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch())
+            {
+                ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<a href=" + m.Groups[4] + " TARGET=_blank><IMG SRC=pic/swf.gif border=0 alt=点击开新窗口欣赏该FLASH动画!> [全屏欣赏]</a><br><br><OBJECT codeBase=http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0 classid=clsid:D27CDB6E-AE6D-11cf-96B8-444553540000 width=" + m.Groups[2] + " height=" + m.Groups[3] + "><PARAM NAME=movie VALUE=" + m.Groups[4] + "><PARAM NAME=quality VALUE=high><param name=menu value=false><embed src=" + m.Groups[4] + " quality=high menu=false pluginspage=http://www.macromedia.com/go/getflashplayer type=application/x-shockwave-flash width=" + m.Groups[2] + " height=" + m.Groups[3] + ">" + m.Groups[4] + "</embed></OBJECT>");
+            }
+
+            #endregion
+
+            #region 处[dir=x][/dir]标记
+
+            //处[dir=x][/dir]标记
+            r = new Regex(@"(\[dir=)(\d*?),(\d*?)\]([\S\t]*?)(\[\/dir\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch())
+            {
+                ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<object classid=clsid:166B1BCA-3F9C-11CF-8075-444553540000 codebase=http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=7,0,2,0 width=" + m.Groups[2] + " height=" + m.Groups[3] + "><param name=src value=" + m.Groups[4] + "><embed src=" + m.Groups[4] + " pluginspage=http://www.macromedia.com/shockwave/download/ width=" + m.Groups[2] + " height=" + m.Groups[3] + "></embed></object>");
+            }
+
+            #endregion
+
+            #region 处[rm=x][/rm]标记
+
+            //处[rm=x][/rm]标记
+            r = new Regex(@"(\[rm=)(\d*?),(\d*?)\]([\S\t]*?)(\[\/rm\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch())
+            {
+                ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<OBJECT classid=clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA class=OBJECT id=RAOCX width=" + m.Groups[2] + " height=" + m.Groups[3] + "><PARAM NAME=SRC VALUE=" + m.Groups[4] + "><PARAM NAME=CONSOLE VALUE=Clip1><PARAM NAME=CONTROLS VALUE=imagewindow><PARAM NAME=AUTOSTART VALUE=true></OBJECT><br><OBJECT classid=CLSID:CFCDAA03-8BE4-11CF-B84B-0020AFBBCCFA height=32 id=video2 width=" + m.Groups[2] + "><PARAM NAME=SRC VALUE=" + m.Groups[4] + "><PARAM NAME=AUTOSTART VALUE=-1><PARAM NAME=CONTROLS VALUE=controlpanel><PARAM NAME=CONSOLE VALUE=Clip1></OBJECT>");
+            }
+
+            #endregion
+
+            #region 处[mp=x][/mp]标记
+
+            //处[mp=x][/mp]标记
+            r = new Regex(@"(\[mp=)(\d*?),(\d*?)\]([\S\t]*?)(\[\/mp\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch())
+            {
+                ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<object align=middle classid=CLSID:22d6f312-b0f6-11d0-94ab-0080c74c7e95 class=OBJECT id=MediaPlayer width=" + m.Groups[2] + " height=" + m.Groups[3] + " ><param name=ShowStatusBar value=-1><param name=Filename value=" + m.Groups[4] + "><embed type=application/x-oleobject codebase=http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701 flename=mp src=" + m.Groups[4] + "  width=" + m.Groups[2] + " height=" + m.Groups[3] + "></embed></object>");
+            }
+
+            #endregion
+
+            #region 处[qt=x][/qt]标记
+
+            //处[qt=x][/qt]标记
+            r = new Regex(@"(\[qt=)(\d*?),(\d*?)\]([\S\t]*?)(\[\/qt\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch())
+            {
+                ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<embed src=" + m.Groups[4] + " width=" + m.Groups[2] + " height=" + m.Groups[3] + " autoplay=true loop=false controller=true playeveryframe=false cache=false scale=TOFIT bgcolor=#000000 kioskmode=false targetcache=false pluginspage=http://www.apple.com/quicktime/>");
+            }
+
+            #endregion
+
+            #region 处[QUOTE][/QUOTE]标记
+
+            r = new Regex(@"(\[QUOTE\])([ \S\t]*?)(\[\/QUOTE\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch()) ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<div style='border:#CCCCCC 1px dashed; width:94%; color:#999999; padding:3px; background:#F8F8F8'>" + m.Groups[2] + "</div><br /> ");
+
+            #endregion
+
+            #region 处[move][/move]标记
+
+            r = new Regex(@"(\[move\])([ \S\t]*?)(\[\/move\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch()) ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<MARQUEE scrollamount=3>" + m.Groups[2] + "</MARQUEE>");
+
+            #endregion
+
+            #region 处[FLY][/FLY]标记
+
+            r = new Regex(@"(\[FLY\])([ \S\t]*?)(\[\/FLY\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch()) ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<MARQUEE width=80% behavior=alternate scrollamount=3>" + m.Groups[2] + "</MARQUEE>");
+
+            #endregion
+
+            #region 处[image][/image]标记
+
+            //处[image][/image]标记
+            r = new Regex(@"(\[image\])([ \S\t]*?)(\[\/image\])", RegexOptions.IgnoreCase);
+            for (m = r.Match(ubbStr); m.Success; m = m.NextMatch())
+            {
+                ubbStr = ubbStr.Replace(m.Groups[0].ToString(), "<img src=\"" + m.Groups[2] + "\" border=0 align=middle><br>");
+            }
+
+            #endregion
+
+            return ubbStr;
+        }
+
+        /// <summary>
+        /// UBB代码处理函数
+        /// </summary>
+        /// <param name="ubbStr">输入UBB字符串</param>
+        /// <returns>输出html字符串</returns>
+        public static async Task<string> UbbToHtmlAsync(this string ubbStr) => await Task.Run(() => UbbToHtml(ubbStr));
+
+        /// <summary>
+        /// UBB转HTML方式2
+        /// </summary>
+        /// <param name="ubbStr">UBB 代码</param>
+        /// <returns>HTML代码</returns>
+        public static string UbbToHtml2(this string ubbStr)
+        {
+            ubbStr = ubbStr.Replace("&", "&amp;");
+            ubbStr = ubbStr.Replace("<", "&lt;");
+            ubbStr = ubbStr.Replace(">", "&gt;");
+            ubbStr = ubbStr.Replace(" ", "&nbsp;"); //空格
+            ubbStr = ubbStr.Replace("\n", "<br>"); //回车
+            Regex my = new Regex(@"(\[IMG\])(.[^\[]*)(\[\/IMG\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<a href=""$2"" target=_blank><IMG SRC=""$2"" border=0 alt=按此在新窗口浏览图片 onload=""javascript:if(this.width>screen.width-333)this.width=screen.width-333""></a>");
+
+            my = new Regex(@"\[DIR=*([0-9]*),*([0-9]*)\](.[^\[]*)\[\/DIR]", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<object classid=clsid:166B1BCA-3F9C-11CF-8075-444553540000 codebase=http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=7,0,2,0 width=$1 height=$2><param name=src value=$3><embed src=$3 pluginspage=http://www.macromedia.com/shockwave/download/ width=$1 height=$2></embed></object>");
+
+            my = new Regex(@"\[QT=*([0-9]*),*([0-9]*)\](.[^\[]*)\[\/QT]", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<embed src=$3 width=$1 height=$2 autoplay=true loop=false controller=true playeveryframe=false cache=false scale=TOFIT bgcolor=#000000 kioskmode=false targetcache=false pluginspage=http://www.apple.com/quicktime/>");
+
+            my = new Regex(@"\[MP=*([0-9]*),*([0-9]*)\](.[^\[]*)\[\/MP]", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<object align=middle classid=CLSID:22d6f312-b0f6-11d0-94ab-0080c74c7e95 class=OBJECT id=MediaPlayer width=$1 height=$2 ><param name=ShowStatusBar value=-1><param name=Filename value=$3><embed type=application/x-oleobject codebase=http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701 flename=mp src=$3  width=$1 height=$2></embed></object>");
+
+            my = new Regex(@"\[RM=*([0-9]*),*([0-9]*)\](.[^\[]*)\[\/RM]", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<OBJECT classid=clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA class=OBJECT id=RAOCX width=$1 height=$2><PARAM NAME=SRC VALUE=$3><PARAM NAME=CONSOLE VALUE=Clip1><PARAM NAME=CONTROLS VALUE=imagewindow><PARAM NAME=AUTOSTART VALUE=true></OBJECT><br><OBJECT classid=CLSID:CFCDAA03-8BE4-11CF-B84B-0020AFBBCCFA height=32 id=video2 width=$1><PARAM NAME=SRC VALUE=$3><PARAM NAME=AUTOSTART VALUE=-1><PARAM NAME=CONTROLS VALUE=controlpanel><PARAM NAME=CONSOLE VALUE=Clip1></OBJECT>");
+
+            my = new Regex(@"(\[FLASH\])(.[^\[]*)(\[\/FLASH\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<OBJECT codeBase=http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=4,0,2,0 classid=clsid:D27CDB6E-AE6D-11cf-96B8-444553540000 width=500 height=400><PARAM NAME=movie VALUE=""$2""><PARAM NAME=quality VALUE=high><embed src=""$2"" quality=high pluginspage='http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash' type='application/x-shockwave-flash' width=500 height=400>$2</embed></OBJECT>");
+
+            my = new Regex(@"(\[ZIP\])(.[^\[]*)(\[\/ZIP\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<br><IMG SRC=pic/zip.gif border=0> <a href=""$2"">点击下载该文件</a>");
+
+            my = new Regex(@"(\[RAR\])(.[^\[]*)(\[\/RAR\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<br><IMG SRC=pic/rar.gif border=0> <a href=""$2"">点击下载该文件</a>");
+
+            my = new Regex(@"(\[UPLOAD=(.[^\[]*)\])(.[^\[]*)(\[\/UPLOAD\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<br><IMG SRC=""pic/$2.gif"" border=0>此主题相关图片如下:<br><A HREF=""$3"" TARGET=_blank><IMG SRC=""$3"" border=0 alt=按此在新窗口浏览图片 onload=""javascript:if(this.width>screen.width-333)this.width=screen.width-333""></A>");
+
+            my = new Regex(@"(\[URL\])(http:\/\/.[^\[]*)(\[\/URL\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<A HREF=""$2"" TARGET=_blank>$2</A>");
+
+            my = new Regex(@"(\[URL\])(.[^\[]*)(\[\/URL\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<A HREF=""http://$2"" TARGET=_blank>$2</A>");
+
+            my = new Regex(@"(\[URL=(http:\/\/.[^\[]*)\])(.[^\[]*)(\[\/URL\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<A HREF=""$2"" TARGET=_blank>$3</A>");
+
+            my = new Regex(@"(\[URL=(.[^\[]*)\])(.[^\[]*)(\[\/URL\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<A HREF=""http://$2"" TARGET=_blank>$3</A>");
+
+            my = new Regex(@"(\[EMAIL\])(\S+\@.[^\[]*)(\[\/EMAIL\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<A HREF=""mailto:$2"">$2</A>");
+
+            my = new Regex(@"(\[EMAIL=(\S+\@.[^\[]*)\])(.[^\[]*)(\[\/EMAIL\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<A HREF=""mailto:$2"" TARGET=_blank>$3</A>");
+
+            my = new Regex(@"^(HTTP://[A-Za-z0-9\./=\?%\-&_~`@':+!]+)", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<a target=_blank href=$1>$1</a>");
+
+            my = new Regex(@"(HTTP://[A-Za-z0-9\./=\?%\-&_~`@':+!]+)$", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<a target=_blank href=$1>$1</a>");
+
+            my = new Regex(@"[^>=""](HTTP://[A-Za-z0-9\./=\?%\-&_~`@':+!]+)", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<a target=_blank href=$1>$1</a>");
+
+            my = new Regex(@"^(FTP://[A-Za-z0-9\./=\?%\-&_~`@':+!]+)", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<a target=_blank href=$1>$1</a>");
+
+            my = new Regex(@"(FTP://[A-Za-z0-9\./=\?%\-&_~`@':+!]+)$", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<a target=_blank href=$1>$1</a>");
+
+            my = new Regex(@"[^>=""](FTP://[A-Za-z0-9\.\/=\?%\-&_~`@':+!]+)", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<a target=_blank href=$1>$1</a>");
+
+            my = new Regex(@"^(RTSP://[A-Za-z0-9\./=\?%\-&_~`@':+!]+)", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<a target=_blank href=$1>$1</a>");
+
+            my = new Regex(@"(RTSP://[A-Za-z0-9\./=\?%\-&_~`@':+!]+)$", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<a target=_blank href=$1>$1</a>");
+
+            my = new Regex(@"[^>=""](RTSP://[A-Za-z0-9\.\/=\?%\-&_~`@':+!]+)", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<a target=_blank href=$1>$1</a>");
+
+            my = new Regex(@"^(MMS://[A-Za-z0-9\./=\?%\-&_~`@':+!]+)", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<a target=_blank href=$1>$1</a>");
+            my = new Regex(@"(MMS://[A-Za-z0-9\./=\?%\-&_~`@':+!]+)$", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<a target=_blank href=$1>$1</a>");
+
+            my = new Regex(@"[^>=""](MMS://[A-Za-z0-9\.\/=\?%\-&_~`@':+!]+)", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<a target=_blank href=$1>$1</a>");
+
+            my = new Regex(@"(\[HTML\])(.[^\[]*)(\[\/HTML\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<table width='100%' border='0' cellspacing='0' cellpadding='6' bgcolor=''><td><b>以下内容为程序代码:</b><br>$2</td></table>");
+
+            my = new Regex(@"(\[CODE\])(.[^\[]*)(\[\/CODE\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<table width='100%' border='0' cellspacing='0' cellpadding='6' bgcolor=''><td><b>以下内容为程序代码:</b><br>$2</td></table>");
+
+            my = new Regex(@"(\[COLOR=(.[^\[]*)\])(.[^\[]*)(\[\/COLOR\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<font COLOR=$2>$3</font>");
+
+            my = new Regex(@"(\[FACE=(.[^\[]*)\])(.[^\[]*)(\[\/FACE\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<font FACE=$2>$3</font>");
+
+            my = new Regex(@"(\[ALIGN=(.[^\[]*)\])(.*)(\[\/ALIGN\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<div ALIGN=$2>$3</div>");
+
+            my = new Regex(@"(\[QUOTE\])(.*)(\[\/QUOTE\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<table cellpadding=0 cellspacing=0 border=0 WIDTH=94% bgcolor=#000000 align=center><tr><td><table width=100% cellpadding=5 cellspacing=1 border=0><TR><TD BGCOLOR=''>$2</table></table><br>");
+
+            my = new Regex(@"(\[MOVE\])(.*)(\[\/MOVE\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<MARQUEE scrollamount=3>$2</marquee>");
+
+            my = new Regex(@"\[GLOW=*([0-9]*),*(#*[a-z0-9]*),*([0-9]*)\](.[^\[]*)\[\/GLOW]", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<table width=$1 style=""filter:glow(color=$2, strength=$3)"">$4</table>");
+
+            my = new Regex(@"\[SHADOW=*([0-9]*),*(#*[a-z0-9]*),*([0-9]*)\](.[^\[]*)\[\/SHADOW]", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<table width=$1 style=""filter:shadow(color=$2, strength=$3)"">$4</table>");
+
+            my = new Regex(@"(\[I\])(.[^\[]*)(\[\/I\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<i>$2</i>");
+
+            my = new Regex(@"(\[B\])(.[^\[]*)(\[\/U\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<u>$2</u>");
+
+            my = new Regex(@"(\[B\])(.[^\[]*)(\[\/B\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<b>$2</b>");
+
+            my = new Regex(@"(\[FLY\])(.[^\[]*)(\[\/FLY\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<marquee onmouseover='this.stop();' onmouseout='this.start();'>$2</marquee>");
+
+            my = new Regex(@"(\[SIZE=1\])(.[^\[]*)(\[\/SIZE\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<font size=1>$2</font>");
+
+            my = new Regex(@"(\[SIZE=2\])(.[^\[]*)(\[\/SIZE\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<font size=2>$2</font>");
+
+            my = new Regex(@"(\[SIZE=3\])(.[^\[]*)(\[\/SIZE\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<font size=3>$2</font>");
+
+            my = new Regex(@"(\[SIZE=4\])(.[^\[]*)(\[\/SIZE\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<font size=4>$2</font>");
+
+            my = new Regex(@"(\[CENTER\])(.[^\[]*)(\[\/CENTER\])", RegexOptions.IgnoreCase);
+            ubbStr = my.Replace(ubbStr, @"<center>$2</center>");
+
+            return ubbStr;
+        }
+
+        /// <summary>
+        /// UBB转HTML方式2
+        /// </summary>
+        /// <param name="ubbStr">UBB 代码</param>
+        /// <returns>HTML代码</returns>
+        public static async Task<string> UbbToHtml2Async(this string ubbStr) => await Task.Run(() => UbbToHtml2(ubbStr));
+
+        /// <summary>
+        /// Html转UBB
+        /// </summary>
+        /// <param name="chr">HTML代码</param>
+        /// <returns>UBB代码</returns>
+        public static string HtmltoUBB(this string chr)
+        {
+            if (chr == null) return "";
+            chr = chr.Replace("&lt", "<");
+            chr = chr.Replace("&gt", ">");
+            chr = chr.Replace("<br/>", " ");
+            chr = Regex.Replace(chr, @"<a href=$1 target=_blank>$2</a>", @"[url=(?<x>[^]]*)](?<y>[^]]*)[/url]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<a href=$1 target=_blank>$1</a>", @"[url](?<x>[^]]*)[/url]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<a href=$1>$2</a>", @"[email=(?<x>[^]]*)](?<y>[^]]*)[/email]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<a href=$1>$1</a>", @"[email](?<x>[^]]*)[/email]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<OBJECT codeBase=http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=4,0,2,0 classid=clsid:D27CDB6E-AE6D-11cf-96B8-444553540000 width=500 height=400><PARAM NAME=movie VALUE=""$1""><PARAM NAME=quality VALUE=high><embed src=""$1"" quality=high pluginspage='http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash' type='application/x-shockwave-flash' width=500 height=400>$1</embed></OBJECT>", @"[flash](?<x>[^]]*)[/flash]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<IMG SRC=""$1"" border=0>", @"[img](?<x>[^]]*)[/img]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<font color=$1>$2</font>", @"[color=(?<x>[^]]*)](?<y>[^]]*)[/color]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<font face=$1>$2</font>", @"[face=(?<x>[^]]*)](?<y>[^]]*)[/face]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<font size=1>$1</font>", @"[size=1](?<x>[^]]*)[/size]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<font size=2>$1</font>", @"[size=2](?<x>[^]]*)[/size]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<font size=3>$1</font>", @"[size=3](?<x>[^]]*)[/size]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<font size=4>$1</font>", @"[size=4](?<x>[^]]*)[/size]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<align=$1>$2</align>", @"[align=(?<x>[^]]*)](?<y>[^]]*)[/align]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<marquee width=90% behavior=alternate scrollamount=3>$1</marquee>", @"[fly](?<x>[^]]*)[/fly]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<marquee scrollamount=3>$1</marquee>", @"[move](?<x>[^]]*)[/move]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<table width=$1 style='filter:glow(color=$2, strength=$3)'>$4</table>", @"[glow=(?<x>[^]]*),(?<y>[^]]*),(?<z>[^]]*)](?<w>[^]]*)[/glow]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<table width=$1 style='filter:shadow(color=$2, strength=$3)'>$4</table>", @"[shadow=(?<x>[^]]*),(?<y>[^]]*),(?<z>[^]]*)](?<w>[^]]*)[/shadow]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<b>$1</b>", @"[b](?<x>[^]]*)[/b]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<i>$1</i>", @"[i](?<x>[^]]*)[/i]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<u>$1</u>", @"[u](?<x>[^]]*)[/u]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<pre id=code><font size=1 face='Verdana, Arial' id=code>$1</font id=code></pre id=code>", @"[code](?<x>[^]]*)[/code]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<ul>$1</ul>", @"[list](?<x>[^]]*)[/list]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<ol type=1>$1</ol id=1>", @"[list=1](?<x>[^]]*)[/list]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<ol type=a>$1</ol id=a>", @"[list=a](?<x>[^]]*)[/list]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<li>$1</li>", @"[*](?<x>[^]]*)[/*]", RegexOptions.IgnoreCase);
+            chr = Regex.Replace(chr, @"<center>—— 以下是引用 ——<table border='1' width='80%' cellpadding='10' cellspacing='0' ><tr><td>$1</td></tr></table></center>", @"[quote](?<x>.*)[/quote]", RegexOptions.IgnoreCase);
+            return chr;
+        }
+
+        /// <summary>
+        /// Html转UBB
+        /// </summary>
+        /// <param name="chr">HTML代码</param>
+        /// <returns>UBB代码</returns>
+        public static async Task<string> HtmltoUBBAsync(this string chr) => await Task.Run(() => HtmltoUBB(chr));
+
+        #endregion
+
+        #region 数字互转
+
+        /// <summary>
+        /// 字符串转int
+        /// </summary>
+        /// <param name="s">源字符串</param>
+        /// <returns>int类型的数字</returns>
+        public static int ToInt32(this string s)
+        {
+            try
+            {
+                return Convert.ToInt32(s);
+            }
+            catch
+            {
+                return 0;
+            }
+        }
+
+        /// <summary>
+        /// 字符串转long
+        /// </summary>
+        /// <param name="s">源字符串</param>
+        /// <returns>int类型的数字</returns>
+        public static long ToInt64(this string s)
+        {
+            try
+            {
+                return Convert.ToInt64(s);
+            }
+            catch
+            {
+                return 0;
+            }
+        }
+
+        /// <summary>
+        /// 字符串转double
+        /// </summary>
+        /// <param name="s">源字符串</param>
+        /// <returns>double类型的数据</returns>
+        public static double ToDouble(this string s)
+        {
+            try
+            {
+                return Convert.ToDouble(s);
+            }
+            catch
+            {
+                return 0;
+            }
+        }
+
+        /// <summary>
+        /// 字符串转decimal
+        /// </summary>
+        /// <param name="s">源字符串</param>
+        /// <returns>int类型的数字</returns>
+        public static decimal ToDecimal(this string s)
+        {
+            try
+            {
+                return Convert.ToDecimal(s);
+            }
+            catch
+            {
+                return 0;
+            }
+        }
+
+        /// <summary>
+        /// 字符串转decimal
+        /// </summary>
+        /// <param name="s">源字符串</param>
+        /// <returns>int类型的数字</returns>
+        public static decimal ToDecimal(this double s)
+        {
+            try
+            {
+                return Convert.ToDecimal(s);
+            }
+            catch
+            {
+                return 0;
+            }
+        }
+
+        /// <summary>
+        /// 字符串转double
+        /// </summary>
+        /// <param name="s">源字符串</param>
+        /// <returns>double类型的数据</returns>
+        public static double ToDouble(this decimal s)
+        {
+            try
+            {
+                return Convert.ToDouble(s);
+            }
+            catch
+            {
+                return 0;
+            }
+        }
+
+        /// <summary>
+        /// 将double转换成int
+        /// </summary>
+        /// <param name="num">double类型</param>
+        /// <returns>int类型</returns>
+        public static int ToInt32(this double num)
+        {
+            return (int)Math.Floor(num);
+        }
+
+        /// <summary>
+        /// 将double转换成int
+        /// </summary>
+        /// <param name="num">double类型</param>
+        /// <returns>int类型</returns>
+        public static int ToInt32(this decimal num)
+        {
+            return (int)Math.Floor(num);
+        }
+
+        /// <summary>
+        /// 将int转换成double
+        /// </summary>
+        /// <param name="num">int类型</param>
+        /// <returns>int类型</returns>
+        public static double ToDouble(this int num)
+        {
+            return num * 1.0;
+        }
+
+        /// <summary>
+        /// 将int转换成decimal
+        /// </summary>
+        /// <param name="num">int类型</param>
+        /// <returns>int类型</returns>
+        public static decimal ToDecimal(this int num)
+        {
+            return (decimal)(num * 1.0);
+        }
+
+        #endregion
+
+        #region 检测字符串中是否包含列表中的关键词
+
+        /// <summary>
+        /// 检测字符串中是否包含列表中的关键词
+        /// </summary>
+        /// <param name="s">源字符串</param>
+        /// <param name="keys">关键词列表</param>
+        /// <returns></returns>
+        public static bool Contains(this string s, string[] keys) => Regex.IsMatch(s.ToLower(), string.Join("|", keys).ToLower());
+
+        #endregion
+
+        #region 匹配Email
+
+        /// <summary>
+        /// 匹配Email
+        /// </summary>
+        /// <param name="s">源字符串</param>
+        /// <param name="isMatch">是否匹配成功,若返回true,则会得到一个Match对象,否则为null</param>
+        /// <returns>匹配对象</returns>
+        public static Match MatchEmail(this string s, out bool isMatch)
+        {
+            Match match = Regex.Match(s, @"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$");
+            isMatch = match.Success;
+            return isMatch ? match : null;
+        }
+
+        /// <summary>
+        /// 匹配Email
+        /// </summary>
+        /// <param name="s">源字符串</param>
+        /// <returns>是否匹配成功</returns>
+        public static bool MatchEmail(this string s)
+        {
+            MatchEmail(s, out bool success);
+            return success;
+        }
+
+        #endregion
+
+        #region 匹配完整的URL
+
+        /// <summary>
+        /// 匹配完整格式的URL,支持以下格式的URL,支持中文域名:<br/>
+        /// 支持不带协议名的网址,支持自适应协议的网址,支持完整路径,支持查询参数,支持锚点,支持锚点查询参数,支持16进制编码<br/>
+        /// www.baidu.com <br/>
+        /// www.baidu.com <br/>
+        /// baidu.com <br/>
+        /// //www.baidu.com <br/>
+        /// http://www.baidu.com <br/>
+        /// https://www.baidu.com <br/>
+        /// https://baidu.com <br/>
+        /// ftp://baidu.com <br/>
+        /// ftp://baidu.com/abc/def <br/>
+        /// ftp://admin:[email protected] <br/>
+        /// ftp://admin:[email protected]/abc/def <br/>
+        /// https://baidu.com:8080 <br/>
+        /// https://baidu.com/abc/def <br/>
+        /// https://baidu.com:8080/abc/def <br/>
+        /// https://baidu.com:8080/abc/def/hhh.html <br/>
+        /// https://baidu.com:8080/abc/def/hhh.html?s=www <br/>
+        /// https://baidu.com/abc/def/hhh.html?s=w@w{w}!s <br/>
+        /// https://baidu.com:8080/abc/def/hhh.html?s=www&amp;x=yy+y <br/>
+        /// https://baidu.com/abc/def/hhh.html?s=www&amp;x=yyy <br/>
+        /// https://baidu.com:8080/abc/def/hhh.html?s=www&amp;x=yyy#top <br/>
+        /// https://baidu.com:8080/abc/def/hi_jk-mn%ADF%AA/hhh.html?s=www&amp;x=yyy#top <br/>
+        /// https://baidu.com:8080/abc/def/hi_j+k-mn%ADF%AA?s=www&amp;x=yyy#top/aaa <br/>
+        /// https://baidu.com:8080/abc/def/hi_jk-mn%ADF%AA?s=www&amp;x=yyy#top/aaa/bbb/ccc <br/>
+        /// http://music.163.com/#/my/m/music/empty <br/>
+        /// http://music.163.com/abc/#/my/m/music/empty <br/>
+        /// http://music.163.com/def/hhh.html?s=www&amp;x=yyy#/my/m/music/empty <br/>
+        /// http://music.163.com/def/hhh.html?s=www&amp;x=yyy/#/my/m/music/empty <br/>
+        /// http://music.163.com/#/search/m/?%23%2Fmy%2Fm%2Fmusic%2Fempty=&amp;s=fade&amp;type=1!k <br/>
+        /// </summary>
+        /// <param name="s">源字符串</param>
+        /// <param name="isMatch">是否匹配成功,若返回true,则会得到一个Match对象,否则为null</param>
+        /// <returns>匹配对象</returns>
+        public static Match MatchUrl(this string s, out bool isMatch)
+        {
+            Match match = Regex.Match(s, @"^((\w*):?//)?((\w+)\.|((\S+):(\S+))@)?((\w+)\.(\w+))(:(\d{1,5}))?(/([a-z0-9A-Z-_@{}!+%/]+(\.\w+)?)?(\?([a-z0-9A-Z-_@{}!+%]+=[a-z0-9A-Z-_@{}!+%]+&?)+)?(/?#[a-z0-9A-Z-_@{}!+%/]+)?(\?([a-z0-9A-Z-_@{}!+%]+=[a-z0-9A-Z-_@{}!+%]*&?)+)?)?$");
+            isMatch = match.Success;
+            return isMatch ? match : null;
+        }
+
+        /// <summary>
+        /// 匹配完整格式的URL,支持以下格式的URL,支持中文域名:<br/>
+        /// 支持不带协议名的网址,支持自适应协议的网址,支持完整路径,支持查询参数,支持锚点,支持锚点查询参数,支持16进制编码<br/>
+        /// www.baidu.com <br/>
+        /// www.baidu.com <br/>
+        /// baidu.com <br/>
+        /// //www.baidu.com <br/>
+        /// http://www.baidu.com <br/>
+        /// https://www.baidu.com <br/>
+        /// https://baidu.com <br/>
+        /// ftp://baidu.com <br/>
+        /// ftp://baidu.com/abc/def <br/>
+        /// ftp://admin:[email protected] <br/>
+        /// ftp://admin:[email protected]/abc/def <br/>
+        /// https://baidu.com:8080 <br/>
+        /// https://baidu.com/abc/def <br/>
+        /// https://baidu.com:8080/abc/def <br/>
+        /// https://baidu.com:8080/abc/def/hhh.html <br/>
+        /// https://baidu.com:8080/abc/def/hhh.html?s=www <br/>
+        /// https://baidu.com/abc/def/hhh.html?s=w@w{w}!s <br/>
+        /// https://baidu.com:8080/abc/def/hhh.html?s=www&amp;x=yy+y <br/>
+        /// https://baidu.com/abc/def/hhh.html?s=www&amp;x=yyy <br/>
+        /// https://baidu.com:8080/abc/def/hhh.html?s=www&amp;x=yyy#top <br/>
+        /// https://baidu.com:8080/abc/def/hi_jk-mn%ADF%AA/hhh.html?s=www&amp;x=yyy#top <br/>
+        /// https://baidu.com:8080/abc/def/hi_j+k-mn%ADF%AA?s=www&amp;x=yyy#top/aaa <br/>
+        /// https://baidu.com:8080/abc/def/hi_jk-mn%ADF%AA?s=www&amp;x=yyy#top/aaa/bbb/ccc <br/>
+        /// http://music.163.com/#/my/m/music/empty <br/>
+        /// http://music.163.com/abc/#/my/m/music/empty <br/>
+        /// http://music.163.com/def/hhh.html?s=www&amp;x=yyy#/my/m/music/empty <br/>
+        /// http://music.163.com/def/hhh.html?s=www&amp;x=yyy/#/my/m/music/empty <br/>
+        /// http://music.163.com/#/search/m/?%23%2Fmy%2Fm%2Fmusic%2Fempty=&amp;s=fade&amp;type=1!k <br/>
+        /// </summary>
+        /// <param name="s">源字符串</param>
+        /// <returns>是否匹配成功</returns>
+        public static bool MatchUrl(this string s)
+        {
+            MatchUrl(s, out bool success);
+            return success;
+        }
+
+        #endregion
+
+        #region 权威校验身份证号码
+
+        /// <summary>
+        /// 根据GB11643-1999标准权威校验中国身份证号码的合法性
+        /// </summary>
+        /// <param name="s">源字符串</param>
+        /// <returns>是否匹配成功</returns>
+        public static bool MatchIdentifyCard(this string s)
+        {
+            if (s.Length == 18)
+            {
+                long n;
+                if (long.TryParse(s.Remove(17), out n) == false || n < Math.Pow(10, 16) || long.TryParse(s.Replace('x', '0').Replace('X', '0'), out n) == false)
+                {
+                    return false; //数字验证  
+                }
+                string address = "11x22x35x44x53x12x23x36x45x54x13x31x37x46x61x14x32x41x50x62x15x33x42x51x63x21x34x43x52x64x65x71x81x82x91";
+                if (address.IndexOf(s.Remove(2), StringComparison.Ordinal) == -1)
+                {
+                    return false; //省份验证  
+                }
+                string birth = s.Substring(6, 8).Insert(6, "-").Insert(4, "-");
+                DateTime time;
+                if (!DateTime.TryParse(birth, out time))
+                {
+                    return false; //生日验证  
+                }
+                string[] arrVarifyCode = ("1,0,x,9,8,7,6,5,4,3,2").Split(',');
+                string[] wi = ("7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2").Split(',');
+                char[] ai = s.Remove(17).ToCharArray();
+                int sum = 0;
+                for (int i = 0; i < 17; i++)
+                {
+                    sum += wi[i].ToInt32() * ai[i].ToString().ToInt32();
+                }
+                int y;
+                Math.DivRem(sum, 11, out y);
+                if (arrVarifyCode[y] != s.Substring(17, 1).ToLower())
+                {
+                    return false; //校验码验证  
+                }
+                return true; //符合GB11643-1999标准  
+            }
+            if (s.Length == 15)
+            {
+                long n;
+                if (long.TryParse(s, out n) == false || n < Math.Pow(10, 14))
+                {
+                    return false; //数字验证  
+                }
+                string address = "11x22x35x44x53x12x23x36x45x54x13x31x37x46x61x14x32x41x50x62x15x33x42x51x63x21x34x43x52x64x65x71x81x82x91";
+                if (address.IndexOf(s.Remove(2), StringComparison.Ordinal) == -1)
+                {
+                    return false; //省份验证  
+                }
+                string birth = s.Substring(6, 6).Insert(4, "-").Insert(2, "-");
+                DateTime time;
+                if (DateTime.TryParse(birth, out time) == false)
+                {
+                    return false; //生日验证  
+                }
+                return true;
+            }
+            return false;
+        }
+
+        #endregion
+
+        #region 校验IP地址的合法性
+
+        /// <summary>
+        /// 校验IP地址的正确性,同时支持IPv4和IPv6
+        /// </summary>
+        /// <param name="s">源字符串</param>
+        /// <param name="isMatch">是否匹配成功,若返回true,则会得到一个Match对象,否则为null</param>
+        /// <returns>匹配对象</returns>
+        public static Match MatchInetAddress(this string s, out bool isMatch)
+        {
+            Match match;
+            if (s.Contains(":"))
+            {
+                //IPv6
+                match = Regex.Match(s, "^((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))$");
+                isMatch = match.Success;
+            }
+            else
+            {
+                //IPv4
+                match = Regex.Match(s, @"^(\d+)\.(\d+)\.(\d+)\.(\d+)$");
+                isMatch = match.Success;
+                foreach (Group m in match.Groups)
+                {
+                    if (m.Value.ToInt32() < 0 || m.Value.ToInt32() > 255)
+                    {
+                        isMatch = false;
+                        break;
+                    }
+                }
+            }
+            return isMatch ? match : null;
+        }
+
+        /// <summary>
+        /// 校验IP地址的正确性,同时支持IPv4和IPv6
+        /// </summary>
+        /// <param name="s">源字符串</param>
+        /// <returns>是否匹配成功</returns>
+        public static bool MatchInetAddress(this string s)
+        {
+            MatchInetAddress(s, out bool success);
+            return success;
+        }
+
+        #endregion
+
+        #region 校验手机号码的正确性
+
+        /// <summary>
+        /// 匹配手机号码
+        /// </summary>
+        /// <param name="s">源字符串</param>
+        /// <param name="isMatch">是否匹配成功,若返回true,则会得到一个Match对象,否则为null</param>
+        /// <returns>匹配对象</returns>
+        public static Match MatchPhoneNumber(this string s, out bool isMatch)
+        {
+            Match match = Regex.Match(s, @"^((1[3,5,8][0-9])|(14[5,7])|(17[0,1,6,7,8]))\d{8}$");
+            isMatch = match.Success;
+            return isMatch ? match : null;
+        }
+
+        /// <summary>
+        /// 匹配手机号码
+        /// </summary>
+        /// <param name="s">源字符串</param>
+        /// <returns>是否匹配成功</returns>
+        public static bool MatchPhoneNumber(this string s)
+        {
+            MatchPhoneNumber(s, out bool success);
+            return success;
+        }
+
+        #endregion
+
+        /// <summary>
+        /// 严格比较两个对象是否是同一对象
+        /// </summary>
+        /// <param name="_this">自己</param>
+        /// <param name="o">需要比较的对象</param>
+        /// <returns>是否同一对象</returns>
+        public new static bool ReferenceEquals(this object _this, object o) => object.ReferenceEquals(_this, o);
+
+        /// <summary>
+        /// 判断字符串是否为空
+        /// </summary>
+        /// <param name="s"></param>
+        /// <returns></returns>
+        public static bool IsNullOrEmpty(this string s) => string.IsNullOrEmpty(s);
+
+        /// <summary>
+        /// 类型直转
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="value"></param>
+        /// <returns></returns>
+        public static T To<T>(this IConvertible value)
+        {
+            try
+            {
+                return (T)Convert.ChangeType(value, typeof(T));
+            }
+            catch
+            {
+                return default(T);
+            }
+        }
+
+        /// <summary>
+        /// 字符串转时间
+        /// </summary>
+        /// <param name="value"></param>
+        /// <returns></returns>
+        public static DateTime ToDateTime(this string value)
+        {
+            try
+            {
+                return DateTime.Parse(value);
+            }
+            catch
+            {
+                return default(DateTime);
+            }
+        }
+
+        /// <summary>
+        /// 字符串转Guid
+        /// </summary>
+        /// <param name="s"></param>
+        /// <returns></returns>
+        public static Guid ToGuid(this string s)
+        {
+            return Guid.Parse(s);
+        }
+
+        /// <summary>
+        /// 根据正则替换
+        /// </summary>
+        /// <param name="input"></param>
+        /// <param name="regex">正则表达式</param>
+        /// <param name="replacement">新内容</param>
+        /// <returns></returns>
+        public static string Replace(this string input, Regex regex, string replacement)
+        {
+            return regex.Replace(input, replacement);
+        }
+    }
+}

+ 170 - 0
Masuit.Tools.Core/Files/FileExt.cs

@@ -0,0 +1,170 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Masuit.Tools.Files
+{
+    /// <summary>
+    /// 大文件操作扩展类
+    /// </summary>
+    public static class FileExt
+    {
+        /// <summary>
+        /// 以文件流的形式复制大文件
+        /// </summary>
+        /// <param name="fs">源</param>
+        /// <param name="dest">目标地址</param>
+        /// <param name="bufferSize">缓冲区大小,默认8MB</param>
+        public static void CopyToFile(this Stream fs, string dest, int bufferSize = 1024 * 8 * 1024)
+        {
+            using (FileStream fsWrite = new FileStream(dest, FileMode.OpenOrCreate, FileAccess.ReadWrite))
+            {
+                byte[] buf = new byte[bufferSize];
+                int len = 0;
+                while ((len = fs.Read(buf, 0, buf.Length)) != 0)
+                {
+                    fsWrite.Write(buf, 0, len);
+                }
+            }
+        }
+
+        /// <summary>
+        /// 以文件流的形式复制大文件(异步方式)
+        /// </summary>
+        /// <param name="fs">源</param>
+        /// <param name="dest">目标地址</param>
+        /// <param name="bufferSize">缓冲区大小,默认8MB</param>
+        public static async void CopyToFileAsync(this Stream fs, string dest, int bufferSize = 1024 * 1024 * 8)
+        {
+            using (FileStream fsWrite = new FileStream(dest, FileMode.OpenOrCreate, FileAccess.ReadWrite))
+            {
+                byte[] buf = new byte[bufferSize];
+                int len = 0;
+                await Task.Run(() =>
+                {
+                    using (fs)
+                    {
+                        while ((len = fs.Read(buf, 0, buf.Length)) != 0)
+                        {
+                            fsWrite.Write(buf, 0, len);
+                        }
+                    }
+                }).ConfigureAwait(true);
+            }
+        }
+
+        /// <summary>
+        /// 计算文件的 MD5 值
+        /// </summary>
+        /// <param name="fs">源文件流</param>
+        /// <returns>MD5 值16进制字符串</returns>
+        public static string GetFileMD5(this FileStream fs) => HashFile(fs, "md5");
+
+        /// <summary>
+        /// 计算文件的 MD5 值
+        /// </summary>
+        /// <param name="fs">源文件流</param>
+        /// <returns>MD5 值16进制字符串</returns>
+        public static Task<string> GetFileMD5Async(this FileStream fs) => HashFileAsync(fs, "md5");
+
+        /// <summary>
+        /// 计算文件的 sha1 值
+        /// </summary>
+        /// <param name="fs">源文件流</param>
+        /// <returns>sha1 值16进制字符串</returns>
+        public static string GetFileSha1(this Stream fs) => HashFile(fs, "sha1");
+
+        /// <summary>
+        /// 计算文件的 sha1 值
+        /// </summary>
+        /// <param name="fs">源文件流</param>
+        /// <returns>sha1 值16进制字符串</returns>
+        public static Task<string> GetFileSha1Async(this FileStream fs) => HashFileAsync(fs, "sha1");
+
+        /// <summary>
+        /// 计算文件的哈希值
+        /// </summary>
+        /// <param name="fs">被操作的源数据流</param>
+        /// <param name="algName">算法:sha1,md5</param>
+        /// <returns>哈希值16进制字符串</returns>
+        private static string HashFile(Stream fs, string algName)
+        {
+            byte[] hashBytes = HashData(fs, algName);
+            return ByteArrayToHexString(hashBytes);
+        }
+
+        /// <summary>
+        /// 计算文件的哈希值
+        /// </summary>
+        /// <param name="fs">被操作的源数据流</param>
+        /// <param name="algName">算法:sha1,md5</param>
+        /// <returns>哈希值16进制字符串</returns>
+        private static async Task<string> HashFileAsync(Stream fs, string algName)
+        {
+            byte[] hashBytes = await HashDataAsync(fs, algName).ConfigureAwait(false);
+            return ByteArrayToHexString(hashBytes);
+        }
+
+        /// <summary>
+        /// 计算哈希值
+        /// </summary>
+        /// <param name="stream">要计算哈希值的 Stream</param>
+        /// <param name="algName">算法:sha1,md5</param>
+        /// <returns>哈希值字节数组</returns>
+        private static byte[] HashData(System.IO.Stream stream, string algName)
+        {
+            System.Security.Cryptography.HashAlgorithm algorithm;
+            if (algName == null)
+            {
+                throw new ArgumentNullException("algName 不能为 null");
+            }
+            if (string.Compare(algName, "sha1", true) == 0)
+            {
+                algorithm = System.Security.Cryptography.SHA1.Create();
+            }
+            else
+            {
+                if (string.Compare(algName, "md5", true) != 0)
+                {
+                    throw new Exception("algName 只能使用 sha1 或 md5");
+                }
+                algorithm = System.Security.Cryptography.MD5.Create();
+            }
+            return algorithm.ComputeHash(stream);
+        }
+
+        /// <summary>
+        /// 计算哈希值
+        /// </summary>
+        /// <param name="stream">要计算哈希值的 Stream</param>
+        /// <param name="algName">算法:sha1,md5</param>
+        /// <returns>哈希值字节数组</returns>
+        private static async Task<byte[]> HashDataAsync(this Stream stream, string algName)
+        {
+            System.Security.Cryptography.HashAlgorithm algorithm;
+            if (algName == null)
+            {
+                throw new ArgumentNullException("algName 不能为 null");
+            }
+            if (string.Compare(algName, "sha1", true) == 0)
+            {
+                algorithm = System.Security.Cryptography.SHA1.Create();
+            }
+            else
+            {
+                if (string.Compare(algName, "md5", true) != 0)
+                {
+                    throw new Exception("algName 只能使用 sha1 或 md5");
+                }
+                algorithm = System.Security.Cryptography.MD5.Create();
+            }
+            return await Task.Run(() => algorithm.ComputeHash(stream)).ConfigureAwait(false);
+
+        }
+
+        /// <summary>
+        /// 字节数组转换为16进制表示的字符串
+        /// </summary>
+        private static string ByteArrayToHexString(byte[] buf) => BitConverter.ToString(buf).Replace("-", "");
+    }
+}

+ 89 - 0
Masuit.Tools.Core/Files/INIFile.cs

@@ -0,0 +1,89 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Masuit.Tools.Files
+{
+    /// <summary>
+    /// INI文件操作辅助类
+    /// </summary>
+    public class INIFile
+    {
+        /// <summary>
+        /// 文件路径
+        /// </summary>
+        public readonly string path;
+
+        /// <summary>
+        /// 传入INI文件路径构造对象
+        /// </summary>
+        /// <param name="INIPath">INI文件路径</param>
+        public INIFile(string INIPath)
+        {
+            path = INIPath;
+        }
+
+        [DllImport("kernel32")]
+        private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
+
+        [DllImport("kernel32")]
+        private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);
+
+        [DllImport("kernel32")]
+        private static extern int GetPrivateProfileString(string section, string key, string defVal, Byte[] retVal, int size, string filePath);
+
+        /// <summary>
+        /// 写INI文件
+        /// </summary>
+        /// <param name="Section">分组节点</param>
+        /// <param name="Key">关键字</param>
+        /// <param name="Value">值</param>
+        public void IniWriteValue(string Section, string Key, string Value)
+        {
+            WritePrivateProfileString(Section, Key, Value, this.path);
+        }
+
+        /// <summary>
+        /// 读取INI文件
+        /// </summary>
+        /// <param name="Section">分组节点</param>
+        /// <param name="Key">关键字</param>
+        /// <returns>值</returns>
+        public string IniReadValue(string Section, string Key)
+        {
+            StringBuilder temp = new StringBuilder(255);
+            int i = GetPrivateProfileString(Section, Key, "", temp, 255, this.path);
+            return temp.ToString();
+        }
+
+        /// <summary>
+        /// 读取INI文件
+        /// </summary>
+        /// <param name="section">分组节点</param>
+        /// <param name="key">关键字</param>
+        /// <returns>值的字节表现形式</returns>
+        public byte[] IniReadValues(string section, string key)
+        {
+            byte[] temp = new byte[255];
+            int i = GetPrivateProfileString(section, key, "", temp, 255, this.path);
+            return temp;
+        }
+
+        /// <summary>
+        /// 删除ini文件下所有段落
+        /// </summary>
+        public void ClearAllSection()
+        {
+            IniWriteValue(null, null, null);
+        }
+
+        /// <summary>
+        /// 删除ini文件下指定段落下的所有键
+        /// </summary>
+        /// <param name="Section">分组节点</param>
+        public void ClearSection(string Section)
+        {
+            IniWriteValue(Section, null, null);
+        }
+    }
+}

+ 931 - 0
Masuit.Tools.Core/Html/HtmlHelper.cs

@@ -0,0 +1,931 @@
+using System;
+using System.IO;
+using System.IO.Compression;
+using System.Net;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Web;
+using Masuit.Tools.Win32;
+
+namespace Masuit.Tools.Html
+{
+    /// <summary>
+    ///1、获取HTML<br/>
+    ///1.1获取指定页面的HTML代码 GetHtml(string url, string postData, bool isPost, CookieContainer cookieContainer)<br/>
+    ///1.2获取HTMLGetHtml(string url, CookieContainer cookieContainer)<br/>
+    ///2、获取字符流<br/>
+    ///2.1获取字符流GetStream(string url, CookieContainer cookieContainer)<br/>
+    ///3、清除HTML标记 <br/>
+    ///3.1清除HTML标记  NoHTML(string Htmlstring)<br/>
+    ///4、匹配页面的链接 <br/>
+    ///4.1获取页面的链接正则 GetHref(string HtmlCode)<br/>
+    ///5、匹配页面的图片地址<br/>
+    /// 5.1匹配页面的图片地址 GetImgSrc(string HtmlCode, string imgHttp)<br/>
+    ///5.2匹配<img src="" />中的图片路径实际链接  GetImg(string ImgString, string imgHttp)<br/>
+    ///6、抓取远程页面内容<br/>
+    /// 6.1以GET方式抓取远程页面内容 Get_Http(string tUrl)<br/>
+    /// 6.2以POST方式抓取远程页面内容 Post_Http(string url, string postData, string encodeType)<br/>
+    ///7、压缩HTML输出<br/>
+    ///7.1压缩HTML输出 ZipHtml(string Html)<br/>
+    ///8、过滤HTML标签<br/>
+    /// 8.1过滤指定HTML标签 DelHtml(string s_TextStr, string html_Str)  <br/>
+    /// 8.2过滤HTML中的不安全标签 RemoveUnsafeHtml(string content)<br/>
+    /// HTML转行成TEXT HtmlToTxt(string strHtml)<br/>
+    /// 字符串转换为 HtmlStringToHtml(string str)<br/>
+    /// html转换成字符串HtmlToString(string strHtml)<br/>
+    /// 获取URL编码<br/>
+    /// 判断URL是否有效<br/>
+    /// 返回 HTML 字符串的编码解码结果
+    /// </summary>
+    public static partial class HtmlTools
+    {
+        #region 私有字段
+        private static CookieContainer cc = new CookieContainer();
+        private static string contentType = "application/x-www-form-urlencoded";
+        private static string accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg," +
+                                       " application/x-shockwave-flash, application/x-silverlight, " +
+                                       "application/vnd.ms-excel, application/vnd.ms-powerpoint, " +
+                                       "application/msword, application/x-ms-application," +
+                                       " application/x-ms-xbap," +
+                                       " application/vnd.ms-xpsdocument, application/xaml+xml, application/x-silverlight-2-b1, */*";
+        private static string userAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1;" +
+                                          " .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)";
+        private static int delay = 1000;
+        private static int currentTry = 0;
+        #endregion
+
+        #region 公有属性
+        /// <summary> 
+        /// Cookie容器
+        /// </summary> 
+        public static CookieContainer CookieContainer
+        {
+            get { return cc; }
+        }
+
+        /// <summary> 
+        /// 获取网页源码时使用的编码
+        /// </summary> 
+        public static Encoding Encoding { get; set; } = Encoding.GetEncoding("utf-8");
+
+        /// <summary>
+        /// 网络延迟
+        /// </summary>
+        public static int NetworkDelay
+        {
+            get
+            {
+                Random r = new Random();
+                return r.Next(delay, delay * 2);
+                // return (r.Next(delay / 1000, delay / 1000 * 2)) * 1000;
+            }
+            set { delay = value; }
+        }
+
+        /// <summary>
+        /// 最大尝试次数
+        /// </summary>
+        public static int MaxTry { get; set; } = 300;
+        #endregion
+
+        #region 1、获取HTML
+
+        /// <summary>
+        /// 去除html标签后并截取字符串
+        /// </summary>
+        /// <param name="html">源html</param>
+        /// <param name="length">截取长度</param>
+        /// <returns></returns>
+        public static string RemoveHtmlTag(this string html, int length = 0)
+        {
+            string strText = Regex.Replace(html, "<[^>]+>", "");
+            strText = Regex.Replace(strText, "&[^;]+;", "");
+            if (length > 0 && strText.Length > length)
+            {
+                return strText.Substring(0, length);
+            }
+            return strText;
+        }
+
+        /// <summary>
+        /// 获取指定页面的HTML代码
+        /// </summary>
+        /// <param name="_"></param>
+        /// <param name="url">指定页面的路径</param>
+        /// <param name="postData">post 提交的字符串</param>
+        /// <param name="isPost">是否以post方式发送请求</param>
+        /// <param name="cookieContainer">Cookie集合</param>
+        public static string GetHtml(this HttpWebRequest _, string url, string postData, bool isPost, CookieContainer cookieContainer)
+        {
+            if (string.IsNullOrEmpty(postData))
+            {
+                return GetHtml(null, url, cookieContainer);
+            }
+            Thread.Sleep(NetworkDelay);
+            currentTry++;
+            HttpWebRequest httpWebRequest = null;
+            HttpWebResponse httpWebResponse = null;
+            try
+            {
+                byte[] byteRequest = Encoding.Default.GetBytes(postData);
+
+                httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
+                httpWebRequest.CookieContainer = cookieContainer;
+                httpWebRequest.ContentType = contentType;
+                httpWebRequest.ServicePoint.ConnectionLimit = MaxTry;
+                httpWebRequest.Referer = url;
+                httpWebRequest.Accept = accept;
+                httpWebRequest.UserAgent = userAgent;
+                httpWebRequest.Method = isPost ? "POST" : "GET";
+                httpWebRequest.ContentLength = byteRequest.Length;
+
+                httpWebRequest.AllowAutoRedirect = false;
+
+                Stream stream = httpWebRequest.GetRequestStream();
+                stream.Write(byteRequest, 0, byteRequest.Length);
+                stream.Close();
+
+                try
+                {
+                    httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
+                    //redirectURL = httpWebResponse.Headers["Location"];// Get redirected uri
+                }
+                catch (WebException ex)
+                {
+                    httpWebResponse = (HttpWebResponse)ex.Response;
+                }
+                //httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
+
+                Stream responseStream = httpWebResponse.GetResponseStream();
+                StreamReader streamReader = new StreamReader(responseStream, Encoding);
+                string html = streamReader.ReadToEnd();
+                streamReader.Close();
+                responseStream.Close();
+                currentTry = 0;
+                httpWebRequest.Abort();
+                httpWebResponse.Close();
+                return html;
+            }
+            catch (Exception)
+            {
+                if (currentTry <= MaxTry)
+                {
+                    GetHtml(null, url, postData, isPost, cookieContainer);
+                }
+                currentTry--;
+                if (httpWebRequest != null) httpWebRequest.Abort();
+                if (httpWebResponse != null) httpWebResponse.Close();
+                return string.Empty;
+            }
+        }
+
+        /// <summary>
+        /// 获取HTML
+        /// </summary>
+        /// <param name="_"></param>
+        /// <param name="url">地址</param>
+        /// <param name="cookieContainer">Cookie集合</param>
+        public static string GetHtml(this HttpWebRequest _, string url, CookieContainer cookieContainer)
+        {
+            Thread.Sleep(NetworkDelay);
+            currentTry++;
+            HttpWebRequest httpWebRequest = null;
+            HttpWebResponse httpWebResponse = null;
+            try
+            {
+                httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
+                httpWebRequest.CookieContainer = cookieContainer;
+                httpWebRequest.ContentType = contentType;
+                httpWebRequest.ServicePoint.ConnectionLimit = MaxTry;
+                httpWebRequest.Referer = url;
+                httpWebRequest.Accept = accept;
+                httpWebRequest.UserAgent = userAgent;
+                httpWebRequest.Method = "GET";
+                httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
+                Stream responseStream = httpWebResponse.GetResponseStream();
+                StreamReader streamReader = new StreamReader(responseStream, Encoding);
+                string html = streamReader.ReadToEnd();
+                streamReader.Close();
+                responseStream.Close();
+                currentTry--;
+                httpWebRequest.Abort();
+                httpWebResponse.Close();
+                return html;
+            }
+            catch (Exception)
+            {
+                if (currentTry <= MaxTry) GetHtml(null, url, cookieContainer);
+                currentTry--;
+                if (httpWebRequest != null) httpWebRequest.Abort();
+                if (httpWebResponse != null) httpWebResponse.Close();
+                return string.Empty;
+            }
+        }
+        #endregion
+
+        #region 2、获取字符流
+
+        ///  <summary>
+        ///  2.1获取字符流
+        ///  </summary>
+        /// ---------------------------------------------------------------------------------------------------------------
+        ///  示例:
+        ///  System.Net.CookieContainer cookie = new System.Net.CookieContainer(); 
+        ///  Stream s = HttpHelper.GetStream("http://www.baidu.com", cookie);
+        ///  picVerify.Image = Image.FromStream(s);
+        /// ---------------------------------------------------------------------------------------------------------------
+        /// <param name="_"></param>
+        /// <param name="url">地址</param>
+        ///  <param name="cookieContainer">cookieContainer</param>
+        public static Stream GetStream(this HttpWebRequest _, string url, CookieContainer cookieContainer)
+        {
+            currentTry++;
+
+            HttpWebRequest httpWebRequest = null;
+            HttpWebResponse httpWebResponse = null;
+
+            try
+            {
+                httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
+                httpWebRequest.CookieContainer = cookieContainer;
+                httpWebRequest.ContentType = contentType;
+                httpWebRequest.ServicePoint.ConnectionLimit = MaxTry;
+                httpWebRequest.Referer = url;
+                httpWebRequest.Accept = accept;
+                httpWebRequest.UserAgent = userAgent;
+                httpWebRequest.Method = "GET";
+
+                httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
+                Stream responseStream = httpWebResponse.GetResponseStream();
+                currentTry--;
+                return responseStream;
+            }
+            catch (Exception)
+            {
+                if (currentTry <= MaxTry)
+                {
+                    GetHtml(null, url, cookieContainer);
+                }
+
+                currentTry--;
+
+                if (httpWebRequest != null)
+                {
+                    httpWebRequest.Abort();
+                }
+                if (httpWebResponse != null)
+                {
+                    httpWebResponse.Close();
+                }
+                return null;
+            }
+        }
+        #endregion
+
+        #region 3、清除HTML标记
+
+        /// <summary>
+        /// 清理Word文档转html后的冗余标签属性
+        /// </summary>
+        /// <param name="html"></param>
+        /// <returns></returns>
+        public static string ClearHtml(this string html)
+        {
+            string s = Regex.Match(Regex.Replace(html, @"background-color:#?\w{3,7}|font-family:'?[\w|\(|\)]*'?;?", string.Empty), @"<body[^>]*>([\s\S]*)<\/body>").Groups[1].Value.Replace("&#xa0;", string.Empty);
+            s = Regex.Replace(s, @"\w+-?\w+:0\w+;?", string.Empty);//去除多余的零值属性
+            s = Regex.Replace(s, "alt=\"(.+?)\"", string.Empty);//除去alt属性
+            s = Regex.Replace(s, @"-aw.+?\s", string.Empty);//去除Word产生的-aw属性
+            return s;
+        }
+
+        ///<summary>   
+        ///3.1清除HTML标记   
+        ///</summary>   
+        ///<param name="htmlstring">包括HTML的源码</param>   
+        ///<returns>已经去除后的文字</returns>   
+        public static string RemoveHtml(this string htmlstring)
+        {
+            //删除脚本   
+            htmlstring = Regex.Replace(htmlstring, @"<script[^>]*?>.*?</script>", "", RegexOptions.IgnoreCase);
+
+            //删除HTML   
+            Regex regex = new Regex("<.+?>", RegexOptions.IgnoreCase);
+            htmlstring = regex.Replace(htmlstring, "");
+            htmlstring = Regex.Replace(htmlstring, @"<(.[^>]*)>", "", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"([\r\n])[\s]+", "", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"-->", "", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"<!--.*", "", RegexOptions.IgnoreCase);
+
+            htmlstring = Regex.Replace(htmlstring, @"&(quot|#34);", "\"", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"&(amp|#38);", "&", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"&(lt|#60);", "<", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"&(gt|#62);", ">", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"&(nbsp|#160);", "   ", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"&(iexcl|#161);", "\xa1", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"&(cent|#162);", "\xa2", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"&(pound|#163);", "\xa3", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"&(copy|#169);", "\xa9", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"&#(\d+);", "", RegexOptions.IgnoreCase);
+
+            htmlstring.Replace("<", "");
+            htmlstring.Replace(">", "");
+            htmlstring.Replace("\r\n", "");
+
+            return htmlstring;
+        }
+
+        #endregion
+
+        #region 4、匹配页面的链接
+        #region 4.1获取页面的链接正则
+        /// <summary>
+        /// 4.1获取页面的链接正则
+        /// </summary>
+        /// <param name="HtmlCode">html代码</param>
+        public static string GetHref(this string HtmlCode)
+        {
+            string MatchVale = "";
+            string Reg = @"(h|H)(r|R)(e|E)(f|F) *= *('|"")?((\w|\\|\/|\.|:|-|_)+)[\S]*";
+            foreach (Match m in Regex.Matches(HtmlCode, Reg))
+            {
+                MatchVale += (m.Value).ToLower().Replace("href=", "").Trim() + "|";
+            }
+            return MatchVale;
+        }
+        #endregion
+
+        #region  4.2取得所有链接URL
+        /// <summary>
+        /// 4.2取得所有链接URL
+        /// </summary>
+        /// <param name="html">html代码</param>
+        /// <returns>提取到的url</returns>
+        public static string GetAllUrl(this string html)
+        {
+            StringBuilder sb = new StringBuilder();
+            Match m = Regex.Match(html.ToLower(), "<a href=(.*?)>.*?</a>");
+            while (m.Success)
+            {
+                sb.AppendLine(m.Result("$1"));
+                m.NextMatch();
+            }
+            return sb.ToString();
+        }
+        #endregion
+
+        #region 4.3获取所有连接文本
+        /// <summary>
+        /// 4.3获取所有连接文本
+        /// </summary>
+        /// <param name="html">html代码</param>
+        /// <returns>所有的带链接的a标签</returns>
+        public static string GetAllLinkText(this string html)
+        {
+            StringBuilder sb = new StringBuilder();
+            Match m = Regex.Match(html.ToLower(), "<a href=.*?>(1,100})</a>");
+
+            while (m.Success)
+            {
+                sb.AppendLine(m.Result("$1"));
+                m.NextMatch();
+            }
+
+            return sb.ToString();
+        }
+        #endregion
+        #endregion
+
+        #region  5、匹配页面的图片地址
+
+        /// <summary>
+        /// 替换html的img路径为绝对路径
+        /// </summary>
+        /// <param name="html"></param>
+        /// <param name="imgDest"></param>
+        /// <returns></returns>
+        public static string ReplaceHtmlImgSource(this string html, string imgDest) => html.Replace("<img src=\"", "<img src=\"" + imgDest + "/");
+
+        /// <summary>
+        /// 匹配页面的图片地址
+        /// </summary>
+        /// <param name="htmlCode">html代码</param>
+        /// <param name="imgHttp">要补充的http://路径信息</param>
+        public static string GetImgSrc(this string htmlCode, string imgHttp)
+        {
+            string matchVale = "";
+            string Reg = @"<img.+?>";
+            foreach (Match m in Regex.Matches(htmlCode.ToLower(), Reg))
+            {
+                matchVale += GetImg((m.Value).ToLower().Trim(), imgHttp) + "|";
+            }
+            return matchVale;
+        }
+
+        /// <summary>
+        /// 将src的绝对路径换成相对路径
+        /// </summary>
+        /// <param name="s"></param>
+        /// <returns></returns>
+        public static string ConvertImgSrcToRelativePath(this string s)
+        {
+            return Regex.Replace(s, @"<img src=""(http:\/\/.+?)/", @"<img src=""/");
+        }
+
+
+        /// <summary>
+        /// 匹配html的所有img标签集合
+        /// </summary>
+        /// <param name="html"></param>
+        /// <returns></returns>
+        public static MatchCollection MatchImgTags(this string html) => Regex.Matches(html, @"<img[\s]+src[\s]*=[\s]*((['""](?<src>[^'""]*)[\'""])|(?<src>[^\s]*))");
+
+        /// <summary>
+        /// 匹配html的一个img标签
+        /// </summary>
+        /// <param name="html"></param>
+        /// <returns></returns>
+        public static Match MatchImgTag(this string html) => Regex.Match(html, @"<img[\s]+src[\s]*=[\s]*((['""](?<src>[^'""]*)[\'""])|(?<src>[^\s]*))");
+
+        /// <summary>
+        /// 获取html中第一个img标签的src
+        /// </summary>
+        /// <param name="html"></param>
+        /// <returns></returns>
+        public static string MatchFirstImgSrc(this string html)
+        {
+            MatchCollection collection = MatchImgTags(html);
+            return collection.Count > 0 ? collection[0].Groups["src"].Value : String.Empty;
+        }
+
+        /// <summary>
+        /// 随机获取html代码中的img标签的src属性
+        /// </summary>
+        /// <param name="html"></param>
+        /// <returns></returns>
+        public static string MatchRandomImgSrc(this string html)
+        {
+            MatchCollection collection = MatchImgTags(html);
+            if (collection.Count > 0)
+            {
+                string img = collection[new Random().StrictNext(collection.Count)].Value;
+                if (img.StartsWith("<"))
+                {
+                    return img.MatchImgTag().Groups["src"].Value;
+                }
+            }
+            return String.Empty;
+        }
+
+        /// <summary>
+        /// 匹配<img src="" />中的图片路径实际链接
+        /// </summary>
+        /// <param name="imgString"><img src="" />字符串</param>
+        /// <param name="imgHttp">图片路径</param>
+        public static string GetImg(this string imgString, string imgHttp)
+        {
+            string matchVale = "";
+            string Reg = @"src=.+\.(bmp|jpg|gif|png|)";
+            foreach (Match m in Regex.Matches(imgString.ToLower(), Reg))
+            {
+                matchVale += (m.Value).ToLower().Trim().Replace("src=", "");
+            }
+            if (matchVale.IndexOf(".net") != -1 || matchVale.IndexOf(".com") != -1 || matchVale.IndexOf(".org") != -1 || matchVale.IndexOf(".cn") != -1 || matchVale.IndexOf(".cc") != -1 || matchVale.IndexOf(".info") != -1 || matchVale.IndexOf(".biz") != -1 || matchVale.IndexOf(".tv") != -1)
+            {
+                return matchVale;
+            }
+            return imgHttp + matchVale;
+        }
+        #endregion
+
+        #region 6、抓取远程页面内容
+
+        /// <summary>
+        /// 6.1以GET方式抓取远程页面内容
+        /// </summary>
+        /// <param name="_"></param>
+        /// <param name="tUrl">URL</param>
+        public static string Get_Http(this HttpWebRequest _, string tUrl)
+        {
+            string strResult;
+            try
+            {
+                var hwr = (HttpWebRequest)WebRequest.Create(tUrl);
+                hwr.Timeout = 19600;
+                var hwrs = (HttpWebResponse)hwr.GetResponse();
+                Stream myStream = hwrs.GetResponseStream();
+                var sr = new StreamReader(myStream, Encoding.Default);
+                var sb = new StringBuilder();
+                while (-1 != sr.Peek())
+                {
+                    sb.Append(sr.ReadLine() + "\r\n");
+                }
+                strResult = sb.ToString();
+                hwrs.Close();
+            }
+            catch (Exception ee)
+            {
+                strResult = ee.Message;
+            }
+            return strResult;
+        }
+
+        /// <summary>
+        /// 6.2以POST方式抓取远程页面内容
+        /// </summary>
+        /// <param name="_"></param>
+        /// <param name="url">URL</param>
+        /// <param name="postData">参数列表</param>
+        /// <param name="encodeType">编码类型</param>
+        public static string Post_Http(this HttpWebRequest _, string url, string postData, string encodeType)
+        {
+            string strResult;
+            try
+            {
+                Encoding encoding = Encoding.GetEncoding(encodeType);
+                byte[] POST = encoding.GetBytes(postData);
+                HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(url);
+                myRequest.Method = "POST";
+                myRequest.ContentType = "application/x-www-form-urlencoded";
+                myRequest.ContentLength = POST.Length;
+                Stream newStream = myRequest.GetRequestStream();
+                newStream.Write(POST, 0, POST.Length); //设置POST
+                newStream.Close();
+                HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
+                StreamReader reader = new StreamReader(myResponse.GetResponseStream(), Encoding.Default);
+                strResult = reader.ReadToEnd();
+            }
+            catch (Exception ex)
+            {
+                strResult = ex.Message;
+            }
+            return strResult;
+        }
+        #endregion
+
+        #region 7、压缩HTML输出
+        /// <summary>
+        /// 7.1压缩HTML输出
+        /// </summary>
+        /// <param name="html">html</param>
+        public static string ZipHtml(this string html)
+        {
+            html = Regex.Replace(html, @">\s+?<", "><");//去除HTML中的空白字符
+            html = Regex.Replace(html, @"\r\n\s*", "");
+            html = Regex.Replace(html, @"<body([\s|\S]*?)>([\s|\S]*?)</body>", @"<body$1>$2</body>", RegexOptions.IgnoreCase);
+            return html;
+        }
+        #endregion
+
+        #region 8、过滤HTML标签
+        #region 8.1过滤指定HTML标签
+
+        /// <summary>
+        /// 8.1过滤指定HTML标签
+        /// </summary>
+        /// <param name="sTextStr">要过滤的字符</param>
+        /// <param name="htmlStr">a img p div</param>
+        public static string DelHtml(this string sTextStr, string htmlStr)
+        {
+            string rStr = "";
+            if (!string.IsNullOrEmpty(sTextStr))
+            {
+                rStr = Regex.Replace(sTextStr, "<" + htmlStr + "[^>]*>", "", RegexOptions.IgnoreCase);
+                rStr = Regex.Replace(rStr, "</" + htmlStr + ">", "", RegexOptions.IgnoreCase);
+            }
+            return rStr;
+        }
+        #endregion
+        #region 8.2过滤HTML中的不安全标签
+
+        /// <summary>
+        /// 8.2过滤HTML中的不安全标签,去掉尖括号
+        /// </summary>
+        /// <param name="content">html代码</param>
+        /// <returns>过滤后的安全内容</returns>
+        public static string RemoveUnsafeHtml(this string content)
+        {
+            content = Regex.Replace(content, @"(\<|\s+)o([a-z]+\s?=)", "$1$2", RegexOptions.IgnoreCase);
+            content = Regex.Replace(content, @"(script|frame|form|meta|behavior|style)([\s|:|>])+", "$1.$2", RegexOptions.IgnoreCase);
+            return content;
+        }
+        #endregion
+        #endregion
+
+        #region 转换HTML操作
+
+        #region HTML转行成TEXT
+        /// <summary>
+        /// HTML转行成TEXT HtmlToTxt(string strHtml)
+        /// </summary>
+        /// <param name="strHtml">html代码</param>
+        /// <returns>普通文本</returns>
+        public static string HtmlToTxt(this string strHtml)
+        {
+            string[] aryReg ={
+            @"<script[^>]*?>.*?</script>",
+            @"<(\/\s*)?!?((\w+:)?\w+)(\w+(\s*=?\s*(([""'])(\\[""'tbnr]|[^\7])*?\7|\w+)|.{0})|\s)*?(\/\s*)?>",
+            @"([\r\n])[\s]+",
+            @"&(quot|#34);",
+            @"&(amp|#38);",
+            @"&(lt|#60);",
+            @"&(gt|#62);",
+            @"&(nbsp|#160);",
+            @"&(iexcl|#161);",
+            @"&(cent|#162);",
+            @"&(pound|#163);",
+            @"&(copy|#169);",
+            @"&#(\d+);",
+            @"-->",
+            @"<!--.*\n"
+            };
+
+            string strOutput = strHtml;
+            for (int i = 0; i < aryReg.Length; i++)
+            {
+                Regex regex = new Regex(aryReg[i], RegexOptions.IgnoreCase);
+                strOutput = regex.Replace(strOutput, string.Empty);
+            }
+            strOutput.Replace("<", "");
+            strOutput.Replace(">", "");
+            strOutput.Replace("\r\n", "");
+            return strOutput;
+        }
+        #endregion
+
+        #region 字符串转换为 Html
+        /// <summary>
+        /// 字符串转换为 HtmlStringToHtml(string str)
+        /// </summary>
+        /// <param name="str">字符串</param>
+        /// <returns>html标签</returns>
+        public static string StringToHtml(this string str)
+        {
+            str = str.Replace("&", "&amp;");
+            str = str.Replace(" ", "&nbsp;");
+            str = str.Replace("'", "''");
+            str = str.Replace("\"", "&quot;");
+            str = str.Replace("<", "&lt;");
+            str = str.Replace(">", "&gt;");
+            str = str.Replace("\n", "<br />");
+            str = str.Replace("\r", "<br />");
+            str = str.Replace("\r\n", "<br />");
+            return str;
+        }
+        #endregion
+
+        #region Html转换成字符串
+        /// <summary>
+        /// html转换成字符串
+        /// </summary>
+        /// <param name="strHtml">html代码</param>
+        /// <returns>安全的字符串</returns>
+        public static string HtmlToString(this string strHtml)
+        {
+            strHtml = strHtml.Replace("<br>", "\r\n");
+            strHtml = strHtml.Replace(@"<br />", "\r\n");
+            strHtml = strHtml.Replace(@"<br/>", "\r\n");
+            strHtml = strHtml.Replace("&gt;", ">");
+            strHtml = strHtml.Replace("&lt;", "<");
+            strHtml = strHtml.Replace("&nbsp;", " ");
+            strHtml = strHtml.Replace("&quot;", "\"");
+            strHtml = Regex.Replace(strHtml, @"<\/?[^>]+>", "", RegexOptions.IgnoreCase);
+            return strHtml;
+        }
+        #endregion
+        #endregion
+
+        #region 获取URL编码
+
+        /// <summary>
+        /// 获取URL编码
+        /// </summary>
+        /// <param name="_"></param>
+        /// <param name="url">URL</param>
+        /// <returns>编码类型</returns>
+        public static string GetEncoding(this HttpWebRequest _, string url)
+        {
+            HttpWebRequest request = null;
+            HttpWebResponse response = null;
+            StreamReader reader = null;
+            try
+            {
+                request = (HttpWebRequest)WebRequest.Create(url);
+                request.Timeout = 20000;
+                request.AllowAutoRedirect = false;
+                response = (HttpWebResponse)request.GetResponse();
+                if (response.StatusCode == HttpStatusCode.OK && response.ContentLength < 1024 * 1024)
+                {
+                    if (response.ContentEncoding.Equals("gzip", StringComparison.InvariantCultureIgnoreCase))
+                    {
+                        reader = new StreamReader(new GZipStream(response.GetResponseStream(), CompressionMode.Decompress));
+                    }
+                    else
+                    {
+                        reader = new StreamReader(response.GetResponseStream(), Encoding.ASCII);
+                    }
+
+                    string html = reader.ReadToEnd();
+                    Regex regCharset = new Regex(@"charset\b\s*=\s*(?<charset>[^""]*)");
+                    if (regCharset.IsMatch(html))
+                    {
+                        return regCharset.Match(html).Groups["charset"].Value;
+                    }
+                    else if (response.CharacterSet != string.Empty)
+                    {
+                        return response.CharacterSet;
+                    }
+                    else
+                    {
+                        return Encoding.Default.BodyName;
+                    }
+                }
+            }
+            finally
+            {
+                if (response != null)
+                {
+                    response.Close();
+                    response = null;
+                }
+                if (reader != null)
+                    reader.Close();
+                if (request != null)
+                    request = null;
+            }
+            return Encoding.Default.BodyName;
+        }
+        #endregion
+
+        #region 判断URL是否有效
+
+        /// <summary>
+        /// 判断URL是否有效
+        /// </summary>
+        /// <param name="_"></param>
+        /// <param name="url">待判断的URL,可以是网页以及图片链接等</param>
+        /// <returns>200为正确,其余为大致网页错误代码</returns>
+        public static int GetUrlError(this HttpWebRequest _, string url)
+        {
+            int num = 200;
+            try
+            {
+                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(url));
+                ServicePointManager.Expect100Continue = false;
+                ((HttpWebResponse)request.GetResponse()).Close();
+            }
+            catch (WebException exception)
+            {
+                if (exception.Status != WebExceptionStatus.ProtocolError)
+                {
+                    return num;
+                }
+                if (exception.Message.IndexOf("500 ") > 0)
+                {
+                    return 500;
+                }
+                if (exception.Message.IndexOf("401 ") > 0)
+                {
+                    return 401;
+                }
+                if (exception.Message.IndexOf("404") > 0)
+                {
+                    num = 404;
+                }
+            }
+            catch
+            {
+                num = 401;
+            }
+            return num;
+        }
+        #endregion
+
+        #region 返回 HTML 字符串的编码解码结果
+        /// <summary>
+        /// 返回 HTML 字符串的编码结果
+        /// </summary>
+        /// <param name="inputData">字符串</param>
+        /// <returns>编码结果</returns>
+        public static string HtmlEncode(string inputData)
+        {
+            return HttpUtility.HtmlEncode(inputData);
+        }
+
+        /// <summary>
+        /// 返回 HTML 字符串的解码结果
+        /// </summary>
+        /// <param name="str">字符串</param>
+        /// <returns>解码结果</returns>
+        public static string HtmlDecode(string str)
+        {
+            return HttpUtility.HtmlDecode(str);
+        }
+        #endregion
+
+        /// <summary>
+        /// 获取Cookie集合
+        /// </summary>
+        /// <param name="cookie"></param>
+        /// <param name="cookieString">Cookie的键</param>
+        /// <returns>Cookie键值集合</returns>
+        public static CookieCollection GetCookieCollection(this CookieCollection cookie, string cookieString)
+        {
+            //string cookieString = "SID=ARRGy4M1QVBtTU-ymi8bL6X8mVkctYbSbyDgdH8inu48rh_7FFxHE6MKYwqBFAJqlplUxq7hnBK5eqoh3E54jqk=;Domain=.google.com;Path=/,LSID=AaMBTixN1MqutGovVSOejyb8mVkctYbSbyDgdH8inu48rh_7FFxHE6MKYwqBFAJqlhCe_QqxLg00W5OZejb_UeQ=;Domain=www.google.com;Path=/accounts";
+            Regex re = new Regex("([^;,]+)=([^;,]+);Domain=([^;,]+);Path=([^;,]+)", RegexOptions.IgnoreCase);
+            foreach (Match m in re.Matches(cookieString))
+            {
+                //name,   value,   path,   domain   
+                Cookie c = new Cookie(m.Groups[1].Value, m.Groups[2].Value, m.Groups[3].Value, m.Groups[3].Value);
+                cookie.Add(c);
+            }
+            return cookie;
+        }
+
+        #region 从HTML中获取文本,保留br,p,img
+
+        /// <summary>
+        /// 从HTML中获取文本,保留br,p,img
+        /// </summary>
+        /// <param name="HTML">html代码</param>
+        /// <returns>保留br,p,img的文本</returns>
+        public static string GetTextFromHTML(this string HTML)
+        {
+            Regex regEx = new Regex(@"</?(?!br|/?p|img)[^>]*>", RegexOptions.IgnoreCase);
+
+            return regEx.Replace(HTML, "");
+        }
+        #endregion
+
+        #region 获取HTML页面内制定Key的Value内容
+
+        /// <summary>
+        /// 获取HTML页面内制定Key的Value内容
+        /// </summary>
+        /// <param name="html">html源代码</param>
+        /// <param name="key">键</param>
+        /// <returns>获取到的值</returns>
+        public static string GetHiddenKeyValue(this string html, string key)
+        {
+            string result = "";
+            string sRegex = string.Format("<input\\s*type=\"hidden\".*?name=\"{0}\".*?\\s*value=[\"|'](?<value>.*?)[\"|'^/]", key);
+            Regex re = new Regex(sRegex, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
+            Match mc = re.Match(html);
+            if (mc.Success)
+            {
+                result = mc.Groups[1].Value;
+            }
+            return result;
+        }
+        #endregion
+
+        /// <summary>
+        /// 替换回车换行符为html换行符
+        /// </summary>
+        /// <param name="str">html</param>
+        public static string StrFormat(this string str)
+        {
+            string str2;
+            if (str == null)
+            {
+                str2 = "";
+            }
+            else
+            {
+                str = str.Replace("\r\n", "<br />");
+                str = str.Replace("\n", "<br />");
+                str2 = str;
+            }
+            return str2;
+        }
+        /// <summary>
+        /// 替换html字符
+        /// </summary>
+        /// <param name="strHtml">html</param>
+        public static string EncodeHtml(this string strHtml)
+        {
+            if (strHtml != "")
+            {
+                strHtml = strHtml.Replace(",", "&def");
+                strHtml = strHtml.Replace("'", "&dot");
+                strHtml = strHtml.Replace(";", "&dec");
+                return strHtml;
+            }
+            return "";
+        }
+
+        /// <summary>
+        /// 为脚本替换特殊字符串
+        /// </summary>
+        /// <param name="str"> </param>
+        /// <returns> </returns>
+        [Obsolete("不建议使用", true)]
+        public static string ReplaceStrToScript(string str)
+        {
+            str = str.Replace("\\", "\\\\");
+            str = str.Replace("'", "\\'");
+            str = str.Replace("\"", "\\\"");
+            return str;
+        }
+    }
+}

+ 1635 - 0
Masuit.Tools.Core/Html/HtmlTools.cs

@@ -0,0 +1,1635 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Data;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Web;
+using System.Xml;
+using Ganss.XSS;
+using Masuit.Tools.Logging;
+
+namespace Masuit.Tools.Html
+{
+    /// <summary>
+    /// html工具类
+    /// </summary>
+    public static partial class HtmlTools
+    {
+        #region 防止html的xss净化器
+        /// <summary>
+        /// 标准的防止html的xss净化器
+        /// </summary>
+        /// <param name="html"></param>
+        /// <returns></returns>
+        public static string HtmlSantinizerStandard(this string html)
+        {
+            var sanitizer = new HtmlSanitizer();
+            sanitizer.AllowedAttributes.Remove("id");
+            sanitizer.AllowedAttributes.Remove("alt");
+            sanitizer.AllowedCssProperties.Remove("font-family");
+            sanitizer.AllowedCssProperties.Remove("background-color");
+            sanitizer.KeepChildNodes = true;
+            sanitizer.AllowedTags.Remove("input");
+            sanitizer.AllowedTags.Remove("button");
+            sanitizer.AllowedTags.Remove("iframe");
+            sanitizer.AllowedTags.Remove("frame");
+            sanitizer.AllowedTags.Remove("textarea");
+            sanitizer.AllowedTags.Remove("select");
+            sanitizer.AllowedTags.Remove("form");
+            return sanitizer.Sanitize(html);
+        }
+
+        /// <summary>
+        /// 自定义的防止html的xss净化器
+        /// </summary>
+        /// <param name="html">源html</param>
+        /// <param name="labels">需要移除的标签集合</param>
+        /// <param name="attributes">需要移除的属性集合</param>
+        /// <param name="styles">需要移除的样式集合</param>
+        /// <returns></returns>
+        public static string HtmlSantinizerCustom(this string html, string[] labels = null, string[] attributes = null, string[] styles = null)
+        {
+            var sanitizer = new HtmlSanitizer();
+            if (labels != null)
+            {
+                foreach (string label in labels)
+                {
+                    sanitizer.AllowedTags.Remove(label);
+                }
+            }
+
+            if (attributes != null)
+            {
+                foreach (string attr in attributes)
+                {
+                    sanitizer.AllowedAttributes.Remove(attr);
+                }
+            }
+
+            if (styles != null)
+            {
+                foreach (string p in styles)
+                {
+                    sanitizer.AllowedCssProperties.Remove(p);
+                }
+            }
+            sanitizer.KeepChildNodes = true;
+            return sanitizer.Sanitize(html);
+        }
+        #endregion
+        #region BaseMethod
+        /// <summary>
+        /// 多个匹配内容
+        /// </summary>
+        /// <param name="sInput">输入内容</param>
+        /// <param name="sRegex">表达式字符串</param>
+        /// <param name="iGroupIndex">第几个分组, 从1开始, 0代表不分组</param>
+        public static List<string> GetList(string sInput, string sRegex, int iGroupIndex)
+        {
+            List<string> list = new List<string>();
+            Regex re = new Regex(sRegex, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
+            MatchCollection mcs = re.Matches(sInput);
+            foreach (Match mc in mcs)
+            {
+                if (iGroupIndex > 0)
+                {
+                    list.Add(mc.Groups[iGroupIndex].Value);
+                }
+                else
+                {
+                    list.Add(mc.Value);
+                }
+            }
+            return list;
+        }
+
+        /// <summary>
+        /// 多个匹配内容
+        /// </summary>
+        /// <param name="sInput">输入内容</param>
+        /// <param name="sRegex">表达式字符串</param>
+        /// <param name="sGroupName">分组名, ""代表不分组</param>
+        public static List<string> GetList(string sInput, string sRegex, string sGroupName)
+        {
+            List<string> list = new List<string>();
+            Regex re = new Regex(sRegex, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
+            MatchCollection mcs = re.Matches(sInput);
+            foreach (Match mc in mcs)
+            {
+                if (sGroupName != "")
+                {
+                    list.Add(mc.Groups[sGroupName].Value);
+                }
+                else
+                {
+                    list.Add(mc.Value);
+                }
+            }
+            return list;
+        }
+
+        /// <summary>
+        /// 单个匹配内容
+        /// </summary>
+        /// <param name="sInput">输入内容</param>
+        /// <param name="sRegex">表达式字符串</param>
+        /// <param name="iGroupIndex">分组序号, 从1开始, 0不分组</param>
+        public static string GetText(string sInput, string sRegex, int iGroupIndex)
+        {
+            Regex re = new Regex(sRegex, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
+            Match mc = re.Match(sInput);
+            string result = "";
+            if (mc.Success)
+            {
+                if (iGroupIndex > 0)
+                {
+                    result = mc.Groups[iGroupIndex].Value;
+                }
+                else
+                {
+                    result = mc.Value;
+                }
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// 单个匹配内容
+        /// </summary>
+        /// <param name="sInput">输入内容</param>
+        /// <param name="sRegex">表达式字符串</param>
+        /// <param name="sGroupName">分组名, ""代表不分组</param>
+        public static string GetText(string sInput, string sRegex, string sGroupName)
+        {
+            Regex re = new Regex(sRegex, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
+            Match mc = re.Match(sInput);
+            string result = "";
+            if (mc.Success)
+            {
+                if (sGroupName != "")
+                {
+                    result = mc.Groups[sGroupName].Value;
+                }
+                else
+                {
+                    result = mc.Value;
+                }
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// 替换指定内容
+        /// </summary>
+        /// <param name="sInput">输入内容</param>
+        /// <param name="sRegex">表达式字符串</param>
+        /// <param name="sReplace">替换值</param>
+        /// <param name="iGroupIndex">分组序号, 0代表不分组</param>
+        public static string Replace(string sInput, string sRegex, string sReplace, int iGroupIndex)
+        {
+            Regex re = new Regex(sRegex, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
+            MatchCollection mcs = re.Matches(sInput);
+            foreach (Match mc in mcs)
+            {
+                if (iGroupIndex > 0)
+                {
+                    sInput = sInput.Replace(mc.Groups[iGroupIndex].Value, sReplace);
+                }
+                else
+                {
+                    sInput = sInput.Replace(mc.Value, sReplace);
+                }
+            }
+            return sInput;
+        }
+
+        /// <summary>
+        /// 替换指定内容
+        /// </summary>
+        /// <param name="sInput">输入内容</param>
+        /// <param name="sRegex">表达式字符串</param>
+        /// <param name="sReplace">替换值</param>
+        /// <param name="sGroupName">分组名, "" 代表不分组</param>
+        public static string Replace(string sInput, string sRegex, string sReplace, string sGroupName)
+        {
+            Regex re = new Regex(sRegex, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
+            MatchCollection mcs = re.Matches(sInput);
+            foreach (Match mc in mcs)
+            {
+                if (sGroupName != "")
+                {
+                    sInput = sInput.Replace(mc.Groups[sGroupName].Value, sReplace);
+                }
+                else
+                {
+                    sInput = sInput.Replace(mc.Value, sReplace);
+                }
+            }
+            return sInput;
+        }
+
+        /// <summary>
+        /// 分割指定内容
+        /// </summary>
+        /// <param name="sInput">输入内容</param>
+        /// <param name="sRegex">表达式字符串</param>
+        /// <param name="iStrLen">最小保留字符串长度</param>
+        public static List<string> Split(string sInput, string sRegex, int iStrLen)
+        {
+            Regex re = new Regex(sRegex, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
+            string[] sArray = re.Split(sInput);
+            List<string> list = new List<string>();
+            list.Clear();
+            foreach (string s in sArray)
+            {
+                if (s.Trim().Length < iStrLen)
+                    continue;
+
+                list.Add(s.Trim());
+            }
+            return list;
+        }
+
+        #endregion BaseMethod
+
+        #region 获得特定内容
+
+        /// <summary>
+        /// 多个链接
+        /// </summary>
+        /// <param name="sInput">输入内容</param>
+        public static List<string> GetLinks(string sInput)
+        {
+            return GetList(sInput, @"<a[^>]+href=\s*(?:'(?<href>[^']+)'|""(?<href>[^""]+)""|(?<href>[^>\s]+))\s*[^>]*>", "href");
+        }
+
+        /// <summary>
+        /// 单个链接
+        /// </summary>
+        /// <param name="sInput">输入内容</param>
+        public static string GetLinkHelp(string sInput)
+        {
+            return GetText(sInput, @"<a[^>]+href=\s*(?:'(?<href>[^']+)'|""(?<href>[^""]+)""|(?<href>[^>\s]+))\s*[^>]*>", "href");
+        }
+
+        /// <summary>
+        /// 图片标签
+        /// </summary>
+        /// <param name="sInput">输入内容</param>
+        public static List<string> GetImgTag(string sInput)
+        {
+            return GetList(sInput, "<img[^>]+src=\\s*(?:'(?<src>[^']+)'|\"(?<src>[^\"]+)\"|(?<src>[^>\\s]+))\\s*[^>]*>", "");
+        }
+
+        /// <summary>
+        /// 图片地址
+        /// </summary>
+        /// <param name="sInput">输入内容</param>
+        public static string GetImgSrc(string sInput)
+        {
+            return GetText(sInput, "<img[^>]+src=\\s*(?:'(?<src>[^']+)'|\"(?<src>[^\"]+)\"|(?<src>[^>\\s]+))\\s*[^>]*>", "src");
+        }
+
+        /// <summary>
+        /// 根据URL获得域名
+        /// </summary>
+        /// <param name="sInput">输入内容</param>
+        public static string GetDomain(string sInput)
+        {
+            return GetText(sInput, @"http(s)?://([\w-]+\.)+(\w){2,}", 0);
+        }
+
+        #endregion 获得特定内容
+
+        #region 根据表达式,获得文章内容
+        /// <summary>
+        /// 文章标题
+        /// </summary>
+        /// <param name="sInput">输入内容</param>
+        /// <param name="sRegex">表达式字符串</param>
+        public static string GetTitle(string sInput, string sRegex)
+        {
+            string sTitle = GetText(sInput, sRegex, "Title");
+            sTitle = ClearTag(sTitle);
+            if (sTitle.Length > 99)
+            {
+                sTitle = sTitle.Substring(0, 99);
+            }
+            return sTitle;
+        }
+
+        /// <summary>
+        /// 网页标题
+        /// </summary>
+        /// <param name="sInput">html</param>
+        public static string GetTitle(string sInput)
+        {
+            return GetText(sInput, @"<Title[^>]*>(?<Title>[\s\S]{10,})</Title>", "Title");
+        }
+
+        /// <summary>
+        /// 网页内容
+        /// </summary>
+        /// <param name="sInput">输入内容</param>
+        public static string GetHtml(string sInput)
+        {
+            return Replace(sInput, @"(?<Head>[^<]+)<", "", "Head");
+        }
+
+        /// <summary>
+        /// 网页Body内容
+        /// </summary>
+        /// <param name="sInput">html</param>
+        public static string GetBodyHelp(string sInput)
+        {
+            return GetText(sInput, @"<Body[^>]*>(?<Body>[\s\S]{10,})</body>", "Body");
+        }
+
+        /// <summary>
+        /// 网页Body内容
+        /// </summary>
+        /// <param name="sInput">输入内容</param>
+        /// <param name="sRegex">表达式字符串</param>
+        public static string GetBody(string sInput, string sRegex)
+        {
+            return GetText(sInput, sRegex, "Body");
+        }
+
+        /// <summary>
+        /// 文章来源
+        /// </summary>
+        /// <param name="sInput">输入内容</param>
+        /// <param name="sRegex">表达式字符串</param>
+        public static string GetSource(string sInput, string sRegex)
+        {
+            string sSource = GetText(sInput, sRegex, "Source");
+            sSource = ClearTag(sSource);
+            if (sSource.Length > 99)
+                sSource = sSource.Substring(0, 99);
+            return sSource;
+        }
+
+        /// <summary>
+        /// 作者名
+        /// </summary>
+        /// <param name="sInput">输入内容</param>
+        /// <param name="sRegex">表达式字符串</param>
+        public static string GetAuthor(string sInput, string sRegex)
+        {
+            string sAuthor = GetText(sInput, sRegex, "Author");
+            sAuthor = ClearTag(sAuthor);
+            if (sAuthor.Length > 99)
+                sAuthor = sAuthor.Substring(0, 99);
+            return sAuthor;
+        }
+
+        /// <summary>
+        /// 分页链接地址
+        /// </summary>
+        /// <param name="sInput">输入内容</param>
+        /// <param name="sRegex">表达式字符串</param>
+        public static List<string> GetPageLinks(string sInput, string sRegex)
+        {
+            return GetList(sInput, sRegex, "href");
+        }
+
+        /// <summary>
+        /// 根据相对路径得到绝对路径
+        /// </summary>
+        /// <param name="sInput">原始网站地址</param>
+        /// <param name="sRelativeUrl">相对链接地址</param>
+        public static string GetUrl(string sInput, string sRelativeUrl)
+        {
+            string sReturnUrl = "";
+            string sUrl = _GetStandardUrlDepth(sInput);//返回了http://www.163.com/news/这种形式
+
+            if (sRelativeUrl.ToLower().StartsWith("http") || sRelativeUrl.ToLower().StartsWith("https"))
+            {
+                sReturnUrl = sRelativeUrl.Trim();
+            }
+            else if (sRelativeUrl.StartsWith("/"))
+            {
+                sReturnUrl = GetDomain(sInput) + sRelativeUrl;
+            }
+            else if (sRelativeUrl.StartsWith("../"))
+            {
+                sUrl = sUrl.Substring(0, sUrl.Length - 1);
+                while (sRelativeUrl.IndexOf("../") >= 0)
+                {
+                    string temp = sUrl.Substring(0, sUrl.LastIndexOf("/")); // CString.GetPreStrByLast(sUrl, "/");
+                    if (temp.Length > 6)
+                    {//temp != "http:/",否则的话,说明已经回溯到尽头了,"../"与网址的层次对应不上。存在这种情况,网页上面的链接是错误的,但浏览器还能正常显示
+                        sUrl = temp;
+                    }
+                    sRelativeUrl = sRelativeUrl.Substring(3);
+                }
+                sReturnUrl = sUrl + "/" + sRelativeUrl.Trim();
+            }
+            else if (sRelativeUrl.StartsWith("./"))
+            {
+                sReturnUrl = sUrl + sRelativeUrl.Trim().Substring(2);
+            }
+            else if (sRelativeUrl.Trim() != "")
+            {//2007images/modecss.css
+                sReturnUrl = sUrl + sRelativeUrl.Trim();
+            }
+            return sReturnUrl;
+        }
+
+        /// <summary>
+        /// 获得标准的URL路径深度
+        /// </summary>
+        /// <param name="url">URL路径</param>
+        /// <returns>返回标准的形式:http://www.163.com/或http://www.163.com/news/。</returns>
+        private static string _GetStandardUrlDepth(string url)
+        {
+            string sheep = url.Trim().ToLower();
+            string header = "http://";
+            if (sheep.IndexOf("https://") != -1)
+            {
+                header = "https://";
+                sheep = sheep.Replace("https://", "");
+            }
+            else
+            {
+                sheep = sheep.Replace("http://", "");
+            }
+
+            int p = sheep.LastIndexOf("/");
+            if (p == -1)
+            {//www.163.com
+                sheep += "/";
+            }
+            else if (p == sheep.Length - 1)
+            {//传来的是:http://www.163.com/news/
+            }
+            else if (sheep.Substring(p).IndexOf(".") != -1)
+            {//传来的是:http://www.163.com/news/hello.htm 这种形式
+                sheep = sheep.Substring(0, p + 1);
+            }
+            else
+            {
+                sheep += "/";
+            }
+
+            return header + sheep;
+        }
+
+        /// <summary>
+        /// 关键字
+        /// </summary>
+        /// <param name="sInput">输入内容</param>
+        public static string GetKeyWord(string sInput)
+        {
+            List<string> list = Split(sInput, "(,|,|\\+|+|。|;|;|:|:|“)|”|、|_|\\(|(|\\)|)", 2);
+            List<string> listReturn = new List<string>();
+            Regex re;
+            foreach (string str in list)
+            {
+                re = new Regex(@"[a-zA-z]+", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
+                MatchCollection mcs = re.Matches(str);
+                string sTemp = str;
+                foreach (Match mc in mcs)
+                {
+                    if (mc.Value.Length > 2)
+                        listReturn.Add(mc.Value);
+                    sTemp = sTemp.Replace(mc.Value, ",");
+                }
+                re = new Regex(@",{1}", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
+                mcs = re.Matches(sTemp);
+                foreach (string s in re.Split(sTemp))
+                {
+                    if (s.Trim().Length <= 2)
+                        continue;
+                    listReturn.Add(s);
+                }
+            }
+            string sReturn = "";
+            for (int i = 0; i < listReturn.Count - 1; i++)
+            {
+                for (int j = i + 1; j < listReturn.Count; j++)
+                {
+                    if (listReturn[i] == listReturn[j])
+                    {
+                        listReturn[j] = "";
+                    }
+                }
+            }
+            foreach (string str in listReturn)
+            {
+                if (str.Length > 2)
+                    sReturn += str + ",";
+            }
+            if (sReturn.Length > 0)
+                sReturn = sReturn.Substring(0, sReturn.Length - 1);
+            else
+                sReturn = sInput;
+            if (sReturn.Length > 99)
+                sReturn = sReturn.Substring(0, 99);
+            return sReturn;
+        }
+
+        /// <summary>
+        /// 获取内容
+        /// </summary>
+        /// <param name="sOriContent">原始数据</param>
+        /// <param name="sOtherRemoveReg">需要移除的字符</param>
+        /// <param name="sPageUrl">URL</param>
+        /// <param name="dtAntiLink">反链 表数据</param>
+        /// <returns>转码后的内容</returns>
+        public static string GetContent(string sOriContent, string sOtherRemoveReg, string sPageUrl, DataTable dtAntiLink)
+        {
+            string sFormartted = sOriContent;
+
+            //去掉有危险的标记
+            sFormartted = Regex.Replace(sFormartted, @"<script[\s\S]*?</script>", "", RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase);
+            sFormartted = Regex.Replace(sFormartted, @"<iframe[^>]*>[\s\S]*?</iframe>", "", RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase);
+            Regex r = new Regex(@"<input[\s\S]+?>|<form[\s\S]+?>|</form[\s\S]*?>|<select[\s\S]+?>?</select>|<textarea[\s\S]*?>?</textarea>|<file[\s\S]*?>|<noscript>|</noscript>", RegexOptions.IgnoreCase);
+            sFormartted = r.Replace(sFormartted, "");
+            string[] sOtherReg = sOtherRemoveReg.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
+            foreach (string sRemoveReg in sOtherReg)
+            {
+                sFormartted = Replace(sFormartted, sRemoveReg, "", 0);
+            }
+
+            //图片路径
+            sFormartted = _ReplaceUrl("<img[\\s\\S]+?src\\s*=\\s*(?:'(?<src>[^']+)'|\"(?<src>[^\"]+)\"|(?<src>[^>\\s]+))\\s*[^>]*>", "src", sFormartted, sPageUrl);
+            //反防盗链
+            string domain = GetDomain(sPageUrl);
+            DataRow[] drs = dtAntiLink.Select("Domain='" + domain + "'");
+            if (drs.Length > 0)
+            {
+                foreach (DataRow dr in drs)
+                {
+                    switch (Convert.ToInt32(dr["Type"]))
+                    {
+                        case 1://置换
+                            sFormartted = sFormartted.Replace(dr["imgUrl"].ToString(), "http://stat.580k.com/t.asp?url=");
+                            break;
+                        default://附加
+                            sFormartted = sFormartted.Replace(dr["imgUrl"].ToString(), "http://stat.580k.com/t.asp?url=" + dr["imgUrl"].ToString());
+                            break;
+                    }
+                }
+            }
+
+            //A链接
+            sFormartted = _ReplaceUrl(@"<a[^>]+href\s*=\s*(?:'(?<href>[^']+)'|""(?<href>[^""]+)""|(?<href>[^>\s]+))\s*[^>]*>", "href", sFormartted, sPageUrl);
+
+            //CSS
+            sFormartted = _ReplaceUrl(@"<link[^>]+href\s*=\s*(?:'(?<href>[^']+)'|""(?<href>[^""]+)""|(?<href>[^>\s]+))\s*[^>]*>", "href", sFormartted, sPageUrl);
+
+            //BACKGROUND
+            sFormartted = _ReplaceUrl(@"background\s*=\s*(?:'(?<img>[^']+)'|""(?<img>[^""]+)""|(?<img>[^>\s]+))", "img", sFormartted, sPageUrl);
+            //style方式的背景:background-image:url(...)
+            sFormartted = _ReplaceUrl(@"background-image\s*:\s*url\s*\x28(?<img>[^\x29]+)\x29", "img", sFormartted, sPageUrl);
+
+            //FLASH
+            sFormartted = _ReplaceUrl(@"<param\s[^>]+""movie""[^>]+value\s*=\s*""(?<flash>[^"">]+\x2eswf)""[^>]*>", "flash", sFormartted, sPageUrl);
+
+            //XSL
+            if (IsXml(sFormartted))
+            {
+                sFormartted = _ReplaceUrl(@"<\x3fxml-stylesheet\s+[^\x3f>]+href=\s*(?:'(?<href>[^']+)'|""(?<href>[^""]+)"")\s*[^\x3f>]*\x3f>", "href", sFormartted, sPageUrl);
+            }
+
+            //script
+            //sFormartted = _ReplaceUrl(@"<script[^>]+src\s*=\s*(?:'(?<src>[^']+)'|""(?<src>[^""]+)""|(?<src>[^>\s]+))\s*[^>]*>", "src", sFormartted,sPageUrl);
+
+            return sFormartted;
+        }
+
+        private static string _ReplaceUrl(string strRe, string subMatch, string sFormartted, string sPageUrl)
+        {
+            Regex re = new Regex(strRe, RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase);
+            MatchCollection mcs = re.Matches(sFormartted);
+            string sOriStr = "";
+            string sSubMatch = "";
+            string sReplaceStr = "";
+            foreach (Match mc in mcs)
+            {
+                sOriStr = mc.Value;
+                sSubMatch = mc.Groups[subMatch].Value;
+                sReplaceStr = sOriStr.Replace(sSubMatch, GetUrl(sPageUrl, sSubMatch));
+                sFormartted = sFormartted.Replace(sOriStr, sReplaceStr);
+            }
+
+            return sFormartted;
+        }
+
+        /// <summary>
+        /// 判断是否是xml格式
+        /// </summary>
+        /// <param name="sFormartted">输入内容</param>
+        /// <returns>是否是xml数据</returns>
+        public static bool IsXml(string sFormartted)
+        {
+            Regex re = new Regex(@"<\x3fxml\s+", RegexOptions.IgnoreCase);
+            MatchCollection mcs = re.Matches(sFormartted);
+            return mcs.Count > 0;
+        }
+
+        #endregion 根据表达式,获得文章内容
+
+        #region HTML相关操作
+        /// <summary>
+        /// 清除html标签
+        /// </summary>
+        /// <param name="sHtml">html代码</param>
+        /// <returns>清理后的内容</returns>
+        public static string ClearTag(string sHtml)
+        {
+            if (sHtml?.Length == 0)
+                return "";
+            string sTemp = sHtml;
+            Regex re = new Regex(@"(<[^>\s]*\b(\w)+\b[^>]*>)|(<>)|(&nbsp;)|(&gt;)|(&lt;)|(&amp;)|\r|\n|\t", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
+            return re.Replace(sHtml, "");
+        }
+        /// <summary>
+        /// 根据正则清除html标签
+        /// </summary>
+        /// <param name="sHtml">html代码</param>
+        /// <param name="sRegex">正则表达式</param>
+        /// <returns>清理后的内容</returns>
+        public static string ClearTag(string sHtml, string sRegex)
+        {
+            string sTemp = sHtml;
+            Regex re = new Regex(sRegex, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
+            return re.Replace(sHtml, "");
+        }
+        /// <summary>
+        /// 将html转换成js代码
+        /// </summary>
+        /// <param name="sHtml">html代码</param>
+        /// <returns>js代码</returns>
+        public static string ConvertToJavascript(string sHtml)
+        {
+            StringBuilder sText = new StringBuilder();
+            var re = new Regex(@"\r\n", RegexOptions.IgnoreCase);
+            string[] strArray = re.Split(sHtml);
+            foreach (string strLine in strArray)
+            {
+                sText.Append("document.writeln(\"" + strLine.Replace("\"", "\\\"") + "\");\r\n");
+            }
+            return sText.ToString();
+        }
+
+        /// <summary>
+        /// 删除字符串中的特定标记 
+        /// </summary>
+        /// <param name="str">html代码</param>
+        /// <param name="tag">指定的标记</param>
+        /// <param name="isContent">是否清除内容 </param>
+        /// <returns>清理后的代码</returns>
+        public static string DelTag(string str, string tag, bool isContent)
+        {
+            if (tag == null || tag == " ")
+            {
+                return str;
+            }
+
+            if (isContent) //要求清除内容 
+            {
+                return Regex.Replace(str, string.Format("<({0})[^>]*>([\\s\\S]*?)<\\/\\1>", tag), "", RegexOptions.IgnoreCase);
+            }
+
+            return Regex.Replace(str, string.Format(@"(<{0}[^>]*(>)?)|(</{0}[^>] *>)|", tag), "", RegexOptions.IgnoreCase);
+        }
+
+        /// <summary>
+        /// 删除字符串中的一组标记 
+        /// </summary>
+        /// <param name="str">html代码</param>
+        /// <param name="tagA">标记</param>
+        /// <param name="isContent">是否清除内容 </param>
+        /// <returns>清理后的代码</returns>
+        public static string DelTagArray(string str, string tagA, bool isContent)
+        {
+            string[] tagAa = tagA.Split(',');
+            foreach (string sr1 in tagAa) //遍历所有标记,删除 
+            {
+                str = DelTag(str, sr1, isContent);
+            }
+            return str;
+        }
+
+        #endregion HTML相关操作
+
+        #region 根据内容获得链接
+        /// <summary>
+        /// 根据内容获得链接
+        /// </summary>
+        /// <param name="sContent">html代码</param>
+        /// <returns>链接</returns>
+        public static string GetLink(string sContent)
+        {
+            string strReturn = "";
+            Regex re = new Regex(@"<a\s+[^>]*href\s*=\s*(?:'(?<href>[^']+)'|""(?<href>[^""]+)""|(?<href>[^>\s]+))\s*[^>]*>", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
+            Regex js = new Regex(@"(href|onclick)=[^>]+javascript[^>]+(('(?<href>[\w\d/-]+\.[^']*)')|(&quot;(?<href>[\w\d/-]+\.[^;]*)&quot;))[^>]*>", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
+            Match mc = js.Match(sContent);//获取javascript中的链接,有待改进
+            if (mc.Success)
+            {
+                strReturn = mc.Groups["href"].Value;
+            }
+            else
+            {
+                Match me = re.Match(sContent);
+                if (me.Success)
+                {
+                    strReturn = System.Web.HttpUtility.HtmlDecode(me.Groups["href"].Value);
+                    //strReturn = RemoveByReg(strReturn, @";.*|javascript:.*");
+                    strReturn = RemoveByReg(strReturn, @";[^?&]*|javascript:.*");
+                }
+            }
+
+            return strReturn;
+        }
+        /// <summary>
+        /// 根据链接得到文本
+        /// </summary>
+        /// <param name="sContent">链接</param>
+        /// <returns>文本</returns>
+        public static string GetTextByLink(string sContent)
+        {
+            Regex re = new Regex(@"<a(?:\s+[^>]*)?>([\s\S]*)?</a>", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
+            Regex email = new Regex(@"(href|onclick)=[^>]+mailto[^>]+@[^>]+>", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
+            Match me = email.Match(sContent);
+            if (me.Success)
+                return "";
+
+            Match mc = re.Match(sContent);
+            if (mc.Success)
+                return mc.Groups[1].Value;
+            else
+                return "";
+        }
+
+        private static void _GetLinks(string sContent, string sUrl, ref Dictionary<string, string> lisA)
+        {
+            const string sFilter =
+@"首页|下载|中文|English|反馈|讨论区|投诉|建议|联系|关于|about|诚邀|工作|简介|新闻|掠影|风采
+|登录|注销|注册|使用|体验|立即|收藏夹|收藏|添加|加入
+|更多|more|专题|精选|热卖|热销|推荐|精彩
+|加盟|联盟|友情|链接|相关
+|订阅|阅读器|RSS
+|免责|条款|声明|我的|我们|组织|概况|有限|免费|公司|法律|导航|广告|地图|隐私
+|〖|〗|【|】|(|)|[|]|『|』|\.";
+
+            Regex re = new Regex(@"<a\s+[^>]*href\s*=\s*[^>]+>[\s\S]*?</a>", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
+            Regex re2 = new Regex(@"""|'", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
+            MatchCollection mcs = re.Matches(sContent);
+            //foreach (Match mc in mcs)
+            for (int i = mcs.Count - 1; i >= 0; i--)
+            {
+                Match mc = mcs[i];
+                string strHref = GetLink(mc.Value).Trim();
+
+                strHref = strHref.Replace("\\\"", "");//针对JS输出链接
+                strHref = strHref.Replace("\\\'", "");
+
+                string strTemp = RemoveByReg(strHref, @"^http.*/$");//屏蔽以“http”开头“/”结尾的链接地址
+                if (strTemp.Length < 2)
+                {
+                    continue;
+                }
+
+                //过滤广告或无意义的链接
+                string strText = ClearTag(GetTextByLink(mc.Value)).Trim();
+                strTemp = RemoveByReg(strText, sFilter);
+                if (Encoding.Default.GetBytes(strTemp).Length < 9)
+                {
+                    continue;
+                }
+                if (re2.IsMatch(strText))
+                {
+                    continue;
+                }
+
+                //换上绝对地址
+                strHref = GetUrlByRelative(sUrl, strHref);
+                if (strHref.Length <= 18)//例如,http://www.163.com = 18
+                {
+                    continue;
+                }
+
+                //计算#字符出现的位置,移除它后面的内容
+                //如果是域名地址,就跳过
+                int charIndex = strHref.IndexOf('#');
+                if (charIndex > -1)
+                {
+                    strHref = strHref.Substring(0, charIndex);
+                }
+                strHref = strHref.Trim(new char[] { '/', '\\' });
+                string tmpDomainURL = GetDomain(strHref);
+                if (strHref.Equals(tmpDomainURL, StringComparison.OrdinalIgnoreCase))
+                {
+                    continue;
+                }
+
+                if (!lisA.ContainsKey(strHref) && !lisA.ContainsValue(strText))
+                {
+                    lisA.Add(strHref, strText);
+                }
+            }
+        }
+
+        /// <summary>
+        /// 判断是否是js链接
+        /// </summary>
+        /// <param name="sHtml">html</param>
+        /// <returns>判断是否是js链接</returns>
+        public static bool IsExistsScriptLink(string sHtml)
+        {
+            Regex re = new Regex(@"<script[^>]+src\s*=\s*(?:'(?<src>[^']+)'|""(?<src>[^""]+)""|(?<src>[^>\s]+))\s*[^>]*>", RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase);
+            return re.IsMatch(sHtml);
+        }
+
+        /// <summary>
+        /// 从RSS FEED中读取
+        /// </summary>
+        /// <param name="sContent">RSS内容</param>
+        /// <param name="sUrl">URL</param>
+        /// <returns>读取到的内容</returns>
+        public static Dictionary<string, string> GetLinksFromRss(string sContent, string sUrl)
+        {
+            Dictionary<string, string> lisDes = new Dictionary<string, string>();
+            return GetLinksFromRss(sContent, sUrl, ref lisDes);
+        }
+
+        /// <summary>
+        /// 从RSS FEED中读取
+        /// </summary>
+        /// <param name="sContent">RSS内容</param>
+        /// <param name="sUrl">URL</param>
+        /// <param name="lisDes">过滤条件</param>
+        /// <returns>读取到的内容</returns>
+        public static Dictionary<string, string> GetLinksFromRss(string sContent, string sUrl, ref Dictionary<string, string> lisDes)
+        {
+            Dictionary<string, string> listResult = new Dictionary<string, string>();
+
+            XmlDocument xml = new XmlDocument();
+
+            //RSS2.0
+            try
+            {
+                xml.LoadXml(sContent.Trim());
+                XmlNodeList nodes = xml.SelectNodes("/rss/channel/item");
+                if (nodes.Count > 0)
+                {
+                    for (int i = nodes.Count - 1; i >= 0; i--)
+                    {
+                        try
+                        {
+                            string sLink = GetUrlByRelative(sUrl, nodes[i].SelectSingleNode("link").InnerText);
+                            listResult.Add(sLink, nodes[i].SelectSingleNode("title").InnerText);
+                            lisDes.Add(sLink, nodes[i].SelectSingleNode("description").InnerText);
+                        }
+                        catch (Exception e)
+                        {
+                            LogManager.Error(e);
+                        }
+                    }
+                    return listResult;
+                }
+            }
+            catch (Exception e)
+            {
+                LogManager.Error(e);
+            }
+
+            //RSS1.0(RDF)
+            try
+            {
+                XmlNamespaceManager nsMgr = new XmlNamespaceManager(xml.NameTable);
+                nsMgr.AddNamespace("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
+                nsMgr.AddNamespace("rss", "http://purl.org/rss/1.0/");
+                XmlNodeList nodes = xml.SelectNodes("/rdf:RDF//rss:item", nsMgr);
+                if (nodes.Count > 0)
+                {
+                    for (int i = nodes.Count - 1; i >= 0; i--)
+                    {
+                        try
+                        {
+                            string sLink = GetUrlByRelative(sUrl, nodes[i].SelectSingleNode("rss:link", nsMgr).InnerText);
+                            listResult.Add(sLink, nodes[i].SelectSingleNode("rss:title", nsMgr).InnerText);
+                            lisDes.Add(sLink, nodes[i].SelectSingleNode("rss:description", nsMgr).InnerText);
+                        }
+                        catch (Exception e)
+                        {
+                            LogManager.Error(e);
+                        }
+                        //listResult.Add("<a href=\"" + nodes[i].SelectSingleNode("rss:link",nsMgr).InnerText + "\">" + nodes[i].SelectSingleNode("rss:title",nsMgr).InnerText + "</a>");
+                    }
+                    return listResult;
+                }
+            }
+            catch (Exception e)
+            {
+                LogManager.Error(e);
+            }
+
+            //RSS ATOM
+            try
+            {
+                XmlNamespaceManager nsMgr = new XmlNamespaceManager(xml.NameTable);
+                nsMgr.AddNamespace("atom", "http://purl.org/atom/ns#");
+                XmlNodeList nodes = xml.SelectNodes("/atom:feed/atom:entry", nsMgr);
+                if (nodes.Count > 0)
+                {
+                    for (int i = nodes.Count - 1; i >= 0; i--)
+                    {
+                        try
+                        {
+                            string sLink = GetUrlByRelative(sUrl, nodes[i].SelectSingleNode("atom:link", nsMgr).Attributes["href"].InnerText);
+                            listResult.Add(sLink, nodes[i].SelectSingleNode("atom:title", nsMgr).InnerText);
+                            lisDes.Add(sLink, nodes[i].SelectSingleNode("atom:content", nsMgr).InnerText);
+                        }
+                        catch (Exception e)
+                        {
+                            LogManager.Error(e);
+                        }
+                        //listResult.Add("<a href=\"" + nodes[i].SelectSingleNode("atom:link",nsMgr).Attributes["href"].InnerText + "\">" + nodes[i].SelectSingleNode("atom:title",nsMgr).InnerText + "</a>");
+                    }
+                    return listResult;
+                }
+            }
+            catch (Exception e)
+            {
+                LogManager.Error(e);
+            }
+
+            return listResult;
+        }
+        /// <summary>
+        ///  从RSS FEED中读取标题
+        /// </summary>
+        /// <param name="sContent">RSS</param>
+        /// <returns>标题</returns>
+        public static string GetTitleFromRss(string sContent)
+        {
+            string title = "";
+            XmlDocument xml = new XmlDocument();
+
+            //RSS2.0
+            try
+            {
+                xml.LoadXml(sContent.Trim());
+                title = xml.SelectSingleNode("/rss/channel/title").InnerText;
+            }
+            catch (Exception e)
+            {
+                LogManager.Error(e);
+            }
+
+            return title;
+        }
+
+        /// <summary>
+        /// 根据标签进行移除
+        /// </summary>
+        /// <param name="sContent">html</param>
+        /// <param name="sRegex">正则表达式</param>
+        /// <returns>清理后的代码</returns>
+        public static string RemoveByReg(string sContent, string sRegex)
+        {
+            Regex re = new Regex(sRegex, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
+            MatchCollection mcs = re.Matches(sContent);
+            foreach (Match mc in mcs)
+            {
+                sContent = sContent.Replace(mc.Value, "");
+            }
+            return sContent;
+        }
+
+        /// <summary>
+        /// 根据正则表达式替换内容
+        /// </summary>
+        /// <param name="sContent">html</param>
+        /// <param name="sReplace">需要替换的内容</param>
+        /// <param name="sRegex">符合正则的内容</param>
+        /// <returns>替换后内容</returns>
+        public static string ReplaceByReg(string sContent, string sReplace, string sRegex)
+        {
+            Regex re = new Regex(sRegex, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
+            sContent = re.Replace(sContent, sReplace);
+            return sContent;
+        }
+
+        /// <summary>
+        ///  网页Body内容
+        /// </summary>
+        /// <param name="sContent">html源代码</param>
+        /// <returns>网页Body内容</returns>
+        public static string GetBody(string sContent)
+        {
+            Regex re = new Regex(@"[\s\S]*?<\bbody\b[^>]*>", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
+            sContent = re.Replace(sContent, "");
+
+            re = new Regex(@"</\bbody\b[^>]*>\s*</html>", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.RightToLeft);
+            sContent = re.Replace(sContent, "");
+            return sContent;
+        }
+        #endregion 根据超链接地址获取页面内容
+
+        #region 根据内容作字符串分析
+        /// <summary>
+        /// 根据标签获取文本
+        /// </summary>
+        /// <param name="sContent">html</param>
+        /// <param name="sRegex">正则表达式</param>
+        /// <returns>文本</returns>
+        public static string GetTextByReg(string sContent, string sRegex)
+        {
+            Regex re = new Regex(sRegex, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
+            Match mc = re.Match(sContent);
+            string str = "";
+            if (mc.Success)
+                str = mc.Groups[0].Value;
+            while (str.EndsWith("_"))
+            {
+                str = RemoveEndWith(str, "_");
+            }
+            return str;
+        }
+
+        // charset=[\s]*(?<Coding>[^'"]+)[\s]*['"]?[\s]*[/]?>
+        /// <summary>
+        /// 根据标签获取文本
+        /// </summary>
+        /// <param name="sContent">html</param>
+        /// <param name="sRegex">正则表达式</param>
+        /// <param name="sGroupName">分组名</param>
+        /// <returns>文本</returns>
+        public static string GetTextByReg(string sContent, string sRegex, string sGroupName)
+        {
+            Regex re = new Regex(sRegex, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
+            Match mc = re.Match(sContent);
+            string str = "";
+            if (mc.Success)
+                str = mc.Groups[sGroupName].Value;
+            return str;
+        }
+
+        /// <summary>
+        /// 获得链接的绝对路径
+        /// </summary>
+        /// <param name="sUrl">原链接地址</param>
+        /// <param name="sRUrl">相对地址</param>
+        /// <returns>获得链接的绝对路径</returns>
+        public static string GetUrlByRelative(string sUrl, string sRUrl)
+        {
+            try
+            {
+                //http://q.yesky.com/grp/dsc/view.do;jsessionid=A6324FD46B4893303124F70C0B2AAC1E?grpId=201595&rvId=8215876
+                Uri baseUri = new Uri(sUrl);
+                if (!sUrl.EndsWith("/"))
+                {
+                    int i = baseUri.Segments.Length - 1;
+                    if (i > 0)
+                    {
+                        string file = baseUri.Segments[i];
+                        if (file.IndexOf('.') < 1)
+                        {
+                            baseUri = new Uri(sUrl + "/");
+                        }
+                    }
+                }
+                Uri myUri = new Uri(baseUri, sRUrl);
+                return myUri.AbsoluteUri;
+            }
+            catch
+            {
+                return sUrl;
+            }
+        }
+
+        /// <summary>
+        /// 根据标签获取数据集合
+        /// </summary>
+        /// <param name="sContent">html</param>
+        /// <param name="sRegex">正则表达式</param>
+        /// <returns>数据集合</returns>
+        public static List<string> GetListByReg(string sContent, string sRegex)
+        {
+            List<string> list = new List<string>();
+            Regex re = new Regex(sRegex, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
+            MatchCollection mcs = re.Matches(sContent);
+            foreach (Match mc in mcs)
+            {
+                list.Add(mc.Groups["href"].Value);
+            }
+            return list;
+        }
+
+        /// <summary>
+        /// 获得主域
+        /// </summary>
+        /// <param name="sUrl">URL</param>
+        /// <returns>域名</returns>
+        public static string GetDomainUrl(string sUrl)
+        {
+            try
+            {
+                Uri baseUri = new Uri(sUrl);
+
+                return baseUri.Scheme + "://" + baseUri.Authority;
+            }
+            catch
+            {
+                return sUrl;
+            }
+        }
+
+        #endregion
+
+        #region 杂项
+
+        /// <summary>
+        /// 从html中过滤出文本
+        /// </summary>
+        /// <param name="sHtml">html</param>
+        /// <returns>纯文本</returns>
+        public static string GetTxtFromHtml(this string sHtml)
+        {
+            string del = @"<head[^>]*>[\s\S]*?</head>";
+            string content = RemoveByReg(sHtml, del);
+
+            del = @"(<script[^>]*>[\s\S]*?</script>)|(<IFRAME[^>]*>[\s\S]*?</IFRAME>)|(<style[^>]*>[\s\S]*?</style>|<title[^>]*>[\s\S]*?</title>|<meta[^>]*>|<option[^>]*>[\s\S]*?</option>)";
+            content = RemoveByReg(content, del);
+
+            del = @"(&nbsp;)|([\n\t]+)";
+            content = RemoveByReg(content, del);
+
+            string re = @"(<table(\s+[^>]*)*>)|(<td(\s+[^>]*)*>)|(<tr(\s+[^>]*)*>)|(<p(\s+[^>]*)*>)|(<div(\s+[^>]*)*>)|(<ul(\s+[^>]*)*>)|(<li(\s+[^>]*)*>)|</table>|</td>|</tr>|</p>|<br>|</div>|</li>|</ul>|<p />|<br />";
+            content = ReplaceByReg(content, "", re);
+            content = ReplaceByReg(content, "", @"[\f\n\r\v]+");
+
+            content = RemoveByReg(content, @"<a(\s+[^>]*)*>[\s\S]*?</a>");
+            content = RemoveByReg(content, "<[^>]+>");//去除各种HTML标记,获得纯内容
+
+            content = content.Replace("\n", "");
+            content = content.Replace("\r", "");
+            content = content.Trim();
+            return content;
+        }
+
+        /// <summary>
+        /// 从html中过滤出文本,不过保留换行符号
+        /// </summary>
+        /// <param name="sHtml">html源代码</param>
+        /// <returns>从html中过滤出文本,不过保留换行符号</returns>
+        public static string GetTxtFromHtml2(this string sHtml)
+        {
+            string del = @"<head[^>]*>[\s\S]*?</head>";
+            string content = RemoveByReg(sHtml, del);
+
+            del = @"(<script[^>]*>[\s\S]*?</script>)|(<IFRAME[^>]*>[\s\S]*?</IFRAME>)|(<style[^>]*>[\s\S]*?</style>|<title[^>]*>[\s\S]*?</title>|<meta[^>]*>|<option[^>]*>[\s\S]*?</option>)";
+            content = RemoveByReg(content, del);
+
+            del = @"(&nbsp;)|([\t]+)";//del = @"(&nbsp;)|([\n\t]+)";
+            content = RemoveByReg(content, del);
+
+            string re = @"(<table(\s+[^>]*)*>)|(<td(\s+[^>]*)*>)|(<tr(\s+[^>]*)*>)|(<p(\s+[^>]*)*>)|(<div(\s+[^>]*)*>)|(<ul(\s+[^>]*)*>)|(<li(\s+[^>]*)*>)|</table>|</td>|</tr>|</p>|<br>|</div>|</li>|</ul>|<p />|<br />";
+            content = ReplaceByReg(content, "", re);
+            //content = CText.ReplaceByReg(content, "", @"[\f\n\r\v]+");
+
+            content = RemoveByReg(content, @"<a(\s+[^>]*)*>[\s\S]*?</a>");
+            content = RemoveByReg(content, "<[^>]+>");//去除各种HTML标记,获得纯内容
+            content = content.Trim();
+
+            return content;
+        }
+        #endregion
+
+        /// <summary>
+        /// 按结尾移除内容
+        /// </summary>
+        /// <param name="sOrg">原始数据</param>
+        /// <param name="sEnd">结束的字符串</param>
+        /// <returns>清理后的内容</returns>
+        public static string RemoveEndWith(string sOrg, string sEnd)
+        {
+            if (sOrg.EndsWith(sEnd))
+                sOrg = sOrg.Remove(sOrg.IndexOf(sEnd), sEnd.Length);
+            return sOrg;
+        }
+
+        #region 根据超链接地址获取页面内容
+        /// <summary>
+        /// 根据超链接地址获取页面内容
+        /// </summary>
+        /// <param name="sUrl">URL</param>
+        /// <returns>页面内容</returns>
+        public static string GetHtmlByUrl(string sUrl)
+        {
+            return GetHtmlByUrl(sUrl, "auto");
+        }
+
+        /// <summary>
+        /// 根据超链接地址获取页面内容
+        /// </summary>
+        /// <param name="sUrl">URL</param>
+        /// <param name="sCoding">文件编码</param>
+        /// <returns>页面内容</returns>
+        public static string GetHtmlByUrl(string sUrl, string sCoding)
+        {
+            return GetHtmlByUrl(ref sUrl, sCoding);
+        }
+
+        /// <summary>
+        /// 根据超链接地址获取页面内容,并将url作为引用类型
+        /// </summary>
+        /// <param name="sUrl">URL</param>
+        /// <param name="sCoding">文件编码</param>
+        /// <returns>页面内容</returns>
+        public static string GetHtmlByUrl(ref string sUrl, string sCoding)
+        {
+            string content = "";
+
+            try
+            {
+                HttpWebResponse response = _MyGetResponse(sUrl);
+                if (response == null)
+                {
+                    return content;
+                }
+
+                sUrl = response.ResponseUri.AbsoluteUri;
+
+                Stream stream = response.GetResponseStream();
+                byte[] buffer = GetContent(stream);
+                stream.Close();
+                stream.Dispose();
+
+                string charset = "";
+                if (string.IsNullOrEmpty(sCoding) || string.Equals(sCoding, "auto", StringComparison.CurrentCultureIgnoreCase))
+                {//如果不指定编码,那么系统代为指定
+                    //首先,从返回头信息中寻找
+                    string ht = response.GetResponseHeader("Content-Type");
+                    response.Close();
+                    string regCharSet = "[\\s\\S]*charset=(?<charset>[\\S]*)";
+                    Regex r = new Regex(regCharSet, RegexOptions.IgnoreCase);
+                    Match m = r.Match(ht);
+                    charset = (m.Captures.Count != 0) ? m.Result("${charset}") : "";
+                    if (charset == "-8") charset = "utf-8";
+                    if (charset?.Length == 0)
+                    {//找不到,则在文件信息本身中查找
+                        //先按gb2312来获取文件信息
+                        content = System.Text.Encoding.GetEncoding("gb2312").GetString(buffer);
+
+                        regCharSet = "(<meta[^>]*charset=(?<charset>[^>'\"]*)[\\s\\S]*?>)|(xml[^>]+encoding=(\"|')*(?<charset>[^>'\"]*)[\\s\\S]*?>)";
+                        r = new Regex(regCharSet, RegexOptions.IgnoreCase);
+                        m = r.Match(content);
+                        if (m.Captures.Count == 0)
+                        {//没办法,都找不到编码,只能返回按"gb2312"获取的信息
+                            //content = CText.RemoveByReg(content, @"<!--[\s\S]*?-->");
+                            return content;
+                        }
+                        charset = m.Result("${charset}");
+                    }
+                }
+                else
+                {
+                    response.Close();
+                    charset = sCoding.ToLower();
+                }
+
+                try
+                {
+                    content = System.Text.Encoding.GetEncoding(charset).GetString(buffer);
+                }
+                catch (ArgumentException)
+                {//指定的编码不可识别
+                    content = System.Text.Encoding.GetEncoding("gb2312").GetString(buffer);
+                }
+
+                //content = CText.RemoveByReg(content, @"<!--[\s\S]*?-->");
+            }
+            catch
+            {
+                content = "";
+            }
+
+            return content;
+        }
+
+        private static HttpWebResponse _MyGetResponse(string sUrl)
+        {
+            int iTimeOut = 10000;
+            //try
+            //{
+            //    //iTimeOut = int.Parse(System.Configuration.ConfigurationManager.AppSettings["SocketTimeOut"]);
+            //}
+            //catch { iTimeOut = 10000; }
+
+            bool bCookie = false;
+            bool bRepeat = false;
+            Uri target = new Uri(sUrl);
+
+ReCatch:
+            try
+            {
+                HttpWebRequest resquest = (HttpWebRequest)WebRequest.Create(target);
+                resquest.MaximumResponseHeadersLength = -1;
+                resquest.ReadWriteTimeout = 120000;//120秒就超时
+                resquest.Timeout = iTimeOut;
+                resquest.MaximumAutomaticRedirections = 50;
+                resquest.MaximumResponseHeadersLength = 5;
+                resquest.AllowAutoRedirect = true;
+                if (bCookie)
+                {
+                    resquest.CookieContainer = new CookieContainer();
+                }
+                resquest.UserAgent = "Mozilla/6.0 (compatible; MSIE 6.0; Windows NT 5.1)";
+                //resquest.UserAgent = @"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.1) Web-Sniffer/1.0.24";
+                //resquest.KeepAlive = true;
+                return (HttpWebResponse)resquest.GetResponse();
+            }
+            catch (WebException)
+            {
+                if (!bRepeat)
+                {
+                    bRepeat = true;
+                    bCookie = true;
+                    goto ReCatch;
+                }
+                return null;
+            }
+            catch
+            {
+                return null;
+            }
+        }
+
+        private static byte[] GetContent(Stream stream)
+        {
+            ArrayList arBuffer = new ArrayList();
+            const int BUFFSIZE = 4096;
+
+            try
+            {
+                byte[] buffer = new byte[BUFFSIZE];
+                int count = stream.Read(buffer, 0, BUFFSIZE);
+                while (count > 0)
+                {
+                    for (int i = 0; i < count; i++)
+                    {
+                        arBuffer.Add(buffer[i]);
+                    }
+                    count = stream.Read(buffer, 0, BUFFSIZE);
+                }
+            }
+            catch (Exception e)
+            {
+                LogManager.Error(e);
+            }
+
+            return (byte[])arBuffer.ToArray(System.Type.GetType("System.Byte"));
+        }
+
+        /// <summary>
+        /// 获取http报文头
+        /// </summary>
+        /// <param name="sUrl">URL</param>
+        /// <returns>报文信息</returns>
+        public static string GetHttpHead(string sUrl)
+        {
+            string sHead = "";
+            Uri uri = new Uri(sUrl);
+            try
+            {
+                WebRequest req = WebRequest.Create(uri);
+                WebResponse resp = req.GetResponse();
+                WebHeaderCollection headers = resp.Headers;
+                string[] sKeys = headers.AllKeys;
+                foreach (string sKey in sKeys)
+                {
+                    sHead += sKey + ":" + headers[sKey] + "\r\n";
+                }
+            }
+            catch (Exception e)
+            {
+                LogManager.Error(e);
+            }
+            return sHead;
+        }
+
+        /// <summary>
+        /// 处理框架页面问题。如果该页面是框架结构的话,返回该框架
+        /// </summary>
+        /// <param name="url">URL</param>
+        /// <param name="content">内容</param>
+        /// <returns>框架结构</returns>
+        public static string[] DealWithFrame(string url, string content)
+        {
+            string regFrame = @"<frame\s+[^>]*src\s*=\s*(?:""(?<src>[^""]+)""|'(?<src>[^']+)'|(?<src>[^\s>""']+))[^>]*>";
+            return DealWithFrame(regFrame, url, content);
+        }
+
+        /// <summary>
+        /// 处理浮动桢问题。如果该页面存在浮动桢,返回浮动桢
+        /// </summary>
+        /// <param name="url">URL</param>
+        /// <param name="content">内容</param>
+        /// <returns>浮动桢</returns>
+        public static string[] DealWithIFrame(string url, string content)
+        {
+            string regiFrame = @"<iframe\s+[^>]*src\s*=\s*(?:""(?<src>[^""]+)""|'(?<src>[^']+)'|(?<src>[^\s>""']+))[^>]*>";
+            return DealWithFrame(regiFrame, url, content);
+        }
+
+        private static string[] DealWithFrame(string strReg, string url, string content)
+        {
+            ArrayList alFrame = new ArrayList();
+            Regex r = new Regex(strReg, RegexOptions.IgnoreCase);
+            Match m = r.Match(content);
+            while (m.Success)
+            {
+                alFrame.Add(GetUrl(url, m.Groups["src"].Value));
+                m = m.NextMatch();
+            }
+
+            return (string[])alFrame.ToArray(System.Type.GetType("System.String"));
+        }
+
+        #endregion 根据超链接地址获取页面内容
+
+        #region 获得多个页面
+        /// <summary>
+        /// 获得多个页面
+        /// </summary>
+        /// <param name="listUrl">URL集合</param>
+        /// <param name="sCoding">文件编码</param>
+        /// <returns>页面集合</returns>
+        /// <exception cref="Exception"> </exception>
+        public static List<KeyValuePair<int, string>> GetHtmlByUrlList(List<KeyValuePair<int, string>> listUrl, string sCoding)
+        {
+            int iTimeOut = int.Parse(System.Configuration.ConfigurationManager.AppSettings["SocketTimeOut"]);
+            StringBuilder sbHtml = new StringBuilder();
+            List<KeyValuePair<int, string>> listResult = new List<KeyValuePair<int, string>>();
+            int nBytes = 0;
+            Socket sock = null;
+            IPHostEntry ipHostInfo = null;
+            try
+            {
+                // 初始化				
+                Uri site = new Uri(listUrl[0].Value);
+                ipHostInfo = System.Net.Dns.GetHostEntry(site.Host);
+                IPAddress ipAddress = ipHostInfo.AddressList[0];
+                IPEndPoint remoteEP = new IPEndPoint(ipAddress, site.Port);
+                sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+                sock.SendTimeout = iTimeOut;
+                sock.ReceiveTimeout = iTimeOut;
+                sock.Connect(remoteEP);
+                foreach (KeyValuePair<int, string> kvUrl in listUrl)
+                {
+                    site = new Uri(kvUrl.Value);
+                    string sendMsg = "GET " + HttpUtility.UrlDecode(site.PathAndQuery) + " HTTP/1.1\r\n" +
+                        "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/msword, application/vnd.ms-powerpoint, */*\r\n" +
+                        "Accept-Language:en-us\r\n" +
+                        "Accept-Encoding:gb2312, deflate\r\n" +
+                        "User-Agent: Mozilla/4.0\r\n" +
+                        "Host: " + site.Host + "\r\n\r\n" + '\0';
+                    // 发送
+                    byte[] msg = Encoding.GetEncoding(sCoding).GetBytes(sendMsg);
+                    if ((nBytes = sock.Send(msg)) == 0)
+                    {
+                        sock.Shutdown(SocketShutdown.Both);
+                        sock.Close();
+                        return listResult;
+                    }
+                    // 接受
+                    byte[] bytes = new byte[2048];
+                    byte bt = Convert.ToByte('\x7f');
+                    do
+                    {
+                        int count = 0;
+                        try
+                        {
+                            nBytes = sock.Receive(bytes, bytes.Length - 1, 0);
+                        }
+                        catch (Exception Ex)
+                        {
+                            string str = Ex.Message;
+                            nBytes = -1;
+                        }
+                        if (nBytes <= 0) break;
+                        if (bytes[nBytes - 1] > bt)
+                        {
+                            for (int i = nBytes - 1; i >= 0; i--)
+                            {
+                                if (bytes[i] > bt)
+                                    count++;
+                                else
+                                    break;
+                            }
+                            if (count % 2 == 1)
+                            {
+                                count = sock.Receive(bytes, nBytes, 1, 0);
+                                if (count < 0)
+                                    break;
+                                nBytes += count;
+                            }
+                        }
+                        else
+                        {
+                            bytes[nBytes] = (byte)'\0';
+                        }
+
+                        string s = Encoding.GetEncoding(sCoding).GetString(bytes, 0, nBytes);
+                        sbHtml.Append(s);
+                    } while (nBytes > 0);
+
+                    listResult.Add(new KeyValuePair<int, string>(kvUrl.Key, sbHtml.ToString()));
+                    sbHtml = null;
+                    sbHtml = new StringBuilder();
+                }
+            }
+            catch (Exception Ex)
+            {
+                string s = Ex.Message;
+                try
+                {
+                    sock.Shutdown(SocketShutdown.Both);
+                    sock.Close();
+                }
+                catch (Exception e)
+                {
+                    LogManager.Error(e);
+                }
+            }
+            finally
+            {
+                try
+                {
+                    sock.Shutdown(SocketShutdown.Both);
+                    sock.Close();
+                }
+                catch (Exception e)
+                {
+                    LogManager.Error(e);
+                }
+            }
+            return listResult;
+        }
+        #endregion 根据超链接地址获取页面内容
+
+        /// <summary>
+        /// 页面类型枚举
+        /// </summary>
+        public enum PageType : int
+        {
+            /// <summary>
+            /// HTML格式
+            /// </summary>
+            HTML = 0,
+            /// <summary>
+            /// RSS格式
+            /// </summary>
+            RSS = 1
+        }
+        /// <summary>
+        /// 获取页面类型
+        /// </summary>
+        /// <param name="sUrl">URL</param>
+        /// <param name="sHtml">内容</param>
+        /// <returns>页面类型枚举</returns>
+        public static PageType GetPageType(string sUrl, ref string sHtml)
+        {
+            PageType pt = PageType.HTML;
+
+            //看有没有RSS FEED
+            string regRss = @"<link\s+[^>]*((type=""application/rss\+xml"")|(type=application/rss\+xml))[^>]*>";
+            Regex r = new Regex(regRss, RegexOptions.IgnoreCase);
+            Match m = r.Match(sHtml);
+            if (m.Captures.Count != 0)
+            {//有,则转向从RSS FEED中抓取
+                string regHref = @"href=\s*(?:'(?<href>[^']+)'|""(?<href>[^""]+)""|(?<href>[^>\s]+))";
+                r = new Regex(regHref, RegexOptions.IgnoreCase);
+                m = r.Match(m.Captures[0].Value);
+                if (m.Captures.Count > 0)
+                {
+                    //有可能是相对路径,加上绝对路径
+                    string rssFile = GetUrl(sUrl, m.Groups["href"].Value);
+                    sHtml = GetHtmlByUrl(rssFile);
+                    pt = PageType.RSS;
+                }
+            }
+            else
+            {//看这个地址本身是不是一个Rss feed
+                r = new Regex(@"<rss\s+[^>]*>", RegexOptions.IgnoreCase);
+                m = r.Match(sHtml);
+                if (m.Captures.Count > 0)
+                {
+                    pt = PageType.RSS;
+                }
+            }
+
+            return pt;
+        }
+    }
+}

+ 226 - 0
Masuit.Tools.Core/Logging/LogManager.cs

@@ -0,0 +1,226 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+using static System.DateTime;
+
+namespace Masuit.Tools.Logging
+{
+    /// <summary>
+    /// 日志组件
+    /// </summary>
+    public class LogManager
+    {
+        static readonly ConcurrentQueue<Tuple<string, string>> LogQueue = new ConcurrentQueue<Tuple<string, string>>();
+
+        private static readonly Task WriteTask;
+
+        static LogManager()
+        {
+            WriteTask = new Task(obj =>
+            {
+                while (true)
+                {
+                    Pause.WaitOne(1000, true);
+                    List<string[]> temp = new List<string[]>();
+                    foreach (var logItem in LogQueue)
+                    {
+                        string logPath = logItem.Item1;
+                        string logMergeContent = String.Concat(logItem.Item2, Environment.NewLine, "----------------------------------------------------------------------------------------------------------------------", Environment.NewLine);
+                        string[] logArr = temp.FirstOrDefault(d => d[0].Equals(logPath));
+                        if (logArr != null)
+                        {
+                            logArr[1] = string.Concat(logArr[1], logMergeContent);
+                        }
+                        else
+                        {
+                            logArr = new[] { logPath, logMergeContent };
+                            temp.Add(logArr);
+                        }
+                        LogQueue.TryDequeue(out Tuple<string, string> _);
+                    }
+                    foreach (var item in temp)
+                    {
+                        WriteText(item[0], item[1]);
+                    }
+                }
+            }, null, TaskCreationOptions.LongRunning);
+            WriteTask.Start();
+        }
+
+        private static AutoResetEvent Pause => new AutoResetEvent(false);
+
+        /// <summary>
+        /// 日志存放目录,默认日志放在当前应用程序运行目录下的logs文件夹中
+        /// </summary>
+        public static string LogDirectory { get; set; } = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
+
+        /// <summary>
+        /// 写入Info级别的日志
+        /// </summary>
+        /// <param name="info"></param>
+        public static void Info(string info) => LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(info).ToUpper()}  {info}"));
+
+        /// <summary>
+        /// 写入Info级别的日志
+        /// </summary>
+        /// <param name="source"></param>
+        /// <param name="info"></param>
+        public static void Info(string source, string info) => LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(info).ToUpper()}   {source}  {info}"));
+
+        /// <summary>
+        /// 写入Info级别的日志
+        /// </summary>
+        /// <param name="source"></param>
+        /// <param name="info"></param>
+        public static void Info(Type source, string info) => LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(info).ToUpper()}   {source.FullName}  {info}"));
+
+        /// <summary>
+        /// 写入debug级别日志
+        /// </summary>
+        /// <param name="debug">异常对象</param>
+        public static void Debug(string debug) => LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(debug).ToUpper()}   {debug}"));
+
+        /// <summary>
+        /// 写入debug级别日志
+        /// </summary>
+        /// <param name="source">异常源的类型</param>
+        /// <param name="debug">异常对象</param>
+        public static void Debug(string source, string debug) => LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(debug).ToUpper()}   {source}  {debug}"));
+
+        /// <summary>
+        /// 写入debug级别日志
+        /// </summary>
+        /// <param name="source">异常源的类型</param>
+        /// <param name="debug">异常对象</param>
+        public static void Debug(Type source, string debug) => LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(debug).ToUpper()}   {source.FullName}  {debug}"));
+
+        /// <summary>
+        /// 写入error级别日志
+        /// </summary>
+        /// <param name="error">异常对象</param>
+        public static void Error(Exception error) => LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(error).ToUpper()}   {error.Source}  {error.Message}{Environment.NewLine}{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(error).ToUpper()}   {error.Source}  {error.StackTrace}"));
+
+        /// <summary>
+        /// 写入error级别日志
+        /// </summary>
+        /// <param name="source">异常源的类型</param>
+        /// <param name="error">异常对象</param>
+        public static void Error(Type source, Exception error) => LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(error).ToUpper()}   {source.FullName}  {error.Message}{Environment.NewLine}{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(error).ToUpper()}   {source.FullName}  {error.StackTrace}"));
+
+        /// <summary>
+        /// 写入error级别日志
+        /// </summary>
+        /// <param name="source">异常源的类型</param>
+        /// <param name="error">异常信息</param>
+        public static void Error(Type source, string error) => LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(error).ToUpper()}   {source.FullName}  {error}"));
+
+        /// <summary>
+        /// 写入error级别日志
+        /// </summary>
+        /// <param name="source">异常源的类型</param>
+        /// <param name="error">异常对象</param>
+        public static void Error(string source, Exception error) => LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(error).ToUpper()}   {source}  {error.Message}{Environment.NewLine}{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(error).ToUpper()}   {source}  {error.StackTrace}"));
+
+        /// <summary>
+        /// 写入error级别日志
+        /// </summary>
+        /// <param name="source">异常源的类型</param>
+        /// <param name="error">异常信息</param>
+        public static void Error(string source, string error) => LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(error).ToUpper()}   {source}  {error}"));
+
+        /// <summary>
+        /// 写入fatal级别日志
+        /// </summary>
+        /// <param name="fatal">异常对象</param>
+        public static void Fatal(Exception fatal) => LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(fatal).ToUpper()}   {fatal.Source}  {fatal.Message}{Environment.NewLine}{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(fatal).ToUpper()}   {fatal.Source}  {fatal.StackTrace}"));
+
+        /// <summary>
+        /// 写入fatal级别日志
+        /// </summary>
+        /// <param name="source">异常源的类型</param>
+        /// <param name="fatal">异常对象</param>
+        public static void Fatal(Type source, Exception fatal) => LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(fatal).ToUpper()}   {source.FullName}  {fatal.Message}{Environment.NewLine}{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(fatal).ToUpper()}   {source.FullName}  {fatal.StackTrace}"));
+
+        /// <summary>
+        /// 写入fatal级别日志
+        /// </summary>
+        /// <param name="source">异常源的类型</param>
+        /// <param name="fatal">异常对象</param>
+        public static void Fatal(Type source, string fatal) => LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(fatal).ToUpper()}   {source.FullName}  {fatal}"));
+
+        /// <summary>
+        /// 写入fatal级别日志
+        /// </summary>
+        /// <param name="source">异常源的类型</param>
+        /// <param name="fatal">异常对象</param>
+        public static void Fatal(string source, Exception fatal) => LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(fatal).ToUpper()}   {source}  {fatal.Message}{Environment.NewLine}{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(fatal).ToUpper()}   {source}  {fatal.StackTrace}"));
+
+        /// <summary>
+        /// 写入fatal级别日志
+        /// </summary>
+        /// <param name="source">异常源的类型</param>
+        /// <param name="fatal">异常对象</param>
+        public static void Fatal(string source, string fatal) => LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{Now}   [{Thread.CurrentThread.ManagedThreadId}]   {nameof(fatal).ToUpper()}   {source}  {fatal}"));
+
+        private static string GetLogPath()
+        {
+            string newFilePath;
+            String logDir = string.IsNullOrEmpty(LogDirectory) ? Path.Combine(Environment.CurrentDirectory, "logs") : LogDirectory;
+            if (!Directory.Exists(logDir))
+            {
+                Directory.CreateDirectory(logDir);
+            }
+            string extension = ".log";
+            string fileNameNotExt = String.Concat(Now.ToString("yyyyMMdd"));
+            string fileNamePattern = string.Concat(fileNameNotExt, "(*)", extension);
+            List<string> filePaths = Directory.GetFiles(logDir, fileNamePattern, SearchOption.TopDirectoryOnly).ToList();
+
+            if (filePaths.Count > 0)
+            {
+                int fileMaxLen = filePaths.Max(d => d.Length);
+                string lastFilePath = filePaths.Where(d => d.Length == fileMaxLen).OrderByDescending(d => d).FirstOrDefault();
+                if (new FileInfo(lastFilePath).Length > 1 * 1024 * 1024)
+                {
+                    string no = new Regex(@"(?is)(?<=\()(.*)(?=\))").Match(Path.GetFileName(lastFilePath)).Value;
+                    bool parse = int.TryParse(no, out int tempno);
+                    string formatno = $"({(parse ? (tempno + 1) : tempno)})";
+                    string newFileName = String.Concat(fileNameNotExt, formatno, extension);
+                    newFilePath = Path.Combine(logDir, newFileName);
+                }
+                else
+                {
+                    newFilePath = lastFilePath;
+                }
+            }
+            else
+            {
+                string newFileName = string.Concat(fileNameNotExt, $"({0})", extension);
+                newFilePath = Path.Combine(logDir, newFileName);
+            }
+            return newFilePath;
+        }
+
+        private static void WriteText(string logPath, string logContent)
+        {
+            try
+            {
+                if (!File.Exists(logPath))
+                {
+                    File.CreateText(logPath).Close();
+                }
+                using (StreamWriter sw = File.AppendText(logPath))
+                {
+                    sw.Write(logContent);
+                }
+            }
+            catch (Exception)
+            {
+            }
+        }
+    }
+}

+ 20 - 0
Masuit.Tools.Core/Masuit.Tools.Core.csproj

@@ -0,0 +1,20 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netstandard2.0</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="AngleSharp" Version="0.9.9" />
+    <PackageReference Include="HtmlSanitizer" Version="4.0.181" />
+    <PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
+    <PackageReference Include="StackExchange.Redis" Version="1.2.6" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Reference Include="System.Configuration">
+      <HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7\System.Configuration.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+
+</Project>

+ 64 - 0
Masuit.Tools.Core/Models/BaiduIP.cs

@@ -0,0 +1,64 @@
+using Newtonsoft.Json;
+
+namespace Masuit.Tools.Models
+{
+    /// <summary>
+    /// 百度IP接口的信息
+    /// </summary>
+    public class BaiduIP
+    {
+        /// <summary>
+        /// 基本信息
+        /// </summary>
+        [JsonProperty("address")]
+        public string Address { get; set; }
+
+        /// <summary>
+        /// 基本地理信息
+        /// </summary>
+        [JsonProperty("content")]
+        public AddressInfo AddressInfo { get; set; }
+
+        /// <summary>
+        /// 返回状态,0正常,1出错
+        /// </summary>
+        [JsonProperty("status")]
+        public int Status { get; set; }
+    }
+
+    /// <summary>
+    /// 基本地理信息
+    /// </summary>
+    public class AddressInfo
+    {
+        /// <summary>
+        /// 基本地址
+        /// </summary>
+        [JsonProperty("address")]
+        public string Address { get; set; }
+
+        /// <summary>
+        /// 经纬度
+        /// </summary>
+        [JsonProperty("point")]
+        public LatiLongitude LatiLongitude { get; set; }
+    }
+
+    /// <summary>
+    /// 经纬度
+    /// </summary>
+    public class LatiLongitude
+    {
+        /// <summary>
+        /// 经度
+        /// </summary>
+        [JsonProperty("x")]
+        public string X { get; set; }
+
+        /// <summary>
+        /// 纬度
+        /// </summary>
+        [JsonProperty("y")]
+        public string Y { get; set; }
+    }
+}

+ 147 - 0
Masuit.Tools.Core/Models/Email.cs

@@ -0,0 +1,147 @@
+using System;
+using System.Net.Mail;
+
+namespace Masuit.Tools.Models
+{
+#pragma warning disable 1591
+    public class Email
+    {
+        /// <summary>
+        /// 发件人用户名
+        /// </summary>
+        public string Username { get; set; }
+        /// <summary>
+        /// 发件人邮箱密码
+        /// </summary>
+        public string Password { get; set; }
+        /// <summary>
+        /// 发送服务器端口号,默认25
+        /// </summary>
+        public int SmtpPort { get; set; } = 25;
+        /// <summary>
+        /// 发送服务器地址
+        /// </summary>
+        public string SmtpServer { get; set; }
+        /// <summary>
+        /// 邮件标题
+        /// </summary>
+        public string Subject { get; set; }
+        /// <summary>
+        /// 邮件正文
+        /// </summary>
+        public string Body { get; set; }
+        /// <summary>
+        /// 收件人,多个收件人用英文逗号隔开
+        /// </summary>
+        public string Tos { get; set; }
+
+        /// <summary>
+        /// 是否启用SSL,默认已启用
+        /// </summary>
+        public bool EnableSsl { get; set; } = true;
+        /// <summary>
+        /// 邮件消息对象
+        /// </summary>
+        MailMessage GetClient
+        {
+            get
+            {
+                if (string.IsNullOrEmpty(Tos)) return null;
+                MailMessage mailMessage = new MailMessage();
+                //多个接收者                
+                foreach (string _str in Tos.Split(','))
+                {
+                    mailMessage.To.Add(_str);
+                }
+                mailMessage.From = new MailAddress(Username, Username);
+                mailMessage.Subject = Subject;
+                mailMessage.Body = Body;
+                mailMessage.IsBodyHtml = true;
+                mailMessage.BodyEncoding = System.Text.Encoding.UTF8;
+                mailMessage.SubjectEncoding = System.Text.Encoding.UTF8;
+                mailMessage.Priority = MailPriority.High;
+                return mailMessage;
+            }
+        }
+        SmtpClient GetSmtpClient => new SmtpClient
+        {
+            UseDefaultCredentials = false,
+            EnableSsl = EnableSsl,
+            Host = SmtpServer,
+            Port = SmtpPort,
+            Credentials = new System.Net.NetworkCredential(Username, Password),
+            DeliveryMethod = SmtpDeliveryMethod.Network,
+        };
+
+        //回调方法
+        Action<string> actionSendCompletedCallback = null;
+
+        /// <summary>
+        /// 使用异步发送邮件
+        /// </summary>
+        /// <param name="completedCallback">邮件发送后的回调方法</param>
+        /// <returns></returns>
+        public void SendAsync(Action<string> completedCallback)
+        {
+            using (SmtpClient smtpClient = GetSmtpClient)
+            {
+                using (MailMessage mailMessage = GetClient)
+                {
+                    if (smtpClient == null || mailMessage == null) return;
+                    Subject = Subject;
+                    Body = Body;
+                    //EnableSsl = false;
+                    //发送邮件回调方法
+                    actionSendCompletedCallback = completedCallback;
+                    smtpClient.SendCompleted += SendCompletedCallback;
+                    smtpClient.SendAsync(mailMessage, "true"); //异步发送邮件,如果回调方法中参数不为"true"则表示发送失败
+                }
+            }
+        }
+
+        /// <summary>
+        /// 使用同步发送邮件
+        /// </summary>
+        public void Send()
+        {
+            using (SmtpClient smtpClient = GetSmtpClient)
+            {
+                using (MailMessage mailMessage = GetClient)
+                {
+                    if (smtpClient == null || mailMessage == null) return;
+                    Subject = Subject;
+                    Body = Body;
+                    //EnableSsl = false;
+                    smtpClient.Send(mailMessage); //异步发送邮件,如果回调方法中参数不为"true"则表示发送失败
+                }
+            }
+        }
+
+        /// <summary>
+        /// 异步操作完成后执行回调方法
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void SendCompletedCallback(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
+        {
+            //同一组件下不需要回调方法,直接在此写入日志即可
+            //写入日志
+            //return;
+            if (actionSendCompletedCallback == null) return;
+            string message = string.Empty;
+            if (e.Cancelled)
+            {
+                message = "异步操作取消";
+            }
+            else if (e.Error != null)
+            {
+                message = (string.Format("UserState:{0},Message:{1}", (string)e.UserState, e.Error.ToString()));
+            }
+            else
+                message = (string)e.UserState;
+            //执行回调方法
+            actionSendCompletedCallback(message);
+        }
+    }
+#pragma warning restore 1591
+}

+ 16 - 0
Masuit.Tools.Core/Models/IspInfo.cs

@@ -0,0 +1,16 @@
+using Newtonsoft.Json;
+
+namespace Masuit.Tools.Models
+{
+    /// <summary>
+    /// ISP信息
+    /// </summary>
+    public class IspInfo
+    {
+        /// <summary>
+        /// 运营商
+        /// </summary>
+        [JsonProperty("wl")]
+        public string ISPName { get; set; }
+    }
+}

+ 191 - 0
Masuit.Tools.Core/Models/PhysicsAddress.cs

@@ -0,0 +1,191 @@
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace Masuit.Tools.Models
+{
+    /// <summary>
+    /// 详细地理信息
+    /// </summary>
+    public class PhysicsAddress
+    {
+        /// <summary>
+        /// 返回状态,0正常,1出错
+        /// </summary>
+        [JsonProperty("status")]
+        public int Status { get; set; }
+
+        /// <summary>
+        /// 返回结果集
+        /// </summary>
+        [JsonProperty("result")]
+        public AddressResult AddressResult { get; set; }
+    }
+
+    /// <summary>
+    /// 返回结果集
+    /// </summary>
+    public class AddressResult
+    {
+        /// <summary>
+        /// 经纬度
+        /// </summary>
+        [JsonProperty("location")]
+        public Location Location { get; set; }
+
+        /// <summary>
+        /// 详细地址
+        /// </summary>
+        [JsonProperty("formatted_address")]
+        public string FormattedAddress { get; set; }
+
+        /// <summary>
+        /// 商业地址
+        /// </summary>
+        [JsonProperty("business")]
+        public string Business { get; set; }
+
+        /// <summary>
+        /// 地理信息成分
+        /// </summary>
+        [JsonProperty("addressComponent")]
+        public AddressComponent AddressComponent { get; set; }
+
+        /// <summary>
+        /// 参考地址
+        /// </summary>
+        [JsonProperty("pois")]
+        public List<Pois> Pois { get; set; }
+
+        /// <summary>
+        /// 语义描述
+        /// </summary>
+        [JsonProperty("sematic_description")]
+        public string SematicDescription { get; set; }
+    }
+
+    /// <summary>
+    /// 经纬度
+    /// </summary>
+    public class Location
+    {
+        /// <summary>
+        /// 经度
+        /// </summary>
+        [JsonProperty("lng")]
+        public double Lng { get; set; }
+
+        /// <summary>
+        /// 纬度
+        /// </summary>
+        [JsonProperty("lat")]
+        public double Lat { get; set; }
+    }
+
+    /// <summary>
+    /// 地理信息成分
+    /// </summary>
+    public class AddressComponent
+    {
+        /// <summary>
+        /// 国家
+        /// </summary>
+        [JsonProperty("country")]
+        public string Country { get; set; }
+
+        /// <summary>
+        /// 国家代码
+        /// </summary>
+        [JsonProperty("country_code")]
+        public int CountryCode { get; set; }
+
+        /// <summary>
+        /// 省
+        /// </summary>
+        [JsonProperty("province")]
+        public string Province { get; set; }
+
+        /// <summary>
+        /// 市
+        /// </summary>
+        [JsonProperty("city")]
+        public string City { get; set; }
+
+        /// <summary>
+        /// 区
+        /// </summary>
+        [JsonProperty("district")]
+        public string District { get; set; }
+
+        /// <summary>
+        /// 街道
+        /// </summary>
+        [JsonProperty("street")]
+        public string Street { get; set; }
+
+        /// <summary>
+        /// 门牌号
+        /// </summary>
+        [JsonProperty("street_number")]
+        public string StreetNumber { get; set; }
+
+        /// <summary>
+        /// 方位
+        /// </summary>
+        [JsonProperty("direction")]
+        public string Direction { get; set; }
+
+        /// <summary>
+        /// 距离
+        /// </summary>
+        [JsonProperty("distance")]
+        public string Distance { get; set; } = "0";
+    }
+
+    /// <summary>
+    /// 参考位置
+    /// </summary>
+    public class Pois
+    {
+        /// <summary>
+        /// 地理位置详细
+        /// </summary>
+        [JsonProperty("addr")]
+        public string AddressDetail { get; set; }
+
+        /// <summary>
+        /// 方位
+        /// </summary>
+        [JsonProperty("direction")]
+        public string Direction { get; set; }
+
+        /// <summary>
+        /// 距离
+        /// </summary>
+        [JsonProperty("distance")]
+        public string Distance { get; set; } = "0";
+
+        /// <summary>
+        /// 建筑物名字
+        /// </summary>
+        [JsonProperty("name")]
+        public string Name { get; set; }
+
+        /// <summary>
+        /// 建筑物类型
+        /// </summary>
+        [JsonProperty("poiType")]
+        public string PoiType { get; set; }
+
+        /// <summary>
+        /// 经纬度
+        /// </summary>
+        [JsonProperty("point")]
+        public LatiLongitude Point { get; set; }
+
+        /// <summary>
+        /// 标签
+        /// </summary>
+        [JsonProperty("tag")]
+        public string Tag { get; set; }
+    }
+}

+ 52 - 0
Masuit.Tools.Core/Models/TaobaoIP.cs

@@ -0,0 +1,52 @@
+using Newtonsoft.Json;
+
+namespace Masuit.Tools.Models
+{
+    /// <summary>
+    /// 淘宝IP接口信息
+    /// </summary>
+    public class TaobaoIP
+    {
+        /// <summary>
+        /// 返回状态码
+        /// </summary>
+        [JsonProperty("code")]
+        public int Code { get; set; }
+
+        /// <summary>
+        /// 数据
+        /// </summary>
+        [JsonProperty("data")]
+        public IPData IpData { get; set; }
+    }
+
+    /// <summary>
+    /// 淘宝IP接口信息
+    /// </summary>
+    public class IPData
+    {
+        /// <summary>
+        /// 国家
+        /// </summary>
+        [JsonProperty("country")]
+        public string Country { get; set; }
+
+        /// <summary>
+        /// 省
+        /// </summary>
+        [JsonProperty("region")]
+        public string Region { get; set; }
+
+        /// <summary>
+        /// 市
+        /// </summary>
+        [JsonProperty("city")]
+        public string City { get; set; }
+
+        /// <summary>
+        /// ISP
+        /// </summary>
+        [JsonProperty("isp")]
+        public string Isp { get; set; }
+    }
+}

+ 650 - 0
Masuit.Tools.Core/Net/FtpClient.cs

@@ -0,0 +1,650 @@
+using System;
+using System.IO;
+using System.Net;
+using System.Text;
+
+namespace Masuit.Tools.Net
+{
+    /// <summary>
+    /// FTP客户端操作类
+    /// </summary>
+    public class FtpClient
+    {
+        string _ftpRemotePath;
+
+        #region 变量属性
+
+        /// <summary>
+        /// Ftp服务器ip
+        /// </summary>
+        public static string FtpServer { get; set; }
+
+        /// <summary>
+        /// Ftp 指定用户名
+        /// </summary>
+        public static string Username { get; set; }
+
+        /// <summary>
+        /// Ftp 指定用户密码
+        /// </summary>
+        public static string Password { get; set; }
+
+        public static string FtpUri = "ftp://" + FtpServer + "/";
+
+        #endregion
+
+        #region 从FTP服务器下载文件,指定本地路径和本地文件名
+
+        /// <summary>
+        /// 从FTP服务器下载文件,指定本地路径和本地文件名
+        /// </summary>
+        /// <param name="remoteFileName">远程文件名</param>
+        /// <param name="localFileName">保存本地的文件名(包含路径)</param>
+        /// <param name="ifCredential">是否启用身份验证(false:表示允许用户匿名下载)</param>
+        /// <param name="updateProgress">报告进度的处理(第一个参数:总大小,第二个参数:当前进度)</param>
+        public static void Download(string remoteFileName, string localFileName, bool ifCredential = false, Action<int, int> updateProgress = null)
+        {
+            using (FileStream outputStream = new FileStream(localFileName, FileMode.Create))
+            {
+                if (FtpServer == null || FtpServer.Trim().Length == 0)
+                {
+                    throw new Exception("ftp下载目标服务器地址未设置!");
+                }
+                Uri uri = new Uri("ftp://" + FtpServer + "/" + remoteFileName);
+                var ftpsize = (FtpWebRequest)WebRequest.Create(uri);
+                ftpsize.UseBinary = true;
+                var reqFtp = (FtpWebRequest)WebRequest.Create(uri);
+                reqFtp.UseBinary = true;
+                reqFtp.KeepAlive = false;
+                if (ifCredential) //使用用户身份认证
+                {
+                    ftpsize.Credentials = new NetworkCredential(Username, Password);
+                    reqFtp.Credentials = new NetworkCredential(Username, Password);
+                }
+                ftpsize.Method = WebRequestMethods.Ftp.GetFileSize;
+                using (FtpWebResponse re = (FtpWebResponse)ftpsize.GetResponse())
+                {
+                    long totalBytes = re.ContentLength;
+                    reqFtp.Method = WebRequestMethods.Ftp.DownloadFile;
+                    var response = (FtpWebResponse)reqFtp.GetResponse();
+                    using (response)
+                    {
+                        var ftpStream = response.GetResponseStream();
+                        //更新进度 
+                        using (ftpStream)
+                        {
+                            updateProgress?.Invoke((int)totalBytes, 0); //更新进度条 
+                            long totalDownloadedByte = 0;
+                            int bufferSize = 1024 * 1024;
+                            byte[] buffer = new byte[bufferSize];
+                            if (ftpStream != null)
+                            {
+                                var readCount = ftpStream.Read(buffer, 0, bufferSize);
+                                while (readCount > 0)
+                                {
+                                    totalDownloadedByte = readCount + totalDownloadedByte;
+                                    outputStream.Write(buffer, 0, readCount);
+                                    //更新进度 
+                                    updateProgress?.Invoke((int)totalBytes, (int)totalDownloadedByte); //更新进度条 
+                                    readCount = ftpStream.Read(buffer, 0, bufferSize);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// 从FTP服务器下载文件,指定本地路径和本地文件名(支持断点下载)
+        /// </summary>
+        /// <param name="remoteFileName">远程文件名</param>
+        /// <param name="localFileName">保存本地的文件名(包含路径)</param>
+        /// <param name="ifCredential">是否启用身份验证(false:表示允许用户匿名下载)</param>
+        /// <param name="size">已下载文件流大小</param>
+        /// <param name="updateProgress">报告进度的处理(第一个参数:总大小,第二个参数:当前进度)</param>
+        public static void BrokenDownload(string remoteFileName, string localFileName, bool ifCredential, long size, Action<int, int> updateProgress = null)
+        {
+            using (FileStream outputStream = new FileStream(localFileName, FileMode.Append))
+            {
+                if (FtpServer == null || FtpServer.Trim().Length == 0)
+                {
+                    throw new Exception("ftp下载目标服务器地址未设置!");
+                }
+                Uri uri = new Uri("ftp://" + FtpServer + "/" + remoteFileName);
+                var ftpsize = (FtpWebRequest)WebRequest.Create(uri);
+                ftpsize.UseBinary = true;
+                ftpsize.ContentOffset = size;
+                var reqFtp = (FtpWebRequest)WebRequest.Create(uri);
+                reqFtp.UseBinary = true;
+                reqFtp.KeepAlive = false;
+                reqFtp.ContentOffset = size;
+                if (ifCredential) //使用用户身份认证
+                {
+                    ftpsize.Credentials = new NetworkCredential(Username, Password);
+                    reqFtp.Credentials = new NetworkCredential(Username, Password);
+                }
+                ftpsize.Method = WebRequestMethods.Ftp.GetFileSize;
+                using (FtpWebResponse re = (FtpWebResponse)ftpsize.GetResponse())
+                {
+                    var totalBytes = re.ContentLength;
+                    reqFtp.Method = WebRequestMethods.Ftp.DownloadFile;
+                    using (var response = (FtpWebResponse)reqFtp.GetResponse())
+                    {
+                        using (var ftpStream = response.GetResponseStream())
+                        {
+                            updateProgress?.Invoke((int)totalBytes, 0); //更新进度条 
+                            long totalDownloadedByte = 0;
+                            int bufferSize = 1024 * 1024;
+                            byte[] buffer = new byte[bufferSize];
+                            if (ftpStream != null)
+                            {
+                                var readCount = ftpStream.Read(buffer, 0, bufferSize);
+                                while (readCount > 0)
+                                {
+                                    totalDownloadedByte = readCount + totalDownloadedByte;
+                                    outputStream.Write(buffer, 0, readCount);
+                                    //更新进度 
+                                    updateProgress?.Invoke((int)totalBytes, (int)totalDownloadedByte); //更新进度条 
+                                    readCount = ftpStream.Read(buffer, 0, bufferSize);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// 从FTP服务器下载文件,指定本地路径和本地文件名
+        /// </summary>
+        /// <param name="remoteFileName">远程文件名</param>
+        /// <param name="localFileName">保存本地的文件名(包含路径)</param>
+        /// <param name="ifCredential">是否启用身份验证(false:表示允许用户匿名下载)</param>
+        /// <param name="updateProgress">报告进度的处理(第一个参数:总大小,第二个参数:当前进度)</param>
+        /// <param name="brokenOpen">是否断点下载:true 会在localFileName 找是否存在已经下载的文件,并计算文件流大小</param>
+        public static void Download(string remoteFileName, string localFileName, bool ifCredential, bool brokenOpen, Action<int, int> updateProgress = null)
+        {
+            if (brokenOpen)
+            {
+                long size = 0;
+                if (File.Exists(localFileName))
+                {
+                    using (FileStream outputStream = new FileStream(localFileName, FileMode.Open))
+                    {
+                        size = outputStream.Length;
+                    }
+                }
+                BrokenDownload(remoteFileName, localFileName, ifCredential, size, updateProgress);
+            }
+            Download(remoteFileName, localFileName, ifCredential, updateProgress);
+        }
+
+        #endregion
+
+        #region 上传文件到FTP服务器
+
+        /// <summary>
+        /// 上传文件到FTP服务器
+        /// </summary>
+        /// <param name="localFullPathName">本地带有完整路径的文件名</param>
+        /// <param name="updateProgress">报告进度的处理(第一个参数:总大小,第二个参数:当前进度)</param>
+        public static void UploadFile(string localFullPathName, Action<int, int> updateProgress = null)
+        {
+            FileInfo finfo = new FileInfo(localFullPathName);
+            if (FtpServer == null || FtpServer.Trim().Length == 0)
+            {
+                throw new Exception("ftp上传目标服务器地址未设置!");
+            }
+            Uri uri = new Uri("ftp://" + FtpServer + "/" + finfo.Name);
+            var reqFtp = (FtpWebRequest)WebRequest.Create(uri);
+            reqFtp.KeepAlive = false;
+            reqFtp.UseBinary = true;
+            reqFtp.Credentials = new NetworkCredential(Username, Password); //用户,密码
+            reqFtp.Method = WebRequestMethods.Ftp.UploadFile; //向服务器发出下载请求命令
+            reqFtp.ContentLength = finfo.Length; //为request指定上传文件的大小
+            int buffLength = 1024 * 1024;
+            byte[] buff = new byte[buffLength];
+            using (var fs = finfo.OpenRead())
+            {
+                using (var stream = reqFtp.GetRequestStream())
+                {
+                    var contentLen = fs.Read(buff, 0, buffLength);
+                    int allbye = (int)finfo.Length;
+                    //更新进度 
+                    updateProgress?.Invoke(allbye, 0); //更新进度条 
+                    int startbye = 0;
+                    while (contentLen != 0)
+                    {
+                        startbye = contentLen + startbye;
+                        stream.Write(buff, 0, contentLen);
+                        //更新进度 
+                        updateProgress?.Invoke(allbye, startbye); //更新进度条 
+                        contentLen = fs.Read(buff, 0, buffLength);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// 上传文件到FTP服务器(断点续传)
+        /// </summary>
+        /// <param name="localFullPath">本地文件全路径名称:C:\Users\JianKunKing\Desktop\IronPython脚本测试工具</param>
+        /// <param name="remoteFilepath">远程文件所在文件夹路径</param>
+        /// <param name="updateProgress">报告进度的处理(第一个参数:总大小,第二个参数:当前进度)</param>
+        /// <returns></returns> 
+        public static bool UploadBroken(string localFullPath, string remoteFilepath, Action<int, int> updateProgress = null)
+        {
+            if (remoteFilepath == null)
+            {
+                remoteFilepath = "";
+            }
+            string newFileName;
+            FileInfo fileInf = new FileInfo(localFullPath);
+            long allbye = fileInf.Length;
+            if (fileInf.Name.IndexOf("#", StringComparison.Ordinal) == -1)
+            {
+                newFileName = RemoveSpaces(fileInf.Name);
+            }
+            else
+            {
+                newFileName = fileInf.Name.Replace("#", "#");
+                newFileName = RemoveSpaces(newFileName);
+            }
+            long startfilesize = GetFileSize(newFileName, remoteFilepath);
+            if (startfilesize >= allbye)
+            {
+                return false;
+            }
+            long startbye = startfilesize;
+            //更新进度 
+            updateProgress?.Invoke((int)allbye, (int)startfilesize); //更新进度条 
+
+            string uri;
+            if (remoteFilepath.Length == 0)
+            {
+                uri = "ftp://" + FtpServer + "/" + newFileName;
+            }
+            else
+            {
+                uri = "ftp://" + FtpServer + "/" + remoteFilepath + "/" + newFileName;
+            }
+            // 根据uri创建FtpWebRequest对象 
+            var reqFtp = (FtpWebRequest)WebRequest.Create(new Uri(uri));
+            // ftp用户名和密码 
+            reqFtp.Credentials = new NetworkCredential(Username, Password);
+            // 默认为true,连接不会被关闭 
+            // 在一个命令之后被执行 
+            reqFtp.KeepAlive = false;
+            // 指定执行什么命令 
+            reqFtp.Method = WebRequestMethods.Ftp.AppendFile;
+            // 指定数据传输类型 
+            reqFtp.UseBinary = true;
+            // 上传文件时通知服务器文件的大小 
+            reqFtp.ContentLength = fileInf.Length;
+            int buffLength = 1024 * 1024; // 缓冲大小设置为2kb 
+            byte[] buff = new byte[buffLength];
+            // 打开一个文件流 (System.IO.FileStream) 去读上传的文件 
+            using (FileStream fs = fileInf.OpenRead())
+            {
+                using (var strm = reqFtp.GetRequestStream())
+                {
+                    // 把上传的文件写入流 
+                    fs.Seek(startfilesize, 0);
+                    int contentLen = fs.Read(buff, 0, buffLength);
+                    // 流内容没有结束 
+                    while (contentLen != 0)
+                    {
+                        // 把内容从file stream 写入 upload stream 
+                        strm.Write(buff, 0, contentLen);
+                        contentLen = fs.Read(buff, 0, buffLength);
+                        startbye += contentLen;
+                        //更新进度 
+                        updateProgress?.Invoke((int)allbye, (int)startbye); //更新进度条 
+                    }
+                }
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// 去除空格
+        /// </summary>
+        /// <param name="str"></param>
+        /// <returns></returns>
+        private static string RemoveSpaces(string str)
+        {
+            string a = "";
+            foreach (char c in str)
+            {
+                var array = Encoding.ASCII.GetBytes(c.ToString());
+                int asciicode = array[0];
+                if (asciicode != 32)
+                {
+                    a += c.ToString();
+                }
+            }
+            return a.Split('.')[a.Split('.').Length - 2] + "." + a.Split('.')[a.Split('.').Length - 1];
+        }
+
+        /// <summary>
+        /// 获取已上传文件大小
+        /// </summary>
+        /// <param name="filename">文件名称</param>
+        /// <param name="remoteFilepath">服务器文件路径</param>
+        /// <returns></returns>
+        public static long GetFileSize(string filename, string remoteFilepath)
+        {
+            try
+            {
+                FileInfo fi = new FileInfo(filename);
+                string uri;
+                if (remoteFilepath.Length == 0)
+                {
+                    uri = "ftp://" + FtpServer + "/" + fi.Name;
+                }
+                else
+                {
+                    uri = "ftp://" + FtpServer + "/" + remoteFilepath + "/" + fi.Name;
+                }
+                var reqFtp = (FtpWebRequest)WebRequest.Create(uri);
+                reqFtp.KeepAlive = false;
+                reqFtp.UseBinary = true;
+                reqFtp.Credentials = new NetworkCredential(Username, Password); //用户,密码
+                reqFtp.Method = WebRequestMethods.Ftp.GetFileSize;
+                FtpWebResponse response = (FtpWebResponse)reqFtp.GetResponse();
+                var filesize = response.ContentLength;
+                return filesize;
+            }
+            catch
+            {
+                return 0;
+            }
+        }
+
+        #endregion
+
+        #region 获取当前目录下明细
+
+        /// <summary>
+        /// 获取当前目录下明细(包含文件和文件夹)
+        /// </summary>
+        /// <returns></returns>
+        public static string[] GetFilesDetails()
+        {
+            StringBuilder result = new StringBuilder();
+            var ftp = (FtpWebRequest)WebRequest.Create(new Uri(FtpUri));
+            ftp.Credentials = new NetworkCredential(Username, Password);
+            ftp.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
+            using (WebResponse response = ftp.GetResponse())
+            {
+                using (StreamReader reader = new StreamReader(response.GetResponseStream() ?? throw new InvalidOperationException(), Encoding.Default))
+                {
+                    string line = reader.ReadLine();
+                    while (line != null)
+                    {
+                        result.Append(line);
+                        result.Append("\n");
+                        line = reader.ReadLine();
+                    }
+                    result.Remove(result.ToString().LastIndexOf("\n", StringComparison.Ordinal), 1);
+                }
+            }
+            return result.ToString().Split('\n');
+        }
+
+        /// <summary>
+        /// 获取当前目录下文件列表(仅文件)
+        /// </summary>
+        /// <returns></returns>
+        public static string[] GetFiles(string mask)
+        {
+            StringBuilder result = new StringBuilder();
+            var reqFtp = (FtpWebRequest)WebRequest.Create(new Uri(FtpUri));
+            reqFtp.UseBinary = true;
+            reqFtp.Credentials = new NetworkCredential(Username, Password);
+            reqFtp.Method = WebRequestMethods.Ftp.ListDirectory;
+            using (WebResponse response = reqFtp.GetResponse())
+            {
+                using (StreamReader reader = new StreamReader(response.GetResponseStream() ?? throw new InvalidOperationException(), Encoding.Default))
+                {
+                    string line = reader.ReadLine();
+                    while (line != null)
+                    {
+                        if (mask.Trim() != string.Empty && mask.Trim() != "*.*")
+                        {
+                            string temp = mask.Substring(0, mask.IndexOf("*", StringComparison.Ordinal));
+                            if (line.Substring(0, temp.Length) == temp)
+                            {
+                                result.Append(line);
+                                result.Append("\n");
+                            }
+                        }
+                        else
+                        {
+                            result.Append(line);
+                            result.Append("\n");
+                        }
+                        line = reader.ReadLine();
+                    }
+                    result.Remove(result.ToString().LastIndexOf('\n'), 1);
+                }
+            }
+            return result.ToString().Split('\n');
+        }
+
+        /// <summary>
+        /// 获取当前目录下所有的文件夹列表(仅文件夹)
+        /// </summary>
+        /// <returns></returns>
+        public static string[] GetDirectories()
+        {
+            string[] drectory = GetFilesDetails();
+            string m = string.Empty;
+            foreach (string str in drectory)
+            {
+                int dirPos = str.IndexOf("<DIR>", StringComparison.Ordinal);
+                if (dirPos > 0)
+                {
+                    /*判断 Windows 风格*/
+                    m += str.Substring(dirPos + 5).Trim() + "\n";
+                }
+                else if (str.Trim().Substring(0, 1).ToUpper() == "D")
+                {
+                    /*判断 Unix 风格*/
+                    string dir = str.Substring(54).Trim();
+                    if (dir != "." && dir != "..")
+                    {
+                        m += dir + "\n";
+                    }
+                }
+            }
+            char[] n = { '\n' };
+            return m.Split(n);
+        }
+
+        #endregion
+
+        #region 删除文件及文件夹
+
+        /// <summary>
+        /// 删除文件
+        /// </summary>
+        /// <param name="fileName"></param>
+        public static void Delete(string fileName)
+        {
+            string uri = FtpUri + fileName;
+            var reqFtp = (FtpWebRequest)WebRequest.Create(new Uri(uri));
+
+            reqFtp.Credentials = new NetworkCredential(Username, Password);
+            reqFtp.KeepAlive = false;
+            reqFtp.Method = WebRequestMethods.Ftp.DeleteFile;
+
+            using (FtpWebResponse response = (FtpWebResponse)reqFtp.GetResponse())
+            {
+                using (Stream datastream = response.GetResponseStream())
+                {
+                    using (StreamReader sr = new StreamReader(datastream ?? throw new InvalidOperationException()))
+                    {
+                        sr.ReadToEnd();
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// 删除文件夹
+        /// </summary>
+        /// <param name="folderName"></param>
+        public static void RemoveDirectory(string folderName)
+        {
+            string uri = FtpUri + folderName;
+            var reqFtp = (FtpWebRequest)WebRequest.Create(new Uri(uri));
+            reqFtp.Credentials = new NetworkCredential(Username, Password);
+            reqFtp.KeepAlive = false;
+            reqFtp.Method = WebRequestMethods.Ftp.RemoveDirectory;
+            using (FtpWebResponse response = (FtpWebResponse)reqFtp.GetResponse())
+            {
+                using (Stream datastream = response.GetResponseStream())
+                {
+                    using (StreamReader sr = new StreamReader(datastream ?? throw new InvalidOperationException()))
+                    {
+                        sr.ReadToEnd();
+                    }
+                }
+            }
+        }
+
+        #endregion
+
+        #region 其他操作
+
+        /// <summary>
+        /// 获取指定文件大小
+        /// </summary>
+        /// <param name="filename"></param>
+        /// <returns></returns>
+        public static long GetFileSize(string filename)
+        {
+            var reqFtp = (FtpWebRequest)WebRequest.Create(new Uri(FtpUri + filename));
+            reqFtp.Method = WebRequestMethods.Ftp.GetFileSize;
+            reqFtp.UseBinary = true;
+            reqFtp.Credentials = new NetworkCredential(Username, Password);
+            using (FtpWebResponse response = (FtpWebResponse)reqFtp.GetResponse())
+            {
+                var fileSize = response.ContentLength;
+                return fileSize;
+            }
+        }
+
+        /// <summary>
+        /// 判断当前目录下指定的子目录是否存在
+        /// </summary>
+        /// <param name="remoteDirectoryName">指定的目录名</param>
+        public bool DirectoryExist(string remoteDirectoryName)
+        {
+            try
+            {
+                string[] dirList = GetDirectories();
+                foreach (string str in dirList)
+                {
+                    if (str.Trim() == remoteDirectoryName.Trim())
+                    {
+                        return true;
+                    }
+                }
+                return false;
+            }
+            catch
+            {
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// 判断当前目录下指定的文件是否存在
+        /// </summary>
+        /// <param name="remoteFileName">远程文件名</param>
+        public bool FileExist(string remoteFileName)
+        {
+            string[] fileList = GetFiles("*.*");
+            foreach (string str in fileList)
+            {
+                if (str.Trim() == remoteFileName.Trim())
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /// <summary>
+        /// 创建文件夹
+        /// </summary>
+        /// <param name="dirName"></param>
+        public void MakeDir(string dirName)
+        {
+            // dirName = name of the directory to create.
+            var reqFtp = (FtpWebRequest)WebRequest.Create(new Uri(FtpUri + dirName));
+            reqFtp.Method = WebRequestMethods.Ftp.MakeDirectory;
+            reqFtp.UseBinary = true;
+            reqFtp.Credentials = new NetworkCredential(Username, Password);
+            using (FtpWebResponse response = (FtpWebResponse)reqFtp.GetResponse())
+            {
+                using (response.GetResponseStream())
+                {
+                }
+            }
+        }
+
+        /// <summary>
+        /// 改名
+        /// </summary>
+        /// <param name="currentFilename"></param>
+        /// <param name="newFilename"></param>
+        public void Rename(string currentFilename, string newFilename)
+        {
+            var reqFtp = (FtpWebRequest)WebRequest.Create(new Uri(FtpUri + currentFilename));
+            reqFtp.Method = WebRequestMethods.Ftp.Rename;
+            reqFtp.RenameTo = newFilename;
+            reqFtp.UseBinary = true;
+            reqFtp.Credentials = new NetworkCredential(Username, Password);
+            using (FtpWebResponse response = (FtpWebResponse)reqFtp.GetResponse())
+            {
+                using (response.GetResponseStream())
+                {
+                }
+            }
+        }
+
+        /// <summary>
+        /// 移动文件
+        /// </summary>
+        /// <param name="currentFilename"></param>
+        /// <param name="newDirectory"></param>
+        public void MoveFile(string currentFilename, string newDirectory)
+        {
+            Rename(currentFilename, newDirectory);
+        }
+
+        /// <summary>
+        /// 切换当前目录
+        /// </summary>
+        /// <param name="directoryName"></param>
+        /// <param name="isRoot">true 绝对路径 false 相对路径</param>
+        public void GotoDirectory(string directoryName, bool isRoot)
+        {
+            if (isRoot)
+            {
+                _ftpRemotePath = directoryName;
+            }
+            else
+            {
+                _ftpRemotePath += directoryName + "/";
+            }
+            FtpUri = "ftp://" + FtpServer + "/" + _ftpRemotePath + "/";
+        }
+
+        #endregion
+    }
+}

+ 550 - 0
Masuit.Tools.Core/Net/SocketClient.cs

@@ -0,0 +1,550 @@
+using System;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Runtime.Serialization;
+using System.Runtime.Serialization.Formatters.Binary;
+using System.Text;
+using System.Threading;
+using Masuit.Tools.Logging;
+
+namespace Masuit.Tools.Net
+{
+    /// <summary>
+    /// Socket客户端操作类
+    /// </summary>
+    public static class SocketClient
+    {
+        #region 私有字段
+
+        /// <summary>
+        /// 设置数据缓冲区大小 默认1024
+        /// </summary>
+        private static readonly int m_maxpacket = 1024 * 4;
+
+        #endregion
+
+        #region 服务器侦听
+
+        /// <summary>
+        /// 服务器侦听方法 返回null则说明没有链接上
+        /// </summary>
+        /// <returns>返回一个套接字(Socket)</returns>
+        public static Socket ListenerSocket(this TcpListener listener)
+        {
+            try
+            {
+                Socket socket = listener.AcceptSocket();
+                return socket;
+            }
+            catch (Exception e)
+            {
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// 服务器侦听方法 返回null则说明没有链接上
+        /// </summary>
+        /// <param name="listener">TCP监听对象</param>
+        /// <returns>返回一个网络流</returns>
+        public static NetworkStream ListenerStream(this TcpListener listener)
+        {
+            try
+            {
+                TcpClient client = listener.AcceptTcpClient();
+                return client.GetStream();
+            }
+            catch (Exception e)
+            {
+                return null;
+            }
+        }
+
+        #endregion
+
+        #region 客户端连接
+
+        /// <summary>
+        /// 从客户端连接获取socket对象
+        /// </summary>
+        /// <param name="tcpclient">TCP客户端</param>
+        /// <param name="ipendpoint">客户端节点</param>
+        /// <returns>客户端socket</returns>
+        public static Socket ConnectSocket(this TcpClient tcpclient, IPEndPoint ipendpoint)
+        {
+            try
+            {
+                tcpclient.Connect(ipendpoint);
+                return tcpclient.Client;
+            }
+            catch (Exception e)
+            {
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// 从客户端连接获取socket对象
+        /// </summary>
+        /// <param name="tcpclient">TCP客户端</param>
+        /// <param name="ipadd">IP地址</param>
+        /// <param name="port">端口号</param>
+        /// <returns>客户端socket</returns>
+        public static Socket ConnectSocket(this TcpClient tcpclient, IPAddress ipadd, int port)
+        {
+            try
+            {
+                tcpclient.Connect(ipadd, port);
+                return tcpclient.Client;
+            }
+            catch (Exception e)
+            {
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// 从客户端获取网络流对象
+        /// </summary>
+        /// <param name="tcpclient">TCP客户端</param>
+        /// <param name="ipendpoint">客户端节点</param>
+        /// <returns>客户端的网络流</returns>
+        public static NetworkStream ConnectStream(this TcpClient tcpclient, IPEndPoint ipendpoint)
+        {
+            try
+            {
+                tcpclient.Connect(ipendpoint);
+                return tcpclient.GetStream();
+            }
+            catch (Exception e)
+            {
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// 从客户端获取网络流对象
+        /// </summary>
+        /// <param name="tcpclient">TCP客户端</param>
+        /// <param name="ipadd">IP地址</param>
+        /// <param name="port">端口号</param>
+        /// <returns>客户端网络流对象</returns>
+        public static NetworkStream ConnectStream(this TcpClient tcpclient, IPAddress ipadd, int port)
+        {
+            try
+            {
+                tcpclient.Connect(ipadd, port);
+                return tcpclient.GetStream();
+            }
+            catch (Exception e)
+            {
+                return null;
+            }
+        }
+
+        #endregion
+
+        #region Socket接收数据
+
+        /// <summary>
+        /// 接受固定长度字符串
+        /// </summary>
+        /// <param name="socket">socket对象</param>
+        /// <param name="size">字符串长度</param>
+        /// <returns>字节数据</returns>
+        public static byte[] ReceiveFixData(this Socket socket, int size)
+        {
+            int offset = 0;
+            int recv = 0;
+            int dataleft = size;
+            byte[] msg = new byte[size];
+            while (dataleft > 0)
+            {
+                recv = socket.Receive(msg, offset, dataleft, 0);
+                if (recv == 0)
+                    break;
+                offset += recv;
+                dataleft -= recv;
+            }
+            return msg;
+        }
+
+        /// <summary>
+        /// 接收变长字符串
+        /// 为了处理粘包问题 ,每次发送数据时 包头(数据字节长度) + 正文
+        /// 这个发送小数据
+        /// 设置包头的字节为8,不能超过8位数的字节数组
+        /// </summary>
+        /// <param name="socket">客户端socket</param>
+        /// <returns>byte[]数组</returns>
+        public static byte[] ReceiveVarData(this Socket socket)
+        {
+            //每次接受数据时,接收固定长度的包头,包头长度为8
+            byte[] lengthbyte = ReceiveFixData(socket, 8);
+            //length得到字符长度 然后加工处理得到数字
+            int length = GetPacketLength(lengthbyte);
+            //得到正文
+            return ReceiveFixData(socket, length);
+        }
+
+        /// <summary>
+        /// 接收T类对象,反序列化
+        /// </summary>
+        /// <typeparam name="T">接收T类对象,T类必须是一个可序列化类</typeparam>
+        /// <param name="socket">客户端socket</param>
+        /// <returns>强类型对象</returns>
+        public static T ReceiveVarData<T>(this Socket socket)
+        {
+            //先接收包头长度 固定8个字节
+            byte[] lengthbyte = ReceiveFixData(socket, 8);
+            //得到字节长度
+            int length = GetPacketLength(lengthbyte);
+            byte[] bytecoll = new byte[m_maxpacket];
+            IFormatter format = new BinaryFormatter();
+            MemoryStream stream = new MemoryStream();
+            int offset = 0; //接收字节个数
+            int lastdata = length; //还剩下多少没有接收,初始大小等于实际大小
+            int receivedata = m_maxpacket; //每次接收大小
+            //循环接收
+            int mark = 0; //标记几次接收到的数据为0长度
+            while (true)
+            {
+                //剩下的字节数是否小于缓存大小
+                if (lastdata < m_maxpacket)
+                    receivedata = lastdata; //就只接收剩下的字节数
+                int count = socket.Receive(bytecoll, 0, receivedata, 0);
+                if (count > 0)
+                {
+                    stream.Write(bytecoll, 0, count);
+                    offset += count;
+                    lastdata -= count;
+                    mark = 0;
+                }
+                else
+                {
+                    mark++;
+                    if (mark == 10)
+                        break;
+                }
+                if (offset == length)
+                    break;
+            }
+            stream.Seek(0, SeekOrigin.Begin); //必须要这个 或者stream.Position = 0;
+            T t = (T)format.Deserialize(stream);
+            stream.Close();
+            return t;
+        }
+
+        /// <summary>
+        /// 在预先得到文件的文件名和大小
+        /// 调用此方法接收文件
+        /// </summary>
+        /// <param name="socket">socket服务端</param>
+        /// <param name="path">路径必须存在</param>
+        /// <param name="filename">文件名</param>
+        /// <param name="size">预先知道的文件大小</param>
+        /// <param name="progress">处理过程</param>
+        public static bool ReceiveFile(this Socket socket, string path, string filename, long size, Action<int> progress)
+        {
+            bool ret = false;
+            if (Directory.Exists(path))
+            {
+                //主要是防止有重名文件
+                string savepath = GetPath(path, filename); //得到文件路径
+                //缓冲区
+                byte[] file = new byte[m_maxpacket];
+                int count = 0; //每次接收的实际长度
+                int receivedata = m_maxpacket; //每次要接收的长度
+                long offset = 0; //循环接收的总长度
+                long lastdata = size; //剩余多少还没接收
+                int mark = 0;
+                using (FileStream fs = new FileStream(savepath, FileMode.OpenOrCreate, FileAccess.Write))
+                {
+                    if (size > 0)
+                        while (true)
+                        {
+                            if (lastdata < receivedata)
+                                receivedata = Convert.ToInt32(lastdata);
+                            count = socket.Receive(file, 0, receivedata, SocketFlags.None);
+                            if (count > 0)
+                            {
+                                fs.Write(file, 0, count);
+                                offset += count;
+                                lastdata -= count;
+                                mark = 0;
+                            }
+                            else
+                            {
+                                mark++; //连续5次接收为0字节 则跳出循环
+                                if (mark == 10)
+                                    break;
+                            }
+                            //接收进度
+                            if (progress != null)
+                                progress(Convert.ToInt32(Convert.ToDouble(offset) / Convert.ToDouble(size) * 100));
+                            //接收完毕
+                            if (offset == size)
+                            {
+                                ret = true;
+                                break;
+                            }
+                        }
+                    fs.Close();
+                }
+            }
+            return ret;
+        }
+
+        /// <summary>
+        /// 从socket服务端接收文件
+        /// </summary>
+        /// <param name="socket">socket服务端</param>
+        /// <param name="path">文件保存路径(必须存在)</param>
+        /// <param name="filename">文件名</param>
+        /// <param name="size">预先知道的文件大小</param>
+        /// <returns>处理结果</returns>
+        public static bool ReceiveFile(this Socket socket, string path, string filename, long size)
+        {
+            return ReceiveFile(socket, path, filename, size, null);
+        }
+
+        /// <summary>
+        /// 预先不知道文件名和文件大小 用此方法接收
+        /// 此方法对于的发送方法是SendFile()
+        /// </summary>
+        /// <param name="socket">socket服务端</param>
+        /// <param name="path">要保存的目录</param>
+        public static void ReceiveFile(this Socket socket, string path)
+        {
+            //得到包头信息字节数组 (文件名 + 文件大小 的字符串长度)
+            //取前8位
+            byte[] info_bt = ReceiveFixData(socket, 8);
+            //得到包头信息字符长度
+            int info_length = GetPacketLength(info_bt);
+            //提取包头信息,(文件名 + 文件大小 的字符串长度)
+            byte[] info = ReceiveFixData(socket, info_length);
+            //得到文件信息字符串 (文件名 + 文件大小)
+            string info_str = Encoding.UTF8.GetString(info);
+            string[] strs = info_str.Split('|');
+            string filename = strs[0]; //文件名
+            long length = Convert.ToInt64(strs[1]); //文件大小
+            //开始接收文件
+            ReceiveFile(socket, path, filename, length);
+        }
+
+        private static int GetPacketLength(byte[] length)
+        {
+            string str = Encoding.UTF8.GetString(length);
+            str = str.TrimEnd('*');
+            ; //("*", "");
+            int _length = 0;
+            if (int.TryParse(str, out _length))
+                return _length;
+            return 0;
+        }
+
+        private static int i;
+
+        private static string markPath = string.Empty;
+        /// <summary>
+        /// 得到文件路径(防止有文件名重复)
+        ///  如:aaa.txt已经在directory目录下存在,则会得到文件aaa(1).txt
+        /// </summary>
+        /// <param name="directory">目录名</param>
+        /// <param name="file">文件名</param>
+        /// <returns>文件路径</returns>
+
+        public static string GetPath(string directory, string file)
+        {
+            if (markPath == string.Empty)
+                markPath = Path.Combine(directory, file);
+            string path = Path.Combine(directory, file);
+            if (File.Exists(path))
+            {
+                i++;
+                string filename = Path.GetFileNameWithoutExtension(markPath) + "(" + i + ")";
+                string extension = Path.GetExtension(markPath);
+                return GetPath(directory, filename + extension);
+            }
+            i = 0;
+            markPath = string.Empty;
+            return path;
+        }
+
+        #endregion
+
+        #region Socket发送数据
+
+        /// <summary>
+        /// 发送固定长度消息
+        /// 发送字节数不能大于int型最大值
+        /// </summary>
+        /// <param name="socket">源socket</param>
+        /// <param name="msg">消息的字节数组</param>
+        /// <returns>返回发送字节个数</returns>
+        public static int SendFixData(this Socket socket, byte[] msg)
+        {
+            int size = msg.Length; //要发送字节长度
+            int offset = 0; //已经发送长度
+            int dataleft = size; //剩下字符
+            int senddata = m_maxpacket; //每次发送大小
+            while (true)
+            {
+                //如过剩下的字节数 小于 每次发送字节数
+                if (dataleft < senddata)
+                    senddata = dataleft;
+                int count = socket.Send(msg, offset, senddata, SocketFlags.None);
+                offset += count;
+                dataleft -= count;
+                if (offset == size)
+                    break;
+            }
+            return offset;
+        }
+
+        /// <summary>
+        /// 发送变长信息 格式 包头(包头占8位) + 正文
+        /// </summary>
+        /// <param name="socket">发送方socket对象</param>
+        /// <param name="contact">发送文本</param>
+        /// <returns>发送的数据内容长度</returns>
+        public static int SendVarData(this Socket socket, string contact)
+        {
+            //得到字符长度
+            int size = Encoding.UTF8.GetBytes(contact).Length;
+            //包头字符
+            string length = GetSendPacketLengthStr(size);
+            //包头 + 正文
+            byte[] sendbyte = Encoding.UTF8.GetBytes(length + contact);
+            //发送
+            return SendFixData(socket, sendbyte);
+        }
+
+        /// <summary>
+        /// 发送变成信息
+        /// </summary>
+        /// <param name="socket">发送方socket对象</param>
+        /// <param name="bytes">消息的 字节数组</param>
+        /// <returns>消息长度</returns>
+        public static int SendVarData(this Socket socket, byte[] bytes)
+        {
+            //得到包头字节
+            int size = bytes.Length;
+            string length = GetSendPacketLengthStr(size);
+            byte[] lengthbyte = Encoding.UTF8.GetBytes(length);
+            //发送包头
+            SendFixData(socket, lengthbyte); //因为不知道正文是什么编码所以没有合并
+            //发送正文
+            return SendFixData(socket, bytes);
+        }
+
+        /// <summary>
+        /// 发送T类型对象,序列化
+        /// </summary>
+        /// <typeparam name="T">T类型</typeparam>
+        /// <param name="socket">发送方的socket对象</param>
+        /// <param name="obj">T类型对象,必须是可序列化的</param>
+        /// <returns>消息长度</returns>
+        public static int SendSerializeObject<T>(this Socket socket, T obj)
+        {
+            byte[] bytes = SerializeObject(obj);
+            return SendVarData(socket, bytes);
+        }
+
+        /// <summary>
+        /// 发送文件
+        /// </summary>
+        /// <param name="socket">socket对象</param>
+        /// <param name="path">文件路径</param>
+        /// <param name="issend">是否发送文件(头)信息,如果当前知道文件[大小,名称]则为false</param>
+        /// <param name="progress">处理过程</param>
+        /// <returns>处理结果</returns>
+        public static bool SendFile(this Socket socket, string path, bool issend, Action<int> progress)
+        {
+            bool ret = false;
+            if (File.Exists(path))
+            {
+                FileInfo fileinfo = new FileInfo(path);
+                string filename = fileinfo.Name;
+                long length = fileinfo.Length;
+                //发送文件信息
+                if (issend)
+                    SendVarData(socket, filename + "|" + length);
+                //发送文件
+                long offset = 0;
+                byte[] b = new byte[m_maxpacket];
+                int mark = 0;
+                using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
+                {
+                    int senddata = b.Length;
+                    long i = length;
+                    //循环读取发送
+                    while (true)
+                    {
+                        int count = fs.Read(b, 0, senddata);
+                        if (count > 0)
+                        {
+                            socket.Send(b, 0, count, SocketFlags.None);
+                            offset += count;
+                            mark = 0;
+                        }
+                        else
+                        {
+                            mark++;
+                            if (mark == 10)
+                                break;
+                        }
+                        if (progress != null)
+                            progress(Convert.ToInt32(Convert.ToDouble(offset) / Convert.ToDouble(length) * 100));
+                        if (offset == length)
+                            break;
+                        Thread.Sleep(50); //设置等待时间,以免粘包
+                    }
+                }
+            }
+            return ret;
+        }
+
+        /// <summary>
+        /// 发送文件,不需要进度信息
+        /// </summary>
+        /// <param name="socket">socket对象</param>
+        /// <param name="path">文件路径</param>
+        /// <param name="issend">是否发生(头)信息</param>
+        /// <returns>处理结果</returns>
+        public static bool SendFile(this Socket socket, string path, bool issend)
+        {
+            return SendFile(socket, path, issend, null);
+        }
+
+        /// <summary>
+        /// 发送文件,不需要进度信息和(头)信息
+        /// </summary>
+        /// <param name="socket">socket对象</param>
+        /// <param name="path">文件路径</param>
+        /// <returns>处理结果</returns>
+        public static bool SendFile(this Socket socket, string path)
+        {
+            return SendFile(socket, path, false, null);
+        }
+
+        private static byte[] SerializeObject(object obj)
+        {
+            IFormatter format = new BinaryFormatter();
+            MemoryStream stream = new MemoryStream();
+            format.Serialize(stream, obj);
+            byte[] ret = stream.ToArray();
+            stream.Close();
+            return ret;
+        }
+
+        private static string GetSendPacketLengthStr(int size)
+        {
+            string length = size + "********"; //得到size的长度
+            return length.Substring(0, 8); //截取前前8位
+        }
+
+        #endregion
+    }
+}

+ 145 - 0
Masuit.Tools.Core/NoSQL/RedisConnectionHelp.cs

@@ -0,0 +1,145 @@
+using System;
+using System.Collections.Concurrent;
+using System.Configuration;
+using StackExchange.Redis;
+
+namespace Masuit.Tools.NoSQL
+{
+    /// <summary>
+    /// ConnectionMultiplexer对象管理帮助类
+    /// </summary>
+    public static class RedisConnectionHelp
+    {
+        /// <summary>
+        /// 系统自定义Key前缀
+        /// </summary>
+        public static readonly string SysCustomKey = ConfigurationManager.AppSettings["redisKey"] ?? "";
+
+        /// <summary>
+        /// Redis服务器连接字符串,在config配置文件中的ConnectionStrings节下配置,name固定为RedisHosts,值的格式:127.0.0.1:6379,allowadmin=true,如:<br/>
+        /// &lt;connectionStrings&gt;<br/>
+        ///      &lt;add name = "RedisHosts" connectionString="127.0.0.1:6379,allowadmin=true"/&gt;<br/>
+        /// &lt;/connectionStrings&gt;
+        /// </summary>
+        public static readonly string RedisConnectionString = ConfigurationManager.ConnectionStrings["RedisHosts"]?.ConnectionString ?? "127.0.0.1:6379,allowadmin=true";
+
+        private static readonly object Locker = new object();
+        private static ConnectionMultiplexer _instance;
+        private static readonly ConcurrentDictionary<string, ConnectionMultiplexer> ConnectionCache = new ConcurrentDictionary<string, ConnectionMultiplexer>();
+
+        /// <summary>
+        /// 单例获取
+        /// </summary>
+        public static ConnectionMultiplexer Instance
+        {
+            get
+            {
+                if (_instance == null)
+                {
+                    lock (Locker)
+                    {
+                        if (_instance == null || !_instance.IsConnected)
+                        {
+                            _instance = GetManager();
+                        }
+                    }
+                }
+                return _instance;
+            }
+        }
+
+        /// <summary>
+        /// 缓存获取
+        /// </summary>
+        /// <param name="connectionString">连接字符串</param>
+        /// <returns>连接对象</returns>
+        public static ConnectionMultiplexer GetConnectionMultiplexer(string connectionString)
+        {
+            if (!ConnectionCache.ContainsKey(connectionString))
+            {
+                ConnectionCache[connectionString] = GetManager(connectionString);
+            }
+            return ConnectionCache[connectionString];
+        }
+
+        private static ConnectionMultiplexer GetManager(string connectionString = null)
+        {
+            connectionString = connectionString ?? RedisConnectionString;
+            var connect = ConnectionMultiplexer.Connect(connectionString);
+
+            //注册如下事件
+            connect.ConnectionFailed += MuxerConnectionFailed;
+            connect.ConnectionRestored += MuxerConnectionRestored;
+            connect.ErrorMessage += MuxerErrorMessage;
+            connect.ConfigurationChanged += MuxerConfigurationChanged;
+            connect.HashSlotMoved += MuxerHashSlotMoved;
+            connect.InternalError += MuxerInternalError;
+
+            return connect;
+        }
+
+        #region 事件
+
+        /// <summary>
+        /// 配置更改时
+        /// </summary>
+        /// <param name="sender">触发者</param>
+        /// <param name="e">事件参数</param>
+        private static void MuxerConfigurationChanged(object sender, EndPointEventArgs e)
+        {
+            Console.WriteLine("Configuration changed: " + e.EndPoint);
+        }
+
+        /// <summary>
+        /// 发生错误时
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private static void MuxerErrorMessage(object sender, RedisErrorEventArgs e)
+        {
+            Console.WriteLine("ErrorMessage: " + e.Message);
+        }
+
+        /// <summary>
+        /// 重新建立连接之前的错误
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private static void MuxerConnectionRestored(object sender, ConnectionFailedEventArgs e)
+        {
+            Console.WriteLine("ConnectionRestored: " + e.EndPoint);
+        }
+
+        /// <summary>
+        /// 连接失败 , 如果重新连接成功你将不会收到这个通知
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private static void MuxerConnectionFailed(object sender, ConnectionFailedEventArgs e)
+        {
+            Console.WriteLine("重新连接:Endpoint failed: " + e.EndPoint + ", " + e.FailureType + (e.Exception == null ? "" : (", " + e.Exception.Message)));
+        }
+
+        /// <summary>
+        /// 更改集群
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private static void MuxerHashSlotMoved(object sender, HashSlotMovedEventArgs e)
+        {
+            Console.WriteLine("HashSlotMoved:NewEndPoint" + e.NewEndPoint + ", OldEndPoint" + e.OldEndPoint);
+        }
+
+        /// <summary>
+        /// redis类库错误
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private static void MuxerInternalError(object sender, InternalErrorEventArgs e)
+        {
+            Console.WriteLine("InternalError:Message" + e.Exception.Message);
+        }
+
+        #endregion 事件
+    }
+}

+ 990 - 0
Masuit.Tools.Core/NoSQL/RedisHelper.cs

@@ -0,0 +1,990 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+using StackExchange.Redis;
+
+namespace Masuit.Tools.NoSQL
+{
+    /// <summary>
+    /// Redis操作
+    /// </summary>
+    public class RedisHelper
+    {
+        private int DbNum { get; }
+        private readonly ConnectionMultiplexer _conn;
+        /// <summary>
+        /// 自定义键
+        /// </summary>
+        public string CustomKey;
+
+        #region 构造函数
+
+        /// <summary>
+        /// 构造函数,使用该构造函数需要先在config中配置链接字符串,连接字符串在config配置文件中的ConnectionStrings节下配置,name固定为RedisHosts,值的格式:127.0.0.1:6379,allowadmin=true,若未正确配置,将按默认值“127.0.0.1:6379,allowadmin=true”进行操作,如:<br/>
+        /// &lt;connectionStrings&gt;<br/>
+        ///      &lt;add name = "RedisHosts" connectionString="127.0.0.1:6379,allowadmin=true"/&gt;<br/>
+        /// &lt;/connectionStrings&gt;
+        /// </summary>
+        /// <param name="dbNum">数据库编号</param>
+        public RedisHelper(int dbNum = 0) : this(dbNum, null)
+        {
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="dbNum">数据库的编号</param>
+        /// <param name="readWriteHosts">Redis服务器连接字符串,格式:127.0.0.1:6379,allowadmin=true</param>
+        public RedisHelper(int dbNum, string readWriteHosts)
+        {
+            DbNum = dbNum;
+            _conn = string.IsNullOrWhiteSpace(readWriteHosts) ? RedisConnectionHelp.Instance : RedisConnectionHelp.GetConnectionMultiplexer(readWriteHosts);
+        }
+
+        #endregion 构造函数
+
+        #region String
+
+        #region 同步方法
+
+        /// <summary>
+        /// 保存单个key value
+        /// </summary>
+        /// <param name="key">Redis Key</param>
+        /// <param name="value">保存的值</param>
+        /// <param name="expiry">过期时间</param>
+        /// <returns>是否保存成功</returns>
+        public bool SetString(string key, string value, TimeSpan? expiry = default(TimeSpan?))
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.StringSet(key, value, expiry));
+        }
+
+        /// <summary>
+        /// 保存多个key value
+        /// </summary>
+        /// <param name="keyValues">键值对</param>
+        /// <returns>是否保存成功</returns>
+        public bool SetString(List<KeyValuePair<RedisKey, RedisValue>> keyValues)
+        {
+            List<KeyValuePair<RedisKey, RedisValue>> newkeyValues =
+                keyValues.Select(p => new KeyValuePair<RedisKey, RedisValue>(AddSysCustomKey(p.Key), p.Value)).ToList();
+            return Do(db => db.StringSet(newkeyValues.ToArray()));
+        }
+
+        /// <summary>
+        /// 保存一个对象
+        /// </summary>
+        /// <typeparam name="T">对象类型</typeparam>
+        /// <param name="key">键</param>
+        /// <param name="obj">值</param>
+        /// <param name="expiry">过期时间</param>
+        /// <returns>是否保存成功</returns>
+        public bool SetString<T>(string key, T obj, TimeSpan? expiry = default(TimeSpan?))
+        {
+            key = AddSysCustomKey(key);
+            string json = ConvertJson(obj);
+            return Do(db => db.StringSet(key, json, expiry));
+        }
+
+        /// <summary>
+        /// 获取单个key的值
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <returns>值</returns>
+        public string GetString(string key)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.StringGet(key));
+        }
+
+        /// <summary>
+        /// 获取多个Key
+        /// </summary>
+        /// <param name="listKey">键集合</param>
+        /// <returns>值集合</returns>
+        public RedisValue[] GetString(List<string> listKey)
+        {
+            List<string> newKeys = listKey.Select(AddSysCustomKey).ToList();
+            return Do(db => db.StringGet(ConvertRedisKeys(newKeys)));
+        }
+
+        /// <summary>
+        /// 获取一个key的对象
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <returns>实例对象</returns>
+        public T GetString<T>(string key)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => ConvertObj<T>(db.StringGet(key)));
+        }
+
+        /// <summary>
+        /// 为数字增长val
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="val">可以为负</param>
+        /// <returns>增长后的值</returns>
+        public double StringIncrement(string key, double val = 1)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.StringIncrement(key, val));
+        }
+
+        /// <summary>
+        /// 为数字减少val
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="val">可以为负</param>
+        /// <returns>减少后的值</returns>
+        public double StringDecrement(string key, double val = 1)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.StringDecrement(key, val));
+        }
+
+        #endregion 同步方法
+
+        #region 异步方法
+
+        /// <summary>
+        /// 保存单个key value
+        /// </summary>
+        /// <param name="key">Redis Key</param>
+        /// <param name="value">保存的值</param>
+        /// <param name="expiry">过期时间</param>
+        /// <returns>是否保存成功</returns>
+        public async Task<bool> SetStringAsync(string key, string value, TimeSpan? expiry = default(TimeSpan?))
+        {
+            key = AddSysCustomKey(key);
+            return await Do(db => db.StringSetAsync(key, value, expiry));
+        }
+
+        /// <summary>
+        /// 保存多个key value
+        /// </summary>
+        /// <param name="keyValues">键值对</param>
+        /// <returns>是否保存成功</returns>
+        public async Task<bool> SetStringAsync(List<KeyValuePair<RedisKey, RedisValue>> keyValues)
+        {
+            List<KeyValuePair<RedisKey, RedisValue>> newkeyValues =
+                keyValues.Select(p => new KeyValuePair<RedisKey, RedisValue>(AddSysCustomKey(p.Key), p.Value)).ToList();
+            return await Do(db => db.StringSetAsync(newkeyValues.ToArray()));
+        }
+
+        /// <summary>
+        /// 保存一个对象
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <param name="obj">需要被缓存的对象</param>
+        /// <param name="expiry">过期时间</param>
+        /// <returns>是否保存成功</returns>
+        public async Task<bool> SetStringAsync<T>(string key, T obj, TimeSpan? expiry = default(TimeSpan?))
+        {
+            key = AddSysCustomKey(key);
+            string json = ConvertJson(obj);
+            return await Do(db => db.StringSetAsync(key, json, expiry));
+        }
+
+        /// <summary>
+        /// 获取单个key的值
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <returns>值</returns>
+        public async Task<string> GetStringAsync(string key)
+        {
+            key = AddSysCustomKey(key);
+            return await Do(db => db.StringGetAsync(key));
+        }
+
+        /// <summary>
+        /// 获取多个Key
+        /// </summary>
+        /// <param name="listKey">键集合</param>
+        /// <returns>值集合</returns>
+        public Task<RedisValue[]> GetStringAsync(List<string> listKey)
+        {
+            List<string> newKeys = listKey.Select(AddSysCustomKey).ToList();
+            return Do(db => db.StringGetAsync(ConvertRedisKeys(newKeys)));
+        }
+
+        /// <summary>
+        /// 获取一个key的对象
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <returns>实例对象</returns>
+        public async Task<T> GetStringAsync<T>(string key)
+        {
+            key = AddSysCustomKey(key);
+            string result = await Do(db => db.StringGetAsync(key));
+            return ConvertObj<T>(result);
+        }
+
+        /// <summary>
+        /// 为数字增长val
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="val">可以为负</param>
+        /// <returns>增长后的值</returns>
+        public Task<double> IncrementStringAsync(string key, double val = 1)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.StringIncrementAsync(key, val));
+        }
+
+        /// <summary>
+        /// 为数字减少val
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="val">可以为负</param>
+        /// <returns>减少后的值</returns>
+        public Task<double> DecrementStringAsync(string key, double val = 1)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.StringDecrementAsync(key, val));
+        }
+
+        #endregion 异步方法
+
+        #endregion String
+
+        #region Hash
+
+        #region 同步方法
+
+        /// <summary>
+        /// 判断某个数据是否已经被缓存
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="dataKey">对象的字段</param>
+        /// <returns>是否缓存成功</returns>
+        public bool HashExists(string key, string dataKey)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.HashExists(key, dataKey));
+        }
+
+        /// <summary>
+        /// 存储数据到hash表
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <param name="dataKey">对象的字段</param>
+        /// <param name="t">对象实例</param>
+        /// <returns>是否存储成功</returns>
+        public bool SetHash<T>(string key, string dataKey, T t)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db =>
+            {
+                string json = ConvertJson(t);
+                return db.HashSet(key, dataKey, json);
+            });
+        }
+
+        /// <summary>
+        /// 移除hash中的某值
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="dataKey">对象的字段</param>
+        /// <returns>是否移除成功</returns>
+        public bool DeleteHash(string key, string dataKey)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.HashDelete(key, dataKey));
+        }
+
+        /// <summary>
+        /// 移除hash中的多个值
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="dataKeys">对象的字段集合</param>
+        /// <returns>数量</returns>
+        public long DeleteHash(string key, List<RedisValue> dataKeys)
+        {
+            key = AddSysCustomKey(key);
+            //List<RedisValue> dataKeys1 = new List<RedisValue>() {"1","2"};
+            return Do(db => db.HashDelete(key, dataKeys.ToArray()));
+        }
+
+        /// <summary>
+        /// 从hash表获取数据
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <param name="dataKey">对象的字段</param>
+        /// <returns>对象实例</returns>
+        public T GetHash<T>(string key, string dataKey)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db =>
+            {
+                string value = db.HashGet(key, dataKey);
+                return ConvertObj<T>(value);
+            });
+        }
+
+        /// <summary>
+        /// 为数字增长val
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="dataKey">对象的字段</param>
+        /// <param name="val">可以为负</param>
+        /// <returns>增长后的值</returns>
+        public double IncrementHash(string key, string dataKey, double val = 1)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.HashIncrement(key, dataKey, val));
+        }
+
+        /// <summary>
+        /// 为数字减少val
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="dataKey">对象的字段</param>
+        /// <param name="val">可以为负</param>
+        /// <returns>减少后的值</returns>
+        public double DecrementHash(string key, string dataKey, double val = 1)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.HashDecrement(key, dataKey, val));
+        }
+
+        /// <summary>
+        /// 获取hashkey所有Redis key
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <returns>数据集合</returns>
+        public List<T> HashKeys<T>(string key)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db =>
+            {
+                RedisValue[] values = db.HashKeys(key);
+                return ConvetList<T>(values);
+            });
+        }
+
+        #endregion 同步方法
+
+        #region 异步方法
+
+        /// <summary>
+        /// 判断某个数据是否已经被缓存
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="dataKey">对象的字段</param>
+        /// <returns>是否缓存成功</returns>
+        public Task<bool> ExistsHashAsync(string key, string dataKey)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.HashExistsAsync(key, dataKey));
+        }
+
+        /// <summary>
+        /// 存储数据到hash表
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <param name="dataKey">对象的字段</param>
+        /// <param name="t">对象实例</param>
+        /// <returns>是否存储成功</returns>
+        public Task<bool> SetHashAsync<T>(string key, string dataKey, T t)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db =>
+            {
+                string json = ConvertJson(t);
+                return db.HashSetAsync(key, dataKey, json);
+            });
+        }
+
+        /// <summary>
+        /// 移除hash中的某值
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="dataKey">对象的字段</param>
+        /// <returns>是否移除成功</returns>
+        public Task<bool> DeleteHashAsync(string key, string dataKey)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.HashDeleteAsync(key, dataKey));
+        }
+
+        /// <summary>
+        /// 移除hash中的多个值
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="dataKeys">对象的字段集合</param>
+        /// <returns>数量</returns>
+        public Task<long> DeleteHashAsync(string key, List<RedisValue> dataKeys)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.HashDeleteAsync(key, dataKeys.ToArray()));
+        }
+
+        /// <summary>
+        /// 从hash表获取数据
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <param name="dataKey">对象的字段</param>
+        /// <returns>对象实例</returns>
+        public async Task<T> GetHashAsync<T>(string key, string dataKey)
+        {
+            key = AddSysCustomKey(key);
+            string value = await Do(db => db.HashGetAsync(key, dataKey));
+            return ConvertObj<T>(value);
+        }
+
+        /// <summary>
+        /// 为数字增长val
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="dataKey">对象的字段</param>
+        /// <param name="val">可以为负</param>
+        /// <returns>增长后的值</returns>
+        public Task<double> IncrementHashAsync(string key, string dataKey, double val = 1)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.HashIncrementAsync(key, dataKey, val));
+        }
+
+        /// <summary>
+        /// 为数字减少val
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="dataKey">对象的字段</param>
+        /// <param name="val">可以为负</param>
+        /// <returns>减少后的值</returns>
+        public Task<double> DecrementHashAsync(string key, string dataKey, double val = 1)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.HashDecrementAsync(key, dataKey, val));
+        }
+
+        /// <summary>
+        /// 获取hashkey所有Redis key
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <returns>数据集合</returns>
+        public async Task<List<T>> HashKeysAsync<T>(string key)
+        {
+            key = AddSysCustomKey(key);
+            RedisValue[] values = await Do(db => db.HashKeysAsync(key));
+            return ConvetList<T>(values);
+        }
+
+        #endregion 异步方法
+
+        #endregion Hash
+
+        #region List
+
+        #region 同步方法
+
+        /// <summary>
+        /// 移除指定ListId的内部List的值
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <param name="value">值</param>
+        public void RemoveList<T>(string key, T value)
+        {
+            key = AddSysCustomKey(key);
+            Do(db => db.ListRemove(key, ConvertJson(value)));
+        }
+
+        /// <summary>
+        /// 获取指定key的List
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <returns>数据集</returns>
+        public List<T> ListRange<T>(string key)
+        {
+            key = AddSysCustomKey(key);
+            return Do(redis =>
+            {
+                var values = redis.ListRange(key);
+                return ConvetList<T>(values);
+            });
+        }
+
+        /// <summary>
+        /// 入队
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <param name="value">值</param>
+        public void ListRightPush<T>(string key, T value)
+        {
+            key = AddSysCustomKey(key);
+            Do(db => db.ListRightPush(key, ConvertJson(value)));
+        }
+
+        /// <summary>
+        /// 出队
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <returns>值</returns>
+        public T ListRightPop<T>(string key)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db =>
+             {
+                 var value = db.ListRightPop(key);
+                 return ConvertObj<T>(value);
+             });
+        }
+
+        /// <summary>
+        /// 入栈
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <param name="value">值</param>
+        public void ListLeftPush<T>(string key, T value)
+        {
+            key = AddSysCustomKey(key);
+            Do(db => db.ListLeftPush(key, ConvertJson(value)));
+        }
+
+        /// <summary>
+        /// 出栈
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <returns>对象实例</returns>
+        public T ListLeftPop<T>(string key)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db =>
+            {
+                var value = db.ListLeftPop(key);
+                return ConvertObj<T>(value);
+            });
+        }
+
+        /// <summary>
+        /// 获取集合中的数量
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <returns>数量</returns>
+        public long ListLength(string key)
+        {
+            key = AddSysCustomKey(key);
+            return Do(redis => redis.ListLength(key));
+        }
+
+        #endregion 同步方法
+
+        #region 异步方法
+
+        /// <summary>
+        /// 移除指定ListId的内部List的值
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="value">值</param>
+        public Task<long> RemoveListAsync<T>(string key, T value)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.ListRemoveAsync(key, ConvertJson(value)));
+        }
+
+        /// <summary>
+        /// 获取指定key的List
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <returns>数据集合</returns>
+        public async Task<List<T>> ListRangeAsync<T>(string key)
+        {
+            key = AddSysCustomKey(key);
+            var values = await Do(redis => redis.ListRangeAsync(key));
+            return ConvetList<T>(values);
+        }
+
+        /// <summary>
+        /// 入队
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <param name="value">值</param>
+        public async Task<long> ListRightPushAsync<T>(string key, T value)
+        {
+            key = AddSysCustomKey(key);
+            return await Do(db => db.ListRightPushAsync(key, ConvertJson(value)));
+        }
+
+        /// <summary>
+        /// 出队
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <returns>对象实例</returns>
+        public async Task<T> ListRightPopAsync<T>(string key)
+        {
+            key = AddSysCustomKey(key);
+            var value = await Do(db => db.ListRightPopAsync(key));
+            return ConvertObj<T>(value);
+        }
+
+        /// <summary>
+        /// 入栈
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <param name="value">值</param>
+        public async Task<long> ListLeftPushAsync<T>(string key, T value)
+        {
+            key = AddSysCustomKey(key);
+            return await Do(db => db.ListLeftPushAsync(key, ConvertJson(value)));
+        }
+
+        /// <summary>
+        /// 出栈
+        /// </summary>
+        /// <typeparam name="T">数据类型</typeparam>
+        /// <param name="key">键</param>
+        /// <returns>实例对象</returns>
+        public async Task<T> ListLeftPopAsync<T>(string key)
+        {
+            key = AddSysCustomKey(key);
+            var value = await Do(db => db.ListLeftPopAsync(key));
+            return ConvertObj<T>(value);
+        }
+
+        /// <summary>
+        /// 获取集合中的数量
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <returns>数量</returns>
+        public async Task<long> ListLengthAsync(string key)
+        {
+            key = AddSysCustomKey(key);
+            return await Do(redis => redis.ListLengthAsync(key));
+        }
+
+        #endregion 异步方法
+
+        #endregion List
+
+        #region SortedSet 有序集合
+
+        #region 同步方法
+
+        /// <summary>
+        /// 添加
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="value">值</param>
+        /// <param name="score">排序号</param>
+        public bool AddSortedSet<T>(string key, T value, double score)
+        {
+            key = AddSysCustomKey(key);
+            return Do(redis => redis.SortedSetAdd(key, ConvertJson<T>(value), score));
+        }
+
+        /// <summary>
+        /// 删除
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="value">值</param>
+        public bool RemoveSortedSet<T>(string key, T value)
+        {
+            key = AddSysCustomKey(key);
+            return Do(redis => redis.SortedSetRemove(key, ConvertJson(value)));
+        }
+
+        /// <summary>
+        /// 获取全部
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <returns>数据集合</returns>
+        public List<T> SetRangeSortedByRank<T>(string key)
+        {
+            key = AddSysCustomKey(key);
+            return Do(redis =>
+            {
+                var values = redis.SortedSetRangeByRank(key);
+                return ConvetList<T>(values);
+            });
+        }
+
+        /// <summary>
+        /// 获取集合中的数量
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <returns>数量</returns>
+        public long SetSortedLength(string key)
+        {
+            key = AddSysCustomKey(key);
+            return Do(redis => redis.SortedSetLength(key));
+        }
+
+        #endregion 同步方法
+
+        #region 异步方法
+
+        /// <summary>
+        /// 添加
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="value">值</param>
+        /// <param name="score">排序号</param>
+        public async Task<bool> SortedSetAddAsync<T>(string key, T value, double score)
+        {
+            key = AddSysCustomKey(key);
+            return await Do(redis => redis.SortedSetAddAsync(key, ConvertJson<T>(value), score));
+        }
+
+        /// <summary>
+        /// 删除
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="value">值</param>
+        public async Task<bool> SortedSetRemoveAsync<T>(string key, T value)
+        {
+            key = AddSysCustomKey(key);
+            return await Do(redis => redis.SortedSetRemoveAsync(key, ConvertJson(value)));
+        }
+
+        /// <summary>
+        /// 获取全部
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <returns>数据集合</returns>
+        public async Task<List<T>> SortedSetRangeByRankAsync<T>(string key)
+        {
+            key = AddSysCustomKey(key);
+            var values = await Do(redis => redis.SortedSetRangeByRankAsync(key));
+            return ConvetList<T>(values);
+        }
+
+        /// <summary>
+        /// 获取集合中的数量
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <returns>数量</returns>
+        public async Task<long> SortedSetLengthAsync(string key)
+        {
+            key = AddSysCustomKey(key);
+            return await Do(redis => redis.SortedSetLengthAsync(key));
+        }
+
+        #endregion 异步方法
+
+        #endregion SortedSet 有序集合
+
+        #region key
+
+        /// <summary>
+        /// 删除单个key
+        /// </summary>
+        /// <param name="key">redis key</param>
+        /// <returns>是否删除成功</returns>
+        public bool DeleteKey(string key)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.KeyDelete(key));
+        }
+
+        /// <summary>
+        /// 删除多个key
+        /// </summary>
+        /// <param name="keys">rediskey</param>
+        /// <returns>成功删除的个数</returns>
+        public long DeleteKey(List<string> keys)
+        {
+            List<string> newKeys = keys.Select(AddSysCustomKey).ToList();
+            return Do(db => db.KeyDelete(ConvertRedisKeys(newKeys)));
+        }
+
+        /// <summary>
+        /// 判断key是否存储
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <returns>是否存储成功</returns>
+        public bool KeyExists(string key)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.KeyExists(key));
+        }
+
+        /// <summary>
+        /// 重新命名key
+        /// </summary>
+        /// <param name="key">旧的键</param>
+        /// <param name="newKey">新的键</param>
+        /// <returns>处理结果</returns>
+        public bool RenameKey(string key, string newKey)
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.KeyRename(key, newKey));
+        }
+
+        /// <summary>
+        /// 设置Key的过期时间
+        /// </summary>
+        /// <param name="key">键</param>
+        /// <param name="expiry">过期时间</param>
+        /// <returns>处理结果</returns>
+        public bool Expire(string key, TimeSpan? expiry = default(TimeSpan?))
+        {
+            key = AddSysCustomKey(key);
+            return Do(db => db.KeyExpire(key, expiry));
+        }
+
+        #endregion key
+
+        #region 发布订阅
+
+        /// <summary>
+        /// Redis发布订阅  订阅
+        /// </summary>
+        /// <param name="subChannel">订阅频道</param>
+        /// <param name="handler">处理过程</param>
+        public void Subscribe(string subChannel, Action<RedisChannel, RedisValue> handler = null)
+        {
+            ISubscriber sub = _conn.GetSubscriber();
+            sub.Subscribe(subChannel, (channel, message) =>
+            {
+                if (handler == null)
+                {
+                    Console.WriteLine(subChannel + " 订阅收到消息:" + message);
+                }
+                else
+                {
+                    handler(channel, message);
+                }
+            });
+        }
+
+        /// <summary>
+        /// Redis发布订阅  发布
+        /// </summary>
+        /// <typeparam name="T">消息对象</typeparam>
+        /// <param name="channel">发布频道</param>
+        /// <param name="msg">消息</param>
+        /// <returns>消息的数量</returns>
+        public long Publish<T>(string channel, T msg)
+        {
+            ISubscriber sub = _conn.GetSubscriber();
+            return sub.Publish(channel, ConvertJson(msg));
+        }
+
+        /// <summary>
+        /// Redis发布订阅  取消订阅
+        /// </summary>
+        /// <param name="channel">频道</param>
+        public void Unsubscribe(string channel)
+        {
+            ISubscriber sub = _conn.GetSubscriber();
+            sub.Unsubscribe(channel);
+        }
+
+        /// <summary>
+        /// Redis发布订阅  取消全部订阅
+        /// </summary>
+        public void UnsubscribeAll()
+        {
+            ISubscriber sub = _conn.GetSubscriber();
+            sub.UnsubscribeAll();
+        }
+
+        #endregion 发布订阅
+
+        #region 其他
+
+        /// <summary>
+        /// 创建一个事务
+        /// </summary>
+        /// <returns>事务对象</returns>
+        public ITransaction CreateTransaction()
+        {
+            return GetDatabase().CreateTransaction();
+        }
+
+        /// <summary>
+        /// 获得一个数据库实例
+        /// </summary>
+        /// <returns>数据库实例</returns>
+        public IDatabase GetDatabase()
+        {
+            return _conn.GetDatabase(DbNum);
+        }
+
+        /// <summary>
+        /// 获得一个服务器实例
+        /// </summary>
+        /// <param name="hostAndPort">服务器地址</param>
+        /// <returns>服务器实例</returns>
+        public IServer GetServer(string hostAndPort)
+        {
+            return _conn.GetServer(hostAndPort);
+        }
+
+        /// <summary>
+        /// 设置前缀
+        /// </summary>
+        /// <param name="customKey">前缀</param>
+        public void SetSysCustomKey(string customKey)
+        {
+            CustomKey = customKey;
+        }
+
+        #endregion 其他
+
+        #region 辅助方法
+
+        private string AddSysCustomKey(string oldKey)
+        {
+            var prefixKey = CustomKey ?? RedisConnectionHelp.SysCustomKey;
+            return prefixKey + oldKey;
+        }
+
+        private T Do<T>(Func<IDatabase, T> func)
+        {
+            var database = _conn.GetDatabase(DbNum);
+            return func(database);
+        }
+
+        private string ConvertJson<T>(T value)
+        {
+            return JsonConvert.SerializeObject(value);
+        }
+
+        private T ConvertObj<T>(RedisValue value)
+        {
+            return JsonConvert.DeserializeObject<T>(value);
+        }
+
+        private List<T> ConvetList<T>(RedisValue[] values)
+        {
+            List<T> result = new List<T>();
+            foreach (var item in values)
+            {
+                var model = ConvertObj<T>(item);
+                result.Add(model);
+            }
+            return result;
+        }
+
+        private RedisKey[] ConvertRedisKeys(List<string> redisKeys)
+        {
+            return redisKeys.Select(redisKey => (RedisKey)redisKey).ToArray();
+        }
+
+        #endregion 辅助方法
+    }
+}

+ 194 - 0
Masuit.Tools.Core/Reflection/ReflectHelper.cs

@@ -0,0 +1,194 @@
+using System;
+using System.ComponentModel;
+using System.IO;
+using System.Reflection;
+using System.Resources;
+using System.Text;
+
+namespace Masuit.Tools.Reflection
+{
+    /// <summary>
+    /// 反射辅助类
+    /// </summary>
+    public static class ReflectHelper
+    {
+        #region 成员读写
+        /// <summary>
+        /// 获取实体相关属性的值
+        /// </summary>
+        /// <param name="obj">反射对象</param>
+        /// <param name="propertyName">属性名</param>
+        /// <returns>属性值</returns>
+        public static object GetInstanceValue(this object obj, string propertyName)
+        {
+            object objRet = null;
+            if (!string.IsNullOrEmpty(propertyName))
+            {
+                PropertyDescriptor descriptor = TypeDescriptor.GetProperties(obj).Find(propertyName, true);
+                if (descriptor != null)
+                {
+                    objRet = descriptor.GetValue(obj);
+                }
+            }
+            return objRet;
+        }
+        #endregion
+
+        #region 方法调用
+        /// <summary>
+        /// 直接调用内部对象的方法/函数或获取属性(支持重载调用)
+        /// </summary>
+        /// <typeparam name="T">泛型T</typeparam>
+        /// <param name="refType">目标数据类型</param>
+        /// <param name="funName">函数名称,区分大小写。</param>
+        /// <param name="objInitial">如果调用属性,则为相关对象的初始化数据,否则为Null。</param>
+        /// <param name="funParams">函数参数信息</param>
+        /// <returns>运行结果</returns>
+        /// <exception cref="InvalidProgramException">非法异常</exception>
+        public static T InvokeMethodOrGetProperty<T>(this Type refType, string funName, object[] objInitial, params object[] funParams)
+        {
+            MemberInfo[] mis = refType.GetMember(funName);
+            if (mis.Length < 1)
+            {
+                throw new InvalidProgramException(string.Concat("函数/方法 [", funName, "] 在指定类型(", refType.ToString(), ")中不存在!"));
+            }
+            MethodInfo targetMethod = null;
+            StringBuilder pb = new StringBuilder();
+            foreach (MemberInfo mi in mis)
+            {
+                if (mi.MemberType != MemberTypes.Method)
+                {
+                    if (mi.MemberType == MemberTypes.Property)
+                    {
+                        #region 调用属性方法Get
+                        targetMethod = ((PropertyInfo)mi).GetGetMethod();
+                        break;
+                        #endregion
+                    }
+                    throw new InvalidProgramException(string.Concat("[", funName, "] 不是有效的函数/属性方法!"));
+                }
+
+                #region 检查函数参数和数据类型 绑定正确的函数到目标调用
+
+                MethodInfo curMethod = (MethodInfo)mi;
+                ParameterInfo[] pis = curMethod.GetParameters();
+                if (pis.Length == funParams.Length)
+                {
+                    var validParamsLen = true;
+
+                    pb = new StringBuilder();
+                    bool paramFlag = true;
+                    int paramIdx = 0;
+
+                    #region 检查数据类型 设置validParamsType是否有效
+                    foreach (ParameterInfo pi in pis)
+                    {
+                        pb.AppendFormat("Parameter {0}: Type={1}, Name={2}\n", paramIdx, pi.ParameterType, pi.Name);
+
+                        //不对Null和接受Object类型的参数检查
+                        if (funParams[paramIdx] != null && pi.ParameterType != typeof(object) && (pi.ParameterType != funParams[paramIdx].GetType()))
+                        {
+                            #region 检查类型是否兼容
+                            try
+                            {
+                                funParams[paramIdx] = Convert.ChangeType(funParams[paramIdx], pi.ParameterType);
+                            }
+                            catch (Exception)
+                            {
+                                paramFlag = false;
+                            }
+                            #endregion
+                            //break;
+                        }
+                        ++paramIdx;
+                    }
+                    #endregion
+
+                    bool validParamsType;
+                    if (paramFlag)
+                    {
+                        validParamsType = true;
+                    }
+                    else
+                    {
+                        continue;
+                    }
+                    if (validParamsLen && validParamsType)
+                    {
+                        targetMethod = curMethod;
+                        break;
+                    }
+                }
+                #endregion
+            }
+
+            if (targetMethod != null)
+            {
+                object objReturn = null;
+                #region 兼顾效率和兼容重载函数调用
+                try
+                {
+                    object objInstance = Activator.CreateInstance(refType, objInitial);
+                    objReturn = targetMethod.Invoke(objInstance, BindingFlags.InvokeMethod, Type.DefaultBinder, funParams,
+                        System.Globalization.CultureInfo.InvariantCulture);
+                }
+                catch (Exception)
+                {
+                    objReturn = refType.InvokeMember(funName, BindingFlags.InvokeMethod, Type.DefaultBinder, null, funParams);
+                }
+                #endregion
+                return (T)objReturn;
+            }
+            throw new InvalidProgramException(string.Concat("函数/方法 [", refType.ToString(), ".", funName, "(args ...) ] 参数长度和数据类型不正确!\n 引用参数信息参考:\n", pb.ToString()));
+        }
+
+        /// <summary>
+        /// 调用相关实体类型的函数方法
+        /// </summary>
+        /// <typeparam name="T">泛型T</typeparam>
+        /// <param name="refType">实体类型</param>
+        /// <param name="funName">函数名称</param>
+        /// <param name="funParams">函数参数列表</param>
+        /// <returns>调用该函数之后的结果</returns>
+        public static T InvokeFunction<T>(this Type refType, string funName, params object[] funParams)
+        {
+            return InvokeMethodOrGetProperty<T>(refType, funName, null, funParams);
+        }
+        #endregion
+
+        #region 资源获取
+        /// <summary>
+        ///  获取程序集资源的文本资源
+        /// </summary>
+        /// <param name="assemblyType">程序集中的某一对象类型</param>
+        /// <param name="resName">资源项名称</param>
+        /// <param name="resourceHolder">资源的根名称。例如,名为“MyResource.en-US.resources”的资源文件的根名称为“MyResource”。</param>
+        public static string GetStringRes(this Type assemblyType, string resName, string resourceHolder)
+        {
+            Assembly thisAssembly = Assembly.GetAssembly(assemblyType);
+            ResourceManager rm = new ResourceManager(resourceHolder, thisAssembly);
+            return rm.GetString(resName);
+        }
+
+        /// <summary>
+        /// 获取程序集嵌入资源的文本形式
+        /// </summary>
+        /// <param name="assemblyType">程序集中的某一对象类型</param>
+        /// <param name="charset">字符集编码</param>
+        /// <param name="ResName">嵌入资源相对路径</param>
+        /// <returns>如没找到该资源则返回空字符</returns>
+        public static string GetManifestString(this Type assemblyType, string charset, string ResName)
+        {
+            Assembly asm = Assembly.GetAssembly(assemblyType);
+            Stream st = asm.GetManifestResourceStream(string.Concat(assemblyType.Namespace,
+                ".", ResName.Replace("/", ".")));
+            if (st == null) { return ""; }
+            int iLen = (int)st.Length;
+            byte[] bytes = new byte[iLen];
+            st.Read(bytes, 0, iLen);
+            return (bytes != null) ? Encoding.GetEncoding(charset).GetString(bytes) : "";
+        }
+        #endregion
+
+    }
+}

+ 404 - 0
Masuit.Tools.Core/Reflection/ReflectionUtil.cs

@@ -0,0 +1,404 @@
+using System;
+using System.ComponentModel;
+using System.IO;
+using System.Reflection;
+using System.Resources;
+using System.Text;
+
+namespace Masuit.Tools.Reflection
+{
+    /// <summary>
+    /// 反射操作辅助类,如获取或设置字段、属性的值等反射信息。
+    /// </summary>
+    public static class ReflectionUtil
+    {
+        #region 属性字段设置
+#pragma warning disable 1591
+        public static BindingFlags bf = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
+#pragma warning restore 1591
+
+        /// <summary>
+        /// 执行方法
+        /// </summary>
+        /// <param name="obj">反射对象</param>
+        /// <param name="methodName">方法名,区分大小写</param>
+        /// <param name="args">方法参数</param>
+        /// <typeparam name="T">约束返回的T必须是引用类型</typeparam>
+        /// <returns>T类型</returns>
+        public static T InvokeMethod<T>(this object obj, string methodName, object[] args) where T : class
+        {
+            T objReturn;
+            Type type = obj.GetType();
+            objReturn = type.InvokeMember(methodName, bf | BindingFlags.InvokeMethod, null, obj, args) as T;
+            return objReturn;
+        }
+
+        /// <summary>
+        /// 设置字段
+        /// </summary>
+        /// <param name="obj">反射对象</param>
+        /// <param name="name">字段名</param>
+        /// <param name="value">值</param>
+        public static void SetField(this object obj, string name, object value)
+        {
+            FieldInfo fi = obj.GetType().GetField(name, bf);
+            fi.SetValue(obj, value);
+        }
+
+        /// <summary>
+        /// 获取字段
+        /// </summary>
+        /// <param name="obj">反射对象</param>
+        /// <param name="name">字段名</param>
+        /// <typeparam name="T">约束返回的T必须是引用类型</typeparam>
+        /// <returns>T类型</returns>
+        public static T GetField<T>(this object obj, string name) where T : class
+        {
+            FieldInfo fi = obj.GetType().GetField(name, bf);
+            return fi.GetValue(obj) as T;
+        }
+
+        /// <summary>
+        /// 获取所有的字段信息
+        /// </summary>
+        /// <param name="obj">反射对象</param>
+        /// <returns>字段信息</returns>
+        public static FieldInfo[] GetFields(this object obj)
+        {
+            FieldInfo[] fieldInfos = obj.GetType().GetFields(bf);
+            return fieldInfos;
+        }
+
+        /// <summary>
+        /// 设置属性
+        /// </summary>
+        /// <param name="obj">反射对象</param>
+        /// <param name="name">属性名</param>
+        /// <param name="value">值</param>
+        public static void SetProperty(this object obj, string name, object value)
+        {
+            PropertyInfo fieldInfo = obj.GetType().GetProperty(name, bf);
+            value = Convert.ChangeType(value, fieldInfo.PropertyType);
+            fieldInfo.SetValue(obj, value, null);
+        }
+
+        /// <summary>
+        /// 获取属性
+        /// </summary>
+        /// <param name="obj">反射对象</param>
+        /// <param name="name">属性名</param>
+        /// <typeparam name="T">约束返回的T必须是引用类型</typeparam>
+        /// <returns>T类型</returns>
+        public static T GetProperty<T>(this object obj, string name) where T : class
+        {
+            PropertyInfo fieldInfo = obj.GetType().GetProperty(name, bf);
+            return fieldInfo.GetValue(obj, null) as T;
+        }
+
+        /// <summary>
+        /// 获取所有的属性信息
+        /// </summary>
+        /// <param name="obj">反射对象</param>
+        /// <returns>属性信息</returns>
+        public static PropertyInfo[] GetProperties(this object obj)
+        {
+            PropertyInfo[] propertyInfos = obj.GetType().GetProperties(bf);
+            return propertyInfos;
+        }
+
+        #endregion
+
+        #region 获取Description
+
+        /// <overloads>
+        ///		Get The Member Description using Description Attribute.
+        /// </overloads>
+        /// <summary>
+        /// Get The Enum Field Description using Description Attribute.
+        /// </summary>
+        /// <param name="value">The value.</param>
+        /// <returns>return description or value.ToString()</returns>
+        public static string GetDescription(this Enum value)
+        {
+            return GetDescription(value, null);
+        }
+
+        /// <summary>
+        /// Get The Enum Field Description using Description Attribute and 
+        /// objects to format the Description.
+        /// </summary>
+        /// <param name="value">Enum For Which description is required.</param>
+        /// <param name="args">An Object array containing zero or more objects to format.</param>
+        /// <returns>return null if DescriptionAttribute is not found or return type description</returns>
+        /// <exception cref="ArgumentNullException"><paramref name="value"/>"/> is <c>null</c>.</exception>
+        public static string GetDescription(this Enum value, params object[] args)
+        {
+            if (value == null)
+            {
+                throw new ArgumentNullException(nameof(value));
+            }
+
+            string text1;
+
+            FieldInfo fi = value.GetType().GetField(value.ToString());
+
+            DescriptionAttribute[] attributes =
+                (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
+
+            text1 = (attributes.Length > 0) ? attributes[0].Description : value.ToString();
+
+            if ((args != null) && (args.Length > 0))
+            {
+                return string.Format(null, text1, args);
+            }
+            return text1;
+        }
+
+        /// <summary>
+        ///	Get The Type Description using Description Attribute.
+        /// </summary>
+        /// <param name="member">Specified Member for which Info is Required</param>
+        /// <returns>return null if DescriptionAttribute is not found or return type description</returns>
+        public static string GetDescription(this MemberInfo member)
+        {
+            return GetDescription(member, null);
+        }
+
+        /// <summary>
+        /// Get The Type Description using Description Attribute and 
+        /// objects to format the Description.
+        /// </summary>
+        /// <param name="member"> Specified Member for which Info is Required</param>
+        /// <param name="args">An Object array containing zero or more objects to format.</param>
+        /// <returns>return <see cref="String.Empty"/> if DescriptionAttribute is 
+        /// not found or return type description</returns>
+        /// <exception cref="ArgumentNullException"><paramref name="member"/>"/> is <c>null</c>.</exception>
+        public static string GetDescription(this MemberInfo member, params object[] args)
+        {
+            string text1;
+
+            if (member == null)
+            {
+                throw new ArgumentNullException(nameof(member));
+            }
+
+            if (member.IsDefined(typeof(DescriptionAttribute), false))
+            {
+                DescriptionAttribute[] attributes =
+                    (DescriptionAttribute[])member.GetCustomAttributes(typeof(DescriptionAttribute), false);
+                text1 = attributes[0].Description;
+            }
+            else
+            {
+                return System.String.Empty;
+            }
+
+            if ((args != null) && (args.Length > 0))
+            {
+                return System.String.Format(null, text1, args);
+            }
+            return text1;
+        }
+
+        #endregion
+
+        #region 获取Attribute信息
+
+        /// <overloads>
+        /// Gets the specified object attributes
+        /// </overloads>
+        /// <summary>
+        /// Gets the specified object attributes for assembly as specified by type
+        /// </summary>
+        /// <param name="attributeType">The attribute Type for which the custom attributes are to be returned.</param>
+        /// <param name="assembly">the assembly in which the specified attribute is defined</param>
+        /// <returns>Attribute as Object or null if not found.</returns>
+        /// <exception cref="ArgumentNullException"><paramref name="attributeType"/>"/> is <c>null</c>.</exception>
+        public static object GetAttribute(this Type attributeType, Assembly assembly)
+        {
+            if (attributeType == null)
+            {
+                throw new ArgumentNullException(nameof(attributeType));
+            }
+            if (assembly == null)
+            {
+                throw new ArgumentNullException(nameof(assembly));
+            }
+            if (assembly.IsDefined(attributeType, false))
+            {
+                object[] attributes = assembly.GetCustomAttributes(attributeType, false);
+                return attributes[0];
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Gets the specified object attributes for type as specified by type
+        /// </summary>
+        /// <param name="attributeType">The attribute Type for which the custom attributes are to be returned.</param>
+        /// <param name="type">the type on which the specified attribute is defined</param>
+        /// <returns>Attribute as Object or null if not found.</returns>
+        public static object GetAttribute(this Type attributeType, MemberInfo type)
+        {
+            return GetAttribute(attributeType, type, false);
+        }
+
+        /// <summary>
+        /// Gets the specified object attributes for type as specified by type with option to serach parent
+        /// </summary>
+        /// <param name="attributeType">The attribute Type for which the custom attributes are to be returned.</param>
+        /// <param name="type">the type on which the specified attribute is defined</param>
+        /// <param name="searchParent">if set to <see langword="true"/> [search parent].</param>
+        /// <returns>
+        /// Attribute as Object or null if not found.
+        /// </returns>
+        public static object GetAttribute(this Type attributeType, MemberInfo type, bool searchParent)
+        {
+            if (attributeType == null)
+            {
+                return null;
+            }
+            if (type == null)
+            {
+                return null;
+            }
+            if (!(attributeType.IsSubclassOf(typeof(Attribute))))
+            {
+                return null;
+            }
+            if (type.IsDefined(attributeType, searchParent))
+            {
+                object[] attributes = type.GetCustomAttributes(attributeType, searchParent);
+
+                if (attributes.Length > 0)
+                {
+                    return attributes[0];
+                }
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Gets the collection of all specified object attributes for type as specified by type
+        /// </summary>
+        /// <param name="attributeType">The attribute Type for which the custom attributes are to be returned.</param>
+        /// <param name="type">the type on which the specified attribute is defined</param>
+        /// <returns>Attribute as Object or null if not found.</returns>
+        public static object[] GetAttributes(this Type attributeType, MemberInfo type)
+        {
+            return GetAttributes(attributeType, type, false);
+        }
+
+        /// <summary>
+        /// Gets the collection of all specified object attributes for type as specified by type with option to serach parent
+        /// </summary>
+        /// <param name="attributeType">The attribute Type for which the custom attributes are to be returned.</param>
+        /// <param name="type">the type on which the specified attribute is defined</param>
+        /// <param name="searchParent">The attribute Type for which the custom attribute is to be returned.</param>
+        /// <returns>
+        /// Attribute as Object or null if not found.
+        /// </returns>
+        public static object[] GetAttributes(this Type attributeType, MemberInfo type, bool searchParent)
+        {
+            if (type == null)
+            {
+                return null;
+            }
+            if (attributeType == null)
+            {
+                return null;
+            }
+            if (!(attributeType.IsSubclassOf(typeof(Attribute))))
+            {
+                return null;
+            }
+            if (type.IsDefined(attributeType, false))
+            {
+                return type.GetCustomAttributes(attributeType, searchParent);
+            }
+            return null;
+        }
+
+        #endregion
+
+        #region 资源获取
+
+        /// <summary>
+        /// 根据资源名称获取图片资源流
+        /// </summary>
+        /// <param name="_"></param>
+        /// <param name="resourceName">资源的名称</param>
+        /// <returns>数据流</returns>
+        public static Stream GetImageResource(this Assembly _, string resourceName)
+        {
+            Assembly asm = Assembly.GetExecutingAssembly();
+            return asm.GetManifestResourceStream(resourceName);
+        }
+
+        /// <summary>
+        ///  获取程序集资源的文本资源
+        /// </summary>
+        /// <param name="assemblyType">程序集中的某一对象类型</param>
+        /// <param name="resName">资源项名称</param>
+        /// <param name="resourceHolder">资源的根名称。例如,名为“MyResource.en-US.resources”的资源文件的根名称为“MyResource”。</param>
+        public static string GetStringRes(this Type assemblyType, string resName, string resourceHolder)
+        {
+            Assembly thisAssembly = Assembly.GetAssembly(assemblyType);
+            ResourceManager rm = new ResourceManager(resourceHolder, thisAssembly);
+            return rm.GetString(resName);
+        }
+
+        /// <summary>
+        /// 获取程序集嵌入资源的文本形式
+        /// </summary>
+        /// <param name="assemblyType">程序集中的某一对象类型</param>
+        /// <param name="charset">字符集编码</param>
+        /// <param name="ResName">嵌入资源相对路径</param>
+        /// <returns>如没找到该资源则返回空字符</returns>
+        public static string GetManifestString(this Type assemblyType, string charset, string ResName)
+        {
+            Assembly asm = Assembly.GetAssembly(assemblyType);
+            Stream st = asm.GetManifestResourceStream(string.Concat(assemblyType.Namespace,
+                ".", ResName.Replace("/", ".")));
+            if (st == null) { return ""; }
+            int iLen = (int)st.Length;
+            byte[] bytes = new byte[iLen];
+            st.Read(bytes, 0, iLen);
+            return (bytes != null) ? Encoding.GetEncoding(charset).GetString(bytes) : "";
+        }
+
+        #endregion
+
+        #region 创建对应实例
+        /// <summary>
+        /// 创建对应实例
+        /// </summary>
+        /// <param name="type">类型</param>
+        /// <returns>对应实例</returns>
+        public static T CreateInstance<T>(string type) where T : class
+        {
+            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
+            foreach (Assembly t in assemblies)
+            {
+                var tmp = t.GetType(type);
+                if (tmp != null)
+                {
+                    return t.CreateInstance(type) as T;
+                }
+            }
+            return null;
+            //return Assembly.GetExecutingAssembly().CreateInstance(type);
+        }
+
+        /// <summary>
+        /// 创建对应实例
+        /// </summary>
+        /// <param name="type">类型</param>
+        /// <returns>对应实例</returns>
+        public static T CreateInstance<T>(this Type type) where T : class
+        {
+            return CreateInstance<T>(type.FullName);
+        }
+        #endregion
+    }
+}

+ 1510 - 0
Masuit.Tools.Core/Security/Encrypt.cs

@@ -0,0 +1,1510 @@
+using System;
+using System.Collections;
+using System.Configuration;
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace Masuit.Tools.Security
+{
+    /// <summary>
+    /// 常用的加密解密算法
+    /// </summary>
+    public static class Encrypt
+    {
+        #region DES对称加密解密
+        /// <summary>
+        /// 加密密钥,需要在config配置文件中AppSettings节点中配置desSecret值,若未配置,默认取“masuit”的MD5值
+        /// </summary>
+        public static string DEFAULT_ENCRYPT_KEY = ConfigurationManager.AppSettings["desSecret"] ?? "masuit".MDString2();
+
+        /// <summary>
+        /// 使用默认加密
+        /// </summary>
+        /// <param name="strText">被加密的字符串</param>
+        /// <returns>加密后的数据</returns>
+        public static string DesEncrypt(this string strText)
+        {
+            try
+            {
+                return DesEncrypt(strText, DEFAULT_ENCRYPT_KEY);
+            }
+            catch
+            {
+                return "";
+            }
+        }
+
+        /// <summary>
+        /// 使用默认解密
+        /// </summary>
+        /// <param name="strText">需要解密的 字符串</param>
+        /// <returns>解密后的数据</returns>
+        public static string DesDecrypt(this string strText)
+        {
+            try
+            {
+                return DesDecrypt(strText, DEFAULT_ENCRYPT_KEY);
+            }
+            catch
+            {
+                return "";
+            }
+        }
+
+        /// <summary> 
+        /// 解密字符串
+        /// 加密密钥必须为8位
+        /// </summary> 
+        /// <param name="strText">被解密的字符串</param> 
+        /// <param name="strEncrKey">密钥</param> 
+        /// <returns>解密后的数据</returns> 
+        public static string DesEncrypt(this string strText, string strEncrKey)
+        {
+            if (strEncrKey.Length < 8)
+            {
+                throw new Exception("密钥长度无效,密钥必须是8位!");
+            }
+            StringBuilder ret = new StringBuilder();
+            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
+            byte[] inputByteArray = Encoding.Default.GetBytes(strText);
+            des.Key = Encoding.ASCII.GetBytes(strEncrKey.Substring(0, 8));
+            des.IV = Encoding.ASCII.GetBytes(strEncrKey.Substring(0, 8));
+            MemoryStream ms = new MemoryStream();
+            CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
+            cs.Write(inputByteArray, 0, inputByteArray.Length);
+            cs.FlushFinalBlock();
+            foreach (byte b in ms.ToArray())
+            {
+                ret.AppendFormat($"{b:X2}");
+            }
+            return ret.ToString();
+        }
+
+        /// <summary>
+        /// DES加密文件
+        /// </summary>
+        /// <param name="fin">文件输入流</param>
+        /// <param name="outFilePath">文件输出路径</param>
+        /// <param name="strEncrKey">加密密钥</param>
+        public static void DesEncrypt(this FileStream fin, string outFilePath, string strEncrKey)
+        {
+            byte[] iv = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
+            var byKey = Encoding.UTF8.GetBytes(strEncrKey.Substring(0, 8));
+            using (fin)
+            {
+                using (FileStream fout = new FileStream(outFilePath, FileMode.OpenOrCreate, FileAccess.Write))
+                {
+                    fout.SetLength(0);
+                    byte[] bin = new byte[100];
+                    long rdlen = 0;
+                    long totlen = fin.Length;
+                    DES des = new DESCryptoServiceProvider();
+                    var encStream = new CryptoStream(fout, des.CreateEncryptor(byKey, iv), CryptoStreamMode.Write);
+                    while (rdlen < totlen)
+                    {
+                        var len = fin.Read(bin, 0, 100);
+                        encStream.Write(bin, 0, len);
+                        rdlen += len;
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// DES解密文件
+        /// </summary>
+        /// <param name="fin">输入文件流</param>
+        /// <param name="outFilePath">文件输出路径</param>
+        /// <param name="sDecrKey">解密密钥</param>
+        public static void DesDecrypt(this FileStream fin, string outFilePath, string sDecrKey)
+        {
+            byte[] iv = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
+            var byKey = Encoding.UTF8.GetBytes(sDecrKey.Substring(0, 8));
+            using (fin)
+            {
+                using (FileStream fout = new FileStream(outFilePath, FileMode.OpenOrCreate, FileAccess.Write))
+                {
+                    fout.SetLength(0);
+                    byte[] bin = new byte[100];
+                    long rdlen = 0;
+                    long totlen = fin.Length;
+                    DES des = new DESCryptoServiceProvider();
+                    CryptoStream encStream = new CryptoStream(fout, des.CreateDecryptor(byKey, iv), CryptoStreamMode.Write);
+                    while (rdlen < totlen)
+                    {
+                        var len = fin.Read(bin, 0, 100);
+                        encStream.Write(bin, 0, len);
+                        rdlen += len;
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        ///     DES解密算法
+        ///     密钥为8位
+        /// </summary>
+        /// <param name="pToDecrypt">需要解密的字符串</param>
+        /// <param name="sKey">密钥</param>
+        /// <returns>解密后的数据</returns>
+        public static string DesDecrypt(this string pToDecrypt, string sKey)
+        {
+            if (sKey.Length < 8)
+            {
+                throw new Exception("密钥长度无效,密钥必须是8位!");
+            }
+            var ms = new MemoryStream();
+
+            var des = new DESCryptoServiceProvider();
+            var inputByteArray = new byte[pToDecrypt.Length / 2];
+            for (int x = 0; x < pToDecrypt.Length / 2; x++)
+            {
+                int i = (Convert.ToInt32(pToDecrypt.Substring(x * 2, 2), 16));
+                inputByteArray[x] = (byte)i;
+            }
+            des.Key = Encoding.ASCII.GetBytes(sKey.Substring(0, 8));
+            des.IV = Encoding.ASCII.GetBytes(sKey.Substring(0, 8));
+            var cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
+            cs.Write(inputByteArray, 0, inputByteArray.Length);
+            cs.FlushFinalBlock();
+            return Encoding.Default.GetString(ms.ToArray());
+        }
+
+        #endregion
+        #region 对称加密算法AES RijndaelManaged加密解密
+        private static readonly string Default_AES_Key = "@#kim123";
+        private static byte[] Keys = { 0x41, 0x72, 0x65, 0x79, 0x6F, 0x75, 0x6D, 0x79,
+                                             0x53,0x6E, 0x6F, 0x77, 0x6D, 0x61, 0x6E, 0x3F };
+
+        /// <summary>
+        /// 对称加密算法AES RijndaelManaged加密(RijndaelManaged(AES)算法是块式加密算法)
+        /// </summary>
+        /// <param name="encryptString">待加密字符串</param>
+        /// <returns>加密结果字符串</returns>
+        public static string AESEncrypt(this string encryptString)
+        {
+            return AESEncrypt(encryptString, Default_AES_Key);
+        }
+
+        /// <summary>
+        /// 对称加密算法AES RijndaelManaged加密(RijndaelManaged(AES)算法是块式加密算法)
+        /// </summary>
+        /// <param name="encryptString">待加密字符串</param>
+        /// <param name="encryptKey">加密密钥,须半角字符</param>
+        /// <returns>加密结果字符串</returns>
+        public static string AESEncrypt(this string encryptString, string encryptKey)
+        {
+            encryptKey = GetSubString(encryptKey, 32, "");
+            encryptKey = encryptKey.PadRight(32, ' ');
+            var rijndaelProvider = new RijndaelManaged { Key = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 32)), IV = Keys };
+            ICryptoTransform rijndaelEncrypt = rijndaelProvider.CreateEncryptor();
+            byte[] inputData = Encoding.UTF8.GetBytes(encryptString);
+            byte[] encryptedData = rijndaelEncrypt.TransformFinalBlock(inputData, 0, inputData.Length);
+            return Convert.ToBase64String(encryptedData);
+        }
+
+        /// <summary>
+        /// 对称加密算法AES RijndaelManaged解密字符串
+        /// </summary>
+        /// <param name="decryptString">待解密的字符串</param>
+        /// <returns>解密成功返回解密后的字符串,失败返源串</returns>
+        public static string AESDecrypt(this string decryptString)
+        {
+            return AESDecrypt(decryptString, Default_AES_Key);
+        }
+
+        /// <summary>
+        /// 对称加密算法AES RijndaelManaged解密字符串
+        /// </summary>
+        /// <param name="decryptString">待解密的字符串</param>
+        /// <param name="decryptKey">解密密钥,和加密密钥相同</param>
+        /// <returns>解密成功返回解密后的字符串,失败返回空</returns>
+        public static string AESDecrypt(this string decryptString, string decryptKey)
+        {
+            try
+            {
+                decryptKey = GetSubString(decryptKey, 32, "");
+                decryptKey = decryptKey.PadRight(32, ' ');
+                var rijndaelProvider = new RijndaelManaged()
+                {
+                    Key = Encoding.UTF8.GetBytes(decryptKey),
+                    IV = Keys
+                };
+                ICryptoTransform rijndaelDecrypt = rijndaelProvider.CreateDecryptor();
+                byte[] inputData = Convert.FromBase64String(decryptString);
+                byte[] decryptedData = rijndaelDecrypt.TransformFinalBlock(inputData, 0, inputData.Length);
+                return Encoding.UTF8.GetString(decryptedData);
+            }
+            catch
+            {
+                return string.Empty;
+            }
+        }
+
+        /// <summary>
+        /// 按字节长度(按字节,一个汉字为2个字节)取得某字符串的一部分
+        /// </summary>
+        /// <param name="sourceString">源字符串</param>
+        /// <param name="length">所取字符串字节长度</param>
+        /// <param name="tailString">附加字符串(当字符串不够长时,尾部所添加的字符串,一般为"...")</param>
+        /// <returns>某字符串的一部分</returns>
+        private static string GetSubString(this string sourceString, int length, string tailString)
+        {
+            return GetSubString(sourceString, 0, length, tailString);
+        }
+
+        /// <summary>
+        /// 按字节长度(按字节,一个汉字为2个字节)取得某字符串的一部分
+        /// </summary>
+        /// <param name="sourceString">源字符串</param>
+        /// <param name="startIndex">索引位置,以0开始</param>
+        /// <param name="length">所取字符串字节长度</param>
+        /// <param name="tailString">附加字符串(当字符串不够长时,尾部所添加的字符串,一般为"...")</param>
+        /// <returns>某字符串的一部分</returns>
+        private static string GetSubString(this string sourceString, int startIndex, int length, string tailString)
+        {
+            //当是日文或韩文时(注:中文的范围:\u4e00 - \u9fa5, 日文在\u0800 - \u4e00, 韩文为\xAC00-\xD7A3)
+            if (System.Text.RegularExpressions.Regex.IsMatch(sourceString, "[\u0800-\u4e00]+") || System.Text.RegularExpressions.Regex.IsMatch(sourceString, "[\xAC00-\xD7A3]+"))
+            {
+                //当截取的起始位置超出字段串长度时
+                if (startIndex >= sourceString.Length)
+                {
+                    return string.Empty;
+                }
+                return sourceString.Substring(startIndex, length + startIndex > sourceString.Length ? (sourceString.Length - startIndex) : length);
+            }
+
+            //中文字符,如"中国人民abcd123"
+            if (length <= 0)
+            {
+                return string.Empty;
+            }
+            byte[] bytesSource = Encoding.Default.GetBytes(sourceString);
+
+            //当字符串长度大于起始位置
+            if (bytesSource.Length > startIndex)
+            {
+                int endIndex = bytesSource.Length;
+
+                //当要截取的长度在字符串的有效长度范围内
+                if (bytesSource.Length > (startIndex + length))
+                {
+                    endIndex = length + startIndex;
+                }
+                else
+                {   //当不在有效范围内时,只取到字符串的结尾
+                    length = bytesSource.Length - startIndex;
+                    tailString = "";
+                }
+                var anResultFlag = new int[length];
+                int nFlag = 0;
+                //字节大于127为双字节字符
+                for (int i = startIndex; i < endIndex; i++)
+                {
+                    if (bytesSource[i] > 127)
+                    {
+                        nFlag++;
+                        if (nFlag == 3)
+                        {
+                            nFlag = 1;
+                        }
+                    }
+                    else
+                    {
+                        nFlag = 0;
+                    }
+                    anResultFlag[i] = nFlag;
+                }
+                //最后一个字节为双字节字符的一半
+                if ((bytesSource[endIndex - 1] > 127) && (anResultFlag[length - 1] == 1))
+                {
+                    length++;
+                }
+                byte[] bsResult = new byte[length];
+                Array.Copy(bytesSource, startIndex, bsResult, 0, length);
+                var myResult = Encoding.Default.GetString(bsResult);
+                myResult += tailString;
+                return myResult;
+            }
+            return string.Empty;
+        }
+
+        /// <summary>
+        /// 加密文件流
+        /// </summary>
+        /// <param name="fs">需要加密的文件流</param>
+        /// <param name="decryptKey">加密密钥</param>
+        /// <returns>加密流</returns>
+        public static CryptoStream AESEncryptStrream(this FileStream fs, string decryptKey)
+        {
+            decryptKey = GetSubString(decryptKey, 32, "");
+            decryptKey = decryptKey.PadRight(32, ' ');
+            var rijndaelProvider = new RijndaelManaged()
+            {
+                Key = Encoding.UTF8.GetBytes(decryptKey),
+                IV = Keys
+            };
+            ICryptoTransform encrypto = rijndaelProvider.CreateEncryptor();
+            return new CryptoStream(fs, encrypto, CryptoStreamMode.Write);
+        }
+
+        /// <summary>
+        /// 解密文件流
+        /// </summary>
+        /// <param name="fs">需要解密的文件流</param>
+        /// <param name="decryptKey">解密密钥</param>
+        /// <returns>加密流</returns>
+        public static CryptoStream AESDecryptStream(this FileStream fs, string decryptKey)
+        {
+            decryptKey = GetSubString(decryptKey, 32, "");
+            decryptKey = decryptKey.PadRight(32, ' ');
+            var rijndaelProvider = new RijndaelManaged()
+            {
+                Key = Encoding.UTF8.GetBytes(decryptKey),
+                IV = Keys
+            };
+            ICryptoTransform decrypto = rijndaelProvider.CreateDecryptor();
+            return new CryptoStream(fs, decrypto, CryptoStreamMode.Read);
+        }
+
+        /// <summary>
+        /// 对指定文件AES加密
+        /// </summary>
+        /// <param name="input">源文件流</param>
+        /// <param name="outputPath">输出文件路径</param>
+        public static void AESEncryptFile(this FileStream input, string outputPath)
+        {
+            using (input)
+            {
+                using (FileStream fren = new FileStream(outputPath, FileMode.Create))
+                {
+                    CryptoStream enfr = AESEncryptStrream(fren, Default_AES_Key);
+                    byte[] bytearrayinput = new byte[input.Length];
+                    input.Read(bytearrayinput, 0, bytearrayinput.Length);
+                    enfr.Write(bytearrayinput, 0, bytearrayinput.Length);
+                }
+            }
+        }
+
+        /// <summary>
+        /// 对指定的文件AES解密
+        /// </summary>
+        /// <param name="input">源文件流</param>
+        /// <param name="outputPath">输出文件路径</param>
+        public static void AESDecryptFile(this FileStream input, string outputPath)
+        {
+            using (input)
+            {
+                FileStream frde = new FileStream(outputPath, FileMode.Create);
+                CryptoStream defr = AESDecryptStream(input, Default_AES_Key);
+                byte[] bytearrayoutput = new byte[1024];
+                while (true)
+                {
+                    var count = defr.Read(bytearrayoutput, 0, bytearrayoutput.Length);
+                    frde.Write(bytearrayoutput, 0, count);
+                    if (count < bytearrayoutput.Length) break;
+                }
+            }
+        }
+
+        #endregion
+
+        #region Base64加密解密
+        /// <summary>
+        /// Base64加密
+        /// </summary>
+        /// <param name="str">需要加密的字符串</param>
+        /// <returns>加密后的数据</returns>
+        public static string Base64Encrypt(this string str)
+        {
+            byte[] encbuff = Encoding.UTF8.GetBytes(str);
+            return Convert.ToBase64String(encbuff);
+        }
+
+        /// <summary>
+        /// Base64解密
+        /// </summary>
+        /// <param name="str">需要解密的字符串</param>
+        /// <returns>解密后的数据</returns>
+        public static string Base64Decrypt(this string str)
+        {
+            byte[] decbuff = Convert.FromBase64String(str);
+            return Encoding.UTF8.GetString(decbuff);
+        }
+        #endregion
+
+        #region MD5加密
+        /// <summary> 
+        /// MD5加密
+        /// </summary> 
+        /// <param name="strText">原数据</param> 
+        /// <returns>MD5字符串</returns> 
+        public static string MD5Encrypt(this string strText)
+        {
+            MD5 md5 = new MD5CryptoServiceProvider();
+            byte[] result = md5.ComputeHash(Encoding.Default.GetBytes(strText));
+            return Encoding.Default.GetString(result);
+        }
+
+        #endregion
+
+        /// <summary>
+        /// SHA256函数
+        /// </summary>
+        /// <param name="str">原始字符串</param>
+        /// <returns>SHA256结果(返回长度为44字节的字符串)</returns>
+        public static string SHA256(this string str)
+        {
+            byte[] sha256Data = Encoding.UTF8.GetBytes(str);
+            var sha256 = new SHA256Managed();
+            byte[] result = sha256.ComputeHash(sha256Data);
+            return Convert.ToBase64String(result);  //返回长度为44字节的字符串
+        }
+
+        #region 创建Key
+
+        /// <summary>
+        ///     创建Key
+        /// </summary>
+        /// <returns>密钥</returns>
+        public static string GenerateKey()
+        {
+            var desCrypto = (DESCryptoServiceProvider)DES.Create();
+            return Encoding.ASCII.GetString(desCrypto.Key);
+        }
+
+        #endregion
+
+        #region MD5加密
+
+        /// <summary>
+        ///     MD5加密
+        /// </summary>
+        /// <param name="pToEncrypt">加密字符串</param>
+        /// <param name="sKey">密钥Key</param>
+        /// <returns>加密后的字符串</returns>
+        public static string MD5Encrypt(this string pToEncrypt, string sKey)
+        {
+            var des = new DESCryptoServiceProvider();
+            var inputByteArray = Encoding.Default.GetBytes(pToEncrypt);
+            des.Key = Encoding.ASCII.GetBytes(sKey);
+            des.IV = Encoding.ASCII.GetBytes(sKey);
+            var ms = new MemoryStream();
+            var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
+            cs.Write(inputByteArray, 0, inputByteArray.Length);
+            cs.FlushFinalBlock();
+            var ret = new StringBuilder();
+            foreach (var b in ms.ToArray())
+                ret.AppendFormat("{0:X2}", b);
+            ret.ToString();
+            return ret.ToString();
+        }
+
+        #endregion
+
+        #region MD5解密
+
+        /// <summary>
+        ///     MD5解密
+        /// </summary>
+        /// <param name="pToDecrypt">解密字符串</param>
+        /// <param name="sKey">密钥Key</param>
+        /// <returns>解密后的数据</returns>
+        public static string MD5Decrypt(this string pToDecrypt, string sKey)
+        {
+            var des = new DESCryptoServiceProvider();
+
+            var inputByteArray = new byte[pToDecrypt.Length / 2];
+            for (var x = 0; x < pToDecrypt.Length / 2; x++)
+            {
+                var i = Convert.ToInt32(pToDecrypt.Substring(x * 2, 2), 16);
+                inputByteArray[x] = (byte)i;
+            }
+
+            des.Key = Encoding.ASCII.GetBytes(sKey);
+            des.IV = Encoding.ASCII.GetBytes(sKey);
+            var ms = new MemoryStream();
+            var cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
+            cs.Write(inputByteArray, 0, inputByteArray.Length);
+            cs.FlushFinalBlock();
+
+            var ret = new StringBuilder();
+
+            return Encoding.Default.GetString(ms.ToArray());
+        }
+
+        #endregion
+
+        #region MD5加密算法
+
+        //number of bits to rotate in tranforming
+        private const int S11 = 7;
+
+        private const int S12 = 12;
+        private const int S13 = 17;
+        private const int S14 = 22;
+        private const int S21 = 5;
+        private const int S22 = 9;
+        private const int S23 = 14;
+        private const int S24 = 20;
+        private const int S31 = 4;
+        private const int S32 = 11;
+        private const int S33 = 16;
+        private const int S34 = 23;
+        private const int S41 = 6;
+        private const int S42 = 10;
+        private const int S43 = 15;
+        private const int S44 = 21;
+
+        //static state variables
+        private static uint A;
+
+        private static uint B;
+        private static uint C;
+        private static uint D;
+
+        private static uint F(uint x, uint y, uint z)
+        {
+            return (x & y) | (~x & z);
+        }
+
+        private static uint G(uint x, uint y, uint z)
+        {
+            return (x & z) | (y & ~z);
+        }
+
+        private static uint H(uint x, uint y, uint z)
+        {
+            return x ^ y ^ z;
+        }
+
+        private static uint I(uint x, uint y, uint z)
+        {
+            return y ^ (x | ~z);
+        }
+
+        private static void FF(ref uint a, uint b, uint c, uint d, uint mj, int s, uint ti)
+        {
+            a = a + F(b, c, d) + mj + ti;
+            a = (a << s) | (a >> (32 - s));
+            a += b;
+        }
+
+        private static void GG(ref uint a, uint b, uint c, uint d, uint mj, int s, uint ti)
+        {
+            a = a + G(b, c, d) + mj + ti;
+            a = (a << s) | (a >> (32 - s));
+            a += b;
+        }
+
+        private static void HH(ref uint a, uint b, uint c, uint d, uint mj, int s, uint ti)
+        {
+            a = a + H(b, c, d) + mj + ti;
+            a = (a << s) | (a >> (32 - s));
+            a += b;
+        }
+
+        private static void II(ref uint a, uint b, uint c, uint d, uint mj, int s, uint ti)
+        {
+            a = a + I(b, c, d) + mj + ti;
+            a = (a << s) | (a >> (32 - s));
+            a += b;
+        }
+
+        private static void MD5_Init()
+        {
+            A = 0x67452301; //in memory, this is 0x01234567
+            B = 0xefcdab89; //in memory, this is 0x89abcdef
+            C = 0x98badcfe; //in memory, this is 0xfedcba98
+            D = 0x10325476; //in memory, this is 0x76543210
+        }
+
+        private static uint[] MD5_Append(byte[] input)
+        {
+            var zeros = 0;
+            var ones = 1;
+            var size = 0;
+            var n = input.Length;
+            var m = n % 64;
+            if (m < 56)
+            {
+                zeros = 55 - m;
+                size = n - m + 64;
+            }
+            else if (m == 56)
+            {
+                zeros = 0;
+                ones = 0;
+                size = n + 8;
+            }
+            else
+            {
+                zeros = 63 - m + 56;
+                size = n + 64 - m + 64;
+            }
+
+            var bs = new ArrayList(input);
+            if (ones == 1)
+                bs.Add((byte)0x80); // 0x80 = $10000000
+            for (var i = 0; i < zeros; i++)
+                bs.Add((byte)0);
+
+            var N = (ulong)n * 8;
+            var h1 = (byte)(N & 0xFF);
+            var h2 = (byte)((N >> 8) & 0xFF);
+            var h3 = (byte)((N >> 16) & 0xFF);
+            var h4 = (byte)((N >> 24) & 0xFF);
+            var h5 = (byte)((N >> 32) & 0xFF);
+            var h6 = (byte)((N >> 40) & 0xFF);
+            var h7 = (byte)((N >> 48) & 0xFF);
+            var h8 = (byte)(N >> 56);
+            bs.Add(h1);
+            bs.Add(h2);
+            bs.Add(h3);
+            bs.Add(h4);
+            bs.Add(h5);
+            bs.Add(h6);
+            bs.Add(h7);
+            bs.Add(h8);
+            var ts = (byte[])bs.ToArray(typeof(byte));
+
+            /* Decodes input (byte[]) into output (UInt32[]). Assumes len is
+            * a multiple of 4.
+           */
+            var output = new uint[size / 4];
+            for (long i = 0, j = 0; i < size; j++, i += 4)
+                output[j] = (uint)(ts[i] | (ts[i + 1] << 8) | (ts[i + 2] << 16) | (ts[i + 3] << 24));
+            return output;
+        }
+
+        private static uint[] MD5_Trasform(uint[] x)
+        {
+            uint a, b, c, d;
+
+            for (var k = 0; k < x.Length; k += 16)
+            {
+                a = A;
+                b = B;
+                c = C;
+                d = D;
+
+                /* Round 1 */
+                FF(ref a, b, c, d, x[k + 0], S11, 0xd76aa478); /* 1 */
+                FF(ref d, a, b, c, x[k + 1], S12, 0xe8c7b756); /* 2 */
+                FF(ref c, d, a, b, x[k + 2], S13, 0x242070db); /* 3 */
+                FF(ref b, c, d, a, x[k + 3], S14, 0xc1bdceee); /* 4 */
+                FF(ref a, b, c, d, x[k + 4], S11, 0xf57c0faf); /* 5 */
+                FF(ref d, a, b, c, x[k + 5], S12, 0x4787c62a); /* 6 */
+                FF(ref c, d, a, b, x[k + 6], S13, 0xa8304613); /* 7 */
+                FF(ref b, c, d, a, x[k + 7], S14, 0xfd469501); /* 8 */
+                FF(ref a, b, c, d, x[k + 8], S11, 0x698098d8); /* 9 */
+                FF(ref d, a, b, c, x[k + 9], S12, 0x8b44f7af); /* 10 */
+                FF(ref c, d, a, b, x[k + 10], S13, 0xffff5bb1); /* 11 */
+                FF(ref b, c, d, a, x[k + 11], S14, 0x895cd7be); /* 12 */
+                FF(ref a, b, c, d, x[k + 12], S11, 0x6b901122); /* 13 */
+                FF(ref d, a, b, c, x[k + 13], S12, 0xfd987193); /* 14 */
+                FF(ref c, d, a, b, x[k + 14], S13, 0xa679438e); /* 15 */
+                FF(ref b, c, d, a, x[k + 15], S14, 0x49b40821); /* 16 */
+
+                /* Round 2 */
+                GG(ref a, b, c, d, x[k + 1], S21, 0xf61e2562); /* 17 */
+                GG(ref d, a, b, c, x[k + 6], S22, 0xc040b340); /* 18 */
+                GG(ref c, d, a, b, x[k + 11], S23, 0x265e5a51); /* 19 */
+                GG(ref b, c, d, a, x[k + 0], S24, 0xe9b6c7aa); /* 20 */
+                GG(ref a, b, c, d, x[k + 5], S21, 0xd62f105d); /* 21 */
+                GG(ref d, a, b, c, x[k + 10], S22, 0x2441453); /* 22 */
+                GG(ref c, d, a, b, x[k + 15], S23, 0xd8a1e681); /* 23 */
+                GG(ref b, c, d, a, x[k + 4], S24, 0xe7d3fbc8); /* 24 */
+                GG(ref a, b, c, d, x[k + 9], S21, 0x21e1cde6); /* 25 */
+                GG(ref d, a, b, c, x[k + 14], S22, 0xc33707d6); /* 26 */
+                GG(ref c, d, a, b, x[k + 3], S23, 0xf4d50d87); /* 27 */
+                GG(ref b, c, d, a, x[k + 8], S24, 0x455a14ed); /* 28 */
+                GG(ref a, b, c, d, x[k + 13], S21, 0xa9e3e905); /* 29 */
+                GG(ref d, a, b, c, x[k + 2], S22, 0xfcefa3f8); /* 30 */
+                GG(ref c, d, a, b, x[k + 7], S23, 0x676f02d9); /* 31 */
+                GG(ref b, c, d, a, x[k + 12], S24, 0x8d2a4c8a); /* 32 */
+
+                /* Round 3 */
+                HH(ref a, b, c, d, x[k + 5], S31, 0xfffa3942); /* 33 */
+                HH(ref d, a, b, c, x[k + 8], S32, 0x8771f681); /* 34 */
+                HH(ref c, d, a, b, x[k + 11], S33, 0x6d9d6122); /* 35 */
+                HH(ref b, c, d, a, x[k + 14], S34, 0xfde5380c); /* 36 */
+                HH(ref a, b, c, d, x[k + 1], S31, 0xa4beea44); /* 37 */
+                HH(ref d, a, b, c, x[k + 4], S32, 0x4bdecfa9); /* 38 */
+                HH(ref c, d, a, b, x[k + 7], S33, 0xf6bb4b60); /* 39 */
+                HH(ref b, c, d, a, x[k + 10], S34, 0xbebfbc70); /* 40 */
+                HH(ref a, b, c, d, x[k + 13], S31, 0x289b7ec6); /* 41 */
+                HH(ref d, a, b, c, x[k + 0], S32, 0xeaa127fa); /* 42 */
+                HH(ref c, d, a, b, x[k + 3], S33, 0xd4ef3085); /* 43 */
+                HH(ref b, c, d, a, x[k + 6], S34, 0x4881d05); /* 44 */
+                HH(ref a, b, c, d, x[k + 9], S31, 0xd9d4d039); /* 45 */
+                HH(ref d, a, b, c, x[k + 12], S32, 0xe6db99e5); /* 46 */
+                HH(ref c, d, a, b, x[k + 15], S33, 0x1fa27cf8); /* 47 */
+                HH(ref b, c, d, a, x[k + 2], S34, 0xc4ac5665); /* 48 */
+
+                /* Round 4 */
+                II(ref a, b, c, d, x[k + 0], S41, 0xf4292244); /* 49 */
+                II(ref d, a, b, c, x[k + 7], S42, 0x432aff97); /* 50 */
+                II(ref c, d, a, b, x[k + 14], S43, 0xab9423a7); /* 51 */
+                II(ref b, c, d, a, x[k + 5], S44, 0xfc93a039); /* 52 */
+                II(ref a, b, c, d, x[k + 12], S41, 0x655b59c3); /* 53 */
+                II(ref d, a, b, c, x[k + 3], S42, 0x8f0ccc92); /* 54 */
+                II(ref c, d, a, b, x[k + 10], S43, 0xffeff47d); /* 55 */
+                II(ref b, c, d, a, x[k + 1], S44, 0x85845dd1); /* 56 */
+                II(ref a, b, c, d, x[k + 8], S41, 0x6fa87e4f); /* 57 */
+                II(ref d, a, b, c, x[k + 15], S42, 0xfe2ce6e0); /* 58 */
+                II(ref c, d, a, b, x[k + 6], S43, 0xa3014314); /* 59 */
+                II(ref b, c, d, a, x[k + 13], S44, 0x4e0811a1); /* 60 */
+                II(ref a, b, c, d, x[k + 4], S41, 0xf7537e82); /* 61 */
+                II(ref d, a, b, c, x[k + 11], S42, 0xbd3af235); /* 62 */
+                II(ref c, d, a, b, x[k + 2], S43, 0x2ad7d2bb); /* 63 */
+                II(ref b, c, d, a, x[k + 9], S44, 0xeb86d391); /* 64 */
+
+                A += a;
+                B += b;
+                C += c;
+                D += d;
+            }
+            return new[] { A, B, C, D };
+        }
+
+        #region MD5对数组数据加密
+
+        /// <summary>
+        ///     MD5对数组数据加密
+        /// </summary>
+        /// <param name="input">包含需要加密的数据的数组</param>
+        /// <returns>加密后的字节流</returns>
+        public static byte[] MD5Array(this byte[] input)
+        {
+            MD5_Init();
+            var block = MD5_Append(input);
+            var bits = MD5_Trasform(block);
+
+            var output = new byte[bits.Length * 4];
+            for (int i = 0, j = 0; i < bits.Length; i++, j += 4)
+            {
+                output[j] = (byte)(bits[i] & 0xff);
+                output[j + 1] = (byte)((bits[i] >> 8) & 0xff);
+                output[j + 2] = (byte)((bits[i] >> 16) & 0xff);
+                output[j + 3] = (byte)((bits[i] >> 24) & 0xff);
+            }
+            return output;
+        }
+
+        #endregion
+
+        #region 获取数组的Hex值
+
+        /// <summary>
+        ///     获取数组的Hex值
+        /// </summary>
+        /// <param name="array">需要求Hex值的数组</param>
+        /// <param name="uppercase">是否转大写</param>
+        /// <returns>字节数组的16进制表示</returns>
+        public static string ArrayToHexString(this byte[] array, bool uppercase)
+        {
+            var hexString = "";
+            var format = "x2";
+            if (uppercase)
+                format = "X2";
+            foreach (var b in array)
+                hexString += b.ToString(format);
+            return hexString;
+        }
+
+        #endregion
+
+        #region 对字符串进行MD5加密
+
+        /// <summary>
+        ///     对字符串进行MD5加密
+        /// </summary>
+        /// <param name="message">需要加密的字符串</param>
+        /// <returns>加密后的结果</returns>
+        public static string MDString(this string message)
+        {
+            var c = message.ToCharArray();
+            var b = new byte[c.Length];
+            for (var i = 0; i < c.Length; i++)
+                b[i] = (byte)c[i];
+            var digest = MD5Array(b);
+            return ArrayToHexString(digest, false);
+        }
+        /// <summary>
+        ///     对字符串进行MD5二次加密
+        /// </summary>
+        /// <param name="message">需要加密的字符串</param>
+        /// <returns>加密后的结果</returns>
+        public static string MDString2(this string message) => MDString(MDString(message));
+
+        /// <summary>
+        /// MD5 三次加密算法
+        /// </summary>
+        /// <param name="s">需要加密的字符串</param>
+        /// <returns>MD5字符串</returns>
+        public static string MDString3(this string s)
+        {
+            MD5 md5 = MD5.Create();
+            byte[] bytes = Encoding.ASCII.GetBytes(s);
+            byte[] bytes1 = md5.ComputeHash(bytes);
+            byte[] bytes2 = md5.ComputeHash(bytes1);
+            byte[] bytes3 = md5.ComputeHash(bytes2);
+
+            StringBuilder sb = new StringBuilder();
+            foreach (var item in bytes3)
+            {
+                sb.Append(item.ToString("x").PadLeft(2, '0'));
+            }
+            return sb.ToString();
+        }
+        /// <summary>
+        ///     对字符串进行MD5加盐加密
+        /// </summary>
+        /// <param name="message">需要加密的字符串</param>
+        /// <param name="salt">盐</param>
+        /// <returns>加密后的结果</returns>
+        public static string MDString(this string message, string salt) => MDString(message + salt);
+
+        /// <summary>
+        ///     对字符串进行MD5二次加盐加密
+        /// </summary>
+        /// <param name="message">需要加密的字符串</param>
+        /// <param name="salt">盐</param>
+        /// <returns>加密后的结果</returns>
+        public static string MDString2(this string message, string salt) => MDString(MDString(message + salt), salt);
+
+        /// <summary>
+        /// MD5 三次加密算法
+        /// </summary>
+        /// <param name="s">需要加密的字符串</param>
+        /// <param name="salt">盐</param>
+        /// <returns>MD5字符串</returns>
+        public static string MDString3(this string s, string salt)
+        {
+            MD5 md5 = MD5.Create();
+            byte[] bytes = Encoding.ASCII.GetBytes(s + salt);
+            byte[] bytes1 = md5.ComputeHash(bytes);
+            byte[] bytes2 = md5.ComputeHash(bytes1);
+            byte[] bytes3 = md5.ComputeHash(bytes2);
+
+            StringBuilder sb = new StringBuilder();
+            foreach (var item in bytes3)
+            {
+                sb.Append(item.ToString("x").PadLeft(2, '0'));
+            }
+            return sb.ToString();
+        }
+        #endregion
+
+        #region 获取文件的MD5值
+
+        /// <summary>
+        /// 获取文件的MD5值
+        /// </summary>
+        /// <param name="fileName">需要求MD5值的文件的文件名及路径</param>
+        /// <returns>MD5字符串</returns>
+        public static string MDFile(this string fileName)
+        {
+            var fs = File.Open(fileName, FileMode.Open, FileAccess.Read);
+            var array = new byte[fs.Length];
+            fs.Read(array, 0, (int)fs.Length);
+            var digest = MD5Array(array);
+            fs.Close();
+            return ArrayToHexString(digest, false);
+        }
+
+        #endregion
+
+        #region 测试MD5加密算法的函数
+
+        /// <summary>
+        ///     测试MD5加密算法的函数
+        /// </summary>
+        /// <param name="message">需要加密的字符串</param>
+        /// <returns>加密后的 数据</returns>
+        private static string MD5Test(this string message)
+        {
+            return "rnMD5 (" + "message" + ") = " + MDString(message);
+        }
+
+        #endregion
+
+        #region MD5加密算法测试用数据
+
+        /// <summary>
+        ///     MD5加密算法测试用数据
+        /// </summary>
+        /// <returns> </returns>
+        private static string TestSuite()
+        {
+            var s = "";
+            s += MD5Test("");
+            s += MD5Test("a");
+            s += MD5Test("abc");
+            s += MD5Test("message digest");
+            s += MD5Test("abcdefghijklmnopqrstuvwxyz");
+            s += MD5Test("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+            s += MD5Test("12345678901234567890123456789012345678901234567890123456789012345678901234567890");
+            return s;
+        }
+
+        #endregion
+
+        #endregion MD5加密算法
+    }
+
+    /// <summary>
+    ///     RC2加密解密算法
+    /// </summary>
+    public static class RC2
+    {
+        private static ASCIIEncoding asciiEncoding;
+        private static byte[] iv;
+        private static byte[] key;
+        private static RC2CryptoServiceProvider rc2CSP;
+        private static UnicodeEncoding textConverter;
+
+        static RC2()
+        {
+            InitializeComponent();
+        }
+
+        private static void InitializeComponent()
+        {
+            key = new byte[] { 106, 51, 25, 141, 157, 142, 23, 111, 234, 159, 187, 154, 215, 34, 37, 204 };
+            iv = new byte[] { 135, 186, 133, 136, 184, 149, 153, 144 };
+            asciiEncoding = new ASCIIEncoding();
+            textConverter = new UnicodeEncoding();
+            rc2CSP = new RC2CryptoServiceProvider();
+        }
+
+        #region 新建一个大小为10261B的文件,以便将加密数据写入固定大小的文件。
+
+        /// <summary>
+        ///     新建一个大小为10261B的文件,以便将加密数据写入固定大小的文件。
+        /// </summary>
+        /// <param name="filePath">文件保存的地址,包含文件名</param>
+        public static string InitBinFile(this string filePath)
+        {
+            var tmp = new byte[10261];
+            try //创建文件流,将其内容全部写入0
+            {
+                var writeFileStream = new FileStream(filePath,
+                    FileMode.Create,
+                    FileAccess.Write,
+                    FileShare.None, 512, false);
+
+                for (var i = 0; i < 10261; i++)
+                    tmp[i] = 0;
+                writeFileStream.Write(tmp, 0, 10261);
+                writeFileStream.Flush();
+                writeFileStream.Close();
+            }
+            catch (IOException)
+            {
+                // MessageBox.Show("文件操作错误!", "错误!", MessageBoxButtons.OK, MessageBoxIcon.Error);
+                return "Error,file operation error!";
+            }
+            return "OK";
+        }
+
+        #endregion
+
+        #region 将文本数据加密后写入一个文件
+
+        /// <summary>
+        ///     将文本数据加密后写入一个文件,其中,这个文件是用InitBinFile建立的,这个文件将被分成十块,
+        ///     用来分别保存10组不同的数据,第一个byte位保留,第2位到第21位分别用来存放每块数据的长度,但
+        ///     一个byte的取值为0-127,所以,用两个byte来存放一个长度。
+        /// </summary>
+        /// <param name="toEncryptText">要加密的文本数据</param>
+        /// <param name="filePath">要写入的文件</param>
+        /// <param name="dataIndex">写入第几块,取值为1--10</param>
+        /// <returns>是否操作成功</returns>
+        public static bool EncryptToFile(this string toEncryptText, string filePath, int dataIndex)
+        {
+            var r = false;
+            if ((dataIndex > 10) && (dataIndex < 1))
+                return r;
+            byte[] encrypted;
+            //打开要写入的文件,主要是为了保持原文件的内容不丢失
+            var tmpFileStream = new FileStream(filePath,
+                FileMode.Open,
+                FileAccess.Read,
+                FileShare.None, 1024, true);
+
+            var index = new byte[10261];
+            //将读取的内容写到byte数组
+            tmpFileStream.Read(index, 0, 10261);
+            tmpFileStream.Close();
+            //定义基本的加密转换运算
+            var Encryptor = rc2CSP.CreateEncryptor(key, iv);
+            var msEncrypt = new MemoryStream();
+            //在此加密转换流中,加密将从csEncrypt,加密后,结果在msEncrypt流中。
+            var csEncrypt = new CryptoStream(msEncrypt,
+                Encryptor, CryptoStreamMode.Write);
+            //将要加密的文本转换成UTF-16 编码,保存在tmp数组。
+            var tmp = textConverter.GetBytes(toEncryptText);
+            //将tmp输入csEncrypt,将通过Encryptor来加密。
+            csEncrypt.Write(tmp, 0, tmp.Length);
+            //输出到msEnctypt
+            csEncrypt.FlushFinalBlock();
+            //将流转成byte[]
+            encrypted = msEncrypt.ToArray();
+            if (encrypted.Length > 1024)
+                return false;
+            //得到加密后数据的大小,将结果存在指定的位置。
+            index[dataIndex * 2 - 1] = Convert.ToByte(Convert.ToString(encrypted.Length / 128));
+            index[dataIndex * 2] = Convert.ToByte(Convert.ToString(encrypted.Length % 128));
+            //将加密后的结果写入index(覆盖)
+            for (var i = 0; i < encrypted.Length; i++)
+                index[1024 * (dataIndex - 1) + 21 + i] = encrypted[i];
+            //建立文件流
+            tmpFileStream = new FileStream(filePath,
+                FileMode.Truncate,
+                FileAccess.Write,
+                FileShare.None, 1024, true);
+            //写文件
+            tmpFileStream.Write(index, 0, 10261);
+            tmpFileStream.Flush();
+            r = true;
+            tmpFileStream.Close();
+            return r;
+        }
+
+        #endregion
+
+        #region 从一个文件中解密出一段文本,其中,这个文件是由InitBinFile建立的,并且由 EncryptToFile加密的
+
+        /// <summary>
+        ///     从一个文件中解密出一段文本,其中,这个文件是由InitBinFile建立的,并且由 EncryptToFile加密的
+        /// </summary>
+        /// <param name="filePath">要解密的文件</param>
+        /// <param name="dataIndex">要从哪一个块中解密</param>
+        /// <returns>解密后的文本</returns>
+        public static string DecryptFromFile(this string filePath, int dataIndex)
+        {
+            var r = "";
+            if ((dataIndex > 10) && (dataIndex < 1))
+                return r;
+            byte[] decrypted;
+            var tmpFileStream = new FileStream(filePath,
+                FileMode.Open,
+                FileAccess.Read,
+                FileShare.None, 1024, true);
+
+            var Decryptor = rc2CSP.CreateDecryptor(key, iv);
+            var msDecrypt = new MemoryStream();
+            var csDecrypt = new CryptoStream(msDecrypt,
+                Decryptor, CryptoStreamMode.Write);
+            var index = new byte[10261];
+
+            tmpFileStream.Read(index, 0, 10261);
+            var startIndex = 1024 * (dataIndex - 1) + 21;
+            var count = index[dataIndex * 2 - 1] * 128 + index[dataIndex * 2];
+            var tmp = new byte[count];
+
+            Array.Copy(index, 1024 * (dataIndex - 1) + 21, tmp, 0, count);
+            csDecrypt.Write(tmp, 0, count);
+            csDecrypt.FlushFinalBlock();
+            decrypted = msDecrypt.ToArray();
+            r = textConverter.GetString(decrypted, 0, decrypted.Length);
+            tmpFileStream.Close();
+            return r;
+        }
+
+        #endregion
+
+        #region 将一段文本加密后保存到一个文件
+
+        /// <summary>
+        ///     将一段文本加密后保存到一个文件
+        /// </summary>
+        /// <param name="toEncryptText">要加密的文本数据</param>
+        /// <param name="filePath">要保存的文件</param>
+        /// <returns>是否加密成功</returns>
+        public static bool EncryptToFile(this string toEncryptText, string filePath)
+        {
+            var r = false;
+            byte[] encrypted;
+            var tmpFileStream = new FileStream(filePath,
+                FileMode.OpenOrCreate,
+                FileAccess.Write,
+                FileShare.None, 1024, true);
+
+            var Encryptor = rc2CSP.CreateEncryptor(key, iv);
+            var msEncrypt = new MemoryStream();
+            var csEncrypt = new CryptoStream(msEncrypt,
+                Encryptor, CryptoStreamMode.Write);
+
+            var tmp = textConverter.GetBytes(toEncryptText);
+            csEncrypt.Write(tmp, 0, tmp.Length);
+            csEncrypt.FlushFinalBlock();
+            encrypted = msEncrypt.ToArray();
+            tmpFileStream.Write(encrypted, 0, encrypted.Length);
+            tmpFileStream.Flush();
+            r = true;
+            tmpFileStream.Close();
+            return r;
+        }
+
+        #endregion
+
+        #region 将一个被加密的文件解密
+
+        /// <summary>
+        ///     将一个被加密的文件解密
+        /// </summary>
+        /// <param name="filePath">要解密的文件</param>
+        /// <returns>解密后的文本</returns>
+        public static string DecryptFromFile(this string filePath)
+        {
+            var r = "";
+            byte[] decrypted;
+            var tmpFileStream = new FileStream(filePath,
+                FileMode.Open,
+                FileAccess.Read,
+                FileShare.None, 1024, true);
+            var Decryptor = rc2CSP.CreateDecryptor(key, iv);
+            var msDecrypt = new MemoryStream();
+            var csDecrypt = new CryptoStream(msDecrypt,
+                Decryptor, CryptoStreamMode.Write);
+
+            var tmp = new byte[tmpFileStream.Length];
+            tmpFileStream.Read(tmp, 0, tmp.Length);
+            csDecrypt.Write(tmp, 0, tmp.Length);
+            csDecrypt.FlushFinalBlock();
+            decrypted = msDecrypt.ToArray();
+            r = textConverter.GetString(decrypted, 0, decrypted.Length);
+            tmpFileStream.Close();
+            return r;
+        }
+
+        #endregion
+
+        #region 将文本数据加密后写入一个文件
+
+        /// <summary>
+        ///     将文本数据加密后写入一个文件,其中,这个文件是用InitBinFile建立的,这个文件将被分成十块,
+        ///     用来分别保存10组不同的数据,第一个byte位保留,第2位到第21位分别用来存放每块数据的长度,但
+        ///     一个byte的取值为0-127,所以,用两个byte来存放一个长度。
+        /// </summary>
+        /// <param name="toEncryptText">要加密的文本数据</param>
+        /// <param name="filePath">要写入的文件</param>
+        /// <param name="dataIndex">写入第几块,取值为1--10</param>
+        /// <param name="IV">初始化向量</param>
+        /// <param name="Key">加密密匙</param>
+        /// <returns>是否操作成功</returns>
+        public static bool EncryptToFile(this string toEncryptText, string filePath, int dataIndex, byte[] IV, byte[] Key)
+        {
+            var r = false;
+            if ((dataIndex > 10) && (dataIndex < 1))
+                return r;
+            byte[] encrypted;
+            //打开要写入的文件,主要是为了保持原文件的内容不丢失
+            var tmpFileStream = new FileStream(filePath,
+                FileMode.Open,
+                FileAccess.Read,
+                FileShare.None, 1024, true);
+
+            var index = new byte[10261];
+            //将读取的内容写到byte数组
+            tmpFileStream.Read(index, 0, 10261);
+            tmpFileStream.Close();
+            //定义基本的加密转换运算
+            var Encryptor = rc2CSP.CreateEncryptor(Key, IV);
+            var msEncrypt = new MemoryStream();
+            //在此加密转换流中,加密将从csEncrypt,加密后,结果在msEncrypt流中。
+            var csEncrypt = new CryptoStream(msEncrypt,
+                Encryptor, CryptoStreamMode.Write);
+            //将要加密的文本转换成UTF-16 编码,保存在tmp数组。
+            var tmp = textConverter.GetBytes(toEncryptText);
+            //将tmp输入csEncrypt,将通过Encryptor来加密。
+            csEncrypt.Write(tmp, 0, tmp.Length);
+            //输出到msEnctypt
+            csEncrypt.FlushFinalBlock();
+            //将流转成byte[]
+            encrypted = msEncrypt.ToArray();
+            if (encrypted.Length > 1024)
+                return false;
+            //得到加密后数据的大小,将结果存在指定的位置。
+            index[dataIndex * 2 - 1] = Convert.ToByte(Convert.ToString(encrypted.Length / 128));
+            index[dataIndex * 2] = Convert.ToByte(Convert.ToString(encrypted.Length % 128));
+            //将加密后的结果写入index(覆盖)
+            for (var i = 0; i < encrypted.Length; i++)
+                index[1024 * (dataIndex - 1) + 21 + i] = encrypted[i];
+            //建立文件流
+            tmpFileStream = new FileStream(filePath,
+                FileMode.Truncate,
+                FileAccess.Write,
+                FileShare.None, 1024, true);
+            //写文件
+            tmpFileStream.Write(index, 0, 10261);
+            tmpFileStream.Flush();
+            r = true;
+            tmpFileStream.Close();
+            return r;
+        }
+
+        #endregion
+
+        #region 从一个文件中解密出一段文本
+
+        /// <summary>
+        ///     从一个文件中解密出一段文本,其中,这个文件是由InitBinFile建立的,并且由 EncryptToFile加密的
+        /// </summary>
+        /// <param name="filePath">要解密的文件</param>
+        /// <param name="dataIndex">要从哪一个块中解密</param>
+        /// <param name="IV">初始化向量</param>
+        /// <param name="Key">解密密匙</param>
+        /// <returns>解密后的文本</returns>
+        public static string DecryptFromFile(this string filePath, int dataIndex, byte[] IV, byte[] Key)
+        {
+            var r = "";
+            if ((dataIndex > 10) && (dataIndex < 1))
+                return r;
+            byte[] decrypted;
+            var tmpFileStream = new FileStream(filePath,
+                FileMode.Open,
+                FileAccess.Read,
+                FileShare.None, 1024, true);
+
+            var Decryptor = rc2CSP.CreateDecryptor(Key, IV);
+            var msDecrypt = new MemoryStream();
+            var csDecrypt = new CryptoStream(msDecrypt,
+                Decryptor, CryptoStreamMode.Write);
+            var index = new byte[10261];
+
+            tmpFileStream.Read(index, 0, 10261);
+            var startIndex = 1024 * (dataIndex - 1) + 21;
+            var count = index[dataIndex * 2 - 1] * 128 + index[dataIndex * 2];
+            var tmp = new byte[count];
+
+            Array.Copy(index, 1024 * (dataIndex - 1) + 21, tmp, 0, count);
+            csDecrypt.Write(tmp, 0, count);
+            csDecrypt.FlushFinalBlock();
+            decrypted = msDecrypt.ToArray();
+            r = textConverter.GetString(decrypted, 0, decrypted.Length);
+            tmpFileStream.Close();
+            return r;
+        }
+
+        #endregion
+
+        #region 将一段文本加密后保存到一个文件
+
+        /// <summary>
+        ///     将一段文本加密后保存到一个文件
+        /// </summary>
+        /// <param name="toEncryptText">要加密的文本数据</param>
+        /// <param name="filePath">要保存的文件</param>
+        /// <param name="IV">初始化向量</param>
+        /// <param name="Key">加密密匙</param>
+        /// <returns>是否加密成功</returns>
+        public static bool EncryptToFile(this string toEncryptText, string filePath, byte[] IV, byte[] Key)
+        {
+            var r = false;
+            byte[] encrypted;
+            var tmpFileStream = new FileStream(filePath,
+                FileMode.OpenOrCreate,
+                FileAccess.Write,
+                FileShare.None, 1024, true);
+
+            var Encryptor = rc2CSP.CreateEncryptor(Key, IV);
+            var msEncrypt = new MemoryStream();
+            var csEncrypt = new CryptoStream(msEncrypt,
+                Encryptor, CryptoStreamMode.Write);
+
+            var tmp = textConverter.GetBytes(toEncryptText);
+            csEncrypt.Write(tmp, 0, tmp.Length);
+            csEncrypt.FlushFinalBlock();
+            encrypted = msEncrypt.ToArray();
+            tmpFileStream.Write(encrypted, 0, encrypted.Length);
+            tmpFileStream.Flush();
+            r = true;
+            tmpFileStream.Close();
+            return r;
+        }
+
+        #endregion
+
+        #region 将一个被加密的文件解密
+
+        /// <summary>
+        ///     将一个被加密的文件解密
+        /// </summary>
+        /// <param name="filePath">要解密的文件</param>
+        /// <param name="IV">初始化向量</param>
+        /// <param name="Key">解密密匙</param>
+        /// <returns>解密后的文本</returns>
+        public static string DecryptFromFile(this string filePath, byte[] IV, byte[] Key)
+        {
+            var r = "";
+            byte[] decrypted;
+            var tmpFileStream = new FileStream(filePath,
+                FileMode.Open,
+                FileAccess.Read,
+                FileShare.None, 1024, true);
+            var Decryptor = rc2CSP.CreateDecryptor(Key, IV);
+            var msDecrypt = new MemoryStream();
+            var csDecrypt = new CryptoStream(msDecrypt,
+                Decryptor, CryptoStreamMode.Write);
+
+            var tmp = new byte[tmpFileStream.Length];
+            tmpFileStream.Read(tmp, 0, tmp.Length);
+            csDecrypt.Write(tmp, 0, tmp.Length);
+            csDecrypt.FlushFinalBlock();
+            decrypted = msDecrypt.ToArray();
+            r = textConverter.GetString(decrypted, 0, decrypted.Length);
+            tmpFileStream.Close();
+            return r;
+        }
+
+        #endregion
+
+        #region 设置加密或解密的初始化向量
+
+        /// <summary>
+        ///     设置加密或解密的初始化向量
+        /// </summary>
+        /// <param name="s">长度等于8的ASCII字符集的字符串</param>
+        public static void SetIV(this string s)
+        {
+            if (s.Length != 8)
+            {
+                // MessageBox.Show("输入的字符串必须为长度为8的且属于ASCII字符集的字符串");
+                iv = null;
+                return;
+            }
+            try
+            {
+                iv = asciiEncoding.GetBytes(s);
+            }
+            catch (Exception)
+            {
+                // MessageBox.Show("输入的字符串必须为长度为8的且属于ASCII字符集的字符串");
+                iv = null;
+            }
+        }
+
+        #endregion
+
+        #region 设置加密或解密的密匙
+
+        /// <summary>
+        ///     设置加密或解密的密匙
+        /// </summary>
+        /// <param name="s">长度等于16的ASCII字符集的字符串</param>
+        public static void SetKey(this string s)
+        {
+            if (s.Length != 16)
+            {
+                // MessageBox.Show("输入的字符串必须为长度为16的且属于ASCII字符集的字符串");
+                key = null;
+                return;
+            }
+            try
+            {
+                key = asciiEncoding.GetBytes(s);
+            }
+            catch (Exception)
+            {
+                //MessageBox.Show("输入的字符串必须为长度为16的且属于ASCII字符集的字符串");
+                key = null;
+            }
+        }
+
+        #endregion
+    }
+
+    /// <summary>
+    ///     对称加密解密算法类
+    /// </summary>
+    public static class Rijndael
+    {
+        private static string Key;
+        private static SymmetricAlgorithm mobjCryptoService;
+
+        /// <summary>
+        ///     对称加密类的构造函数
+        /// </summary>
+        public static void SymmetricMethod()
+        {
+            mobjCryptoService = new RijndaelManaged();
+            Key = "Guz(%&hj7x89H$yuBI0456FtmaT5&fvHUFCy76*h%(HilJ$lhj!y6&(*jkP87jH7";
+        }
+
+        /// <summary>
+        ///     获得密钥
+        /// </summary>
+        /// <returns>密钥</returns>
+        private static byte[] GetLegalKey()
+        {
+            var sTemp = Key;
+            mobjCryptoService.GenerateKey();
+            var bytTemp = mobjCryptoService.Key;
+            var KeyLength = bytTemp.Length;
+            if (sTemp.Length > KeyLength)
+                sTemp = sTemp.Substring(0, KeyLength);
+            else if (sTemp.Length < KeyLength)
+                sTemp = sTemp.PadRight(KeyLength, ' ');
+            return Encoding.ASCII.GetBytes(sTemp);
+        }
+
+        /// <summary>
+        ///     获得初始向量IV
+        /// </summary>
+        /// <returns>初试向量IV</returns>
+        private static byte[] GetLegalIV()
+        {
+            var sTemp = "E4ghj*Ghg7!rNIfb&95GUY86GfghUber57HBh(u%g6HJ($jhWk7&!hg4ui%$hjk";
+            mobjCryptoService.GenerateIV();
+            var bytTemp = mobjCryptoService.IV;
+            var IVLength = bytTemp.Length;
+            if (sTemp.Length > IVLength)
+                sTemp = sTemp.Substring(0, IVLength);
+            else if (sTemp.Length < IVLength)
+                sTemp = sTemp.PadRight(IVLength, ' ');
+            return Encoding.ASCII.GetBytes(sTemp);
+        }
+
+        /// <summary>
+        ///     加密方法
+        /// </summary>
+        /// <param name="Source">待加密的串</param>
+        /// <returns>经过加密的串</returns>
+        public static string Encrypto(this string Source)
+        {
+            var bytIn = Encoding.UTF8.GetBytes(Source);
+            var ms = new MemoryStream();
+            mobjCryptoService.Key = GetLegalKey();
+            mobjCryptoService.IV = GetLegalIV();
+            var encrypto = mobjCryptoService.CreateEncryptor();
+            var cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Write);
+            cs.Write(bytIn, 0, bytIn.Length);
+            cs.FlushFinalBlock();
+            ms.Close();
+            var bytOut = ms.ToArray();
+            return Convert.ToBase64String(bytOut);
+        }
+
+        /// <summary>
+        ///     解密方法
+        /// </summary>
+        /// <param name="Source">待解密的串</param>
+        /// <returns>经过解密的串</returns>
+        public static string Decrypto(this string Source)
+        {
+            var bytIn = Convert.FromBase64String(Source);
+            var ms = new MemoryStream(bytIn, 0, bytIn.Length);
+            mobjCryptoService.Key = GetLegalKey();
+            mobjCryptoService.IV = GetLegalIV();
+            var encrypto = mobjCryptoService.CreateDecryptor();
+            var cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Read);
+            var sr = new StreamReader(cs);
+            return sr.ReadToEnd();
+        }
+    }
+}

+ 38 - 0
Masuit.Tools.Core/Security/HashEncode.cs

@@ -0,0 +1,38 @@
+using System;
+using System.Security.Cryptography;
+using System.Text;
+using Masuit.Tools.Win32;
+
+namespace Masuit.Tools.Security
+{
+    /// <summary>
+    /// 得到随机安全码(哈希加密)。
+    /// </summary>
+    public static class HashEncode
+    {
+        /// <summary>
+        /// 得到随机哈希加密字符串
+        /// </summary>
+        /// <returns>随机哈希加密字符串</returns>
+        public static string GetSecurity(this Random r) => HashEncoding(r.StrictNext().ToString());
+
+        /// <summary>
+        /// 哈希加密一个字符串
+        /// </summary>
+        /// <param name="security">需要加密的字符串</param>
+        /// <returns>加密后的数据</returns>
+        public static string HashEncoding(this string security)
+        {
+            var code = new UnicodeEncoding();
+            byte[] message = code.GetBytes(security);
+            var arithmetic = new SHA512Managed();
+            var value = arithmetic.ComputeHash(message);
+            var sb = new StringBuilder();
+            foreach (byte o in value)
+            {
+                sb.Append((int)o + "O");
+            }
+            return sb.ToString();
+        }
+    }
+}

+ 373 - 0
Masuit.Tools.Core/Security/RSACrypt.cs

@@ -0,0 +1,373 @@
+using System;
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace Masuit.Tools.Security
+{
+    /// <summary>
+    /// RSA密钥对
+    /// </summary>
+    public struct RsaKey
+    {
+        /// <summary>
+        /// 公钥
+        /// </summary>
+        public string PublicKey;
+
+        /// <summary>
+        /// 私钥
+        /// </summary>
+        public string PrivateKey;
+    }
+    /// <summary> 
+    /// RSA加密解密及RSA签名和验证
+    /// </summary> 
+    public static class RsaCrypt
+    {
+        #region RSA 加密解密 
+
+        #region RSA 的密钥产生 
+
+        /// <summary>
+        /// 生成 RSA 公钥和私钥
+        /// </summary>
+        public static RsaKey GenerateRsaKeys()
+        {
+            using (var rsa = new RSACryptoServiceProvider())
+            {
+                return new RsaKey { PrivateKey = rsa.ToXmlString(true), PublicKey = rsa.ToXmlString(false) };
+            }
+        }
+
+        #endregion
+
+        #region RSA的加密函数 
+
+        //############################################################################## 
+        //RSA 方式加密 
+        //说明KEY必须是XML的行式,返回的是字符串 
+        //在有一点需要说明!!该加密方式有 长度 限制的!! 
+        //############################################################################## 
+
+        //RSA的加密函数  string
+        /// <summary>
+        /// RSA的加密函数 string
+        /// </summary>
+        /// <param name="publicKey">公钥</param>
+        /// <param name="mStrEncryptString">需要加密的字符串</param>
+        /// <returns>加密后的内容</returns>
+        /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired. </exception>
+        public static string RSAEncrypt(this string mStrEncryptString, string publicKey)
+        {
+            var rsa = new RSACryptoServiceProvider();
+            rsa.FromXmlString(publicKey);
+            var plainTextBArray = new UnicodeEncoding().GetBytes(mStrEncryptString);
+            var cypherTextBArray = rsa.Encrypt(plainTextBArray, false);
+            return Convert.ToBase64String(cypherTextBArray);
+        }
+
+        //RSA的加密函数 byte[]
+        /// <summary>
+        /// RSA的加密函数 byte[]
+        /// </summary>
+        /// <param name="encryptString">需要加密的字节数组</param>
+        /// <param name="publicKey">公钥</param>
+        /// <returns>加密后的内容</returns>
+        /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired. </exception>
+        public static string RSAEncrypt(this byte[] encryptString, string publicKey)
+        {
+            var rsa = new RSACryptoServiceProvider();
+            rsa.FromXmlString(publicKey);
+            var cypherTextBArray = rsa.Encrypt(encryptString, false);
+            return Convert.ToBase64String(cypherTextBArray);
+        }
+
+        #endregion
+
+        #region RSA的解密函数 
+
+        //RSA的解密函数  string
+        /// <summary>
+        /// RSA的解密函数  string
+        /// </summary>
+        /// <param name="mStrDecryptString">需要解密的字符串</param>
+        /// <param name="privateKey">私钥</param>
+        /// <returns>解密后的内容</returns>
+        /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired. </exception>
+        public static string RSADecrypt(this string mStrDecryptString, string privateKey)
+        {
+            var rsa = new RSACryptoServiceProvider();
+            rsa.FromXmlString(privateKey);
+            var plainTextBArray = Convert.FromBase64String(mStrDecryptString);
+            var dypherTextBArray = rsa.Decrypt(plainTextBArray, false);
+            return new UnicodeEncoding().GetString(dypherTextBArray);
+        }
+
+        //RSA的解密函数  byte
+        /// <summary>
+        /// RSA的解密函数  byte
+        /// </summary>
+        /// <param name="decryptString">需要解密的字符串</param>
+        /// <param name="privateKey">私钥</param>
+        /// <returns>解密后的内容</returns>
+        /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired. </exception>
+        public static string RSADecrypt(this byte[] decryptString, string privateKey)
+        {
+            var rsa = new RSACryptoServiceProvider();
+            rsa.FromXmlString(privateKey);
+            var dypherTextBArray = rsa.Decrypt(decryptString, false);
+            return new UnicodeEncoding().GetString(dypherTextBArray);
+        }
+
+        #endregion
+
+        #endregion
+
+        #region RSA数字签名 
+
+        #region 获取Hash描述表 
+
+        //获取Hash描述表 
+        /// <summary>
+        /// 获取Hash描述表
+        /// </summary>
+        /// <param name="mStrSource">源数据</param>
+        /// <returns>Hash描述表</returns>
+        public static byte[] GetHashBytes(this string mStrSource)
+        {
+            //从字符串中取得Hash描述 
+            HashAlgorithm md5 = HashAlgorithm.Create("MD5");
+            var buffer = Encoding.UTF8.GetBytes(mStrSource);
+            return md5?.ComputeHash(buffer);
+        }
+
+        //获取Hash描述表 
+        /// <summary>
+        /// 获取Hash描述表
+        /// </summary>
+        /// <param name="mStrSource">源数据</param>
+        /// <returns>Hash描述表</returns>
+        public static string GetHashString(this string mStrSource)
+        {
+            //从字符串中取得Hash描述 
+            HashAlgorithm md5 = HashAlgorithm.Create("MD5");
+            var buffer = Encoding.UTF8.GetBytes(mStrSource);
+            var hashData = md5?.ComputeHash(buffer);
+            return Convert.ToBase64String(hashData);
+        }
+
+        //获取Hash描述表 
+        /// <summary>
+        /// 从文件流获取Hash描述表
+        /// </summary>
+        /// <param name="objFile">源文件</param>
+        /// <returns>Hash描述表</returns>
+        public static byte[] GetHashBytes(this FileStream objFile)
+        {
+            //从文件中取得Hash描述 
+            using (objFile)
+            {
+                HashAlgorithm md5 = HashAlgorithm.Create("MD5");
+                return md5?.ComputeHash(objFile);
+            }
+        }
+
+        //获取Hash描述表 
+        /// <summary>
+        /// 从文件流获取Hash描述表
+        /// </summary>
+        /// <param name="objFile">源文件</param>
+        /// <returns>Hash描述表</returns>
+        public static string GetHashString(this FileStream objFile)
+        {
+            //从文件中取得Hash描述 
+            using (objFile)
+            {
+                HashAlgorithm md5 = HashAlgorithm.Create("MD5");
+                var hashData = md5?.ComputeHash(objFile);
+                return Convert.ToBase64String(hashData);
+            }
+        }
+
+        #endregion
+
+        #region RSA签名 
+
+        //RSA签名 
+        /// <summary>
+        /// RSA签名
+        /// </summary>
+        /// <param name="hashbyteSignature">签名字节数据</param>
+        /// <param name="privateKey">私钥</param>
+        /// <returns>处理结果</returns>
+        /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired. </exception>
+        /// <exception cref="CryptographicUnexpectedOperationException">The key is null.-or- The hash algorithm is null. </exception>
+        public static byte[] SignatureBytes(this byte[] hashbyteSignature, string privateKey)
+        {
+            var rsa = new RSACryptoServiceProvider();
+            rsa.FromXmlString(privateKey);
+            var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa);
+            //设置签名的算法为MD5 
+            rsaFormatter.SetHashAlgorithm("MD5");
+            //执行签名 
+            return rsaFormatter.CreateSignature(hashbyteSignature);
+        }
+
+        //RSA签名 
+        /// <summary>
+        /// RSA签名
+        /// </summary>
+        /// <param name="hashbyteSignature">签名字节数据</param>
+        /// <param name="privateKey">私钥</param>
+        /// <returns>处理结果</returns>
+        /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired. </exception>
+        /// <exception cref="CryptographicUnexpectedOperationException">The key is null.-or- The hash algorithm is null. </exception>
+        public static string SignatureString(this byte[] hashbyteSignature, string privateKey)
+        {
+            var rsa = new RSACryptoServiceProvider();
+            rsa.FromXmlString(privateKey);
+            var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa);
+            //设置签名的算法为MD5 
+            rsaFormatter.SetHashAlgorithm("MD5");
+            //执行签名 
+            var encryptedSignatureData = rsaFormatter.CreateSignature(hashbyteSignature);
+            return Convert.ToBase64String(encryptedSignatureData);
+        }
+
+        //RSA签名 
+        /// <summary>
+        /// RSA签名
+        /// </summary>
+        /// <param name="mStrHashbyteSignature">签名字符串数据</param>
+        /// <param name="pStrKeyPrivate">私钥</param>
+        /// <returns>处理结果</returns>
+        /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired. </exception>
+        /// <exception cref="CryptographicUnexpectedOperationException">The key is null.-or- The hash algorithm is null. </exception>
+        public static byte[] SignatureBytes(this string mStrHashbyteSignature, string pStrKeyPrivate)
+        {
+            byte[] hashbyteSignature = Convert.FromBase64String(mStrHashbyteSignature);
+            var rsa = new RSACryptoServiceProvider();
+            rsa.FromXmlString(pStrKeyPrivate);
+            var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa);
+            //设置签名的算法为MD5 
+            rsaFormatter.SetHashAlgorithm("MD5");
+            //执行签名 
+            return rsaFormatter.CreateSignature(hashbyteSignature);
+        }
+
+        //RSA签名 
+        /// <summary>
+        /// RSA签名
+        /// </summary>
+        /// <param name="mStrHashbyteSignature">签名字符串数据</param>
+        /// <param name="pStrKeyPrivate">私钥</param>
+        /// <returns>处理结果</returns>
+        /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired. </exception>
+        /// <exception cref="CryptographicUnexpectedOperationException">The key is null.-or- The hash algorithm is null. </exception>
+        public static string SignatureString(this string mStrHashbyteSignature, string pStrKeyPrivate)
+        {
+            var hashbyteSignature = Convert.FromBase64String(mStrHashbyteSignature);
+            var rsa = new RSACryptoServiceProvider();
+            rsa.FromXmlString(pStrKeyPrivate);
+            var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa);
+            //设置签名的算法为MD5 
+            rsaFormatter.SetHashAlgorithm("MD5");
+            //执行签名 
+            var encryptedSignatureData = rsaFormatter.CreateSignature(hashbyteSignature);
+            return Convert.ToBase64String(encryptedSignatureData);
+        }
+
+        #endregion
+
+        #region RSA 签名验证 
+
+        /// <summary>
+        /// RSA 签名验证 
+        /// </summary>
+        /// <param name="deformatterData">反格式化字节数据</param>
+        /// <param name="publicKey">公钥</param>
+        /// <param name="hashbyteDeformatter">哈希字节数据</param>
+        /// <returns>处理结果</returns>
+        /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired. </exception>
+        /// <exception cref="CryptographicUnexpectedOperationException">The key is null.-or- The hash algorithm is null. </exception>
+        public static bool SignatureDeformatter(this byte[] deformatterData, string publicKey, byte[] hashbyteDeformatter)
+        {
+            var rsa = new RSACryptoServiceProvider();
+            rsa.FromXmlString(publicKey);
+            var rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
+            //指定解密的时候HASH算法为MD5 
+            rsaDeformatter.SetHashAlgorithm("MD5");
+            if (rsaDeformatter.VerifySignature(hashbyteDeformatter, deformatterData)) return true;
+            return false;
+        }
+
+        /// <summary>
+        /// RSA 签名验证 
+        /// </summary>
+        /// <param name="deformatterData">反格式化字节数据</param>
+        /// <param name="publicKey">公钥</param>
+        /// <param name="pStrHashbyteDeformatter">哈希字符串数据</param>
+        /// <returns>处理结果</returns>
+        /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired. </exception>
+        /// <exception cref="CryptographicUnexpectedOperationException">The key is null.-or- The hash algorithm is null. </exception>
+        public static bool SignatureDeformatter(this byte[] deformatterData, string publicKey, string pStrHashbyteDeformatter)
+        {
+            byte[] hashbyteDeformatter = Convert.FromBase64String(pStrHashbyteDeformatter);
+            var rsa = new RSACryptoServiceProvider();
+            rsa.FromXmlString(publicKey);
+            var rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
+            //指定解密的时候HASH算法为MD5 
+            rsaDeformatter.SetHashAlgorithm("MD5");
+            if (rsaDeformatter.VerifySignature(hashbyteDeformatter, deformatterData)) return true;
+            return false;
+        }
+
+        /// <summary>
+        /// RSA 签名验证
+        /// </summary>
+        /// <param name="pStrDeformatterData">反格式化字符串数据</param>
+        /// <param name="publicKey">公钥</param>
+        /// <param name="hashbyteDeformatter">哈希字节数据</param>
+        /// <returns>处理结果</returns>
+        /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired. </exception>
+        /// <exception cref="CryptographicUnexpectedOperationException">The key is null.-or- The hash algorithm is null. </exception>
+        public static bool SignatureDeformatter(this string pStrDeformatterData, string publicKey, byte[] hashbyteDeformatter)
+        {
+            var rsa = new RSACryptoServiceProvider();
+            rsa.FromXmlString(publicKey);
+            var rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
+            //指定解密的时候HASH算法为MD5 
+            rsaDeformatter.SetHashAlgorithm("MD5");
+            var deformatterData = Convert.FromBase64String(pStrDeformatterData);
+            if (rsaDeformatter.VerifySignature(hashbyteDeformatter, deformatterData)) return true;
+            return false;
+        }
+
+        /// <summary>
+        /// RSA 签名验证
+        /// </summary>
+        /// <param name="pStrDeformatterData">格式字符串数据</param>
+        /// <param name="publicKey">公钥</param>
+        /// <param name="pStrHashbyteDeformatter">哈希字符串数据</param>
+        /// <returns>处理结果</returns>
+        /// <exception cref="CryptographicException">The cryptographic service provider (CSP) cannot be acquired. </exception>
+        /// <exception cref="CryptographicUnexpectedOperationException">The key is null.-or- The hash algorithm is null. </exception>
+        public static bool SignatureDeformatter(this string pStrDeformatterData, string publicKey, string pStrHashbyteDeformatter)
+        {
+            byte[] hashbyteDeformatter = Convert.FromBase64String(pStrHashbyteDeformatter);
+            var rsa = new RSACryptoServiceProvider();
+            rsa.FromXmlString(publicKey);
+            var rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
+            //指定解密的时候HASH算法为MD5 
+            rsaDeformatter.SetHashAlgorithm("MD5");
+            var deformatterData = Convert.FromBase64String(pStrDeformatterData);
+            if (rsaDeformatter.VerifySignature(hashbyteDeformatter, deformatterData)) return true;
+            return false;
+        }
+
+        #endregion
+
+        #endregion
+    }
+}

+ 180 - 0
Masuit.Tools.Core/Systems/EnumExt.cs

@@ -0,0 +1,180 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Linq;
+using System.Reflection;
+
+namespace Masuit.Tools.Systems
+{
+    /// <summary>
+    /// 枚举扩展类
+    /// </summary>
+    public static class EnumExt
+    {
+        private static readonly ConcurrentDictionary<Type, Dictionary<int, string>> EnumNameValueDict = new ConcurrentDictionary<Type, Dictionary<int, string>>();
+        private static readonly ConcurrentDictionary<Type, Dictionary<string, int>> EnumValueNameDict = new ConcurrentDictionary<Type, Dictionary<string, int>>();
+        private static ConcurrentDictionary<string, Type> _enumTypeDict;
+
+        /// <summary>
+        /// 获取枚举对象Key与显示名称的字典
+        /// </summary>
+        /// <param name="enumType"></param>
+        /// <returns></returns>
+        public static Dictionary<int, string> GetDictionary(this Type enumType)
+        {
+            if (!enumType.IsEnum) throw new Exception("给定的类型不是枚举类型");
+            Dictionary<int, string> names = EnumNameValueDict.ContainsKey(enumType) ? EnumNameValueDict[enumType] : new Dictionary<int, string>();
+            if (names.Count == 0)
+            {
+                names = GetDictionaryItems(enumType);
+                EnumNameValueDict[enumType] = names;
+            }
+            return names;
+        }
+
+        private static Dictionary<int, string> GetDictionaryItems(Type enumType)
+        {
+            FieldInfo[] enumItems = enumType.GetFields(BindingFlags.Public | BindingFlags.Static);
+            Dictionary<int, string> names = new Dictionary<int, string>(enumItems.Length);
+            foreach (FieldInfo enumItem in enumItems)
+            {
+                int intValue = (int)enumItem.GetValue(enumType);
+                names[intValue] = enumItem.Name;
+            }
+            return names;
+        }
+
+        /// <summary>
+        /// 获取枚举对象显示名称与Key的字典
+        /// </summary>
+        /// <param name="enumType"></param>
+        /// <returns></returns>
+        public static Dictionary<string, int> GetValueItems(this Type enumType)
+        {
+            if (!enumType.IsEnum) throw new Exception("给定的类型不是枚举类型");
+            Dictionary<string, int> values = EnumValueNameDict.ContainsKey(enumType) ? EnumValueNameDict[enumType] : new Dictionary<string, int>();
+            if (values.Count == 0)
+            {
+                values = GetValueNameItems(enumType);
+                EnumValueNameDict[enumType] = values;
+            }
+            return values;
+        }
+
+        private static Dictionary<string, int> GetValueNameItems(Type enumType)
+        {
+            FieldInfo[] enumItems = enumType.GetFields(BindingFlags.Public | BindingFlags.Static);
+            Dictionary<string, int> values = new Dictionary<string, int>(enumItems.Length);
+            foreach (FieldInfo enumItem in enumItems)
+            {
+                values[enumItem.Name] = (int)enumItem.GetValue(enumType);
+            }
+            return values;
+        }
+
+
+        /// <summary>
+        /// 获取枚举对象的值内容
+        /// </summary>
+        /// <param name="enumType"></param>
+        /// <param name="name"></param>
+        /// <returns></returns>
+        public static int GetValue(this Type enumType, string name)
+        {
+            if (!enumType.IsEnum) throw new Exception("给定的类型不是枚举类型");
+            Dictionary<string, int> enumDict = GetValueNameItems(enumType);
+            return enumDict.ContainsKey(name) ? enumDict[name] : enumDict.Select(d => d.Value).FirstOrDefault();
+        }
+
+        /// <summary>
+        /// 获取枚举类型
+        /// </summary>
+        /// <param name="assembly"></param>
+        /// <param name="typeName"></param>
+        /// <returns></returns>
+        public static Type GetEnumType(Assembly assembly, string typeName)
+        {
+            _enumTypeDict = _enumTypeDict ?? LoadEnumTypeDict(assembly);
+            if (_enumTypeDict.ContainsKey(typeName))
+            {
+                return _enumTypeDict[typeName];
+            }
+            return null;
+        }
+
+        private static ConcurrentDictionary<string, Type> LoadEnumTypeDict(Assembly assembly)
+        {
+            Type[] typeArray = assembly.GetTypes();
+            Dictionary<string, Type> dict = typeArray.Where(o => o.IsEnum).ToDictionary(o => o.Name, o => o);
+            return new ConcurrentDictionary<string, Type>(dict);
+        }
+
+
+        /// <summary>
+        /// 根据枚举成员获取自定义属性EnumDisplayNameAttribute的属性DisplayName
+        /// </summary>
+        /// <returns></returns>
+        public static Dictionary<string, int> GetDescriptionAndValue(this Type enumType)
+        {
+            Dictionary<string, int> dicResult = new Dictionary<string, int>();
+            foreach (object e in Enum.GetValues(enumType))
+            {
+                dicResult.Add(GetDescription(e as Enum), (int)e);
+            }
+            return dicResult;
+        }
+
+        /// <summary>
+        /// 根据枚举成员获取DescriptionAttribute的属性Description
+        /// </summary>
+        /// <returns></returns>
+        public static string GetDescription(this Enum en)
+        {
+            Type type = en.GetType(); //获取类型  
+            MemberInfo[] memberInfos = type.GetMember(en.ToString()); //获取成员  
+            if (memberInfos.Any())
+            {
+                DescriptionAttribute[] attrs = memberInfos[0].GetCustomAttributes(typeof(DescriptionAttribute), false) as DescriptionAttribute[]; //获取描述特性  
+                if (attrs != null && attrs.Length > 0)
+                {
+                    return attrs[0].Description; //返回当前描述  
+                }
+            }
+            return en.ToString();
+        }
+
+        /// <summary>  
+        /// 扩展方法:根据枚举值得到相应的枚举定义字符串  
+        /// </summary>  
+        /// <param name="value"></param>  
+        /// <param name="enumType"></param>  
+        /// <returns></returns>  
+        public static String ToEnumString(this int value, Type enumType)
+        {
+            NameValueCollection nvc = GetEnumStringFromEnumValue(enumType);
+            return nvc[value.ToString()];
+        }
+
+        /// <summary>  
+        /// 根据枚举类型得到其所有的 值 与 枚举定义字符串 的集合  
+        /// </summary>  
+        /// <param name="enumType"></param>  
+        /// <returns></returns>  
+        public static NameValueCollection GetEnumStringFromEnumValue(Type enumType)
+        {
+            NameValueCollection nvc = new NameValueCollection();
+            FieldInfo[] fields = enumType.GetFields();
+            foreach (FieldInfo field in fields)
+            {
+                if (field.FieldType.IsEnum)
+                {
+                    var strValue = ((int)enumType.InvokeMember(field.Name, BindingFlags.GetField, null, null, null)).ToString();
+                    nvc.Add(strValue, field.Name);
+                }
+            }
+            return nvc;
+        }
+    }
+}

+ 71 - 0
Masuit.Tools.Core/Win32/WindowsCommand.cs

@@ -0,0 +1,71 @@
+using System;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Security.Cryptography;
+
+namespace Masuit.Tools.Win32
+{
+    /// <summary>
+    /// 命令提示符
+    /// </summary>
+    public static class WindowsCommand
+    {
+
+        /// <summary>
+        /// 生成真正的随机数
+        /// </summary>
+        /// <param name="r"></param>
+        /// <param name="seed"></param>
+        /// <returns></returns>
+        public static int StrictNext(this Random r, int seed = Int32.MaxValue)
+        {
+            byte[] b = new byte[4];
+            new RNGCryptoServiceProvider().GetBytes(b);
+            return new Random(BitConverter.ToInt32(b, 0)).Next(seed);
+        }
+
+        /// <summary>
+        /// 执行一个控制台程序,并获取在控制台返回的数据
+        /// </summary>
+        /// <param name="dosCommand">dos/cmd命令</param>
+        /// <param name="outtime">等待执行时间毫秒值,默认不等待</param>
+        /// <returns>控制台输出信息</returns>
+        /// <exception cref="SystemException">尚未设置进程 <see cref="P:System.Diagnostics.Process.Id" />,而且不存在可从其确定 <see cref="P:System.Diagnostics.Process.Id" /> 属性的 <see cref="P:System.Diagnostics.Process.Handle" />。- 或 -没有与此 <see cref="T:System.Diagnostics.Process" /> 对象关联的进程。- 或 -您正尝试为远程计算机上运行的进程调用 <see cref="M:System.Diagnostics.Process.WaitForExit(System.Int32)" />。此方法仅对本地计算机上运行的进程可用。</exception>
+        /// <exception cref="Win32Exception">未能访问该等待设置。</exception>
+        /// <exception cref="Exception">命令参数无效,必须传入一个控制台能被cmd.exe可执行程序; 如:ping 127.0.0.1</exception>
+        public static string Execute(string dosCommand, int outtime = 0)
+        {
+            string output = "";
+            if (!string.IsNullOrEmpty(dosCommand))
+            {
+                using (Process process = new Process()) //创建进程对象  
+                {
+                    ProcessStartInfo startinfo = new ProcessStartInfo(); //创建进程时使用的一组值,如下面的属性  
+                    startinfo.FileName = "cmd.exe"; //设定需要执行的命令程序  
+                    //以下是隐藏cmd窗口的方法  
+                    startinfo.Arguments = "/c" + dosCommand; //设定参数,要输入到命令程序的字符,其中"/c"表示执行完命令后马上退出  
+                    startinfo.UseShellExecute = false; //不使用系统外壳程序启动  
+                    startinfo.RedirectStandardInput = false; //不重定向输入  
+                    startinfo.RedirectStandardOutput = true; //重定向输出,而不是默认的显示在dos控制台上  
+                    startinfo.CreateNoWindow = true; //不创建窗口  
+                    process.StartInfo = startinfo;
+
+                    if (process.Start()) //开始进程  
+                    {
+                        if (outtime == 0)
+                        {
+                            process.WaitForExit();
+                        }
+                        else
+                        {
+                            process.WaitForExit(outtime);
+                        }
+                        output = process.StandardOutput.ReadToEnd(); //读取进程的输出  
+                    }
+                }
+                return output;
+            }
+            throw new Exception("命令参数无效,必须传入一个控制台能被cmd.exe可执行程序;\n如:ping 127.0.0.1");
+        }
+    }
+}

+ 7 - 0
Masuit.Tools.NoSQL.MongoDBClient.Core/Masuit.Tools.NoSQL.MongoDBClient.Core.csproj

@@ -0,0 +1,7 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netstandard2.0</TargetFramework>
+  </PropertyGroup>
+
+</Project>

+ 789 - 0
Masuit.Tools.NoSQL.MongoDBClient.Core/MongoDbClient.cs

@@ -0,0 +1,789 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Threading.Tasks;
+using MongoDB.Bson;
+using MongoDB.Driver;
+
+namespace Masuit.Tools.NoSQL.MongoDBClient
+{
+    public class MongoDbClient
+    {
+        public MongoClient Client { get; set; }
+        public IMongoDatabase Database { get; set; }
+        private static readonly object LockObj = new object();
+        private static MongoDbClient Instance { get; set; }
+        private MongoDbClient(string url, string database)
+        {
+            Client = new MongoClient(url);
+            Database = Client.GetDatabase(database);
+        }
+
+        /// <summary>
+        /// 获取mongo单例
+        /// </summary>
+        /// <param name="url">连接字符串</param>
+        /// <param name="database">数据库</param>
+        /// <returns></returns>
+        public static MongoDbClient GetInstance(string url, string database)
+        {
+            if (Instance == null)
+            {
+                lock (LockObj)
+                {
+                    if (Instance == null)
+                    {
+                        Instance = new MongoDbClient(url, database);
+                    }
+                }
+            }
+            return Instance;
+        }
+
+        /// <summary>
+        /// 获取表
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collection">表名</param>
+        /// <returns></returns>
+        public IMongoCollection<T> GetCollection<T>(string collection)
+        {
+            return Database.GetCollection<T>(collection);
+        }
+
+        #region 插入
+
+        /// <summary>
+        /// 插入一条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collection">表名</param>
+        /// <param name="t">数据</param>
+        public void InsertOne<T>(string collection, T t)
+        {
+            Database.GetCollection<T>(collection).InsertOne(t);
+        }
+
+        /// <summary>
+        /// 插入一条数据
+        /// </summary>
+        /// <param name="collection">表名</param>
+        /// <param name="doc">文档</param>
+        public void InsertOne(string collection, BsonDocument doc)
+        {
+            Database.GetCollection<BsonDocument>(collection).InsertOne(doc);
+        }
+
+        /// <summary>
+        /// 插入一条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collection">表名</param>
+        /// <param name="t">数据</param>
+        public void InsertOneAsync<T>(string collection, T t)
+        {
+            Database.GetCollection<T>(collection).InsertOneAsync(t);
+        }
+
+        /// <summary>
+        /// 插入一条数据
+        /// </summary>
+        /// <param name="collection">表名</param>
+        /// <param name="doc">文档</param>
+        public void InsertOneAsync(string collection, BsonDocument doc)
+        {
+            Database.GetCollection<BsonDocument>(collection).InsertOneAsync(doc);
+        }
+
+        /// <summary>
+        /// 插入多条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collection">表名</param>
+        /// <param name="list">集合</param>
+        public void InsertMany<T>(string collection, IEnumerable<T> list)
+        {
+            Database.GetCollection<T>(collection).InsertMany(list);
+        }
+
+        /// <summary>
+        /// 插入多条数据
+        /// </summary>
+        /// <param name="collection">表名</param>
+        /// <param name="list">Bson集合</param>
+        public void InsertMany(string collection, IEnumerable<BsonDocument> list)
+        {
+            Database.GetCollection<BsonDocument>(collection).InsertMany(list);
+        }
+
+        /// <summary>
+        /// 插入多条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collection">表名</param>
+        /// <param name="list">集合</param>
+        public void InsertManyAsync<T>(string collection, IEnumerable<T> list)
+        {
+            Database.GetCollection<T>(collection).InsertManyAsync(list);
+        }
+
+        /// <summary>
+        /// 插入多条数据
+        /// </summary>
+        /// <param name="collection">表名</param>
+        /// <param name="list">Bson集合</param>
+        public void InsertManyAsync(string collection, IEnumerable<BsonDocument> list)
+        {
+            Database.GetCollection<BsonDocument>(collection).InsertManyAsync(list);
+        }
+
+        /// <summary>
+        /// 大批量插入数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collection">表名</param>
+        /// <param name="list">数据集合</param>
+        /// <returns></returns>
+        public List<WriteModel<T>> BulkInsert<T>(string collection, IEnumerable<WriteModel<T>> list)
+        {
+            BulkWriteResult<T> result = Database.GetCollection<T>(collection).BulkWrite(list);
+            return result.ProcessedRequests.ToList();
+        }
+
+        /// <summary>
+        /// 大批量插入数据
+        /// </summary>
+        /// <param name="collection">表名</param>
+        /// <param name="list">Bson数据集合</param>
+        /// <returns></returns>
+        public List<WriteModel<BsonDocument>> BulkInsert(string collection, IEnumerable<WriteModel<BsonDocument>> list)
+        {
+            BulkWriteResult<BsonDocument> result = Database.GetCollection<BsonDocument>(collection).BulkWrite(list);
+            return result.ProcessedRequests.ToList();
+        }
+
+        /// <summary>
+        /// 大批量插入数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collection">表名</param>
+        /// <param name="list">数据集合</param>
+        /// <returns></returns>
+        public async Task<List<WriteModel<T>>> BulkInsertAsync<T>(string collection, IEnumerable<WriteModel<T>> list)
+        {
+            BulkWriteResult<T> result = await Database.GetCollection<T>(collection).BulkWriteAsync(list);
+            return result.ProcessedRequests.ToList();
+        }
+
+        /// <summary>
+        /// 大批量插入数据
+        /// </summary>
+        /// <param name="collection">表名</param>
+        /// <param name="list">Bson数据集合</param>
+        /// <returns></returns>
+        public async Task<List<WriteModel<BsonDocument>>> BulkInsertAsync(string collection, IEnumerable<WriteModel<BsonDocument>> list)
+        {
+            BulkWriteResult<BsonDocument> result = await Database.GetCollection<BsonDocument>(collection).BulkWriteAsync(list);
+            return result.ProcessedRequests.ToList();
+        }
+
+        #endregion
+
+        #region 更新
+
+        /// <summary>
+        /// 修改一条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collection">表名</param>
+        /// <param name="filter">条件</param>
+        /// <param name="update">更新的数据</param>
+        /// <param name="upsert">如果它不存在是否插入文档</param>
+        /// <returns></returns>
+        public string UpdateOne<T>(string collection, Expression<Func<T, Boolean>> filter, UpdateDefinition<T> update, bool upsert)
+        {
+            UpdateResult result = Database.GetCollection<T>(collection).UpdateOne(filter, update, new UpdateOptions() { IsUpsert = upsert });
+            return result.ToJson();
+        }
+
+        /// <summary>
+        /// 修改一条数据
+        /// </summary>
+        /// <param name="collection">表名</param>
+        /// <param name="filter">条件</param>
+        /// <param name="update">更新的数据</param>
+        /// <param name="upsert">如果它不存在是否插入文档</param>
+        /// <returns></returns>
+        public string UpdateOne(string collection, Expression<Func<BsonDocument, Boolean>> filter, UpdateDefinition<BsonDocument> update, bool upsert)
+        {
+            UpdateResult result = Database.GetCollection<BsonDocument>(collection).UpdateOne(filter, update, new UpdateOptions() { IsUpsert = upsert });
+            return result.ToJson();
+        }
+
+        /// <summary>
+        /// 修改一条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collection">表名</param>
+        /// <param name="filter">条件</param>
+        /// <param name="update">更新的数据</param>
+        /// <param name="upsert">如果它不存在是否插入文档</param>
+        /// <returns></returns>
+        public async Task<string> UpdateOneAsync<T>(string collection, Expression<Func<T, Boolean>> filter, UpdateDefinition<T> update, bool upsert)
+        {
+            UpdateResult result = await Database.GetCollection<T>(collection).UpdateOneAsync(filter, update, new UpdateOptions() { IsUpsert = upsert });
+            return result.ToJson();
+        }
+
+        /// <summary>
+        /// 修改一条数据
+        /// </summary>
+        /// <param name="collection">表名</param>
+        /// <param name="filter">条件</param>
+        /// <param name="update">更新的数据</param>
+        /// <param name="upsert">如果它不存在是否插入文档</param>
+        /// <returns></returns>
+        public async Task<string> UpdateOneAsync(string collection, Expression<Func<BsonDocument, Boolean>> filter, UpdateDefinition<BsonDocument> update, bool upsert)
+        {
+            UpdateResult result = await Database.GetCollection<BsonDocument>(collection).UpdateOneAsync(filter, update, new UpdateOptions() { IsUpsert = upsert });
+            return result.ToJson();
+        }
+
+        /// <summary>
+        /// 修改文档
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="filter">修改条件</param>
+        /// <param name="update">修改结果</param>
+        /// <param name="upsert">是否插入新文档(filter条件满足就更新,否则插入新文档)</param>
+        /// <returns></returns>
+        public Int64 UpdateMany<T>(String collName, Expression<Func<T, Boolean>> filter, UpdateDefinition<T> update, Boolean upsert = false)
+        {
+            UpdateResult result = Database.GetCollection<T>(collName).UpdateMany(filter, update, new UpdateOptions { IsUpsert = upsert });
+            return result.ModifiedCount;
+        }
+
+        /// <summary>
+        /// 修改文档
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="filter">修改条件</param>
+        /// <param name="update">修改结果</param>
+        /// <param name="upsert">是否插入新文档(filter条件满足就更新,否则插入新文档)</param>
+        /// <returns></returns>
+        public Int64 UpdateMany(String collName, Expression<Func<BsonDocument, Boolean>> filter, UpdateDefinition<BsonDocument> update, Boolean upsert = false)
+        {
+            UpdateResult result = Database.GetCollection<BsonDocument>(collName).UpdateMany(filter, update, new UpdateOptions { IsUpsert = upsert });
+            return result.ModifiedCount;
+        }
+
+        /// <summary>
+        /// 修改多个文档
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">集合名称</param>
+        /// <param name="filter">修改条件</param>
+        /// <param name="update">修改结果</param>
+        /// <param name="upsert">是否插入新文档(filter条件满足就更新,否则插入新文档)</param>
+        /// <returns></returns>
+        public async Task<long> UpdateManyAsync<T>(String collName, Expression<Func<T, Boolean>> filter, UpdateDefinition<T> update, Boolean upsert = false)
+        {
+            UpdateResult result = await Database.GetCollection<T>(collName).UpdateManyAsync(filter, update, new UpdateOptions { IsUpsert = upsert });
+            return result.ModifiedCount;
+        }
+
+        /// <summary>
+        /// 修改多个文档
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="filter">修改条件</param>
+        /// <param name="update">修改结果</param>
+        /// <param name="upsert">是否插入新文档(filter条件满足就更新,否则插入新文档)</param>
+        /// <returns></returns>
+        public async Task<long> UpdateManyAsync(String collName, Expression<Func<BsonDocument, Boolean>> filter, UpdateDefinition<BsonDocument> update, Boolean upsert = false)
+        {
+            UpdateResult result = await Database.GetCollection<BsonDocument>(collName).UpdateManyAsync(filter, update, new UpdateOptions { IsUpsert = upsert });
+            return result.ModifiedCount;
+        }
+
+        /// <summary>
+        /// 修改文档
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <param name="update">更新后的数据</param>
+        /// <returns></returns>
+        public T UpdateOne<T>(String collName, Expression<Func<T, Boolean>> filter, UpdateDefinition<T> update)
+        {
+            T result = Database.GetCollection<T>(collName).FindOneAndUpdate(filter, update);
+            return result;
+        }
+
+        /// <summary>
+        /// 修改文档
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <param name="update">更新后的Bson数据</param>
+        /// <returns></returns>
+        public BsonDocument UpdateOne(String collName, Expression<Func<BsonDocument, Boolean>> filter, UpdateDefinition<BsonDocument> update)
+        {
+            BsonDocument result = Database.GetCollection<BsonDocument>(collName).FindOneAndUpdate(filter, update);
+            return result;
+        }
+
+        /// <summary>
+        /// 修改文档
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <param name="update">更新后的数据</param>
+        /// <returns></returns>
+        public async Task<T> UpdateOneAsync<T>(String collName, Expression<Func<T, Boolean>> filter, UpdateDefinition<T> update)
+        {
+            T result = await Database.GetCollection<T>(collName).FindOneAndUpdateAsync(filter, update);
+            return result;
+        }
+
+        /// <summary>
+        /// 修改文档
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <param name="update">更新后的Bson数据</param>
+        /// <returns></returns>
+        public async Task<BsonDocument> UpdateOneAsync(String collName, Expression<Func<BsonDocument, Boolean>> filter, UpdateDefinition<BsonDocument> update)
+        {
+            BsonDocument result = await Database.GetCollection<BsonDocument>(collName).FindOneAndUpdateAsync(filter, update);
+            return result;
+        }
+
+        #endregion
+
+        #region 删除
+
+        /// <summary>
+        /// 按BsonDocument条件删除
+        /// </summary>
+        /// <param name="collection">集合名称</param>
+        /// <param name="document">文档</param>
+        /// <returns></returns>
+        public Int64 Delete<T>(String collection, BsonDocument document)
+        {
+            DeleteResult result = Database.GetCollection<T>(collection).DeleteOne(document);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按BsonDocument条件删除
+        /// </summary>
+        /// <param name="collection">集合名称</param>
+        /// <param name="document">文档</param>
+        /// <returns></returns>
+        public Int64 Delete(String collection, BsonDocument document)
+        {
+            DeleteResult result = Database.GetCollection<BsonDocument>(collection).DeleteOne(document);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按BsonDocument条件删除
+        /// </summary>
+        /// <param name="collection">集合名称</param>
+        /// <param name="document">文档</param>
+        /// <returns></returns>
+        public async Task<long> DeleteAsync<T>(String collection, BsonDocument document)
+        {
+            DeleteResult result = await Database.GetCollection<T>(collection).DeleteOneAsync(document);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按BsonDocument条件删除
+        /// </summary>
+        /// <param name="collection">集合名称</param>
+        /// <param name="document">文档</param>
+        /// <returns></returns>
+        public async Task<long> DeleteAsync(String collection, BsonDocument document)
+        {
+            DeleteResult result = await Database.GetCollection<BsonDocument>(collection).DeleteOneAsync(document);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按json字符串删除
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="json">json字符串</param>
+        /// <returns></returns>
+        public Int64 Delete<T>(String collName, String json)
+        {
+            var result = Database.GetCollection<T>(collName).DeleteOne(json);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按json字符串删除
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="json">json字符串</param>
+        /// <returns></returns>
+        public Int64 Delete(String collName, String json)
+        {
+            var result = Database.GetCollection<BsonDocument>(collName).DeleteOne(json);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按json字符串删除
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="json">json字符串</param>
+        /// <returns></returns>
+        public async Task<long> DeleteAsync<T>(String collName, String json)
+        {
+            var result = await Database.GetCollection<T>(collName).DeleteOneAsync(json);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按json字符串删除
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="json">json字符串</param>
+        /// <returns></returns>
+        public async Task<long> DeleteAsync(String collName, String json)
+        {
+            var result = await Database.GetCollection<BsonDocument>(collName).DeleteOneAsync(json);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按条件表达式删除
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="predicate">条件表达式</param>
+        /// <returns></returns>
+        public Int64 Delete<T>(String collName, Expression<Func<T, Boolean>> predicate)
+        {
+            var result = Database.GetCollection<T>(collName).DeleteOne(predicate);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按条件表达式删除
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="predicate">条件表达式</param>
+        /// <returns></returns>
+        public Int64 Delete(String collName, Expression<Func<BsonDocument, Boolean>> predicate)
+        {
+            var result = Database.GetCollection<BsonDocument>(collName).DeleteOne(predicate);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按条件表达式删除
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="predicate">条件表达式</param>
+        /// <returns></returns>
+        public async Task<long> DeleteAsync<T>(String collName, Expression<Func<T, Boolean>> predicate)
+        {
+            var result = await Database.GetCollection<T>(collName).DeleteOneAsync(predicate);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按条件表达式删除
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="predicate">条件表达式</param>
+        /// <returns></returns>
+        public async Task<long> DeleteAsync(String collName, Expression<Func<BsonDocument, Boolean>> predicate)
+        {
+            var result = await Database.GetCollection<BsonDocument>(collName).DeleteOneAsync(predicate);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按检索条件删除
+        /// 建议用Builders&lt;T&gt;构建复杂的查询条件
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public Int64 Delete<T>(String collName, FilterDefinition<T> filter)
+        {
+            var result = Database.GetCollection<T>(collName).DeleteOne(filter);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按检索条件删除
+        /// 建议用Builders&lt;T&gt;构建复杂的查询条件
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public Int64 Delete(String collName, FilterDefinition<BsonDocument> filter)
+        {
+            var result = Database.GetCollection<BsonDocument>(collName).DeleteOne(filter);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按检索条件删除
+        /// 建议用Builders&lt;T&gt;构建复杂的查询条件
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<long> DeleteAsync<T>(String collName, FilterDefinition<T> filter)
+        {
+            var result = await Database.GetCollection<T>(collName).DeleteOneAsync(filter);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按检索条件删除
+        /// 建议用Builders&lt;T&gt;构建复杂的查询条件
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<long> DeleteAsync(String collName, FilterDefinition<BsonDocument> filter)
+        {
+            var result = await Database.GetCollection<BsonDocument>(collName).DeleteOneAsync(filter);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 删除一条记录
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public T DeleteOne<T>(String collName, Expression<Func<T, Boolean>> filter)
+        {
+            T result = Database.GetCollection<T>(collName).FindOneAndDelete(filter);
+            return result;
+        }
+
+        /// <summary>
+        /// 删除一条记录
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public BsonDocument DeleteOne(String collName, Expression<Func<BsonDocument, Boolean>> filter)
+        {
+            BsonDocument result = Database.GetCollection<BsonDocument>(collName).FindOneAndDelete(filter);
+            return result;
+        }
+
+        /// <summary>
+        /// 删除一条记录
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<T> DeleteOneAsync<T>(String collName, Expression<Func<T, Boolean>> filter)
+        {
+            T result = await Database.GetCollection<T>(collName).FindOneAndDeleteAsync(filter);
+            return result;
+        }
+
+        /// <summary>
+        /// 删除一条记录
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<BsonDocument> DeleteOneAsync(String collName, Expression<Func<BsonDocument, Boolean>> filter)
+        {
+            BsonDocument result = await Database.GetCollection<BsonDocument>(collName).FindOneAndDeleteAsync(filter);
+            return result;
+        }
+
+        #endregion
+
+        #region 查询 
+
+        /// <summary>
+        /// 查询,复杂查询直接用Linq处理
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <returns>要查询的对象</returns>
+        public IQueryable<T> GetQueryable<T>(String collName)
+        {
+            return Database.GetCollection<T>(collName).AsQueryable();
+        }
+
+        /// <summary>
+        /// 查询,复杂查询直接用Linq处理
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <returns>要查询的对象</returns>
+        public IQueryable<BsonDocument> GetQueryable(String collName)
+        {
+            return Database.GetCollection<BsonDocument>(collName).AsQueryable();
+        }
+
+        /// <summary>
+        /// 获取一条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public T Get<T>(String collName, FilterDefinition<T> filter)
+        {
+            IFindFluent<T, T> find = Database.GetCollection<T>(collName).Find(filter);
+            return find.FirstOrDefault();
+        }
+
+        /// <summary>
+        /// 获取一条数据
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public BsonDocument Get(String collName, FilterDefinition<BsonDocument> filter)
+        {
+            IFindFluent<BsonDocument, BsonDocument> find = Database.GetCollection<BsonDocument>(collName).Find(filter);
+            return find.FirstOrDefault();
+        }
+
+        /// <summary>
+        /// 获取一条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<T> GetAsync<T>(String collName, FilterDefinition<T> filter)
+        {
+            IAsyncCursor<T> find = await Database.GetCollection<T>(collName).FindAsync(filter);
+            return await find.FirstOrDefaultAsync();
+        }
+
+        /// <summary>
+        /// 获取一条数据
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<BsonDocument> GetAsync(String collName, FilterDefinition<BsonDocument> filter)
+        {
+            IAsyncCursor<BsonDocument> find = await Database.GetCollection<BsonDocument>(collName).FindAsync(filter);
+            return await find.FirstOrDefaultAsync();
+        }
+
+        /// <summary>
+        /// 获取多条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public IEnumerable<T> GetMany<T>(String collName, FilterDefinition<T> filter)
+        {
+            IFindFluent<T, T> find = Database.GetCollection<T>(collName).Find(filter);
+            return find.ToEnumerable();
+        }
+
+        /// <summary>
+        /// 获取多条数据
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public IEnumerable<BsonDocument> GetMany(String collName, FilterDefinition<BsonDocument> filter)
+        {
+            IFindFluent<BsonDocument, BsonDocument> find = Database.GetCollection<BsonDocument>(collName).Find(filter);
+            return find.ToEnumerable();
+        }
+
+        /// <summary>
+        /// 获取多条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<IEnumerable<T>> GetManyAsync<T>(String collName, FilterDefinition<T> filter)
+        {
+            IAsyncCursor<T> find = await Database.GetCollection<T>(collName).FindAsync(filter);
+            return find.ToEnumerable();
+        }
+
+        /// <summary>
+        /// 获取多条数据
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<IEnumerable<BsonDocument>> GetManyAsync(String collName, FilterDefinition<BsonDocument> filter)
+        {
+            IAsyncCursor<BsonDocument> find = await Database.GetCollection<BsonDocument>(collName).FindAsync(filter);
+            return find.ToEnumerable();
+        }
+
+        /// <summary>
+        /// 判断是否存在符合条件的数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public bool Any<T>(String collName, FilterDefinition<T> filter)
+        {
+            IFindFluent<T, T> find = Database.GetCollection<T>(collName).Find(filter);
+            return find.Any();
+        }
+
+        /// <summary>
+        /// 判断是否存在符合条件的数据
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public bool Any(String collName, FilterDefinition<BsonDocument> filter)
+        {
+            IFindFluent<BsonDocument, BsonDocument> find = Database.GetCollection<BsonDocument>(collName).Find(filter);
+            return find.Any();
+        }
+
+        /// <summary>
+        /// 判断是否存在符合条件的数据
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<bool> AnyAsync<T>(String collName, FilterDefinition<T> filter)
+        {
+            IAsyncCursor<T> find = await Database.GetCollection<T>(collName).FindAsync(filter);
+            return await find.AnyAsync();
+        }
+
+        /// <summary>
+        /// 判断是否存在符合条件的数据
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<bool> AnyAsync(String collName, FilterDefinition<BsonDocument> filter)
+        {
+            IAsyncCursor<BsonDocument> find = await Database.GetCollection<BsonDocument>(collName).FindAsync(filter);
+            return await find.AnyAsync();
+        }
+
+        #endregion
+    }
+}

+ 58 - 0
Masuit.Tools.NoSQL.MongoDBClient/Masuit.Tools.NoSQL.MongoDBClient.csproj

@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{1D45BDC4-74C4-4356-8B93-7F7A09106BB8}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Masuit.Tools.NoSQL.MongoDBClient</RootNamespace>
+    <AssemblyName>Masuit.Tools.NoSQL.MongoDBClient</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>bin\Release\Masuit.Tools.NoSQL.MongoDBClient.xml</DocumentationFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="MongoDB.Bson, Version=2.4.4.0, Culture=neutral, processorArchitecture=MSIL">
+      <HintPath>..\packages\MongoDB.Bson.2.4.4\lib\net45\MongoDB.Bson.dll</HintPath>
+    </Reference>
+    <Reference Include="MongoDB.Driver, Version=2.4.4.0, Culture=neutral, processorArchitecture=MSIL">
+      <HintPath>..\packages\MongoDB.Driver.2.4.4\lib\net45\MongoDB.Driver.dll</HintPath>
+    </Reference>
+    <Reference Include="MongoDB.Driver.Core, Version=2.4.4.0, Culture=neutral, processorArchitecture=MSIL">
+      <HintPath>..\packages\MongoDB.Driver.Core.2.4.4\lib\net45\MongoDB.Driver.Core.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="MongoDbClient.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="app.config" />
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>

+ 789 - 0
Masuit.Tools.NoSQL.MongoDBClient/MongoDbClient.cs

@@ -0,0 +1,789 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Threading.Tasks;
+using MongoDB.Bson;
+using MongoDB.Driver;
+
+namespace Masuit.Tools.NoSQL.MongoDBClient
+{
+    public class MongoDbClient
+    {
+        public MongoClient Client { get; set; }
+        public IMongoDatabase Database { get; set; }
+        private static readonly object LockObj = new object();
+        private static MongoDbClient Instance { get; set; }
+        private MongoDbClient(string url, string database)
+        {
+            Client = new MongoClient(url);
+            Database = Client.GetDatabase(database);
+        }
+
+        /// <summary>
+        /// 获取mongo单例
+        /// </summary>
+        /// <param name="url">连接字符串</param>
+        /// <param name="database">数据库</param>
+        /// <returns></returns>
+        public static MongoDbClient GetInstance(string url, string database)
+        {
+            if (Instance == null)
+            {
+                lock (LockObj)
+                {
+                    if (Instance == null)
+                    {
+                        Instance = new MongoDbClient(url, database);
+                    }
+                }
+            }
+            return Instance;
+        }
+
+        /// <summary>
+        /// 获取表
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collection">表名</param>
+        /// <returns></returns>
+        public IMongoCollection<T> GetCollection<T>(string collection)
+        {
+            return Database.GetCollection<T>(collection);
+        }
+
+        #region 插入
+
+        /// <summary>
+        /// 插入一条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collection">表名</param>
+        /// <param name="t">数据</param>
+        public void InsertOne<T>(string collection, T t)
+        {
+            Database.GetCollection<T>(collection).InsertOne(t);
+        }
+
+        /// <summary>
+        /// 插入一条数据
+        /// </summary>
+        /// <param name="collection">表名</param>
+        /// <param name="doc">文档</param>
+        public void InsertOne(string collection, BsonDocument doc)
+        {
+            Database.GetCollection<BsonDocument>(collection).InsertOne(doc);
+        }
+
+        /// <summary>
+        /// 插入一条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collection">表名</param>
+        /// <param name="t">数据</param>
+        public void InsertOneAsync<T>(string collection, T t)
+        {
+            Database.GetCollection<T>(collection).InsertOneAsync(t);
+        }
+
+        /// <summary>
+        /// 插入一条数据
+        /// </summary>
+        /// <param name="collection">表名</param>
+        /// <param name="doc">文档</param>
+        public void InsertOneAsync(string collection, BsonDocument doc)
+        {
+            Database.GetCollection<BsonDocument>(collection).InsertOneAsync(doc);
+        }
+
+        /// <summary>
+        /// 插入多条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collection">表名</param>
+        /// <param name="list">集合</param>
+        public void InsertMany<T>(string collection, IEnumerable<T> list)
+        {
+            Database.GetCollection<T>(collection).InsertMany(list);
+        }
+
+        /// <summary>
+        /// 插入多条数据
+        /// </summary>
+        /// <param name="collection">表名</param>
+        /// <param name="list">Bson集合</param>
+        public void InsertMany(string collection, IEnumerable<BsonDocument> list)
+        {
+            Database.GetCollection<BsonDocument>(collection).InsertMany(list);
+        }
+
+        /// <summary>
+        /// 插入多条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collection">表名</param>
+        /// <param name="list">集合</param>
+        public void InsertManyAsync<T>(string collection, IEnumerable<T> list)
+        {
+            Database.GetCollection<T>(collection).InsertManyAsync(list);
+        }
+
+        /// <summary>
+        /// 插入多条数据
+        /// </summary>
+        /// <param name="collection">表名</param>
+        /// <param name="list">Bson集合</param>
+        public void InsertManyAsync(string collection, IEnumerable<BsonDocument> list)
+        {
+            Database.GetCollection<BsonDocument>(collection).InsertManyAsync(list);
+        }
+
+        /// <summary>
+        /// 大批量插入数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collection">表名</param>
+        /// <param name="list">数据集合</param>
+        /// <returns></returns>
+        public List<WriteModel<T>> BulkInsert<T>(string collection, IEnumerable<WriteModel<T>> list)
+        {
+            BulkWriteResult<T> result = Database.GetCollection<T>(collection).BulkWrite(list);
+            return result.ProcessedRequests.ToList();
+        }
+
+        /// <summary>
+        /// 大批量插入数据
+        /// </summary>
+        /// <param name="collection">表名</param>
+        /// <param name="list">Bson数据集合</param>
+        /// <returns></returns>
+        public List<WriteModel<BsonDocument>> BulkInsert(string collection, IEnumerable<WriteModel<BsonDocument>> list)
+        {
+            BulkWriteResult<BsonDocument> result = Database.GetCollection<BsonDocument>(collection).BulkWrite(list);
+            return result.ProcessedRequests.ToList();
+        }
+
+        /// <summary>
+        /// 大批量插入数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collection">表名</param>
+        /// <param name="list">数据集合</param>
+        /// <returns></returns>
+        public async Task<List<WriteModel<T>>> BulkInsertAsync<T>(string collection, IEnumerable<WriteModel<T>> list)
+        {
+            BulkWriteResult<T> result = await Database.GetCollection<T>(collection).BulkWriteAsync(list);
+            return result.ProcessedRequests.ToList();
+        }
+
+        /// <summary>
+        /// 大批量插入数据
+        /// </summary>
+        /// <param name="collection">表名</param>
+        /// <param name="list">Bson数据集合</param>
+        /// <returns></returns>
+        public async Task<List<WriteModel<BsonDocument>>> BulkInsertAsync(string collection, IEnumerable<WriteModel<BsonDocument>> list)
+        {
+            BulkWriteResult<BsonDocument> result = await Database.GetCollection<BsonDocument>(collection).BulkWriteAsync(list);
+            return result.ProcessedRequests.ToList();
+        }
+
+        #endregion
+
+        #region 更新
+
+        /// <summary>
+        /// 修改一条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collection">表名</param>
+        /// <param name="filter">条件</param>
+        /// <param name="update">更新的数据</param>
+        /// <param name="upsert">如果它不存在是否插入文档</param>
+        /// <returns></returns>
+        public string UpdateOne<T>(string collection, Expression<Func<T, Boolean>> filter, UpdateDefinition<T> update, bool upsert)
+        {
+            UpdateResult result = Database.GetCollection<T>(collection).UpdateOne(filter, update, new UpdateOptions() { IsUpsert = upsert });
+            return result.ToJson();
+        }
+
+        /// <summary>
+        /// 修改一条数据
+        /// </summary>
+        /// <param name="collection">表名</param>
+        /// <param name="filter">条件</param>
+        /// <param name="update">更新的数据</param>
+        /// <param name="upsert">如果它不存在是否插入文档</param>
+        /// <returns></returns>
+        public string UpdateOne(string collection, Expression<Func<BsonDocument, Boolean>> filter, UpdateDefinition<BsonDocument> update, bool upsert)
+        {
+            UpdateResult result = Database.GetCollection<BsonDocument>(collection).UpdateOne(filter, update, new UpdateOptions() { IsUpsert = upsert });
+            return result.ToJson();
+        }
+
+        /// <summary>
+        /// 修改一条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collection">表名</param>
+        /// <param name="filter">条件</param>
+        /// <param name="update">更新的数据</param>
+        /// <param name="upsert">如果它不存在是否插入文档</param>
+        /// <returns></returns>
+        public async Task<string> UpdateOneAsync<T>(string collection, Expression<Func<T, Boolean>> filter, UpdateDefinition<T> update, bool upsert)
+        {
+            UpdateResult result = await Database.GetCollection<T>(collection).UpdateOneAsync(filter, update, new UpdateOptions() { IsUpsert = upsert });
+            return result.ToJson();
+        }
+
+        /// <summary>
+        /// 修改一条数据
+        /// </summary>
+        /// <param name="collection">表名</param>
+        /// <param name="filter">条件</param>
+        /// <param name="update">更新的数据</param>
+        /// <param name="upsert">如果它不存在是否插入文档</param>
+        /// <returns></returns>
+        public async Task<string> UpdateOneAsync(string collection, Expression<Func<BsonDocument, Boolean>> filter, UpdateDefinition<BsonDocument> update, bool upsert)
+        {
+            UpdateResult result = await Database.GetCollection<BsonDocument>(collection).UpdateOneAsync(filter, update, new UpdateOptions() { IsUpsert = upsert });
+            return result.ToJson();
+        }
+
+        /// <summary>
+        /// 修改文档
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="filter">修改条件</param>
+        /// <param name="update">修改结果</param>
+        /// <param name="upsert">是否插入新文档(filter条件满足就更新,否则插入新文档)</param>
+        /// <returns></returns>
+        public Int64 UpdateMany<T>(String collName, Expression<Func<T, Boolean>> filter, UpdateDefinition<T> update, Boolean upsert = false)
+        {
+            UpdateResult result = Database.GetCollection<T>(collName).UpdateMany(filter, update, new UpdateOptions { IsUpsert = upsert });
+            return result.ModifiedCount;
+        }
+
+        /// <summary>
+        /// 修改文档
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="filter">修改条件</param>
+        /// <param name="update">修改结果</param>
+        /// <param name="upsert">是否插入新文档(filter条件满足就更新,否则插入新文档)</param>
+        /// <returns></returns>
+        public Int64 UpdateMany(String collName, Expression<Func<BsonDocument, Boolean>> filter, UpdateDefinition<BsonDocument> update, Boolean upsert = false)
+        {
+            UpdateResult result = Database.GetCollection<BsonDocument>(collName).UpdateMany(filter, update, new UpdateOptions { IsUpsert = upsert });
+            return result.ModifiedCount;
+        }
+
+        /// <summary>
+        /// 修改多个文档
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">集合名称</param>
+        /// <param name="filter">修改条件</param>
+        /// <param name="update">修改结果</param>
+        /// <param name="upsert">是否插入新文档(filter条件满足就更新,否则插入新文档)</param>
+        /// <returns></returns>
+        public async Task<long> UpdateManyAsync<T>(String collName, Expression<Func<T, Boolean>> filter, UpdateDefinition<T> update, Boolean upsert = false)
+        {
+            UpdateResult result = await Database.GetCollection<T>(collName).UpdateManyAsync(filter, update, new UpdateOptions { IsUpsert = upsert });
+            return result.ModifiedCount;
+        }
+
+        /// <summary>
+        /// 修改多个文档
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="filter">修改条件</param>
+        /// <param name="update">修改结果</param>
+        /// <param name="upsert">是否插入新文档(filter条件满足就更新,否则插入新文档)</param>
+        /// <returns></returns>
+        public async Task<long> UpdateManyAsync(String collName, Expression<Func<BsonDocument, Boolean>> filter, UpdateDefinition<BsonDocument> update, Boolean upsert = false)
+        {
+            UpdateResult result = await Database.GetCollection<BsonDocument>(collName).UpdateManyAsync(filter, update, new UpdateOptions { IsUpsert = upsert });
+            return result.ModifiedCount;
+        }
+
+        /// <summary>
+        /// 修改文档
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <param name="update">更新后的数据</param>
+        /// <returns></returns>
+        public T UpdateOne<T>(String collName, Expression<Func<T, Boolean>> filter, UpdateDefinition<T> update)
+        {
+            T result = Database.GetCollection<T>(collName).FindOneAndUpdate(filter, update);
+            return result;
+        }
+
+        /// <summary>
+        /// 修改文档
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <param name="update">更新后的Bson数据</param>
+        /// <returns></returns>
+        public BsonDocument UpdateOne(String collName, Expression<Func<BsonDocument, Boolean>> filter, UpdateDefinition<BsonDocument> update)
+        {
+            BsonDocument result = Database.GetCollection<BsonDocument>(collName).FindOneAndUpdate(filter, update);
+            return result;
+        }
+
+        /// <summary>
+        /// 修改文档
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <param name="update">更新后的数据</param>
+        /// <returns></returns>
+        public async Task<T> UpdateOneAsync<T>(String collName, Expression<Func<T, Boolean>> filter, UpdateDefinition<T> update)
+        {
+            T result = await Database.GetCollection<T>(collName).FindOneAndUpdateAsync(filter, update);
+            return result;
+        }
+
+        /// <summary>
+        /// 修改文档
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <param name="update">更新后的Bson数据</param>
+        /// <returns></returns>
+        public async Task<BsonDocument> UpdateOneAsync(String collName, Expression<Func<BsonDocument, Boolean>> filter, UpdateDefinition<BsonDocument> update)
+        {
+            BsonDocument result = await Database.GetCollection<BsonDocument>(collName).FindOneAndUpdateAsync(filter, update);
+            return result;
+        }
+
+        #endregion
+
+        #region 删除
+
+        /// <summary>
+        /// 按BsonDocument条件删除
+        /// </summary>
+        /// <param name="collection">集合名称</param>
+        /// <param name="document">文档</param>
+        /// <returns></returns>
+        public Int64 Delete<T>(String collection, BsonDocument document)
+        {
+            DeleteResult result = Database.GetCollection<T>(collection).DeleteOne(document);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按BsonDocument条件删除
+        /// </summary>
+        /// <param name="collection">集合名称</param>
+        /// <param name="document">文档</param>
+        /// <returns></returns>
+        public Int64 Delete(String collection, BsonDocument document)
+        {
+            DeleteResult result = Database.GetCollection<BsonDocument>(collection).DeleteOne(document);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按BsonDocument条件删除
+        /// </summary>
+        /// <param name="collection">集合名称</param>
+        /// <param name="document">文档</param>
+        /// <returns></returns>
+        public async Task<long> DeleteAsync<T>(String collection, BsonDocument document)
+        {
+            DeleteResult result = await Database.GetCollection<T>(collection).DeleteOneAsync(document);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按BsonDocument条件删除
+        /// </summary>
+        /// <param name="collection">集合名称</param>
+        /// <param name="document">文档</param>
+        /// <returns></returns>
+        public async Task<long> DeleteAsync(String collection, BsonDocument document)
+        {
+            DeleteResult result = await Database.GetCollection<BsonDocument>(collection).DeleteOneAsync(document);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按json字符串删除
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="json">json字符串</param>
+        /// <returns></returns>
+        public Int64 Delete<T>(String collName, String json)
+        {
+            var result = Database.GetCollection<T>(collName).DeleteOne(json);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按json字符串删除
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="json">json字符串</param>
+        /// <returns></returns>
+        public Int64 Delete(String collName, String json)
+        {
+            var result = Database.GetCollection<BsonDocument>(collName).DeleteOne(json);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按json字符串删除
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="json">json字符串</param>
+        /// <returns></returns>
+        public async Task<long> DeleteAsync<T>(String collName, String json)
+        {
+            var result = await Database.GetCollection<T>(collName).DeleteOneAsync(json);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按json字符串删除
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="json">json字符串</param>
+        /// <returns></returns>
+        public async Task<long> DeleteAsync(String collName, String json)
+        {
+            var result = await Database.GetCollection<BsonDocument>(collName).DeleteOneAsync(json);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按条件表达式删除
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="predicate">条件表达式</param>
+        /// <returns></returns>
+        public Int64 Delete<T>(String collName, Expression<Func<T, Boolean>> predicate)
+        {
+            var result = Database.GetCollection<T>(collName).DeleteOne(predicate);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按条件表达式删除
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="predicate">条件表达式</param>
+        /// <returns></returns>
+        public Int64 Delete(String collName, Expression<Func<BsonDocument, Boolean>> predicate)
+        {
+            var result = Database.GetCollection<BsonDocument>(collName).DeleteOne(predicate);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按条件表达式删除
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="predicate">条件表达式</param>
+        /// <returns></returns>
+        public async Task<long> DeleteAsync<T>(String collName, Expression<Func<T, Boolean>> predicate)
+        {
+            var result = await Database.GetCollection<T>(collName).DeleteOneAsync(predicate);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按条件表达式删除
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="predicate">条件表达式</param>
+        /// <returns></returns>
+        public async Task<long> DeleteAsync(String collName, Expression<Func<BsonDocument, Boolean>> predicate)
+        {
+            var result = await Database.GetCollection<BsonDocument>(collName).DeleteOneAsync(predicate);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按检索条件删除
+        /// 建议用Builders&lt;T&gt;构建复杂的查询条件
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public Int64 Delete<T>(String collName, FilterDefinition<T> filter)
+        {
+            var result = Database.GetCollection<T>(collName).DeleteOne(filter);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按检索条件删除
+        /// 建议用Builders&lt;T&gt;构建复杂的查询条件
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public Int64 Delete(String collName, FilterDefinition<BsonDocument> filter)
+        {
+            var result = Database.GetCollection<BsonDocument>(collName).DeleteOne(filter);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按检索条件删除
+        /// 建议用Builders&lt;T&gt;构建复杂的查询条件
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<long> DeleteAsync<T>(String collName, FilterDefinition<T> filter)
+        {
+            var result = await Database.GetCollection<T>(collName).DeleteOneAsync(filter);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 按检索条件删除
+        /// 建议用Builders&lt;T&gt;构建复杂的查询条件
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<long> DeleteAsync(String collName, FilterDefinition<BsonDocument> filter)
+        {
+            var result = await Database.GetCollection<BsonDocument>(collName).DeleteOneAsync(filter);
+            return result.DeletedCount;
+        }
+
+        /// <summary>
+        /// 删除一条记录
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public T DeleteOne<T>(String collName, Expression<Func<T, Boolean>> filter)
+        {
+            T result = Database.GetCollection<T>(collName).FindOneAndDelete(filter);
+            return result;
+        }
+
+        /// <summary>
+        /// 删除一条记录
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public BsonDocument DeleteOne(String collName, Expression<Func<BsonDocument, Boolean>> filter)
+        {
+            BsonDocument result = Database.GetCollection<BsonDocument>(collName).FindOneAndDelete(filter);
+            return result;
+        }
+
+        /// <summary>
+        /// 删除一条记录
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<T> DeleteOneAsync<T>(String collName, Expression<Func<T, Boolean>> filter)
+        {
+            T result = await Database.GetCollection<T>(collName).FindOneAndDeleteAsync(filter);
+            return result;
+        }
+
+        /// <summary>
+        /// 删除一条记录
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<BsonDocument> DeleteOneAsync(String collName, Expression<Func<BsonDocument, Boolean>> filter)
+        {
+            BsonDocument result = await Database.GetCollection<BsonDocument>(collName).FindOneAndDeleteAsync(filter);
+            return result;
+        }
+
+        #endregion
+
+        #region 查询 
+
+        /// <summary>
+        /// 查询,复杂查询直接用Linq处理
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <returns>要查询的对象</returns>
+        public IQueryable<T> GetQueryable<T>(String collName)
+        {
+            return Database.GetCollection<T>(collName).AsQueryable();
+        }
+
+        /// <summary>
+        /// 查询,复杂查询直接用Linq处理
+        /// </summary>
+        /// <param name="collName">集合名称</param>
+        /// <returns>要查询的对象</returns>
+        public IQueryable<BsonDocument> GetQueryable(String collName)
+        {
+            return Database.GetCollection<BsonDocument>(collName).AsQueryable();
+        }
+
+        /// <summary>
+        /// 获取一条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public T Get<T>(String collName, FilterDefinition<T> filter)
+        {
+            IFindFluent<T, T> find = Database.GetCollection<T>(collName).Find(filter);
+            return find.FirstOrDefault();
+        }
+
+        /// <summary>
+        /// 获取一条数据
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public BsonDocument Get(String collName, FilterDefinition<BsonDocument> filter)
+        {
+            IFindFluent<BsonDocument, BsonDocument> find = Database.GetCollection<BsonDocument>(collName).Find(filter);
+            return find.FirstOrDefault();
+        }
+
+        /// <summary>
+        /// 获取一条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<T> GetAsync<T>(String collName, FilterDefinition<T> filter)
+        {
+            IAsyncCursor<T> find = await Database.GetCollection<T>(collName).FindAsync(filter);
+            return await find.FirstOrDefaultAsync();
+        }
+
+        /// <summary>
+        /// 获取一条数据
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<BsonDocument> GetAsync(String collName, FilterDefinition<BsonDocument> filter)
+        {
+            IAsyncCursor<BsonDocument> find = await Database.GetCollection<BsonDocument>(collName).FindAsync(filter);
+            return await find.FirstOrDefaultAsync();
+        }
+
+        /// <summary>
+        /// 获取多条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public IEnumerable<T> GetMany<T>(String collName, FilterDefinition<T> filter)
+        {
+            IFindFluent<T, T> find = Database.GetCollection<T>(collName).Find(filter);
+            return find.ToEnumerable();
+        }
+
+        /// <summary>
+        /// 获取多条数据
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public IEnumerable<BsonDocument> GetMany(String collName, FilterDefinition<BsonDocument> filter)
+        {
+            IFindFluent<BsonDocument, BsonDocument> find = Database.GetCollection<BsonDocument>(collName).Find(filter);
+            return find.ToEnumerable();
+        }
+
+        /// <summary>
+        /// 获取多条数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<IEnumerable<T>> GetManyAsync<T>(String collName, FilterDefinition<T> filter)
+        {
+            IAsyncCursor<T> find = await Database.GetCollection<T>(collName).FindAsync(filter);
+            return find.ToEnumerable();
+        }
+
+        /// <summary>
+        /// 获取多条数据
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<IEnumerable<BsonDocument>> GetManyAsync(String collName, FilterDefinition<BsonDocument> filter)
+        {
+            IAsyncCursor<BsonDocument> find = await Database.GetCollection<BsonDocument>(collName).FindAsync(filter);
+            return find.ToEnumerable();
+        }
+
+        /// <summary>
+        /// 判断是否存在符合条件的数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public bool Any<T>(String collName, FilterDefinition<T> filter)
+        {
+            IFindFluent<T, T> find = Database.GetCollection<T>(collName).Find(filter);
+            return find.Any();
+        }
+
+        /// <summary>
+        /// 判断是否存在符合条件的数据
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public bool Any(String collName, FilterDefinition<BsonDocument> filter)
+        {
+            IFindFluent<BsonDocument, BsonDocument> find = Database.GetCollection<BsonDocument>(collName).Find(filter);
+            return find.Any();
+        }
+
+        /// <summary>
+        /// 判断是否存在符合条件的数据
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<bool> AnyAsync<T>(String collName, FilterDefinition<T> filter)
+        {
+            IAsyncCursor<T> find = await Database.GetCollection<T>(collName).FindAsync(filter);
+            return await find.AnyAsync();
+        }
+
+        /// <summary>
+        /// 判断是否存在符合条件的数据
+        /// </summary>
+        /// <param name="collName">表名</param>
+        /// <param name="filter">条件</param>
+        /// <returns></returns>
+        public async Task<bool> AnyAsync(String collName, FilterDefinition<BsonDocument> filter)
+        {
+            IAsyncCursor<BsonDocument> find = await Database.GetCollection<BsonDocument>(collName).FindAsync(filter);
+            return await find.AnyAsync();
+        }
+
+        #endregion
+    }
+}

+ 36 - 0
Masuit.Tools.NoSQL.MongoDBClient/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("Masuit.Tools.NoSQL.MongoDBClient")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Masuit.Tools.NoSQL.MongoDBClient")]
+[assembly: AssemblyCopyright("Copyright ©  2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("1d45bdc4-74c4-4356-8b93-7f7a09106bb8")]
+
+// 程序集的版本信息由下列四个值组成: 
+//
+//      主版本
+//      次版本
+//      生成号
+//      修订号
+//
+// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
+//通过使用 "*",如下所示:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 11 - 0
Masuit.Tools.NoSQL.MongoDBClient/app.config

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <runtime>
+    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+      <dependentAssembly>
+        <assemblyIdentity name="System.Runtime.InteropServices.RuntimeInformation" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
+      </dependentAssembly>
+    </assemblyBinding>
+  </runtime>
+</configuration>

+ 7 - 0
Masuit.Tools.NoSQL.MongoDBClient/packages.config

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="MongoDB.Bson" version="2.4.4" targetFramework="net45" />
+  <package id="MongoDB.Driver" version="2.4.4" targetFramework="net45" />
+  <package id="MongoDB.Driver.Core" version="2.4.4" targetFramework="net45" />
+  <package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net45" />
+</packages>