添加项目文件。
This commit is contained in:
6
QYZH.InteractiveMagazine.Common/Class1.cs
Normal file
6
QYZH.InteractiveMagazine.Common/Class1.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace QYZH.InteractiveMagazine.Common;
|
||||
|
||||
public class Class1
|
||||
{
|
||||
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
using System;
|
||||
|
||||
namespace QYZH.InteractiveMagazine.Common.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 日期时间扩展方法
|
||||
/// </summary>
|
||||
public static class DateTimeExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 转换为Unix时间戳(秒)
|
||||
/// </summary>
|
||||
/// <param name="dateTime">日期时间</param>
|
||||
/// <returns>Unix时间戳</returns>
|
||||
public static long ToTimestamp(this DateTime dateTime)
|
||||
{
|
||||
return new DateTimeOffset(dateTime.ToUniversalTime()).ToUnixTimeSeconds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从Unix时间戳(秒)转换为DateTime
|
||||
/// </summary>
|
||||
/// <param name="timestamp">Unix时间戳</param>
|
||||
/// <returns>日期时间</returns>
|
||||
public static DateTime FromTimestamp(long timestamp)
|
||||
{
|
||||
return DateTimeOffset.FromUnixTimeSeconds(timestamp).LocalDateTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为指定格式的日期时间字符串
|
||||
/// </summary>
|
||||
/// <param name="dateTime">日期时间</param>
|
||||
/// <param name="format">格式字符串,默认为"yyyy-MM-dd HH:mm:ss"</param>
|
||||
/// <returns>格式化的日期时间字符串</returns>
|
||||
public static string ToDateTimeString(this DateTime dateTime, string format = "yyyy-MM-dd HH:mm:ss")
|
||||
{
|
||||
return dateTime.ToString(format);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从生日计算年龄
|
||||
/// </summary>
|
||||
/// <param name="birthday">生日日期</param>
|
||||
/// <returns>年龄</returns>
|
||||
public static int GetAge(this DateTime birthday)
|
||||
{
|
||||
int age = DateTime.Now.Year - birthday.Year;
|
||||
|
||||
if (DateTime.Now.DayOfYear < birthday.DayOfYear)
|
||||
{
|
||||
age--;
|
||||
}
|
||||
|
||||
return age;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否是今天
|
||||
/// </summary>
|
||||
/// <param name="dateTime">日期时间</param>
|
||||
/// <returns>是否是今天</returns>
|
||||
public static bool IsToday(this DateTime dateTime)
|
||||
{
|
||||
return dateTime.Date == DateTime.Today;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当天开始时间(00:00:00)
|
||||
/// </summary>
|
||||
/// <param name="dateTime">日期时间</param>
|
||||
/// <returns>当天开始时间</returns>
|
||||
public static DateTime ToStartOfDay(this DateTime dateTime)
|
||||
{
|
||||
return dateTime.Date;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当天结束时间(23:59:59.999)
|
||||
/// </summary>
|
||||
/// <param name="dateTime">日期时间</param>
|
||||
/// <returns>当天结束时间</returns>
|
||||
public static DateTime ToEndOfDay(this DateTime dateTime)
|
||||
{
|
||||
return dateTime.Date.AddDays(1).AddTicks(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
79
QYZH.InteractiveMagazine.Common/Extensions/EnumExtension.cs
Normal file
79
QYZH.InteractiveMagazine.Common/Extensions/EnumExtension.cs
Normal file
@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace QYZH.InteractiveMagazine.Common.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 枚举扩展方法
|
||||
/// </summary>
|
||||
public static class EnumExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取枚举的DescriptionAttribute描述
|
||||
/// </summary>
|
||||
/// <typeparam name="T">枚举类型</typeparam>
|
||||
/// <param name="enumValue">枚举值</param>
|
||||
/// <returns>描述文本,如果没有DescriptionAttribute则返回枚举名称</returns>
|
||||
public static string GetDescription<T>(this T enumValue) where T : Enum
|
||||
{
|
||||
System.Reflection.FieldInfo? field = enumValue.GetType().GetField(enumValue.ToString());
|
||||
if (field == null)
|
||||
{
|
||||
return enumValue.ToString();
|
||||
}
|
||||
|
||||
var attribute = (DescriptionAttribute?)Attribute.GetCustomAttribute(
|
||||
field, typeof(DescriptionAttribute));
|
||||
|
||||
return attribute?.Description ?? enumValue.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取枚举名称
|
||||
/// </summary>
|
||||
/// <typeparam name="T">枚举类型</typeparam>
|
||||
/// <param name="enumValue">枚举值</param>
|
||||
/// <returns>枚举名称</returns>
|
||||
public static string GetName<T>(this T enumValue) where T : Enum
|
||||
{
|
||||
return enumValue.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有枚举名称列表
|
||||
/// </summary>
|
||||
/// <typeparam name="T">枚举类型</typeparam>
|
||||
/// <returns>枚举名称列表</returns>
|
||||
public static List<string> GetNames<T>() where T : Enum
|
||||
{
|
||||
return Enum.GetNames(typeof(T)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有枚举描述列表
|
||||
/// </summary>
|
||||
/// <typeparam name="T">枚举类型</typeparam>
|
||||
/// <returns>枚举描述列表</returns>
|
||||
public static List<string> GetDescriptions<T>() where T : Enum
|
||||
{
|
||||
return Enum.GetValues(typeof(T))
|
||||
.Cast<T>()
|
||||
.Select(e => e.GetDescription())
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将枚举转换为字典(名称,值)
|
||||
/// </summary>
|
||||
/// <typeparam name="T">枚举类型</typeparam>
|
||||
/// <returns>枚举字典</returns>
|
||||
public static Dictionary<string, int> ToDictionary<T>() where T : Enum
|
||||
{
|
||||
return Enum.GetValues(typeof(T))
|
||||
.Cast<T>()
|
||||
.ToDictionary(e => e.GetDescription(), e => Convert.ToInt32(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace QYZH.InteractiveMagazine.Common.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 对象扩展方法
|
||||
/// </summary>
|
||||
public static class ObjectExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 将源对象的属性值拷贝到目标对象
|
||||
/// </summary>
|
||||
/// <typeparam name="T">目标对象类型</typeparam>
|
||||
/// <param name="source">源对象</param>
|
||||
/// <param name="target">目标对象</param>
|
||||
/// <returns>目标对象</returns>
|
||||
public static T CopyTo<T>(this object source, T target)
|
||||
{
|
||||
if (source == null || target == null)
|
||||
{
|
||||
return target;
|
||||
}
|
||||
|
||||
Type sourceType = source.GetType();
|
||||
Type targetType = target.GetType();
|
||||
|
||||
PropertyInfo[] sourceProperties = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
foreach (PropertyInfo sourceProp in sourceProperties)
|
||||
{
|
||||
if (!sourceProp.CanRead)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
PropertyInfo? targetProp = targetType.GetProperty(sourceProp.Name);
|
||||
|
||||
if (targetProp != null && targetProp.CanWrite &&
|
||||
targetProp.PropertyType == sourceProp.PropertyType)
|
||||
{
|
||||
object? value = sourceProp.GetValue(source);
|
||||
targetProp.SetValue(target, value);
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将对象转换为JSON字符串
|
||||
/// </summary>
|
||||
/// <param name="obj">对象</param>
|
||||
/// <param name="formatting">格式化选项</param>
|
||||
/// <returns>JSON字符串</returns>
|
||||
public static string ToJson(this object obj, Formatting formatting = Formatting.None)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return JsonConvert.SerializeObject(obj, formatting);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将对象转换为字典
|
||||
/// </summary>
|
||||
/// <param name="obj">对象</param>
|
||||
/// <returns>字典</returns>
|
||||
public static Dictionary<string, object?> ToDictionary(this object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return new Dictionary<string, object?>();
|
||||
}
|
||||
|
||||
var dictionary = new Dictionary<string, object?>();
|
||||
PropertyInfo[] properties = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
foreach (PropertyInfo property in properties)
|
||||
{
|
||||
if (property.CanRead)
|
||||
{
|
||||
dictionary[property.Name] = property.GetValue(obj);
|
||||
}
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
}
|
||||
}
|
||||
150
QYZH.InteractiveMagazine.Common/Extensions/StringExtension.cs
Normal file
150
QYZH.InteractiveMagazine.Common/Extensions/StringExtension.cs
Normal file
@ -0,0 +1,150 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace QYZH.InteractiveMagazine.Common.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 字符串扩展方法
|
||||
/// </summary>
|
||||
public static class StringExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// MD5加密
|
||||
/// </summary>
|
||||
/// <param name="input">原始字符串</param>
|
||||
/// <returns>MD5哈希值(32位小写)</returns>
|
||||
public static string ToMd5(this string input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
using (var md5 = MD5.Create())
|
||||
{
|
||||
byte[] bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(input));
|
||||
var sb = new StringBuilder();
|
||||
foreach (byte b in bytes)
|
||||
{
|
||||
sb.Append(b.ToString("x2"));
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SHA256加密
|
||||
/// </summary>
|
||||
/// <param name="input">原始字符串</param>
|
||||
/// <returns>SHA256哈希值(64位小写)</returns>
|
||||
public static string ToSha256(this string input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
using (var sha256 = SHA256.Create())
|
||||
{
|
||||
byte[] bytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(input));
|
||||
var sb = new StringBuilder();
|
||||
foreach (byte b in bytes)
|
||||
{
|
||||
sb.Append(b.ToString("x2"));
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base64编码
|
||||
/// </summary>
|
||||
/// <param name="input">原始字符串</param>
|
||||
/// <returns>Base64编码后的字符串</returns>
|
||||
public static string ToBase64(this string input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(input);
|
||||
return Convert.ToBase64String(bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base64解码
|
||||
/// </summary>
|
||||
/// <param name="input">Base64编码的字符串</param>
|
||||
/// <returns>解码后的原始字符串</returns>
|
||||
public static string FromBase64(this string input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
byte[] bytes = Convert.FromBase64String(input);
|
||||
return Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断字符串是否为空或空白
|
||||
/// </summary>
|
||||
/// <param name="input">待检查的字符串</param>
|
||||
/// <returns>是否为空或空白</returns>
|
||||
public static bool IsNullOrWhiteSpace(this string input)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 手机号脱敏
|
||||
/// </summary>
|
||||
/// <param name="phone">手机号</param>
|
||||
/// <returns>脱敏后的手机号(中间4位用*替换)</returns>
|
||||
public static string MaskPhone(this string phone)
|
||||
{
|
||||
if (string.IsNullOrEmpty(phone) || phone.Length < 7)
|
||||
{
|
||||
return phone;
|
||||
}
|
||||
|
||||
return phone.Substring(0, 3) + "****" + phone.Substring(phone.Length - 4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 身份证脱敏
|
||||
/// </summary>
|
||||
/// <param name="idCard">身份证号</param>
|
||||
/// <returns>脱敏后的身份证号(保留前3位和后4位)</returns>
|
||||
public static string MaskIdCard(this string idCard)
|
||||
{
|
||||
if (string.IsNullOrEmpty(idCard) || idCard.Length < 7)
|
||||
{
|
||||
return idCard;
|
||||
}
|
||||
|
||||
int length = idCard.Length;
|
||||
return idCard.Substring(0, 3) + new string('*', length - 7) + idCard.Substring(length - 4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 正则匹配
|
||||
/// </summary>
|
||||
/// <param name="input">待匹配的字符串</param>
|
||||
/// <param name="pattern">正则表达式</param>
|
||||
/// <returns>是否匹配</returns>
|
||||
public static bool IsMatchRegex(this string input, string pattern)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input) || string.IsNullOrEmpty(pattern))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Regex.IsMatch(input, pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
110
QYZH.InteractiveMagazine.Common/Helpers/EnumHelper.cs
Normal file
110
QYZH.InteractiveMagazine.Common/Helpers/EnumHelper.cs
Normal file
@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace QYZH.InteractiveMagazine.Common.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// 枚举工具类
|
||||
/// </summary>
|
||||
public static class EnumHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 根据枚举名称获取枚举值
|
||||
/// </summary>
|
||||
/// <typeparam name="TEnum">枚举类型</typeparam>
|
||||
/// <param name="name">枚举名称</param>
|
||||
/// <returns>枚举值</returns>
|
||||
public static TEnum GetValue<TEnum>(string name) where TEnum : Enum
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
throw new ArgumentException("枚举名称不能为空", nameof(name));
|
||||
}
|
||||
|
||||
if (Enum.TryParse(typeof(TEnum), name, true, out object? result))
|
||||
{
|
||||
return (TEnum)result;
|
||||
}
|
||||
|
||||
throw new ArgumentException($"枚举 '{typeof(TEnum).Name}' 中不存在名称为 '{name}' 的值");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据枚举值获取枚举名称
|
||||
/// </summary>
|
||||
/// <typeparam name="TEnum">枚举类型</typeparam>
|
||||
/// <param name="value">枚举值</param>
|
||||
/// <returns>枚举名称</returns>
|
||||
public static string GetName<TEnum>(object value) where TEnum : Enum
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
if (Enum.IsDefined(typeof(TEnum), value))
|
||||
{
|
||||
return Enum.GetName(typeof(TEnum), value)!;
|
||||
}
|
||||
|
||||
throw new ArgumentException($"枚举 '{typeof(TEnum).Name}' 中不存在值 '{value}'");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取枚举的所有值
|
||||
/// </summary>
|
||||
/// <typeparam name="TEnum">枚举类型</typeparam>
|
||||
/// <returns>枚举值列表</returns>
|
||||
public static List<TEnum> GetAllValues<TEnum>() where TEnum : Enum
|
||||
{
|
||||
return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据Description获取枚举值
|
||||
/// </summary>
|
||||
/// <typeparam name="TEnum">枚举类型</typeparam>
|
||||
/// <param name="description">描述文本</param>
|
||||
/// <returns>枚举值</returns>
|
||||
public static TEnum GetValueByDescription<TEnum>(string description) where TEnum : Enum
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(description))
|
||||
{
|
||||
throw new ArgumentException("描述不能为空", nameof(description));
|
||||
}
|
||||
|
||||
foreach (TEnum value in Enum.GetValues(typeof(TEnum)))
|
||||
{
|
||||
string desc = GetDescription(value);
|
||||
if (desc.Equals(description, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ArgumentException($"枚举 '{typeof(TEnum).Name}' 中不存在描述为 '{description}' 的值");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取枚举的DescriptionAttribute描述
|
||||
/// </summary>
|
||||
/// <typeparam name="TEnum">枚举类型</typeparam>
|
||||
/// <param name="value">枚举值</param>
|
||||
/// <returns>描述文本</returns>
|
||||
public static string GetDescription<TEnum>(TEnum value) where TEnum : Enum
|
||||
{
|
||||
System.Reflection.FieldInfo? field = value.GetType().GetField(value.ToString());
|
||||
if (field == null)
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
var attribute = (DescriptionAttribute?)Attribute.GetCustomAttribute(
|
||||
field, typeof(DescriptionAttribute));
|
||||
|
||||
return attribute?.Description ?? value.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
103
QYZH.InteractiveMagazine.Common/Helpers/HttpHelper.cs
Normal file
103
QYZH.InteractiveMagazine.Common/Helpers/HttpHelper.cs
Normal file
@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace QYZH.InteractiveMagazine.Common.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// HTTP请求工具类
|
||||
/// </summary>
|
||||
public static class HttpHelper
|
||||
{
|
||||
private static readonly HttpClient _httpClient = new HttpClient();
|
||||
|
||||
/// <summary>
|
||||
/// 设置默认请求头
|
||||
/// </summary>
|
||||
static HttpHelper()
|
||||
{
|
||||
_httpClient.Timeout = TimeSpan.FromSeconds(30);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送GET请求
|
||||
/// </summary>
|
||||
/// <param name="url">请求地址</param>
|
||||
/// <returns>响应内容字符串</returns>
|
||||
public static async Task<string> GetAsync(string url)
|
||||
{
|
||||
HttpResponseMessage response = await _httpClient.GetAsync(url);
|
||||
response.EnsureSuccessStatusCode();
|
||||
return await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送GET请求并反序列化为指定类型
|
||||
/// </summary>
|
||||
/// <typeparam name="T">响应类型</typeparam>
|
||||
/// <param name="url">请求地址</param>
|
||||
/// <returns>反序列化后的对象</returns>
|
||||
public static async Task<T?> GetAsync<T>(string url)
|
||||
{
|
||||
string json = await GetAsync(url);
|
||||
return JsonConvert.DeserializeObject<T>(json);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送POST请求
|
||||
/// </summary>
|
||||
/// <param name="url">请求地址</param>
|
||||
/// <param name="data">请求数据</param>
|
||||
/// <returns>响应内容字符串</returns>
|
||||
public static async Task<string> PostAsync(string url, object data)
|
||||
{
|
||||
string json = JsonConvert.SerializeObject(data);
|
||||
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
||||
HttpResponseMessage response = await _httpClient.PostAsync(url, content);
|
||||
response.EnsureSuccessStatusCode();
|
||||
return await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送POST请求并反序列化为指定类型
|
||||
/// </summary>
|
||||
/// <typeparam name="T">响应类型</typeparam>
|
||||
/// <param name="url">请求地址</param>
|
||||
/// <param name="data">请求数据</param>
|
||||
/// <returns>反序列化后的对象</returns>
|
||||
public static async Task<T?> PostAsync<T>(string url, object data)
|
||||
{
|
||||
string json = await PostAsync(url, data);
|
||||
return JsonConvert.DeserializeObject<T>(json);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送DELETE请求
|
||||
/// </summary>
|
||||
/// <param name="url">请求地址</param>
|
||||
/// <returns>响应内容字符串</returns>
|
||||
public static async Task<string> DeleteAsync(string url)
|
||||
{
|
||||
HttpResponseMessage response = await _httpClient.DeleteAsync(url);
|
||||
response.EnsureSuccessStatusCode();
|
||||
return await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送PUT请求
|
||||
/// </summary>
|
||||
/// <param name="url">请求地址</param>
|
||||
/// <param name="data">请求数据</param>
|
||||
/// <returns>响应内容字符串</returns>
|
||||
public static async Task<string> PutAsync(string url, object data)
|
||||
{
|
||||
string json = JsonConvert.SerializeObject(data);
|
||||
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
||||
HttpResponseMessage response = await _httpClient.PutAsync(url, content);
|
||||
response.EnsureSuccessStatusCode();
|
||||
return await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
91
QYZH.InteractiveMagazine.Common/Helpers/JsonHelper.cs
Normal file
91
QYZH.InteractiveMagazine.Common/Helpers/JsonHelper.cs
Normal file
@ -0,0 +1,91 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace QYZH.InteractiveMagazine.Common.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// JSON工具类
|
||||
/// </summary>
|
||||
public static class JsonHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// JSON序列化设置
|
||||
/// </summary>
|
||||
private static readonly JsonSerializerSettings _settings = new JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
DateFormatString = "yyyy-MM-dd HH:mm:ss",
|
||||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 将对象序列化为JSON字符串
|
||||
/// </summary>
|
||||
/// <param name="obj">对象</param>
|
||||
/// <returns>JSON字符串</returns>
|
||||
public static string Serialize(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return JsonConvert.SerializeObject(obj, _settings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将对象序列化为格式化的JSON字符串
|
||||
/// </summary>
|
||||
/// <param name="obj">对象</param>
|
||||
/// <returns>格式化的JSON字符串</returns>
|
||||
public static string SerializePretty(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return JsonConvert.SerializeObject(obj, Formatting.Indented, _settings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将JSON字符串反序列化为指定类型
|
||||
/// </summary>
|
||||
/// <typeparam name="T">目标类型</typeparam>
|
||||
/// <param name="json">JSON字符串</param>
|
||||
/// <returns>反序列化后的对象</returns>
|
||||
public static T? Deserialize<T>(string json)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(json))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<T>(json, _settings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将JSON字符串反序列化为指定类型(带异常处理)
|
||||
/// </summary>
|
||||
/// <typeparam name="T">目标类型</typeparam>
|
||||
/// <param name="json">JSON字符串</param>
|
||||
/// <param name="defaultValue">反序列化失败时的默认值</param>
|
||||
/// <returns>反序列化后的对象或默认值</returns>
|
||||
public static T? TryDeserialize<T>(string json, T? defaultValue = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(json))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
T? result = JsonConvert.DeserializeObject<T>(json, _settings);
|
||||
return result ?? defaultValue;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
180
QYZH.InteractiveMagazine.Common/Helpers/SnowflakeIdHelper.cs
Normal file
180
QYZH.InteractiveMagazine.Common/Helpers/SnowflakeIdHelper.cs
Normal file
@ -0,0 +1,180 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace QYZH.InteractiveMagazine.Common.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// 雪花ID生成器
|
||||
/// 基于Twitter Snowflake算法实现
|
||||
/// </summary>
|
||||
public static class SnowflakeIdHelper
|
||||
{
|
||||
private static long _sequence = 0L;
|
||||
private static long _lastTimestamp = -1L;
|
||||
private static readonly object _lock = new object();
|
||||
|
||||
// 基础时间戳 (2020-01-01 00:00:00 UTC)
|
||||
private const long TwEpoch = 1577836800000L;
|
||||
|
||||
// 机器ID位数
|
||||
private const int WorkerIdBits = 5;
|
||||
|
||||
// 数据中心ID位数
|
||||
private const int DataCenterIdBits = 5;
|
||||
|
||||
// 序列号位数
|
||||
private const int SequenceBits = 12;
|
||||
|
||||
// 最大值计算
|
||||
private const long MaxWorkerId = -1L ^ (-1L << WorkerIdBits);
|
||||
private const long MaxDataCenterId = -1L ^ (-1L << DataCenterIdBits);
|
||||
private const long MaxSequence = -1L ^ (-1L << SequenceBits);
|
||||
|
||||
// 位移偏移量
|
||||
private const int WorkerIdShift = SequenceBits;
|
||||
private const int DataCenterIdShift = SequenceBits + WorkerIdBits;
|
||||
private const int TimestampLeftShift = SequenceBits + WorkerIdBits + DataCenterIdBits;
|
||||
|
||||
private static long _workerId;
|
||||
private static long _dataCenterId;
|
||||
|
||||
/// <summary>
|
||||
/// 静态构造函数,初始化机器ID和数据中心ID
|
||||
/// </summary>
|
||||
static SnowflakeIdHelper()
|
||||
{
|
||||
_workerId = GetWorkerId();
|
||||
_dataCenterId = GetDataCenterId();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化雪花ID生成器
|
||||
/// </summary>
|
||||
/// <param name="workerId">机器ID (0-31)</param>
|
||||
/// <param name="dataCenterId">数据中心ID (0-31)</param>
|
||||
public static void Initialize(long workerId, long dataCenterId)
|
||||
{
|
||||
if (workerId < 0 || workerId > MaxWorkerId)
|
||||
{
|
||||
throw new ArgumentException($"机器ID必须在0-{MaxWorkerId}范围内", nameof(workerId));
|
||||
}
|
||||
|
||||
if (dataCenterId < 0 || dataCenterId > MaxDataCenterId)
|
||||
{
|
||||
throw new ArgumentException($"数据中心ID必须在0-{MaxDataCenterId}范围内", nameof(dataCenterId));
|
||||
}
|
||||
|
||||
_workerId = workerId;
|
||||
_dataCenterId = dataCenterId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成雪花ID
|
||||
/// </summary>
|
||||
/// <returns>唯一的雪花ID</returns>
|
||||
public static long GenerateId()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
long timestamp = GetCurrentMilliseconds();
|
||||
|
||||
// 时钟回拨检测
|
||||
if (timestamp < _lastTimestamp)
|
||||
{
|
||||
throw new InvalidOperationException("时钟回拨异常,拒绝生成ID");
|
||||
}
|
||||
|
||||
// 同一毫秒内,序列号递增
|
||||
if (timestamp == _lastTimestamp)
|
||||
{
|
||||
_sequence = (_sequence + 1) & MaxSequence;
|
||||
|
||||
// 序列号溢出,等待下一毫秒
|
||||
if (_sequence == 0)
|
||||
{
|
||||
timestamp = WaitNextMillis(_lastTimestamp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_sequence = 0L;
|
||||
}
|
||||
|
||||
_lastTimestamp = timestamp;
|
||||
|
||||
// 组装ID: 时间戳 + 数据中心ID + 机器ID + 序列号
|
||||
return ((timestamp - TwEpoch) << TimestampLeftShift) |
|
||||
(_dataCenterId << DataCenterIdShift) |
|
||||
(_workerId << WorkerIdShift) |
|
||||
_sequence;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前毫秒数
|
||||
/// </summary>
|
||||
private static long GetCurrentMilliseconds()
|
||||
{
|
||||
return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 等待下一毫秒
|
||||
/// </summary>
|
||||
private static long WaitNextMillis(long lastTimestamp)
|
||||
{
|
||||
long timestamp = GetCurrentMilliseconds();
|
||||
while (timestamp <= lastTimestamp)
|
||||
{
|
||||
timestamp = GetCurrentMilliseconds();
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取机器ID(基于MAC地址简单计算)
|
||||
/// </summary>
|
||||
private static long GetWorkerId()
|
||||
{
|
||||
try
|
||||
{
|
||||
string macAddress = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()
|
||||
.FirstOrDefault(n => n.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up &&
|
||||
n.NetworkInterfaceType != System.Net.NetworkInformation.NetworkInterfaceType.Loopback)?
|
||||
.GetPhysicalAddress().ToString() ?? "0";
|
||||
|
||||
long hash = 0;
|
||||
foreach (char c in macAddress)
|
||||
{
|
||||
hash = (hash * 31 + c) & MaxWorkerId;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据中心ID(基于机器名简单计算)
|
||||
/// </summary>
|
||||
private static long GetDataCenterId()
|
||||
{
|
||||
try
|
||||
{
|
||||
string machineName = Environment.MachineName;
|
||||
long hash = 0;
|
||||
foreach (char c in machineName)
|
||||
{
|
||||
hash = (hash * 31 + c) & MaxDataCenterId;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
102
QYZH.InteractiveMagazine.Common/Helpers/ValidateHelper.cs
Normal file
102
QYZH.InteractiveMagazine.Common/Helpers/ValidateHelper.cs
Normal file
@ -0,0 +1,102 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace QYZH.InteractiveMagazine.Common.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// 参数校验工具类
|
||||
/// </summary>
|
||||
public static class ValidateHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 邮箱正则表达式
|
||||
/// </summary>
|
||||
private const string EmailPattern = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";
|
||||
|
||||
/// <summary>
|
||||
/// 手机号正则表达式(中国大陆)
|
||||
/// </summary>
|
||||
private const string PhonePattern = @"^1[3-9]\d{9}$";
|
||||
|
||||
/// <summary>
|
||||
/// 身份证号正则表达式(中国大陆)
|
||||
/// </summary>
|
||||
private const string IdCardPattern = @"^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$";
|
||||
|
||||
/// <summary>
|
||||
/// 校验邮箱格式
|
||||
/// </summary>
|
||||
/// <param name="email">邮箱地址</param>
|
||||
/// <returns>是否有效</returns>
|
||||
public static bool IsEmail(string email)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(email))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Regex.IsMatch(email, EmailPattern);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 校验手机号格式
|
||||
/// </summary>
|
||||
/// <param name="phone">手机号</param>
|
||||
/// <returns>是否有效</returns>
|
||||
public static bool IsPhone(string phone)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(phone))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Regex.IsMatch(phone, PhonePattern);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 校验身份证号格式
|
||||
/// </summary>
|
||||
/// <param name="idCard">身份证号</param>
|
||||
/// <returns>是否有效</returns>
|
||||
public static bool IsIdCard(string idCard)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(idCard))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Regex.IsMatch(idCard, IdCardPattern);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 校验URL格式
|
||||
/// </summary>
|
||||
/// <param name="url">URL地址</param>
|
||||
/// <returns>是否有效</returns>
|
||||
public static bool IsUrl(string url)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const string urlPattern = @"^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$";
|
||||
return Regex.IsMatch(url, urlPattern);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 校验邮政编码格式
|
||||
/// </summary>
|
||||
/// <param name="zipCode">邮政编码</param>
|
||||
/// <returns>是否有效</returns>
|
||||
public static bool IsZipCode(string zipCode)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(zipCode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const string zipPattern = @"^\d{6}$";
|
||||
return Regex.IsMatch(zipCode, zipPattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\QYZH.InteractiveMagazine.Models\QYZH.InteractiveMagazine.Models.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="16.1.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user