合并接口代码
This commit is contained in:
parent
d5bf18d324
commit
a9be87598b
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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 正常请求
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>();
|
||||
}
|
||||
}
|
||||
|
|
@ -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>();
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
{
|
||||
// 执行中的过滤器管道
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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 = "");
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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、手机号形式的按原处理规则中间几位屏蔽;
|
||||
2、否则看用户名长度,小于等于5位的,第一位不屏蔽,后面的屏蔽,比如“test1”,处理后为“t****”;
|
||||
3、5位以上的,用户名长度除2向下取整,再减1做为起始值,从起始值开始后面4位用*号;比如“test123”,处理后为“te****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 = @"[1,2,3,4,5,6,7,8,9,0]{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 = @"([1,2,3,4,5,6,7,8,9,0]{2})([1,2,3,4,5,6,7,8,9,0]{4})([1,2,3,4,5,6,7,8,9,0]{2})";
|
||||
xinghao = "****";
|
||||
}
|
||||
else if (phoneNo.Length == 9)
|
||||
{
|
||||
rexstr = @"([1,2,3,4,5,6,7,8,9,0]{2})([1,2,3,4,5,6,7,8,9,0]{5})([1,2,3,4,5,6,7,8,9,0]{2})";
|
||||
xinghao = "*****";
|
||||
}
|
||||
else if (phoneNo.Length == 10)
|
||||
{
|
||||
rexstr = @"([1,2,3,4,5,6,7,8,9,0]{2})([1,2,3,4,5,6,7,8,9,0]{5})([1,2,3,4,5,6,7,8,9,0]{3})";
|
||||
xinghao = "*****";
|
||||
}
|
||||
else
|
||||
{
|
||||
rexstr = @"([1,2,3,4,5,6,7,8,9,0]{3})([1,2,3,4,5,6,7,8,9,0]{" + (phoneNo.Length - 6) + @"})([1,2,3,4,5,6,7,8,9,0]{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
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DG.Tool" Version="1.0.7" />
|
||||
<ProjectReference Include="..\DG.Tool\DG.Tool.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue