合并接口代码

This commit is contained in:
liuzhen 2025-07-14 14:53:51 +08:00
parent d5bf18d324
commit a9be87598b
108 changed files with 9794 additions and 41 deletions

View File

@ -9,11 +9,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DG.Core" Version="1.1.3" />
<PackageReference Include="DG.Redis" Version="1.0.17" />
<PackageReference Include="DG.Tool" Version="1.0.9" />
<PackageReference Include="DG.Kafka" Version="1.0.2" />
<PackageReference Include="DG.Kafka.Worker" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
@ -29,6 +24,11 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DG.Core\DG.Core.csproj" />
<ProjectReference Include="..\DG.Kafka.Worker\DG.Kafka.Worker.csproj" />
<ProjectReference Include="..\DG.Kafka\DG.Kafka.csproj" />
<ProjectReference Include="..\DG.Redis\DG.Redis.csproj" />
<ProjectReference Include="..\DG.Tool\DG.Tool.csproj" />
<ProjectReference Include="..\Zxd.Core.Shared\Zxd.Core.Shared.csproj" />
<ProjectReference Include="..\Zxd.EntityFramework\Zxd.EntityFramework.csproj" />
<ProjectReference Include="..\Zxd.Entity\Zxd.Entity.csproj" />

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public enum LifeCycle
{
Scoped = 0x1,
Singleton = 0x2,
Transient = 0x3,
}
}

View File

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Version>1.1.9</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public interface IScopedDependency
{
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public interface ISingletonDependency
{
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public interface ITransientDependency
{
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public class ApiException : DGException
{
public ApiException(string? message)
: base(message)
{
}
public ApiException(string? message, int code)
: base(message)
{
Data.Add("code", code);
}
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public class DGException : Exception
{
public DGException(string? message)
: base(message)
{
}
public DGException(string? message, int code)
: base(message)
{
Data.Add("code", code);
}
}
}

View File

@ -0,0 +1,20 @@

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public static class HttpExtensions
{
public static string GetCorrelationId(this HttpContext httpContext)
{
httpContext.Request.Headers.TryGetValue("Cko-Correlation-Id", out StringValues correlationId);
return correlationId.FirstOrDefault() ?? httpContext.TraceIdentifier;
}
}
}

View File

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace DG.Core
{
public class JsonOptionsExtensions : JsonConverter<DateTime>
{
private readonly string Format;
public JsonOptionsExtensions(string format = "yyyy-MM-dd HH:mm:ss")
{
Format = format;
}
public override void Write(Utf8JsonWriter writer, DateTime date, JsonSerializerOptions options)
{
writer.WriteStringValue(date.ToString(Format));
}
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
// 获取时间类型的字符串
var dt = reader.GetString();
if (!string.IsNullOrEmpty(dt))
{
//将日期与时间之间的"T"替换为一个空格,将结尾的"Z"去掉,否则会报错
dt = dt.Replace("T", " ").Replace("Z", "");
//取到秒,毫秒内容也要去掉,经过测试,不去掉会报错
if (dt.Length > 19)
{
dt = dt.Substring(0, 19);
}
return DateTime.ParseExact(dt, Format, null);
}
return DateTime.Now;
}
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public static class LinqMethodExtensions
{
/// <summary>
/// 使用自定linq扩展执行排序查询分页功能 item1: 未分页结果item2分页后的结果
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <param name="coditionEntity"></param>
/// <returns></returns>
public static IQueryable<T> UseCoditionFind<T>(this IQueryable<T> source, bool condition, Action<IQueryable<T>> action)
{
if (condition)
{
action(source);
}
return source;
}
}
}

View File

@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public static class PredicateExtensionses
{
public static Expression<Func<T, bool>> True<T>() { return f => true; }
public static Expression<Func<T, bool>> False<T>() { return f => false; }
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expLeft, Expression<Func<T, bool>> expRight)
{
var candidateExpr = Expression.Parameter(typeof(T), "candidate");
var parameterReplacer = new ParameterReplacer(candidateExpr);
var left = parameterReplacer.Replace(expLeft.Body);
var right = parameterReplacer.Replace(expRight.Body);
var body = Expression.And(left, right);
return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expLeft, Expression<Func<T, bool>> expRight)
{
var candidateExpr = Expression.Parameter(typeof(T), "candidate");
var parameterReplacer = new ParameterReplacer(candidateExpr);
var left = parameterReplacer.Replace(expLeft.Body);
var right = parameterReplacer.Replace(expRight.Body);
var body = Expression.OrElse(left, right);
return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
}
/// <summary>
/// And ((a or b )and (x or d))关系但是and后面里面的关系是Or的关系如 a.resid='' and ((a.channel>=1 and a.channel<10) or (a.channel>=50 and a.channel<60))
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="expLeft"></param>
/// <param name="expRight"></param>
/// <returns></returns>
public static Expression<Func<T, bool>> AndListOr<T>(this Expression<Func<T, bool>> expLeft, Expression<Func<T, bool>>[] predicates)
{
var candidateExpr = Expression.Parameter(typeof(T), "candidate");
var parameterReplacer = new ParameterReplacer(candidateExpr);
var left = parameterReplacer.Replace(expLeft.Body);
Expression<Func<T, bool>> lambda = predicates[0];
for (int i = 1; i < predicates.Length; i++)
{
lambda = lambda.Or(predicates[i]);
}
var right = parameterReplacer.Replace(lambda.Body);
var body = Expression.And(left, right);
return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
}
/// <summary>
/// 传入条件之间为OR查询
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <param name="predicates"></param>
/// <returns></returns>
public static IQueryable<T> WhereOR<T>(this IQueryable<T> source, params Expression<Func<T, bool>>[] predicates)
{
if (source == null) throw new ArgumentNullException("source");
if (predicates == null) throw new ArgumentNullException("predicates");
if (predicates.Length == 0) return source.Where(x => true);
if (predicates.Length == 1) return source.Where(predicates[0]);
var param = Expression.Parameter(typeof(T), "x");
Expression body = Expression.Invoke(predicates[0], param);
for (int i = 1; i < predicates.Length; i++)
{
body = Expression.OrElse(body, Expression.Invoke(predicates[i], param));
}
var lambda = Expression.Lambda<Func<T, bool>>(body, param);
return source.Where(lambda);
}
}
internal class ParameterReplacer : ExpressionVisitor
{
public ParameterReplacer(ParameterExpression paramExpr)
{
this.ParameterExpression = paramExpr;
}
public ParameterExpression ParameterExpression { get; private set; }
public Expression Replace(Expression expr)
{
return this.Visit(expr);
}
protected override Expression VisitParameter(ParameterExpression p)
{
return this.ParameterExpression;
}
}
}

View File

@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public static class SystemKeyExtensions
{
/// <summary>
/// If extensions
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <param name="condition"></param>
/// <param name="action"></param>
/// <returns></returns>
public static T If<T>(this T t, bool condition, Action<T> action) where T : class
{
if (condition)
{
action(t);
}
return t;
}
/// <summary>
/// If extensions
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <param name="predicate"></param>
/// <param name="action"></param>
/// <returns></returns>
public static T If<T>(this T t, Predicate<T> predicate, Action<T> action) where T : class
{
if (t == null)
{
throw new ArgumentNullException();
}
if (predicate(t))
{
action(t);
}
return t;
}
/// <summary>
/// If extensions
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <param name="condition"></param>
/// <param name="func"></param>
/// <returns></returns>
public static T If<T>(this T t, bool condition, Func<T, T> func) where T : class => condition ? func(t) : t;
/// <summary>
/// If extensions
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <param name="predicate"></param>
/// <param name="func"></param>
/// <returns></returns>
public static T If<T>(this T t, Predicate<T> predicate, Func<T, T> func) where T : class => predicate(t) ? func(t) : t;
/// <summary>
/// If and else extensions
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <param name="condition"></param>
/// <param name="ifAction"></param>
/// <param name="elseAction"></param>
/// <returns></returns>
public static T IfAndElse<T>(this T t, bool condition, Action<T> ifAction, Action<T> elseAction) where T : class
{
if (condition)
{
ifAction(t);
}
else
{
elseAction(t);
}
return t;
}
/// <summary>
/// If and else extensions
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <param name="predicate"></param>
/// <param name="ifAction"></param>
/// <param name="elseAction"></param>
/// <returns></returns>
public static T IfAndElse<T>(this T t, Predicate<T> predicate, Action<T> ifAction, Action<T> elseAction) where T : class
{
if (t == null)
{
throw new ArgumentNullException();
}
if (predicate(t))
{
ifAction(t);
}
else
{
elseAction(t);
}
return t;
}
/// <summary>
/// If and else extensions
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <param name="condition"></param>
/// <param name="ifFunc"></param>
/// <param name="elseFunc"></param>
/// <returns></returns>
public static T IfAndElse<T>(this T t, bool condition, Func<T, T> ifFunc, Func<T, T> elseFunc) where T : class => condition ? ifFunc(t) : elseFunc(t);
/// <summary>
/// If and else extensions
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <param name="predicate"></param>
/// <param name="ifFunc"></param>
/// <param name="elseFunc"></param>
/// <returns></returns>
public static T IfAndElse<T>(this T t, Predicate<T> predicate, Func<T, T> ifFunc, Func<T, T> elseFunc) where T : class => predicate(t) ? ifFunc(t) : elseFunc(t);
}
}

759
code/DG.Core/HttpClient.cs Normal file
View File

@ -0,0 +1,759 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Unicode;
using System.Threading.Tasks;
using System.Web;
namespace DG.Core
{
public class HttpClient : IHttpClient
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly ILogger<HttpClient> _logger;
private static LogLevel _logLevel = LogLevel.Debug;
public HttpClient(IHttpClientFactory httpClientFactory,
ILogger<HttpClient> logger)
{
_httpClientFactory = httpClientFactory;
_logger = logger;
}
private static JsonSerializerOptions options = new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNameCaseInsensitive = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
public void ChangeLogLevel(LogLevel logLevel)
{
_logLevel = logLevel;
}
private void Log(string message)
{
_logger.Log(_logLevel, message);
}
/// <summary>
/// Post Security
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="url"></param>
/// <param name="data"></param>
/// <param name="clientid"></param>
/// <param name="accessKey"></param>
/// <param name="iv"></param>
/// <returns></returns>
public async Task<T> PostSecurityAsync<T>(string url, object data, string clientid, string accessKey, string iv)
{
try
{
var timeStamp = GetTimeStamp();
var options = new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNameCaseInsensitive = true
};
var param = JsonSerializer.Serialize(data, options);
var bodyJson = EncryptByAES(param, accessKey, iv);
var sign = SignData(bodyJson, accessKey);
var client = _httpClientFactory.CreateClient();
client.DefaultRequestHeaders.TryAddWithoutValidation("clientid", clientid);
client.DefaultRequestHeaders.Add("sign", sign);
var httpData = new StringContent(bodyJson, Encoding.UTF8, "application/json");
Log($"POST 请求Url:{url}, Body:{bodyJson}");
var httpResponse = await client.PostAsync($"{url}", httpData);
var stream = await httpResponse.Content.ReadAsStringAsync();
Log($"请求结果:{stream}");
var response = JsonSerializer.Deserialize<T>(stream, options);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "POST 方法请求错误!");
throw;
}
}
private static string SignData(string ciphertext, string accessKey)
{
Encoding utf = new UTF8Encoding();
HMACMD5 hmac = new HMACMD5(utf.GetBytes(accessKey));
byte[] hashValue = hmac.ComputeHash(utf.GetBytes(ciphertext));
return Convert.ToBase64String(hashValue);
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="url"></param>
/// <param name="param"></param>
/// <param name="data"></param>
/// <param name="clientid"></param>
/// <param name="accessKey"></param>
/// <returns></returns>
public async Task<T> PostSecurityAsync<T>(string url, object param, object data, string clientid, string accessKey)
{
try
{
var timeStamp = GetTimeStamp();
var paramStr = JsonSerializer.Serialize(param, options);
var bodyJson = JsonSerializer.Serialize(data, options);
var content = EncyptData(paramStr, accessKey);
var sign = SignData(content, accessKey);
var client = _httpClientFactory.CreateClient();
client.Timeout = TimeSpan.FromSeconds(30);
var httpData = new StringContent(bodyJson, Encoding.UTF8, "application/json");
url = $"{url}?content={HttpUtility.UrlEncode(content)}&sign={HttpUtility.UrlEncode(sign, Encoding.UTF8)}&clientid={clientid}";
Log($"POST 请求Url:{url}, Body:{bodyJson}");
var httpResponse = await client.PostAsync(url, httpData);
var stream = await httpResponse.Content.ReadAsStringAsync();
Log($"请求结果:{stream}");
var response = JsonSerializer.Deserialize<T>(stream, options);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "POST 方法请求错误!");
throw;
}
}
/// <summary>
/// Post Security
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="url"></param>
/// <param name="data"></param>
/// <param name="clientid"></param>
/// <param name="accessKey"></param>
/// <param name="iv"></param>
/// <returns></returns>
public async Task<string> PostSecurityAsync(string url, object data, string clientid, string accessKey, string iv)
{
try
{
var timeStamp = GetTimeStamp();
var options = new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNameCaseInsensitive = true
};
var param = JsonSerializer.Serialize(data, options);
var bodyJson = EncryptByAES(param, accessKey, iv);
var sign = SignData(bodyJson, accessKey);
var client = _httpClientFactory.CreateClient();
client.DefaultRequestHeaders.TryAddWithoutValidation("clientid", clientid);
client.DefaultRequestHeaders.Add("sign", sign);
var httpData = new StringContent(bodyJson, Encoding.UTF8, "application/json");
Log($"POST 请求Url:{url}, Body:{bodyJson}");
var httpResponse = await client.PostAsync($"{url}", httpData);
var response = await httpResponse.Content.ReadAsStringAsync();
Log($"请求结果:{response}");
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "POST 方法请求错误!");
throw;
}
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="url"></param>
/// <param name="param"></param>
/// <param name="data"></param>
/// <param name="clientid"></param>
/// <param name="accessKey"></param>
/// <returns></returns>
public async Task<string> PostSecurityAsync(string url, object param, object data, string clientid, string accessKey)
{
try
{
var timeStamp = GetTimeStamp();
var paramStr = JsonSerializer.Serialize(param, options);
var bodyJson = JsonSerializer.Serialize(data, options);
var content = EncyptData(paramStr, accessKey);
var sign = SignData(content, accessKey);
var client = _httpClientFactory.CreateClient();
var httpData = new StringContent(bodyJson, Encoding.UTF8, "application/json");
url = $"{url}?content={HttpUtility.UrlEncode(content)}&sign={HttpUtility.UrlEncode(sign, Encoding.UTF8)}&clientid={clientid}";
Log($"POST 请求Url:{url}, Body:{bodyJson}");
var httpResponse = await client.PostAsync(url, httpData);
var response = await httpResponse.Content.ReadAsStringAsync();
Log($"请求结果:{response}");
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "POST 方法请求错误!");
throw;
}
}
public async Task<T> UploadFileAsync<T>(string url, string fileName, string fullName, Dictionary<string, string>? headers = null)
{
try
{
var buffer = await File.ReadAllBytesAsync(fullName);
var client = _httpClientFactory.CreateClient();
if (headers != null)
{
foreach (var header in headers)
{
client.DefaultRequestHeaders.Add(header.Key, header.Value);
}
}
ByteArrayContent fileContent = new ByteArrayContent(buffer);
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = "file", FileName = fileName };
MultipartFormDataContent content = new MultipartFormDataContent
{
fileContent
};
Log($"UploadFile 文件上传请求Url:{url}");
var httpResponse = await client.PostAsync(url, content);
var stream = await httpResponse.Content.ReadAsStringAsync();
Log($"请求结果:{stream}");
var response = JsonSerializer.Deserialize<T>(stream, options);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "UploadFile 方法请求错误!");
throw;
}
}
public async Task<string> UploadFileAsync(string url, string fileName, string fullName, Dictionary<string, string>? headers = null)
{
try
{
var buffer = await File.ReadAllBytesAsync(fullName);
var client = _httpClientFactory.CreateClient();
if (headers != null)
{
foreach (var header in headers)
{
client.DefaultRequestHeaders.Add(header.Key, header.Value);
}
}
ByteArrayContent fileContent = new ByteArrayContent(buffer);
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = "file", FileName = fileName };
MultipartFormDataContent content = new MultipartFormDataContent
{
fileContent
};
Log($"UploadFile 文件上传请求Url:{url}");
var httpResponse = await client.PostAsync(url, content);
var response = await httpResponse.Content.ReadAsStringAsync();
Log($"请求结果:{response}");
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "UploadFile 方法请求错误!");
throw;
}
}
#region
/// <summary>
/// Post
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="url"></param>
/// <param name="data"></param>
/// <param name="appId"></param>
/// <param name="appSecret"></param>
/// <param name="mediaType"></param>
/// <returns></returns>
public async Task<T> PostAsync2<T>(string url, string data, string? appId = "", string? appSecret = "", string? mediaType = "application/json")
{
// _logger.LogInformation("卧槽进来了。1111");
try
{
var client = _httpClientFactory.CreateClient();
//var options = new JsonSerializerOptions
//{
// DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
// PropertyNameCaseInsensitive = true
//};
// _logger.LogInformation("卧槽,进来了。");
var bodyJson = data;
if (!string.IsNullOrEmpty(appId))
{
client.DefaultRequestHeaders.Add("appid", appId);
}
if (!string.IsNullOrEmpty(appId) && !string.IsNullOrEmpty(appSecret))
{
var timeStamp = GetTimeStamp();
var sign = CreateSign(appId, bodyJson, appSecret, timeStamp);
var authorization = $"{appId}:{sign}";
client.DefaultRequestHeaders.TryAddWithoutValidation("authorization", authorization);
client.DefaultRequestHeaders.Add("timestamps", timeStamp);
}
var httpData = new StringContent(bodyJson, Encoding.UTF8, mediaType);
_logger.LogInformation($"POST 请求Url:{url}, Body:{bodyJson}");
var httpResponse = await client.PostAsync($"{url}", httpData);
var stream = await httpResponse.Content.ReadAsStringAsync();
_logger.LogInformation($"请求结果:{stream}");
var response = JsonSerializer.Deserialize<T>(stream, options);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "POST 方法请求错误!");
throw;
}
}
/// <summary>
/// Post
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="url"></param>
/// <param name="data"></param>
/// <param name="appId"></param>
/// <param name="appSecret"></param>
/// <param name="mediaType"></param>
/// <returns></returns>
public async Task<T> PostAsync<T>(string url, object? data = null, string? appId = "", string? appSecret = "", string? mediaType = "application/json")
{
try
{
var client = _httpClientFactory.CreateClient();
//var options = new JsonSerializerOptions
//{
// DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
// PropertyNameCaseInsensitive = true
//};
//_logger.LogInformation("卧槽,进来了。");
var bodyJson = data != null ? Newtonsoft.Json.JsonConvert.SerializeObject(data) : "";
if (!string.IsNullOrEmpty(appId))
{
client.DefaultRequestHeaders.Add("appid", appId);
}
if (!string.IsNullOrEmpty(appId) && !string.IsNullOrEmpty(appSecret))
{
var timeStamp = GetTimeStamp();
var sign = CreateSign(appId, bodyJson, appSecret, timeStamp);
var authorization = $"{appId}:{sign}";
client.DefaultRequestHeaders.TryAddWithoutValidation("authorization", authorization);
client.DefaultRequestHeaders.Add("timestamps", timeStamp);
}
var httpData = new StringContent(bodyJson, Encoding.UTF8, mediaType);
_logger.LogInformation($"POST 请求Url:{url}, Body:{bodyJson}");
var httpResponse = await client.PostAsync($"{url}", httpData);
var stream = await httpResponse.Content.ReadAsStringAsync();
_logger.LogInformation($"请求结果:{stream}");
var response = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(stream);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "POST 方法请求错误!");
throw;
}
}
public async Task<string> PostAsync(string url, object? data = null, string? appId = "", string? appSecret = "", string? mediaType = "application/json")
{
try
{
var client = _httpClientFactory.CreateClient();
var options = new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNameCaseInsensitive = true
};
var bodyJson = data != null ? JsonSerializer.Serialize(data, options) : "";
if (!string.IsNullOrEmpty(appId))
{
client.DefaultRequestHeaders.Add("appid", appId);
}
if (!string.IsNullOrEmpty(appId) && !string.IsNullOrEmpty(appSecret))
{
var timeStamp = GetTimeStamp();
var sign = CreateSign(appId, bodyJson, appSecret, timeStamp);
var authorization = $"{appId}:{sign}";
client.DefaultRequestHeaders.TryAddWithoutValidation("authorization", authorization);
client.DefaultRequestHeaders.Add("timestamps", timeStamp);
}
var httpData = new StringContent(bodyJson, Encoding.UTF8, mediaType);
Log($"POST 请求Url:{url}, Body:{bodyJson}");
var httpResponse = await client.PostAsync($"{url}", httpData);
var response = await httpResponse.Content.ReadAsStringAsync();
Log($"请求结果:{response}");
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "POST 方法请求错误!");
throw;
}
}
/// <summary>
/// Get
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="url"></param>
/// <param name="appId"></param>
/// <param name="appSecret"></param>
/// <returns></returns>
public async Task<T> GetAsync<T>(string url, string appId = "", string appSecret = "", int timeout = 10000)
{
try
{
var client = _httpClientFactory.CreateClient();
client.Timeout = TimeSpan.FromMilliseconds(timeout);
var options = new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNameCaseInsensitive = true
};
if (!string.IsNullOrEmpty(appId))
{
client.DefaultRequestHeaders.Add("appid", appId);
}
if (!string.IsNullOrEmpty(appId) && !string.IsNullOrEmpty(appSecret))
{
var uri = new Uri(url);
var query = uri.Query;
var param = new Dictionary<string, object>();
if (query != null)
{
foreach (var item in query.Split('&'))
{
var sp = item.Split("=");
if (sp.Count() > 1)
{
param.Add(sp[0].Replace("?", ""), sp[1]);
}
}
}
var timeStamp = GetTimeStamp();
param = param.OrderBy(m => m.Key).ToDictionary(m => m.Key, n => n.Value);
var paramStr = JsonSerializer.Serialize(param, options);
var sign = CreateSign(appId, paramStr, appSecret, timeStamp);
var authorization = $"{appId}:{sign}";
client.DefaultRequestHeaders.TryAddWithoutValidation("authorization", authorization);
client.DefaultRequestHeaders.Add("timestamps", timeStamp);
}
Log($"GET 请求Url:{url}");
var httpResponse = await client.GetAsync($"{url}");
var stream = await httpResponse.Content.ReadAsStringAsync();
Log($"请求结果:{stream}");
var response = JsonSerializer.Deserialize<T>(stream, options);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "GET 方法请求错误!");
throw;
}
}
/// <summary>
/// Get
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="url"></param>
/// <param name="param"></param>
/// <param name="appId"></param>
/// <param name="appSecret"></param>
/// <returns></returns>
public async Task<T> GetAsync<T>(string url, Dictionary<string, object> param, string appId = "", string appSecret = "")
{
try
{
var client = _httpClientFactory.CreateClient();
client.Timeout = TimeSpan.FromSeconds(30);
var options = new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNameCaseInsensitive = true
};
var urlParam = string.Join("&", param.Select(m => m.Key + "=" + m.Value));
if (url.IndexOf('?') > -1)
{
url += urlParam;
}
else
{
url = url + "?" + urlParam;
}
if (!string.IsNullOrEmpty(appId))
{
client.DefaultRequestHeaders.Add("appid", appId);
}
if (!string.IsNullOrEmpty(appId) && !string.IsNullOrEmpty(appSecret))
{
var timeStamp = GetTimeStamp();
param = param.OrderBy(m => m.Key).ToDictionary(m => m.Key, n => n.Value);
var paramStr = JsonSerializer.Serialize(param, options);
var sign = CreateSign(appId, paramStr, appSecret, timeStamp);
var authorization = $"{appId}:{sign}";
client.DefaultRequestHeaders.TryAddWithoutValidation("authorization", authorization);
client.DefaultRequestHeaders.Add("timestamps", timeStamp);
}
Log($"GET 请求Url:{url}");
var httpResponse = await client.GetAsync($"{url}");
var stream = await httpResponse.Content.ReadAsStringAsync();
Log($"请求结果:{stream}");
var response = JsonSerializer.Deserialize<T>(stream, options);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "GET 方法请求错误!");
throw;
}
}
/// <summary>
/// Get
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="url"></param>
/// <param name="appId"></param>
/// <param name="appSecret"></param>
/// <returns></returns>
public async Task<string> GetAsync(string url, string appId = "", string appSecret = "")
{
try
{
var client = _httpClientFactory.CreateClient();
client.Timeout = TimeSpan.FromSeconds(30);
var options = new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNameCaseInsensitive = true
};
if (!string.IsNullOrEmpty(appId) && !string.IsNullOrEmpty(appSecret))
{
var uri = new Uri(url);
var query = uri.Query;
var param = new Dictionary<string, object>();
if (query != null)
{
foreach (var item in query.Split('&'))
{
var sp = item.Split("=");
if (sp.Count() > 1)
{
param.Add(sp[0].Replace("?", ""), sp[1]);
}
}
}
var timeStamp = GetTimeStamp();
param = param.OrderBy(m => m.Key).ToDictionary(m => m.Key, n => n.Value);
var paramStr = JsonSerializer.Serialize(param, options);
var sign = CreateSign(appId, paramStr, appSecret, timeStamp);
var authorization = $"{appId}:{sign}";
client.DefaultRequestHeaders.TryAddWithoutValidation("authorization", authorization);
client.DefaultRequestHeaders.Add("timestamps", timeStamp);
}
Log($"GET 请求Url:{url}");
var httpResponse = await client.GetAsync($"{url}");
var response = await httpResponse.Content.ReadAsStringAsync();
Log($"请求结果:{response}");
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "GET 方法请求错误!");
throw;
}
}
/// <summary>
/// Get
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="url"></param>
/// <param name="param"></param>
/// <param name="appId"></param>
/// <param name="appSecret"></param>
/// <returns></returns>
public async Task<string> GetAsync(string url, Dictionary<string, object> param, string appId = "", string appSecret = "")
{
try
{
var client = _httpClientFactory.CreateClient();
client.Timeout = TimeSpan.FromSeconds(30);
var options = new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNameCaseInsensitive = true
};
var urlParam = string.Join("&", param.Select(m => m.Key + "=" + m.Value));
if (url.IndexOf('?') > -1)
{
url += urlParam;
}
else
{
url = url + "?" + urlParam;
}
if (!string.IsNullOrEmpty(appId))
{
client.DefaultRequestHeaders.Add("appid", appId);
}
if (!string.IsNullOrEmpty(appId) && !string.IsNullOrEmpty(appSecret))
{
var timeStamp = GetTimeStamp();
param = param.OrderBy(m => m.Key).ToDictionary(m => m.Key, n => n.Value);
var paramStr = JsonSerializer.Serialize(param, options);
var sign = CreateSign(appId, paramStr, appSecret, timeStamp);
var authorization = $"{appId}:{sign}";
client.DefaultRequestHeaders.TryAddWithoutValidation("authorization", authorization);
client.DefaultRequestHeaders.Add("timestamps", timeStamp);
}
Log($"GET 请求Url:{url}");
var httpResponse = await client.GetAsync($"{url}");
var response = await httpResponse.Content.ReadAsStringAsync();
Log($"请求结果:{response}");
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "GET 方法请求错误!");
throw;
}
}
/// <summary>
/// 生成签名
/// </summary>
/// <param name="appId"></param>
/// <param name="bodyJson"></param>
/// <param name="secret"></param>
/// <param name="timestamps"></param>
/// <returns></returns>
private static string CreateSign(string appId, string bodyJson, string secret, string timestamps)
{
var enStrList = new string[] { appId, bodyJson, secret, timestamps };
Array.Sort(enStrList, string.CompareOrdinal);
var enStr = string.Join("", enStrList);
var md = GetMd5Hash(enStr);
return md;
}
/// <summary>
/// 计算 md5
/// </summary>
/// <param name="enCode"></param>
/// <returns></returns>
private static string GetMd5Hash(string enCode)
{
string res = "";
byte[] data = Encoding.GetEncoding("utf-8").GetBytes(enCode);
MD5 md5 = MD5.Create();
byte[] bytes = md5.ComputeHash(data);
for (int i = 0; i < bytes.Length; i++)
{
res += bytes[i].ToString("x2");
}
return res;
}
/// <summary>
/// 获取时间戳
/// </summary>
/// <returns></returns>
public static string GetTimeStamp()
{
TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return Convert.ToInt64(ts.TotalSeconds).ToString();
}
/// <summary>
/// 加密
/// </summary>
/// <param name="ciphertext"></param>
/// <param name="accessKey"></param>
/// <returns></returns>
private static string EncyptData(string ciphertext, string accessKey)
{
SymmetricAlgorithm des = DES.Create();
Encoding utf = new UTF8Encoding();
byte[] key = utf.GetBytes(accessKey);
byte[] iv = { 0x75, 0x70, 0x63, 0x68, 0x69, 0x6e, 0x61, 0x31 };
ICryptoTransform encryptor = des.CreateEncryptor(key, iv);
byte[] data = utf.GetBytes(ciphertext);
byte[] encData = encryptor.TransformFinalBlock(data, 0, data.Length);
return Convert.ToBase64String(encData);
}
/// <summary>
/// 解密
/// </summary>
/// <param name="cryptograph"></param>
/// <param name="accessKey"></param>
/// <returns></returns>
private static string DecyptData(string cryptograph, string accessKey)
{
SymmetricAlgorithm des = DES.Create();
Encoding utf = new UTF8Encoding();
byte[] key = utf.GetBytes(accessKey);
byte[] iv = { 0x75, 0x70, 0x63, 0x68, 0x69, 0x6e, 0x61, 0x31 };
ICryptoTransform decryptor = des.CreateDecryptor(key, iv);
byte[] encData = Convert.FromBase64String(cryptograph);
byte[] data = decryptor.TransformFinalBlock(encData, 0, encData.Length);
return utf.GetString(data);
}
/// <summary>
/// AES加密算法
/// </summary>
/// <param name="input">明文字符串</param>
/// <returns>字符串</returns>
private static string EncryptByAES(string input, string key, string iv)
{
if (string.IsNullOrWhiteSpace(input))
{
return input;
}
Aes aes = Aes.Create();
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.FeedbackSize = 128;
aes.Key = Encoding.UTF8.GetBytes(key);
aes.IV = Encoding.UTF8.GetBytes(iv);
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using MemoryStream msEncrypt = new();
using CryptoStream csEncrypt = new(msEncrypt, encryptor, CryptoStreamMode.Write);
using (StreamWriter swEncrypt = new(csEncrypt))
{
swEncrypt.Write(input);
}
byte[] bytes = msEncrypt.ToArray();
return Convert.ToBase64String(bytes);
}
#endregion
}
}

View File

@ -0,0 +1,39 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public interface IHttpClient
{
void ChangeLogLevel(LogLevel logLevel);
Task<T> PostSecurityAsync<T>(string url, object data, string clientid, string accessKey, string iv);
Task<T> PostSecurityAsync<T>(string url, object param, object data, string clientid, string accessKey);
Task<string> PostSecurityAsync(string url, object data, string clientid, string accessKey, string iv);
Task<string> PostSecurityAsync(string url, object param, object data, string clientid, string accessKey);
Task<T> PostAsync<T>(string url, object? data = null, string? appId = "", string? appSecret = "", string? mediaType = "application/json");
Task<T> PostAsync2<T>(string url, string data, string? appId = "", string? appSecret = "", string? mediaType = "application/json");
Task<string> PostAsync(string url, object? data = null, string? appId = "", string? appSecret = "", string? mediaType = "application/json");
Task<T> GetAsync<T>(string url, string appId = "", string appSecret = "", int timeout = 10000);
Task<T> GetAsync<T>(string url, Dictionary<string, object> param, string appId = "", string appSecret = "");
Task<string> GetAsync(string url, string appId = "", string appSecret = "");
Task<string> GetAsync(string url, Dictionary<string, object> param, string appId = "", string appSecret = "");
Task<T> UploadFileAsync<T>(string url, string fileName, string fullName, Dictionary<string, string>? headers = null);
Task<string> UploadFileAsync(string url, string fileName, string fullName, Dictionary<string, string>? headers = null);
}
}

View File

@ -0,0 +1,51 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public static class IMvcBuilderApiResultExtensions
{
/// <summary>
/// 启用API标准返回值模式
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static IMvcBuilder AddApiResult(this IMvcBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
return builder.AddMvcOptions(options => {
options.Filters.Add(typeof(ApiExceptionFilterAttribute));
options.Filters.Add(typeof(ApiResultFilterAttribute));
});
}
/// <summary>
/// 启用API签名模式
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static IMvcBuilder AddApiSignature(this IMvcBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
return builder.AddMvcOptions(options => {
options.Filters.Add(typeof(ApiSecurityAsyncFilter));
options.Filters.Add(typeof(ApiSignatureAsyncFilterAttribute));
options.Filters.Add(typeof(ApiTimeSecurityAsyncFilter));
});
}
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public interface IMapper
{
TTarget Map<TSource, TTarget>(TSource source);
List<TTarget> Map<TSource, TTarget>(List<TSource> source);
}
}

View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
internal class Mapper
{
public static readonly Mapper Instance = new Mapper();
private Mapper()
{
}
public TTarget Map<TSource, TTarget>(TSource source) => CacheModel<TSource, TTarget>.Invoke(source);
public List<TTarget> Map<TSource, TTarget>(List<TSource> sources) => sources.AsParallel().Select(CacheModel<TSource, TTarget>.Invoke).ToList();
internal class CacheModel<TSource, TTarget>
{
private static readonly Func<TSource, TTarget> Func;
static CacheModel()
{
var parameterExpression = Expression.Parameter(typeof(TSource), "x");
var sourcePropNames = typeof(TSource).GetProperties()
.Where(x => !x.IsDefined(typeof(NotMapAttribute), true))
.Select(x => x.Name)
.ToArray();
var memberBindings = typeof(TTarget).GetProperties()
.Where(x => x.CanWrite && sourcePropNames.Any(y => y.ToUpper() == x.Name.ToUpper()))
.Select(x => Expression.Bind(typeof(TTarget).GetProperty(x.Name),
Expression.Property(parameterExpression,
typeof(TSource).GetProperty(sourcePropNames.FirstOrDefault(y => y.ToUpper() == x.Name.ToUpper())))));
Func = Expression.Lambda<Func<TSource, TTarget>>(Expression.MemberInit(Expression.New(typeof(TTarget)), memberBindings), parameterExpression).Compile();
}
public static TTarget Invoke(TSource source) => Func(source);
}
}
}

View File

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public static class MapperExtendsions
{
/// <summary>
/// 映射到
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TTarget"></typeparam>
/// <param name="source"></param>
/// <returns></returns>
public static TTarget Map<TSource, TTarget>(this TSource source) => Mapper.Instance.Map<TSource, TTarget>(source);
/// <summary>
/// 映射到
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TTarget"></typeparam>
/// <param name="sources"></param>
/// <returns></returns>
public static List<TTarget> Map<TSource, TTarget>(this List<TSource> sources) => Mapper.Instance.Map<TSource, TTarget>(sources);
/// <summary>
/// 复制到
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TTarget"></typeparam>
/// <param name="source"></param>
/// <returns></returns>
/// <remarks>因为重名了,所以对方法取别名,同 MapTo</remarks>
public static TTarget Replicate<TSource, TTarget>(this TSource source) => source.Map<TSource, TTarget>();
/// <summary>
/// 复制到
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TTarget"></typeparam>
/// <param name="sources"></param>
/// <returns></returns>
/// <remarks>因为重名了,所以对方法取别名,同 MapTo</remarks>
public static List<TTarget> Replicate<TSource, TTarget>(this List<TSource> sources) => sources.Map<TSource, TTarget>();
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public class MapperManager : IMapper
{
public TTarget Map<TSource, TTarget>(TSource source) => source.Map<TSource, TTarget>();
public List<TTarget> Map<TSource, TTarget>(List<TSource> source) => source.Map<TSource, TTarget>();
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public class NotMapAttribute : Attribute
{
public NotMapAttribute()
{
}
}
}

View File

@ -0,0 +1,49 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using System.Text.Json;
namespace DG.Core
{
/// <summary>
/// 表示处理API异常的筛选器。
/// </summary>
public class ApiExceptionFilterAttribute : Attribute, IExceptionFilter
{
private readonly ILogger<ApiExceptionFilterAttribute> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="ApiExceptionFilterAttribute" /> class.
/// </summary>
/// <param name="logger">The logger</param>
public ApiExceptionFilterAttribute(ILogger<ApiExceptionFilterAttribute> logger)
{
_logger = logger;
}
/// <summary>
/// Called when [exception].
/// </summary>
/// <param name="context">The context.</param>
public void OnException(ExceptionContext context)
{
_logger.LogError(0, context.Exception, $"ip={context.HttpContext.Connection.RemoteIpAddress}, path={context.HttpContext.Request.Path}, error={JsonSerializer.Serialize(context.Exception.Message)}");
if (context.Exception.Data != null && context.Exception.Data["code"] != null)
{
var code = (int)context.Exception.Data["code"];
context.Result = new ObjectResult(ApiResult.Failed(context.Exception.Message, code));
}
else
{
context.Result = new ObjectResult(ApiResult.Failed(context.Exception.Message));
}
context.ExceptionHandled = true;
}
}
}

View File

@ -0,0 +1,37 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public class ApiResourceFilter : Attribute, IResourceFilter
{
public void OnResourceExecuted(ResourceExecutedContext context)
{
if (!context.ModelState.IsValid)
{
var errors = string.Empty;
foreach (var key in context.ModelState.Keys)
{
var modelState = context.ModelState[key];
foreach (var error in modelState.Errors)
{
errors += string.IsNullOrEmpty(errors) ? error.ErrorMessage
: $",{error.ErrorMessage}";
}
}
context.Result = new ObjectResult(ApiResult.Failed(errors));
}
// 执行完后的操作
}
public void OnResourceExecuting(ResourceExecutingContext context)
{
// 执行中的过滤器管道
}
}
}

View File

@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace DG.Core
{
public class ApiResult : IApiResult
{
/// <summary>
/// Represents an empty <see cref="IApiResult"/>.
/// </summary>
public static readonly IApiResult Empty = new ApiResult
{
Code = 0
};
/// <summary>
/// Gets or sets the status code.
/// </summary>
/// <value>The status code.</value>
[JsonPropertyName("code")]
public int Code { get; set; }
/// <summary>
/// Gets or sets the message.
/// </summary>
/// <value>The message.</value>
[JsonPropertyName("message")]
public string? Message { get; set; }
/// <summary>
/// Creates a new instance of <see cref="IApiResult{TData}"/> by the specified result.
/// </summary>
/// <typeparam name="TData">The type of the result.</typeparam>
/// <param name="data">The result.</param>
/// <returns>An instance inherited from <see cref="IApiResult{TResult}"/> interface.</returns>
public static IApiResult<TData> Succeed<TData>(TData data) => new ApiResult<TData>
{
Code = 0,
Data = data
};
/// <summary>
/// Creates a new instance of <see cref="IApiResult"/> by the specified error message.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="code">The status code</param>
/// <returns>An instance inherited from <see cref="IApiResult"/> interface.</returns>
public static IApiResult Failed(string message, int? code = null) => new ApiResult
{
Code = code ?? -1,
Message = message
};
/// <summary>
/// Creates a new instance of <see cref="IApiResult{TResult}"/> by the specified error message.
/// </summary>
/// <typeparam name="TData">The type of the result.</typeparam>
/// <param name="data">The error result.</param>
/// <param name="message">The message.</param>
/// <param name="code">The status code.</param>
/// <returns>An instance inherited from <see cref="IApiResult"/> interface.</returns>
public static IApiResult<TData> Failed<TData>(TData data, string message, int? code = null) => new ApiResult<TData>
{
Code = code ?? -1,
Message = message,
Data = data
};
/// <summary>
/// Creates a new instance of <see cref="IApiResult"/> by the specified status code and message.
/// </summary>
/// <param name="code">The status code.</param>
/// <param name="message">The message.</param>
/// <returns>An instance inherited from <see cref="IApiResult"/> interface.</returns>
public static IApiResult From(int code, string message = null) => new ApiResult
{
Code = code,
Message = message
};
/// <summary>
/// Creates a new instance of <see cref="IApiResult{TResult}"/> by the specified result.
/// </summary>
/// <typeparam name="TData">The type of the result.</typeparam>
/// <param name="data">The result.</param>
/// <param name="code">The status code.</param>
/// <param name="message">The message.</param>
/// <returns>An instance inherited from <see cref="IApiResult{TResult}"/> interface.</returns>
public static IApiResult<TData> From<TData>(TData data, int code, string message) => new ApiResult<TData>
{
Code = code,
Message = message,
Data = data
};
}
}

View File

@ -0,0 +1,69 @@
using System;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace DG.Core
{
public class ApiResultFilterAttribute : ResultFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext context)
{
if (context.Filters.Any(filterMetadata => filterMetadata.GetType() == typeof(ApiResultFilterForbidAttribute)))
{
return;
}
switch (context.Result)
{
case ObjectResult result:
{
// this include OkObjectResult, NotFoundObjectResult, BadRequestObjectResult, CreatedResult (lose Location)
var objectResult = result;
if (objectResult.Value == null)
{
context.Result = new ObjectResult(ApiResult.Empty);
}
else if (objectResult.Value is ValidationProblemDetails validationProblemDetails)
{
var errors = string.Empty;
foreach(var error in validationProblemDetails.Errors)
{
errors += string.IsNullOrEmpty(errors) ? error.Value.First()
: $",{error.Value.First()}";
}
context.Result = new ObjectResult(ApiResult.Failed(errors));
}
else if (!(objectResult.Value is IApiResult))
{
if (objectResult.DeclaredType != null)
{
var apiResult = Activator.CreateInstance(
typeof(ApiResult<>).MakeGenericType(objectResult.DeclaredType), objectResult.Value, objectResult.StatusCode);
context.Result = new ObjectResult(apiResult);
}
else
{
context.Result = objectResult;
}
}
break;
}
case EmptyResult _:
// return void or Task
context.Result = new ObjectResult(ApiResult.Empty);
break;
case ContentResult result:
context.Result = new ObjectResult(ApiResult.Succeed(result.Content));
break;
case StatusCodeResult result:
// this include OKResult, NoContentResult, UnauthorizedResult, NotFoundResult, BadRequestResult
context.Result = new ObjectResult(ApiResult.From(result.StatusCode));
break;
}
}
}
}

View File

@ -0,0 +1,15 @@
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public class ApiResultFilterForbidAttribute : ResultFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext context)
{ }
}
}

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace DG.Core
{
public class ApiResult<TData> : ApiResult, IApiResult<TData>
{
/// <summary>
/// Initializes a new instance of the <see cref="ApiResult{TResult}"/> class.
/// </summary>
public ApiResult() { }
/// <summary>
/// Initializes a new instance of the <see cref="ApiResult{TResult}" /> class.
/// </summary>
/// <param name="data">The result.</param>
/// <param name="code">The status code.</param>
public ApiResult(TData data, int? code)
{
Code = code ?? 0;
Data = data;
}
/// <summary>
/// Gets or sets the result.
/// </summary>
/// <value>The result.</value>
[JsonPropertyName("data")]
public TData Data { get; set; }
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public interface IApiResult
{
/// <summary>
/// Gets or sets the status code.
/// </summary>
/// <value>The status code.</value>
int Code { get; set; }
/// <summary>
/// Gets or sets the message.
/// </summary>
/// <value>The message.</value>
string Message { get; set; }
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public interface IApiResult<TData> : IApiResult
{
/// <summary>
/// Gets or sets the result.
/// </summary>
/// <value>The result.</value>
TData Data { get; set; }
}
}

View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public class PageResult<TData> where TData : class
{
public PageResult(int pageIndex, int pageSize, int total, IList<TData>? data)
{
PageIndex = pageIndex;
PageSize = pageSize;
Total = total;
Data = data;
TotalCount = total == 0 ? 0 : (Total / PageSize) + (Total % PageSize) > 0 ? 1 : 0;
}
/// <summary>
/// 页数
/// </summary>
public int PageIndex { get; set; }
/// <summary>
/// 分页大小
/// </summary>
public int PageSize { get; set; }
/// <summary>
/// 总数量
/// </summary>
public int Total { get; set; }
/// <summary>
/// 分页总数量
/// </summary>
public int TotalCount { get; set; }
/// <summary>
/// 数据
/// </summary>
public IList<TData>? Data { get; set; }
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public class SearchPageBase
{
/// <summary>
/// 页数
/// </summary>
public int PageIndex { get; set; }
/// <summary>
/// 分页大小
/// </summary>
public int PageSize { get; set; }
/// <summary>
/// 排序字段,支持逗号隔开
/// </summary>
public string? Sort { get; set; }
/// <summary>
/// 升降序Asc/Desc
/// </summary>
public string? Order { get; set; }
/// <summary>
/// 是否导出
/// </summary>
public bool? Export { get; set; }
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public class SelectItem
{
public SelectItem(object key, object value)
{
Key = key;
Value = value;
}
public object Key { get; set; }
public object? Value { get; set; }
}
}

View File

@ -0,0 +1,133 @@
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.Json;
using Microsoft.Extensions.Configuration;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Text.Json.Serialization;
namespace DG.Core
{
public class ApiSecurityAsyncFilter : IAsyncAuthorizationFilter
{
private readonly IConfiguration _configuration;
private readonly ILogger<ApiSecurityAsyncFilter> _logger;
public ApiSecurityAsyncFilter(IConfiguration configuration,
ILogger<ApiSecurityAsyncFilter> logger)
{
_configuration = configuration;
_logger = logger;
}
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
if (!context.Filters.Any(filterMetadata => filterMetadata.GetType() == typeof(ApiSecurityAttribute)))
{
return;
}
var request = context.HttpContext.Request;
if (!request.Method.ToLower().Equals("post"))
{
context.Result = new ObjectResult(ApiResult.Failed("ApiSecurityAsyncFilter只支持POST方法!", 10004));
return;
}
var clientKeys = _configuration.GetSection("ClientKey").Get<List<ClientKey>>();
if (clientKeys == null || !clientKeys.Any())
{
context.Result = new ObjectResult(ApiResult.Failed("ClientKey没有配置!", 10003));
return;
}
var clientid = request.Headers["clientid"].ToString();
var sign = request.Headers["sign"].ToString();
if (string.IsNullOrEmpty(clientid) || string.IsNullOrEmpty(sign))
{
context.Result = new ObjectResult(ApiResult.Failed("请求头clientid或sign不能为空!", 10003));
return;
}
var client = clientKeys.First(x => x.Id == clientid);
request.EnableBuffering();
var stream = request.Body;
var buffer = new byte[request.ContentLength.Value];
await stream.ReadAsync(buffer);
var bodyJson = Encoding.UTF8.GetString(buffer);
stream.Position = 0;
var signData = SignData(bodyJson, client.NewAccessKey);
if (!signData.Equals(sign))
{
context.Result = new ObjectResult(ApiResult.Failed("签名不合法!", 10001));
return;
}
try
{
var contextAes = DecryptByAES(client, bodyJson);
var options = new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNameCaseInsensitive = true
};
var dataContext = Encoding.UTF8.GetBytes(contextAes);
var requestBodyStream = new MemoryStream();//创建一个流
requestBodyStream.Seek(0, SeekOrigin.Begin);//设置从0开始读取
requestBodyStream.Write(dataContext, 0, dataContext.Length);//把修改写入流中
request.Body = requestBodyStream;//把修改后的内容赋值给请求body
request.Body.Seek(0, SeekOrigin.Begin);
request.Body.Position = 0;
}
catch (Exception ex)
{
_logger.LogInformation(ex, "报错解密");
}
}
private static string SignData(string ciphertext, string accessKey)
{
Encoding utf = new UTF8Encoding();
HMACMD5 hmac = new HMACMD5(utf.GetBytes(accessKey));
byte[] hashValue = hmac.ComputeHash(utf.GetBytes(ciphertext));
return Convert.ToBase64String(hashValue);
}
private static string DecryptByAES(ClientKey client, string bodyJson)
{
return DecryptByAES(bodyJson, client.NewAccessKey, client.Vi);
}
/// <summary>
/// AES解密
/// </summary>
/// <param name="input">密文字节数组</param>
/// <returns>返回解密后的字符串</returns>
private static string DecryptByAES(string input, string key, string iv)
{
if (string.IsNullOrWhiteSpace(input))
{
return input;
}
var buffer = Convert.FromBase64String(input);
using Aes aes = Aes.Create();
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.FeedbackSize = 128;
aes.Key = Encoding.UTF8.GetBytes(key);
aes.IV = Encoding.UTF8.GetBytes(iv);
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using MemoryStream msEncrypt = new(buffer);
using CryptoStream csEncrypt = new(msEncrypt, decryptor, CryptoStreamMode.Read);
using StreamReader srEncrypt = new(csEncrypt);
return srEncrypt.ReadToEnd();
}
}
}

View File

@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
/// <summary>
/// 安全API
/// </summary>
public class ApiSecurityAttribute : Attribute, IFilterMetadata
{
public ApiSecurityAttribute()
{
}
}
}

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
internal class ClientKey
{
public ClientKey(string id, string name, string accessKey, string vi, string newAccessKey)
{
Id = id;
Name = name;
AccessKey = accessKey;
Vi = vi;
NewAccessKey = newAccessKey;
}
public ClientKey()
{
}
public string Id { get; set; }
public string Name { get; set; }
public string AccessKey { get; set; }
public string Vi { get; set; }
public string NewAccessKey { get; set; }
}
}

View File

@ -0,0 +1,65 @@
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
namespace DG.Core
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddMapper(this IServiceCollection services)
=> services.AddSingleton<IMapper, MapperManager>();
/// <summary>
/// Add auto ioc services
/// </summary>
/// <param name="services"></param>
/// <param name="baseType"></param>
/// <param name="lifeCycle"></param>
/// <returns></returns>
public static IServiceCollection AddAutoIoc(this IServiceCollection services, Type baseType, LifeCycle lifeCycle)
{
if (!baseType.IsInterface)
{
throw new TypeLoadException("The status code must be an enumerated type");
}
var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory;
var referencedAssemblies = System.IO.Directory.GetFiles(path, "*.dll").Select(Assembly.LoadFrom).ToArray();
var types = referencedAssemblies
.SelectMany(a => a.DefinedTypes)
.Select(type => type.AsType())
.Where(x => x != baseType && baseType.IsAssignableFrom(x)).ToArray();
var implementTypes = types.Where(x => x.IsClass).ToArray();
var interfaceTypes = types.Where(x => x.IsInterface).ToArray();
foreach (var implementType in implementTypes)
{
var interfaceType = interfaceTypes.FirstOrDefault(x => x.IsAssignableFrom(implementType));
if (interfaceType != null)
switch (lifeCycle)
{
case LifeCycle.Singleton:
services.AddSingleton(interfaceType, implementType);
break;
case LifeCycle.Transient:
services.AddTransient(interfaceType, implementType);
break;
case LifeCycle.Scoped:
services.AddScoped(interfaceType, implementType);
break;
default:
throw new ArgumentOutOfRangeException(nameof(lifeCycle), lifeCycle, null);
}
}
return services;
}
public static IServiceCollection AddDGHttpClient(this IServiceCollection services)
{
return services.AddHttpClient()
.AddTransient<IHttpClient, HttpClient>();
}
}
}

View File

@ -0,0 +1,138 @@
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.Json;
using Microsoft.Extensions.Configuration;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using System.Text.Json.Serialization;
namespace DG.Core
{
public class ApiSignatureAsyncFilterAttribute : IAsyncAuthorizationFilter
{
private readonly IConfiguration _configuration;
public ApiSignatureAsyncFilterAttribute(IConfiguration configuration)
{
_configuration = configuration;
}
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
if (context.Filters.Any(filterMetadata =>
filterMetadata.GetType() == typeof(ApiSignatureFilterForbidAttribute) ||
filterMetadata.GetType() == typeof(ApiSecurityAttribute) ||
filterMetadata.GetType() == typeof(ApiTimeSecurityAttribute)))
{
return;
}
var request = context.HttpContext.Request;
var appId = _configuration.GetSection("SignConfig:AppId").Value;
var secret = _configuration.GetSection("SignConfig:Secret").Value;
if (string.IsNullOrWhiteSpace(appId) || string.IsNullOrWhiteSpace(secret))
{
context.Result = new ObjectResult(ApiResult.Failed("appId或secret没有配置!", 10003));
return;
}
var authorization = request.Headers["Authorization"].ToString();
var timestamps = request.Headers["timestamps"].ToString();
if (string.IsNullOrEmpty(authorization) || string.IsNullOrEmpty(timestamps))
{
context.Result = new ObjectResult(ApiResult.Failed("请求头authorization或timestamps不能为空!", 10003));
return;
}
string? bodyJson;
var options = new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNameCaseInsensitive = true
};
if (request.Method.ToLower().Equals("get") || request.Method.ToLower().Equals("delete"))
{
var query = request.Query;
var parames = new Dictionary<string, object>();
foreach (var item in query)
{
parames.Add(item.Key, item.Value.ToString());
}
parames = parames.OrderBy(m => m.Key).ToDictionary(m => m.Key, n => n.Value);
bodyJson = JsonSerializer.Serialize(parames, options);
}
else
{
request.EnableBuffering();
var stream = request.Body;
var buffer = new byte[request.ContentLength.Value];
await stream.ReadAsync(buffer);
bodyJson = Encoding.UTF8.GetString(buffer);
stream.Position = 0;
}
var md = CreateSign(appId, bodyJson, secret, timestamps);
if (authorization != $"{appId}:{md}")
{
context.Result = new ObjectResult(ApiResult.Failed("签名不合法!", 10001));
}
else
{
var nowTime = GetTimeStamp();
var diff = Convert.ToInt32(nowTime) - Convert.ToInt32(timestamps);
if (diff > 1800)
{
context.Result = new ObjectResult(ApiResult.Failed("签名已过期!", 10002));
}
}
}
/// <summary>
/// 生成签名
/// </summary>
/// <param name="appId"></param>
/// <param name="bodyJson"></param>
/// <param name="secret"></param>
/// <param name="timestamps"></param>
/// <returns></returns>
private static string CreateSign(string appId, string bodyJson, string secret, string timestamps)
{
var enStrList = new string[] { appId, bodyJson, secret, timestamps };
Array.Sort(enStrList, string.CompareOrdinal);
var enStr = string.Join("", enStrList);
var md = GetMd5Hash(enStr);
return md;
}
/// <summary>
/// 计算 md5
/// </summary>
/// <param name="enCode"></param>
/// <returns></returns>
private static string GetMd5Hash(string enCode)
{
string res = "";
byte[] data = Encoding.GetEncoding("utf-8").GetBytes(enCode);
MD5 md5 = MD5.Create();
byte[] bytes = md5.ComputeHash(data);
for (int i = 0; i < bytes.Length; i++)
{
res += bytes[i].ToString("x2");
}
return res;
}
/// <summary>
/// 获取时间戳
/// </summary>
/// <returns></returns>
public static string GetTimeStamp()
{
TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return Convert.ToInt64(ts.TotalSeconds).ToString();
}
}
}

View File

@ -0,0 +1,19 @@
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
/// <summary>
/// API屏蔽签名
/// </summary>
public class ApiSignatureFilterForbidAttribute : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
}
}
}

View File

@ -0,0 +1,171 @@
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.Json;
using Microsoft.Extensions.Configuration;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Text.Json.Serialization;
using System.Collections.Specialized;
namespace DG.Core
{
public class ApiTimeSecurityAsyncFilter : IAsyncAuthorizationFilter
{
private readonly IConfiguration _configuration;
private readonly ILogger<ApiTimeSecurityAsyncFilter> _logger;
public ApiTimeSecurityAsyncFilter(IConfiguration configuration,
ILogger<ApiTimeSecurityAsyncFilter> logger)
{
_configuration = configuration;
_logger = logger;
}
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
if (!context.Filters.Any(filterMetadata => filterMetadata.GetType() == typeof(ApiTimeSecurityAttribute)))
{
return;
}
var request = context.HttpContext.Request;
var clientKeys = _configuration.GetSection("ClientKey").Get<List<ClientKey>>();
if (clientKeys == null || !clientKeys.Any())
{
context.Result = new ObjectResult(ApiResult.Failed("ClientKey没有配置!", 10003));
return;
}
var clientid = request.Headers["clientid"].ToString();
var sign = request.Headers["sign"].ToString();
var timestamps = request.Headers["timestamps"].ToString();
if (string.IsNullOrEmpty(clientid) || string.IsNullOrEmpty(sign) || string.IsNullOrEmpty(timestamps))
{
context.Result = new ObjectResult(ApiResult.Failed("请求头clientid或sign或timestamps不能为空!", 10003));
return;
}
var client = clientKeys.First(x => x.Id == clientid);
string? bodyJson;
var options = new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNameCaseInsensitive = true
};
if (request.Method.ToLower().Equals("get") || request.Method.ToLower().Equals("delete"))
{
var query = request.Query;
var parames = new Dictionary<string, object>();
foreach (var item in query)
{
parames.Add(item.Key, item.Value.ToString());
}
bodyJson = JsonSerializer.Serialize(parames, options);
}
else
{
request.EnableBuffering();
var stream = request.Body;
var buffer = new byte[request.ContentLength.Value];
await stream.ReadAsync(buffer);
bodyJson = Encoding.UTF8.GetString(buffer);
stream.Position = 0;
var content = JsonSerializer.Deserialize<ContentDto>(bodyJson);
bodyJson = content.Content;
}
var signData = SignData(bodyJson, client.NewAccessKey);
if (!signData.Equals(sign))
{
context.Result = new ObjectResult(ApiResult.Failed("签名不合法!", 10001));
return;
}
else
{
var nowTime = GetTimeStamp();
var diff = Convert.ToInt32(nowTime) - Convert.ToInt32(timestamps);
if (diff > 1800)
{
context.Result = new ObjectResult(ApiResult.Failed("签名已过期!", 10002));
}
}
try
{
var contextAes = DecryptByAES(client, bodyJson);
var dataContext = Encoding.UTF8.GetBytes(contextAes);
var requestBodyStream = new MemoryStream();//创建一个流
requestBodyStream.Seek(0, SeekOrigin.Begin);//设置从0开始读取
requestBodyStream.Write(dataContext, 0, dataContext.Length);//把修改写入流中
request.Body = requestBodyStream;//把修改后的内容赋值给请求body
request.Body.Seek(0, SeekOrigin.Begin);
request.Body.Position = 0;
}
catch (Exception ex)
{
_logger.LogInformation(ex, "报错解密");
}
}
private static string SignData(string ciphertext, string accessKey)
{
Encoding utf = new UTF8Encoding();
HMACMD5 hmac = new HMACMD5(utf.GetBytes(accessKey));
byte[] hashValue = hmac.ComputeHash(utf.GetBytes(ciphertext));
return Convert.ToBase64String(hashValue);
}
private static string DecryptByAES(ClientKey client, string bodyJson)
{
return DecryptByAES(bodyJson, client.NewAccessKey, client.Vi);
}
/// <summary>
/// AES解密
/// </summary>
/// <param name="input">密文字节数组</param>
/// <returns>返回解密后的字符串</returns>
private static string DecryptByAES(string input, string key, string iv)
{
if (string.IsNullOrWhiteSpace(input))
{
return input;
}
var buffer = Convert.FromBase64String(input);
using Aes aes = Aes.Create();
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.FeedbackSize = 128;
aes.Key = Encoding.UTF8.GetBytes(key);
aes.IV = Encoding.UTF8.GetBytes(iv);
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using MemoryStream msEncrypt = new(buffer);
using CryptoStream csEncrypt = new(msEncrypt, decryptor, CryptoStreamMode.Read);
using StreamReader srEncrypt = new(csEncrypt);
return srEncrypt.ReadToEnd();
}
/// <summary>
/// 获取时间戳
/// </summary>
/// <returns></returns>
public static string GetTimeStamp()
{
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return Convert.ToInt64(ts.TotalSeconds).ToString();
}
}
public class ContentDto
{
public string Content { get; set; }
}
}

View File

@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
/// <summary>
/// 安全API
/// </summary>
public class ApiTimeSecurityAttribute : Attribute, IFilterMetadata
{
public ApiTimeSecurityAttribute()
{
}
}
}

View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public class DecimalValidationAttribute : ValidationAttribute
{
public int? Length { get; }
private bool LengthError { get; set; }
public DecimalValidationAttribute()
{
}
public DecimalValidationAttribute(int? length)
{
Length = length;
}
/// <summary>
/// IsValid 为 false 时,提示得 error 信息
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public override string FormatErrorMessage(string name)
{
var lengthMessage = LengthError ? $",且长度不能超过{Length}" : "";
return $"{name}必须输入数字{lengthMessage},请重新输入!";
}
/// <summary>
/// 验证当前字段得结果
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public override bool IsValid(object? value)
{
if (value == null) return true;
if (decimal.TryParse(Convert.ToString(value), out decimal num))
{
if (Length != null && num.ToString().Length > Length)
{
LengthError = true;
return false;
}
return true;
}
else
{
return false;
}
}
}
}

View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public class IntValidationAttribute : ValidationAttribute
{
public int? Length { get; }
private bool LengthError { get; set; }
public IntValidationAttribute()
{
}
public IntValidationAttribute(int? length)
{
Length = length;
}
/// <summary>
/// IsValid 为 false 时,提示得 error 信息
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public override string FormatErrorMessage(string name)
{
var lengthMessage = LengthError ? $",且长度不能超过{Length}" : "";
return $"{name}必须输入数字{lengthMessage},请重新输入!";
}
/// <summary>
/// 验证当前字段得结果
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public override bool IsValid(object? value)
{
if (value == null) return true;
if (int.TryParse(Convert.ToString(value), out int num))
{
if (Length != null && num.ToString().Length > Length)
{
LengthError = true;
return false;
}
return true;
}
else
{
return false;
}
}
}
}

View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Core
{
public class LongValidationAttribute : ValidationAttribute
{
public int? Length { get; }
private bool LengthError { get; set; }
public LongValidationAttribute()
{
}
public LongValidationAttribute(int? length)
{
Length = length;
}
/// <summary>
/// IsValid 为 false 时,提示得 error 信息
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public override string FormatErrorMessage(string name)
{
var lengthMessage = LengthError ? $",且长度不能超过{Length}" : "";
return $"{name}必须输入数字{lengthMessage},请重新输入!";
}
/// <summary>
/// 验证当前字段得结果
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public override bool IsValid(object? value)
{
if (value == null) return true;
if (long.TryParse(Convert.ToString(value), out long num))
{
if (Length != null && num.ToString().Length > Length)
{
LengthError = true;
return false;
}
return true;
}
else
{
return false;
}
}
}
}

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Version>1.0.32</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.6" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="6.0.0" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,23 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;
namespace DG.EntityFramework
{
public class DbContextProvider<TDbContext> : IDbContextProvider<TDbContext>
where TDbContext : DbContext
{
private readonly TDbContext _dbContext;
public DbContextProvider(TDbContext dbContext)
{
_dbContext = dbContext;
}
public TDbContext GetDbContext()
{
return _dbContext;
}
}
}

