添加项目文件。

This commit is contained in:
cmn
2025-11-27 16:58:03 +08:00
parent c5adc0a415
commit ee1bb22e95
23 changed files with 2447 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace TelegramService.Help
{
public class EntrustHelper
{
public delegate object SetTextcallBack(string action, object obj);
public static SetTextcallBack STCB;
}
}

View File

@@ -0,0 +1,745 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
namespace TelegramService.Help
{
public static class ExtendHelper
{
#region Exception
/// <summary>
/// 获取 错误信息
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string StackTrace(this Exception s, string str = null)
{
StackTrace st = new StackTrace(s, true);
//Get the first stack frame
// StackFrame frame = st.GetFrames().Last();
StackFrame frame = st.GetFrame(0);
StringBuilder sb = new StringBuilder();
sb.Append("\n===================================错误文件==========================================================\r\n");
sb.Append(frame.GetFileName() + "\r\n");
sb.Append("===================================错误类============================================================\r\n");
sb.Append("[" + Path.GetFileNameWithoutExtension(frame.GetFileName()) + "][" + frame.GetMethod().Name + "][" + frame.GetFileLineNumber() + "]" + "\r\n");
sb.Append("===================================错误内容==========================================================\r\n");
sb.Append(s.ToString() + "\r\n");
if (str.IsNotNull())
{
sb.Append("===================================备注==============================================================\r\n");
sb.Append(str + "\r\n");
}
sb.Append("=====================================================================================================\r\n");
return sb.ToString();
}
/// <summary>
/// 获取 位置信息
/// </summary>
/// <returns></returns>
public static string getStackTrace()
{
StackTrace st = new StackTrace(true);
StackFrame frame = st.GetFrame(1);
StringBuilder sb = new StringBuilder();
if (frame != null)
{
sb.Append("[" + Path.GetFileNameWithoutExtension(frame.GetFileName()) + "][" + frame.GetMethod().Name + "][" + frame.GetFileLineNumber() + "]");
}
return sb.ToString();
}
/// <summary>
/// 获取 位置信息
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string StackTrace(this string s)
{
StackTrace st = new StackTrace(true);
StackFrame frame = st.GetFrame(1);
StringBuilder sb = new StringBuilder();
sb.Append(s);
if (frame != null)
{
sb.Append("[" + Path.GetFileNameWithoutExtension(frame.GetFileName()) + "][" + frame.GetMethod().Name + "][" + frame.GetFileLineNumber() + "]");
}
return sb.ToString();
}
#endregion
#region int
/// <summary>
/// 转换指定时间得到对应的时间戳
/// true 则生成13位的时间戳,
/// false 则生成10位的时间戳,默认为 true
/// </summary>
/// <param name="s"></param>
/// <param name="isLongTime">精度(毫秒)设置 true则生成13位的时间戳精度设置为 false则生成10位的时间戳默认为 true </param>
/// <returns>返回对应的时间戳</returns>
public static long ToTimeStamp(this DateTime s, bool isLongTime = true)
{
var ts = s.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return isLongTime ? Convert.ToInt64(ts.TotalMilliseconds) : Convert.ToInt64(ts.TotalSeconds);
}
/// <summary>
/// 取整 有小数进1
/// </summary>
/// <param name="d"></param>
/// <param name="decimals"></param>
/// <returns></returns>
public static int ToInteger(this double d)
{
return Math.Ceiling(d).ToInt32();
}
/// <summary>
/// 转换为int
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static int ToInt32(this string s)
{
return Convert.ToInt32(s);
}
/// <summary>
/// 转换为Double
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static double ToDouble(this string s)
{
return Convert.ToDouble(s);
}
/// <summary>
/// 转换为int
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static int ToInt32(this object s)
{
return Convert.ToInt32(s);
}
#endregion
#region bool
/// <summary>
/// 判断是否 包含 字符串 true 包含 false 不包含
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static bool IndexOfStr(this string[] s, string sStr)
{
foreach (var item in s)
{
if (item.IndexOf(sStr) > -1)
{
return true;
}
}
return false;
}
/// <summary>
/// 判断是否 存在 字符串 true 存在 false 不存在
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static bool IndexToStr(this string[] s, string sStr)
{
foreach (var item in s)
{
if (item == sStr)
{
return true;
}
}
return false;
}
/// <summary>
/// 判断 为空
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static bool IsNull(this string s)
{
return string.IsNullOrWhiteSpace(s);
}
/// <summary>
/// 判断 为空
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static bool IsNullOrWhiteSpace(this string s)
{
return string.IsNullOrWhiteSpace(s);
}
/// <summary>
/// 判断 不为空
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static bool IsNotNull(this string s)
{
return !string.IsNullOrWhiteSpace(s);
}
/// <summary>
/// 判断 不为空
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static bool IsNotNullOrNotWhiteSpace(this string s)
{
return !string.IsNullOrWhiteSpace(s);
}
/// <summary>
/// 判断是否 包含 字符串 true 包含 false 不包含
/// </summary>
/// <param name="s"></param>
/// <param name="sStr"></param>
/// <returns></returns>
public static bool IndexOfStr(this string s, string sStr)
{
if (s.IndexOf(sStr) > -1)
{
return true;
}
return false;
}
/// <summary>
/// 判断是否 包含 字符串 true 包含 false 不包含 或关系
/// </summary>
/// <param name="s"></param>
/// <param name="sStr"></param>
/// <returns></returns>
public static bool IndexOfStrOr(this string s, params string[] sArrStr)
{
for (int i = 0; i < sArrStr.Length; i++)
{
if (s.IndexOf(sArrStr[i]) > -1)
{
return true;
}
}
return false;
}
/// <summary>
/// 判断是否 包含 字符串 true 包含 false 不包含 和关系
/// </summary>
/// <param name="s"></param>
/// <param name="sStr"></param>
/// <returns></returns>
public static bool IndexOfStrAnd(this string s, params string[] sArrStr)
{
for (int i = 0; i < sArrStr.Length; i++)
{
if (s.IndexOf(sArrStr[i]) == -1)
{
return false;
}
}
return true;
}
/// <summary>
/// 判断是否 包含 字符串 true 包含 false 不包含 和关系
/// </summary>
/// <param name="s"></param>
/// <param name="sArrStr"></param>
/// <returns></returns>
public static bool And(this string s, params string[] sArrStr)
{
for (int i = 0; i < sArrStr.Length; i++)
{
if (!s.Contains(sArrStr[i]))
{
return false;
}
}
return true;
}
/// <summary>
/// 判断是否 包含 字符串 true 包含 false 不包含 和关系
/// </summary>
/// <param name="s"></param>
/// <param name="sArrStr"></param>
/// <returns></returns>
public static bool Or(this string s, params string[] sArrStr)
{
for (int i = 0; i < sArrStr.Length; i++)
{
if (s.Contains(sArrStr[i]))
{
return true;
}
}
return false;
}
#endregion
#region DateTime
/// <summary>
/// 字符串转换为 时间
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static DateTime ToDateTime(this object s)
{
return Convert.ToDateTime(s);
}
/// <summary>
/// 字符串转换为 时间
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static DateTime ToDateTime(this string s)
{
return Convert.ToDateTime(s);
}
/// <summary>
/// 时间戳转为C#格式时间
/// </summary>
/// <param name="timeStamp"></param>
/// <returns></returns>
public static DateTime ToDateTimeByStamp(this string timeStamp)
{
DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
long lTime;
if (timeStamp.Length.Equals(10))//判断是10位
{
lTime = long.Parse(timeStamp + "0000000");
}
else
{
lTime = long.Parse(timeStamp + "0000");//13位
}
TimeSpan toNow = new TimeSpan(lTime);
DateTime daTime = dtStart.Add(toNow);
return daTime;
}
#endregion
#region double
/// <summary>
/// 带小数点数字匹配
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static double MatchingNumber(this string s)
{
string s1 = Regex.Replace(s, @"[^\d.\d]", "");
if (s1.IsNotNull())
{
return s1.ToDouble();
}
return 0;
}
/// <summary>
/// 保留小数点 不四舍五入
/// </summary>
/// <param name="d"></param>
/// <param name="decimals"></param>
/// <returns></returns>
public static double NotRound(this double d, int decimals)
{
if (decimals == 0)
{
return (int)d;
}
string sStr = "1";
for (int i = 0; i < decimals; i++)
{
sStr += "0";
}
decimals = Convert.ToInt32(sStr);
return Math.Floor(d * decimals) / decimals;
}
/// <summary>
/// 实现数据的四舍五入法
/// </summary>
/// <param name="v">要进行处理的数据</param>
/// <param name="x">保留的小数位数</param>
/// <returns>四舍五入后的结果</returns>
public static double Round(this double v, int x)
{
bool isNegative = false;
//如果是负数
if (v < 0)
{
isNegative = true;
v = -v;
}
int IValue = 1;
for (int i = 1; i <= x; i++)
{
IValue = IValue * 10;
}
double Int = Math.Round(v * IValue + 0.5, 0);
v = Int / IValue;
if (isNegative)
{
v = -v;
}
return v;
}
/// <summary>
/// 获取百分比 iCount=总数
/// </summary>
/// <param name="d"></param>
/// <param name="iCount"></param>
/// <returns></returns>
public static double getProportion(this double d, double iCount)
{
try
{
double dc = Math.Round((d / iCount) * 100, 2);
if (double.IsNaN(dc))
{
return 0;
}
return dc;
}
catch (Exception)
{
}
return 0;
}
/// <summary>
/// 获取百分比 iCount=总数
/// </summary>
/// <param name="d"></param>
/// <param name="iCount"></param>
/// <returns></returns>
public static double getProportion(this int d, double iCount)
{
try
{
double dc = Math.Round((d / iCount) * 100, 2);
if (double.IsNaN(dc))
{
return 0;
}
return dc;
}
catch (Exception)
{
}
return 0;
}
/// <summary>
/// 转换为 double
/// </summary>
/// <param name="d"></param>
/// <param name="decimals"></param>
/// <returns></returns>
public static double ToDouble(this object d)
{
return Convert.ToDouble(d);
}
#endregion
#region string
/// <summary>
/// url 编码
/// </summary>
/// <param name="s"></param>
/// <param name="e"></param>
/// <returns></returns>
public static string ToUrlEncode(this object s, Encoding e = null)
{
return ToUrlEncode(s.ToString(), e);
}
/// <summary>
/// url 编码
/// </summary>
/// <param name="s"></param>
/// <param name="e"></param>
/// <returns></returns>
public static string ToUrlEncode(this string s, Encoding e = null)
{
if (e == null) e = Encoding.UTF8;
return System.Web.HttpUtility.UrlEncode(s, e);
}
/// <summary>
/// 数字 千位分隔符
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string ToThousandsSeparator(this double s)
{
return s.ToString("N0");
}
/// <summary>
/// 数字 千位分隔符
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string ToThousandsSeparator(this int s)
{
return s.ToString("N0");
}
/// <summary>
/// 将c# DateTime时间格式转换为Unix时间戳格式 13位
/// </summary>
/// <param name="time">时间</param>
/// <returns>long</returns>
public static string ToTimeStamp13(this System.DateTime time)
{
System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1, 0, 0, 0, 0));
long t = (time.Ticks - startTime.Ticks) / 10000; //除10000调整为13位
return t.ToString();
}
/// <summary>
/// 将c# DateTime时间格式转换为Unix时间戳格式 10位
/// </summary>
/// <param name="time">时间</param>
/// <returns>long</returns>
public static string ToTimeStamp10(this System.DateTime time)
{
DateTime dateStart = new DateTime(1970, 1, 1, 8, 0, 0);
int timeStamp = Convert.ToInt32((time - dateStart).TotalSeconds);
return timeStamp.ToString(); ;
}
/// <summary>
/// 截取字符串 过滤空格
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static string[] SplitRemoveEmptyEntries(this string s, params string[] arr)
{
try
{
if (string.IsNullOrWhiteSpace(s))
{
return new string[] { };
}
return s.Split(arr, StringSplitOptions.RemoveEmptyEntries);
}
catch (Exception)
{
return new string[] { };
}
}
/// <summary>
/// 过滤sql 特殊符号
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string ReplaceSQLChar(this string str)
{
if (str == String.Empty)
return String.Empty;
str = str.Replace("'", "");
str = str.Replace("<", "");
str = str.Replace(">", "");
str = str.Replace("@", "");
str = str.Replace("=", "");
str = str.Replace("+", "");
str = str.Replace("*", "");
str = str.Replace("&", "");
str = str.Replace("#", "");
str = str.Replace("%", "");
str = str.Replace("$", "");
//删除与数据库相关的词
str = Regex.Replace(str, "select", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "insert", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "delete from", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "count", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "drop table", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "truncate", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "asc", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "mid", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "char", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "xp_cmdshell", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "exec master", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "net localgroup administrators", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "and", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "net user", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "or", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "net", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "-", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "delete", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "drop", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "script", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "update", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "and", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "chr", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "master", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "truncate", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "declare", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "mid", "", RegexOptions.IgnoreCase);
return str;
}
/// <summary>
/// 将DateTime 格式转换为 yyyy-MM-dd HH:mm:ss
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string ToDateStr(this DateTime d)
{
return d.ToString("yyyy-MM-dd HH:mm:ss");
}
/// <summary>
/// 将DateTime 格式转换为 yyyy-MM-dd HH:mm:ss
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string ToDateStr(this DateTime? d)
{
return Convert.ToDateTime(d).ToString("yyyy-MM-dd HH:mm:ss");
}
/// <summary>
/// Md5 加密
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string GetMD5Hash(this string str)
{
using (MD5 mi = MD5.Create())
{
byte[] buffer = Encoding.Default.GetBytes(str);
//开始加密
byte[] newBuffer = mi.ComputeHash(buffer);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < newBuffer.Length; i++)
{
sb.Append(newBuffer[i].ToString("x2"));
}
return sb.ToString();
}
}
#endregion
#region T
/// <summary>
/// 对象拷贝
/// </summary>
/// <param name="obj">被复制对象</param>
/// <returns>新对象</returns>
public static T CopyOjbect<T>(T obj)
{
Object targetDeepCopyObj = null;
if ((T)obj == null)
{
return (T)targetDeepCopyObj;
}
Type targetType = obj.GetType();
//值类型
if (targetType.IsValueType == true)
{
targetDeepCopyObj = obj;
}
//引用类型
else
{
targetDeepCopyObj = System.Activator.CreateInstance(targetType); //创建引用对象
System.Reflection.MemberInfo[] memberCollection = obj.GetType().GetMembers();
foreach (System.Reflection.MemberInfo member in memberCollection)
{
//拷贝字段
if (member.MemberType == System.Reflection.MemberTypes.Field)
{
System.Reflection.FieldInfo field = (System.Reflection.FieldInfo)member;
Object fieldValue = field.GetValue(obj);
if (fieldValue is ICloneable)
{
field.SetValue(targetDeepCopyObj, (fieldValue as ICloneable).Clone());
}
else
{
field.SetValue(targetDeepCopyObj, CopyOjbect(fieldValue));
}
}//拷贝属性
else if (member.MemberType == System.Reflection.MemberTypes.Property)
{
System.Reflection.PropertyInfo myProperty = (System.Reflection.PropertyInfo)member;
MethodInfo info = myProperty.GetSetMethod(false);
if (info != null)
{
try
{
object propertyValue = myProperty.GetValue(obj, null);
if (propertyValue is ICloneable)
{
myProperty.SetValue(targetDeepCopyObj, (propertyValue as ICloneable).Clone(), null);
}
else
{
myProperty.SetValue(targetDeepCopyObj, CopyOjbect(propertyValue), null);
}
}
catch (System.Exception ex)
{
}
}
}
}
}
return (T)targetDeepCopyObj;
}
#endregion
}
}

