添加项目文件。
This commit is contained in:
13
TelegramService.Help/EntrustHelper.cs
Normal file
13
TelegramService.Help/EntrustHelper.cs
Normal 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;
|
||||
|
||||
}
|
||||
}
|
||||
745
TelegramService.Help/ExtendHelper.cs
Normal file
745
TelegramService.Help/ExtendHelper.cs
Normal 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
|
||||
|
||||
}
|
||||
}
|
||||
226
TelegramService.Help/HtmlTag.cs
Normal file
226
TelegramService.Help/HtmlTag.cs
Normal 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(" ", " ");
|
||||
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("(<[^>]+?>)| ", 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
244
TelegramService.Help/HttpHelper.cs
Normal file
244
TelegramService.Help/HttpHelper.cs
Normal 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; }
|
||||
|
||||
}
|
||||
9
TelegramService.Help/TelegramService.Help.csproj
Normal file
9
TelegramService.Help/TelegramService.Help.csproj
Normal file
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user