View File

@ -0,0 +1,38 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Text;
namespace DG.EntityFramework
{
/// <summary>
/// Entity Framework Core Options
/// </summary>
public class EFCoreOptions<TDbContext>
where TDbContext : DbContext
{
/// <summary>
/// Gets or sets the database's connection string that will be used to store database entities.
/// </summary>
public string ConnectionString { get; set; }
/// <summary>
///
/// </summary>
public DbConnection ExistingConnection { get; internal set; }
/// <summary>
///
/// </summary>
public DbContextOptionsBuilder<TDbContext> DbContextOptions { get; }
internal string Version { get; set; }
public EFCoreOptions()
{
DbContextOptions = new DbContextOptionsBuilder<TDbContext>();
Version = "1.0.0";
}
}
}

View File

@ -0,0 +1,28 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
namespace DG.EntityFramework
{
public class EFCoreOptionsExtension<TDbContext>
where TDbContext : DbContext
{
private readonly Action<EFCoreOptions<TDbContext>> _configure;
public EFCoreOptionsExtension(Action<EFCoreOptions<TDbContext>> configure)
{
_configure = configure;
}
public void AddServices(IServiceCollection services)
{
var options = new EFCoreOptions<TDbContext>();
_configure(options);
services.AddDbContext<TDbContext>();
services.Configure(_configure);
services.AddScoped<IUnitOfWorkManager, UnitOfWorkManager<TDbContext>>();
services.AddScoped<IUnitOfWorkCompleteHandle, UnitOfWorkCompleteHandle<TDbContext>>();
services.AddScoped<IDbContextProvider<TDbContext>, DbContextProvider<TDbContext>>();
}
}
}

View File

@ -0,0 +1,26 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.Extensions.Logging;
namespace DG.EntityFramework
{
public class EFDbContext : DbContext
{
public EFDbContext(DbContextOptions options)
: base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development")
{
var loggerFactory = new LoggerFactory();
loggerFactory.AddProvider(new EFLoggerProvider());
optionsBuilder.UseLoggerFactory(loggerFactory);
}
base.OnConfiguring(optionsBuilder);
}
}
}

View File

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Extensions.Logging;
namespace DG.EntityFramework
{
public class EFLoggerProvider : ILoggerProvider
{
public ILogger CreateLogger(string categoryName) => new EFLogger(categoryName);
public void Dispose()
{
}
}
public class EFLogger : ILogger
{
private readonly string categoryName;
public EFLogger(string categoryName) => this.categoryName = categoryName;
public bool IsEnabled(LogLevel logLevel) => true;
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
//ef core执行数据库查询时的categoryName为Microsoft.EntityFrameworkCore.Database.Command,日志级别为Information
if (categoryName != "Microsoft.EntityFrameworkCore.Database.Command" ||
logLevel != LogLevel.Information) return;
var logContent = formatter(state, exception);
Console.WriteLine("<------------------ sql start ------------------>");
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("sql: ");
Console.ResetColor();
Console.Write(logContent);
Console.ResetColor();
Console.WriteLine();
Console.WriteLine("<------------------ sql end ------------------>");
}
public IDisposable BeginScope<TState>(TState state) => null;
}
}

View File

@ -0,0 +1,18 @@
using Microsoft.EntityFrameworkCore;
namespace DG.EntityFramework
{
/// <summary>
///
/// </summary>
/// <typeparam name="TDbContext"></typeparam>
public interface IDbContextProvider<out TDbContext>
where TDbContext : DbContext
{
/// <summary>
///
/// </summary>
/// <returns></returns>
TDbContext GetDbContext();
}
}

View File

@ -0,0 +1,394 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;
using System.Data;
using System.Data.Common;
using System.Diagnostics.CodeAnalysis;
namespace DG.EntityFramework
{
public class BaseRepository<TDbContext> : IBaseRepository<TDbContext>
where TDbContext : DbContext
{
private readonly IServiceProvider _serviceProvider;
private readonly TDbContext _context;
public BaseRepository(
IServiceProvider serviceProvider,
TDbContext dbContext
)
{
_serviceProvider = serviceProvider;
_context = dbContext;
}
public IRepositoryBase<TDbContext, TEntity> GetRepository<TEntity>()
where TEntity : class
=> _serviceProvider.GetRequiredService<IRepositoryBase<TDbContext, TEntity>>();
public async Task<IDbContextTransaction> BeginTransactionAsync()
=> await _context.Database.BeginTransactionAsync();
/// <summary>
/// 创建SqlCommand
/// </summary>
/// <param name="sql"></param>
/// <param name="transaction"></param>
/// <param name="parameters"></param>
/// <returns></returns>
private async Task<DbCommand> CreateCommand(string sql, params object[] parameters)
{
var conn = _context.Database.GetDbConnection();
if (conn.State != ConnectionState.Open)
{
await conn.OpenAsync();
}
var cmd = conn.CreateCommand();
cmd.CommandText = sql;
cmd.Parameters.AddRange(parameters);
return cmd;
}
/// <summary>
/// 执行存储过程的扩展方法ExecuteSqlCommand
/// </summary>
/// <param name="commandType"></param>
/// <param name="sql"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public async Task<int> ExecuteSqlCommandNonQueryAsync(CommandType commandType, string sql, [NotNull] params object[] parameters)
{
//创建SqlCommand
var command = await CreateCommand(sql, parameters);
var conn = _context.Database.GetDbConnection();
var transaction = _context.Database.CurrentTransaction?.GetDbTransaction();
if (conn.State != ConnectionState.Open)
{
await conn.OpenAsync();
}
_context.Database.UseTransaction(transaction);
command.CommandType = commandType;
if (transaction != null)
{
command.Transaction = transaction;
}
return await command.ExecuteNonQueryAsync();
}
public async Task<List<T>> ExecuteSqlCommandAsync<T>(CommandType commandType, string sql, [NotNull] params object[] parameters)
where T : class, new()
{
//创建SqlCommand
var command = await CreateCommand(sql, parameters);
var conn = _context.Database.GetDbConnection();
var transaction = _context.Database.CurrentTransaction?.GetDbTransaction();
if (conn.State != ConnectionState.Open)
{
await conn.OpenAsync();
}
_context.Database.UseTransaction(transaction);
command.CommandType = commandType;
if (transaction != null)
{
command.Transaction = transaction;
}
var reader = await command.ExecuteReaderAsync();
List<T> list = new();
Type type = typeof(T);
if (reader.HasRows)
{
while (reader.Read())
{
var note = Activator.CreateInstance(type);
var columns = reader.GetColumnSchema();
foreach (var item in type.GetProperties())
{
if (!columns.Any(x => x.ColumnName.ToLower() == item.Name.ToLower())) continue;
var value = reader[item.Name];
if (!item.CanWrite || value is DBNull || value == DBNull.Value) continue;
try
{
#region SetValue
switch (item.PropertyType.ToString())
{
case "System.String":
item.SetValue(note, Convert.ToString(value), null);
break;
case "System.Int32":
item.SetValue(note, Convert.ToInt32(value), null);
break;
case "System.Int64":
item.SetValue(note, Convert.ToInt64(value), null);
break;
case "System.DateTime":
item.SetValue(note, Convert.ToDateTime(value), null);
break;
case "System.Boolean":
item.SetValue(note, Convert.ToBoolean(value), null);
break;
case "System.Double":
item.SetValue(note, Convert.ToDouble(value), null);
break;
case "System.Decimal":
item.SetValue(note, Convert.ToDecimal(value), null);
break;
default:
item.SetValue(note, value, null);
break;
}
#endregion
}
catch
{
//throw (new Exception(ex.Message));
}
}
list.Add(note as T);
}
await reader.CloseAsync();
await conn.CloseAsync();
return list;
}
return list;
}
public async Task<List<T>> ExecuteSqlToListAsync<T>(string sql, [MaybeNull] params object[] parameters)
where T : class, new()
{
//创建SqlCommand
var command = await CreateCommand(sql, parameters);
var conn = _context.Database.GetDbConnection();
if (conn.State != ConnectionState.Open)
{
await conn.OpenAsync();
}
if (conn.State == ConnectionState.Open)
{
var reader = await command.ExecuteReaderAsync();
List<T> list = new();
Type type = typeof(T);
if (reader.HasRows)
{
while (reader.Read())
{
var note = Activator.CreateInstance(type);
var columns = reader.GetColumnSchema();
foreach (var item in type.GetProperties())
{
if (!columns.Any(x => x.ColumnName.ToLower() == item.Name.ToLower())) continue;
var value = reader[item.Name];
if (!item.CanWrite || value is DBNull || value == DBNull.Value) continue;
try
{
#region SetValue
switch (item.PropertyType.ToString())
{
case "System.String":
item.SetValue(note, Convert.ToString(value), null);
break;
case "System.Int32":
case "System.Nullable`1[System.Int32]":
item.SetValue(note, Convert.ToInt32(value), null);
break;
case "System.Int64":
case "System.Nullable`1[System.Int64]":
item.SetValue(note, Convert.ToInt64(value), null);
break;
case "System.DateTime":
case "System.Nullable`1[System.DateTime]":
item.SetValue(note, Convert.ToDateTime(value), null);
break;
case "System.Boolean":
case "System.Nullable`1[System.Boolean]":
item.SetValue(note, Convert.ToBoolean(value), null);
break;
case "System.Double":
case "System.Nullable`1[System.Double]":
item.SetValue(note, Convert.ToDouble(value), null);
break;
case "System.Decimal":
case "System.Nullable`1[System.Decimal]":
item.SetValue(note, Convert.ToDecimal(value), null);
break;
default:
item.SetValue(note, value, null);
break;
}
#endregion
}
catch
{
//throw (new Exception(ex.Message));
}
}
list.Add(note as T);
}
await reader.CloseAsync();
await conn.CloseAsync();
return list;
}
return list;
}
return new List<T>();
}
public async Task<T> ExecuteSqlToEntityAsync<T>(string sql, [MaybeNull] params object[] parameters)
where T : class, new()
{
//创建SqlCommand
var command = await CreateCommand(sql, parameters);
var conn = _context.Database.GetDbConnection();
if (conn.State != ConnectionState.Open)
{
await conn.OpenAsync();
}
if (conn.State == ConnectionState.Open)
{
var reader = await command.ExecuteReaderAsync();
T entity = new();
Type type = typeof(T);
if (reader.HasRows)
{
while (reader.Read())
{
var note = Activator.CreateInstance(type);
var columns = reader.GetColumnSchema();
foreach (var item in type.GetProperties())
{
if (!columns.Any(x => x.ColumnName.ToLower() == item.Name.ToLower())) continue;
var value = reader[item.Name];
if (!item.CanWrite || value is DBNull || value == DBNull.Value) continue;
try
{
#region SetValue
switch (item.PropertyType.ToString())
{
case "System.String":
item.SetValue(note, Convert.ToString(value), null);
break;
case "System.Int32":
case "System.Nullable`1[System.Int32]":
item.SetValue(note, Convert.ToInt32(value), null);
break;
case "System.Int64":
case "System.Nullable`1[System.Int64]":
item.SetValue(note, Convert.ToInt64(value), null);
break;
case "System.DateTime":
case "System.Nullable`1[System.DateTime]":
item.SetValue(note, Convert.ToDateTime(value), null);
break;
case "System.Boolean":
case "System.Nullable`1[System.Boolean]":
item.SetValue(note, Convert.ToBoolean(value), null);
break;
case "System.Double":
case "System.Nullable`1[System.Double]":
item.SetValue(note, Convert.ToDouble(value), null);
break;
case "System.Decimal":
case "System.Nullable`1[System.Decimal]":
item.SetValue(note, Convert.ToDecimal(value), null);
break;
default:
item.SetValue(note, value, null);
break;
}
#endregion
}
catch
{
//throw (new Exception(ex.Message));
}
}
entity = note as T;
}
await reader.CloseAsync();
await conn.CloseAsync();
return entity;
}
return entity;
}
return new T();
}
public async Task<int> ExecuteSqlToCountAsync(string sql, [MaybeNull] params object[] parameters)
{
//创建SqlCommand
var command = await CreateCommand(sql, parameters);
var conn = _context.Database.GetDbConnection();
if (conn.State != ConnectionState.Open)
{
await conn.OpenAsync();
}
if (conn.State == ConnectionState.Open)
{
var reader = await command.ExecuteReaderAsync();
if (reader.HasRows)
{
while (reader.Read())
{
var columns = reader.GetColumnSchema();
var value = reader[0];
if (value is int)
{
return (int)value;
}
}
await reader.CloseAsync();
await conn.CloseAsync();
return 0;
}
return 0;
}
return 0;
}
public async Task<long> ExecuteSqlToCountLongAsync(string sql, [MaybeNull] params object[] parameters)
{
//创建SqlCommand
var command = await CreateCommand(sql, parameters);
var conn = _context.Database.GetDbConnection();
var result = 0L;
if (conn.State != ConnectionState.Open)
{
await conn.OpenAsync();
}
if (conn.State == ConnectionState.Open)
{
var reader = await command.ExecuteReaderAsync();
if (reader.HasRows)
{
while (reader.Read())
{
var value = reader[0];
if (value is long)
{
result = (long)value;
}
}
}
await reader.CloseAsync();
await conn.CloseAsync();
}
return result;
}
public async Task<IDbContextTransaction> BeginTransactionAsync(IsolationLevel isolationLevel)
=> await _context.Database.BeginTransactionAsync(isolationLevel);
}
}

View File

@ -0,0 +1,64 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.EntityFramework
{
public interface IBaseRepository<TDbContext>
where TDbContext : DbContext
{
IRepositoryBase<TDbContext, TEntity> GetRepository<TEntity>()
where TEntity : class;
/// <summary>
/// 执行存储过程的扩展方法ExecuteSqlCommand
/// </summary>
/// <param name="commandType"></param>
/// <param name="sql"></param>
/// <param name="parameters"></param>
/// <returns></returns>
Task<int> ExecuteSqlCommandNonQueryAsync(CommandType commandType, string sql, [NotNull] params object[] parameters);
/// <summary>
/// 执行存储过程的扩展方法ExecuteSqlCommand
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="commandType"></param>
/// <param name="sql"></param>
/// <param name="parameters"></param>
/// <returns></returns>
Task<List<T>> ExecuteSqlCommandAsync<T>(CommandType commandType, string sql, [NotNull] params object[] parameters)
where T : class, new();
/// <summary>
/// 开启事务
/// </summary>
/// <returns></returns>
Task<IDbContextTransaction> BeginTransactionAsync();
/// <summary>
///
/// </summary>
/// <param name="isolationLevel"></param>
/// <returns></returns>
Task<IDbContextTransaction> BeginTransactionAsync(IsolationLevel isolationLevel);
Task<List<T>> ExecuteSqlToListAsync<T>(string sql, [MaybeNull] params object[] parameters)
where T : class, new();
Task<T> ExecuteSqlToEntityAsync<T>(string sql, [MaybeNull] params object[] parameters)
where T : class, new();
Task<int> ExecuteSqlToCountAsync(string sql, [MaybeNull] params object[] parameters);
Task<long> ExecuteSqlToCountLongAsync(string sql, [MaybeNull] params object[] parameters);
}
}

View File

@ -0,0 +1,127 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace DG.EntityFramework
{
public interface IRepositoryBase<TDbContext, TEntity>
where TDbContext : DbContext
where TEntity : class
{
#region Qurey
/// <summary>
/// Used to get a IQueryable that is used to retrieve entities from entire table.
/// </summary>
/// <returns>IQueryable to be used to select entities from database</returns>
IQueryable<TEntity> Query();
/// <summary>
/// Used to get a IQueryable that is used to retrieve entities from entire table.
/// </summary>
/// <param name="propertySelectors"></param>
/// <returns>IQueryable to be used to select entities from database</returns>
IQueryable<TEntity> QueryIncluding(params Expression<Func<TEntity, object>>[] propertySelectors);
/// <summary>
/// Used to query a array of entities from datatable
/// </summary>
/// <returns>Array of entities</returns>
Task<TEntity[]> QueryArrayAsync();
/// <summary>
/// Used to query a array of entities from datatable by predicate
/// </summary>
/// <param name="predicate"></param>
/// <returns>Array of entities</returns>
//Task<TEntity[]> QueryArrayAsync(Expression<Func<TEntity, bool>> predicate);
/// <summary>
/// Used to query a list of entities from datatable
/// </summary>
/// <returns>List of entities</returns>
Task<List<TEntity>> QueryListAsync();
/// <summary>
/// Used to query a list of entities from datatable by predicate
/// </summary>
/// <param name="predicate"></param>
/// <returns>List of entities</returns>
//Task<List<TEntity>> QueryListAsync(Expression<Func<TEntity, bool>> predicate);
/// <summary>
/// Used to query a single entity from datatable by predicate
/// </summary>
/// <param name="predicate"></param>
/// <returns>Entity</returns>
Task<TEntity> SingleAsync(Expression<Func<TEntity, bool>> predicate = null);
/// <summary>
/// Gets an entity with given given predicate or null if not found.
/// </summary>
/// <param name="predicate">Predicate to filter entities</param>
Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate = null);
#endregion Qurey
#region Insert
/// <summary>
/// Insert a new entity
/// </summary>
/// <param name="entity"></param>
/// <param name="submit"></param>
/// <returns>Inserted entity</returns>
Task<TEntity> InsertAsync(TEntity entity, bool submit = true);
Task<List<TEntity>> BatchInsertAsync(List<TEntity> entities, bool submit = true);
#endregion Insert
#region Update
/// <summary>
/// Updates an existing entity
/// </summary>
/// <param name="entity"></param>
/// <param name="submit"></param>
/// <returns></returns>
Task<TEntity> UpdateAsync(TEntity entity, bool submit = true);
Task<TEntity> UpdateAsync(TEntity entity, Expression<Func<TEntity, object>> expression, bool submit = true);
Task BatchUpdateAsync(List<TEntity> entities, bool submit = true);
Task BatchUpdateAsync(List<TEntity> entities, Expression<Func<TEntity, object>> expression, bool submit = true);
#endregion Update
#region Delete
/// <summary>
/// Deletes an entity
/// </summary>
/// <param name="entity">Entity</param>
/// <param name="submit"></param>
/// <returns>Entity to be deleted</returns>
Task DeleteAsync(TEntity entity, bool submit = true);
Task BatchDeleteAsync(List<TEntity> entities, bool submit = true);
#endregion Delete
#region Expression
TDbContext Context { get; }
DbSet<TEntity> Table { get; }
void Attach(TEntity entity);
#endregion Expression
}
}

View File

@ -0,0 +1,298 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
using Microsoft.EntityFrameworkCore.Storage;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace DG.EntityFramework
{
public class RepositoryBase<TDbContext, TEntity> : IRepositoryBase<TDbContext, TEntity>
where TDbContext : DbContext
where TEntity : class
{
/// <summary>
///
/// </summary>
public TDbContext Context { get; }
/// <summary>
///
/// </summary>
public DbSet<TEntity> Table => Context.Set<TEntity>();
/// <summary>
///
/// </summary>
/// <param name="dbContextProvider"></param>
public RepositoryBase(TDbContext context)
{
Context = context;
}
#region Qurey
/// <summary>
/// Used to get a IQueryable that is used to retrieve entities from entire table.
/// </summary>
/// <returns>IQueryable to be used to select entities from database</returns>
public IQueryable<TEntity> Query()
{
if (!(Context.Set<TEntity>() is IQueryable<TEntity> query))
throw new Exception($"{typeof(TEntity)} TEntity cannot be empty");
return query;
}
/// <summary>
/// Used to get a IQueryable that is used to retrieve entities from entire table.
/// </summary>
/// <param name="propertySelectors"></param>
/// <returns>IQueryable to be used to select entities from database</returns>
public IQueryable<TEntity> QueryIncluding(params Expression<Func<TEntity, object>>[] propertySelectors)
{
if (propertySelectors == null || !propertySelectors.Any())
{
return Query();
}
var query = Query();
return propertySelectors.Aggregate(query, (current, propertySelector) => current.Include(propertySelector));
}
/// <summary>
/// Used to query a array of entities from data table
/// </summary>
/// <returns>Array of entities</returns>
public async Task<TEntity[]> QueryArrayAsync()
{
return await Query().ToArrayAsync();
}
/// <summary>
/// Used to query a array of entities from data table by predicate
/// </summary>
/// <param name="predicate"></param>
/// <returns>Array of entities</returns>
public async Task<TEntity[]> QueryArrayAsync(Expression<Func<TEntity, bool>> predicate)
{
return await Query().Where(predicate).ToArrayAsync();
}
/// <summary>
/// Used to query a list of entities from data table
/// </summary>
/// <returns>List of entities</returns>
public async Task<List<TEntity>> QueryListAsync()
{
return await Query().ToListAsync();
}
/// <summary>
/// Used to query a list of entities from data table by predicate
/// </summary>
/// <param name="predicate"></param>
/// <returns>List of entities</returns>
public async Task<List<TEntity>> QueryListAsync(Expression<Func<TEntity, bool>> predicate = null)
{
return await Query().Where(predicate).ToListAsync();
}
/// <summary>
/// Used to query a single entity from datatable by predicate
/// </summary>
/// <param name="predicate"></param>
/// <returns>Entity</returns>
public async Task<TEntity> SingleAsync(Expression<Func<TEntity, bool>> predicate = null)
{
if (predicate == null)
{
return await Query().SingleAsync();
}
return await Query().SingleAsync(predicate);
}
/// <summary>
/// Gets an entity with given given predicate or null if not found.
/// </summary>
/// <param name="predicate">Predicate to filter entities</param>
public async Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate = null)
{
if (predicate == null)
{
return await Query().FirstOrDefaultAsync();
}
return await Query().FirstOrDefaultAsync(predicate);
}
#endregion Qurey
#region Insert
/// <summary>
/// Insert a new entity
/// </summary>
/// <param name="entity"></param>
/// <param name="submit"></param>
/// <returns>Inserted entity</returns>
public virtual async Task<TEntity> InsertAsync(TEntity entity, bool submit = true)
{
AttachIfNot(entity);
Context.Entry(entity).State = EntityState.Added;
if (submit)
{
await Context.SaveChangesAsync();
}
return entity;
}
public virtual async Task<List<TEntity>> BatchInsertAsync(List<TEntity> entities, bool submit = true)
{
foreach (var entity in entities)
{
AttachIfNot(entity);
Context.Entry(entity).State = EntityState.Added;
}
if (submit)
{
await Context.SaveChangesAsync();
}
return entities;
}
#endregion Insert
#region Update
/// <summary>
/// Updates an existing entity
/// </summary>
/// <param name="entity"></param>
/// <param name="submit"></param>
/// <returns></returns>
public virtual async Task<TEntity> UpdateAsync(TEntity entity, bool submit = true)
{
Attach(entity);
Context.Entry(entity).State = EntityState.Modified;
if (submit)
{
await Context.SaveChangesAsync();
}
return await Task.FromResult(entity);
}
public virtual async Task<TEntity> UpdateAsync(TEntity entity, Expression<Func<TEntity, object>> expression, bool submit = true)
{
Attach(entity);
var entry = Context.Entry(entity);
//entry.State = EntityState.Unchanged;
foreach (var proInfo in expression.GetPropertyAccessList())
{
if (!string.IsNullOrEmpty(proInfo.Name))
entry.Property(proInfo.Name).IsModified = true;
}
if (submit)
{
await Context.SaveChangesAsync();
}
return await Task.FromResult(entity);
}
public virtual async Task BatchUpdateAsync(List<TEntity> entities, bool submit = true)
{
foreach(var entity in entities)
{
Attach(entity);
Context.Entry(entity).State = EntityState.Modified;
}
if (submit)
{
await Context.SaveChangesAsync();
}
}
public virtual async Task BatchUpdateAsync(List<TEntity> entities, Expression<Func<TEntity, object>> expression, bool submit = true)
{
foreach (var entity in entities)
{
Attach(entity);
var entry = Context.Entry(entity);
//entry.State = EntityState.Unchanged;
foreach (var proInfo in expression.GetPropertyAccessList())
{
if (!string.IsNullOrEmpty(proInfo.Name))
//4.4将每个 被修改的属性的状态 设置为已修改状态;后面生成update语句时就只为已修改的属性 更新
entry.Property(proInfo.Name).IsModified = true;
}
}
if (submit)
{
await Context.SaveChangesAsync();
}
}
#endregion Update
#region Delete
/// <summary>
/// Deletes an entity
/// </summary>
/// <param name="entity">Entity</param>
/// <param name="submit"></param>
/// <returns>Entity to be deleted</returns>
public virtual async Task DeleteAsync(TEntity entity, bool submit = true)
{
AttachIfNot(entity);
await Task.FromResult(Table.Remove(entity));
if (submit)
{
await Context.SaveChangesAsync();
}
}
public virtual async Task BatchDeleteAsync(List<TEntity> entities, bool submit = true)
{
foreach (var entity in entities)
{
AttachIfNot(entity);
Context.Entry(entity).State = EntityState.Deleted;
}
Table.RemoveRange(entities);
if (submit)
{
await Context.SaveChangesAsync();
}
}
#endregion Delete
#region Expression
/// <summary>
///
/// </summary>
/// <param name="entity"></param>
public void AttachIfNot(TEntity entity)
{
if (!Table.Local.Contains(entity))
{
Table.Attach(entity);
}
}
public void Attach(TEntity entity)
{
Table.Attach(entity);
}
#endregion Expression
}
}

View File