View File

@@ -0,0 +1,226 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
namespace TelegramService.Help
{
public class HtmlTag
{
private String m_Name;
private String m_BeginTag;
private String m_InnerHTML;
private Hashtable m_Attributes = new Hashtable();
static Regex attrReg = new Regex(@"([a-zA-Z1-9_-]+)\s*=\s*(\x27|\x22)([^\x27\x22]*)(\x27|\x22)", RegexOptions.IgnoreCase);
private HtmlTag(string name, string beginTag, string innerHTML)
{
m_Name = name;
m_BeginTag = beginTag;
m_InnerHTML = innerHTML;
MatchCollection matchs = attrReg.Matches(beginTag);
foreach (Match match in matchs)
{
m_Attributes[match.Groups[1].Value.ToUpper()] = match.Groups[3].Value;
}
}
public string GetBeginTag()
{
return m_BeginTag;
}
public List<HtmlTag> FindTag(String name)
{
return FindTag(m_InnerHTML, name, String.Format(@"<{0}(\s[^<>]*|)>", name));
}
public List<HtmlTag> FindImgTag()
{
return FindTag(m_InnerHTML, "img", @"<img\b[^<>]*?\bsrc[\s\t\r\n]*=[\s\t\r\n]*[""']?[\s\t\r\n]*(?<imgUrl>[^\s\t\r\n""'<>]*)[^<>]*?/?[\s\t\r\n]*>");
}
public List<HtmlTag> FindTag(String name, String format)
{
return FindTag(m_InnerHTML, name, format);
}
public List<HtmlTag> FindTagByAttr(String tagName, String attrName, String attrValue)
{
return FindTagByAttr(m_InnerHTML, tagName, attrName, attrValue);
}
public String TagName
{
get { return m_Name; }
}
public String InnerHTML
{
get { return m_InnerHTML; }
}
public String InnerText
{
get { return checkStr(m_InnerHTML); }
}
public String GetAttribute(string name)
{
return m_Attributes[name.ToUpper()] as String;
}
public String FindDate
{
get
{
Match m = Regex.Match(InnerText, @"(?<date>((1[6-9]|[2-3]\d)\d{2})-(\d{1,2})-(\d{1,2}))");
if (m.Groups.Count > 0)
{
return m.Groups["date"].Value;
}
else
{
return null;
}
}
}
public static string checkStr2(string html)
{
html = html.Replace("<br>", "$br$");
html = html.Replace("<br/>", "$br/$");
System.Text.RegularExpressions.Regex regex1 = new System.Text.RegularExpressions.Regex(@"<script[\s\S]+</script *>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex2 = new System.Text.RegularExpressions.Regex(@" href *= *[\s\S]*script *:", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex3 = new System.Text.RegularExpressions.Regex(@" no[\s\S]*=", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex4 = new System.Text.RegularExpressions.Regex(@"<iframe[\s\S]+</iframe *>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex5 = new System.Text.RegularExpressions.Regex(@"<frameset[\s\S]+</frameset *>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex6 = new System.Text.RegularExpressions.Regex(@"\<img[^\>]+\>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex7 = new System.Text.RegularExpressions.Regex(@"</p>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex8 = new System.Text.RegularExpressions.Regex(@"<p>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex9 = new System.Text.RegularExpressions.Regex(@"<[^>]*>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
html = regex1.Replace(html, ""); //过滤<script></script>标记
html = regex2.Replace(html, ""); //过滤href=javascript: (<A>) 属性
html = regex3.Replace(html, " _disibledevent="); //过滤其它控件的on...事件
html = regex4.Replace(html, ""); //过滤iframe
html = regex5.Replace(html, ""); //过滤frameset
html = regex6.Replace(html, ""); //过滤frameset
// html = regex7.Replace(html, ""); //过滤frameset
// html = regex8.Replace(html, ""); //过滤frameset
html = regex9.Replace(html, "");
html = html.Replace(" ", "");
html = html.Replace("</strong>", "");
html = html.Replace("<strong>", "");
html = html.Replace("$br$", "<br>");
html = html.Replace("$br/$", "<br/>");
return html;
}
public static string checkStr(string html)
{
if (string.IsNullOrEmpty(html))
{
return html;
}
System.Text.RegularExpressions.Regex regex1 = new System.Text.RegularExpressions.Regex(@"<script[\s\S]+</script *>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex2 = new System.Text.RegularExpressions.Regex(@" href *= *[\s\S]*script *:", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex3 = new System.Text.RegularExpressions.Regex(@" no[\s\S]*=", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex4 = new System.Text.RegularExpressions.Regex(@"<iframe[\s\S]+</iframe *>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex5 = new System.Text.RegularExpressions.Regex(@"<frameset[\s\S]+</frameset *>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex6 = new System.Text.RegularExpressions.Regex(@"\<img[^\>]+\>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex7 = new System.Text.RegularExpressions.Regex(@"</p>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex8 = new System.Text.RegularExpressions.Regex(@"<p>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex9 = new System.Text.RegularExpressions.Regex(@"<[^>]*>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
html = regex1.Replace(html, ""); //过滤<script></script>标记
html = regex2.Replace(html, ""); //过滤href=javascript: (<A>) 属性
html = regex3.Replace(html, " _disibledevent="); //过滤其它控件的on...事件
html = regex4.Replace(html, ""); //过滤iframe
html = regex5.Replace(html, ""); //过滤frameset
html = regex6.Replace(html, ""); //过滤frameset
html = regex7.Replace(html, ""); //过滤frameset
html = regex8.Replace(html, ""); //过滤frameset
html = regex9.Replace(html, "");
html = html.Replace(" ", "");
html = html.Replace("</strong>", "");
html = html.Replace("<strong>", "");
html = html.Replace("&nbsp;", " ");
return html;
}
public static string HtmlToText(string str)
{
string m_outstr = str;
m_outstr = new Regex(@"(?m)<script[^>]*>(\w|\W)*?</script[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase).Replace(m_outstr, "");
m_outstr = new Regex(@"(?m)<style[^>]*>(\w|\W)*?</style[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase).Replace(m_outstr, "");
m_outstr = new Regex(@"(?m)<select[^>]*>(\w|\W)*?</select[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase).Replace(m_outstr, "");
//m_outstr = new Regex(@"(?m)<a[^>]*>(\w|\W)*?</a[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase).Replace(m_outstr, "");
Regex objReg = new System.Text.RegularExpressions.Regex("(<[^>]+?>)|&nbsp;", RegexOptions.Multiline | RegexOptions.IgnoreCase);
m_outstr = objReg.Replace(m_outstr, "");
Regex objReg2 = new System.Text.RegularExpressions.Regex("(\\s)+", RegexOptions.Multiline | RegexOptions.IgnoreCase);
m_outstr = objReg2.Replace(m_outstr, " ");
return m_outstr;
}
/// <summary>
/// 在文本html的文本查找标志名为tagName,并且属性attrName的值为attrValue的所有标志
/// 例如FindTagByAttr(html, "div", "class", "demo")
/// 返回所有class为demo的div标志
/// </summary>
public static List<HtmlTag> FindTagByAttr(String html, String tagName, String attrName, String attrValue)
{
String format = String.Format(@"<{0}\s[^<>]*{1}\s*=\s*(\x27|\x22){2}(\x27|\x22)[^<>]*>", tagName, attrName, attrValue);
return FindTag(html, tagName, format);
}
public static List<HtmlTag> FindTag(String html, String name, String format)
{
Regex reg = new Regex(format, RegexOptions.IgnoreCase);
Regex tagReg = new Regex(String.Format(@"<(\/|)({0})(\s[^<>]*|)>", name), RegexOptions.IgnoreCase);
List<HtmlTag> tags = new List<HtmlTag>();
int start = 0;
while (true)
{
Match match = reg.Match(html, start);
if (match.Success)
{
start = match.Index + match.Length;
Match tagMatch = null;
int beginTagCount = 1;
while (true)
{
tagMatch = tagReg.Match(html, start);
if (!tagMatch.Success)
{
tagMatch = null;
break;
}
start = tagMatch.Index + tagMatch.Length;
if (tagMatch.Groups[1].Value == "/") beginTagCount--;
else beginTagCount++;
if (beginTagCount == 0) break;
}
if (tagMatch != null)
{
HtmlTag tag = new HtmlTag(name, match.Value, html.Substring(match.Index + match.Length, tagMatch.Index - match.Index - match.Length));
tags.Add(tag);
}
else
{
break;
}
}
else
{
break;
}
}
return tags;
}
}
}

View File

@@ -0,0 +1,244 @@
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
public static class HttpHelper
{
private static readonly HttpClient DefaultClient;
private static readonly HttpResult HttpResult;
static HttpHelper()
{
var handler = CreateBestHandler();
TrySetPooledConnectionLifetime(handler, TimeSpan.FromMinutes(2));
DefaultClient = new HttpClient(handler, disposeHandler: false)
{
Timeout = Timeout.InfiniteTimeSpan
};
HttpResult = new HttpResult();
}
private static HttpClient CreateProxyClient(string proxy)
{
var (address, isHttpsProxy) = ParseProxyScheme(proxy);
var handler = CreateBestHandler();
TrySetPooledConnectionLifetime(handler, TimeSpan.FromMinutes(2));
handler.Proxy = new WebProxy(address)
{
// 关键两行!解决 95% 的 HTTPS 代理报错
UseDefaultCredentials = false,
BypassProxyOnLocal = false
};
// 如果是 https:// 开头的代理(极少数 socks5 也可能用这个格式),强制走 CONNECT
if (isHttpsProxy)
{
// .NET 6+ 推荐方式(安全又快)
handler.SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls13;
}
handler.UseProxy = true;
return new HttpClient(handler, disposeHandler: true)
{
Timeout = Timeout.InfiniteTimeSpan
};
}
private static HttpClientHandler CreateBestHandler()
{
return new HttpClientHandler
{
UseCookies = false,
AutomaticDecompression = DecompressionMethods.All,
AllowAutoRedirect = true,
// 下面这行是终极救命稻草(解决代理返回 407 需要认证的坑)
Proxy = null, // 先留空,后面再设
UseProxy = false,
// 防止某些代理服务器返回奇怪的证书
ServerCertificateCustomValidationCallback = (msg, cert, chain, errors) => true
};
}
// 智能解析代理地址,支持以下所有格式:
// http://1.2.3.4:8888
// https://1.2.3.4:8888
// 1.2.3.4:8888
// user:pass@1.2.3.4:8888
private static (Uri address, bool isHttpsProxy) ParseProxyScheme(string proxy)
{
proxy = proxy.Trim();
var uri = proxy.Contains("://")
? new Uri(proxy)
: new Uri("http://" + proxy);
// 带用户名密码的代理
if (!string.IsNullOrEmpty(uri.UserInfo))
{
var parts = uri.UserInfo.Split(new[] { ':' }, 2);
var credential = new NetworkCredential(parts[0], parts.Length > 1 ? parts[1] : "");
// 注意:这里不能直接设 DefaultProxyCredentials会全局污染
// 我们改在下面用更安全的方式处理
}
bool isHttps = uri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase);
var address = new Uri($"{(isHttps ? "http" : uri.Scheme)}://{uri.Host}:{uri.Port}");
return (address, isHttps);
}
public static async Task<HttpResult> SendAsync(
string url,
HttpMethod method,
Dictionary<string, string>? headers = null,
Dictionary<string, string>? cookies = null,
HttpContent? content = null,
int timeoutSeconds = 30,
string? proxy = null,
CancellationToken cancellationToken = default)
{
var client = string.IsNullOrWhiteSpace(proxy)
? DefaultClient
: CreateProxyClient(proxy);
var shouldDispose = !string.IsNullOrWhiteSpace(proxy);
// 处理带账号密码的代理(终极写法)
if (!string.IsNullOrWhiteSpace(proxy) && proxy.Contains("@"))
{
var uri = new Uri(proxy.Contains("://") ? proxy : "http://" + proxy);
if (!string.IsNullOrEmpty(uri.UserInfo))
{
var parts = uri.UserInfo.Split(new[] { ':' }, 2);
var credential = new NetworkCredential(parts[0], parts.Length > 1 ? parts[1] : "");
// 关键:每个 HttpClientHandler 单独设置凭据,不污染全局
if (client.DefaultRequestHeaders.ProxyAuthorization == null)
{
var handler = (HttpClientHandler)client.GetType()
.GetProperty("Handler", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
?.GetValue(client)!;
if (handler?.Proxy != null)
{
handler.Proxy.Credentials = credential;
}
}
}
}
try
{
using var request = new HttpRequestMessage(method, url);
if (content != null) request.Content = content;
if (headers != null)
{
foreach (var h in headers)
{
if (IsContentHeader(h.Key))
request.Content?.Headers.TryAddWithoutValidation(h.Key, h.Value);
else
request.Headers.TryAddWithoutValidation(h.Key, h.Value);
}
}
if (cookies is { Count: > 0 })
{
request.Headers.TryAddWithoutValidation("Cookie", string.Join("; ", cookies.Select(c => $"{c.Key}={c.Value}")));
}
using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
cts.CancelAfter(TimeSpan.FromSeconds(timeoutSeconds));
using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cts.Token);
if (!response.IsSuccessStatusCode)
{
var err = await response.Content.ReadAsStringAsync(cts.Token);
HttpResult.StatusCode = (int)response.StatusCode;
HttpResult.Html = $"请求失败 {(int)response.StatusCode} {response.ReasonPhrase}\n{err}".Trim();
return HttpResult;
}
var bytes = await response.Content.ReadAsByteArrayAsync(cts.Token);
var charset = response.Content.Headers.ContentType?.CharSet;
if (!string.IsNullOrEmpty(charset) && !charset.Equals("utf-8", StringComparison.OrdinalIgnoreCase))
{
try {
HttpResult.StatusCode = (int)response.StatusCode;
HttpResult.Html = Encoding.GetEncoding(charset).GetString(bytes);
return HttpResult;
} catch { }
}
HttpResult.StatusCode = (int)response.StatusCode;
HttpResult.Html = Encoding.UTF8.GetString(bytes);
return HttpResult;
}
catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested)
{
HttpResult.StatusCode = 500;
HttpResult.Html = $"请求超时({timeoutSeconds}s";
return HttpResult;
}
finally
{
if (shouldDispose) client.Dispose();
}
}
// 你的三个快捷方法完全不变
public static Task<HttpResult> GetAsync(string url, Dictionary<string, string>? headers = null,
Dictionary<string, string>? cookies = null, int timeoutSeconds = 30, string? proxy = null) =>
SendAsync(url, HttpMethod.Get, headers, cookies, null, timeoutSeconds, proxy);
public static Task<HttpResult> PostFormAsync(string url, Dictionary<string, string> form,
Dictionary<string, string>? headers = null, Dictionary<string, string>? cookies = null,
int timeoutSeconds = 30, string? proxy = null)
{
var content = new FormUrlEncodedContent(form);
return SendAsync(url, HttpMethod.Post, headers, cookies, content, timeoutSeconds, proxy);
}
public static Task<HttpResult> PostJsonAsync(string url, string json,
Dictionary<string, string>? headers = null, Dictionary<string, string>? cookies = null,
int timeoutSeconds = 30, string? proxy = null)
{
var content = new StringContent(json, Encoding.UTF8, "application/json");
headers ??= new();
headers["Content-Type"] = "application/json; charset=utf-8";
return SendAsync(url, HttpMethod.Post, headers, cookies, content, timeoutSeconds, proxy);
}
private static bool IsContentHeader(string name) =>
name.StartsWith("Content-", StringComparison.OrdinalIgnoreCase);
private static void TrySetPooledConnectionLifetime(HttpClientHandler handler, TimeSpan lifetime)
{
try
{
var prop = handler.GetType().GetProperty("PooledConnectionLifetime");
prop?.SetValue(handler, lifetime);
}
catch { }
}
}
public class HttpResult
{
public int StatusCode { get; set; }
public string Html { get; set; }
}

View File

@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>