@ -0,0 +1,39 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
namespace DG.EntityFramework
{
/// <summary>
/// Extensions method
/// </summary>
public static class ServiceCollectionExtensions
{
/// <summary>
/// Add EntityFramework
/// </summary>
/// <typeparam name="TDbContext"></typeparam>
/// <param name="services"></param>
/// <param name="options"></param>
/// <param name="isUseLogger"></param>
/// <returns></returns>
public static IServiceCollection AddDGEntityFramework<TDbContext>(this IServiceCollection services,
Action<DbContextOptionsBuilder> options)
where TDbContext : DbContext
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
services.AddDbContext<TDbContext>(options, ServiceLifetime.Scoped, ServiceLifetime.Scoped);
services.AddScoped<IUnitOfWorkManager, UnitOfWorkManager<TDbContext>>();
services.AddScoped<IDbContextProvider<TDbContext>, DbContextProvider<TDbContext>>();
services.AddScoped(typeof(IRepositoryBase<,>), typeof(RepositoryBase<,>));
services.AddScoped(typeof(IBaseRepository<>), typeof(BaseRepository<>));
return services;
}
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.EntityFramework
{
/// <summary>
/// Used to complete a unit of work. This interface can not be injected or directly used.
/// </summary>
public interface IUnitOfWorkCompleteHandle : IDisposable
{
/// <summary>
/// Completes this unit of work. It saves all changes and commit transaction if exists.
/// </summary>
void Complete();
/// <summary>
/// Completes this unit of work. It saves all changes and commit transaction if exists.
/// </summary>
/// <returns></returns>
Task CompleteAsync();
/// <summary>
///
/// </summary>
void Rollback();
/// <summary>
///
/// </summary>
/// <returns></returns>
Task RollbackAsync();
}
}

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
namespace DG.EntityFramework
{
/// <summary>
/// Unit of work manager. Used to begin and control a unit of work.
/// </summary>
public interface IUnitOfWorkManager
{
/// <summary>
/// Begins a new unit of work.
/// </summary>
/// <returns>A handle to be able to complete the unit of work</returns>
IUnitOfWorkCompleteHandle Begin();
/// <summary>
/// Begins a new unit of work.
/// </summary>
/// <returns>A handle to be able to complete the unit of work</returns>
IUnitOfWorkCompleteHandle Begin(TransactionScopeOption scope);
/// <summary>
/// Begins a new unit of work.
/// </summary>
/// <returns>A handle to be able to complete the unit of work</returns>
IUnitOfWorkCompleteHandle Begin(UnitOfWorkOptions options);
}
}

View File

@ -0,0 +1,45 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace DG.EntityFramework
{
public class UnitOfWorkCompleteHandle<TDbContext> : IUnitOfWorkCompleteHandle
where TDbContext : DbContext
{
private readonly IDbContextTransaction _dbContextTransaction;
public UnitOfWorkCompleteHandle(IDbContextTransaction dbContextTransaction)
{
_dbContextTransaction = dbContextTransaction ?? throw new ArgumentNullException(nameof(dbContextTransaction));
}
public void Complete()
{
_dbContextTransaction.Commit();
}
public async Task CompleteAsync()
{
await _dbContextTransaction.CommitAsync();
}
public void Rollback()
{
_dbContextTransaction.Rollback();
}
public async Task RollbackAsync()
{
await _dbContextTransaction.RollbackAsync();
}
public void Dispose()
{
_dbContextTransaction.Dispose();
}
}
}

View File

@ -0,0 +1,45 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
namespace DG.EntityFramework
{
public class UnitOfWorkCompleteScopeHandle<TDbContext> : IUnitOfWorkCompleteHandle
where TDbContext : DbContext
{
private readonly TransactionScope _transactionScope;
public UnitOfWorkCompleteScopeHandle(TransactionScope transactionScope)
{
_transactionScope = transactionScope ?? throw new ArgumentNullException(nameof(transactionScope));
}
public void Complete()
{
_transactionScope.Complete();
}
public async Task CompleteAsync()
{
await Task.Run(() => _transactionScope.Complete());
}
public void Rollback()
{
_transactionScope.Dispose();
}
public async Task RollbackAsync()
{
await Task.Run(() => _transactionScope.Dispose());
}
public void Dispose()
{
_transactionScope.Dispose();
}
}
}

View File

@ -0,0 +1,42 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Threading.Tasks;
using System.Transactions;
namespace DG.EntityFramework
{
public class UnitOfWorkManager<TDbContext> : IUnitOfWorkManager
where TDbContext : DbContext
{
private readonly TDbContext _dbContext;
public UnitOfWorkManager(TDbContext dbContext)
{
_dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
}
public IUnitOfWorkCompleteHandle Begin()
{
var tran = _dbContext.Database.BeginTransaction();
var handle = new UnitOfWorkCompleteHandle<TDbContext>(tran);
return handle;
}
public IUnitOfWorkCompleteHandle Begin(TransactionScopeOption scope)
{
return Begin(new UnitOfWorkOptions { Scope = scope });
}
public IUnitOfWorkCompleteHandle Begin(UnitOfWorkOptions options)
{
var scope = new TransactionScope(
options.Scope.GetValueOrDefault(),
new TransactionOptions {
Timeout = options.Timeout.GetValueOrDefault(),
IsolationLevel = options.IsolationLevel.GetValueOrDefault()
});
var handle = new UnitOfWorkCompleteScopeHandle<TDbContext>(scope);
return handle;
}
}
}

View File

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Transactions;
namespace DG.EntityFramework
{
/// <summary>
/// Unit of work options.
/// </summary>
public class UnitOfWorkOptions
{
/// <summary>
/// Creates a new UnitOfWorkOptions object.
/// </summary>
public UnitOfWorkOptions()
{
IsTransactional = true;
Scope = TransactionScopeOption.Required;
Timeout = TimeSpan.FromMinutes(2);
IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
}
/// <summary>
/// Scope option.
/// </summary>
public TransactionScopeOption? Scope { get; set; }
/// <summary>
/// Is this Unit of work transactional? Uses default value if not supplied.
/// </summary>
public bool? IsTransactional { get; set; }
/// <summary>
/// Timeout of Unit of work As milliseconds. Uses default value if not supplied.
/// </summary>
public TimeSpan? Timeout { get; set; }
/// <summary>
/// If this Unit of work is transactional, this option indicated the isolation level of the transaction. Uses default value if not supplied.
/// </summary>
public IsolationLevel? IsolationLevel { get; set; }
/// <summary>
/// This option should be set to System.Transactions.TransactionScopeAsyncFlowOption.Enabled if unit of work is used in an async scope.
/// </summary>
public TransactionScopeAsyncFlowOption? AsyncFlowOption { get; set; }
}
}

View File

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Version>1.0.17</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
<PackageReference Include="StackExchange.Redis" Version="2.6.48" />
</ItemGroup>
<ItemGroup>
<Using Include="StackExchange.Redis" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,298 @@
namespace DG.Redis
{
/// <summary>
/// Redis manage interface
/// </summary>
public interface IRedisManager
{
/// <summary>
/// Redis connection
/// </summary>
/// <returns></returns>
void RedisConnection(string name, string connStr, int DefaultDatabase);
/// <summary>
/// Get database
/// </summary>
/// <returns></returns>
IDatabase GetDatabase(string name = "");
/// <summary>
/// Add a new entity
/// </summary>
/// <typeparam name="TEntity">Entity</typeparam>
/// <param name="key">Key</param>
/// <param name="entity">Entity</param>
/// <param name="cacheTime">Cache time</param>
/// <returns></returns>
bool Set<TEntity>(string key, TEntity entity, TimeSpan? cacheTime = null, string name = "");
/// <summary>
/// Add a new array
/// </summary>
/// <typeparam name="TEntity">Entity</typeparam>
/// <param name="key">Key</param>
/// <param name="entities">An array</param>
/// <param name="cacheTime">Cache time</param>
/// <returns></returns>
bool Set<TEntity>(string key, TEntity[] entities, TimeSpan? cacheTime = null, string name = "");
/// <summary>
/// Add a new list
/// </summary>
/// <typeparam name="TEntity">Entity</typeparam>
/// <param name="key">Key</param>
/// <param name="entities">An list</param>
/// <param name="cacheTime">Cache time</param>
/// <returns></returns>
bool Set<TEntity>(string key, List<TEntity> entities, TimeSpan? cacheTime = null, string name = "");
/// <summary>
/// Add a new entity
/// </summary>
/// <typeparam name="TEntity">Entity</typeparam>
/// <param name="key">Key</param>
/// <param name="entity">Entity</param>
/// <param name="cacheTime">Cache time</param>
/// <returns></returns>
Task<bool> SetAsync<TEntity>(string key, TEntity entity, TimeSpan? cacheTime = null, string name = "");
/// <summary>
/// Add a new array
/// </summary>
/// <typeparam name="TEntity">Entity</typeparam>
/// <param name="key">Key</param>
/// <param name="entities">An array</param>
/// <param name="cacheTime">Cache time</param>
/// <returns></returns>
Task<bool> SetAsync<TEntity>(string key, TEntity[] entities, TimeSpan? cacheTime = null, string name = "");
/// <summary>
/// Add a new list
/// </summary>
/// <typeparam name="TEntity">entity</typeparam>
/// <param name="key">key</param>
/// <param name="entities">a list</param>
/// <param name="cacheTime">cache time</param>
/// <returns></returns>
Task<bool> SetAsync<TEntity>(string key, List<TEntity> entities, TimeSpan? cacheTime = null, string name = "");
/// <summary>
/// Get list tatal
/// </summary>
/// <param name="key">Key</param>
/// <returns></returns>
long Count(string key, string name = "");
/// <summary>
/// Get list tatal
/// </summary>
/// <param name="key">Key</param>
/// <returns></returns>
Task<long> CountAsync(string key, string name = "");
/// <summary>
/// 判断在缓存中是否存在该key的缓存数据
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
bool Exists(string key, string name = "");
/// <summary>
/// 判断是否存在
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
Task<bool> ExistsAsync(string key, string name = "");
/// <summary>
/// Set cache time
/// </summary>
/// <param name="key">Key</param>
/// <param name="cacheTime">Cache time</param>
/// <returns></returns>
bool Expire(string key, TimeSpan cacheTime, string name = "");
/// <summary>
/// Set cache time
/// </summary>
/// <param name="key">Key</param>
/// <param name="cacheTime">Cache time</param>
/// <returns></returns>
/// <returns></returns>
Task<bool> ExpireAsync(string key, TimeSpan cacheTime, string name = "");
/// <summary>
/// Remove by key
/// </summary>
/// <param name="key">Key</param>
/// <returns></returns>
bool Remove(string key, string name = "");
/// <summary>
/// Remove by key array
/// </summary>
/// <param name="keys">Key array</param>
/// <returns></returns>
bool Remove(string[] keys, string name = "");
/// <summary>
/// Remove by key list
/// </summary>
/// <param name="keys">Key list</param>
/// <returns></returns>
bool Remove(List<string> keys, string name = "");
/// <summary>
/// Remove by key
/// </summary>
/// <param name="key">Key</param>
/// <returns></returns>
Task<bool> RemoveAsync(string key, string name = "");
/// <summary>
/// Remove by key array
/// </summary>
/// <param name="keys">Key array</param>
/// <returns></returns>
Task<bool> RemoveAsync(string[] keys, string name = "");
/// <summary>
/// Remove by key list
/// </summary>
/// <param name="keys">Key list</param>
/// <returns></returns>
Task<bool> RemoveAsync(List<string> keys, string name = "");
/// <summary>
/// Blocking Dequeue
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
TEntity BlockingDequeue<TEntity>(string key, string name = "");
/// <summary>
/// Blocking Dequeue
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
Task<TEntity> BlockingDequeueAsync<TEntity>(string key, string name = "");
/// <summary>
/// Dequeue entity
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
TEntity Dequeue<TEntity>(string key, string name = "");
/// <summary>
/// Dequeue entity
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
Task<TEntity> DequeueAsync<TEntity>(string key, string name = "");
/// <summary>
/// Enqueue entity
/// </summary>
/// <param name="key"></param>
/// <param name="entity"></param>
void Enqueue<TEntity>(string key, TEntity entity, string name = "");
/// <summary>
/// Enqueue entity
/// </summary>
/// <param name="key"></param>
/// <param name="entity"></param>
Task EnqueueAsync<TEntity>(string key, TEntity entity, string name = "");
/// <summary>
/// Increment
/// </summary>
/// <param name="key"></param>
/// <remarks>
/// 三种命令模式
/// Sync,同步模式会直接阻塞调用者,但是显然不会阻塞其他线程。
/// Async,异步模式直接走的是Task模型。
/// Fire - and - Forget,就是发送命令,然后完全不关心最终什么时候完成命令操作。
/// 即发即弃:通过配置 CommandFlags 来实现即发即弃功能在该实例中该方法会立即返回如果是string则返回null 如果是int则返回0.这个操作将会继续在后台运行,一个典型的用法页面计数器的实现:
/// </remarks>
/// <returns></returns>
long Increment(string key, string name = "");
/// <summary>
/// Increment
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
Task<long> IncrementAsync(string key, string name = "");
/// <summary>
/// Decrement
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
long Decrement(string key, string value, string name = "");
/// <summary>
/// Decrement
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
Task<long> DecrementAsync(string key, string value, string name = "");
/// <summary>
/// Get an entity
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
TEntity Get<TEntity>(string key, string name = "");
/// <summary>
/// Get an list
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
List<TEntity> GetList<TEntity>(string key, string name = "");
/// <summary>
/// Get an array
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
TEntity[] GetArray<TEntity>(string key, string name = "");
/// <summary>
/// Get an entity
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
Task<TEntity> GetAsync<TEntity>(string key, string name = "");
Task<TEntity> GetHashAsync<TEntity>(string key, string name = "");
/// <summary>
/// Get an list
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
Task<List<TEntity>> GetListAsync<TEntity>(string key, string name = "");
/// <summary>
/// Get an array
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
Task<TEntity[]> GetArrayAsync<TEntity>(string key, string name = "");
}
}

View File

@ -0,0 +1,375 @@
using System.Text.Json;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Text.Encodings.Web;
using Microsoft.Extensions.Configuration;
using System.Xml.Linq;
using System.Reflection;
namespace DG.Redis
{
public class RedisManager : IRedisManager
{
private readonly ILogger<RedisManager> _logger;
private List<(string, string, int, ConnectionMultiplexer)> _connQueue = new();
public static JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions()
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
public RedisManager(
ILogger<RedisManager> logger)
{
_logger = logger;
var redisOptions = RedisClient.Default.ConfigurationManager.GetSection("Redis").Get<List<RedisOptions>>();
foreach (var option in redisOptions)
{
var connStr = string.Format("{0}:{1},allowAdmin=true,abortConnect=false,password={2},defaultdatabase={3}",
option.HostName,
option.Port,
option.Password,
option.DefaultDatabase
);
var options = ConfigurationOptions.Parse(connStr);
RedisConnection(option.Name, connStr, option.DefaultDatabase);
}
}
public void RedisConnection(string name, string connStr, int DefaultDatabase)
{
try
{
_logger.LogDebug($"Redis config: {connStr}");
_connQueue.Add((name, connStr, DefaultDatabase, ConnectionMultiplexer.Connect(connStr)));
_logger.LogInformation($"Redis name: [{name}] manager started!");
}
catch (Exception ex)
{
_logger.LogError($"Redis name: [{name}] connection error: {ex.Message}");
throw;
}
}
public IDatabase GetDatabase(string name = "")
{
try
{
var con = _connQueue.FirstOrDefault();
if (!string.IsNullOrEmpty(name))
{
con = _connQueue.FirstOrDefault(x => x.Item1 == name);
return con.Item4.GetDatabase(con.Item3);
}
return con.Item4.GetDatabase(con.Item3);
}
catch
{
var con = _connQueue.FirstOrDefault(x => x.Item1 == name);
var conn = ConnectionMultiplexer.Connect(con.Item2);
_logger.LogInformation("Redis manager reconnection!");
return conn.GetDatabase(con.Item3);
}
}
public bool Set<TEntity>(string key, TEntity entity, TimeSpan? cacheTime = null, string name = "")
{
if (Exists(key, name))
{
Remove(key, name);
}
var result = GetDatabase(name).StringSet(key, JsonSerializer.Serialize(entity, new JsonSerializerOptions
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
}));
if (cacheTime != null)
{
return result && Expire(key, cacheTime.Value, name);
}
return result;
}
public bool Set<TEntity>(string key, TEntity[] entities, TimeSpan? cacheTime = null, string name = "")
{
if (Exists(key, name))
{
Remove(key, name);
}
var redisValues = entities.Select(p => (RedisValue)(JsonSerializer.Serialize(p, new JsonSerializerOptions
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
}))).ToArray();
var result = GetDatabase(name).SetAdd(key, redisValues) == redisValues.Length;
if (cacheTime != null)
{
return result && Expire(key, cacheTime.Value, name);
}
return result;
}
public bool Set<TEntity>(string key, List<TEntity> entities, TimeSpan? cacheTime = null, string name = "")
{
if (Exists(key, name))
{
Remove(key, name);
}
return Set(key, entities.ToArray(), cacheTime, name);
}
public async Task<bool> SetAsync<TEntity>(string key, TEntity entity, TimeSpan? cacheTime = null, string name = "")
{
if (await ExistsAsync(key, name))
{
await RemoveAsync(key, name);
}
var result = await GetDatabase(name).StringSetAsync(key, JsonSerializer.Serialize(entity, new JsonSerializerOptions
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
}));
if (cacheTime != null)
{
return result && await ExpireAsync(key, cacheTime.Value, name);
}
return result;
}
public async Task<bool> SetAsync<TEntity>(string key, TEntity[] entities, TimeSpan? cacheTime = null, string name = "")
{
if (await ExistsAsync(key, name))
{
await RemoveAsync(key, name);
}
var redisValues = entities.Select(p => (RedisValue)(JsonSerializer.Serialize(p, new JsonSerializerOptions
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
}))).ToArray();
var result = await GetDatabase(name).SetAddAsync(key, redisValues) == redisValues.Length;
if (cacheTime != null)
{
return result && await ExpireAsync(key, cacheTime.Value, name);
}
return result;
}
public async Task<bool> SetAsync<TEntity>(string key, List<TEntity> entities, TimeSpan? cacheTime = null, string name = "")
{
if (await ExistsAsync(key, name))
{
await RemoveAsync(key, name);
}
return await SetAsync(key, entities.ToArray(), cacheTime, name);
}
public long Count(string key, string name = "")
{
return GetDatabase(name).ListLength(key);
}
public async Task<long> CountAsync(string key, string name = "")
{
return await GetDatabase(name).ListLengthAsync(key);
}
public bool Exists(string key, string name = "")
{
return GetDatabase(name).KeyExists(key);
}
public async Task<bool> ExistsAsync(string key, string name = "")
{
return await GetDatabase(name).KeyExistsAsync(key);
}
public bool Expire(string key, TimeSpan cacheTime, string name = "")
{
return GetDatabase(name).KeyExpire(key, DateTime.Now.AddSeconds(int.Parse(cacheTime.TotalSeconds.ToString())));
}
public async Task<bool> ExpireAsync(string key, TimeSpan cacheTime, string name = "")
{
return await GetDatabase(name).KeyExpireAsync(key, DateTime.Now.AddSeconds(int.Parse(cacheTime.TotalSeconds.ToString())));
}
public bool Remove(string key, string name = "")
{
return GetDatabase(name).KeyDelete(key);
}
public bool Remove(string[] keys, string name = "")
{
var redisKeys = keys.Select(p => (RedisKey)(JsonSerializer.Serialize(p, new JsonSerializerOptions
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
}))).ToArray();
return GetDatabase(name).KeyDelete(redisKeys) == redisKeys.Length;
}
public bool Remove(List<string> keys, string name = "")
{
return Remove(keys.ToArray(), name);
}
public async Task<bool> RemoveAsync(string key, string name = "")
{
return await GetDatabase(name).KeyDeleteAsync(key);
}
public async Task<bool> RemoveAsync(string[] keys, string name = "")
{
var redisKeys = keys.Select(p => (RedisKey)(JsonSerializer.Serialize(p, new JsonSerializerOptions
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
}))).ToArray();
return await GetDatabase(name).KeyDeleteAsync(redisKeys) == redisKeys.Length;
}
public async Task<bool> RemoveAsync(List<string> keys, string name = "")
{
return await RemoveAsync(keys.ToArray(), name);
}
public TEntity BlockingDequeue<TEntity>(string key, string name = "")
{
return JsonSerializer.Deserialize<TEntity>(GetDatabase(name).ListRightPop(key));
}
public async Task<TEntity> BlockingDequeueAsync<TEntity>(string key, string name = "")
{
return JsonSerializer.Deserialize<TEntity>(await GetDatabase(name).ListRightPopAsync(key));
}
public TEntity Dequeue<TEntity>(string key, string name = "")
{
return JsonSerializer.Deserialize<TEntity>(GetDatabase(name).ListLeftPop(key));
}
public async Task<TEntity> DequeueAsync<TEntity>(string key, string name = "")
{
return JsonSerializer.Deserialize<TEntity>(await GetDatabase(name).ListLeftPopAsync(key));
}
public void Enqueue<TEntity>(string key, TEntity entity, string name = "")
{
GetDatabase(name).ListLeftPush(key, JsonSerializer.Serialize(entity, new JsonSerializerOptions
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
}));
}
public async Task EnqueueAsync<TEntity>(string key, TEntity entity, string name = "")
{
await GetDatabase(name).ListLeftPushAsync(key, JsonSerializer.Serialize(entity, new JsonSerializerOptions
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
}));
}
public long Increment(string key, string name = "")
{
return GetDatabase(name).StringIncrement(key, flags: CommandFlags.FireAndForget);
}
public async Task<long> IncrementAsync(string key, string name = "")
{
return await GetDatabase(name).StringIncrementAsync(key, flags: CommandFlags.FireAndForget);
}
public long Decrement(string key, string value, string name = "")
{
return GetDatabase(name).HashDecrement(key, value, flags: CommandFlags.FireAndForget);
}
public async Task<long> DecrementAsync(string key, string value, string name = "")
{
return await GetDatabase(name).HashDecrementAsync(key, value, flags: CommandFlags.FireAndForget);
}
public TEntity Get<TEntity>(string key, string name = "")
{
if (!Exists(key, name))
{
return default;
}
var result = GetDatabase(name).StringGet(key);
return JsonSerializer.Deserialize<TEntity>(result);
}
public List<TEntity> GetList<TEntity>(string key, string name = "")
{
if (!Exists(key, name))
{
return null;
}
var result = GetDatabase(name).SetMembers(key);
return result.Select(p => JsonSerializer.Deserialize<TEntity>(p, jsonSerializerOptions)).ToList();
}
public TEntity[] GetArray<TEntity>(string key, string name = "")
{
if (!Exists(key, name))
{
return null;
}
var result = GetDatabase(name).SetMembers(key);
return result.Select(p => JsonSerializer.Deserialize<TEntity>(p, jsonSerializerOptions)).ToArray();
}
public async Task<TEntity> GetAsync<TEntity>(string key, string name = "")
{
if (!await ExistsAsync(key, name))
{
return default;
}
var result = await GetDatabase(name).StringGetAsync(key);
return JsonSerializer.Deserialize<TEntity>(result, jsonSerializerOptions);
}
public async Task<TEntity> GetHashAsync<TEntity>(string key, string name = "")
{
if (!await ExistsAsync(key, name))
{
return default;
}
var result = await GetDatabase(name).HashGetAllAsync(key);
var entity = ConvertFromRedis<TEntity>(result);
return entity;
}
private T ConvertFromRedis<T>(HashEntry[] hashEntries)
{
PropertyInfo[] properties = typeof(T).GetProperties();
var obj = Activator.CreateInstance(typeof(T));
foreach (var property in properties)
{
HashEntry entry = hashEntries.FirstOrDefault(g => g.Name.ToString().ToLower().Equals(property.Name.ToLower()));
if (entry.Equals(new HashEntry())) continue;
property.SetValue(obj, Convert.ChangeType(entry.Value.ToString(), property.PropertyType));
}
return (T)obj;
}
public async Task<List<TEntity>> GetListAsync<TEntity>(string key, string name = "")
{
if (!await ExistsAsync(key, name))
{
return null;
}
var result = await GetDatabase(name).SetMembersAsync(key);
return result.Select(p => JsonSerializer.Deserialize<TEntity>(p, jsonSerializerOptions)).ToList();
}
public async Task<TEntity[]> GetArrayAsync<TEntity>(string key, string name = "")
{
if (!await ExistsAsync(key, name))
{
return null;
}
var result = await GetDatabase(name).SetMembersAsync(key);
return result.Select(p => JsonSerializer.Deserialize<TEntity>(p, jsonSerializerOptions)).ToArray();
}
}
}

View File

@ -0,0 +1,26 @@
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Redis
{
public class RedisClient
{
public void ReadFromConfiguration(IConfiguration configuration)
{
ConfigurationManager = configuration;
}
public IConfiguration ConfigurationManager { get; private set; }
private static readonly Lazy<RedisClient> _defaultClient = new(() => new RedisClient());
public static RedisClient Default
{
get { return _defaultClient.Value; }
}
}
}

View File

@ -0,0 +1,30 @@
namespace DG.Redis
{
/// <summary>
/// Redis config Options
/// </summary>
public class RedisOptions
{
public string Name { get; set; }
/// <summary>
/// Host
/// </summary>
public string HostName { get; set; }
/// <summary>
/// Port
/// </summary>
public string Port { get; set; }
/// <summary>
/// Password
/// </summary>
public string Password { get; set; }
/// <summary>
/// Default Database
/// </summary>
public int DefaultDatabase { get; set; }
}
}

View File

@ -0,0 +1,31 @@
using DG.Redis;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.Extensions.DependencyInjection
{
/// <summary>
/// Extensions method
/// </summary>
public static class ServiceCollectionExtensions
{
/// <summary>
/// Redis service registered
/// </summary>
/// <param name="services"></param>
/// <param name="configuration"></param>
/// <returns></returns>
public static IServiceCollection AddRedis(this IServiceCollection services, IConfiguration configuration)
{
RedisClient.Default.ReadFromConfiguration(configuration);
services.AddSingleton<IRedisManager, RedisManager>();
return services;
}
}
}

79
code/DG.Tool/AesUtil.cs Normal file
View File

@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace DG.Tool
{
public class AesUtil
{
/// <summary>
/// AES加密算法
/// </summary>
/// <param name="input">明文字符串</param>
/// <returns>字符串</returns>
public static string EncryptByAES(string input, string key, string iv)
{
if (string.IsNullOrWhiteSpace(input))
{
return input;
}
using (RijndaelManaged rijndaelManaged = new RijndaelManaged())
{
rijndaelManaged.Mode = CipherMode.CBC;
rijndaelManaged.Padding = PaddingMode.PKCS7;
rijndaelManaged.FeedbackSize = 128;
rijndaelManaged.Key = Encoding.UTF8.GetBytes(key);
rijndaelManaged.IV = Encoding.UTF8.GetBytes(iv);
ICryptoTransform encryptor = rijndaelManaged.CreateEncryptor(rijndaelManaged.Key, rijndaelManaged.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(input);
}
byte[] bytes = msEncrypt.ToArray();
return Convert.ToBase64String(bytes);
}
}
}
}
/// <summary>
/// AES解密
/// </summary>
/// <param name="input">密文字节数组</param>
/// <returns>返回解密后的字符串</returns>
public static string DecryptByAES(string input, string key, string iv)
{
if (string.IsNullOrWhiteSpace(input))
{
return input;
}
var buffer = Convert.FromBase64String(input);
using (RijndaelManaged rijndaelManaged = new RijndaelManaged())
{
rijndaelManaged.Mode = CipherMode.CBC;
rijndaelManaged.Padding = PaddingMode.PKCS7;
rijndaelManaged.FeedbackSize = 128;
rijndaelManaged.Key = Encoding.UTF8.GetBytes(key);
rijndaelManaged.IV = Encoding.UTF8.GetBytes(iv);
ICryptoTransform decryptor = rijndaelManaged.CreateDecryptor(rijndaelManaged.Key, rijndaelManaged.IV);
using (MemoryStream msEncrypt = new MemoryStream(buffer))
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srEncrypt = new StreamReader(csEncrypt))
{
return srEncrypt.ReadToEnd();
}
}
}
}
}
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Tool.Attributes
{
/// <summary>
/// 导出列的别名
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class ExportColumnNameAttribute : Attribute
{
public string? Name { get; set; }
public ExportColumnNameAttribute(string? name)
{
Name = name;
}
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Tool
{
/// <summary>
/// 不需要导出的列
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class NotExportColumnAttribute : Attribute
{
}
}

21
code/DG.Tool/BlowFish.cs Normal file
View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Tool
{
public static class BlowFish
{
public static string BlowFishKey = "upchina6"; //Common.Utility.GetSettingByKey("BlowFishKey");
public static string BlowFishIV = "upchina1";// Common.Utility.GetSettingByKey("BlowFishIV");
public static string Encode(string authInfohqRights)
{
var iv = Encoding.UTF8.GetBytes(BlowFishIV);
var blowFish = new BlowfishSimple(BlowFishKey, iv);
return blowFish.Encrypt(authInfohqRights, iv);
}
}
}

View File

@ -0,0 +1,379 @@
/*
Copyright 2001-2007 Markus Hahn
All rights reserved. See documentation for license details.
*/
namespace DG.Tool
{
/// <summary>Blowfish CBC implementation.</summary>
/// <remarks>Use this class to encrypt or decrypt byte arrays or a single blocks
/// with Blowfish in CBC (Cipher Block Block Chaining) mode. This is the recommended
/// way to use Blowfish.NET, unless certain requirements (e.g. moving block without
/// decryption) exist.
/// </remarks>
public class BlowfishCBC : BlowfishECB
{
// we store the IV as two 32bit integers, to void packing and
// unpacking inbetween the handling of data chunks
uint ivHi;
uint ivLo;
/// <summary>The current initialization vector (IV), which measures one block.</summary>
public byte[] IV
{
set
{
SetIV(value, 0);
}
get
{
byte[] result = new byte[BLOCK_SIZE];
GetIV(result, 0);
return result;
}
}
/// <summary>Sets the initialization vector (IV) with an offset.</summary>
/// <param name="buf">The buffer containing the new IV material.</param>
/// <param name="ofs">Where the IV material starts.</param>
public void SetIV(byte[] buf, int ofs)
{
this.ivHi = (((uint)buf[ofs]) << 24) |
(((uint)buf[ofs + 1]) << 16) |
(((uint)buf[ofs + 2]) << 8) |
buf[ofs + 3];
this.ivLo = (((uint)buf[ofs + 4]) << 24) |
(((uint)buf[ofs + 5]) << 16) |
(((uint)buf[ofs + 6]) << 8) |
buf[ofs + 7];
}
/// <summary>Gets the current IV material (of the size of one block).</summary>
/// <param name="buf">The buffer to copy the IV to.</param>
/// <param name="ofs">Where to start copying.</param>
public void GetIV(byte[] buf, int ofs)
{
uint ivHi = this.ivHi;
uint ivLo = this.ivLo;
buf[ofs++] = (byte)(ivHi >> 24);
buf[ofs++] = (byte)(ivHi >> 16);
buf[ofs++] = (byte)(ivHi >> 8);
buf[ofs++] = (byte)ivHi;
buf[ofs++] = (byte)(ivLo >> 24);
buf[ofs++] = (byte)(ivLo >> 16);
buf[ofs++] = (byte)(ivLo >> 8);
buf[ofs] = (byte)ivLo;
}
/// <summary>Default constructor.</summary>
/// <remarks>The IV needs to be assigned after the instance has been created!</remarks>
/// <see cref="BlowfishNET.BlowfishECB.Initialize"/>
public BlowfishCBC(byte[] key, int ofs, int len) : base(key, ofs, len)
{
}
/// <summary>Zero key constructor.</summary>
/// <remarks>After construction you need to initialize the instance and then apply the IV.</remarks>
public BlowfishCBC() : base(null, 0, 0)
{
}
/// <see cref="BlowfishNET.BlowfishECB.Invalidate"/>
public new void Invalidate()
{
base.Invalidate();
this.ivHi = this.ivLo = 0;
}
/// <see cref="BlowfishNET.BlowfishECB.EncryptBlock"/>
public new void EncryptBlock(
uint hi,
uint lo,
out uint outHi,
out uint outLo)
{
byte[] block = this.block;
block[0] = (byte)(hi >> 24);
block[1] = (byte)(hi >> 16);
block[2] = (byte)(hi >> 8);
block[3] = (byte)hi;
block[4] = (byte)(lo >> 24);
block[5] = (byte)(lo >> 16);
block[6] = (byte)(lo >> 8);
block[7] = (byte)lo;
Encrypt(block, 0, block, 0, BLOCK_SIZE);
outHi = (((uint)block[0]) << 24) |
(((uint)block[1]) << 16) |
(((uint)block[2]) << 8) |
block[3];
outLo = (((uint)block[4]) << 24) |
(((uint)block[5]) << 16) |
(((uint)block[6]) << 8) |
block[7];
}
/// <see cref="BlowfishNET.BlowfishECB.DecryptBlock"/>
public new void DecryptBlock(
uint hi,
uint lo,
out uint outHi,
out uint outLo)
{
byte[] block = this.block;
block[0] = (byte)(hi >> 24);
block[1] = (byte)(hi >> 16);
block[2] = (byte)(hi >> 8);
block[3] = (byte)hi;
block[4] = (byte)(lo >> 24);
block[5] = (byte)(lo >> 16);
block[6] = (byte)(lo >> 8);
block[7] = (byte)lo;
Decrypt(block, 0, block, 0, BLOCK_SIZE);
outHi = (((uint)block[0]) << 24) |
(((uint)block[1]) << 16) |
(((uint)block[2]) << 8) |
block[3];
outLo = (((uint)block[4]) << 24) |
(((uint)block[5]) << 16) |
(((uint)block[6]) << 8) |
block[7];
}
/// <see cref="BlowfishNET.BlowfishECB.Encrypt"/>
public new int Encrypt(
byte[] dataIn,
int posIn,
byte[] dataOut,
int posOut,
int count)
{
int end;
uint[] sbox1 = this.sbox1;
uint[] sbox2 = this.sbox2;
uint[] sbox3 = this.sbox3;
uint[] sbox4 = this.sbox4;
uint[] pbox = this.pbox;
uint pbox00 = pbox[0];
uint pbox01 = pbox[1];
uint pbox02 = pbox[2];
uint pbox03 = pbox[3];
uint pbox04 = pbox[4];
uint pbox05 = pbox[5];
uint pbox06 = pbox[6];
uint pbox07 = pbox[7];
uint pbox08 = pbox[8];
uint pbox09 = pbox[9];
uint pbox10 = pbox[10];
uint pbox11 = pbox[11];
uint pbox12 = pbox[12];
uint pbox13 = pbox[13];
uint pbox14 = pbox[14];
uint pbox15 = pbox[15];
uint pbox16 = pbox[16];
uint pbox17 = pbox[17];
uint hi = this.ivHi;
uint lo = this.ivLo;
count &= ~(BLOCK_SIZE - 1);
end = posIn + count;
while (posIn < end)
{
hi ^= (((uint)dataIn[posIn]) << 24) |
(((uint)dataIn[posIn + 1]) << 16) |
(((uint)dataIn[posIn + 2]) << 8) |
dataIn[posIn + 3];
lo ^= (((uint)dataIn[posIn + 4]) << 24) |
(((uint)dataIn[posIn + 5]) << 16) |
(((uint)dataIn[posIn + 6]) << 8) |
dataIn[posIn + 7];
posIn += 8;
hi ^= pbox00;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox01;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox02;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox03;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox04;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox05;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox06;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox07;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox08;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox09;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox10;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox11;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox12;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox13;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox14;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox15;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox16;
uint swap = lo ^ pbox17;
lo = hi;
hi = swap;
dataOut[posOut] = (byte)(hi >> 24);
dataOut[posOut + 1] = (byte)(hi >> 16);
dataOut[posOut + 2] = (byte)(hi >> 8);
dataOut[posOut + 3] = (byte)hi;
dataOut[posOut + 4] = (byte)(lo >> 24);
dataOut[posOut + 5] = (byte)(lo >> 16);
dataOut[posOut + 6] = (byte)(lo >> 8);
dataOut[posOut + 7] = (byte)lo;
posOut += 8;
}
this.ivHi = hi;
this.ivLo = lo;
return count;
}
/// <see cref="BlowfishNET.BlowfishECB.Decrypt"/>
public new int Decrypt(
byte[] dataIn,
int posIn,
byte[] dataOut,
int posOut,
int count)
{
int end;
uint hi, lo, hiBak, loBak;
uint[] sbox1 = this.sbox1;
uint[] sbox2 = this.sbox2;
uint[] sbox3 = this.sbox3;
uint[] sbox4 = this.sbox4;
uint[] pbox = this.pbox;
uint pbox00 = pbox[0];
uint pbox01 = pbox[1];
uint pbox02 = pbox[2];
uint pbox03 = pbox[3];
uint pbox04 = pbox[4];
uint pbox05 = pbox[5];
uint pbox06 = pbox[6];
uint pbox07 = pbox[7];
uint pbox08 = pbox[8];
uint pbox09 = pbox[9];
uint pbox10 = pbox[10];
uint pbox11 = pbox[11];
uint pbox12 = pbox[12];
uint pbox13 = pbox[13];
uint pbox14 = pbox[14];
uint pbox15 = pbox[15];
uint pbox16 = pbox[16];
uint pbox17 = pbox[17];
uint ivHi = this.ivHi;
uint ivLo = this.ivLo;
count &= ~(BLOCK_SIZE - 1);
end = posIn + count;
while (posIn < end)
{
hi = hiBak = (((uint)dataIn[posIn]) << 24) |
(((uint)dataIn[posIn + 1]) << 16) |
(((uint)dataIn[posIn + 2]) << 8) |
dataIn[posIn + 3];
lo = loBak = (((uint)dataIn[posIn + 4]) << 24) |
(((uint)dataIn[posIn + 5]) << 16) |
(((uint)dataIn[posIn + 6]) << 8) |
dataIn[posIn + 7];
posIn += 8;
hi ^= pbox17;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox16;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox15;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox14;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox13;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox12;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox11;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox10;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox09;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox08;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox07;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox06;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox05;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox04;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox03;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox02;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox01;
lo ^= ivHi ^ pbox00;
hi ^= ivLo;
dataOut[posOut] = (byte)(lo >> 24);
dataOut[posOut + 1] = (byte)(lo >> 16);
dataOut[posOut + 2] = (byte)(lo >> 8);
dataOut[posOut + 3] = (byte)lo;
dataOut[posOut + 4] = (byte)(hi >> 24);
dataOut[posOut + 5] = (byte)(hi >> 16);
dataOut[posOut + 6] = (byte)(hi >> 8);
dataOut[posOut + 7] = (byte)hi;
ivHi = hiBak;
ivLo = loBak;
posOut += 8;
}
this.ivHi = ivHi;
this.ivLo = ivLo;
return count;
}
/// <see cref="BlowfishNET.BlowfishECB.Clone"/>
public new object Clone()
{
BlowfishCBC result;
result = new BlowfishCBC();
result.pbox = (uint[])this.pbox.Clone();
result.sbox1 = (uint[])this.sbox1.Clone();
result.sbox2 = (uint[])this.sbox2.Clone();
result.sbox3 = (uint[])this.sbox3.Clone();
result.sbox4 = (uint[])this.sbox4.Clone();
result.block = (byte[])this.block.Clone();
result.isWeakKey = this.isWeakKey;
result.ivHi = this.ivHi;
result.ivLo = this.ivLo;
return result;
}
}
}

View File

@ -0,0 +1,405 @@
/*
Copyright 2001-2007 Markus Hahn
All rights reserved. See documentation for license details.
*/
using System;
namespace DG.Tool
{
/// <summary>Blowfish CFB implementation.</summary>
/// <remarks>Use this class to encrypt or decrypt byte arrays in CFB (Cipher Feedback) mode.
/// Useful if you don't want to deal with padding of blocks (in comparsion to CBC), however
/// a safe initialization vector (IV) is still needed. Notice that the data does not have to
/// be block-aligned in comparsion to ECB and CBC, so byte-per-byte streaming is possible.
/// </remarks>
public class BlowfishCFB : BlowfishECB
{
byte[] iv = new byte[BLOCK_SIZE];
int ivBytesLeft = 0;
/// <summary>The current initialization vector (IV), which measures one block.</summary>
public byte[] IV
{
set
{
SetIV(value, 0);
}
get
{
byte[] result = new byte[BLOCK_SIZE];
GetIV(result, 0);
return result;
}
}
/// <summary>Sets the initialization vector (IV) with an offset.</summary>
/// <param name="buf">The buffer containing the new IV material.</param>
/// <param name="ofs">Where the IV material starts.</param>
public void SetIV(byte[] buf, int ofs)
{
Array.Copy(buf, ofs, this.iv, 0, this.iv.Length);
this.ivBytesLeft = 0;
}
/// <summary>Gets the current IV material (of the size of one block).</summary>
/// <param name="buf">The buffer to copy the IV to.</param>
/// <param name="ofs">Where to start copying.</param>
public void GetIV(byte[] buf, int ofs)
{
Array.Copy(this.iv, 0, buf, ofs, this.iv.Length);
}
/// <summary>Default constructor.</summary>
/// <remarks>The IV needs to be assigned after the instance has been created!</remarks>
/// <see cref="BlowfishNET.BlowfishECB.Initialize"/>
public BlowfishCFB(byte[] key, int ofs, int len) : base(key, ofs, len)
{
}
/// <summary>Zero key constructor.</summary>
/// <remarks>After construction you need to initialize the instance and then apply the IV.</remarks>
public BlowfishCFB() : base(null, 0, 0)
{
}
/// <see cref="BlowfishNET.BlowfishECB.Invalidate"/>
public new void Invalidate()
{
base.Invalidate();
Array.Clear(this.iv, 0, this.iv.Length);
}
/// <see cref="BlowfishNET.BlowfishECB.Encrypt"/>
public new int Encrypt(
byte[] dataIn,
int posIn,
byte[] dataOut,
int posOut,
int count)
{
int end = posIn + count;
byte[] iv = this.iv;
int ivBytesLeft = this.ivBytesLeft;
int ivPos = iv.Length - ivBytesLeft;
// consume what's left in the IV buffer, but make sure to keep the new
// ciphertext in a round-robin fashion (since it represents the new IV)
if (ivBytesLeft >= count)
{
// what we have is enough to deal with the request
for (; posIn < end; posIn++, posOut++, ivPos++)
{
iv[ivPos] = dataOut[posOut] = (byte)(dataIn[posIn] ^ iv[ivPos]);
}
this.ivBytesLeft = iv.Length - ivPos;
return count;
}
for (; ivPos < BLOCK_SIZE; posIn++, posOut++, ivPos++)
{
iv[ivPos] = dataOut[posOut] = (byte)(dataIn[posIn] ^ iv[ivPos]);
}
count -= ivBytesLeft;
uint[] sbox1 = this.sbox1;
uint[] sbox2 = this.sbox2;
uint[] sbox3 = this.sbox3;
uint[] sbox4 = this.sbox4;
uint[] pbox = this.pbox;
uint pbox00 = pbox[0];
uint pbox01 = pbox[1];
uint pbox02 = pbox[2];
uint pbox03 = pbox[3];
uint pbox04 = pbox[4];
uint pbox05 = pbox[5];
uint pbox06 = pbox[6];
uint pbox07 = pbox[7];
uint pbox08 = pbox[8];
uint pbox09 = pbox[9];
uint pbox10 = pbox[10];
uint pbox11 = pbox[11];
uint pbox12 = pbox[12];
uint pbox13 = pbox[13];
uint pbox14 = pbox[14];
uint pbox15 = pbox[15];
uint pbox16 = pbox[16];
uint pbox17 = pbox[17];
// now load the current IV into 32bit integers for speed
uint hi = (((uint)iv[0]) << 24) |
(((uint)iv[1]) << 16) |
(((uint)iv[2]) << 8) |
iv[3];
uint lo = (((uint)iv[4]) << 24) |
(((uint)iv[5]) << 16) |
(((uint)iv[6]) << 8) |
iv[7];
// we deal with the even part first
int rest = count % BLOCK_SIZE;
end -= rest;
for (; ; )
{
// need to create new IV material no matter what
hi ^= pbox00;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox01;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox02;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox03;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox04;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox05;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox06;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox07;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox08;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox09;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox10;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox11;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox12;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox13;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox14;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox15;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox16;
uint swap = lo ^ pbox17;
lo = hi;
hi = swap;
if (posIn >= end)
{
// exit right in the middle so we always have new IV material for the rest below
break;
}
hi ^= (((uint)dataIn[posIn]) << 24) |
(((uint)dataIn[posIn + 1]) << 16) |
(((uint)dataIn[posIn + 2]) << 8) |
dataIn[posIn + 3];
lo ^= (((uint)dataIn[posIn + 4]) << 24) |
(((uint)dataIn[posIn + 5]) << 16) |
(((uint)dataIn[posIn + 6]) << 8) |
dataIn[posIn + 7];
posIn += 8;
// now stream out the whole block
dataOut[posOut] = (byte)(hi >> 24);
dataOut[posOut + 1] = (byte)(hi >> 16);
dataOut[posOut + 2] = (byte)(hi >> 8);
dataOut[posOut + 3] = (byte)hi;
dataOut[posOut + 4] = (byte)(lo >> 24);
dataOut[posOut + 5] = (byte)(lo >> 16);
dataOut[posOut + 6] = (byte)(lo >> 8);
dataOut[posOut + 7] = (byte)lo;
posOut += 8;
}
// store back the new IV
iv[0] = (byte)(hi >> 24);
iv[1] = (byte)(hi >> 16);
iv[2] = (byte)(hi >> 8);
iv[3] = (byte)hi;
iv[4] = (byte)(lo >> 24);
iv[5] = (byte)(lo >> 16);
iv[6] = (byte)(lo >> 8);
iv[7] = (byte)lo;
// emit the rest
for (int i = 0; i < rest; i++)
{
iv[i] = dataOut[posOut + i] = (byte)(dataIn[posIn + i] ^ iv[i]);
}
this.ivBytesLeft = iv.Length - rest;
return count;
}
/// <see cref="BlowfishNET.BlowfishECB.Decrypt"/>
public new int Decrypt(
byte[] dataIn,
int posIn,
byte[] dataOut,
int posOut,
int count)
{
// same as above except that the ciphertext (input data) is what we keep...
int end = posIn + count;
byte[] iv = this.iv;
int ivBytesLeft = this.ivBytesLeft;
int ivPos = iv.Length - ivBytesLeft;
if (ivBytesLeft >= count)
{
for (; posIn < end; posIn++, posOut++, ivPos++)
{
int b = dataIn[posIn];
dataOut[posOut] = (byte)(b ^ iv[ivPos]);
dataIn[posIn] = (byte)b;
}
this.ivBytesLeft = iv.Length - ivPos;
return count;
}
for (; ivPos < BLOCK_SIZE; posIn++, posOut++, ivPos++)
{
iv[ivPos] = dataOut[posOut] = (byte)(dataIn[posIn] ^ iv[ivPos]);
}
count -= ivBytesLeft;
uint[] sbox1 = this.sbox1;
uint[] sbox2 = this.sbox2;
uint[] sbox3 = this.sbox3;
uint[] sbox4 = this.sbox4;
uint[] pbox = this.pbox;
uint pbox00 = pbox[0];
uint pbox01 = pbox[1];
uint pbox02 = pbox[2];
uint pbox03 = pbox[3];
uint pbox04 = pbox[4];
uint pbox05 = pbox[5];
uint pbox06 = pbox[6];
uint pbox07 = pbox[7];
uint pbox08 = pbox[8];
uint pbox09 = pbox[9];
uint pbox10 = pbox[10];
uint pbox11 = pbox[11];
uint pbox12 = pbox[12];
uint pbox13 = pbox[13];
uint pbox14 = pbox[14];
uint pbox15 = pbox[15];
uint pbox16 = pbox[16];
uint pbox17 = pbox[17];
uint hi = (((uint)iv[0]) << 24) |
(((uint)iv[1]) << 16) |
(((uint)iv[2]) << 8) |
iv[3];
uint lo = (((uint)iv[4]) << 24) |
(((uint)iv[5]) << 16) |
(((uint)iv[6]) << 8) |
iv[7];
int rest = count % BLOCK_SIZE;
end -= rest;
for (; ; )
{
hi ^= pbox00;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox01;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox02;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox03;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox04;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox05;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox06;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox07;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox08;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox09;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox10;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox11;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox12;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox13;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox14;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox15;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox16;
uint swap = lo ^ pbox17;
lo = hi;
hi = swap;
if (posIn >= end)
{
break;
}
uint chi = (((uint)dataIn[posIn]) << 24) |
(((uint)dataIn[posIn + 1]) << 16) |
(((uint)dataIn[posIn + 2]) << 8) |
dataIn[posIn + 3];
uint clo = (((uint)dataIn[posIn + 4]) << 24) |
(((uint)dataIn[posIn + 5]) << 16) |
(((uint)dataIn[posIn + 6]) << 8) |
dataIn[posIn + 7];
posIn += 8;
hi ^= chi;
lo ^= clo;
dataOut[posOut] = (byte)(hi >> 24);
dataOut[posOut + 1] = (byte)(hi >> 16);
dataOut[posOut + 2] = (byte)(hi >> 8);
dataOut[posOut + 3] = (byte)hi;
dataOut[posOut + 4] = (byte)(lo >> 24);
dataOut[posOut + 5] = (byte)(lo >> 16);
dataOut[posOut + 6] = (byte)(lo >> 8);
dataOut[posOut + 7] = (byte)lo;
posOut += 8;
hi = chi;
lo = clo;
}
iv[0] = (byte)(hi >> 24);
iv[1] = (byte)(hi >> 16);
iv[2] = (byte)(hi >> 8);
iv[3] = (byte)hi;
iv[4] = (byte)(lo >> 24);
iv[5] = (byte)(lo >> 16);
iv[6] = (byte)(lo >> 8);
iv[7] = (byte)lo;
for (int i = 0; i < rest; i++)
{
int b = dataIn[posIn + i];
dataOut[posOut + i] = (byte)(b ^ iv[i]);
iv[i] = (byte)b;
}
this.ivBytesLeft = iv.Length - rest;
return count;
}
/// <see cref="BlowfishNET.BlowfishECB.Clone"/>
public new object Clone()
{
BlowfishCFB result;
result = new BlowfishCFB();
result.pbox = (uint[])this.pbox.Clone();
result.sbox1 = (uint[])this.sbox1.Clone();
result.sbox2 = (uint[])this.sbox2.Clone();
result.sbox3 = (uint[])this.sbox3.Clone();
result.sbox4 = (uint[])this.sbox4.Clone();
result.block = (byte[])this.block.Clone();
result.isWeakKey = this.isWeakKey;
result.iv = (byte[])this.iv.Clone();
return result;
}
}
}

View File

@ -0,0 +1,717 @@
/*
Copyright 2001-2007 Markus Hahn
All rights reserved. See documentation for license details.
*/
using System;
namespace DG.Tool
{
/// <summary>Blowfish ECB implementation.</summary>
/// <remarks>Use this class to encrypt or decrypt byte arrays or a single
/// block with Blowfish in the ECB (Electronic Code Book) mode. The key
/// length can be flexible from zero up to 56 bytes.</remarks>
public class BlowfishECB : ICloneable
{
/// <summary>The maximum and recommended key size in bytes.</summary>
public const int MAX_KEY_LENGTH = 56;
/// <summary>The block size in bytes.</summary>
public const int BLOCK_SIZE = 8;
const int PBOX_ENTRIES = 18;
const int SBOX_ENTRIES = 256;
#region Cipher State
/// <summary>Runtime p-box.</summary>
protected uint[] pbox = new uint[PBOX_ENTRIES];
/// <summary>Runtime s-box #1.</summary>
protected uint[] sbox1 = new uint[SBOX_ENTRIES];
/// <summary>Runtime s-box #2.</summary>
protected uint[] sbox2 = new uint[SBOX_ENTRIES];
/// <summary>Runtime s-box #3.</summary>
protected uint[] sbox3 = new uint[SBOX_ENTRIES];
/// <summary>Runtime s-box #4.</summary>
protected uint[] sbox4 = new uint[SBOX_ENTRIES];
/// <summary>Single block cache.</summary>
protected byte[] block = new byte[BLOCK_SIZE];
/// <summary>1 if a weak key was detected, 0 if not and -1 if it hasn't
/// been determined yet.</summary>
protected int isWeakKey;
#endregion
/// <summary>To check if the key used is weak.</summary>
/// <remarks>If a key is weak it means that eventually an attack is easier to apply than
/// just a simple brute force on keys. Due to the randomness in the key setup process
/// such a case however is unlikely to happen, yet checking after each setup might still
/// be the preferred way. In the case of a weak key detected a simple recreation with a
/// different key (or just a different salt value) is the recommended solution. For
/// performance reasons we don't do the weak key check during the initialization, but on
/// demand only, and then only once to determine the flag.</remarks>
public bool IsWeakKey
{
get
{
if (-1 == this.isWeakKey)
{
this.isWeakKey = 0;
int i, j;
for (i = 0; i < SBOX_ENTRIES - 1; i++)
{
j = i + 1;
while (j < SBOX_ENTRIES)
{
if ((this.sbox1[i] == this.sbox1[j]) |
(this.sbox2[i] == this.sbox2[j]) |
(this.sbox3[i] == this.sbox3[j]) |
(this.sbox4[i] == this.sbox4[j])) break;
else j++;
}
if (j < SBOX_ENTRIES)
{
this.isWeakKey = 1;
break;
}
}
}
return (1 == this.isWeakKey);
}
}
/// <summary>Resets the instance with new or initial key material. Allows the switch of
/// keys at runtime without any new internal object allocation.</summary>
/// <param name="key">The buffer with the key material.</param>
/// <param name="ofs">Position at which the key material starts in the buffer.</param>
/// <param name="len">Size of the key material, up to MAX_KEY_LENGTH bytes.</param>
public void Initialize(byte[] key, int ofs, int len)
{
this.isWeakKey = -1;
Array.Copy(PBOX_INIT, 0, this.pbox, 0, PBOX_INIT.Length);
Array.Copy(SBOX_INIT_1, 0, this.sbox1, 0, SBOX_INIT_1.Length);
Array.Copy(SBOX_INIT_2, 0, this.sbox2, 0, SBOX_INIT_2.Length);
Array.Copy(SBOX_INIT_3, 0, this.sbox3, 0, SBOX_INIT_3.Length);
Array.Copy(SBOX_INIT_4, 0, this.sbox4, 0, SBOX_INIT_4.Length);
if (0 == len)
{
return;
}
int keyPos = ofs;
int keyEnd = ofs + len;
uint build = 0;
for (int i = 0; i < PBOX_ENTRIES; i++)
{
for (int j = 0; j < 4; j++)
{
build = (build << 8) | key[keyPos];
if (++keyPos == keyEnd)
{
keyPos = ofs;
}
}
this.pbox[i] ^= build;
}
uint hi = 0;
uint lo = 0;
uint[] box = this.pbox;
for (int i = 0; i < PBOX_ENTRIES; i += 2)
{
EncryptBlock(hi, lo, out hi, out lo);
box[i] = hi;
box[i + 1] = lo;
}
box = this.sbox1;
for (int i = 0; i < SBOX_ENTRIES; i += 2)
{
EncryptBlock(hi, lo, out hi, out lo);
box[i] = hi;
box[i + 1] = lo;
}
box = this.sbox2;
for (int i = 0; i < SBOX_ENTRIES; i += 2)
{
EncryptBlock(hi, lo, out hi, out lo);
box[i] = hi;
box[i + 1] = lo;
}
box = this.sbox3;
for (int i = 0; i < SBOX_ENTRIES; i += 2)
{
EncryptBlock(hi, lo, out hi, out lo);
box[i] = hi;
box[i + 1] = lo;
}
box = this.sbox4;
for (int i = 0; i < SBOX_ENTRIES; i += 2)
{
EncryptBlock(hi, lo, out hi, out lo);
box[i] = hi;
box[i + 1] = lo;
}
}
/// <summary>Zero constructor, properly initializes an instance. Initialize afterwards
/// to set up a valid key!</summary>
public BlowfishECB()
{
Initialize(null, 0, 0);
}
/// <see cref="BlowfishECB.Initialize"/>
public BlowfishECB(byte[] key, int ofs, int len)
{
Initialize(key, ofs, len);
}
/// <summary> Deletes all internal data structures and invalidates this instance.</summary>
/// <remarks>Call this method as soon as the work with a particular instance is done,
/// so no sensitive translated key material remains. The instance is invalid after this
/// call and usage can lead to unexpected results!</remarks>
public void Invalidate()
{
Array.Clear(this.pbox, 0, this.pbox.Length);
Array.Clear(this.sbox1, 0, this.sbox1.Length);
Array.Clear(this.sbox2, 0, this.sbox2.Length);
Array.Clear(this.sbox3, 0, this.sbox3.Length);
Array.Clear(this.sbox4, 0, this.sbox4.Length);
Array.Clear(this.block, 0, this.block.Length);
}
static readonly byte[] TEST_KEY = { 0x1c, 0x58, 0x7f, 0x1c, 0x13, 0x92, 0x4f, 0xef };
static readonly uint[] TEST_VECTOR_PLAIN = { 0x30553228, 0x6d6f295a };
static readonly uint[] TEST_VECTOR_CIPHER = { 0x55cb3774, 0xd13ef201 };
/// <summary>To execute a selftest.</summary>
/// <remarks>Call this method to make sure that the implemenation is able to produce
/// valid output according to the specification. This should usually be done at process
/// startup time, before the usage of this class and its inherited variants.</remarks>
/// <returns>True if the selftest passed or false is it failed. In such a case you must
/// not use the cipher to avoid data corruption!</returns>
public static bool RunSelfTest()
{
uint hi = TEST_VECTOR_PLAIN[0];
uint lo = TEST_VECTOR_PLAIN[1];
BlowfishECB bfe = new BlowfishECB(TEST_KEY, 0, TEST_KEY.Length);
bfe.EncryptBlock(hi, lo, out hi, out lo);
if ((TEST_VECTOR_CIPHER[0] != hi) ||
(TEST_VECTOR_CIPHER[1] != lo))
{
return false;
}
bfe.DecryptBlock(hi, lo, out hi, out lo);
if ((TEST_VECTOR_PLAIN[0] != hi) ||
(TEST_VECTOR_PLAIN[1] != lo))
{
return false;
}
return true;
}
/// <summary>Encrypts a single block.</summary>
/// <param name="hi">The high 32bit word of the block.</param>
/// <param name="lo">The low 32bit word of the block.</param>
/// <param name="outHi">Where to put the encrypted high word.</param>
/// <param name="outLo">Where to put the encrypted low word.</param>
public void EncryptBlock(
uint hi,
uint lo,
out uint outHi,
out uint outLo)
{
byte[] block = this.block;
block[0] = (byte)(hi >> 24);
block[1] = (byte)(hi >> 16);
block[2] = (byte)(hi >> 8);
block[3] = (byte)hi;
block[4] = (byte)(lo >> 24);
block[5] = (byte)(lo >> 16);
block[6] = (byte)(lo >> 8);
block[7] = (byte)lo;
Encrypt(block, 0, block, 0, BLOCK_SIZE);
outHi = (((uint)block[0]) << 24) |
(((uint)block[1]) << 16) |
(((uint)block[2]) << 8) |
block[3];
outLo = (((uint)block[4]) << 24) |
(((uint)block[5]) << 16) |
(((uint)block[6]) << 8) |
block[7];
}
/// <summary>Decrypts a single block.</summary>
/// <param name="hi">The high 32bit word of the block.</param>
/// <param name="lo">The low 32bit word of the block.</param>
/// <param name="outHi">Where to put the decrypted high word.</param>
/// <param name="outLo">Where to put the decrypted low word.</param>
public void DecryptBlock(
uint hi,
uint lo,
out uint outHi,
out uint outLo)
{
byte[] block = this.block;
block[0] = (byte)(hi >> 24);
block[1] = (byte)(hi >> 16);
block[2] = (byte)(hi >> 8);
block[3] = (byte)hi;
block[4] = (byte)(lo >> 24);
block[5] = (byte)(lo >> 16);
block[6] = (byte)(lo >> 8);
block[7] = (byte)lo;
Decrypt(block, 0, block, 0, BLOCK_SIZE);
outHi = (((uint)block[0]) << 24) |
(((uint)block[1]) << 16) |
(((uint)block[2]) << 8) |
block[3];
outLo = (((uint)block[4]) << 24) |
(((uint)block[5]) << 16) |
(((uint)block[6]) << 8) |
block[7];
}
/// <summary>Encrypts byte buffers.</summary>
/// <remarks>Use this method to encrypt bytes from one array to another one. You can also
/// use the same array for input and output. Note that the number of bytes must be adjusted
/// to the block size of the algorithm. Overlapping bytes will not be encrypted. No check for
/// buffer overflows are made.</remarks>
/// <param name="dataIn">The input buffer.</param>
/// <param name="posIn">Where to start reading in the input buffer.</param>
/// <param name="dataOut">The output buffer.</param>
/// <param name="posOut">Where to start writing to the output buffer.</param>
/// <param name="count">The number ob bytes to encrypt.</param>
/// <returns>The number of bytes processed.</returns>
public int Encrypt(
byte[] dataIn,
int posIn,
byte[] dataOut,
int posOut,
int count)
{
uint[] sbox1 = this.sbox1;
uint[] sbox2 = this.sbox2;
uint[] sbox3 = this.sbox3;
uint[] sbox4 = this.sbox4;
uint[] pbox = this.pbox;
uint pbox00 = pbox[0];
uint pbox01 = pbox[1];
uint pbox02 = pbox[2];
uint pbox03 = pbox[3];
uint pbox04 = pbox[4];
uint pbox05 = pbox[5];
uint pbox06 = pbox[6];
uint pbox07 = pbox[7];
uint pbox08 = pbox[8];
uint pbox09 = pbox[9];
uint pbox10 = pbox[10];
uint pbox11 = pbox[11];
uint pbox12 = pbox[12];
uint pbox13 = pbox[13];
uint pbox14 = pbox[14];
uint pbox15 = pbox[15];
uint pbox16 = pbox[16];
uint pbox17 = pbox[17];
count &= ~(BLOCK_SIZE - 1);
int end = posIn + count;
while (posIn < end)
{
uint hi = (((uint)dataIn[posIn]) << 24) |
(((uint)dataIn[posIn + 1]) << 16) |
(((uint)dataIn[posIn + 2]) << 8) |
dataIn[posIn + 3];
uint lo = (((uint)dataIn[posIn + 4]) << 24) |
(((uint)dataIn[posIn + 5]) << 16) |
(((uint)dataIn[posIn + 6]) << 8) |
dataIn[posIn + 7];
posIn += 8;
hi ^= pbox00;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox01;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox02;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox03;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox04;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox05;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox06;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox07;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox08;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox09;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox10;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox11;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox12;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox13;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox14;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox15;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox16;
lo ^= pbox17;
dataOut[posOut] = (byte)(lo >> 24);
dataOut[posOut + 1] = (byte)(lo >> 16);
dataOut[posOut + 2] = (byte)(lo >> 8);
dataOut[posOut + 3] = (byte)lo;
dataOut[posOut + 4] = (byte)(hi >> 24);
dataOut[posOut + 5] = (byte)(hi >> 16);
dataOut[posOut + 6] = (byte)(hi >> 8);
dataOut[posOut + 7] = (byte)hi;
posOut += 8;
}
return count;
}
/// <summary>Decrypts single bytes.</summary>
/// <remarks>Use this method to decrypt bytes from one array to another one. You can also use
/// the same array for input and output. Note that the number of bytes must be adjusted to the
/// block size of the algorithm. Overlapping bytes will not be decrypted. No check for buffer
/// overflows are made.</remarks>
/// <param name="dataIn">The input buffer.</param>
/// <param name="posIn">Where to start reading in the input buffer.</param>
/// <param name="dataOut">The output buffer.</param>
/// <param name="posOut">Where to start writing to the output buffer.</param>
/// <param name="count">Number ob bytes to decrypt.</param>
/// <returns>The number of bytes processed.</returns>
public int Decrypt(
byte[] dataIn,
int posIn,
byte[] dataOut,
int posOut,
int count)
{
uint[] sbox1 = this.sbox1;
uint[] sbox2 = this.sbox2;
uint[] sbox3 = this.sbox3;
uint[] sbox4 = this.sbox4;
uint[] pbox = this.pbox;
uint pbox00 = pbox[0];
uint pbox01 = pbox[1];
uint pbox02 = pbox[2];
uint pbox03 = pbox[3];
uint pbox04 = pbox[4];
uint pbox05 = pbox[5];
uint pbox06 = pbox[6];
uint pbox07 = pbox[7];
uint pbox08 = pbox[8];
uint pbox09 = pbox[9];
uint pbox10 = pbox[10];
uint pbox11 = pbox[11];
uint pbox12 = pbox[12];
uint pbox13 = pbox[13];
uint pbox14 = pbox[14];
uint pbox15 = pbox[15];
uint pbox16 = pbox[16];
uint pbox17 = pbox[17];
count &= ~(BLOCK_SIZE - 1);
int end = posIn + count;
while (posIn < end)
{
uint hi = (((uint)dataIn[posIn]) << 24) |
(((uint)dataIn[posIn + 1]) << 16) |
(((uint)dataIn[posIn + 2]) << 8) |
dataIn[posIn + 3];
uint lo = (((uint)dataIn[posIn + 4]) << 24) |
(((uint)dataIn[posIn + 5]) << 16) |
(((uint)dataIn[posIn + 6]) << 8) |
dataIn[posIn + 7];
posIn += 8;
hi ^= pbox17;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox16;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox15;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox14;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox13;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox12;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox11;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox10;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox09;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox08;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox07;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox06;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox05;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox04;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox03;
lo ^= (((sbox1[(int)(hi >> 24)] + sbox2[(int)((hi >> 16) & 0x0ff)]) ^ sbox3[(int)((hi >> 8) & 0x0ff)]) + sbox4[(int)(hi & 0x0ff)]) ^ pbox02;
hi ^= (((sbox1[(int)(lo >> 24)] + sbox2[(int)((lo >> 16) & 0x0ff)]) ^ sbox3[(int)((lo >> 8) & 0x0ff)]) + sbox4[(int)(lo & 0x0ff)]) ^ pbox01;
lo ^= pbox00;
dataOut[posOut] = (byte)(lo >> 24);
dataOut[posOut + 1] = (byte)(lo >> 16);
dataOut[posOut + 2] = (byte)(lo >> 8);
dataOut[posOut + 3] = (byte)lo;
dataOut[posOut + 4] = (byte)(hi >> 24);
dataOut[posOut + 5] = (byte)(hi >> 16);
dataOut[posOut + 6] = (byte)(hi >> 8);
dataOut[posOut + 7] = (byte)hi;
posOut += 8;
}
return count;
}
/// <remarks>Cloning can be very useful if you need multiple instances all using
/// the same key, since the expensive cipher setup will be bypassed.</remarks>
/// <see cref="System.ICloneable.Clone()"/>
public object Clone()
{
BlowfishECB result = new BlowfishECB();
result.pbox = (uint[])this.pbox.Clone();
result.sbox1 = (uint[])this.sbox1.Clone();
result.sbox2 = (uint[])this.sbox2.Clone();
result.sbox3 = (uint[])this.sbox3.Clone();
result.sbox4 = (uint[])this.sbox4.Clone();
result.block = (byte[])this.block.Clone();
result.isWeakKey = this.isWeakKey;
return result;
}
#region Boxes Initialization Data
/// <summary>The P-box initialization data.</summary>
protected static readonly uint[] PBOX_INIT =
{
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
};
/// <summary>The first S-box initialization data.</summary>
protected static readonly uint[] SBOX_INIT_1 =
{
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
};
/// <summary>The second S-box initialization data.</summary>
protected static readonly uint[] SBOX_INIT_2 =
{
0x4b7a70e9, 0xb5b32944,
0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29,
0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 0x4cdd2086, 0x8470eb26,
0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c,
0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 0xd19113f9, 0x7ca92ff6,
0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f,
0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 0xde9a771f, 0xd9930810,
0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa,
0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 0x71dff89e, 0x10314e55,
0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1,
0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 0xc6150eba, 0x94e2ea78,
0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883,
0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 0x1521b628, 0x29076170,
0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7,
0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 0x9b540b19, 0x875fa099,
0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263,
0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 0x5d4a14d9, 0xe864b7e3,
0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7,
0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 0x095bbf00, 0xad19489d,
0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460,
0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 0x9e447a2e, 0xc3453484,
0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a,
0xe6e39f2b, 0xdb83adf7
};
/// <summary>The third S-box initialization data.</summary>
protected static readonly uint[] SBOX_INIT_3 =
{
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a,
0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785,
0x7fac6dd0, 0x31cb8504, 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900,
0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9,
0xee39d7ab, 0x3b124e8b, 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397,
0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9,
0x5ef47e1c, 0x9029317c, 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f,
0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e,
0xaf664fd1, 0xcad18115, 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd,
0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8,
0x991be14c, 0xdb6e6b0d, 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c,
0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b,
0x12754ccc, 0x782ef11c, 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386,
0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0,
0x7745ae04, 0xd736fccc, 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2,
0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770,
0x8cd55591, 0xc902de4c, 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c,
0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa,
0xa002b5c4, 0x0de6d027, 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63,
0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9,
0x1ac15bb4, 0xd39eb8fc, 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4,
0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
};
/// <summary>The fourth S-box initialization data.</summary>
protected static readonly uint[] SBOX_INIT_4 =
{
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
};
#endregion
}
}

View File

@ -0,0 +1,165 @@
/*
Copyright 2001-2007 Markus Hahn
All rights reserved. See documentation for license details.
*/
using System;
using System.Text;
namespace DG.Tool
{
/// <summary>An easy-to-use-string encryption solution using Blowfish/CBC.</summary>
/// <remarks>As a simple solution for developers, who want nothing more than protect
/// single strings with a password, this class provides the necessary functionality.
/// The password (aka as key) is hashed using the SHA-1 implementation of the .NET
/// framework. The random number generator for the CBC initialization vector (IV)
/// and BASE64 are used from the framework's security services.</remarks>
public class BlowfishSimple
{
BlowfishCBC bfc;
private byte[] iv;
private byte[] IV
{
get
{
if (iv == null || iv.Length < 8)
{
return Encoding.UTF8.GetBytes("Blowfish");
}
return iv;
}
set { iv = value; }
}
static byte[] TransformKey(String key)
{
UTF8Encoding ue = new UTF8Encoding();
return ue.GetBytes(key);
}
/// <summary>Empty constructor. Before using the instance you MUST call Initialize(),
/// otherwise any result or behavior is unpredictable!</summary>
public BlowfishSimple()
{
}
/// <summary>Default constructor.</summary>
/// <param name="keyStr">The string which is used as the key material (aka as
/// password or passphrase). Internally the UTF-8 representation of this string
/// is used, hashed with SHA-1. The result is then a 160bit binary key. Notice
/// that this transformation will not make weak (meaning short or easily guessable)
/// keys any safer!</param>
public BlowfishSimple(String keyStr)
{
Initialize(keyStr, null);
}
public BlowfishSimple(String keyStr, Byte[] iv)
{
Initialize(keyStr, iv);
}
/// <summary>Initializes the instance with a (new) key string.</summary>
/// <param name="keyStr">The key material.</param>
/// <see cref="BlowfishSimple(String)"/>
public void Initialize(String keyStr, Byte[] iv)
{
IV = iv;
byte[] key = TransformKey(keyStr);
this.bfc = new BlowfishCBC(key, 0, key.Length);
Array.Clear(key, 0, key.Length);
}
/// <summary>Encrypts a string.</summary>
/// <remarks>For efficiency the given string will be UTF-8 encoded and padded to
/// the next 8byte block border. The CBC IV plus the encrypted data will then be
/// BASE64 encoded and returned as the final encryption result.</remarks>
/// <param name="plainText">The string to encrypt.</param>
/// <returns>The encrypted string.</returns>
public String Encrypt(String plainText)
{
return Encrypt(plainText, this.IV);
}
public String Encrypt(String plainText, byte[] iv)
{
if (string.IsNullOrEmpty(plainText)) return string.Empty;
int txtLen = plainText.Length;
if (txtLen % 8 != 0)
plainText = plainText.PadRight(txtLen - txtLen % 8 + 8, ' ');
byte[] ueData = Encoding.UTF8.GetBytes(plainText);
int origLen = ueData.Length;
byte[] inBuf = new byte[origLen];
Array.Copy(ueData, 0, inBuf, 0, origLen);
byte[] outBuf = new byte[inBuf.Length];
this.bfc.IV = iv;
this.bfc.Encrypt(
inBuf,
0,
outBuf,
0,
inBuf.Length);
String sResult = Convert.ToBase64String(outBuf);
Array.Clear(inBuf, 0, inBuf.Length);
return sResult;
}
/// <summary>Decrypts a string which was formely generated by the Encrypt()
/// method and a particular key.</summary>
/// <remarks>The string has to be decrypted with the same key, otherwise the
/// result will be simply garbage. If you want to check if the key is the right
/// one use the VerifyKey() method.</remarks>
/// <param name="cipherText">The string to decrypt.</param>
/// <returns>The decrypted string, or null on error (usually caused by a wrong
/// key passed in).</returns>
public String Decrypt(String cipherText)
{
return Decrypt(cipherText, this.IV);
}
public String Decrypt(String cipherText, byte[] iv)
{
byte[] cdata;
try
{
cdata = Convert.FromBase64String(cipherText);
}
catch (FormatException)
{
return null;
}
this.bfc.SetIV(iv, 0);
byte[] outBuf = new byte[cdata.Length];
int dataAbs = outBuf.Length;
this.bfc.Decrypt(
cdata,
0,
outBuf,
0,
dataAbs);
return Encoding.UTF8.GetString(outBuf);
}
}
}

View File

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Version>1.0.13</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="EPPlus" Version="6.2.7" />
<PackageReference Include="NPOI" Version="2.6.2" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DG.Tool
{
public static class DateTimeTool
{
/// <summary>
/// 获取指定日期所在周的第一天,星期天为第一天
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTime GetDateTimeWeekFirstDaySun(DateTime dateTime)
{
DateTime firstWeekDay = DateTime.Now;
try
{
//得到是星期几,然后从当前日期减去相应天数
int weeknow = Convert.ToInt32(dateTime.DayOfWeek);
int daydiff = (-1) * weeknow;
firstWeekDay = dateTime.AddDays(daydiff);
}
catch { }
return firstWeekDay;
}
/// <summary>
/// 获取指定日期所在周的第一天,星期一为第一天
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTime GetDateTimeWeekFirstDayMon(DateTime dateTime)
{
DateTime firstWeekDay = DateTime.Now;
try
{
int weeknow = Convert.ToInt32(dateTime.DayOfWeek);
//星期一为第一天weeknow等于0时要向前推6天。
weeknow = (weeknow == 0 ? (7 - 1) : (weeknow - 1));
int daydiff = (-1) * weeknow;
firstWeekDay = dateTime.AddDays(daydiff);
}
catch { }
return firstWeekDay;
}
/// <summary>
/// 获取指定日期所在周的最后一天,星期六为最后一天
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTime GetDateTimeWeekLastDaySat(DateTime dateTime)
{
DateTime lastWeekDay = DateTime.Now;
try
{
int weeknow = Convert.ToInt32(dateTime.DayOfWeek);
int daydiff = (7 - weeknow) - 1;
lastWeekDay = dateTime.AddDays(daydiff);
}
catch { }
return lastWeekDay;
}
/// <summary>
/// 获取指定日期所在周的最后一天,星期天为最后一天
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTime GetDateTimeWeekLastDaySun(DateTime dateTime)
{
DateTime lastWeekDay = DateTime.Now;
try
{
int weeknow = Convert.ToInt32(dateTime.DayOfWeek);
weeknow = (weeknow == 0 ? 7 : weeknow);
int daydiff = (7 - weeknow);
lastWeekDay = dateTime.AddDays(daydiff);
}
catch { }
return lastWeekDay;
}
/// <summary>
/// 获取指定日期的月份第一天
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTime GetDateTimeMonthFirstDay(DateTime dateTime)
{
if (dateTime == null)
{
dateTime = DateTime.Now;
}
return new DateTime(dateTime.Year, dateTime.Month, 1);
}
/// <summary>
/// 获取指定月份最后一天
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTime GetDateTimeMonthLastDay(DateTime dateTime)
{
int day = DateTime.DaysInMonth(dateTime.Year, dateTime.Month);
return new DateTime(dateTime.Year, dateTime.Month, day);
}
/// <summary>
/// 时间戳转为C#格式时间
/// </summary>
/// <param name=”timeStamp”></param>
/// <returns></returns>
public static DateTime GetTimeFromLinuxTime(long timeStamp)
{
System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0);
dtDateTime = dtDateTime.AddMilliseconds(timeStamp).ToLocalTime();
return dtDateTime;
}
/// <summary>
/// 时间戳转为C#格式时间
/// </summary>
/// <param name=”timeStamp”></param>
/// <returns></returns>
public static DateTime GetTimeFromLinuxShortTime(long timeStamp)
{
DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
long lTime = long.Parse(timeStamp.ToString() + "0000000");
TimeSpan toNow = new TimeSpan(lTime); return dtStart.Add(toNow);
}
/// <summary>
/// DateTime时间格式转换为Unix时间戳格式
/// </summary>
/// <param name=”time”></param>
/// <returns></returns>
public static int ConvertDateTimeInt(System.DateTime time)
{
System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
return (int)(time - startTime).TotalSeconds;
}
}
}

View File

@ -0,0 +1,55 @@
using System;
using System.ComponentModel;
using System.Reflection;
namespace DG.Tool
{
/// <summary>
/// 获取实体类Attribute自定义属性
/// </summary>
public static class EnumHelper
{
/// <summary>
/// 返回枚举项的描述信息。
/// </summary>
/// <param name="value">要获取描述信息的枚举项。</param>
/// <returns>枚举想的描述信息。</returns>
public static string GetDescription(this Enum value)
{
Type enumType = value.GetType();
// 获取枚举常数名称。
string name = Enum.GetName(enumType, value);
if (name != null)
{
// 获取枚举字段。
FieldInfo fieldInfo = enumType.GetField(name);
if (fieldInfo != null)
{
// 获取描述的属性。
DescriptionAttribute attr = Attribute.GetCustomAttribute(fieldInfo,
typeof(DescriptionAttribute), false) as DescriptionAttribute;
if (attr != null)
{
return attr.Description;
}
}
}
return null;
}
/// <summary>
/// 获取枚举名字
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static string GetName(this Enum value)
{
Type enumType = value.GetType();
// 获取枚举常数名称。
string name = Enum.GetName(enumType, value);
if (name == null) return null;
// 获取枚举字段。
FieldInfo fieldInfo = enumType.GetField(name);
return fieldInfo?.Name;
}
}
}

897
code/DG.Tool/ExcelHelper.cs Normal file
View File

@ -0,0 +1,897 @@
using Microsoft.VisualBasic;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using OfficeOpenXml;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace DG.Tool
{
public static class ExcelHelper
{
public static void Export<T>(string fullName, List<T> data)
{
ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial;
var ttype = typeof(T);
var typeName = ttype.Name;
var typeDescriptionAttr = ttype.GetCustomAttribute<DescriptionAttribute>();
if (typeDescriptionAttr != null)
{
typeName = typeDescriptionAttr.Description;
}
var tps = ttype.GetProperties().ToList();
for (var i = tps.Count - 1; i >= 0; i--)
{
var attr = tps[i].GetCustomAttribute<NotExportColumnAttribute>();
if (attr != null)
{
tps.RemoveAt(i);
}
}
using (var package = new ExcelPackage(new FileInfo(fullName)))
{
var worksheet = package.Workbook.Worksheets.Add(typeName);
for (var i = 0; i < tps.Count; i++)
{
var tp = tps[i];
var tpName = tp.Name;
var tpDescriptionAttr = tp.GetCustomAttribute<DescriptionAttribute>();
if (tpDescriptionAttr != null)
{
tpName = tpDescriptionAttr.Description;
}
worksheet.Cells[1, i + 1].Value = tpName;
}
for (var j = 0; j < data.Count; j++)
{
for (var k = 0; k < tps.Count; k++)
{
var val_display = "";
var val = tps[k].GetValue(data[j], null);
if (val != null)
{
val_display = Convert.ToString(val);
}
worksheet.Cells[j + 2, k + 1].Value = val_display;
}
}
package.Save();
}
}
/// <summary>
/// excel导入
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="bytes"></param>
/// <param name="dataRow">数据从第几行开始</param>
/// <param name="onlyFirstSheet">只导入第一个Sheet的数据</param>
/// <returns></returns>
public static List<T> Import<T>(byte[] bytes, int dataRow = 2, bool onlyFirstSheet = true) where T : class, new()
{
var ttype = typeof(T);
var tps = ttype.GetProperties();
var items = new List<T>();
using (var ms = new MemoryStream(bytes))
{
ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial;
using (var package = new ExcelPackage(ms))
{
var sheets = package.Workbook.Worksheets.ToList();
if (onlyFirstSheet)
{
sheets = new List<ExcelWorksheet> { package.Workbook.Worksheets[0] };
}
foreach (var sheet in sheets)
{
for (var i = dataRow; i <= sheet.Dimension.Rows; i++)
{
var one = Activator.CreateInstance<T>();
for (var j = 0; j < tps.Length; j++)
{
var cell = sheet.Cells[i, j + 1];
if (cell == null)
{
continue;
}
var tp = tps[j];
var val = GetValue2(tp, cell.GetValue<string>());
tp.SetValue(one, val, null);
}
items.Add(one);
}
}
}
}
return items;
}
public static async Task ExportAsync<T>(string fullName, List<T> data)
{
ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial;
var ttype = typeof(T);
var typeName = ttype.Name;
var typeDescriptionAttr = ttype.GetCustomAttribute<DescriptionAttribute>();
if (typeDescriptionAttr != null)
{
typeName = typeDescriptionAttr.Description;
}
var tps = ttype.GetProperties().ToList();
for (var i = tps.Count - 1; i >= 0; i--)
{
var attr = tps[i].GetCustomAttribute<NotExportColumnAttribute>();
if (attr != null)
{
tps.RemoveAt(i);
}
}
using (var package = new ExcelPackage(new FileInfo(fullName)))
{
var worksheet = package.Workbook.Worksheets.Add(typeName);
for (var i = 0; i < tps.Count; i++)
{
var tp = tps[i];
var tpName = tp.Name;
var tpDescriptionAttr = tp.GetCustomAttribute<DescriptionAttribute>();
if (tpDescriptionAttr != null)
{
tpName = tpDescriptionAttr.Description;
}
worksheet.Cells[1, i + 1].Value = tpName;
}
for (var j = 0; j < data.Count; j++)
{
for (var k = 0; k < tps.Count; k++)
{
var val_display = "";
var val = tps[k].GetValue(data[j], null);
if (val != null)
{
val_display = Convert.ToString(val);
}
worksheet.Cells[j + 2, k + 1].Value = val_display;
}
}
await package.SaveAsync();
}
}
private static object GetValue2(PropertyInfo tp, string val)
{
if (tp.PropertyType == typeof(int) || tp.PropertyType == typeof(int?))
{
if (int.TryParse(val, out int temp))
{
return temp;
}
return default(int?);
}
if (tp.PropertyType == typeof(long) || tp.PropertyType == typeof(long?))
{
if (long.TryParse(val, out long temp))
{
return temp;
}
return default(long?);
}
if (tp.PropertyType == typeof(decimal) || tp.PropertyType == typeof(decimal?))
{
if (decimal.TryParse(val, out decimal temp))
{
return temp;
}
return default(decimal?);
}
if (tp.PropertyType == typeof(DateTime) || tp.PropertyType == typeof(DateTime?))
{
if (DateTime.TryParse(val, out DateTime temp))
{
return temp;
}
return default(DateTime?);
}
if (tp.PropertyType == typeof(bool) || tp.PropertyType == typeof(bool?))
{
if (bool.TryParse(val, out bool temp))
{
return temp;
}
return default(bool?);
}
return val;
}
/// <summary>
/// 生成Excel文件(多行头部)
/// </summary>
/// <param name="dt">数据源</param>
/// <param name="strExcelFileName">文件名</param>
/// <param name="extHeaders"></param>
public static void GridToExcelByNPOIMultiHeader(DataTable dt, string strExcelFileName, List<List<string>> extHeaders)
{
HSSFWorkbook workbook = new HSSFWorkbook();
try
{
int sheetIndex = 0;
int dataIndex = 0;
ICellStyle HeadercellStyle = workbook.CreateCellStyle();
HeadercellStyle.BorderBottom = BorderStyle.Thin;
HeadercellStyle.BorderLeft = BorderStyle.Thin;
HeadercellStyle.BorderRight = BorderStyle.Thin;
HeadercellStyle.BorderTop = BorderStyle.Thin;
HeadercellStyle.Alignment = HorizontalAlignment.Center;
ICellStyle cellStyle = workbook.CreateCellStyle();
//为避免日期格式被Excel自动替换所以设定 format 为 『@』 表示一率当成text來看
cellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("@");
cellStyle.BorderBottom = BorderStyle.Thin;
cellStyle.BorderLeft = BorderStyle.Thin;
cellStyle.BorderRight = BorderStyle.Thin;
cellStyle.BorderTop = BorderStyle.Thin;
//字体
IFont headerfont = workbook.CreateFont();
headerfont.Boldweight = (short)FontBoldWeight.Bold;
HeadercellStyle.SetFont(headerfont);
IFont cellfont = workbook.CreateFont();
cellfont.Boldweight = (short)FontBoldWeight.Normal;
cellStyle.SetFont(cellfont);
var index = extHeaders.Count;
while (dataIndex < dt.Rows.Count)
{
sheetIndex++;
ISheet sheet = workbook.CreateSheet($"Sheet{sheetIndex}");
if (index > 0)
{
for (var i = 0; i < index; i++)
{
IRow extHeaderRow = sheet.CreateRow(i);
if (extHeaders[i].Count == 0)
{
ICell extCell = extHeaderRow.CreateCell(0);
extCell.SetCellValue("");
extCell.CellStyle = HeadercellStyle;
}
else
{
for (var j = 0; j < extHeaders[i].Count; j++)
{
ICell cell = extHeaderRow.CreateCell(j);
cell.SetCellValue(extHeaders[i][j]);
cell.CellStyle = HeadercellStyle;
}
}
}
}
//用column name 作为列名
int icolIndex = 0;
IRow headerRow = sheet.CreateRow(index);
foreach (DataColumn item in dt.Columns)
{
ICell cell = headerRow.CreateCell(icolIndex);
cell.SetCellValue(item.ColumnName);
cell.CellStyle = HeadercellStyle;
icolIndex++;
}
//建立内容行
int iRowIndex = 1;
int iCellIndex = 0;
for (int count = 0; dataIndex < dt.Rows.Count; dataIndex++, count++)
{
if (count >= 65000)
break;
DataRow Rowitem = dt.Rows[dataIndex];
IRow DataRow = sheet.CreateRow(index + iRowIndex);
foreach (DataColumn Colitem in dt.Columns)
{
ICell cell = DataRow.CreateCell(iCellIndex);
cell.SetCellValue(Rowitem[Colitem].ToString());
cell.CellStyle = cellStyle;
iCellIndex++;
}
iCellIndex = 0;
iRowIndex++;
}
//自适应列宽度
for (int i = 0; i < icolIndex; i++)
{
sheet.AutoSizeColumn(i);
}
}
if (System.IO.File.Exists(strExcelFileName))
System.IO.File.Delete(strExcelFileName);
//写Excel
FileStream file = new FileStream(strExcelFileName, FileMode.Create);
workbook.Write(file);
file.Flush();
file.Close();
}
catch (Exception ex)
{
throw;
}
finally { workbook = null; }
}
/// <summary>
/// 生成Excel文件
/// </summary>
/// <param name="dt">数据源</param>
/// <param name="strExcelFileName">文件名</param>
/// <param name="isWebDownload">如果是web下载strExcelFileName则仅仅是文件名而非路径名</param>
public static void GridToExcelByNPOI(DataTable dt, string strExcelFileName)
{
HSSFWorkbook workbook = new HSSFWorkbook();
try
{
int sheetIndex = 0;
int dataIndex = 0;
ICellStyle HeadercellStyle = workbook.CreateCellStyle();
HeadercellStyle.BorderBottom = BorderStyle.Thin;
HeadercellStyle.BorderLeft = BorderStyle.Thin;
HeadercellStyle.BorderRight = BorderStyle.Thin;
HeadercellStyle.BorderTop = BorderStyle.Thin;
HeadercellStyle.Alignment = HorizontalAlignment.Center;
ICellStyle cellStyle = workbook.CreateCellStyle();
//为避免日期格式被Excel自动替换所以设定 format 为 『@』 表示一率当成text來看
cellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("@");
cellStyle.BorderBottom = BorderStyle.Thin;
cellStyle.BorderLeft = BorderStyle.Thin;
cellStyle.BorderRight = BorderStyle.Thin;
cellStyle.BorderTop = BorderStyle.Thin;
//字体
IFont headerfont = workbook.CreateFont();
headerfont.Boldweight = (short)FontBoldWeight.Bold;
HeadercellStyle.SetFont(headerfont);
IFont cellfont = workbook.CreateFont();
cellfont.Boldweight = (short)FontBoldWeight.Normal;
cellStyle.SetFont(cellfont);
while (dataIndex < dt.Rows.Count)
{
sheetIndex++;
ISheet sheet = workbook.CreateSheet($"Sheet{sheetIndex}");
//用column name 作为列名
int icolIndex = 0;
IRow headerRow = sheet.CreateRow(0);
foreach (DataColumn item in dt.Columns)
{
ICell cell = headerRow.CreateCell(icolIndex);
cell.SetCellValue(item.ColumnName);
cell.CellStyle = HeadercellStyle;
icolIndex++;
}
//建立内容行
int iRowIndex = 1;
int iCellIndex = 0;
for (int count = 0; dataIndex < dt.Rows.Count; dataIndex++, count++)
{
if (count >= 65000)
break;
DataRow Rowitem = dt.Rows[dataIndex];
IRow DataRow = sheet.CreateRow(iRowIndex);
foreach (DataColumn Colitem in dt.Columns)
{
ICell cell = DataRow.CreateCell(iCellIndex);
cell.SetCellValue(Rowitem[Colitem].ToString());
cell.CellStyle = cellStyle;
iCellIndex++;
}
iCellIndex = 0;
iRowIndex++;
}
//自适应列宽度
for (int i = 0; i < icolIndex; i++)
{
sheet.AutoSizeColumn(i);
}
}
//如果没有传路径,就生成用于web下载的流
//if (isWebDownload)
//{
// using (MemoryStream ms = new MemoryStream())
// {
// workbook.Write(ms);
// ms.Flush();
// ms.Position = 0;
// byte[] bytes = ms.GetBuffer();
// HttpContext.GetUserIp();
// string UserAgent = WebRequest.DefaultWebProxy.
// .g
// Request.UserAgent
// string UserAgent = HttpContext.Current.Request.ServerVariables["http_user_agent"].ToLower();
// string filename = strExcelFileName + ".xls";
// if (UserAgent.IndexOf("firefox") <= 0)//火狐,文件名不需要编码
// {
// filename = HttpUtility.UrlEncode(filename, Encoding.UTF8);
// }
// HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";
// HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=" + filename);
// HttpContext.Current.Response.BinaryWrite(bytes);
// HttpContext.Current.Response.End();
// }
//}
//else
{
if (System.IO.File.Exists(strExcelFileName))
System.IO.File.Delete(strExcelFileName);
//写Excel
FileStream file = new FileStream(strExcelFileName, FileMode.Create);
workbook.Write(file);
file.Flush();
file.Close();
}
}
catch (Exception ex)
{
throw;
}
finally { workbook = null; }
}
/// <summary>
/// 将DataTable数据导入到excel中
/// </summary>
/// <param name="data">要导入的数据</param>
/// <param name="isColumnWritten">DataTable的列名是否要导入</param>
/// <param name="fileName">导出文件名全路径</param>
/// <param name="sheetName">要导入的excel的sheet的名称</param>
/// <returns>导入数据行数(包含列名那一行)</returns>
public static int DataTableToExcel(DataTable data, string fileName, bool isColumnWritten, string sheetName = "Sheet1")
{
int i = 0;
int j = 0;
int count = 0;
ISheet sheet = null;
IWorkbook workbook = null;
string myDir = Path.GetDirectoryName(fileName);
//判断文件夹是否存在
if (!Directory.Exists(myDir))
{
//文件夹不存在则创建该文件夹
if (myDir != null)
Directory.CreateDirectory(myDir);
}
using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite))
{
if (fileName.IndexOf(".xlsx", StringComparison.Ordinal) > 0) // 2007版本
workbook = new XSSFWorkbook();
else if (fileName.IndexOf(".xls", StringComparison.Ordinal) > 0) // 2003版本
workbook = new HSSFWorkbook();
try
{
if (workbook != null)
{
sheet = workbook.CreateSheet(sheetName);
}
else
{
return -1;
}
if (isColumnWritten == true) //写入DataTable的列名
{
IRow row = sheet.CreateRow(0);
for (j = 0; j < data.Columns.Count; ++j)
{
row.CreateCell(j).SetCellValue(data.Columns[j].ColumnName);
}
count = 1;
}
else
{
count = 0;
}
for (i = 0; i < data.Rows.Count; ++i)
{
IRow row = sheet.CreateRow(count);
for (j = 0; j < data.Columns.Count; ++j)
{
row.CreateCell(j).SetCellValue(data.Rows[i][j].ToString());
}
++count;
}
workbook.Write(fs); //写入到excel
workbook.Close();
return count;
}
catch (Exception ex)
{
workbook?.Close();
throw new Exception(ex.Message);
}
}
}
public static DataTable ExcelToDataTable(string fileName, string sheetName, bool isFirstRowColumn, Dictionary<string, string[]> columnTemplate = null, string[] requireColumns = null, int? maxRows = null)
{
ISheet sheet = null;
DataTable data = new DataTable();
IWorkbook workbook = null;
int startRow = 0;
try
{
using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
try
{
workbook = new XSSFWorkbook(fs);
}
catch
{
workbook = new HSSFWorkbook(fs);
}
}
if (sheetName != null)
{
if (workbook != null)
{
sheet = workbook.GetSheet(sheetName);
if (sheet == null) //如果没有找到指定的sheetName对应的sheet则尝试获取第一个sheet
{
sheet = workbook.GetSheetAt(0);
}
}
}
else
{
if (workbook != null) sheet = workbook.GetSheetAt(0);
}
if (sheet != null)
{
IRow firstRow = sheet.GetRow(0);
int cellCount = firstRow.LastCellNum; //一行最后一个cell的编号 即总的列数
if (isFirstRowColumn)
{
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
{
ICell cell = firstRow.GetCell(i);
string cellValue = cell?.StringCellValue?.Trim();
if (!string.IsNullOrWhiteSpace(cellValue))//列名正确性验证
{
if (columnTemplate != null && !columnTemplate.First().Value.Contains(cellValue))
throw new Exception($"{columnTemplate.First().Key}不存在列名:{cellValue}!正确列名为:{string.Join(",", columnTemplate.First().Value)}");
DataColumn column = new DataColumn(cellValue);
data.Columns.Add(column);
}
}
startRow = sheet.FirstRowNum + 1;
}
else
{
startRow = sheet.FirstRowNum;
}
//最后一列的标号
int rowCount = sheet.LastRowNum;
if (maxRows != null)
{
if (rowCount > maxRows)
throw new Exception($"请拆分文件,一次最多支持{maxRows}条数据");
}
for (int i = startRow; i <= rowCount; ++i)
{
IRow row = sheet.GetRow(i);
if (row == null || row.Cells.Count == 0 || row.FirstCellNum == -1 || row.Cells.All(d => d.CellType == CellType.Blank)) continue; //没有数据的行默认是null       
DataRow dataRow = data.NewRow();
for (int j = row.FirstCellNum; j < cellCount; ++j)
{
var cellvalue = row.GetCell(j);
if (cellvalue == null || (cellvalue.ToString().Trim() == "0"))
{
if (requireColumns != null && requireColumns.Contains(data.Columns[j].ColumnName))
{
//throw new Exception($"第{i}行,第{j}列,【{data.Columns[j].ColumnName}】不能为空或0必须填写");
}
}
if (cellvalue != null) dataRow[j] = cellvalue.ToString().Trim();
else
{
dataRow[j] = ""; //string.Empty;
}
}
data.Rows.Add(dataRow);
}
}
workbook?.Close();
return data;
}
catch (Exception ex)
{
workbook?.Close();
throw new Exception(ex.Message);
}
}
/// <summary>
/// 将excel中的数据导入到DataTable中
/// </summary>
/// <param name="sheetName">excel工作薄sheet的名称</param>
/// <param name="isFirstRowColumn">第一行是否是DataTable的列名</param>
/// <param name="fileName">第一行是否是DataTable的列名</param>
/// <param name="startRow">开始行数</param>
/// <param name="startData">开始收集数据行数</param>
/// <returns>返回的DataTable</returns>
public static DataTable ExcelToDataTable(string sheetName, bool isFirstRowColumn, string fileName, int startRow = 0, int startData = 1)
{
ISheet sheet = null;
DataTable data = new DataTable();
try
{
IWorkbook workbook = null;
FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
if (fileName.IndexOf(".xlsx") > 0 || fileName.IndexOf(".xlsm") > 0) // 2007版本
workbook = new XSSFWorkbook(fs);
else if (fileName.IndexOf(".xls") > 0) // 2003版本
workbook = new HSSFWorkbook(fs);
if (sheetName != null)
{
sheet = workbook.GetSheet(sheetName);
if (sheet == null) //如果没有找到指定的sheetName对应的sheet则尝试获取第一个sheet
{
sheet = workbook.GetSheetAt(0);
}
}
else
{
sheet = workbook.GetSheetAt(0);
}
if (sheet != null)
{
IRow firstRow = sheet.GetRow(startRow);
int cellCount = firstRow.LastCellNum; //一行最后一个cell的编号 即总的列数
if (isFirstRowColumn)
{
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
{
ICell cell = firstRow.GetCell(i);
if (cell != null)
{
string cellValue = cell.StringCellValue.Replace(" ", "").Replace("?", "");
if (cellValue != null)
{
if (data.Columns[cellValue] != null)
{
cellValue += i;
}
DataColumn column = new DataColumn(cellValue);
data.Columns.Add(column);
}
}
}
startRow += sheet.FirstRowNum + startData;
}
else
{
startRow = sheet.FirstRowNum;
}
//最后一列的标号
int rowCount = sheet.LastRowNum;
for (int i = startRow; i <= rowCount; ++i)
{
IRow row = sheet.GetRow(i);
if (row == null) continue; //没有数据的行默认是null       
DataRow dataRow = data.NewRow();
for (int j = row.FirstCellNum; j < cellCount; ++j)
{
if (row.GetCell(j) != null) //同理没有数据的单元格都默认是null
dataRow[j] = row.GetCell(j).ToString();
}
data.Rows.Add(dataRow);
}
}
return data;
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
return null;
}
}
/// <summary>
/// DataTable转成List
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dt"></param>
/// <returns></returns>
public static List<T> ToDataList<T>(this DataTable dt)
{
var list = new List<T>();
var plist = new List<PropertyInfo>(typeof(T).GetProperties());
foreach (DataRow item in dt.Rows)
{
T s = Activator.CreateInstance<T>();
for (int i = 0; i < dt.Columns.Count; i++)
{
PropertyInfo info = plist.Find(p => p.Name == dt.Columns[i].ColumnName);
if (info != null)
{
try
{
if (!Convert.IsDBNull(item[i]))
{
object v = null;
if (info.PropertyType.ToString().Contains("System.Nullable"))
{
v = Convert.ChangeType(item[i], Nullable.GetUnderlyingType(info.PropertyType));
}
else
{
v = Convert.ChangeType(item[i], info.PropertyType);
}
info.SetValue(s, v, null);
}
}
catch (Exception ex)
{
throw new Exception("字段[" + info.Name + "]转换出错," + ex.Message);
}
}
}
list.Add(s);
}
return list;
}
/// <summary>
/// DataTable转成Dto
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dt"></param>
/// <returns></returns>
public static T ToDataDto<T>(this DataTable dt)
{
T s = Activator.CreateInstance<T>();
if (dt == null || dt.Rows.Count == 0)
{
return s;
}
var plist = new List<PropertyInfo>(typeof(T).GetProperties());
for (int i = 0; i < dt.Columns.Count; i++)
{
PropertyInfo info = plist.Find(p => p.Name == dt.Columns[i].ColumnName);
if (info != null)
{
try
{
if (!Convert.IsDBNull(dt.Rows[0][i]))
{
object v = null;
if (info.PropertyType.ToString().Contains("System.Nullable"))
{
v = Convert.ChangeType(dt.Rows[0][i], Nullable.GetUnderlyingType(info.PropertyType));
}
else
{
v = Convert.ChangeType(dt.Rows[0][i], info.PropertyType);
}
info.SetValue(s, v, null);
}
}
catch (Exception ex)
{
throw new Exception("字段[" + info.Name + "]转换出错," + ex.Message);
}
}
}
return s;
}
/// <summary>
/// list转化为table
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="entitys"></param>
/// <returns></returns>
public static DataTable ListToDataTable<T>(List<T> entitys)
{
//检查实体集合不能为空
if (entitys == null || entitys.Count < 1)
{
return new DataTable();
}
//取出第一个实体的所有Propertie
Type entityType = entitys[0].GetType();
PropertyInfo[] entityProperties = entityType.GetProperties();
//生成DataTable的structure
//生产代码中应将生成的DataTable结构Cache起来此处略
DataTable dt = new DataTable("dt");
for (int i = 0; i < entityProperties.Length; i++)
{
//dt.Columns.Add(entityProperties[i].Name, entityProperties[i].PropertyType);
dt.Columns.Add(entityProperties[i].Name);
}
//将所有entity添加到DataTable中
foreach (object entity in entitys)
{
//检查所有的的实体都为同一类型
if (entity.GetType() != entityType)
{
throw new Exception("要转换的集合元素类型不一致");
}
DataRow dr = dt.NewRow();
dt.Rows.Add(dr);
int rowCount = dt.Rows.Count;
object[] entityValues = new object[entityProperties.Length];
for (int i = 0; i < entityProperties.Length; i++)
{
entityValues[i] = entityProperties[i].GetValue(entity, null);
//给当前行的每列加数据
dt.Rows[rowCount][i] = entityValues[i];
}
}
return dt;
}
}
}

101
code/DG.Tool/HttpHelper.cs Normal file
View File

@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace DG.Tool
{
public static class HttpHelper
{
public static string PostAjaxData(string url, string param, Encoding encoding)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "application/json;charet=utf-8";
request.Headers.Add("dataType", "json");
request.Headers.Add("type", "post");
byte[] data = encoding.GetBytes(param);
using (BinaryWriter reqStream = new BinaryWriter(request.GetRequestStream()))
{
reqStream.Write(data, 0, data.Length);
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
StreamReader reader = new StreamReader(response.GetResponseStream(), encoding);
string result = reader.ReadToEnd();
return result;
}
}
public static T PostAjaxData<T>(string url, string param, Encoding encoding)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "application/json;charet=utf-8";
request.Headers.Add("dataType", "json");
request.Headers.Add("type", "post");
byte[] data = encoding.GetBytes(param);
using (BinaryWriter reqStream = new BinaryWriter(request.GetRequestStream()))
{
reqStream.Write(data, 0, data.Length);
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
StreamReader reader = new StreamReader(response.GetResponseStream(), encoding);
string result = reader.ReadToEnd();
return JsonHelper.FromJson<T>(result);
}
}
/// <summary>
/// 获取数据
/// </summary>
/// <param name="url"></param>
/// <param name="encoding"></param>
/// <returns></returns>
public static string GetData(string Url, string RequestPara, Encoding encoding)
{
RequestPara = RequestPara.IndexOf('?') > -1 ? (RequestPara) : ("?" + RequestPara);
WebRequest hr = HttpWebRequest.Create(Url + RequestPara);
byte[] buf = encoding.GetBytes(RequestPara);
hr.Method = "GET";
System.Net.WebResponse response = hr.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8"));
string ReturnVal = reader.ReadToEnd();
reader.Close();
response.Close();
return ReturnVal;
}
/// <summary>
/// 获取数据
/// </summary>
/// <param name="url"></param>
/// <param name="encoding"></param>
/// <returns></returns>
public static T GetData<T>(string Url, string RequestPara, Encoding encoding)
{
RequestPara = RequestPara.IndexOf('?') > -1 ? (RequestPara) : ("?" + RequestPara);
WebRequest hr = HttpWebRequest.Create(Url + RequestPara);
byte[] buf = encoding.GetBytes(RequestPara);
hr.Method = "GET";
System.Net.WebResponse response = hr.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8"));
string ReturnVal = reader.ReadToEnd();
reader.Close();
response.Close();
return JsonHelper.FromJson<T>(ReturnVal);
}
}
}

View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;
using System.Threading.Tasks;
namespace DG.Tool
{
public static class JsonHelper
{
public static JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions()
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
/// <summary>
/// 类对像转换成json格式
/// </summary>
/// <returns></returns>
public static string ToJson(this object t)
{
return JsonSerializer.Serialize(t, jsonSerializerOptions);
}
/// <summary>
/// 类转化为json
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <returns></returns>
public static string ToJson<T>(this T t)
{
return JsonSerializer.Serialize(t, jsonSerializerOptions);
}
public static T FromJson<T>(string t)
{
return JsonSerializer.Deserialize<T>(t, jsonSerializerOptions);
}
}
}

434
code/DG.Tool/PhoneHelper.cs Normal file
View File

@ -0,0 +1,434 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace DG.Tool
{
public class PhoneHelper
{
/// <summary>
/// 格式化以手机号码作为用户名的username
/// </summary>
/// <param name="username"></param>
/// <returns></returns>
public static string FormatPhoneUserName(string username)
{
string newUsername = GetFormatPhoneUserName(username);//手机号码格式化
//newUsername = FormatUserName(newUsername);//用户名格式化
//return newUsername;
return newUsername;
}
/// <summary>
/// 格式化以手机号码作为用户名的username(存在多个用户名)
/// </summary>
/// <param name="username"></param>
/// <returns></returns>
public static string FormatPhoneMoreUserName(string username)
{
string newUsername = GetFormatPhoneUserName(username);//手机号码格式化
if (string.IsNullOrEmpty(newUsername))
return newUsername;
string userNames = string.Empty;
foreach (var item in newUsername.Split(','))
{
userNames += FormatUserName(item) + ",";//用户名格式化
}
userNames = userNames.Substring(0, userNames.Length - 1);
return userNames;
}
/// <summary>
/// 格式化以手机号码作为用户名的username
/// </summary>
/// <param name="username">需要改动的用户名</param>
/// <param name="ntype"></param>
/// <returns></returns>
public static string FormatPhoneUserNameContent(string username)
{
string newUsername = GetFormatPhoneUserName(username);//手机号码格式化
return newUsername;
}
/// <summary>
/// 格式化以手机号码作为用户名的username
/// </summary>
/// <param name="username">需要改动的用户名</param>
/// <param name="username">需要改动的用户名</param>
/// <param name="ntype"></param>
/// <returns></returns>
public static string FormatPhoneUserNameContent(string username, string subTypeCode)
{
string newUsername = GetFormatPhoneUserName(username);//手机号码格式化
if (subTypeCode != "SMS_ResetPwd")
return newUsername;
//创建对象
Regex regex = new Regex("账号(?<value>[\\s\\S]*?)的", RegexOptions.Multiline);
//匹配
MatchCollection match = regex.Matches(username);
//取得第一个值
if (match.Count > 0)
{
string value = match[0].Groups["value"].ToString();
string newValue = FormatUserName(value);
newUsername = newUsername.Replace(string.Format("账号{0}的", value), string.Format("账号{0}的", newValue));
}
//创建对象
Regex regex2 = new Regex("帐号(?<value>[\\s\\S]*?)", RegexOptions.Multiline);
//匹配
MatchCollection match2 = regex2.Matches(newUsername);
//取得第一个值
if (match2.Count > 0)
{
string value1 = match2[0].Groups["value"].ToString();
string newValue1 = FormatUserName(value1);
newUsername = newUsername.Replace(string.Format("帐号{0}", value1), string.Format("帐号{0}", newValue1));
}
return newUsername;
}
/// <summary>
/// 用户名
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
public static string FormatUserName(string userName)
{
/*
1
25test1t****
35214*test123te****3
*/
if (string.IsNullOrEmpty(userName))
return "";
if (userName == "未设置")
return userName;
string newUserName = userName;
//判断 是否已经在手机号屏蔽的时候屏蔽过一次
if (userName.IndexOf("*****") > -1)
{
return newUserName;
}
int nameLth = newUserName.Length;
if (nameLth <= 5)
{
newUserName = newUserName.Substring(0, 1) + GetAsterisk(nameLth - 1);
}
else
{
int startIndex = nameLth / 2;
startIndex = startIndex - 1;
newUserName = newUserName.Substring(0, startIndex) + "****" + newUserName.Substring(startIndex + 4, nameLth - startIndex - 4);
}
return newUserName;
}
/// <summary>
/// 格式化以手机号码作为用户名的username
/// </summary>
/// <param name="username"></param>
/// <returns></returns>
private static string GetFormatPhoneUserName(string username)
{
string newUsername = username;
if (string.IsNullOrWhiteSpace(newUsername))
return newUsername;
while (ContainMobile(newUsername))
{
string phone = GetMobile(newUsername);
if (string.IsNullOrWhiteSpace(phone))
break;
newUsername = newUsername.Replace(phone, (phone.Substring(0, 3) + "*****" + phone.Substring(8, 3)));
}
return newUsername;
}
#region
/// <summary>
/// 00852+8位是香港的电话
/// </summary>
/// <param name="number"></param>
/// <returns></returns>
public static bool ChekMobile(string number)
{
string rgs = @"^(13|14|15|16|17|18|19|0085)\d{9}$";
Regex reg = new Regex(rgs);
return reg.IsMatch(number);
}
/// <summary>
/// 检查是否包含手机号码
/// </summary>
/// <param name="number"></param>
/// <returns></returns>
public static bool ContainMobile(string number)
{
string rgs = @".*(13|14|15|16|17|18|19)\d{9}.*";
Regex reg = new Regex(rgs);
return reg.IsMatch(number);
}
/// <summary>
/// 从文本中返回号码字符串
/// </summary>
/// <param name="txt"></param>
/// <returns></returns>
public static string GetMobile(string txt)
{
string rgs = @"(12|13|14|15|16|17|18|19)\d{9}";
string result = Regex.Match(txt, rgs).Value;
return result;
}
public static bool CheckIsNum(string txt)
{
string rgs = "^\\d{6,16}$";
Regex reg = new Regex(rgs);
return reg.IsMatch(txt);
}
public static bool IsNum(string txt)
{
string rgs = "^\\d+$";
Regex reg = new Regex(rgs);
return reg.IsMatch(txt);
}
public static bool IsChinese(string txt)
{
string rgs = "[\u4E00-\u9FA5]";
Regex reg = new Regex(rgs);
return reg.IsMatch(txt);
}
public static bool IsNumOrStr(string txt)
{
string rgs = "^[A-Za-z0-9]+$";
Regex reg = new Regex(rgs);
return reg.IsMatch(txt);
}
#endregion
/// <summary>
/// 获取星号
/// </summary>
/// <param name="number">需要返回的星号数量</param>
/// <returns></returns>
private static string GetAsterisk(int number)
{
string xingHao = string.Empty;
if (number == 0)
return xingHao;
for (int i = 0; i < number; i++)
{
xingHao += "*";
}
return xingHao;
}
#region 8*
/// <summary>
/// 超过8个数字的数据替换成*
/// </summary>
/// <param name="txt"></param>
/// <returns></returns>
public static string Replace8Number(object txt)
{
if (txt == null)
{
return "";
}
if (string.IsNullOrEmpty(txt.ToString()))
{
return "";
}
var content = txt.ToString();
//普通数字
string numReg = @"\d+";
var result = Regex.Matches(content, numReg).Cast<Match>().Select(t => t.Value).ToList();
if (result != null && result.Count > 0)
{
foreach (var s in result)
{
if (s.Length > 7)
{
content = content.Replace(s, GetHideNumber(s));
}
}
}
//下标数字
numReg = @"[₁,₂,₃,₄,₅,₆,₇,₈,₉,₀]{8,}";
result = Regex.Matches(content, numReg).Cast<Match>().Select(t => t.Value).ToList();
if (result != null && result.Count > 0)
{
foreach (var s in result)
{
if (s.Length > 7)
{
content = content.Replace(s, GetHideDownNumber(s));
}
}
}
//上标数字
numReg = @"[¹,²,³,⁴,⁵,⁶,⁷,⁸,⁹,⁰]{8,}";
result = Regex.Matches(content, numReg).Cast<Match>().Select(t => t.Value).ToList();
if (result != null && result.Count > 0)
{
foreach (var s in result)
{
if (s.Length > 7)
{
content = content.Replace(s, GetHideUpNumber(s));
}
}
}
//全角数字
numReg = @"[,,,,,,,,,]{8,}";
result = Regex.Matches(content, numReg).Cast<Match>().Select(t => t.Value).ToList();
if (result != null && result.Count > 0)
{
foreach (var s in result)
{
if (s.Length > 7)
{
content = content.Replace(s, GetHideRoundNumber(s));
}
}
}
return content;
}
//全角数字屏蔽
public static string GetHideRoundNumber(string phoneNo)
{
string rexstr = "";
string xinghao = "";
if (phoneNo.Length == 8)
{
rexstr = @"([,,,,,,,,,]{2})([,,,,,,,,,]{4})([,,,,,,,,,]{2})";
xinghao = "****";
}
else if (phoneNo.Length == 9)
{
rexstr = @"([,,,,,,,,,]{2})([,,,,,,,,,]{5})([,,,,,,,,,]{2})";
xinghao = "*****";
}
else if (phoneNo.Length == 10)
{
rexstr = @"([,,,,,,,,,]{2})([,,,,,,,,,]{5})([,,,,,,,,,]{3})";
xinghao = "*****";
}
else
{
rexstr = @"([,,,,,,,,,]{3})([,,,,,,,,,]{" + (phoneNo.Length - 6) + @"})([,,,,,,,,,]{3})";
for (int i = 0; i < (phoneNo.Length - 6); i++)
{
xinghao += "*";
}
}
Regex re = new Regex(rexstr, RegexOptions.None);
phoneNo = re.Replace(phoneNo, "$1" + xinghao + "$3");
return phoneNo;
}
//上标数字屏蔽
public static string GetHideUpNumber(string phoneNo)
{
string rexstr = "";
string xinghao = "";
if (phoneNo.Length == 8)
{
rexstr = @"([¹,²,³,⁴,⁵,⁶,⁷,⁸,⁹,⁰,]{2})([¹,²,³,⁴,⁵,⁶,⁷,⁸,⁹,⁰,]{4})([¹,²,³,⁴,⁵,⁶,⁷,⁸,⁹,⁰,]{2})";
xinghao = "****";
}
else if (phoneNo.Length == 9)
{
rexstr = @"([¹,²,³,⁴,⁵,⁶,⁷,⁸,⁹,⁰,]{2})([¹,²,³,⁴,⁵,⁶,⁷,⁸,⁹,⁰,]{5})([¹,²,³,⁴,⁵,⁶,⁷,⁸,⁹,⁰,]{2})";
xinghao = "*****";
}
else if (phoneNo.Length == 10)
{
rexstr = @"([¹,²,³,⁴,⁵,⁶,⁷,⁸,⁹,⁰,]{2})([¹,²,³,⁴,⁵,⁶,⁷,⁸,⁹,⁰,]{5})([¹,²,³,⁴,⁵,⁶,⁷,⁸,⁹,⁰,]{3})";
xinghao = "*****";
}
else
{
rexstr = @"([¹,²,³,⁴,⁵,⁶,⁷,⁸,⁹,⁰,]{3})([¹,²,³,⁴,⁵,⁶,⁷,⁸,⁹,⁰,]{" + (phoneNo.Length - 6) + @"})([¹,²,³,⁴,⁵,⁶,⁷,⁸,⁹,⁰,]{3})";
for (int i = 0; i < (phoneNo.Length - 6); i++)
{
xinghao += "*";
}
}
Regex re = new Regex(rexstr, RegexOptions.None);
phoneNo = re.Replace(phoneNo, "$1" + xinghao + "$3");
return phoneNo;
}
//下标数字屏蔽
public static string GetHideDownNumber(string phoneNo)
{
string rexstr = "";
string xinghao = "";
if (phoneNo.Length == 8)
{
rexstr = @"([₁,₂,₃,₄,₅,₆,₇,₈,₉,₀]{2})([₁,₂,₃,₄,₅,₆,₇,₈,₉,₀]{4})([₁,₂,₃,₄,₅,₆,₇,₈,₉,₀]{2})";
xinghao = "****";
}
else if (phoneNo.Length == 9)
{
rexstr = @"([₁,₂,₃,₄,₅,₆,₇,₈,₉,₀]{2})([₁,₂,₃,₄,₅,₆,₇,₈,₉,₀]{5})([₁,₂,₃,₄,₅,₆,₇,₈,₉,₀]{2})";
xinghao = "*****";
}
else if (phoneNo.Length == 10)
{
rexstr = @"([₁,₂,₃,₄,₅,₆,₇,₈,₉,₀]{2})([₁,₂,₃,₄,₅,₆,₇,₈,₉,₀]{5})([₁,₂,₃,₄,₅,₆,₇,₈,₉,₀]{3})";
xinghao = "*****";
}
else
{
rexstr = @"([₁,₂,₃,₄,₅,₆,₇,₈,₉,₀]{3})([₁,₂,₃,₄,₅,₆,₇,₈,₉,₀]{" + (phoneNo.Length - 6) + @"})([₁,₂,₃,₄,₅,₆,₇,₈,₉,₀]{3})";
for (int i = 0; i < (phoneNo.Length - 6); i++)
{
xinghao += "*";
}
}
Regex re = new Regex(rexstr, RegexOptions.None);
phoneNo = re.Replace(phoneNo, "$1" + xinghao + "$3");
return phoneNo;
}
//数字屏蔽
public static string GetHideNumber(string phoneNo)
{
string rexstr = "";
string xinghao = "";
if (phoneNo.Length == 8)
{
rexstr = @"(\d{2})(\d{4})(\d{2})";
xinghao = "****";
}
else if (phoneNo.Length == 9)
{
rexstr = @"(\d{2})(\d{5})(\d{2})";
xinghao = "*****";
}
else if (phoneNo.Length == 10)
{
rexstr = @"(\d{2})(\d{5})(\d{3})";
xinghao = "*****";
}
else
{
rexstr = @"(\d{3})(\d{" + (phoneNo.Length - 6) + @"})(\d{3})";
for (int i = 0; i < (phoneNo.Length - 6); i++)
{
xinghao += "*";
}
}
Regex re = new Regex(rexstr, RegexOptions.None);
phoneNo = re.Replace(phoneNo, "$1" + xinghao + "$3");
return phoneNo;
}
#endregion
}
}

259
code/DG.Tool/ResUtil.cs Normal file
View File

@ -0,0 +1,259 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace DG.Tool
{
public static class ResUtil
{
//生成resid
public static string CreateResId(string number)
{
number = number.Replace("+86", "");
if (number.StartsWith("01") && number.Length == 12)
{
number = number.Substring(1);
}
//1、正则表达式提取数字串值
number = Regex.Replace(number, @"[^\d.\d]", "", RegexOptions.IgnoreCase);
//*******开始resid算法******************//
bool ismobile = ChekMobile(number) || ChekMobile(number.TrimStart('0'));
if (ismobile)
number = number.TrimStart('0');
string bkn_ms_52 = InReversibleStr(number, ismobile);
string kn_ms_6 = ReversibleStr(number);
string resId = MixResID(bkn_ms_52, kn_ms_6, number, ismobile);
return resId;
}
/// <summary>
/// 00852+8位是香港的电话
/// </summary>
/// <param name="number"></param>
/// <returns></returns>
public static bool ChekMobile(string number)
{
string rgs = @"^(13|14|15|16|17|18|19|0085)\d{9}$";
Regex reg = new Regex(rgs);
return reg.IsMatch(number);
}
/// <summary>
/// 检查是否包含手机号码
/// </summary>
/// <param name="number"></param>
/// <returns></returns>
public static bool ContainMobile(string number)
{
string rgs = @".*(13|14|15|16|17|18|19)\d{9}.*";
Regex reg = new Regex(rgs);
return reg.IsMatch(number);
}
public static bool CheckIsNum(string txt)
{
string rgs = "^\\d{6,16}$";
Regex reg = new Regex(rgs);
return reg.IsMatch(txt);
}
public static string UserMd5(string str)
{
var cl = str;
var result = string.Empty;
var md5 = MD5.Create();//实例化一个md5对像
// 加密后是一个字节类型的数组这里要注意编码UTF8/Unicode等的选择 
var s = md5.ComputeHash(Encoding.UTF8.GetBytes(cl));
// 通过使用循环,将字节类型的数组转换为字符串,此字符串是常规字符格式化所得
for (int i = 0; i < s.Length; i++)
{
// 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母如果使用大写X则格式后的字符是大写字符
result = result + s[i].ToString("x2");
}
return result;
}
public static string NumberFormat(string number)
{
if (string.IsNullOrEmpty(number) || number.Length <= 6)
{
return number;
}
return number.Substring(0, 3) + new string('*', number.Length - 6) + number.Substring(number.Length - 3);
}
/// <summary>
/// 不可逆密码串
/// </summary>
/// <param name="number"></param>
/// <returns></returns>
private static string InReversibleStr(string number, bool ismobile)
{
//11位手机前补'x'、不足12位的号码前补'0超过12位的取后12位
string rnum = ismobile ? "x" + number : number;
rnum = rnum.PadLeft(12, '0');
rnum = rnum.Substring(rnum.Length - 12);
string strms = EncryptMD5(rnum + "@no_zuo_no_die@").Substring(10, 13);
Int64 si = Convert.ToInt64(strms, 16);
return Convert.ToString(si, 2).PadLeft(52, '0');
}
/// <summary>
/// md5加密
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public static string EncryptMD5(string input)
{
if (string.IsNullOrEmpty(input))
{
return string.Empty;
}
MD5 md5 = MD5.Create();
byte[] data = md5.ComputeHash(Encoding.Default.GetBytes(input));
// Create a new Stringbuilder to collect the bytes
// and create a string.
StringBuilder sBuilder = new();
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
return sBuilder.ToString();
}
/// <summary>
/// 生成可逆密码串
/// </summary>
/// <param name="number"></param>
/// <returns></returns>
private static string ReversibleStr(string number)
{
//2位可逆
int H2 = Int32.Parse(number.Substring(number.Length - 2)) % 64;
string strms = Convert.ToString(Convert.ToInt64(H2), 2).PadLeft(6, '0');
return MixKN_MS(strms, true);
}
private static string MixResID(string bkn_ms, string kn_ms, string number, bool ismobile)
{
StringBuilder sb = new StringBuilder();
int i = 0;
for (; i < kn_ms.Length; i++)
{
sb.Append(bkn_ms.Substring(i * 2, 2));
sb.Append(kn_ms.Substring(i, 1));
}
sb.Append(bkn_ms.Substring(i * 2));
sb.Append(ismobile ? "1" : "0");
return Convert2TO10(sb.ToString()).ToString().PadLeft(18, '0');
}
private static string MixKN_MS(string kn_ms, bool bMix)
{
int iMove = 2;
StringBuilder sb = new StringBuilder();
if (bMix)
{
kn_ms = kn_ms.Substring(kn_ms.Length - iMove) + kn_ms.Substring(0, kn_ms.Length - iMove);
}
for (int i = 0; i < kn_ms.Length / 2; i++)
{
sb.Append(kn_ms[i * 2 + 1]);
sb.Append(kn_ms[i * 2]);
}
kn_ms = sb.ToString();
if (!bMix)
{
kn_ms = kn_ms.Substring(iMove) + kn_ms.Substring(0, iMove);
}
return kn_ms;
}
/// <summary>
/// 返回后二位的手机号码串
/// </summary>
/// <param name="resId"></param>
/// <returns></returns>
public static string Reve_ms(string resId)
{
string code = Convert10TO2(Convert.ToDecimal(resId)).PadLeft(59, '0');
code = code.Substring(code.Length - 59);
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 6; i++)
{
sb.Append(code[i * 3 - 1]);
}
code = MixKN_MS(sb.ToString(), false);
code = Convert.ToInt32(code, 2).ToString().PadLeft(2, '0');
return "*********" + code;
}
/// <summary>
/// 二进制转十进制
/// </summary>
/// <param name="resid"></param>
/// <returns></returns>
public static decimal Convert2TO10(string resid)
{
decimal residNum = 0;
string str = resid;
for (int i = 0, j = resid.Length - 1; i < resid.Length; i++, j--)
{
string bitebag = resid.Substring(j, 1);
decimal t = Convert.ToInt32(bitebag) * Pow(i);
residNum = residNum + t;
}
return residNum;
}
/// <summary>
/// 十进制转二进制
/// </summary>
/// <param name="resudnum"></param>
/// <returns></returns>
public static string Convert10TO2(decimal resudnum)
{
string str = string.Empty;
while (resudnum > 0)
{
int y = Convert.ToInt32(resudnum % Convert.ToDecimal(2));
resudnum = Math.Floor(resudnum / Convert.ToDecimal(2));
str = y.ToString() + str;
}
return str;
}
public static decimal Pow(int y)
{
decimal pow = 1;
if (y == 0)
{
pow = 1;
}
else if (y == 1)
{
pow = 2;
}
else
{
pow = 2;
while (y > 1)
{
pow = pow * 2;
y--;
}
}
return pow;
}
}
}

View File

@ -0,0 +1,143 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace DG.Tool
{
public static class SecurityHelper
{
/// <summary>
/// 加密
/// </summary>
/// <param name="ciphertext"></param>
/// <param name="accessKey"></param>
/// <returns></returns>
public static string EncyptData(string ciphertext, string accessKey)
{
SymmetricAlgorithm des = new DESCryptoServiceProvider();
Encoding utf = new UTF8Encoding();
byte[] key = utf.GetBytes(accessKey);
byte[] iv = { 0x75, 0x70, 0x63, 0x68, 0x69, 0x6e, 0x61, 0x31 };
ICryptoTransform encryptor = des.CreateEncryptor(key, iv);
byte[] data = utf.GetBytes(ciphertext);
byte[] encData = encryptor.TransformFinalBlock(data, 0, data.Length);
return Convert.ToBase64String(encData);
}
/// <summary>
/// 解密
/// </summary>
/// <param name="cryptograph"></param>
/// <param name="accessKey"></param>
/// <returns></returns>
public static string DecyptData(string cryptograph, string accessKey)
{
SymmetricAlgorithm des = new DESCryptoServiceProvider();
Encoding utf = new UTF8Encoding();
byte[] key = utf.GetBytes(accessKey);
byte[] iv = { 0x75, 0x70, 0x63, 0x68, 0x69, 0x6e, 0x61, 0x31 };
ICryptoTransform decryptor = des.CreateDecryptor(key, iv);
byte[] encData = Convert.FromBase64String(cryptograph);
byte[] data = decryptor.TransformFinalBlock(encData, 0, encData.Length);
return utf.GetString(data);
}
public static string SignData(string ciphertext, string accessKey)
{
Encoding utf = new UTF8Encoding();
HMACMD5 hmac = new HMACMD5(utf.GetBytes(accessKey));
byte[] hashValue = hmac.ComputeHash(utf.GetBytes(ciphertext));
return Convert.ToBase64String(hashValue);
}
/// <summary>
/// 加密
/// </summary>
/// <param name="ciphertext"></param>
/// <param name="accessKey"></param>
/// <param name="iv"></param>
/// <returns></returns>
public static string EncyptDataNew(string ciphertext, string accessKey, string iv)
{
SymmetricAlgorithm des = new DESCryptoServiceProvider();
Encoding utf = new UTF8Encoding();
byte[] key = utf.GetBytes(accessKey);
byte[] ivbt = utf.GetBytes(iv);
ICryptoTransform encryptor = des.CreateEncryptor(key, ivbt);
byte[] data = utf.GetBytes(ciphertext);
byte[] encData = encryptor.TransformFinalBlock(data, 0, data.Length);
return Convert.ToBase64String(encData);
}
/// <summary>
/// 解密
/// </summary>
/// <param name="cryptograph"></param>
/// <param name="accessKey"></param>
/// <param name="iv"></param>
/// <returns></returns>
public static string DecyptDataNew(string cryptograph, string accessKey, string iv)
{
SymmetricAlgorithm des = new DESCryptoServiceProvider();
Encoding utf = new UTF8Encoding();
byte[] key = utf.GetBytes(accessKey);
byte[] ivbt = utf.GetBytes(iv);
ICryptoTransform decryptor = des.CreateDecryptor(key, ivbt);
byte[] encData = Convert.FromBase64String(cryptograph);
byte[] data = decryptor.TransformFinalBlock(encData, 0, encData.Length);
return utf.GetString(data);
}
public static string CreateSignEncodingStr(string json, string clientid, string accessKey)
{
if (string.IsNullOrWhiteSpace(clientid))
{
clientid = "UPWEBSITE";
}
string key = "content={0}&clientid=" + clientid + "&sign={1}";
string jiami = EncyptData(json, accessKey);
string jiami1 = HttpUtility.UrlEncode(jiami, Encoding.UTF8);
string jiasuo = SignData(jiami, accessKey);
string jiasuo1 = HttpUtility.UrlEncode(jiasuo, Encoding.UTF8);
key = string.Format(key, jiami1, jiasuo1);
return key;
}
public static object CreateSignEncodingJsonStr(string json, string clientid, string accessKey)
{
//if (string.IsNullOrWhiteSpace(clientid))
//{
// clientid = "UPWEBSITE";
//}
//string key = "content={0}&clientid=" + clientid + "&sign={1}";
//string jiami = EncyptData(json, accessKey);
//string jiami1 = HttpUtility.UrlEncode(jiami, Encoding.UTF8);
//string jiasuo = SignData(jiami, accessKey);
//string jiasuo1 = HttpUtility.UrlEncode(jiasuo, Encoding.UTF8);
//key = string.Format(key, jiami1, jiasuo1);
//return key;
if (string.IsNullOrWhiteSpace(clientid))
{
clientid = "UPWEBSITE";
}
string content = EncyptData(json, accessKey);
string sign = SignData(content, accessKey);
var maxjson = new
{
content = content,
clientId = clientid,
sign = sign
};
return maxjson;
}
}
}

View File

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace DG.Tool
{
public static class SignHelper
{
/// <summary>
/// 计算签名
/// </summary>
/// <param name="param"></param>
/// <param name="timestamps"></param>
/// <returns></returns>
public static string GetSign(string appId, string appSecret, Dictionary<string, object> param, string timestamps)
{
//一次排序
var newP = param.OrderBy(m => m.Key).ToDictionary(m => m.Key, n => n.Value);
var pJosn = JsonHelper.ToJson(newP);
//二次排序
var enStrList = new string[] { appId, pJosn, appSecret, timestamps };
Array.Sort(enStrList, string.CompareOrdinal);
//拼接
var enStr = string.Join("", enStrList);
//md5 加密
return GetMd5Hash(enStr);
}
/// <summary>
/// 计算 md5
/// </summary>
/// <param name="enCode"></param>
/// <returns></returns>
private static string GetMd5Hash(string enCode)
{
string res = "";
byte[] data = Encoding.GetEncoding("utf-8").GetBytes(enCode);
MD5 md5 = MD5.Create();
byte[] bytes = md5.ComputeHash(data);
for (int i = 0; i < bytes.Length; i++)
{
res += bytes[i].ToString("x2");
}
return res;
}
/// <summary>
/// 获取时间戳
/// </summary>
/// <returns></returns>
public static string GetTimeStamp()
{
TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return Convert.ToInt64(ts.TotalSeconds).ToString();
}
}
}

365
code/DG.Tool/TimeHelper.cs Normal file
View File

@ -0,0 +1,365 @@
using System;
using System.Diagnostics;
using System.Globalization;
namespace DG.Tool
{
/// <summary>
/// 时间类
/// 1、SecondToMinute(int Second) 把秒转换成分钟
/// </summary>
public class TimeHelper
{
#region Stopwatch计时器
/// <summary>
/// 计时器开始
/// </summary>
/// <returns></returns>
public static Stopwatch TimerStart()
{
Stopwatch watch = new Stopwatch();
watch.Reset();
watch.Start();
return watch;
}
/// <summary>
/// 计时器结束
/// </summary>
/// <param name="watch"></param>
/// <returns></returns>
public static string TimerEnd(Stopwatch watch)
{
watch.Stop();
double costtime = watch.ElapsedMilliseconds;
return costtime.ToString();
}
#endregion Stopwatch计时器
//返回每月的第一天和最后一天
public static void ReturnDateFormat(int month, out string firstDay, out string lastDay)
{
int year = DateTime.Now.Year + month / 12;
if (month != 12)
{
month = month % 12;
}
switch (month)
{
case 1:
firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
lastDay = DateTime.Now.ToString(year + "-0" + month + "-31");
break;
case 2:
firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
if (DateTime.IsLeapYear(DateTime.Now.Year))
lastDay = DateTime.Now.ToString(year + "-0" + month + "-29");
else
lastDay = DateTime.Now.ToString(year + "-0" + month + "-28");
break;
case 3:
firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
lastDay = DateTime.Now.ToString("yyyy-0" + month + "-31");
break;
case 4:
firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
lastDay = DateTime.Now.ToString(year + "-0" + month + "-30");
break;
case 5:
firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
lastDay = DateTime.Now.ToString(year + "-0" + month + "-31");
break;
case 6:
firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
lastDay = DateTime.Now.ToString(year + "-0" + month + "-30");
break;
case 7:
firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
lastDay = DateTime.Now.ToString(year + "-0" + month + "-31");
break;
case 8:
firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
lastDay = DateTime.Now.ToString(year + "-0" + month + "-31");
break;
case 9:
firstDay = DateTime.Now.ToString(year + "-0" + month + "-01");
lastDay = DateTime.Now.ToString(year + "-0" + month + "-30");
break;
case 10:
firstDay = DateTime.Now.ToString(year + "-" + month + "-01");
lastDay = DateTime.Now.ToString(year + "-" + month + "-31");
break;
case 11:
firstDay = DateTime.Now.ToString(year + "-" + month + "-01");
lastDay = DateTime.Now.ToString(year + "-" + month + "-30");
break;
default:
firstDay = DateTime.Now.ToString(year + "-" + month + "-01");
lastDay = DateTime.Now.ToString(year + "-" + month + "-31");
break;
}
}
/// <summary>
/// 将时间格式化成 年月日 的形式,如果时间为null返回当前系统时间
/// </summary>
/// <param name="dt">年月日分隔符</param>
/// <param name="Separator"></param>
/// <returns></returns>
public string GetFormatDate(DateTime dt, char Separator)
{
if (dt != null && !dt.Equals(DBNull.Value))
{
string tem = string.Format("yyyy{0}MM{1}dd", Separator, Separator);
return dt.ToString(tem);
}
else
{
return GetFormatDate(DateTime.Now, Separator);
}
}
/// <summary>
/// 将时间格式化成 时分秒 的形式,如果时间为null返回当前系统时间
/// </summary>
/// <param name="dt"></param>
/// <param name="Separator"></param>
/// <returns></returns>
public string GetFormatTime(DateTime dt, char Separator)
{
if (dt != null && !dt.Equals(DBNull.Value))
{
string tem = string.Format("hh{0}mm{1}ss", Separator, Separator);
return dt.ToString(tem);
}
else
{
return GetFormatDate(DateTime.Now, Separator);
}
}
/// <summary>
/// 把秒转换成分钟
/// </summary>
/// <returns></returns>
public static int SecondToMinute(int Second)
{
decimal mm = (decimal)((decimal)Second / (decimal)60);
return Convert.ToInt32(Math.Ceiling(mm));
}
#region
/// <summary>
/// 返回某年某月最后一天
/// </summary>
/// <param name="year">年份</param>
/// <param name="month">月份</param>
/// <returns>日</returns>
public static int GetMonthLastDate(int year, int month)
{
DateTime lastDay = new DateTime(year, month, new GregorianCalendar().GetDaysInMonth(year, month));
int Day = lastDay.Day;
return Day;
}
#endregion
#region
public static string DateDiff(DateTime DateTime1, DateTime DateTime2)
{
string dateDiff = null;
try
{
//TimeSpan ts1 = new TimeSpan(DateTime1.Ticks);
//TimeSpan ts2 = new TimeSpan(DateTime2.Ticks);
//TimeSpan ts = ts1.Subtract(ts2).Duration();
TimeSpan ts = DateTime2 - DateTime1;
if (ts.Days >= 1)
{
dateDiff = DateTime1.Month.ToString() + "月" + DateTime1.Day.ToString() + "日";
}
else
{
if (ts.Hours > 1)
{
dateDiff = ts.Hours.ToString() + "小时前";
}
else
{
dateDiff = ts.Minutes.ToString() + "分钟前";
}
}
}
catch
{ }
return dateDiff;
}
#endregion
#region
/// <summary>
/// 获得两个日期的间隔
/// </summary>
/// <param name="DateTime1">日期一。</param>
/// <param name="DateTime2">日期二。</param>
/// <returns>日期间隔TimeSpan。</returns>
public static TimeSpan DateDiff2(DateTime DateTime1, DateTime DateTime2)
{
TimeSpan ts1 = new TimeSpan(DateTime1.Ticks);
TimeSpan ts2 = new TimeSpan(DateTime2.Ticks);
TimeSpan ts = ts1.Subtract(ts2).Duration();
return ts;
}
#endregion
#region
/// <summary>
/// 格式化日期时间
/// </summary>
/// <param name="dateTime1">日期时间</param>
/// <param name="dateMode">显示模式</param>
/// <returns>0-9种模式的日期</returns>
public static string FormatDate(DateTime dateTime1, string dateMode)
{
switch (dateMode)
{
case "0":
return dateTime1.ToString("yyyy-MM-dd");
case "1":
return dateTime1.ToString("yyyy-MM-dd HH:mm:ss");
case "2":
return dateTime1.ToString("yyyy/MM/dd");
case "3":
return dateTime1.ToString("yyyy年MM月dd日");
case "4":
return dateTime1.ToString("MM-dd");
case "5":
return dateTime1.ToString("MM/dd");
case "6":
return dateTime1.ToString("MM月dd日");
case "7":
return dateTime1.ToString("yyyy-MM");
case "8":
return dateTime1.ToString("yyyy/MM");
case "9":
return dateTime1.ToString("yyyy年MM月");
default:
return dateTime1.ToString();
}
}
#endregion
#region
/// <summary>
/// 得到随机日期
/// </summary>
/// <param name="time1">起始日期</param>
/// <param name="time2">结束日期</param>
/// <returns>间隔日期之间的 随机日期</returns>
public static DateTime GetRandomTime(DateTime time1, DateTime time2)
{
Random random = new Random();
DateTime minTime = new DateTime();
DateTime maxTime = new DateTime();
TimeSpan ts = new TimeSpan(time1.Ticks - time2.Ticks);
// 获取两个时间相隔的秒数
double dTotalSecontds = ts.TotalSeconds;
int iTotalSecontds = 0;
if (dTotalSecontds > Int32.MaxValue)
{
iTotalSecontds = Int32.MaxValue;
}
else if (dTotalSecontds < Int32.MinValue)
{
iTotalSecontds = Int32.MinValue;
}
else
{
iTotalSecontds = (int)dTotalSecontds;
}
if (iTotalSecontds > 0)
{
minTime = time2;
maxTime = time1;
}
else if (iTotalSecontds < 0)
{
minTime = time1;
maxTime = time2;
}
else
{
return time1;
}
int maxValue = iTotalSecontds;
if (iTotalSecontds <= Int32.MinValue)
maxValue = Int32.MinValue + 1;
int i = random.Next(Math.Abs(maxValue));
return minTime.AddSeconds(i);
}
#endregion
/// <summary>
/// DateTime时间格式转换为Unix时间戳格式
/// </summary>
/// <param name=”time”></param>
/// <returns></returns>
public static int ConvertDateTimeInt(System.DateTime time)
{
System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
return (int)(time - startTime).TotalSeconds;
}
/// <summary>
/// 时间戳转为C#格式时间
/// </summary>
/// <param name=”timeStamp”></param>
/// <returns></returns>
public static DateTime GetTimeFromLinuxTime(long timeStamp)
{
System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0);
dtDateTime = dtDateTime.AddMilliseconds(timeStamp).ToLocalTime();
return dtDateTime;
}
}
}

254
code/DG.Tool/Utility.cs Normal file
View File

@ -0,0 +1,254 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace DG.Tool
{
public static class Utility
{
/// <summary>
/// 获取随机数
/// </summary>
/// <param name="codeCount"></param>
/// <returns></returns>
public static string CreateRandomSatl(int codeCount)
{
string allChar = "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,w,x,y,z";
string[] allCharArray = allChar.Split(',');
string randomCode = "";
int temp = -1;
Random rand = new Random();
for (int i = 0; i < codeCount; i++)
{
if (temp != -1)
{
rand = new Random(i * temp * ((int)DateTime.Now.Ticks));
}
int t = rand.Next(50);
if (temp == t)
{
return CreateRandomSatl(codeCount);
}
temp = t;
randomCode += allCharArray[t];
}
return randomCode;
}
public static string Sha512(string value)
{
SHA512 s512 = new SHA512Managed();
byte[] bit_pwd = Encoding.Default.GetBytes(value);
byte[] bit_shapsw = s512.ComputeHash(bit_pwd);
string shapsw = Convert.ToBase64String(bit_shapsw);
return shapsw;
}
public static int PasswordStrength(string password)
{
if (string.IsNullOrWhiteSpace(password)) return -1;
//字符统计
int iNum = 0, iLtt = 0, iSym = 0;
foreach (char c in password)
{
if (c >= '0' && c <= '9') iNum++;
else if (c >= 'a' && c <= 'z') iLtt++;
else if (c >= 'A' && c <= 'Z') iLtt++;
else iSym++;
}
if (password.Length < 6) return 3; //长度小于6的密码
if (iLtt == 0 && iSym == 0) return 1; //纯数字密码
if (iNum == 0 && iSym == 0) return 2; //纯字母密码
return 0; //正确
}
public static string GetSendMsgModel(string strJson, string modelParam)
{
string key = string.Empty;
string values = string.Empty;
strJson = strJson.Replace(",\"", "*\"").Replace("\":", "\"#").ToString();
Regex regex = new Regex(@"(?<={)[^}]+(?=})");
MatchCollection mc = regex.Matches(strJson);
Dictionary<string, string> list = new Dictionary<string, string>();
for (int i = 0; i < mc.Count; i++)
{
string strRow = mc[i].Value;
string[] strRows = strRow.Split('*');
foreach (string str in strRows)
{
string[] strCell = str.Split('#');
key = strCell[0].Replace("\"", "");
values = strCell[1].Replace("\"", "");
list.Add(key, values);
}
}
foreach (var item in list)
{
modelParam = modelParam.Replace("${" + item.Key + "}", item.Value);
}
return modelParam;
}
public static string DateEnToCn(string date)
{
string datename = "";
date = date.ToLower();
switch (date)
{//--Monday 周一 Tuesday 周二 Wednesday 周三 Thursday 周四 Friday 周五 Saturday 周六 Sunday 周日
case "monday": datename = "星期一"; break;
case "tuesday": datename = "星期二"; break;
case "wednesday": datename = "星期三"; break;
case "thursday": datename = "星期四"; break;
case "friday": datename = "星期五"; break;
case "saturday": datename = "星期六"; break;
case "sunday": datename = "星期日"; break;
}
return datename;
}
/// <summary>
/// 将c# DateTime时间格式转换为Unix时间戳格式
/// </summary>
/// <param name="time">时间</param>
/// <returns>long</returns>
public static long ConvertDateTimeToInt(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;
}
/// <summary>
/// 时间戳转为C#格式时间
/// </summary>
/// <param name="timeStamp"></param>
/// <returns></returns>
public static DateTime ConvertStringToDateTime(string timeStamp)
{
DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
long lTime = long.Parse(timeStamp + "0000");
TimeSpan toNow = new TimeSpan(lTime);
return dtStart.Add(toNow);
}
/// <summary>
/// 获取文件的MD5码
/// </summary>
/// <param name="fileName">传入的文件名(含路径及后缀名)</param>
/// <returns></returns>
public static string GetMD5HashFromFile(string fileName)
{
try
{
FileStream file = new FileStream(fileName, System.IO.FileMode.Open);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] retVal = md5.ComputeHash(file);
file.Close();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < retVal.Length; i++)
{
sb.Append(retVal[i].ToString("x2"));
}
return sb.ToString();
}
catch (Exception ex)
{
throw new Exception("GetMD5HashFromFile() fail,error:" + ex.Message);
}
}
#region SecondToHour
/// <summary>
/// 秒转换小时
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public static string SecondToHour(double time)
{
string str = "";
int hour = 0;
int minute = 0;
int second = 0;
second = Convert.ToInt32(time);
if (second > 60)
{
minute = second / 60;
second = second % 60;
}
if (minute > 60)
{
hour = minute / 60;
minute = minute % 60;
}
return (hour + "小时" + minute + "分钟"
+ second + "秒");
}
#endregion
/// <summary>
///时间格式化
/// </summary>
/// <param name="dt">返回字符串的类型(默认4)
///例子: 2014/05/08 19:14:17
///type=1 2014/05/08 没有时分秒
///type=2 2014/05/08 19:14 没有秒
///type=3 14/05/08 19:14 没有年前两位和秒
///type=4 05/08 19:14 没有年和秒
/// </param>
/// <returns></returns>
public static string ToUnityString(this DateTime dt, int type = 4)
{
if (dt == DateTime.MinValue)
return "";
string formartStr = string.Empty;
switch (type)
{
case 1: formartStr = "yyyy/MM/dd"; break;
case 2: formartStr = "yyyy/MM/dd HH:mm"; break;
case 3: formartStr = "yy/MM/dd HH:mm"; break;
case 4: formartStr = "MM/dd HH:mm"; break;
case 5: formartStr = "yyyyMM"; break;
case 6: formartStr = "yyyy-MM-dd"; break;
case 7: formartStr = "yyyy-MM-dd HH:mm:ss"; break;
}
return dt.ToString(formartStr);
}
/// <summary>
///时间格式化
/// </summary>
/// <param name="dt">返回字符串的类型(默认4)
///例子: 2014/05/08 19:14:17
///type=1 2014/05/08 没有时分秒
///type=2 2014/05/08 19:14 没有秒
///type=3 14/05/08 19:14 没有年前两位和秒
///type=4 05/08 19:14 没有年和秒
/// </param>
/// <returns></returns>
public static string ToUnityString(this DateTime? dt, int type = 4)
{
if (dt == null || dt.Value == DateTime.MinValue)
return "";
string formartStr = string.Empty;
switch (type)
{
case 1: formartStr = "yyyy/MM/dd"; break;
case 2: formartStr = "yyyy/MM/dd HH:mm"; break;
case 3: formartStr = "yy/MM/dd HH:mm"; break;
case 4: formartStr = "MM/dd HH:mm"; break;
case 5: formartStr = "yyyyMM"; break;
case 6: formartStr = "yyyy-MM-dd"; break;
}
return dt.Value.ToString(formartStr);
}
}
}

View File

@ -30,9 +30,6 @@
<ItemGroup>
<PackageReference Include="Dapper" Version="2.0.143" />
<PackageReference Include="DG.Core" Version="1.1.2" />
<PackageReference Include="DG.Tool" Version="1.0.11" />
<PackageReference Include="DG.Worker" Version="1.0.1" />
<PackageReference Include="Exceptionless" Version="6.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
@ -50,6 +47,9 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DG.Core\DG.Core.csproj" />
<ProjectReference Include="..\DG.Kafka.Worker\DG.Kafka.Worker.csproj" />
<ProjectReference Include="..\DG.Tool\DG.Tool.csproj" />
<ProjectReference Include="..\Zxd.Core.Shared\Zxd.Core.Shared.csproj" />
<ProjectReference Include="..\Zxd.EntityFramework\Zxd.EntityFramework.csproj" />
</ItemGroup>

View File

@ -16,9 +16,6 @@
<ItemGroup>
<PackageReference Include="DG.Core" Version="1.0.25" />
<PackageReference Include="DG.Redis" Version="1.0.17" />
<PackageReference Include="DG.Tool" Version="1.0.9" />
<PackageReference Include="DG.Worker" Version="1.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
@ -34,6 +31,10 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DG.Core\DG.Core.csproj" />
<ProjectReference Include="..\DG.Kafka.Worker\DG.Kafka.Worker.csproj" />
<ProjectReference Include="..\DG.Redis\DG.Redis.csproj" />
<ProjectReference Include="..\DG.Tool\DG.Tool.csproj" />
<ProjectReference Include="..\Zxd.Core.Shared\Zxd.Core.Shared.csproj" />
<ProjectReference Include="..\Zxd.EntityFramework\Zxd.EntityFramework.csproj" />
<ProjectReference Include="..\Zxd.Entity\Zxd.Entity.csproj" />

View File

@ -13,11 +13,6 @@
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="DG.Core" Version="1.1.3" />
<PackageReference Include="DG.Redis" Version="1.0.17" />
<PackageReference Include="DG.Tool" Version="1.0.11" />
<PackageReference Include="DG.Kafka.Worker" Version="1.0.12" />
<PackageReference Include="DG.Worker" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
@ -33,6 +28,11 @@
<PackageReference Include="System.Management" Version="7.0.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DG.Core\DG.Core.csproj" />
<ProjectReference Include="..\DG.Kafka.Worker\DG.Kafka.Worker.csproj" />
<ProjectReference Include="..\DG.Kafka\DG.Kafka.csproj" />
<ProjectReference Include="..\DG.Redis\DG.Redis.csproj" />
<ProjectReference Include="..\DG.Tool\DG.Tool.csproj" />
<ProjectReference Include="..\Zxd.Core.Shared\Zxd.Core.Shared.csproj" />
<ProjectReference Include="..\Zxd.EntityFramework\Zxd.EntityFramework.csproj" />
<ProjectReference Include="..\Zxd.SqlSugar\Zxd.SqlSugar.csproj" />

View File

@ -10,10 +10,6 @@
<ItemGroup>
<PackageReference Include="DG.Core" Version="1.0.25" />
<PackageReference Include="DG.Redis" Version="1.0.17" />
<PackageReference Include="DG.Tool" Version="1.0.9" />
<PackageReference Include="DG.Kafka" Version="1.0.3" />
<PackageReference Include="DG.Kafka.Worker" Version="1.0.3" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
@ -29,6 +25,11 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DG.Core\DG.Core.csproj" />
<ProjectReference Include="..\DG.Kafka.Worker\DG.Kafka.Worker.csproj" />
<ProjectReference Include="..\DG.Kafka\DG.Kafka.csproj" />
<ProjectReference Include="..\DG.Redis\DG.Redis.csproj" />
<ProjectReference Include="..\DG.Tool\DG.Tool.csproj" />
<ProjectReference Include="..\Zxd.Core.Shared\Zxd.Core.Shared.csproj" />
<ProjectReference Include="..\Zxd.EntityFramework\Zxd.EntityFramework.csproj" />
<ProjectReference Include="..\Zxd.Entity\Zxd.Entity.csproj" />

View File

@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Zxd.Core.Domain.Dto.Dg
{
public class Sms_RecordsDto
{
/// <summary>
/// 渠道名称
/// </summary>
public string channel_name { get; set; }
public int id { get; set; }
/// <summary>
/// 资源ID
/// </summary>
public string umid { get; set; }
/// <summary>
/// 脱敏手机号
/// </summary>
public string mobile { get; set; }
/// <summary>
/// 内部单号
/// </summary>
public string trade_no { get; set; }
/// <summary>
/// 外部单号
/// </summary>
public string out_trade_no { get; set; }
/// <summary>
/// 模板类型ID
/// </summary>
public int sms_temp_type_id { get; set; }
/// <summary>
/// 渠道ID
/// </summary>
public int channel_id { get; set; }
/// <summary>
/// 渠道商模板ID
/// </summary>
public string template_id { get; set; }
/// <summary>
/// 短信内容
/// </summary>
public string sms_content { get; set; }
/// <summary>
/// 发送状态 0: 失败 1: 成功
/// </summary>
public bool send_state { get; set; }
/// <summary>
/// 发送时间
/// </summary>
public DateTime send_time { get; set; }
/// <summary>
/// 回执返回值
/// </summary>
public string receipt_code { get; set; }
/// <summary>
/// 回执状态码
/// </summary>
public string receipt_status { get; set; }
/// <summary>
/// 回执接收时间
/// </summary>
public DateTime receipt_time { get; set; }
/// <summary>
/// 回执成功 0失败 1成功
/// </summary>
public bool receipt_success { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Zxd.Core.Domain.Dto.Dg;
namespace Zxd.Core.Domain.Impl
{
public interface ISmsRecordDomain : IScopedDependency
{
Task<List<Sms_RecordsDto>> GetSmsRecordsList(string umid);
}
}

View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Zxd.Core.Domain.Dto.Dg;
using Zxd.Entity.dg;
namespace Zxd.Core.Domain
{
public class SmsRecordDomain : ISmsRecordDomain
{
private readonly IBaseRepository<DgDbContext> _dgRepository;
public SmsRecordDomain(
IBaseRepository<DgDbContext> dgRepository)
{
_dgRepository = dgRepository;
}
public async Task<List<Sms_RecordsDto>> GetSmsRecordsList(string umid)
{
if (string.IsNullOrEmpty(umid))
{
throw new ApiException("umid不能为空");
}
DateTime dateTime = DateTime.Now.AddDays(-10);//超过10天的数据不做查找
var query = _dgRepository.GetRepository<Sms_Records>().Query();
var channel = _dgRepository.GetRepository<Sms_Channel>().Query();
var xx = (from a in query
join b in channel on a.channel_id equals b.id
where a.umid == umid && a.send_time >= dateTime
select new Sms_RecordsDto()
{
channel_id = a.channel_id,
id = a.id,
channel_name = b.channel_name,
mobile = a.phone,
out_trade_no = a.out_trade_no,
receipt_code = a.receipt_code,
receipt_status = a.receipt_status,
receipt_success = a.receipt_success,
receipt_time = a.receipt_time,
send_state = true,
send_time = a.send_time,
sms_content = a.sms_content,
sms_temp_type_id = 0,
template_id = a.template_id,
trade_no = a.trade_no,
umid = a.umid,
}
).OrderByDescending(m => m.id);
return xx.ToList();
}
}
}

View File

@ -15,12 +15,7 @@
<Folder Include="Dto\Exents\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Crm.Core.Shared" Version="1.0.1" />
<PackageReference Include="Dapper" Version="2.0.123" />
<PackageReference Include="DG.Core" Version="1.1.3" />
<PackageReference Include="DG.Kafka" Version="1.0.1" />
<PackageReference Include="DG.Redis" Version="1.0.17" />
<PackageReference Include="DG.Tool" Version="1.0.11" />
<PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="Serilog.AspNetCore" Version="6.0.1" />
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />
@ -31,10 +26,20 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DG.Core\DG.Core.csproj" />
<ProjectReference Include="..\DG.Kafka\DG.Kafka.csproj" />
<ProjectReference Include="..\DG.Redis\DG.Redis.csproj" />
<ProjectReference Include="..\DG.Tool\DG.Tool.csproj" />
<ProjectReference Include="..\Zxd.Core.Shared\Zxd.Core.Shared.csproj" />
<ProjectReference Include="..\Zxd.EntityFramework\Zxd.EntityFramework.csproj" />
<ProjectReference Include="..\Zxd.Entity\Zxd.Entity.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="Crm.Core.Shared">
<HintPath>..\..\lib\Crm.Core.Shared.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Using Include="System.Text.Json" />
<Using Include="System.Text.Json.Serialization" />

View File

@ -9,7 +9,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DG.Tool" Version="1.0.7" />
<ProjectReference Include="..\DG.Tool\DG.Tool.csproj" />
</ItemGroup>
</Project>

View File

@ -1,4 +1,5 @@
using Zxd.Core.Domain.Dto.Activity;
using Crm.Core.Shared;
using Zxd.Core.Domain.Dto.Activity;
namespace Zxd.Core.WebApi.Controllers
{

View File

@ -1,4 +1,5 @@
using Zxd.Core.Domain.Dto.Crm;
using Zxd.Core.Domain.Dto.Dg;
using Zxd.Core.Domain.Dto.Wework;
using Zxd.Core.Domain.Dto.Zxd.Order;
using static Zxd.Domain.Impl.ICustomerDomain;
@ -10,11 +11,13 @@ namespace Zxd.Core.WebApi.Controllers
{
private readonly ICustomerDomain _customerDomain;
private readonly IOrderDomain _orderDomain;
private readonly ISmsRecordDomain _smsRecordDomain;
public CustomerController(ICustomerDomain customerDomain, IOrderDomain orderDomain)
public CustomerController(ICustomerDomain customerDomain, IOrderDomain orderDomain, ISmsRecordDomain smsRecordDomain)
{
_customerDomain = customerDomain;
_orderDomain = orderDomain;
_smsRecordDomain = smsRecordDomain;
}
@ -92,11 +95,21 @@ namespace Zxd.Core.WebApi.Controllers
public async Task<List<string>> ExtUserBandGetAsync(string? ResId)
{
return await _customerDomain.ExtUserBandGetAsync(ResId);
}/// <summary>
/// 根据外部联系人Userid获取resid
/// </summary>
/// <returns></returns>
}
/// <summary>
/// 获取验证码列表
/// </summary>
/// <param name="umid"></param>
/// <returns></returns>
[HttpGet("GetSmsRecord")]
public async Task<List<Sms_RecordsDto>> GetSmsRecord(string umid)
{
return await _smsRecordDomain.GetSmsRecordsList(umid);
}
/// <summary>
/// 根据外部联系人Userid获取resid
/// </summary>
/// <returns></returns>
[HttpPost("GetResidByExtUser")]
public async Task<List<string>> GetResidByExtUser([FromBody] string extUser)
{

View File

@ -24,6 +24,11 @@
<ItemGroup>
<ProjectReference Include="..\Zxd.Core.Domain\Zxd.Core.Domain.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="Crm.Core.Shared">
<HintPath>..\..\lib\Crm.Core.Shared.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Using Include="Microsoft.EntityFrameworkCore" />

View File

@ -53,6 +53,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DG.Kafka", "DG.Kafka\DG.Kaf
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DG.Kafka.Worker", "DG.Kafka.Worker\DG.Kafka.Worker.csproj", "{1E97050D-CA19-46A7-92A2-7BFA09006971}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DG.Core", "DG.Core\DG.Core.csproj", "{A32F8817-49CB-4729-97A5-7E7615760A41}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DG.EntityFramework", "DG.EntityFramework\DG.EntityFramework.csproj", "{D15B60AC-C477-411D-828D-ABD65568ABF8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DG.Redis", "DG.Redis\DG.Redis.csproj", "{2ADFE051-3B5E-4828-BF5D-3E90A887E7F1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DG.Tool", "DG.Tool\DG.Tool.csproj", "{F04DB682-8C17-4781-9C91-ACC7E953371A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -131,6 +139,22 @@ Global
{1E97050D-CA19-46A7-92A2-7BFA09006971}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E97050D-CA19-46A7-92A2-7BFA09006971}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E97050D-CA19-46A7-92A2-7BFA09006971}.Release|Any CPU.Build.0 = Release|Any CPU
{A32F8817-49CB-4729-97A5-7E7615760A41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A32F8817-49CB-4729-97A5-7E7615760A41}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A32F8817-49CB-4729-97A5-7E7615760A41}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A32F8817-49CB-4729-97A5-7E7615760A41}.Release|Any CPU.Build.0 = Release|Any CPU
{D15B60AC-C477-411D-828D-ABD65568ABF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D15B60AC-C477-411D-828D-ABD65568ABF8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D15B60AC-C477-411D-828D-ABD65568ABF8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D15B60AC-C477-411D-828D-ABD65568ABF8}.Release|Any CPU.Build.0 = Release|Any CPU
{2ADFE051-3B5E-4828-BF5D-3E90A887E7F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2ADFE051-3B5E-4828-BF5D-3E90A887E7F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2ADFE051-3B5E-4828-BF5D-3E90A887E7F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2ADFE051-3B5E-4828-BF5D-3E90A887E7F1}.Release|Any CPU.Build.0 = Release|Any CPU
{F04DB682-8C17-4781-9C91-ACC7E953371A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F04DB682-8C17-4781-9C91-ACC7E953371A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F04DB682-8C17-4781-9C91-ACC7E953371A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F04DB682-8C17-4781-9C91-ACC7E953371A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -153,6 +177,10 @@ Global
{BB3183D9-38F5-4860-ADE6-735EF9F8EF7F} = {19629268-FAF2-42CA-A7D4-D5CCE739FF4A}
{FAA4E537-81BF-462E-BE19-3194B7DD7D47} = {5E8706D3-CCF5-4654-B3AC-00DF95CED9EE}
{1E97050D-CA19-46A7-92A2-7BFA09006971} = {5E8706D3-CCF5-4654-B3AC-00DF95CED9EE}
{A32F8817-49CB-4729-97A5-7E7615760A41} = {5E8706D3-CCF5-4654-B3AC-00DF95CED9EE}
{D15B60AC-C477-411D-828D-ABD65568ABF8} = {5E8706D3-CCF5-4654-B3AC-00DF95CED9EE}
{2ADFE051-3B5E-4828-BF5D-3E90A887E7F1} = {5E8706D3-CCF5-4654-B3AC-00DF95CED9EE}
{F04DB682-8C17-4781-9C91-ACC7E953371A} = {5E8706D3-CCF5-4654-B3AC-00DF95CED9EE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6C94942A-1B07-4CF7-BB70-E63A968E909D}

Some files were not shown because too many files have changed in this diff Show More