增加同步物流模块
修改现有架构,改为分模块( 简易版)
This commit is contained in:
1 parent
15e11618c9
commit
fa03add754
120 files changed
+9437
-298
No files matched your search
@@ -20,6 +20,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Store.User", "Store.User\St
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Store.Framework", "Store.Framework\Store.Framework.csproj", "{CD6FB773-0431-4FAE-9E30-65953118FEBF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MAX.Core", "MAX.Core\MAX.Core.csproj", "{281F6609-E5BC-8A5C-8382-CD7C4670ACBF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Store.Contracts", "Store.Contracts\Store.Contracts.csproj", "{3694EDE2-3192-44E6-B45C-9CDC99916876}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Store.SyncLogistics", "Store.SyncLogistics\Store.SyncLogistics.csproj", "{11AF9AF8-8DA0-E764-D5FF-8EF35E1FF7C8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -42,6 +48,18 @@ Global
|
||||
{CD6FB773-0431-4FAE-9E30-65953118FEBF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CD6FB773-0431-4FAE-9E30-65953118FEBF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CD6FB773-0431-4FAE-9E30-65953118FEBF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{281F6609-E5BC-8A5C-8382-CD7C4670ACBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{281F6609-E5BC-8A5C-8382-CD7C4670ACBF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{281F6609-E5BC-8A5C-8382-CD7C4670ACBF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{281F6609-E5BC-8A5C-8382-CD7C4670ACBF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3694EDE2-3192-44E6-B45C-9CDC99916876}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3694EDE2-3192-44E6-B45C-9CDC99916876}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3694EDE2-3192-44E6-B45C-9CDC99916876}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3694EDE2-3192-44E6-B45C-9CDC99916876}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{11AF9AF8-8DA0-E764-D5FF-8EF35E1FF7C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{11AF9AF8-8DA0-E764-D5FF-8EF35E1FF7C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{11AF9AF8-8DA0-E764-D5FF-8EF35E1FF7C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{11AF9AF8-8DA0-E764-D5FF-8EF35E1FF7C8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using KJD_Web.Requests;
|
||||
using Store.Framework.Dtos;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using KJD_Web.Requests;
|
||||
using Store.Framework.Dtos;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using KJD_Web.Requests;
|
||||
using Store.Framework.Dtos;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -2,12 +2,13 @@ using KJD_Web.BLL.WXXD.Dtos;
|
||||
using KJD_Web.BLL.WXXD.Requests;
|
||||
using KJD_Web.Model;
|
||||
using KJD_Web.Model.WxModel;
|
||||
using KJD_Web.Requests;
|
||||
using KJD_Web.Utils;
|
||||
using NaiBa.Util.Extension;
|
||||
using NaiBa.Util.Helper;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Store.Framework.Dtos;
|
||||
using Store.Framework.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
|
||||
@@ -1,92 +1,102 @@
|
||||
using Autofac;
|
||||
using Autofac.Integration.WebApi;
|
||||
using FreeSql;
|
||||
using KJD_Web.Repository;
|
||||
using MAX.Core.DependencyInjection;
|
||||
using MAX.Core.Logger;
|
||||
using MAX.Framework.Logger;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Web;
|
||||
//using Autofac;
|
||||
//using Autofac.Core;
|
||||
//using Autofac.Integration.WebApi;
|
||||
//using FreeSql;
|
||||
//using KJD_Web.Repository;
|
||||
//using MAX.Core;
|
||||
//using MAX.Core.DependencyInjection;
|
||||
//using MAX.Core.Helpers;
|
||||
//using MAX.Core.Interfaces;
|
||||
//using MAX.Core.Logger;
|
||||
//using MAX.Core.Reflections;
|
||||
//using MAX.Framework.Logger;
|
||||
//using Store.Framework.Commons;
|
||||
//using Store.VirtualLogistics.Services;
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Configuration;
|
||||
//using System.Diagnostics;
|
||||
//using System.Linq;
|
||||
//using System.Reflection;
|
||||
//using System.Web;
|
||||
//using System.Web.Services.Description;
|
||||
|
||||
namespace KJD_Web;
|
||||
//namespace KJD_Web;
|
||||
|
||||
public class ContainerConfig
|
||||
{
|
||||
//public class ContainerConfig
|
||||
//{
|
||||
|
||||
public static IContainer BuildContainer()
|
||||
{
|
||||
var builder = new ContainerBuilder();
|
||||
var appAssembly = Assembly.GetExecutingAssembly();
|
||||
// public static IContainer BuildContainer()
|
||||
// {
|
||||
// var builder = new ContainerBuilder();
|
||||
// var appAssembly = StoreAppTypeFinder.Current.GetAssemblies().ToArray();
|
||||
|
||||
var connection = ConfigurationManager.ConnectionStrings["ConnKJD"];
|
||||
if (connection == null || string.IsNullOrWhiteSpace(connection.ConnectionString))
|
||||
{
|
||||
throw new ConfigurationErrorsException("未配置连接字符串:ConnKJD");
|
||||
}
|
||||
// var connection = ConfigurationManager.ConnectionStrings["ConnKJD"];
|
||||
// if (connection == null || string.IsNullOrWhiteSpace(connection.ConnectionString))
|
||||
// {
|
||||
// throw new ConfigurationErrorsException("未配置连接字符串:ConnKJD");
|
||||
// }
|
||||
// var ss = StoreAppTypeFinder.Current.Find<VirtualLogisticsService>();
|
||||
// // ImageCacheService 使用独立的 imagecache 数据库。
|
||||
// builder.Register(_ =>
|
||||
// {
|
||||
// return new FreeSqlBuilder()
|
||||
// .UseConnectionString(
|
||||
// DataType.MySql,
|
||||
// connection.ConnectionString)
|
||||
// .Build();
|
||||
// })
|
||||
// .As<IFreeSql>()
|
||||
// .SingleInstance();
|
||||
|
||||
// ImageCacheService 使用独立的 imagecache 数据库。
|
||||
builder.Register(_ =>
|
||||
{
|
||||
return new FreeSqlBuilder()
|
||||
.UseConnectionString(
|
||||
DataType.MySql,
|
||||
connection.ConnectionString)
|
||||
.Build();
|
||||
})
|
||||
.As<IFreeSql>()
|
||||
.SingleInstance();
|
||||
|
||||
builder.RegisterGeneric(typeof(AutofacRepository<>))
|
||||
.As(typeof(IBaseRepository<>))
|
||||
.UsingConstructor(typeof(IFreeSql))
|
||||
.InstancePerRequest();
|
||||
// builder.RegisterGeneric(typeof(AutofacRepository<>))
|
||||
// .As(typeof(IBaseRepository<>))
|
||||
// .UsingConstructor(typeof(IFreeSql))
|
||||
// .InstancePerRequest();
|
||||
|
||||
|
||||
// 注册 Web API 所有 Controller
|
||||
builder.RegisterApiControllers(appAssembly);
|
||||
builder.RegisterInstance(NLogger.Instance).As<ILoggerFacade>().SingleInstance();
|
||||
// // 注册 Web API 所有 Controller
|
||||
// builder.RegisterApiControllers(appAssembly);
|
||||
// builder.RegisterInstance(NLogger.Instance).As<ILoggerFacade>().SingleInstance();
|
||||
|
||||
|
||||
|
||||
|
||||
#region 注册所有IOC接口
|
||||
// #region 注册所有IOC接口
|
||||
|
||||
Type typeSingleton = typeof(ISingletonDependency);
|
||||
builder.RegisterAssemblyTypes(appAssembly)
|
||||
.Where(a =>
|
||||
typeSingleton.IsAssignableFrom(a)
|
||||
&& a.IsClass
|
||||
&& !a.IsAbstract
|
||||
)
|
||||
.AsImplementedInterfaces()
|
||||
.AsSelf()
|
||||
.SingleInstance();
|
||||
// Type typeSingleton = typeof(ISingletonDependency);
|
||||
// builder.RegisterAssemblyTypes(appAssembly)
|
||||
// .Where(a =>
|
||||
// typeSingleton.IsAssignableFrom(a)
|
||||
// && a.IsClass
|
||||
// && !a.IsAbstract
|
||||
// )
|
||||
// .AsImplementedInterfaces()
|
||||
// .AsSelf()
|
||||
// .SingleInstance();
|
||||
|
||||
Type typeTransient = typeof(ITransientDependency);
|
||||
builder.RegisterAssemblyTypes(appAssembly)
|
||||
.Where(a =>
|
||||
typeTransient.IsAssignableFrom(a)
|
||||
&& a.IsClass
|
||||
&& !a.IsAbstract
|
||||
)
|
||||
.AsImplementedInterfaces()
|
||||
.AsSelf()
|
||||
.InstancePerDependency();
|
||||
// Type typeTransient = typeof(ITransientDependency);
|
||||
// builder.RegisterAssemblyTypes(appAssembly)
|
||||
// .Where(a =>
|
||||
// typeTransient.IsAssignableFrom(a)
|
||||
// && a.IsClass
|
||||
// && !a.IsAbstract
|
||||
// )
|
||||
// .AsImplementedInterfaces()
|
||||
// .AsSelf()
|
||||
// .InstancePerDependency();
|
||||
|
||||
Type typeScoped = typeof(IScopedDependency);
|
||||
builder.RegisterAssemblyTypes(appAssembly)
|
||||
.Where(a => typeScoped.IsAssignableFrom(a) && a.IsClass && !a.IsAbstract)
|
||||
.AsImplementedInterfaces()
|
||||
.AsSelf()
|
||||
.InstancePerRequest();
|
||||
// Type typeScoped = typeof(IScopedDependency);
|
||||
// builder.RegisterAssemblyTypes(appAssembly)
|
||||
// .Where(a => typeScoped.IsAssignableFrom(a) && a.IsClass && !a.IsAbstract)
|
||||
// .AsImplementedInterfaces()
|
||||
// .AsSelf()
|
||||
// .InstancePerRequest();
|
||||
|
||||
#endregion
|
||||
// #endregion
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
// var app = builder.Build();
|
||||
// return app;
|
||||
// }
|
||||
|
||||
}
|
||||
//}
|
||||
@@ -1,6 +1,7 @@
|
||||
using KJD_Web.BLL.WXXD;
|
||||
using KJD_Web.Requests;
|
||||
using KJD_Web.Utils;
|
||||
using Store.Framework.Base;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using KJD_Web.Model;
|
||||
using KJD_Web.Services;
|
||||
using KJD_Web.Services;
|
||||
using MAX.Core.Logger;
|
||||
using MySqlX.XDevAPI.Common;
|
||||
using Store.Framework.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Web.Http;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
using KJD_Web.Model;
|
||||
using KJD_Web.Requests.Users;
|
||||
using KJD_Web.Requests.Users;
|
||||
using KJD_Web.Responses.Users;
|
||||
using KJD_Web.Services.Users;
|
||||
using Store.Framework.Base;
|
||||
using Store.Framework.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using KJD_Web.BLL.WXXD;
|
||||
using KJD_Web.Model;
|
||||
using KJD_Web.Requests;
|
||||
using KJD_Web.Requests.Users;
|
||||
using KJD_Web.Utils;
|
||||
using NaiBa.Util.Extension;
|
||||
using Store.Framework.Dtos;
|
||||
using Store.Framework.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using KJD_Web.BLL.WXXD;
|
||||
using KJD_Web.Model;
|
||||
using KJD_Web.Requests;
|
||||
using KJD_Web.Requests.Users;
|
||||
using KJD_Web.Services.Users;
|
||||
using MAX.Core.Logger;
|
||||
using NaiBa.Util.Extension;
|
||||
using Org.BouncyCastle.Ocsp;
|
||||
using Store.Framework.Dtos;
|
||||
using Store.Framework.Models;
|
||||
using System;
|
||||
using System.Web.Http;
|
||||
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace MAX.Core.Logger
|
||||
{
|
||||
/// <summary>
|
||||
/// 日志操作
|
||||
/// </summary>
|
||||
public interface ILoggerFacade
|
||||
{
|
||||
/// <summary>
|
||||
/// 调试级别是否启用
|
||||
/// </summary>
|
||||
bool IsDebugEnabled { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 调试
|
||||
/// </summary>
|
||||
void Debug(Exception ex, string message);
|
||||
/// <summary>
|
||||
/// 调试
|
||||
/// </summary>
|
||||
/// <param name="message">日志消息</param>
|
||||
void Debug(string message);
|
||||
/// <summary>
|
||||
/// 信息
|
||||
/// </summary>
|
||||
void Info(Exception ex, string message);
|
||||
/// <summary>
|
||||
/// 信息
|
||||
/// </summary>
|
||||
/// <param name="message">日志消息</param>
|
||||
void Info(string message);
|
||||
/// <summary>
|
||||
/// 警告
|
||||
/// </summary>
|
||||
void Warn(Exception ex, string message);
|
||||
/// <summary>
|
||||
/// 警告
|
||||
/// </summary>
|
||||
/// <param name="message">日志消息</param>
|
||||
void Warn(string message);
|
||||
/// <summary>
|
||||
/// 错误
|
||||
/// </summary>
|
||||
void Error(Exception ex, string message);
|
||||
/// <summary>
|
||||
/// 错误
|
||||
/// </summary>
|
||||
/// <param name="message">日志消息</param>
|
||||
void Error(string message);
|
||||
/// <summary>
|
||||
/// 致命错误
|
||||
/// </summary>
|
||||
void Fatal(Exception ex, string message);
|
||||
/// <summary>
|
||||
/// 致命错误
|
||||
/// </summary>
|
||||
/// <param name="message">日志消息</param>
|
||||
void Fatal(string message);
|
||||
void Error(Exception ex);
|
||||
|
||||
/// <summary>
|
||||
/// 写入日志
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="level"></param>
|
||||
void Log(string message, LogLevel level);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
namespace MAX.Core.Logger
|
||||
{
|
||||
/// <summary>
|
||||
/// 日志等级
|
||||
/// </summary>
|
||||
public enum LogLevel
|
||||
{
|
||||
Trace = 0,
|
||||
Debug = 1,
|
||||
Info = 2,
|
||||
Warn = 3,
|
||||
Error = 4,
|
||||
Fatal = 5,
|
||||
None = 6
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace MAX.Core.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// 作用域(每个 Scope/请求一个实例)
|
||||
/// </summary>
|
||||
public interface IScopedDependency
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace MAX.Core.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// 单例
|
||||
/// </summary>
|
||||
public interface ISingletonDependency
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace MAX.Core.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// 每次实例化
|
||||
/// </summary>
|
||||
public interface ITransientDependency
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Autofac;
|
||||
using Autofac.Integration.WebApi;
|
||||
using AutoMapper;
|
||||
using FreeSql;
|
||||
using KJD_Web.Repository;
|
||||
using KJD_Web.Utils;
|
||||
@@ -8,6 +9,7 @@ using MAX.Core.Logger;
|
||||
using MAX.Framework.Logger;
|
||||
using MySql.Data.MySqlClient;
|
||||
using NLog;
|
||||
using Store.Framework.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
@@ -27,30 +29,15 @@ namespace KJD_Web
|
||||
NLogger.Instance.Info("应用程序启动");
|
||||
var container = ContainerConfig.BuildContainer();
|
||||
|
||||
|
||||
// 让 Web API 用 Autofac 解析 Controller
|
||||
GlobalConfiguration.Configuration.DependencyResolver =
|
||||
new AutofacWebApiDependencyResolver(container);
|
||||
GlobalConfiguration.Configure(WebApiConfig.Register);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static IFreeSql CreateImageCacheFreeSql()
|
||||
{
|
||||
var connection = ConfigurationManager.ConnectionStrings["ConnKJD"];
|
||||
if (connection == null || string.IsNullOrWhiteSpace(connection.ConnectionString))
|
||||
{
|
||||
throw new ConfigurationErrorsException("未配置连接字符串:ConnKJD");
|
||||
}
|
||||
//var connectionBuilder = new MySqlConnectionStringBuilder(connection.ConnectionString)
|
||||
//{
|
||||
// Database = "imagecache"
|
||||
//};
|
||||
|
||||
return new FreeSqlBuilder()
|
||||
.UseConnectionString(DataType.MySql, connection.ConnectionString)
|
||||
.UseAutoSyncStructure(false)
|
||||
.Build();
|
||||
}
|
||||
|
||||
protected void Session_Start(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
@@ -190,7 +190,6 @@
|
||||
<Compile Include="BLL\WXXD\WXShopRevenueStatisticsManage.cs" />
|
||||
<Compile Include="BLL\WXXD\WXUserManage.cs" />
|
||||
<Compile Include="ContainerConfig.cs" />
|
||||
<Compile Include="Controllers\ApiControllerBase.cs" />
|
||||
<Compile Include="Controllers\AsmxApiController.cs" />
|
||||
<Compile Include="Controllers\ImageCacheController.cs" />
|
||||
<Compile Include="Controllers\WX\OEMController.cs" />
|
||||
@@ -214,12 +213,7 @@
|
||||
<Compile Include="Controllers\UpdateController.cs" />
|
||||
<Compile Include="Controllers\ShopController.cs" />
|
||||
<Compile Include="Controllers\UserController.cs" />
|
||||
<Compile Include="Core\Logger\ILoggerFacade.cs" />
|
||||
<Compile Include="Core\Logger\LogLevel.cs" />
|
||||
<Compile Include="Core\Logger\NLogger.cs" />
|
||||
<Compile Include="DependencyInjection\IScopedDependency.cs" />
|
||||
<Compile Include="DependencyInjection\ISingletonDependency.cs" />
|
||||
<Compile Include="DependencyInjection\ITransientDependency.cs" />
|
||||
<Compile Include="Mappers\WeOrderMapper.cs" />
|
||||
<Compile Include="Model\WxModel\oms_wei_ewaybill_path.cs" />
|
||||
<Compile Include="Entitys\OEMEntity.cs" />
|
||||
<Compile Include="Entitys\UserPaymentRecordEntity.cs" />
|
||||
@@ -233,7 +227,6 @@
|
||||
<Compile Include="Entitys\UserPointsRecordEntity.cs" />
|
||||
<Compile Include="Entitys\UserPointsShopExpire.cs" />
|
||||
<Compile Include="LogHelper.cs" />
|
||||
<Compile Include="Model\ApiResult.cs" />
|
||||
<Compile Include="Model\ErpModel\ErpMerchantInfo.cs" />
|
||||
<Compile Include="Model\JSTDownProdSkuInfo.cs" />
|
||||
<Compile Include="Model\PddModel\BuyerLoginInfo.cs" />
|
||||
@@ -278,8 +271,8 @@
|
||||
<Compile Include="Services\Users\UserService.OEM.cs" />
|
||||
<Compile Include="Services\Users\UserService.cs" />
|
||||
<Compile Include="SignValidateFilterAttribute.cs" />
|
||||
<Compile Include="Utils\ApiRequestLogger.cs" />
|
||||
<Compile Include="GetPostActionSelector.cs" />
|
||||
<Compile Include="Startup.cs" />
|
||||
<Compile Include="WebApiConfig.cs" />
|
||||
<Compile Include="Upload\Prod\BaseClass.cs" />
|
||||
<Compile Include="Upload\Prod\BaseWxProd.cs" />
|
||||
@@ -297,8 +290,6 @@
|
||||
<Compile Include="Upload\Prod\WXProd.aspx.designer.cs">
|
||||
<DependentUpon>WXProd.aspx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Utils\HttpUtils.cs" />
|
||||
<Compile Include="Utils\RandomUtils.cs" />
|
||||
<Compile Include="Global.asax.cs">
|
||||
<DependentUpon>Global.asax</DependentUpon>
|
||||
</Compile>
|
||||
@@ -316,21 +307,6 @@
|
||||
<Compile Include="Model\TemuDBOrderInfo.cs" />
|
||||
<Compile Include="Model\UserLoginResultParam.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Utils\EncrypUtil.cs" />
|
||||
<Compile Include="Utils\Extension\Extension.Convert.cs" />
|
||||
<Compile Include="Utils\Extension\Extension.Enum.cs" />
|
||||
<Compile Include="Utils\Extension\Extension.Exception.cs" />
|
||||
<Compile Include="Utils\Extension\Extension.Linq.cs" />
|
||||
<Compile Include="Utils\Extension\Extension.Validate.cs" />
|
||||
<Compile Include="Utils\Helper\HtmlHelper.cs" />
|
||||
<Compile Include="Utils\Helper\JsonHelper.cs" />
|
||||
<Compile Include="Utils\Helper\ReflectionHelper.cs" />
|
||||
<Compile Include="Utils\Helper\RegexHelper.cs" />
|
||||
<Compile Include="Utils\HtmlUtils.cs" />
|
||||
<Compile Include="Utils\JsonUtils.cs" />
|
||||
<Compile Include="Utils\MySqlUtils.cs" />
|
||||
<Compile Include="Utils\RegexUtils.cs" />
|
||||
<Compile Include="Utils\TimeUtils.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
@@ -349,6 +325,27 @@
|
||||
<Version>3.5.311</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MAX.Core\MAX.Core.csproj">
|
||||
<Project>{281F6609-E5BC-8A5C-8382-CD7C4670ACBF}</Project>
|
||||
<Name>MAX.Core</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Store.Contracts\Store.Contracts.csproj">
|
||||
<Project>{3694ede2-3192-44e6-b45c-9cdc99916876}</Project>
|
||||
<Name>Store.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Store.Framework\Store.Framework.csproj">
|
||||
<Project>{cd6fb773-0431-4fae-9e30-65953118febf}</Project>
|
||||
<Name>Store.Framework</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Store.SyncLogistics\Store.SyncLogistics.csproj">
|
||||
<Project>{11af9af8-8da0-e764-d5ff-8ef35e1ff7c8}</Project>
|
||||
<Name>Store.SyncLogistics</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Services\Order\" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
using AutoMapper;
|
||||
using KJD_Web.Entitys;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace KJD_Web.Mapper;
|
||||
|
||||
public class WeOrderProfile : Profile
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using KJD_Web.Model;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Store.Framework.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -1,21 +1,9 @@
|
||||
using Newtonsoft.Json;
|
||||
using Store.Framework.Dtos;
|
||||
using System;
|
||||
|
||||
namespace KJD_Web.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// Sign签名
|
||||
/// </summary>
|
||||
public class SignRequestBase
|
||||
{
|
||||
public string time { get; set; }
|
||||
public string code { get; set; }
|
||||
public string code_version { get; set; }
|
||||
public string version { get; set; }
|
||||
[JsonProperty("user_name")]
|
||||
public string UserName { get; set; }
|
||||
public string path { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Store.Framework.Dtos;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Store.Framework.Dtos;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using KJD_Web.Entitys;
|
||||
using KJD_Web.Model.WxModel;
|
||||
using MySqlX.XDevAPI;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
@@ -267,8 +269,170 @@ namespace KJD_Web.Services.Users
|
||||
summary.ConsumeTotal = (long)Math.Round(sum * 100m);
|
||||
return summary;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 填充历史数据
|
||||
/// </summary>
|
||||
// public void FillHistoryOemAmount()
|
||||
// {
|
||||
// List<UserPaymentRecordSmall> data = new List<UserPaymentRecordSmall>();
|
||||
// string path = @"d:\ddddd.json";
|
||||
// if (File.Exists(path))
|
||||
// {
|
||||
// data = JsonConvert.DeserializeObject<List<UserPaymentRecordSmall>>(File.ReadAllText(path));
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// data = _freeSql.Select<UserPaymentRecordSmall>()
|
||||
// .Where(a => a.type == 20 || a.type == 26)
|
||||
// .Where(a => a.create_time > DateTime.Parse("2026-09-01 00:00:00"))
|
||||
// .OrderBy(a => a.id)
|
||||
// .ToList();
|
||||
// }
|
||||
// Debug.WriteLine($"共;{data.Count}");
|
||||
// int max = 500;
|
||||
// int count = 0;
|
||||
// List<UserPaymentRecordSmall> list = new List<UserPaymentRecordSmall>();
|
||||
// foreach (var item in data)
|
||||
// {
|
||||
// //if (item.IsFill) continue;
|
||||
// try
|
||||
// {
|
||||
// if (!string.IsNullOrEmpty(item.remark))
|
||||
// {
|
||||
// item.OrderId = item.remark.Split(':')[1];
|
||||
// list.Add(item);
|
||||
// if (list.Count == max)
|
||||
// {
|
||||
// var orderNames = list.Select(a => a.OrderId);
|
||||
// List<weiOrder> orders = _freeSql.Select<weiOrder>()
|
||||
// .Where(a => orderNames.Contains(a.order_id))
|
||||
// .ToList();
|
||||
// fillOemAmount(list, orders);
|
||||
// var uCount = _freeSql.Update<UserPaymentRecordSmall>()
|
||||
// .SetSource(list)
|
||||
// .UpdateColumns(a => new { a.oem_amount })
|
||||
// .ExecuteAffrows();
|
||||
// if (uCount != list.Count)
|
||||
// {
|
||||
// Debug.WriteLine("数量不对");
|
||||
// }
|
||||
// list.ForEach(a => a.IsFill = true);
|
||||
// File.WriteAllText(path, JsonConvert.SerializeObject(data));
|
||||
// count += list.Count;
|
||||
// list.Clear();
|
||||
// Debug.WriteLine($"成功修改;{list.Count}");
|
||||
// Debug.WriteLine($"共修改;{count}");
|
||||
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// private void fillOemAmount(List<UserPaymentRecordSmall> list, List<weiOrder> orders)
|
||||
// {
|
||||
// foreach (var item in list)
|
||||
// {
|
||||
// var order = orders.FirstOrDefault(a => a.order_id == item.OrderId);
|
||||
// if (order != null)
|
||||
// {
|
||||
// item.oem_amount = getoemamount(order.province_name, item.amount.Value, item.type);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// private Dictionary<string, decimal> DicWarehousePostage = new Dictionary<string, decimal>
|
||||
// {
|
||||
// { "湖北", 2.2m },
|
||||
//{ "湖南", 2.2m },
|
||||
//{ "江西", 2.2m },
|
||||
//{ "河南", 2.2m },
|
||||
//{ "上海", 3m },
|
||||
//{ "浙江", 2.2m },
|
||||
//{ "安徽", 2.2m },
|
||||
//{ "江苏", 2.2m },
|
||||
//{ "河北", 2.2m },
|
||||
//{ "山东", 2.2m },
|
||||
//{ "福建", 2.2m },
|
||||
//{ "广东", 2.2m },
|
||||
//{ "深圳", 2.8m },
|
||||
//{ "天津", 2.2m },
|
||||
//{ "北京", 3.2m },
|
||||
//{ "山西", 2.2m },
|
||||
//{ "陕西", 2.2m },
|
||||
//{ "广西", 2.2m },
|
||||
//{ "云南", 2.2m },
|
||||
//{ "贵州", 2.2m },
|
||||
//{ "四川", 2.2m },
|
||||
//{ "重庆", 2.2m },
|
||||
//{ "黑龙江", 2.7m },
|
||||
//{ "吉林", 2.7m },
|
||||
//{ "辽宁", 2.7m },
|
||||
//{ "青海", 2.7m },
|
||||
//{ "宁夏", 2.7m },
|
||||
//{ "甘肃", 2.7m },
|
||||
//{ "内蒙", 4.5m },
|
||||
//{ "海南", 4.5m },
|
||||
//{ "新疆", 12.5m },
|
||||
//{ "西藏", 12.5m },
|
||||
// };
|
||||
// private decimal getoemamount(string province, decimal amount, int type)
|
||||
// {
|
||||
// foreach (var item in DicWarehousePostage)
|
||||
// {
|
||||
// if (province.StartsWith(item.Key))
|
||||
// {
|
||||
// if (type == 20)
|
||||
// return amount - item.Value;
|
||||
// if (type == 26)
|
||||
// return amount - item.Value - 0.3m;
|
||||
|
||||
// }
|
||||
// }
|
||||
// return amount;
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
//[FreeSql.DataAnnotations.Table(Name = "wxxd.user_payment_record")]
|
||||
//public class UserPaymentRecordSmall()
|
||||
//{
|
||||
// public long id { get; set; }
|
||||
// public int type { get; set; }
|
||||
// /// <summary>
|
||||
// /// 金额(元)
|
||||
// /// </summary>
|
||||
// public decimal? amount { get; set; }
|
||||
// /// <summary>
|
||||
// /// 归属oem用户的金额
|
||||
// /// </summary>
|
||||
// public decimal? oem_amount { get; set; }
|
||||
// public string remark { get; set; }
|
||||
|
||||
// public DateTime create_time { get; set; }
|
||||
|
||||
// [FreeSql.DataAnnotations.Column(IsIgnore = true)]
|
||||
// public bool IsFill { get; set; }
|
||||
|
||||
// [FreeSql.DataAnnotations.Column(IsIgnore = true)]
|
||||
// public string OrderId { get; set; }
|
||||
//}
|
||||
//[FreeSql.DataAnnotations.Table(Name = "erp.oms_wei_order")]
|
||||
//public class weiOrder
|
||||
//{
|
||||
// public string order_id { get; set; }
|
||||
// public string province_name { get; set; }
|
||||
//}
|
||||
|
||||
|
||||
public class UserAmountSummary
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using KJD_Web.Model;
|
||||
using KJD_Web.Requests;
|
||||
using KJD_Web.Utils;
|
||||
using KJD_Web.Utils;
|
||||
using Newtonsoft.Json;
|
||||
using Store.Framework.Dtos;
|
||||
using Store.Framework.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using Autofac;
|
||||
using FreeSql;
|
||||
using KJD_Web.Repository;
|
||||
using MAX.Core.DependencyInjection;
|
||||
using MAX.Core.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace KJD_Web;
|
||||
|
||||
public class Startup : IStartup
|
||||
{
|
||||
public int Priority => IntPriority.Normal;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Register(IServiceRegistrar registrar)
|
||||
{
|
||||
(registrar.Services as ContainerBuilder).RegisterGeneric(typeof(AutofacRepository<>))
|
||||
.As(typeof(IBaseRepository<>))
|
||||
.UsingConstructor(typeof(IFreeSql))
|
||||
.InstancePerRequest();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -82,6 +82,13 @@
|
||||
<staticContent>
|
||||
<mimeMap fileExtension=".asmx" mimeType="application/octet-stream" />
|
||||
</staticContent>
|
||||
<security>
|
||||
<requestFiltering>
|
||||
<verbs>
|
||||
<add verb="CONNECT" allowed="false" />
|
||||
</verbs>
|
||||
</requestFiltering>
|
||||
</security>
|
||||
</system.webServer>
|
||||
<system.codedom>
|
||||
<compilers>
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
<package id="MySql.Data" version="8.0.30" targetFramework="net472" />
|
||||
<package id="Newtonsoft.Json" version="13.0.4" targetFramework="net472" />
|
||||
<package id="Newtonsoft.Json.Bson" version="1.0.2" targetFramework="net472" />
|
||||
<package id="NLog" version="6.2.0" targetFramework="net472" />
|
||||
<package id="Portable.BouncyCastle" version="1.9.0" targetFramework="net472" />
|
||||
<package id="System.Buffers" version="4.6.1" targetFramework="net472" />
|
||||
<package id="System.Diagnostics.DiagnosticSource" version="10.0.0" targetFramework="net472" />
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
using System;
|
||||
|
||||
namespace MAX.Core.Caches;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存
|
||||
/// </summary>
|
||||
public interface ICache
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否存在指定键的缓存
|
||||
/// </summary>
|
||||
/// <param name="key">缓存键</param>
|
||||
bool Exists(string key);
|
||||
/// <summary>
|
||||
/// 从缓存中获取数据
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
T Get<T>(string key);
|
||||
/// <summary>
|
||||
/// 从缓存中获取数据,如果不存在,则执行获取数据操作并添加到缓存中
|
||||
/// </summary>
|
||||
/// <typeparam name="T">缓存数据类型</typeparam>
|
||||
/// <param name="key">缓存键</param>
|
||||
/// <param name="func">获取数据操作</param>
|
||||
T Get<T>(string key, Func<T> func);
|
||||
/// <summary>
|
||||
/// 当缓存数据不存在则添加,已存在不会添加,添加成功返回true
|
||||
/// </summary>
|
||||
/// <typeparam name="T">缓存数据类型</typeparam>
|
||||
/// <param name="key">缓存键</param>
|
||||
/// <param name="value">值</param>
|
||||
bool TryAdd<T>(string key, T value);
|
||||
/// <summary>
|
||||
/// 覆盖添加
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
bool OverlayAdd<T>(string key, T value);
|
||||
/// <summary>
|
||||
/// 移除缓存
|
||||
/// </summary>
|
||||
/// <param name="key">缓存键</param>
|
||||
void Remove(string key);
|
||||
/// <summary>
|
||||
/// 清空缓存
|
||||
/// </summary>
|
||||
void Clear();
|
||||
}
|
||||
|
||||
public interface ICache<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否存在指定键的缓存
|
||||
/// </summary>
|
||||
/// <param name="key">缓存键</param>
|
||||
bool Exists(string key);
|
||||
|
||||
/// <summary>
|
||||
/// 从缓存中获取数据,如果不存在,则执行获取数据操作并添加到缓存中
|
||||
/// </summary>
|
||||
/// <typeparam name="T">缓存数据类型</typeparam>
|
||||
/// <param name="key">缓存键</param>
|
||||
T Get(string key);
|
||||
/// <summary>
|
||||
/// 从缓存中获取数据,如果不存在,则执行获取数据操作并添加到缓存中
|
||||
/// </summary>
|
||||
/// <typeparam name="T">缓存数据类型</typeparam>
|
||||
/// <param name="key">缓存键</param>
|
||||
/// <param name="func">获取数据操作</param>
|
||||
T Get(string key, Func<T> func);
|
||||
/// <summary>
|
||||
/// 当缓存数据不存在则添加,已存在不会添加,添加成功返回true
|
||||
/// </summary>
|
||||
/// <typeparam name="T">缓存数据类型</typeparam>
|
||||
/// <param name="key">缓存键</param>
|
||||
/// <param name="value">值</param>
|
||||
bool TryAdd(string key, T value);
|
||||
/// <summary>
|
||||
/// 覆盖添加
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
bool OverlayAdd(string key, T value);
|
||||
/// <summary>
|
||||
/// 移除缓存
|
||||
/// </summary>
|
||||
/// <param name="key">缓存键</param>
|
||||
void Remove(string key);
|
||||
/// <summary>
|
||||
/// 清空缓存
|
||||
/// </summary>
|
||||
void Clear();
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
|
||||
using MAX.Core.DependencyInjection;
|
||||
using MAX.Core.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
|
||||
namespace MAX.Core.Caches;
|
||||
|
||||
/// <summary>
|
||||
/// 内存缓存
|
||||
/// </summary>
|
||||
public class MemoryCache : ICache, ISingletonDependency
|
||||
{
|
||||
//private static readonly Object _locker = new object();
|
||||
private readonly ConcurrentDictionary<string, object> _cache = new();
|
||||
|
||||
public virtual void Clear()
|
||||
{
|
||||
_cache.Clear();
|
||||
}
|
||||
|
||||
public virtual bool Exists(string key)
|
||||
{
|
||||
return _cache.ContainsKey(key);
|
||||
}
|
||||
public virtual T Get<T>(string key)
|
||||
{
|
||||
if (Exists(key))
|
||||
{
|
||||
return (T)_cache[key];
|
||||
}
|
||||
return default;
|
||||
}
|
||||
public virtual TResult Get<TResult>(string key, Func<TResult> func)
|
||||
{
|
||||
if (Exists(key))
|
||||
{
|
||||
return (TResult)_cache[key];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (func != null)
|
||||
{
|
||||
TResult t = func();
|
||||
TryAdd(key, t);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return default;
|
||||
}
|
||||
|
||||
public virtual bool OverlayAdd<T>(string key, T value)
|
||||
{
|
||||
if (Exists(key))
|
||||
{
|
||||
_cache[key] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cache.TryAdd(key, value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual void Remove(string key)
|
||||
{
|
||||
_cache.TryRemove(key, out _);
|
||||
}
|
||||
|
||||
public virtual bool TryAdd<T>(string key, T value)
|
||||
{
|
||||
_cache.AddOrUpdate(key, value, (oldkey, oldvalue) => value);
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取所有Key
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string[] AllKeys()
|
||||
{
|
||||
return _cache.Keys.ToArray();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 单例缓存抽象类
|
||||
/// </summary>
|
||||
/// <typeparam name="TModel">单例对象</typeparam>
|
||||
/// <typeparam name="TValue">缓存类型</typeparam>
|
||||
public abstract class SingleInstanceLittleCache<TModel, TValue> : SingleInstance<TModel>, ICache<TValue> where TModel : class
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, TValue> _cache = new();
|
||||
/// <summary>
|
||||
/// 自定义前缀
|
||||
/// </summary>
|
||||
//public abstract string KeyPrefix { get; }
|
||||
//private string FormatKey(string key)
|
||||
//{
|
||||
// return KeyPrefix + key;
|
||||
//}
|
||||
|
||||
public virtual void Clear()
|
||||
{
|
||||
_cache.Clear();
|
||||
}
|
||||
|
||||
public virtual bool Exists(string key)
|
||||
{
|
||||
return _cache.ContainsKey(key);
|
||||
}
|
||||
public virtual TValue Get(string key)
|
||||
{
|
||||
if (Exists(key))
|
||||
{
|
||||
return _cache[key];
|
||||
}
|
||||
return default;
|
||||
}
|
||||
public virtual TValue Get(string key, Func<TValue> func)
|
||||
{
|
||||
if (Exists(key))
|
||||
{
|
||||
return _cache[key];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (func != null)
|
||||
{
|
||||
TValue t = func();
|
||||
TryAdd(key, t);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return default;
|
||||
}
|
||||
|
||||
public virtual bool OverlayAdd(string key, TValue value)
|
||||
{
|
||||
if (Exists(key))
|
||||
{
|
||||
_cache[key] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cache.TryAdd(key, value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual void Remove(string key)
|
||||
{
|
||||
_cache.TryRemove(key, out _);
|
||||
}
|
||||
|
||||
public virtual bool TryAdd(string key, TValue value)
|
||||
{
|
||||
_cache.AddOrUpdate(key, value, (oldkey, oldvalue) => value);
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取所有Key
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string[] AllKeys()
|
||||
{
|
||||
return _cache.Keys.ToArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace MAX.Core.Commons;
|
||||
|
||||
/// <summary>
|
||||
/// 公共Value
|
||||
/// </summary>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
public class CommonValue<TValue>
|
||||
{
|
||||
public CommonValue() { }
|
||||
public CommonValue(TValue value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
public TValue Value { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 公共TextValue
|
||||
/// </summary>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
public class CommonTextValue<TValue> : CommonValue<TValue>
|
||||
{
|
||||
public string Text { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 公共TextValue
|
||||
/// </summary>
|
||||
public class CommonTextValue : CommonTextValue<string>
|
||||
{
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 默认公共键值对 Key Value
|
||||
/// </summary>
|
||||
public class CommonKeyValue : CommonValue<string>
|
||||
{
|
||||
public string Key { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
|
||||
namespace MAX.Core.Commons;
|
||||
|
||||
/// <summary>
|
||||
/// 通用返回
|
||||
/// </summary>
|
||||
public class Result
|
||||
{
|
||||
/// <summary>
|
||||
/// 返回结果是否成功
|
||||
/// </summary>
|
||||
public bool Success { get; set; } = false;
|
||||
/// <summary>
|
||||
/// 返回消息
|
||||
/// </summary>
|
||||
public string Msg { get; set; } = "";
|
||||
/// <summary>
|
||||
/// 返回内容
|
||||
/// </summary>
|
||||
public object Data { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// 返回状态码
|
||||
/// </summary>
|
||||
public int Code { get; set; }
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 通用返回 指定Data类型
|
||||
/// </summary>
|
||||
/// <typeparam name="TData">数据类型</typeparam>
|
||||
public class Result<TData> : Result
|
||||
{
|
||||
/// <summary>
|
||||
/// 返回内容
|
||||
/// </summary>
|
||||
public new TData Data { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 通用返回
|
||||
/// </summary>
|
||||
/// <typeparam name="TStatus">状态类型枚举</typeparam>
|
||||
/// <typeparam name="TData">数据类型</typeparam>
|
||||
public class Result<TStatus, TData> : Result where TStatus : Enum
|
||||
{
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
public TStatus Status { get; set; }
|
||||
/// <summary>
|
||||
/// 返回内容
|
||||
/// </summary>
|
||||
public new TData Data { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace MAX.Core.Cryptography;
|
||||
|
||||
public class Base64Helper
|
||||
{
|
||||
/// <summary>
|
||||
/// Base64加密
|
||||
/// </summary>
|
||||
/// <param name="codeName">加密采用的编码方式</param>
|
||||
/// <param name="source">待加密的明文</param>
|
||||
/// <returns></returns>
|
||||
public static string Encode(string source, Encoding encode)
|
||||
{
|
||||
string encodeValue = "";
|
||||
byte[] bytes = encode.GetBytes(source);
|
||||
try
|
||||
{
|
||||
encodeValue = Convert.ToBase64String(bytes);
|
||||
}
|
||||
catch
|
||||
{
|
||||
encodeValue = source;
|
||||
}
|
||||
return encodeValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base64加密,采用utf8编码方式加密
|
||||
/// </summary>
|
||||
/// <param name="source">待加密的明文</param>
|
||||
/// <returns>加密后的字符串</returns>
|
||||
public static string Encode(string source)
|
||||
{
|
||||
return Encode(source, Encoding.UTF8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base64解密
|
||||
/// </summary>
|
||||
/// <param name="codeName">解密采用的编码方式,注意和加密时采用的方式一致</param>
|
||||
/// <param name="result">待解密的密文</param>
|
||||
/// <returns>解密后的字符串</returns>
|
||||
public static string Decode(string result, Encoding encode)
|
||||
{
|
||||
string decode = "";
|
||||
byte[] bytes = Convert.FromBase64String(result);
|
||||
try
|
||||
{
|
||||
decode = encode.GetString(bytes);
|
||||
}
|
||||
catch
|
||||
{
|
||||
decode = result;
|
||||
}
|
||||
return decode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base64解密,采用utf8编码方式解密
|
||||
/// </summary>
|
||||
/// <param name="result">待解密的密文</param>
|
||||
/// <returns>解密后的字符串</returns>
|
||||
public static string Decode(string result)
|
||||
{
|
||||
return Decode(result, Encoding.UTF8);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace MAX.Core.Cryptography;
|
||||
|
||||
public sealed class DESHelper
|
||||
{
|
||||
|
||||
//默认密钥向量
|
||||
private static readonly byte[] IVKey = { 36, 109, 97, 120, 111, 110, 120, 36 };
|
||||
/// <summary>
|
||||
/// DES加密字符串
|
||||
/// </summary>
|
||||
/// <param name="encryptString">待加密的字符串</param>
|
||||
/// <param name="encryptKey">加密密钥,要求为8位</param>
|
||||
/// <returns>加密成功返回加密后的字符串,失败返回源串</returns>
|
||||
public static string Encrypt(string encryptString, string encryptKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
encryptKey = GetSubString(encryptKey, 8, "");
|
||||
encryptKey = encryptKey.PadRight(8, ' ');
|
||||
byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8));
|
||||
byte[] rgbIV = IVKey;
|
||||
byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
|
||||
DES dCSP = DES.Create();
|
||||
MemoryStream mStream = new();
|
||||
CryptoStream cStream = new(mStream, dCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
|
||||
cStream.Write(inputByteArray, 0, inputByteArray.Length);
|
||||
cStream.FlushFinalBlock();
|
||||
return Convert.ToBase64String(mStream.ToArray());
|
||||
}
|
||||
catch
|
||||
{
|
||||
return encryptString;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DES解密字符串
|
||||
/// </summary>
|
||||
/// <param name="decryptString">待解密的字符串</param>
|
||||
/// <param name="decryptKey">解密密钥,要求为8位,和加密密钥相同</param>
|
||||
/// <returns>解密成功返回解密后的字符串,失败返源串</returns>
|
||||
public static string Decrypt(string decryptString, string decryptKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
decryptKey = GetSubString(decryptKey, 0, 8, "");
|
||||
decryptKey = decryptKey.PadRight(8, ' ');
|
||||
byte[] rgbKey = Encoding.UTF8.GetBytes(decryptKey);
|
||||
byte[] rgbIV = IVKey;
|
||||
byte[] inputByteArray = Convert.FromBase64String(decryptString);
|
||||
DES DCSP = DES.Create();
|
||||
|
||||
MemoryStream mStream = new();
|
||||
CryptoStream cStream = new(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
|
||||
cStream.Write(inputByteArray, 0, inputByteArray.Length);
|
||||
cStream.FlushFinalBlock();
|
||||
return Encoding.UTF8.GetString(mStream.ToArray());
|
||||
}
|
||||
catch
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#region 截取字符串函数
|
||||
|
||||
/// <summary>
|
||||
/// 截取字符串函数
|
||||
/// </summary>
|
||||
/// <param name="Str">所要截取的字符串</param>
|
||||
/// <param name="Num">截取字符串的长度</param>
|
||||
/// <returns></returns>
|
||||
public static string GetSubString(string Str, int Num)
|
||||
{
|
||||
if (Str is null or "")
|
||||
{
|
||||
return "";
|
||||
}
|
||||
string outstr = string.Empty;
|
||||
int n = 0;
|
||||
foreach (char ch in Str)
|
||||
{
|
||||
n += Encoding.Default.GetByteCount(ch.ToString());
|
||||
|
||||
if (n > Num)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
outstr += ch;
|
||||
}
|
||||
}
|
||||
|
||||
return outstr;
|
||||
}
|
||||
/// <summary>
|
||||
/// 截取字符串函数,如果超过指定长度则将超出的部分用指定字符串代替
|
||||
/// </summary>
|
||||
/// <param name="Str">所要截取的字符串</param>
|
||||
/// <param name="Num">截取字符串的长度</param>
|
||||
/// <param name="LastStr">截取字符串后省略部分的字符串</param>
|
||||
/// <returns></returns>
|
||||
public static string GetSubString(string Str, int Num, string LastStr)
|
||||
{
|
||||
return GetSubString(Str, 0, Num, LastStr);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 截取字符串,超过部分用指定字符串替换
|
||||
|
||||
/* 宗波于 2010-6-12 日添加, 来源于DiscuzNt */
|
||||
/// <summary>
|
||||
/// 取指定长度的字符串
|
||||
/// </summary>
|
||||
/// <param name="p_SrcString">要检查的字符串</param>
|
||||
/// <param name="p_StartIndex">起始位置</param>
|
||||
/// <param name="p_Length">指定长度</param>
|
||||
/// <param name="p_TailString">用于替换的字符串</param>
|
||||
/// <returns>截取后的字符串</returns>
|
||||
public static string GetSubString(string p_SrcString, int p_StartIndex, int p_Length, string p_TailString)
|
||||
{
|
||||
string myResult = p_SrcString;
|
||||
|
||||
byte[] bComments = Encoding.UTF8.GetBytes(p_SrcString);
|
||||
foreach (char c in Encoding.UTF8.GetChars(bComments))
|
||||
{ //当是日文或韩文时(注:中文的范围:\u4e00 - \u9fa5, 日文在\u0800 - \u4e00, 韩文为\xAC00-\xD7A3)
|
||||
if (c is (> '\u0800' and < '\u4e00') or (> '\xAC00' and < '\xD7A3'))
|
||||
{
|
||||
//if (System.Text.RegularExpressions.Regex.IsMatch(p_SrcString, "[\u0800-\u4e00]+") || System.Text.RegularExpressions.Regex.IsMatch(p_SrcString, "[\xAC00-\xD7A3]+"))
|
||||
//当截取的起始位置超出字段串长度时
|
||||
if (p_StartIndex >= p_SrcString.Length)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
return p_SrcString.Substring(p_StartIndex,
|
||||
p_Length + p_StartIndex > p_SrcString.Length ? p_SrcString.Length - p_StartIndex : p_Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p_Length >= 0)
|
||||
{
|
||||
byte[] bsSrcString = Encoding.Default.GetBytes(p_SrcString);
|
||||
|
||||
//当字符串长度大于起始位置
|
||||
if (bsSrcString.Length > p_StartIndex)
|
||||
{
|
||||
int p_EndIndex = bsSrcString.Length;
|
||||
|
||||
//当要截取的长度在字符串的有效长度范围内
|
||||
if (bsSrcString.Length > p_StartIndex + p_Length)
|
||||
{
|
||||
p_EndIndex = p_Length + p_StartIndex;
|
||||
}
|
||||
else
|
||||
{ //当不在有效范围内时,只取到字符串的结尾
|
||||
|
||||
p_Length = bsSrcString.Length - p_StartIndex;
|
||||
p_TailString = "";
|
||||
}
|
||||
|
||||
int nRealLength = p_Length;
|
||||
int[] anResultFlag = new int[p_Length];
|
||||
byte[] bsResult = null;
|
||||
|
||||
int nFlag = 0;
|
||||
for (int i = p_StartIndex; i < p_EndIndex; i++)
|
||||
{
|
||||
if (bsSrcString[i] > 127)
|
||||
{
|
||||
nFlag++;
|
||||
if (nFlag == 3)
|
||||
{
|
||||
nFlag = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nFlag = 0;
|
||||
}
|
||||
|
||||
anResultFlag[i] = nFlag;
|
||||
}
|
||||
|
||||
if (bsSrcString[p_EndIndex - 1] > 127 && anResultFlag[p_Length - 1] == 1)
|
||||
{
|
||||
nRealLength = p_Length + 1;
|
||||
}
|
||||
|
||||
bsResult = new byte[nRealLength];
|
||||
|
||||
Array.Copy(bsSrcString, p_StartIndex, bsResult, 0, nRealLength);
|
||||
|
||||
myResult = Encoding.Default.GetString(bsResult);
|
||||
myResult += p_TailString;
|
||||
}
|
||||
}
|
||||
|
||||
return myResult;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace MAX.Core.Cryptography;
|
||||
|
||||
public class MD5Helper
|
||||
{
|
||||
/// <summary>
|
||||
/// MD5加密
|
||||
/// </summary>
|
||||
/// <param name="instring"></param>
|
||||
/// <returns></returns>
|
||||
public static string Md5_32(string instring)
|
||||
{
|
||||
return _Md532(instring);
|
||||
}
|
||||
public static string Md5_Lower32(string instring)
|
||||
{
|
||||
return _Md532(instring, true);
|
||||
}
|
||||
public static string _Md532(string instring, bool IsLower = false)
|
||||
{
|
||||
byte[] result = Encoding.UTF8.GetBytes(string.IsNullOrEmpty(instring) ? "" : instring.Trim());
|
||||
MD5 md5 = MD5.Create();
|
||||
byte[] output = md5.ComputeHash(result);
|
||||
string value = BitConverter.ToString(output).Replace("-", "");
|
||||
if (IsLower)
|
||||
{
|
||||
return value.ToLower();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// MD5加密
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static long GetLong(byte[] result)
|
||||
{
|
||||
return
|
||||
Convert.ToInt64(
|
||||
BitConverter.ToString(MD5.Create().ComputeHash(result), 4,
|
||||
8).Replace("-", ""), 16);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MD5 16位加密转long
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <returns></returns>
|
||||
public static long GetLong(string url)
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Convert.ToInt64(BitConverter.ToString(MD5.Create().ComputeHash(Encoding.Default.GetBytes(url)), 4, 8).Replace("-", ""), 16);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.Text;
|
||||
|
||||
namespace MAX.Core.Cryptography;
|
||||
|
||||
/// <summary>
|
||||
/// Url 加密 解密
|
||||
/// </summary>
|
||||
public class UrlHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Url加密
|
||||
/// </summary>
|
||||
/// <param name="codeName">加密采用的编码方式</param>
|
||||
/// <param name="source">待加密的明文</param>
|
||||
/// <returns></returns>
|
||||
public static string Encode(string source, Encoding encode)
|
||||
{
|
||||
return System.Web.HttpUtility.UrlEncode(source, encode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Url加密,采用utf8编码方式加密
|
||||
/// </summary>
|
||||
/// <param name="source">待加密的明文</param>
|
||||
/// <returns>加密后的字符串</returns>
|
||||
public static string Encode(string source)
|
||||
{
|
||||
return Encode(source, Encoding.UTF8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Url解密
|
||||
/// </summary>
|
||||
/// <param name="codeName">解密采用的编码方式,注意和加密时采用的方式一致</param>
|
||||
/// <param name="result">待解密的密文</param>
|
||||
/// <returns>解密后的字符串</returns>
|
||||
public static string Decode(string result, Encoding encode)
|
||||
{
|
||||
return System.Web.HttpUtility.UrlDecode(result, Encoding.UTF8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Url解密,采用utf8编码方式解密
|
||||
/// </summary>
|
||||
/// <param name="result">待解密的密文</param>
|
||||
/// <returns>解密后的字符串</returns>
|
||||
public static string Decode(string result)
|
||||
{
|
||||
return Decode(result, Encoding.UTF8);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using MAX.Core.Interfaces;
|
||||
|
||||
namespace MAX.Core.DependencyInjection;
|
||||
|
||||
/// <summary>
|
||||
/// 依赖注册器:把当前模块的服务注册到 <see cref="IServiceRegistrar"/>。
|
||||
/// 底层使用哪个容器由宿主项目决定,MAX.Core 不引用任何容器。
|
||||
/// </summary>
|
||||
public interface IDependencyRegistrar: IPriority
|
||||
{
|
||||
/// <summary>
|
||||
/// 注册服务
|
||||
/// </summary>
|
||||
void Register(IServiceRegistrar registrar);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace MAX.Core.DependencyInjection;
|
||||
|
||||
/// <summary>
|
||||
/// 作用域(每个 Scope/请求一个实例)
|
||||
/// </summary>
|
||||
public interface IScopedDependency
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
|
||||
namespace MAX.Core.DependencyInjection;
|
||||
|
||||
/// <summary>
|
||||
/// 依赖注册抽象(由 MAX.Core 自己定义,不依赖任何第三方 DI 容器)。
|
||||
/// 具体实现由宿主项目提供,内部适配外部容器(Autofac、Microsoft.Extensions.DependencyInjection 等)。
|
||||
/// </summary>
|
||||
public interface IServiceRegistrar
|
||||
{
|
||||
object Services { get; }
|
||||
/// <summary>
|
||||
/// 注册单例:<typeparamref name="TImplementation"/> 实现 <typeparamref name="TService"/>
|
||||
/// </summary>
|
||||
void RegisterSingleton<TService, TImplementation>() where TService : class where TImplementation : class, TService;
|
||||
|
||||
/// <summary>
|
||||
/// 注册单例实例
|
||||
/// </summary>
|
||||
void RegisterSingleton<TService>(TService instance) where TService : class;
|
||||
|
||||
/// <summary>
|
||||
/// 注册单例(匿名工厂)
|
||||
/// </summary>
|
||||
void RegisterSingleton<TService>(Func<IServiceProvider, TService> factory) where TService : class;
|
||||
|
||||
/// <summary>
|
||||
/// 注册单例(key):<typeparamref name="TImplementation"/> 实现 <typeparamref name="TService"/>
|
||||
/// </summary>
|
||||
void RegisterSingleton<TService, TImplementation>(object? serviceKey) where TService : class where TImplementation : class, TService;
|
||||
|
||||
/// <summary>
|
||||
/// 注册单例实例(key)
|
||||
/// </summary>
|
||||
void RegisterSingleton<TService>(object? serviceKey, TService instance) where TService : class;
|
||||
|
||||
/// <summary>
|
||||
/// 注册单例(key + 匿名工厂)
|
||||
/// </summary>
|
||||
void RegisterSingleton<TService>(object? serviceKey, Func<IServiceProvider, object?, TService> factory) where TService : class;
|
||||
|
||||
/// <summary>
|
||||
/// 注册作用域生命周期
|
||||
/// </summary>
|
||||
void RegisterScoped<TService, TImplementation>() where TService : class where TImplementation : class, TService;
|
||||
|
||||
/// <summary>
|
||||
/// 注册作用域生命周期(匿名工厂)
|
||||
/// </summary>
|
||||
void RegisterScoped<TService>(Func<IServiceProvider, TService> factory) where TService : class;
|
||||
|
||||
/// <summary>
|
||||
/// 注册作用域生命周期(key):<typeparamref name="TImplementation"/> 实现 <typeparamref name="TService"/>
|
||||
/// </summary>
|
||||
void RegisterScoped<TService, TImplementation>(object? serviceKey) where TService : class where TImplementation : class, TService;
|
||||
|
||||
/// <summary>
|
||||
/// 注册作用域生命周期(key + 匿名工厂)
|
||||
/// </summary>
|
||||
void RegisterScoped<TService>(object? serviceKey, Func<IServiceProvider, object?, TService> factory) where TService : class;
|
||||
|
||||
/// <summary>
|
||||
/// 注册瞬时生命周期
|
||||
/// </summary>
|
||||
void RegisterTransient<TService, TImplementation>() where TService : class where TImplementation : class, TService;
|
||||
|
||||
/// <summary>
|
||||
/// 注册瞬时生命周期(匿名工厂)
|
||||
/// </summary>
|
||||
void RegisterTransient<TService>(Func<IServiceProvider, TService> factory) where TService : class;
|
||||
|
||||
/// <summary>
|
||||
/// 注册瞬时生命周期(key):<typeparamref name="TImplementation"/> 实现 <typeparamref name="TService"/>
|
||||
/// </summary>
|
||||
void RegisterTransient<TService, TImplementation>(object? serviceKey) where TService : class where TImplementation : class, TService;
|
||||
|
||||
/// <summary>
|
||||
/// 注册瞬时生命周期(key + 匿名工厂)
|
||||
/// </summary>
|
||||
void RegisterTransient<TService>(object? serviceKey, Func<IServiceProvider, object?, TService> factory) where TService : class;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace MAX.Core.DependencyInjection;
|
||||
|
||||
/// <summary>
|
||||
/// 单例
|
||||
/// </summary>
|
||||
public interface ISingletonDependency
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace MAX.Core.DependencyInjection;
|
||||
|
||||
/// <summary>
|
||||
/// 每次实例化
|
||||
/// </summary>
|
||||
public interface ITransientDependency
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
//using MAX.Core.Autofac;
|
||||
//using MAX.Core.Infrastructure;
|
||||
//using System;
|
||||
//using System.Collections.Concurrent;
|
||||
|
||||
//namespace MAX.Core.DependencyInjection;
|
||||
|
||||
//public interface ILazyServiceProvider
|
||||
//{
|
||||
// object LazyGetService(Type serviceType);
|
||||
// T LazyGetService<T>();
|
||||
//}
|
||||
|
||||
//public class LazyServiceProvider : SingleInstance<LazyServiceProvider>, ILazyServiceProvider
|
||||
//{
|
||||
// protected ConcurrentDictionary<Type, Lazy<object>> CachedServices { get; }
|
||||
// private LazyServiceProvider()
|
||||
// {
|
||||
// CachedServices = new ConcurrentDictionary<Type, Lazy<object>>();
|
||||
// }
|
||||
// public virtual T LazyGetService<T>()
|
||||
// {
|
||||
// return (T)LazyGetService(typeof(T));
|
||||
// }
|
||||
|
||||
// public virtual object LazyGetService(Type serviceType)
|
||||
// {
|
||||
// return GetService(serviceType);
|
||||
// }
|
||||
// public virtual object GetService(Type serviceType)
|
||||
// {
|
||||
// return CachedServices.GetOrAdd(
|
||||
// serviceType,
|
||||
// _ => new Lazy<object>(() => IocManager.Resolve(serviceType))
|
||||
// ).Value;
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,218 @@
|
||||
using MAX.Core.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MAX.Core.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// 系统扩展 - 类型转换
|
||||
/// </summary>
|
||||
public static partial class Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// IsNullOrEmpty
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsNullOrEmpty(this string input)
|
||||
{
|
||||
return string.IsNullOrEmpty(input);
|
||||
}
|
||||
/// <summary>
|
||||
/// 安全转换为字符串,去除两端空格,当值为null时返回""
|
||||
/// </summary>
|
||||
/// <param name="input">输入值</param>
|
||||
public static string SafeString(this object input)
|
||||
{
|
||||
return input?.ToString().Trim() ?? string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为bool
|
||||
/// </summary>
|
||||
/// <param name="obj">数据</param>
|
||||
public static bool ToBool(this string obj, bool defvalue = false)
|
||||
{
|
||||
return Helpers.Convert.ToBool(obj, defvalue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为可空bool
|
||||
/// </summary>
|
||||
/// <param name="obj">数据</param>
|
||||
public static bool? ToBoolOrNull(this string obj)
|
||||
{
|
||||
return Helpers.Convert.ToBoolOrNull(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为int
|
||||
/// </summary>
|
||||
/// <param name="obj">数据</param>
|
||||
public static int ToInt(this string obj, int defvalue = 0)
|
||||
{
|
||||
return Helpers.Convert.ToInt(obj, defvalue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为可空int
|
||||
/// </summary>
|
||||
/// <param name="obj">数据</param>
|
||||
public static int? ToIntOrNull(this string obj)
|
||||
{
|
||||
return Helpers.Convert.ToIntOrNull(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为long
|
||||
/// </summary>
|
||||
/// <param name="obj">数据</param>
|
||||
public static long ToLong(this string obj, long defvalue = 0)
|
||||
{
|
||||
return Helpers.Convert.ToLong(obj, defvalue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为可空long
|
||||
/// </summary>
|
||||
/// <param name="obj">数据</param>
|
||||
public static long? ToLongOrNull(this string obj)
|
||||
{
|
||||
return Helpers.Convert.ToLongOrNull(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为double
|
||||
/// </summary>
|
||||
/// <param name="obj">数据</param>
|
||||
public static double ToDouble(this string obj, double defvalue = 0)
|
||||
{
|
||||
return Helpers.Convert.ToDouble(obj, defvalue: defvalue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为可空double
|
||||
/// </summary>
|
||||
/// <param name="obj">数据</param>
|
||||
public static double? ToDoubleOrNull(this string obj)
|
||||
{
|
||||
return Helpers.Convert.ToDoubleOrNull(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为decimal
|
||||
/// </summary>
|
||||
/// <param name="obj">数据</param>
|
||||
public static decimal ToDecimal(this string obj, decimal defvalue = 0)
|
||||
{
|
||||
return Helpers.Convert.ToDecimal(obj, defvalue: defvalue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为可空decimal
|
||||
/// </summary>
|
||||
/// <param name="obj">数据</param>
|
||||
public static decimal? ToDecimalOrNull(this string obj)
|
||||
{
|
||||
return Helpers.Convert.ToDecimalOrNull(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为日期
|
||||
/// </summary>
|
||||
/// <param name="obj">数据</param>
|
||||
public static DateTime ToDate(this string obj)
|
||||
{
|
||||
return Helpers.Convert.ToDate(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为可空日期
|
||||
/// </summary>
|
||||
/// <param name="obj">数据</param>
|
||||
public static DateTime? ToDateOrNull(this string obj)
|
||||
{
|
||||
return Helpers.Convert.ToDateOrNull(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为Guid
|
||||
/// </summary>
|
||||
/// <param name="obj">数据</param>
|
||||
public static Guid ToGuid(this string obj)
|
||||
{
|
||||
return Helpers.Convert.ToGuid(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为可空Guid
|
||||
/// </summary>
|
||||
/// <param name="obj">数据</param>
|
||||
public static Guid? ToGuidOrNull(this string obj)
|
||||
{
|
||||
return Helpers.Convert.ToGuidOrNull(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为Guid集合
|
||||
/// </summary>
|
||||
/// <param name="obj">数据,范例: "83B0233C-A24F-49FD-8083-1337209EBC9A,EAB523C6-2FE7-47BE-89D5-C6D440C3033A"</param>
|
||||
public static List<Guid> ToGuidList(this string obj)
|
||||
{
|
||||
return Helpers.Convert.ToGuidList(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为Guid集合
|
||||
/// </summary>
|
||||
/// <param name="obj">字符串集合</param>
|
||||
public static List<Guid> ToGuidList(this IList<string> obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
return obj.Select(t => t.ToGuid()).ToList();
|
||||
}
|
||||
/// <summary>
|
||||
/// 转换枚举描述
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToDescription(this Enum obj)
|
||||
{
|
||||
return EnumHelper.GetDescription(obj.GetType(), obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 枚举值 → 单个 EnumItem
|
||||
/// </summary>
|
||||
/// <typeparam name="TEnum"></typeparam>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static EnumItem<TEnum> ToItem<TEnum>(this TEnum value) where TEnum : struct, Enum
|
||||
{
|
||||
return new EnumItem<TEnum>(value);
|
||||
}
|
||||
/// <summary>
|
||||
/// 是否单一标记
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsSingleFlag(Enum obj)
|
||||
{
|
||||
return EnumHelper.IsSingleFlag(obj);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取第一个标记
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static Enum GetFirstFlag(this Enum obj)
|
||||
{
|
||||
return EnumHelper.GetFirstFlag(obj);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using MAX.Core.Cryptography;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace MAX.Core.Extensions;
|
||||
|
||||
public static class DictionaryExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 字典转url Get 参数
|
||||
/// </summary>
|
||||
/// <param name="parameters"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToUrlParams(this IDictionary<string, string> parameters, bool IsUrlEncode = true)
|
||||
{
|
||||
IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters);
|
||||
IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator();
|
||||
StringBuilder sb = new("");
|
||||
while (dem.MoveNext())
|
||||
{
|
||||
string key = dem.Current.Key;
|
||||
string value = dem.Current.Value;
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
sb.Append(key).Append("=").Append(IsUrlEncode ? UrlHelper.Encode(value) : value).Append("&");
|
||||
|
||||
}
|
||||
}
|
||||
string content = sb.ToString().Substring(0, sb.Length - 1);
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
|
||||
namespace MAX.Core.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// 常用公共操作
|
||||
/// </summary>
|
||||
public static partial class Common
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取类型
|
||||
/// </summary>
|
||||
/// <typeparam name="T">类型</typeparam>
|
||||
public static Type GetType<T>()
|
||||
{
|
||||
return GetType(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取类型
|
||||
/// </summary>
|
||||
/// <param name="type">类型</param>
|
||||
public static Type GetType(Type type)
|
||||
{
|
||||
return Nullable.GetUnderlyingType(type) ?? type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 换行符
|
||||
/// </summary>
|
||||
public static string Line => Environment.NewLine;
|
||||
|
||||
|
||||
#if NET5_0
|
||||
/// <summary>
|
||||
/// 是否Linux操作系统
|
||||
/// </summary>
|
||||
public static bool IsLinux => RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
|
||||
|
||||
/// <summary>
|
||||
/// 是否Windows操作系统
|
||||
/// </summary>
|
||||
public static bool IsWindows => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
|
||||
/// <summary>
|
||||
/// 是否苹果操作系统
|
||||
/// </summary>
|
||||
public static bool IsOsx => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||
|
||||
/// <summary>
|
||||
/// 当前操作系统
|
||||
/// </summary>
|
||||
public static string System => IsWindows ? "Windows" : IsLinux ? "Linux" : IsOsx ? "OSX" : string.Empty;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
|
||||
namespace MAX.Core.Helpers;
|
||||
|
||||
public class CommonItem : IComparable<CommonItem>
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
/// <param name="text">文本</param>
|
||||
/// <param name="value">值</param>
|
||||
/// <param name="sortId">排序号</param>
|
||||
/// <param name="group">组</param>
|
||||
/// <param name="disabled">禁用</param>
|
||||
public CommonItem(string text, object value, string des = "", int? sortId = null, string group = null, bool? disabled = null)
|
||||
{
|
||||
Text = text;
|
||||
Value = value;
|
||||
Description = des;
|
||||
SortId = sortId;
|
||||
Group = group;
|
||||
Disabled = disabled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文本
|
||||
/// </summary>
|
||||
public string Text { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 值
|
||||
/// </summary>
|
||||
public object Value { get; protected set; }
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
/// <summary>
|
||||
/// 排序号
|
||||
/// </summary>
|
||||
public int? SortId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 组
|
||||
/// </summary>
|
||||
public string Group { get; }
|
||||
/// <summary>
|
||||
/// 是否选中
|
||||
/// </summary>
|
||||
public bool IsSelected { get; set; }
|
||||
/// <summary>
|
||||
/// 禁用
|
||||
/// </summary>
|
||||
public bool? Disabled { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 比较
|
||||
/// </summary>
|
||||
/// <param name="other">其它列表项</param>
|
||||
public int CompareTo(CommonItem other)
|
||||
{
|
||||
return string.Compare(Text, other.Text, StringComparison.CurrentCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public class CommonItem<T> : CommonItem
|
||||
{
|
||||
public new T Value
|
||||
{
|
||||
get { return (T)base.Value; }
|
||||
set { base.Value = value; }
|
||||
}
|
||||
public CommonItem(string text, T value, string des = "", int? sortId = null, string group = null, bool? disabled = null) : base(text, value, des, sortId, group, disabled)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,385 @@
|
||||
using MAX.Core.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MAX.Core.Helpers;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field)]
|
||||
public class ConvertAttribute : Attribute
|
||||
{
|
||||
public Type ConverterType { get; set; }
|
||||
public ConvertAttribute(Type type)
|
||||
{
|
||||
ConverterType = type;
|
||||
}
|
||||
}
|
||||
public interface IConverter
|
||||
{
|
||||
object Converter(object input);
|
||||
}
|
||||
/// <summary>
|
||||
/// 类型转换
|
||||
/// </summary>
|
||||
public static partial class Convert
|
||||
{
|
||||
/// <summary>
|
||||
/// 转换为32位整型
|
||||
/// </summary>
|
||||
/// <param name="input">输入值</param>
|
||||
public static int ToInt(object input, int defvalue = 0)
|
||||
{
|
||||
return ToIntOrNull(input) ?? defvalue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为32位可空整型
|
||||
/// </summary>
|
||||
/// <param name="input">输入值</param>
|
||||
public static int? ToIntOrNull(object input)
|
||||
{
|
||||
bool success = int.TryParse(input.SafeString(), out int result);
|
||||
if (success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
double? temp = ToDoubleOrNull(input, 0);
|
||||
if (temp == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return System.Convert.ToInt32(temp);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为64位整型
|
||||
/// </summary>
|
||||
/// <param name="input">输入值</param>
|
||||
public static long ToLong(object input, long defvalue = 0)
|
||||
{
|
||||
return ToLongOrNull(input) ?? defvalue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为64位可空整型
|
||||
/// </summary>
|
||||
/// <param name="input">输入值</param>
|
||||
public static long? ToLongOrNull(object input)
|
||||
{
|
||||
bool success = long.TryParse(input.SafeString(), out long result);
|
||||
if (success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
decimal? temp = ToDecimalOrNull(input, 0);
|
||||
if (temp == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return System.Convert.ToInt64(temp);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为32位浮点型,并按指定小数位舍入
|
||||
/// </summary>
|
||||
/// <param name="input">输入值</param>
|
||||
/// <param name="digits">小数位数</param>
|
||||
public static float ToFloat(object input, int? digits = null)
|
||||
{
|
||||
return ToFloatOrNull(input, digits) ?? 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为32位可空浮点型,并按指定小数位舍入
|
||||
/// </summary>
|
||||
/// <param name="input">输入值</param>
|
||||
/// <param name="digits">小数位数</param>
|
||||
public static float? ToFloatOrNull(object input, int? digits = null)
|
||||
{
|
||||
bool success = float.TryParse(input.SafeString(), out float result);
|
||||
if (!success)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (digits == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return (float)Math.Round(result, digits.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为64位浮点型,并按指定小数位舍入
|
||||
/// </summary>
|
||||
/// <param name="input">输入值</param>
|
||||
/// <param name="digits">小数位数</param>
|
||||
public static double ToDouble(object input, int? digits = null, double defvalue = 0)
|
||||
{
|
||||
return ToDoubleOrNull(input, digits) ?? defvalue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为64位可空浮点型,并按指定小数位舍入
|
||||
/// </summary>
|
||||
/// <param name="input">输入值</param>
|
||||
/// <param name="digits">小数位数</param>
|
||||
public static double? ToDoubleOrNull(object input, int? digits = null)
|
||||
{
|
||||
if (input is bool b)
|
||||
{
|
||||
return b ? 1 : 0;
|
||||
}
|
||||
bool success = double.TryParse(input.SafeString(), out double result);
|
||||
if (!success)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (digits == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return Math.Round(result, digits.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为128位浮点型,并按指定小数位舍入
|
||||
/// </summary>
|
||||
/// <param name="input">输入值</param>
|
||||
/// <param name="digits">小数位数</param>
|
||||
public static decimal ToDecimal(object input, int? digits = null, decimal defvalue = 0)
|
||||
{
|
||||
return ToDecimalOrNull(input, digits) ?? defvalue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为128位可空浮点型,并按指定小数位舍入
|
||||
/// </summary>
|
||||
/// <param name="input">输入值</param>
|
||||
/// <param name="digits">小数位数</param>
|
||||
public static decimal? ToDecimalOrNull(object input, int? digits = null)
|
||||
{
|
||||
bool success = decimal.TryParse(input.SafeString(), out decimal result);
|
||||
if (!success)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (digits == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return Math.Round(result, digits.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为布尔值
|
||||
/// </summary>
|
||||
/// <param name="input">输入值</param>
|
||||
public static bool ToBool(object input, bool defvalue = false)
|
||||
{
|
||||
return ToBoolOrNull(input) ?? defvalue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为可空布尔值
|
||||
/// </summary>
|
||||
/// <param name="input">输入值</param>
|
||||
public static bool? ToBoolOrNull(object input)
|
||||
{
|
||||
bool? value = GetBool(input);
|
||||
if (value != null)
|
||||
{
|
||||
return value.Value;
|
||||
}
|
||||
|
||||
return bool.TryParse(input.SafeString(), out bool result) ? result : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取布尔值
|
||||
/// </summary>
|
||||
private static bool? GetBool(object input)
|
||||
{
|
||||
return input.SafeString().ToLower() switch
|
||||
{
|
||||
"0" => false,
|
||||
"否" => false,
|
||||
"不" => false,
|
||||
"no" => false,
|
||||
"fail" => false,
|
||||
"1" => true,
|
||||
"是" => true,
|
||||
"ok" => true,
|
||||
"yes" => true,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为日期
|
||||
/// </summary>
|
||||
/// <param name="input">输入值</param>
|
||||
public static DateTime ToDate(object input)
|
||||
{
|
||||
return ToDateOrNull(input) ?? DateTime.MinValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为可空日期
|
||||
/// </summary>
|
||||
/// <param name="input">输入值</param>
|
||||
public static DateTime? ToDateOrNull(object input)
|
||||
{
|
||||
return DateTime.TryParse(input.SafeString(), out DateTime result) ? result : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为Guid
|
||||
/// </summary>
|
||||
/// <param name="input">输入值</param>
|
||||
public static Guid ToGuid(object input)
|
||||
{
|
||||
return ToGuidOrNull(input) ?? Guid.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为可空Guid
|
||||
/// </summary>
|
||||
/// <param name="input">输入值</param>
|
||||
public static Guid? ToGuidOrNull(object input)
|
||||
{
|
||||
return Guid.TryParse(input.SafeString(), out Guid result) ? result : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为Guid集合
|
||||
/// </summary>
|
||||
/// <param name="input">以逗号分隔的Guid集合字符串,范例:83B0233C-A24F-49FD-8083-1337209EBC9A,EAB523C6-2FE7-47BE-89D5-C6D440C3033A</param>
|
||||
public static List<Guid> ToGuidList(string input)
|
||||
{
|
||||
return ToList<Guid>(input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 泛型集合转换
|
||||
/// </summary>
|
||||
/// <typeparam name="T">目标元素类型</typeparam>
|
||||
/// <param name="input">以逗号分隔的元素集合字符串,范例:83B0233C-A24F-49FD-8083-1337209EBC9A,EAB523C6-2FE7-47BE-89D5-C6D440C3033A</param>
|
||||
public static List<T> ToList<T>(string input)
|
||||
{
|
||||
List<T> result = [];
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
string[] array = input.Split(',');
|
||||
result.AddRange(from each in array where !string.IsNullOrWhiteSpace(each) select To<T>(each));
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通用泛型转换
|
||||
/// </summary>
|
||||
/// <typeparam name="T">目标类型</typeparam>
|
||||
/// <param name="input">输入值</param>
|
||||
public static T To<T>(object input)
|
||||
{
|
||||
Type type = Common.GetType<T>();
|
||||
return (T)To(type, input);
|
||||
}
|
||||
public static object To(Type type, object input)
|
||||
{
|
||||
object defValue = null;
|
||||
if (type != null)
|
||||
{
|
||||
defValue = type.IsValueType ? Activator.CreateInstance(type) : null;
|
||||
}
|
||||
if (input == null)
|
||||
{
|
||||
return defValue;
|
||||
}
|
||||
|
||||
if (input is string && string.IsNullOrWhiteSpace(input.ToString()))
|
||||
{
|
||||
return defValue;
|
||||
}
|
||||
|
||||
string typeName = type.Name.ToLower();
|
||||
try
|
||||
{
|
||||
if (typeName == "string")
|
||||
{
|
||||
return input.ToString();
|
||||
}
|
||||
|
||||
if (typeName == "guid")
|
||||
{
|
||||
return new Guid(input.ToString());
|
||||
}
|
||||
|
||||
if (type.IsEnum)
|
||||
{
|
||||
return EnumHelper.Parse(type, input);
|
||||
}
|
||||
|
||||
if (typeof(IConverter).IsAssignableFrom(type))
|
||||
{
|
||||
object instance = Activator.CreateInstance(type);
|
||||
return ((IConverter)instance).Converter(input);
|
||||
}
|
||||
if (input is IConvertible)
|
||||
{
|
||||
return System.Convert.ChangeType(input, type);
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return defValue;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 转换为字节数组
|
||||
/// </summary>
|
||||
/// <param name="input">输入值</param>
|
||||
public static byte[] ToBytes(string input)
|
||||
{
|
||||
return ToBytes(input, Encoding.UTF8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为字节数组
|
||||
/// </summary>
|
||||
/// <param name="input">输入值</param>
|
||||
/// <param name="encoding">字符编码</param>
|
||||
public static byte[] ToBytes(string input, Encoding encoding)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(input) ? new byte[] { } : encoding.GetBytes(input);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
|
||||
namespace MAX.Core.Helpers;
|
||||
|
||||
public class DateHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Unix纪元时间
|
||||
/// </summary>
|
||||
private static readonly DateTime UnixEpoch = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
/// <summary>
|
||||
/// 将时间转换为秒级时间戳
|
||||
/// </summary>
|
||||
/// <param name="dateTime"></param>
|
||||
/// <returns></returns>
|
||||
public static long GetUnixTimestampInSeconds(DateTime dateTime)
|
||||
{
|
||||
TimeSpan timeSpan = dateTime.ToUniversalTime() - UnixEpoch;
|
||||
return (long)timeSpan.TotalSeconds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将时间转换为毫秒级时间戳
|
||||
/// </summary>
|
||||
/// <param name="dateTime"></param>
|
||||
/// <returns></returns>
|
||||
public static long GetUnixTimestampInMilliseconds(DateTime dateTime)
|
||||
{
|
||||
TimeSpan timeSpan = dateTime.ToUniversalTime() - UnixEpoch;
|
||||
return (long)timeSpan.TotalMilliseconds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将时间转换为微秒时间戳
|
||||
/// </summary>
|
||||
/// <param name="dateTime"></param>
|
||||
/// <returns></returns>
|
||||
public static long GetUnixTimestampInMicroseconds(DateTime dateTime)
|
||||
{
|
||||
long us = dateTime.ToUniversalTime().Ticks - UnixEpoch.Ticks;
|
||||
return us;
|
||||
}
|
||||
/// <summary>
|
||||
/// 将时间Ticks转换为毫微秒时间戳
|
||||
/// </summary>
|
||||
/// <param name="dateTime"></param>
|
||||
/// <returns></returns>
|
||||
public static long GetUnixTimestampInMicroseconds(long ticks)
|
||||
{
|
||||
long us = ticks - UnixEpoch.Ticks;
|
||||
return us;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将秒级时间戳转换为时间
|
||||
/// </summary>
|
||||
/// <param name="timestamp"></param>
|
||||
/// <returns></returns>
|
||||
public static DateTime ConvertFromUnixTimestampInSeconds(long timestamp)
|
||||
{
|
||||
return UnixEpoch.AddSeconds(timestamp).ToLocalTime();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将毫秒级时间戳转换为时间
|
||||
/// </summary>
|
||||
/// <param name="timestamp"></param>
|
||||
/// <returns></returns>
|
||||
public static DateTime ConvertFromUnixTimestampInMilliseconds(long timestamp)
|
||||
{
|
||||
return UnixEpoch.AddMilliseconds(timestamp).ToLocalTime();
|
||||
}
|
||||
/// <summary>
|
||||
/// 将微秒级时间戳转换为时间
|
||||
/// </summary>
|
||||
/// <param name="timestamp"></param>
|
||||
/// <returns></returns>
|
||||
public static DateTime ConvertFromUnixTimestampInMicroseconds(long timestamp)
|
||||
{
|
||||
long us = timestamp + UnixEpoch.Ticks;
|
||||
return new DateTime(us);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取当前时间的秒级时间戳
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static long GetCurrentUnixTimestampInSeconds()
|
||||
{
|
||||
return GetUnixTimestampInSeconds(DateTime.UtcNow);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前时间的毫秒级时间戳
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static long GetCurrentUnixTimestampInMilliseconds()
|
||||
{
|
||||
return GetUnixTimestampInMilliseconds(DateTime.UtcNow);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前时间的微秒级时间戳
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static long GetCurrentUnixTimestampInMicroseconds()
|
||||
{
|
||||
return GetUnixTimestampInMicroseconds(DateTime.UtcNow);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
using MAX.Core.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MAX.Core.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// 枚举操作
|
||||
/// </summary>
|
||||
public static partial class EnumHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取实例
|
||||
/// </summary>
|
||||
/// <typeparam name="TEnum">枚举类型</typeparam>
|
||||
/// <param name="member">成员名或值,范例:Enum1枚举有成员A=0,则传入"A"或"0"获取 Enum1.A</param>
|
||||
public static TEnum Parse<TEnum>(object member)
|
||||
{
|
||||
string value = member.SafeString();
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
if (typeof(TEnum).IsGenericType)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
throw new ArgumentNullException(nameof(member));
|
||||
}
|
||||
return (TEnum)Enum.Parse(Common.GetType<TEnum>(), value, true);
|
||||
}
|
||||
public static object Parse(Type enumObj, object member)
|
||||
{
|
||||
string value = member.SafeString();
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
if (enumObj.IsGenericType)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new ArgumentNullException(nameof(member));
|
||||
}
|
||||
return Enum.Parse(enumObj, value, true);
|
||||
}
|
||||
public static TEnum ParseByDescription<TEnum>(string description)
|
||||
{
|
||||
return (TEnum)ParseByDescription(Common.GetType<TEnum>(), description);
|
||||
}
|
||||
public static object ParseByDescription(Type enumObj, string description)
|
||||
{
|
||||
List<EnumItem> listitem = GetItems(enumObj);
|
||||
foreach (EnumItem item in listitem)
|
||||
{
|
||||
if (item.Description == description)
|
||||
{
|
||||
return Enum.Parse(enumObj, item.Numeric.ToString(), true);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取成员名
|
||||
/// </summary>
|
||||
/// <typeparam name="TEnum">枚举类型</typeparam>
|
||||
/// <param name="member">成员名、值、实例均可,范例:Enum1枚举有成员A=0,则传入Enum1.A或0,获取成员名"A"</param>
|
||||
public static string GetName<TEnum>(object member)
|
||||
{
|
||||
return GetName(Common.GetType<TEnum>(), member);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取成员名
|
||||
/// </summary>
|
||||
/// <param name="type">枚举类型</param>
|
||||
/// <param name="member">成员名、值、实例均可</param>
|
||||
public static string GetName(Type type, object member)
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (member == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (member is string)
|
||||
{
|
||||
return member.ToString();
|
||||
}
|
||||
|
||||
if (type.GetTypeInfo().IsEnum == false)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return Enum.GetName(type, member);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取成员值
|
||||
/// </summary>
|
||||
/// <typeparam name="TEnum">枚举类型</typeparam>
|
||||
/// <param name="member">成员名、值、实例均可,范例:Enum1枚举有成员A=0,可传入"A"、0、Enum1.A,获取值0</param>
|
||||
public static int GetValue<TEnum>(object member)
|
||||
{
|
||||
return GetValue(Common.GetType<TEnum>(), member);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取成员值
|
||||
/// </summary>
|
||||
/// <param name="type">枚举类型</param>
|
||||
/// <param name="member">成员名、值、实例均可</param>
|
||||
public static int GetValue(Type type, object member)
|
||||
{
|
||||
string value = member.SafeString();
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(member));
|
||||
}
|
||||
|
||||
return (int)Enum.Parse(type, member.ToString(), true);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取描述,使用System.ComponentModel.Description特性设置描述
|
||||
/// </summary>
|
||||
/// <typeparam name="TEnum">枚举类型</typeparam>
|
||||
/// <param name="member">成员名、值、实例均可</param>
|
||||
public static string GetDescription<TEnum>(object member)
|
||||
{
|
||||
return ReflectionHelper.GetDescription<TEnum>(GetName<TEnum>(member));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取描述,使用System.ComponentModel.Description特性设置描述
|
||||
/// </summary>
|
||||
/// <param name="type">枚举类型</param>
|
||||
/// <param name="member">成员名、值、实例均可</param>
|
||||
public static string GetDescription(Type type, object member)
|
||||
{
|
||||
return ReflectionHelper.GetDescription(type, GetName(type, member));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取项集合,文本设置为Description,值为Value
|
||||
/// </summary>
|
||||
/// <typeparam name="TEnum">枚举类型</typeparam>
|
||||
public static List<EnumItem> GetItems<TEnum>()
|
||||
{
|
||||
return GetItems(typeof(TEnum));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取项集合,文本设置为Description,值为Value
|
||||
/// </summary>
|
||||
/// <param name="type">枚举类型</param>
|
||||
public static List<EnumItem> GetItems(Type type)
|
||||
{
|
||||
type = Common.GetType(type);
|
||||
if (type.IsEnum == false)
|
||||
{
|
||||
throw new InvalidOperationException($"类型 {type} 不是枚举");
|
||||
}
|
||||
|
||||
List<EnumItem> result = [];
|
||||
foreach (FieldInfo field in type.GetFields())
|
||||
{
|
||||
AddItem(type, result, field);
|
||||
}
|
||||
|
||||
return result.OrderBy(t => t.Numeric).ToList();
|
||||
}
|
||||
|
||||
public static CommonItem GetItem(object obj)
|
||||
{
|
||||
CommonItem item = null;
|
||||
if (obj is Enum em)
|
||||
{
|
||||
//item.Text = em.get
|
||||
string text = em.ToString();
|
||||
int value = GetValue(obj.GetType(), obj);
|
||||
string description = em.ToDescription();
|
||||
item = new CommonItem(text, value, des: description);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加描述项
|
||||
/// </summary>
|
||||
private static void AddItem(Type type, ICollection<EnumItem> result, FieldInfo field)
|
||||
{
|
||||
if (!field.FieldType.IsEnum)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string text = field.Name;
|
||||
int value = GetValue(type, field.Name);
|
||||
string description = ReflectionHelper.GetDescription(field);
|
||||
result.Add(new EnumItem(text, value, description));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取名称集合
|
||||
/// </summary>
|
||||
/// <typeparam name="TEnum">枚举类型</typeparam>
|
||||
public static List<string> GetNames<TEnum>()
|
||||
{
|
||||
return GetNames(typeof(TEnum));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取名称集合
|
||||
/// </summary>
|
||||
/// <param name="type">枚举类型</param>
|
||||
public static List<string> GetNames(Type type)
|
||||
{
|
||||
type = Common.GetType(type);
|
||||
if (type.IsEnum == false)
|
||||
{
|
||||
throw new InvalidOperationException($"类型 {type} 不是枚举");
|
||||
}
|
||||
|
||||
List<string> result = [];
|
||||
foreach (FieldInfo field in type.GetFields())
|
||||
{
|
||||
if (!field.FieldType.IsEnum)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result.Add(field.Name);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取名称集合
|
||||
/// </summary>
|
||||
/// <typeparam name="TEnum">枚举类型</typeparam>
|
||||
public static List<string> GetDescriptions<TEnum>()
|
||||
{
|
||||
return GetDescriptions(typeof(TEnum));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取名称集合
|
||||
/// </summary>
|
||||
/// <param name="type">枚举类型</param>
|
||||
public static List<string> GetDescriptions(Type type)
|
||||
{
|
||||
type = Common.GetType(type);
|
||||
if (type.IsEnum == false)
|
||||
{
|
||||
throw new InvalidOperationException($"类型 {type} 不是枚举");
|
||||
}
|
||||
|
||||
List<string> result = [];
|
||||
foreach (FieldInfo field in type.GetFields())
|
||||
{
|
||||
if (!field.FieldType.IsEnum)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string description = ReflectionHelper.GetDescription(field);
|
||||
result.Add(description);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// 是否单一标记
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsSingleFlag(Enum obj)
|
||||
{
|
||||
int intValue = GetValue(obj.GetType(), obj);
|
||||
return (intValue > 0) && ((intValue & (intValue - 1)) == 0);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取第一个标记
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static T GetFirstFlag<T>(T value) where T : Enum
|
||||
{
|
||||
long v = System.Convert.ToInt64(value);
|
||||
long first = v & -v;
|
||||
return Enum.GetValues(typeof(T)).Cast<T>().First(flag => System.Convert.ToInt64(flag) == first);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Enum展示类型
|
||||
/// </summary>
|
||||
public enum EnumDisplayType
|
||||
{
|
||||
Text,
|
||||
Value,
|
||||
Description,
|
||||
CommonItem
|
||||
}
|
||||
public class EnumItem
|
||||
{
|
||||
public string Name { get; init; }
|
||||
public int Numeric { get; init; }
|
||||
public string Description { get; init; }
|
||||
|
||||
public EnumItem(string name, int numeric, string description)
|
||||
{
|
||||
Name = name;
|
||||
Numeric = numeric;
|
||||
Description = description;
|
||||
}
|
||||
}
|
||||
public class EnumItem<TEnum> : EnumItem where TEnum : struct, Enum
|
||||
{
|
||||
public TEnum Value { get; }
|
||||
|
||||
public EnumItem(TEnum value)
|
||||
: base(value.ToString(), System.Convert.ToInt32(value), GetDescription(value))
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
private static string GetDescription(TEnum value)
|
||||
{
|
||||
var field = typeof(TEnum).GetField(value.ToString())!;
|
||||
var attr = field.GetCustomAttribute<DescriptionAttribute>();
|
||||
return attr?.Description ?? string.Empty;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MAX.Core.Helpers;
|
||||
public class EnvironmentHelper
|
||||
{
|
||||
private static string? _currentEnvironment;
|
||||
|
||||
// 获取当前环境
|
||||
public static string CurrentEnvironment
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_currentEnvironment == null)
|
||||
{
|
||||
_currentEnvironment = DetermineEnvironment();
|
||||
}
|
||||
return _currentEnvironment;
|
||||
}
|
||||
}
|
||||
public static bool IsTest => CurrentEnvironment.Equals("Test", StringComparison.OrdinalIgnoreCase);
|
||||
public static bool IsDevelopment => CurrentEnvironment.Equals("Development", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
public static bool IsProduction => CurrentEnvironment.Equals("Production", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
private static string DetermineEnvironment()
|
||||
{
|
||||
// 1. 检查环境变量
|
||||
var envVar = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ??
|
||||
Environment.GetEnvironmentVariable("ENVIRONMENT");
|
||||
|
||||
if (!string.IsNullOrEmpty(envVar))
|
||||
{
|
||||
return envVar;
|
||||
}
|
||||
|
||||
|
||||
// 检查当前机器名
|
||||
var machineName = Environment.MachineName;
|
||||
if (machineName.ToUpper().Contains("DEV") ||
|
||||
machineName.ToUpper().Contains("TEST"))
|
||||
{
|
||||
return machineName.Contains("TEST") ? "Test" : "Development";
|
||||
}
|
||||
|
||||
// 4. 默认返回 Production
|
||||
return "Production";
|
||||
}
|
||||
|
||||
// 获取环境描述
|
||||
public static string EnvironmentDescription
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsTest) return "测试环境";
|
||||
if (IsDevelopment) return "开发环境";
|
||||
if (IsProduction) return "生产环境";
|
||||
return $"未知环境 ({CurrentEnvironment})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MAX.Core.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// 文件和流操作
|
||||
/// </summary>
|
||||
public static partial class FileHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 流转换为字节流
|
||||
/// </summary>
|
||||
/// <param name="stream">流</param>
|
||||
public static async Task<byte[]> ToBytesAsync(Stream stream)
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
byte[] buffer = new byte[stream.Length];
|
||||
await stream.ReadAsync(buffer, 0, buffer.Length);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 流转换为字节流
|
||||
/// </summary>
|
||||
/// <param name="stream">流</param>
|
||||
public static byte[] ToBytes(Stream stream)
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
byte[] buffer = new byte[stream.Length];
|
||||
stream.Read(buffer, 0, buffer.Length);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 字符串转换成字节数组
|
||||
/// </summary>
|
||||
/// <param name="data">数据,默认字符编码utf-8</param>
|
||||
public static byte[] ToBytes(string data)
|
||||
{
|
||||
return ToBytes(data, Encoding.UTF8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 字符串转换成字节数组
|
||||
/// </summary>
|
||||
/// <param name="data">数据</param>
|
||||
/// <param name="encoding">字符编码</param>
|
||||
public static byte[] ToBytes(string data, Encoding encoding)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(data))
|
||||
{
|
||||
return new byte[] { };
|
||||
}
|
||||
|
||||
return encoding.GetBytes(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将文件读取到字节流中
|
||||
/// </summary>
|
||||
/// <param name="filePath">文件的绝对路径</param>
|
||||
public static byte[] Read(string filePath)
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
FileInfo fileInfo = new(filePath);
|
||||
using BinaryReader reader = new(fileInfo.Open(FileMode.Open));
|
||||
return reader.ReadBytes((int)fileInfo.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 流转换成字符串
|
||||
/// </summary>
|
||||
/// <param name="stream">流</param>
|
||||
/// <param name="encoding">字符编码</param>
|
||||
/// <param name="bufferSize">缓冲区大小</param>
|
||||
/// <param name="isCloseStream">读取完成是否释放流,默认为true</param>
|
||||
public static string ToString(Stream stream, Encoding encoding = null, int bufferSize = 1024 * 2, bool isCloseStream = true)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
encoding ??= Encoding.UTF8;
|
||||
|
||||
if (stream.CanRead == false)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
using StreamReader reader = new(stream, encoding, true, bufferSize, !isCloseStream);
|
||||
if (stream.CanSeek)
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
string result = reader.ReadToEnd();
|
||||
if (stream.CanSeek)
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 流转换成字符串
|
||||
/// </summary>
|
||||
/// <param name="stream">流</param>
|
||||
/// <param name="encoding">字符编码</param>
|
||||
/// <param name="bufferSize">缓冲区大小</param>
|
||||
/// <param name="isCloseStream">读取完成是否释放流,默认为true</param>
|
||||
public static async Task<string> ToStringAsync(Stream stream, Encoding encoding = null, int bufferSize = 1024 * 2, bool isCloseStream = true)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
encoding ??= Encoding.UTF8;
|
||||
|
||||
if (stream.CanRead == false)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
using StreamReader reader = new(stream, encoding, true, bufferSize, !isCloseStream);
|
||||
if (stream.CanSeek)
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
string result = await reader.ReadToEndAsync();
|
||||
if (stream.CanSeek)
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 复制流并转换成字符串
|
||||
/// </summary>
|
||||
/// <param name="stream">流</param>
|
||||
/// <param name="encoding">字符编码</param>
|
||||
public static async Task<string> CopyToStringAsync(Stream stream, Encoding encoding = null)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
encoding ??= Encoding.UTF8;
|
||||
|
||||
if (stream.CanRead == false)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
using MemoryStream memoryStream = new();
|
||||
using StreamReader reader = new(memoryStream, encoding);
|
||||
if (stream.CanSeek)
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
stream.CopyTo(memoryStream);
|
||||
if (memoryStream.CanSeek)
|
||||
{
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
string result = await reader.ReadToEndAsync();
|
||||
if (stream.CanSeek)
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,45 @@
|
||||
namespace MAX.Core.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// 标识生成器
|
||||
/// </summary>
|
||||
public static partial class IdHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 标识
|
||||
/// </summary>
|
||||
private static string _id;
|
||||
|
||||
/// <summary>
|
||||
/// 设置标识
|
||||
/// </summary>
|
||||
/// <param name="id">Id</param>
|
||||
public static void SetId(string id)
|
||||
{
|
||||
_id = id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置标识
|
||||
/// </summary>
|
||||
public static void Reset()
|
||||
{
|
||||
_id = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用Guid创建标识,去掉分隔符
|
||||
/// </summary>
|
||||
public static string Guid()
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(_id) ? System.Guid.NewGuid().ToString("N") : _id;
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// 获取Guid
|
||||
///// </summary>
|
||||
//public static Guid GetGuid()
|
||||
//{
|
||||
// return string.IsNullOrWhiteSpace(_id) ? System.Guid.NewGuid() : _id.ToGuid();
|
||||
//}
|
||||
}
|
||||
@@ -0,0 +1,369 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace MAX.Core.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// This is a generic parameters base class used for Dialog Parameters and Navigation Parameters.
|
||||
/// </summary>
|
||||
public abstract class ParametersBase : IEnumerable<KeyValuePair<string, object>>
|
||||
{
|
||||
private readonly List<KeyValuePair<string, object>> _entries = [];
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor.
|
||||
/// </summary>
|
||||
protected ParametersBase()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a list of parameters.
|
||||
/// </summary>
|
||||
/// <param name="query">Query string to be parsed.</param>
|
||||
protected ParametersBase(string query)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(query))
|
||||
{
|
||||
int num = query.Length;
|
||||
for (int i = ((query.Length > 0) && (query[0] == '?')) ? 1 : 0; i < num; i++)
|
||||
{
|
||||
int startIndex = i;
|
||||
int num4 = -1;
|
||||
while (i < num)
|
||||
{
|
||||
char ch = query[i];
|
||||
if (ch == '=')
|
||||
{
|
||||
if (num4 < 0)
|
||||
{
|
||||
num4 = i;
|
||||
}
|
||||
}
|
||||
else if (ch == '&')
|
||||
{
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
string key = null;
|
||||
string value;
|
||||
if (num4 >= 0)
|
||||
{
|
||||
key = query.Substring(startIndex, num4 - startIndex);
|
||||
value = query.Substring(num4 + 1, i - num4 - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = query.Substring(startIndex, i - startIndex);
|
||||
}
|
||||
|
||||
if (key != null)
|
||||
{
|
||||
Add(Uri.UnescapeDataString(key), Uri.UnescapeDataString(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches Parameter collection and returns value if Collection contains key.
|
||||
/// Otherwise returns null.
|
||||
/// </summary>
|
||||
/// <param name="key">The key for the value to be returned.</param>
|
||||
/// <returns>The value of the parameter referenced by the key; otherwise <c>null</c>.</returns>
|
||||
public object this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (KeyValuePair<string, object> entry in _entries)
|
||||
{
|
||||
if (string.Compare(entry.Key, key, StringComparison.Ordinal) == 0)
|
||||
{
|
||||
return entry.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The count, or number, of parameters in collection.
|
||||
/// </summary>
|
||||
public int Count => _entries.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Returns an IEnumerable of the Keys in the collection.
|
||||
/// </summary>
|
||||
public IEnumerable<string> Keys =>
|
||||
_entries.Select(x => x.Key);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the key and value to the parameters collection.
|
||||
/// </summary>
|
||||
/// <param name="key">The key to reference this value in the parameters collection.</param>
|
||||
/// <param name="value">The value of the parameter to store.</param>
|
||||
public void Add(string key, object value) =>
|
||||
_entries.Add(new KeyValuePair<string, object>(key, value));
|
||||
|
||||
|
||||
public void Remove(string key)
|
||||
{
|
||||
_entries.RemoveAll(x => x.Key == key);
|
||||
}
|
||||
|
||||
public void Update(string key, object value)
|
||||
{
|
||||
_entries.RemoveAll(x => x.Key == key);
|
||||
Add(key, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks collection for presence of key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key to check in the collection.</param>
|
||||
/// <returns><c>true</c> if key exists; else returns <c>false</c>.</returns>
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
return _entries.Any(x => string.Compare(x.Key, key, StringComparison.Ordinal) == 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets an enumerator for the KeyValuePairs in parameter collection.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator.</returns>
|
||||
public IEnumerator<KeyValuePair<string, object>> GetEnumerator() =>
|
||||
_entries.GetEnumerator();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of the member referenced by key.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of object to be returned.</typeparam>
|
||||
/// <param name="key">The key for the value to be returned.</param>
|
||||
/// <returns>Returns a matching parameter of <typeparamref name="T"/> if one exists in the Collection.</returns>
|
||||
public T GetValue<T>(string key) =>
|
||||
_entries.GetValue<T>(key);
|
||||
|
||||
/// <summary>
|
||||
/// Returns an IEnumerable of all parameters.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type for the values to be returned.</typeparam>
|
||||
/// <param name="key">The key for the values to be returned.</param>
|
||||
///<returns>Returns a IEnumerable of all the instances of type <typeparamref name="T"/>.</returns>
|
||||
public IEnumerable<T> GetValues<T>(string key) =>
|
||||
_entries.GetValues<T>(key);
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see if the parameter collection contains the value.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type for the values to be returned.</typeparam>
|
||||
/// <param name="key">The key for the value to be returned.</param>
|
||||
/// <param name="value">Value of the returned parameter if it exists.</param>
|
||||
public bool TryGetValue<T>(string key, out T value) =>
|
||||
_entries.TryGetValue(key, out value);
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() =>
|
||||
GetEnumerator();
|
||||
|
||||
/// <summary>
|
||||
/// Converts parameter collection to a parameter string.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the parameters.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder queryBuilder = new();
|
||||
|
||||
if (_entries.Count > 0)
|
||||
{
|
||||
queryBuilder.Append('?');
|
||||
bool first = true;
|
||||
|
||||
foreach (KeyValuePair<string, object> kvp in _entries)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
queryBuilder.Append('&');
|
||||
}
|
||||
else
|
||||
{
|
||||
first = false;
|
||||
}
|
||||
|
||||
queryBuilder.Append(Uri.EscapeDataString(kvp.Key));
|
||||
queryBuilder.Append('=');
|
||||
queryBuilder.Append(Uri.EscapeDataString(kvp.Value != null ? kvp.Value.ToString() : ""));
|
||||
}
|
||||
}
|
||||
|
||||
return queryBuilder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a collection of parameters to the local parameter list.
|
||||
/// </summary>
|
||||
/// <param name="parameters">An IEnumerable of KeyValuePairs to add to the current parameter list.</param>
|
||||
public void FromParameters(IEnumerable<KeyValuePair<string, object>> parameters) =>
|
||||
_entries.AddRange(parameters);
|
||||
}
|
||||
|
||||
|
||||
public static class ParametersExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Searches <paramref name="parameters"/> for <paramref name="key"/>
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the parameter to return</typeparam>
|
||||
/// <param name="parameters">A collection of parameters to search</param>
|
||||
/// <param name="key">The key of the parameter to find</param>
|
||||
/// <returns>A matching value of <typeparamref name="T"/> if it exists</returns>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static T GetValue<T>(this IEnumerable<KeyValuePair<string, object>> parameters, string key) =>
|
||||
(T)GetValue(parameters, key, typeof(T));
|
||||
|
||||
/// <summary>
|
||||
/// Searches <paramref name="parameters"/> for value referenced by <paramref name="key"/>
|
||||
/// </summary>
|
||||
/// <param name="parameters">A collection of parameters to search</param>
|
||||
/// <param name="key">The key of the parameter to find</param>
|
||||
/// <param name="type">The type of the parameter to return</param>
|
||||
/// <returns>A matching value of <paramref name="type"/> if it exists</returns>
|
||||
/// <exception cref="InvalidCastException">Unable to convert the value of Type</exception>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static object GetValue(this IEnumerable<KeyValuePair<string, object>> parameters, string key, Type type)
|
||||
{
|
||||
foreach (KeyValuePair<string, object> kvp in parameters)
|
||||
{
|
||||
if (string.Compare(kvp.Key, key, StringComparison.Ordinal) == 0)
|
||||
{
|
||||
if (TryGetValueInternal(kvp, type, out object value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new InvalidCastException($"Unable to convert the value of Type '{kvp.Value.GetType().FullName}' to '{type.FullName}' for the key '{key}' ");
|
||||
}
|
||||
}
|
||||
|
||||
return GetDefault(type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches <paramref name="parameters"/> for value referenced by <paramref name="key"/>
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the parameter to return</typeparam>
|
||||
/// <param name="parameters">A collection of parameters to search</param>
|
||||
/// <param name="key">The key of the parameter to find</param>
|
||||
/// <param name="value">The value of parameter to return</param>
|
||||
/// <returns>Success if value is found; otherwise returns <c>false</c></returns>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static bool TryGetValue<T>(this IEnumerable<KeyValuePair<string, object>> parameters, string key, out T value)
|
||||
{
|
||||
Type type = typeof(T);
|
||||
|
||||
foreach (KeyValuePair<string, object> kvp in parameters)
|
||||
{
|
||||
if (string.Compare(kvp.Key, key, StringComparison.Ordinal) == 0)
|
||||
{
|
||||
bool success = TryGetValueInternal(kvp, typeof(T), out object valueAsObject);
|
||||
value = (T)valueAsObject;
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches <paramref name="parameters"/> for value referenced by <paramref name="key"/>
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the parameter to return</typeparam>
|
||||
/// <param name="parameters">A collection of parameters to search</param>
|
||||
/// <param name="key">The key of the parameter to find</param>
|
||||
/// <returns>An IEnumerable{T} of all the values referenced by key</returns>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static IEnumerable<T> GetValues<T>(this IEnumerable<KeyValuePair<string, object>> parameters, string key)
|
||||
{
|
||||
List<T> values = [];
|
||||
Type type = typeof(T);
|
||||
|
||||
foreach (KeyValuePair<string, object> kvp in parameters)
|
||||
{
|
||||
if (string.Compare(kvp.Key, key, StringComparison.Ordinal) == 0)
|
||||
{
|
||||
TryGetValueInternal(kvp, type, out object value);
|
||||
values.Add((T)value);
|
||||
}
|
||||
}
|
||||
|
||||
return values.AsEnumerable();
|
||||
}
|
||||
|
||||
private static bool TryGetValueInternal(KeyValuePair<string, object> kvp, Type type, out object value)
|
||||
{
|
||||
value = GetDefault(type);
|
||||
bool success = false;
|
||||
if (kvp.Value == null)
|
||||
{
|
||||
success = true;
|
||||
}
|
||||
else if (kvp.Value.GetType() == type)
|
||||
{
|
||||
success = true;
|
||||
value = kvp.Value;
|
||||
}
|
||||
else if (type.IsAssignableFrom(kvp.Value.GetType()))
|
||||
{
|
||||
success = true;
|
||||
value = kvp.Value;
|
||||
}
|
||||
else if (type.IsEnum)
|
||||
{
|
||||
string valueAsString = kvp.Value.ToString();
|
||||
if (Enum.IsDefined(type, valueAsString))
|
||||
{
|
||||
success = true;
|
||||
value = Enum.Parse(type, valueAsString);
|
||||
}
|
||||
else if (int.TryParse(valueAsString, out int numericValue))
|
||||
{
|
||||
success = true;
|
||||
value = Enum.ToObject(type, numericValue);
|
||||
}
|
||||
}
|
||||
|
||||
if (!success && type.GetInterface("System.IConvertible") != null)
|
||||
{
|
||||
success = true;
|
||||
value = System.Convert.ChangeType(kvp.Value, type);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see if key exists in parameter collection
|
||||
/// </summary>
|
||||
/// <param name="parameters">IEnumerable to search</param>
|
||||
/// <param name="key">The key to search the <paramref name="parameters"/> for existence</param>
|
||||
/// <returns><c>true</c> if key exists; <c>false</c> otherwise</returns>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static bool ContainsKey(this IEnumerable<KeyValuePair<string, object>> parameters, string key) =>
|
||||
parameters.Any(x => string.Compare(x.Key, key, StringComparison.Ordinal) == 0);
|
||||
|
||||
private static object GetDefault(Type type)
|
||||
{
|
||||
if (type.IsValueType)
|
||||
{
|
||||
return Activator.CreateInstance(type);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,614 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MAX.Core.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// 反射操作
|
||||
/// </summary>
|
||||
public static class ReflectionHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取类型描述,使用DescriptionAttribute设置描述
|
||||
/// </summary>
|
||||
/// <typeparam name="T">类型</typeparam>
|
||||
public static string GetDescription<T>()
|
||||
{
|
||||
return GetDescription(Common.GetType<T>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取类型成员描述,使用DescriptionAttribute设置描述
|
||||
/// </summary>
|
||||
/// <typeparam name="T">类型</typeparam>
|
||||
/// <param name="memberName">成员名称</param>
|
||||
public static string GetDescription<T>(string memberName)
|
||||
{
|
||||
return GetDescription(Common.GetType<T>(), memberName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取类型成员描述,使用DescriptionAttribute设置描述
|
||||
/// </summary>
|
||||
/// <param name="type">类型</param>
|
||||
/// <param name="memberName">成员名称</param>
|
||||
public static string GetDescription(Type type, string memberName)
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(memberName))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return GetDescription(type.GetTypeInfo().GetMember(memberName).FirstOrDefault());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取类型成员描述,使用DescriptionAttribute设置描述
|
||||
/// </summary>
|
||||
/// <param name="member">成员</param>
|
||||
public static string GetDescription(MemberInfo member)
|
||||
{
|
||||
if (member == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return member.GetCustomAttribute<DescriptionAttribute>() is DescriptionAttribute attribute ? attribute.Description : member.Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取显示名称,使用DisplayNameAttribute设置显示名称
|
||||
/// </summary>
|
||||
/// <typeparam name="T">类型</typeparam>
|
||||
public static string GetDisplayName<T>()
|
||||
{
|
||||
return GetDisplayName(Common.GetType<T>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取显示名称,使用DisplayAttribute或DisplayNameAttribute设置显示名称
|
||||
/// </summary>
|
||||
public static string GetDisplayName(MemberInfo member)
|
||||
{
|
||||
if (member == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (member.GetCustomAttribute<DisplayNameAttribute>() is DisplayNameAttribute displayNameAttribute)
|
||||
{
|
||||
return displayNameAttribute.DisplayName;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取显示名称或描述,使用DisplayNameAttribute设置显示名称,使用DescriptionAttribute设置描述
|
||||
/// </summary>
|
||||
/// <typeparam name="T">类型</typeparam>
|
||||
public static string GetDisplayNameOrDescription<T>()
|
||||
{
|
||||
return GetDisplayNameOrDescription(Common.GetType<T>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取属性显示名称或描述,使用DisplayAttribute或DisplayNameAttribute设置显示名称,使用DescriptionAttribute设置描述
|
||||
/// </summary>
|
||||
public static string GetDisplayNameOrDescription(MemberInfo member)
|
||||
{
|
||||
string result = GetDisplayName(member);
|
||||
return string.IsNullOrWhiteSpace(result) ? GetDescription(member) : result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类型列表
|
||||
/// </summary>
|
||||
/// <typeparam name="TFind">查找类型</typeparam>
|
||||
/// <param name="assemblies">待查找的程序集列表</param>
|
||||
public static List<Type> FindTypes<TFind>(params Assembly[] assemblies)
|
||||
{
|
||||
Type findType = typeof(TFind);
|
||||
return FindTypes(findType, assemblies);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类型列表
|
||||
/// </summary>
|
||||
/// <param name="findType">查找类型</param>
|
||||
/// <param name="assemblies">待查找的程序集列表</param>
|
||||
public static List<Type> FindTypes(Type findType, params Assembly[] assemblies)
|
||||
{
|
||||
List<Type> result = [];
|
||||
foreach (Assembly assembly in assemblies)
|
||||
{
|
||||
result.AddRange(GetTypes(findType, assembly));
|
||||
}
|
||||
|
||||
return result.Distinct().ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取类型列表
|
||||
/// </summary>
|
||||
private static List<Type> GetTypes(Type findType, Assembly assembly)
|
||||
{
|
||||
List<Type> result = [];
|
||||
if (assembly == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
Type[] types;
|
||||
try
|
||||
{
|
||||
types = assembly.GetTypes();
|
||||
}
|
||||
catch (ReflectionTypeLoadException ex)
|
||||
{
|
||||
Debug.WriteLine(ex);
|
||||
return result;
|
||||
}
|
||||
foreach (Type type in types)
|
||||
{
|
||||
AddType(result, findType, type);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加类型
|
||||
/// </summary>
|
||||
private static void AddType(List<Type> result, Type findType, Type type)
|
||||
{
|
||||
if (type.IsInterface || type.IsAbstract)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (findType.IsAssignableFrom(type) == false && MatchGeneric(findType, type) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
result.Add(type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 泛型匹配
|
||||
/// </summary>
|
||||
private static bool MatchGeneric(Type findType, Type type)
|
||||
{
|
||||
if (findType.IsGenericTypeDefinition == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Type definition = findType.GetGenericTypeDefinition();
|
||||
foreach (Type implementedInterface in type.FindInterfaces((filter, criteria) => true, null))
|
||||
{
|
||||
if (implementedInterface.IsGenericType == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return definition.IsAssignableFrom(implementedInterface.GetGenericTypeDefinition());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取实现了接口的所有实例
|
||||
/// </summary>
|
||||
/// <typeparam name="TInterface">接口类型</typeparam>
|
||||
/// <param name="assemblies">待查找的程序集列表</param>
|
||||
public static List<TInterface> GetInstancesByInterface<TInterface>(params Assembly[] assemblies)
|
||||
{
|
||||
return FindTypes<TInterface>(assemblies)
|
||||
.Select(t => CreateInstance<TInterface>(t)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 动态创建实例
|
||||
/// </summary>
|
||||
/// <typeparam name="T">目标类型</typeparam>
|
||||
/// <param name="type">类型</param>
|
||||
/// <param name="parameters">传递给构造函数的参数</param>
|
||||
public static T CreateInstance<T>(Type type, params object[] parameters)
|
||||
{
|
||||
return Convert.To<T>(Activator.CreateInstance(type, parameters));
|
||||
}
|
||||
|
||||
public static Type GetType(string typeName)
|
||||
{
|
||||
|
||||
Type type = null;
|
||||
|
||||
Assembly[] assemblyArray = AppDomain.CurrentDomain.GetAssemblies();
|
||||
|
||||
int assemblyArrayLength = assemblyArray.Length;
|
||||
|
||||
for (int i = 0; i < assemblyArrayLength; ++i)
|
||||
{
|
||||
|
||||
type = assemblyArray[i].GetType(typeName);
|
||||
|
||||
if (type != null)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < assemblyArrayLength; ++i)
|
||||
{
|
||||
Type[] typeArray = assemblyArray[i].GetTypes();
|
||||
int typeArrayLength = typeArray.Length;
|
||||
for (int j = 0; j < typeArrayLength; ++j)
|
||||
{
|
||||
if (typeArray[j].Name.Equals(typeName))
|
||||
{
|
||||
return typeArray[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取程序集
|
||||
/// </summary>
|
||||
/// <param name="assemblyName">程序集名称</param>
|
||||
public static Assembly GetAssembly(string assemblyName)
|
||||
{
|
||||
return Assembly.Load(new AssemblyName(assemblyName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否布尔类型
|
||||
/// </summary>
|
||||
/// <param name="member">成员</param>
|
||||
public static bool IsBool(MemberInfo member)
|
||||
{
|
||||
if (member == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return member.MemberType switch
|
||||
{
|
||||
MemberTypes.TypeInfo => member.ToString() == "System.Boolean",
|
||||
MemberTypes.Property => IsBool((PropertyInfo)member),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否布尔类型
|
||||
/// </summary>
|
||||
private static bool IsBool(PropertyInfo property)
|
||||
{
|
||||
return property.PropertyType == typeof(bool) || property.PropertyType == typeof(bool?);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否枚举类型
|
||||
/// </summary>
|
||||
/// <param name="member">成员</param>
|
||||
public static bool IsEnum(MemberInfo member)
|
||||
{
|
||||
if (member == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return member.MemberType switch
|
||||
{
|
||||
MemberTypes.TypeInfo => ((TypeInfo)member).IsEnum,
|
||||
MemberTypes.Property => IsEnum((PropertyInfo)member),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否枚举类型
|
||||
/// </summary>
|
||||
private static bool IsEnum(PropertyInfo property)
|
||||
{
|
||||
if (property.PropertyType.GetTypeInfo().IsEnum)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Type value = Nullable.GetUnderlyingType(property.PropertyType);
|
||||
if (value == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return value.GetTypeInfo().IsEnum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否日期类型
|
||||
/// </summary>
|
||||
/// <param name="member">成员</param>
|
||||
public static bool IsDate(MemberInfo member)
|
||||
{
|
||||
if (member == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return member.MemberType switch
|
||||
{
|
||||
MemberTypes.TypeInfo => member.ToString() == "System.DateTime",
|
||||
MemberTypes.Property => IsDate((PropertyInfo)member),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否日期类型
|
||||
/// </summary>
|
||||
private static bool IsDate(PropertyInfo property)
|
||||
{
|
||||
if (property.PropertyType == typeof(DateTime))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (property.PropertyType == typeof(DateTime?))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否整型
|
||||
/// </summary>
|
||||
/// <param name="member">成员</param>
|
||||
public static bool IsInt(MemberInfo member)
|
||||
{
|
||||
if (member == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return member.MemberType switch
|
||||
{
|
||||
MemberTypes.TypeInfo => member.ToString() is "System.Int32" or "System.Int16" or "System.Int64",
|
||||
MemberTypes.Property => IsInt((PropertyInfo)member),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否整型
|
||||
/// </summary>
|
||||
private static bool IsInt(PropertyInfo property)
|
||||
{
|
||||
if (property.PropertyType == typeof(int))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (property.PropertyType == typeof(int?))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (property.PropertyType == typeof(short))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (property.PropertyType == typeof(short?))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (property.PropertyType == typeof(long))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (property.PropertyType == typeof(long?))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否数值类型
|
||||
/// </summary>
|
||||
/// <param name="member">成员</param>
|
||||
public static bool IsNumber(MemberInfo member)
|
||||
{
|
||||
if (member == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsInt(member))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return member.MemberType switch
|
||||
{
|
||||
MemberTypes.TypeInfo => member.ToString() is "System.Double" or "System.Decimal" or "System.Single",
|
||||
MemberTypes.Property => IsNumber((PropertyInfo)member),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否数值类型
|
||||
/// </summary>
|
||||
private static bool IsNumber(PropertyInfo property)
|
||||
{
|
||||
if (property.PropertyType == typeof(double))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (property.PropertyType == typeof(double?))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (property.PropertyType == typeof(decimal))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (property.PropertyType == typeof(decimal?))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (property.PropertyType == typeof(float))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (property.PropertyType == typeof(float?))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否集合
|
||||
/// </summary>
|
||||
/// <param name="type">类型</param>
|
||||
public static bool IsCollection(Type type)
|
||||
{
|
||||
if (type.IsArray)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return IsGenericCollection(type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否泛型集合
|
||||
/// </summary>
|
||||
/// <param name="type">类型</param>
|
||||
public static bool IsGenericCollection(Type type)
|
||||
{
|
||||
if (!type.IsGenericType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Type typeDefinition = type.GetGenericTypeDefinition();
|
||||
return typeDefinition == typeof(IEnumerable<>)
|
||||
|| typeDefinition == typeof(IReadOnlyCollection<>)
|
||||
|| typeDefinition == typeof(IReadOnlyList<>)
|
||||
|| typeDefinition == typeof(ICollection<>)
|
||||
|| typeDefinition == typeof(IList<>)
|
||||
|| typeDefinition == typeof(List<>);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从目录中获取所有程序集
|
||||
/// </summary>
|
||||
/// <param name="directoryPath">目录绝对路径</param>
|
||||
public static List<Assembly> GetAssemblies(string directoryPath)
|
||||
{
|
||||
return Directory.GetFiles(directoryPath, "*.*", SearchOption.AllDirectories).ToList()
|
||||
.Where(t => t.EndsWith(".exe") || t.EndsWith(".dll"))
|
||||
.Select(path => Assembly.Load(new AssemblyName(path))).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取公共属性列表
|
||||
/// </summary>
|
||||
/// <param name="instance">实例</param>
|
||||
public static List<CommonItem> GetPublicProperties(object instance)
|
||||
{
|
||||
PropertyInfo[] properties = instance.GetType().GetProperties();
|
||||
return properties.ToList().Select(t => new CommonItem(t.Name, t.GetValue(instance))).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取顶级基类
|
||||
/// </summary>
|
||||
/// <typeparam name="T">类型</typeparam>
|
||||
public static Type GetTopBaseType<T>()
|
||||
{
|
||||
return GetTopBaseType(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取顶级基类
|
||||
/// </summary>
|
||||
/// <param name="type">类型</param>
|
||||
public static Type GetTopBaseType(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (type.IsInterface)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
if (type.BaseType == typeof(object))
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
return GetTopBaseType(type.BaseType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取元素类型,如果是集合,返回集合的元素类型
|
||||
/// </summary>
|
||||
/// <param name="type">类型</param>
|
||||
public static Type GetElementType(Type type)
|
||||
{
|
||||
if (IsCollection(type) == false)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
if (type.IsArray)
|
||||
{
|
||||
return type.GetElementType();
|
||||
}
|
||||
|
||||
Type[] genericArgumentsTypes = type.GetTypeInfo().GetGenericArguments();
|
||||
if (genericArgumentsTypes == null || genericArgumentsTypes.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("泛型类型参数不能为空");
|
||||
}
|
||||
|
||||
return genericArgumentsTypes[0];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace MAX.Core.Helpers;
|
||||
|
||||
public class UriHelper
|
||||
{
|
||||
#region 对外公开方法
|
||||
/// <summary>
|
||||
/// 带有前缀的域名
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetSchemeDomain(string url)
|
||||
{
|
||||
Uri uri = new(url);
|
||||
return $"{uri.Scheme}://{uri.Authority}";
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取域名
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetDomain(string url)
|
||||
{
|
||||
Uri uri = new(url);
|
||||
return uri.Host;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取 URL
|
||||
/// </summary>
|
||||
/// <param name="url">URL 地址</param>
|
||||
/// <returns></returns>
|
||||
public static string GetUrl(string url)
|
||||
{
|
||||
Uri uri = new(url);
|
||||
return uri.AbsolutePath;
|
||||
}
|
||||
/// <summary>
|
||||
/// URL 解码
|
||||
/// </summary>
|
||||
/// <param name="url">URL 地址</param>
|
||||
/// <returns></returns>
|
||||
public static string UrlDecode(string url)
|
||||
{
|
||||
return System.Web.HttpUtility.UrlDecode(url);
|
||||
}
|
||||
/// <summary>
|
||||
/// URL 解码
|
||||
/// </summary>
|
||||
/// <param name="url">URL 地址</param>
|
||||
/// <param name="encoding">编码格式</param>
|
||||
/// <returns></returns>
|
||||
public static string UrlDecode(string url, Encoding encoding)
|
||||
{
|
||||
return System.Web.HttpUtility.UrlDecode(url, encoding);
|
||||
}
|
||||
/// <summary>
|
||||
/// URL 编码
|
||||
/// </summary>
|
||||
/// <param name="url">URL 地址</param>
|
||||
/// <returns></returns>
|
||||
public static string UrlEncode(string url)
|
||||
{
|
||||
return System.Web.HttpUtility.UrlEncode(url);
|
||||
}
|
||||
/// <summary>
|
||||
/// URL 编码
|
||||
/// </summary>
|
||||
/// <param name="url">URL 地址</param>
|
||||
/// <param name="encoding">编码格式</param>
|
||||
/// <returns></returns>
|
||||
public static string UrlEncode(string url, Encoding encoding)
|
||||
{
|
||||
return System.Web.HttpUtility.UrlEncode(url, encoding);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取参数列表
|
||||
/// </summary>
|
||||
/// <param name="url">Url 地址</param>
|
||||
/// <returns></returns>
|
||||
public static List<string> GetQueryList(string url)
|
||||
{
|
||||
return GetQueryList(url, Encoding.UTF8);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取参数列表
|
||||
/// </summary>
|
||||
/// <param name="url">Url 地址</param>
|
||||
/// <param name="encoding">编码格式</param>
|
||||
/// <returns></returns>
|
||||
public static List<string> GetQueryList(string url, Encoding encoding)
|
||||
{
|
||||
Uri uri = new(url);
|
||||
string query = uri.PathAndQuery;
|
||||
if (query.IndexOf(".") > 0)
|
||||
{
|
||||
query = query.Substring(0, query.IndexOf("."));
|
||||
}
|
||||
|
||||
List<string> dataList = [];
|
||||
string[] queryDataList = query.Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (queryDataList != null && queryDataList.Length > 0)
|
||||
{
|
||||
foreach (string queryData in queryDataList)
|
||||
{
|
||||
dataList.Add(System.Web.HttpUtility.UrlDecode(queryData, encoding));
|
||||
}
|
||||
}
|
||||
return dataList;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取参数字典
|
||||
/// </summary>
|
||||
/// <param name="url">Url 地址</param>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<string, string> GetQueryDict(string url)
|
||||
{
|
||||
return GetQueryDict(url, Encoding.UTF8);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取参数字典
|
||||
/// </summary>
|
||||
/// <param name="url">Url 地址</param>
|
||||
/// <param name="encoding">编码格式</param>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<string, string> GetQueryDict(string url, Encoding encoding)
|
||||
{
|
||||
Uri uri = new(url);
|
||||
string query = uri.Query.TrimStart(new char[] { '?' });
|
||||
|
||||
Dictionary<string, string> dataDict = [];
|
||||
string[] queryDataList = query.Split(new string[] { "&" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (queryDataList != null && queryDataList.Length > 0)
|
||||
{
|
||||
foreach (string queryData in queryDataList)
|
||||
{
|
||||
string[] keyValue = queryData.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (!dataDict.ContainsKey(keyValue[0]))
|
||||
{
|
||||
dataDict.Add(keyValue[0].ToLower(), System.Web.HttpUtility.UrlDecode(keyValue[1], encoding));
|
||||
}
|
||||
}
|
||||
}
|
||||
return dataDict;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
namespace MAX.Core.Interfaces;
|
||||
|
||||
public interface IPriority
|
||||
{
|
||||
/// <summary> 优先级(优先级越高越先执行) </summary>
|
||||
int Priority { get; }
|
||||
}
|
||||
|
||||
public static class IntPriority
|
||||
{
|
||||
public const int Highest = 5000;
|
||||
|
||||
public const int VeryHigh = 4000;
|
||||
|
||||
public const int Higher = 3000;
|
||||
|
||||
public const int High = 2000;
|
||||
|
||||
public const int AboveNormal = 1000;
|
||||
|
||||
public const int Normal = 0;
|
||||
|
||||
public const int BelowNormal = -1000;
|
||||
|
||||
public const int Low = -2000;
|
||||
|
||||
public const int Lower = -3000;
|
||||
|
||||
public const int VeryLow = -4000;
|
||||
|
||||
public const int Lowest = -5000;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using MAX.Core.DependencyInjection;
|
||||
|
||||
namespace MAX.Core.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// 启动器:实现 <see cref="IDependencyRegistrar"/>,由宿主项目统一发现并按 <see cref="Priority"/> 排序执行。
|
||||
/// </summary>
|
||||
public interface IStartup : IDependencyRegistrar
|
||||
{
|
||||
/// <summary>
|
||||
/// 优先级(优先级越高越先执行)
|
||||
/// </summary>
|
||||
int Priority { get; }
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
void Initialize();
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MAX.Core.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// 单例,需要在当前类中定义
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class SingleInstance<T> where T : class
|
||||
{
|
||||
private static readonly object lockObj = new();
|
||||
private static T mySelf;//= default(T);
|
||||
public static T Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (lockObj)
|
||||
{
|
||||
mySelf ??= InstanceCreator.CreateInstance<T>();
|
||||
}
|
||||
|
||||
return mySelf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class InstanceCreator
|
||||
{
|
||||
public static T CreateInstance<T>()
|
||||
{
|
||||
Type type = typeof(T);
|
||||
try
|
||||
{
|
||||
return (T)type.Assembly.CreateInstance(type.FullName, true, BindingFlags.NonPublic | BindingFlags.Instance, null, null, null, null);
|
||||
}
|
||||
catch (MissingMethodException ex)
|
||||
{
|
||||
throw new Exception($"{ex.Message}\n(单例模式下,构造函数必须为 private)");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
namespace MAX.Core.Logger;
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of <see cref="ILoggerBase"/> that logs into a <see cref="TextWriter"/>.
|
||||
/// </summary>
|
||||
public class ConsoleLogger : ILoggerFacade
|
||||
{
|
||||
private readonly bool _debug;
|
||||
private readonly bool _console;
|
||||
|
||||
public bool IsDebugEnabled => true;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="ConsoleLogger"/> that writes to
|
||||
/// the console output.
|
||||
/// </summary>
|
||||
public ConsoleLogger(bool debug = true, bool console = true)
|
||||
{
|
||||
_debug = debug;
|
||||
_console = console;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///// <summary>
|
||||
///// Disposes the associated <see cref="TextWriter"/>.
|
||||
///// </summary>
|
||||
///// <param name="disposing">When <see langword="true"/>, disposes the associated <see cref="TextWriter"/>.</param>
|
||||
//protected virtual void Dispose(bool disposing)
|
||||
//{
|
||||
// if (disposing)
|
||||
// {
|
||||
// writer?.Dispose();
|
||||
// }
|
||||
//}
|
||||
|
||||
///<summary>
|
||||
///Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
///</summary>
|
||||
/// <remarks>Calls <see cref="Dispose(bool)"/></remarks>.
|
||||
///<filterpriority>2</filterpriority>
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public void Debug(Exception ex, string message)
|
||||
{
|
||||
Log(message, LogLevel.Debug);
|
||||
}
|
||||
|
||||
public void Debug(string message)
|
||||
{
|
||||
Log(message, LogLevel.Debug);
|
||||
}
|
||||
|
||||
public void Info(Exception ex, string message)
|
||||
{
|
||||
Log(message, LogLevel.Info);
|
||||
}
|
||||
|
||||
public void Info(string message)
|
||||
{
|
||||
Log(message, LogLevel.Info);
|
||||
}
|
||||
|
||||
public void Warn(Exception ex, string message)
|
||||
{
|
||||
Log(message, LogLevel.Warn);
|
||||
}
|
||||
|
||||
public void Warn(string message)
|
||||
{
|
||||
Log(message, LogLevel.Warn);
|
||||
}
|
||||
|
||||
public void Error(Exception ex, string message)
|
||||
{
|
||||
Log(message, LogLevel.Error);
|
||||
}
|
||||
|
||||
public void Error(string message)
|
||||
{
|
||||
Log(message, LogLevel.Error);
|
||||
}
|
||||
|
||||
public void Fatal(Exception ex, string message)
|
||||
{
|
||||
Log(message, LogLevel.Fatal);
|
||||
}
|
||||
|
||||
public void Fatal(string message)
|
||||
{
|
||||
Log(message, LogLevel.Fatal);
|
||||
}
|
||||
|
||||
public void Error(Exception ex)
|
||||
{
|
||||
Log(ex.Message, LogLevel.Error);
|
||||
}
|
||||
|
||||
public void Log(string message, LogLevel level)
|
||||
{
|
||||
string messageToLog = string.Format(CultureInfo.InvariantCulture, "{1}: {2}. Timestamp:{0:u}.", DateTime.Now,
|
||||
level.ToString().ToUpper(CultureInfo.InvariantCulture), message);
|
||||
//Trace.WriteLine(messageToLog);
|
||||
if (_debug)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(messageToLog);
|
||||
}
|
||||
if (_console)
|
||||
{
|
||||
Console.WriteLine(messageToLog);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
namespace MAX.Core.Logger;
|
||||
|
||||
/// <summary>自定义日志记录器接口</summary>
|
||||
public interface ICustomLogger
|
||||
{
|
||||
/// <summary>记录日志信息</summary>
|
||||
/// <param name="group">日志分组</param>
|
||||
/// <param name="message">日志内容</param>
|
||||
void Log(string group, string message);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
|
||||
namespace MAX.Core.Logger;
|
||||
|
||||
/// <summary>
|
||||
/// 日志操作
|
||||
/// </summary>
|
||||
public interface ILoggerFacade
|
||||
{
|
||||
/// <summary>
|
||||
/// 调试级别是否启用
|
||||
/// </summary>
|
||||
bool IsDebugEnabled { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 调试
|
||||
/// </summary>
|
||||
void Debug(Exception ex, string message);
|
||||
/// <summary>
|
||||
/// 调试
|
||||
/// </summary>
|
||||
/// <param name="message">日志消息</param>
|
||||
void Debug(string message);
|
||||
/// <summary>
|
||||
/// 信息
|
||||
/// </summary>
|
||||
void Info(Exception ex, string message);
|
||||
/// <summary>
|
||||
/// 信息
|
||||
/// </summary>
|
||||
/// <param name="message">日志消息</param>
|
||||
void Info(string message);
|
||||
/// <summary>
|
||||
/// 警告
|
||||
/// </summary>
|
||||
void Warn(Exception ex, string message);
|
||||
/// <summary>
|
||||
/// 警告
|
||||
/// </summary>
|
||||
/// <param name="message">日志消息</param>
|
||||
void Warn(string message);
|
||||
/// <summary>
|
||||
/// 错误
|
||||
/// </summary>
|
||||
void Error(Exception ex, string message);
|
||||
/// <summary>
|
||||
/// 错误
|
||||
/// </summary>
|
||||
/// <param name="message">日志消息</param>
|
||||
void Error(string message);
|
||||
/// <summary>
|
||||
/// 致命错误
|
||||
/// </summary>
|
||||
void Fatal(Exception ex, string message);
|
||||
/// <summary>
|
||||
/// 致命错误
|
||||
/// </summary>
|
||||
/// <param name="message">日志消息</param>
|
||||
void Fatal(string message);
|
||||
void Error(Exception ex);
|
||||
|
||||
/// <summary>
|
||||
/// 写入日志
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="level"></param>
|
||||
void Log(string message, LogLevel level);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace MAX.Core.Logger;
|
||||
|
||||
/// <summary>
|
||||
/// 日志等级
|
||||
/// </summary>
|
||||
public enum LogLevel
|
||||
{
|
||||
Trace = 0,
|
||||
Debug = 1,
|
||||
Info = 2,
|
||||
Warn = 3,
|
||||
Error = 4,
|
||||
Fatal = 5,
|
||||
None = 6
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<NoWarn>NU1608;CS1574;CS1573;CS1572;CS1571;CS1711;CS1570;CS1591</NoWarn>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Web" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,197 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace MAX.Core.Reflections;
|
||||
|
||||
public partial class AppTypeFinder : Finder
|
||||
{
|
||||
public static AppTypeFinder Instance { get; } = new AppTypeFinder();
|
||||
|
||||
/// <summary>
|
||||
/// 所有程序集
|
||||
/// </summary>
|
||||
public static List<Assembly> Assemblies => Instance.GetAssemblies();
|
||||
|
||||
public static Exception LoadDLL(string dllPath, out Assembly assembly)
|
||||
{
|
||||
return Instance.LoadAssemblyToAppDomain(dllPath, out assembly);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 程序集是否匹配
|
||||
/// </summary>
|
||||
protected override bool Match(string assemblyName)
|
||||
{
|
||||
if (base.Match(assemblyName))
|
||||
{
|
||||
if (AvailablePrefix().Exists(assemblyName.StartsWith))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return Regex.IsMatch(assemblyName, "^(MAX\\.)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
protected virtual List<string> AvailablePrefix()
|
||||
{
|
||||
return ["MAX."];
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> GetAllTypes()
|
||||
{
|
||||
List<Type> types = [];
|
||||
foreach (Assembly item in Assemblies)
|
||||
{
|
||||
try
|
||||
{
|
||||
types.AddRange(item.GetTypes());
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找当前程序集中所有继承或实现了指定类型的非抽象类。
|
||||
/// </summary>
|
||||
/// <param name="targetType">
|
||||
/// 要匹配的目标类型,可以是:
|
||||
/// <list type="bullet">
|
||||
/// <item><description>普通接口类型(例如 <c>IMyService</c>)</description></item>
|
||||
/// <item><description>开放泛型接口类型(例如 <c>IRepository<></c>)</description></item>
|
||||
/// <item><description>普通基类类型(例如 <c>BaseHandler</c>)</description></item>
|
||||
/// <item><description>开放泛型基类类型(例如 <c>BaseHandler<></c>)</description></item>
|
||||
/// </list>
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// 所有满足条件的具体类(非抽象类)的 <see cref="Type"/> 数组。
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// 当 <paramref name="targetType"/> 为 <c>null</c> 时抛出。
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// 此方法会遍历 <c>GetAllTypes()</c> 返回的所有类型,并筛选出:
|
||||
/// <list type="bullet">
|
||||
/// <item><description>实现了指定接口的类(包括开放泛型接口的封闭实现)</description></item>
|
||||
/// <item><description>继承了指定基类的类(包括开放泛型基类的封闭实现)</description></item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// <para>示例:</para>
|
||||
/// <code>
|
||||
/// // 查找所有实现了 IEnumDisplayHandler<T> 的类
|
||||
/// var handlers = FindAllDerivedTypes(typeof(IEnumDisplayHandler<>));
|
||||
///
|
||||
/// // 查找所有实现了 IMyService 的类
|
||||
/// var services = FindAllDerivedTypes(typeof(IMyService));
|
||||
///
|
||||
/// // 查找所有继承 BaseHandler 的类
|
||||
/// var subclasses = FindAllDerivedTypes(typeof(BaseHandler));
|
||||
///
|
||||
/// // 查找所有继承开放泛型基类 BaseHandler<T> 的类
|
||||
/// var genericSubclasses = FindAllDerivedTypes(typeof(BaseHandler<>));
|
||||
/// </code>
|
||||
/// </remarks>
|
||||
public static Type[] FindAllDerivedTypes(Type targetType)
|
||||
{
|
||||
if (targetType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(targetType));
|
||||
}
|
||||
|
||||
return GetAllTypes().Where(t =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!t.IsClass || t.IsAbstract)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 开放泛型接口
|
||||
if (targetType.IsInterface && targetType.IsGenericTypeDefinition)
|
||||
{
|
||||
return t.GetInterfaces().Any(i =>
|
||||
i.IsGenericType && i.GetGenericTypeDefinition() == targetType);
|
||||
}
|
||||
|
||||
// 普通接口
|
||||
if (targetType.IsInterface)
|
||||
{
|
||||
return targetType.IsAssignableFrom(t);
|
||||
}
|
||||
|
||||
// 开放泛型基类
|
||||
if (targetType.IsGenericTypeDefinition)
|
||||
{
|
||||
return IsSubclassOfRawGeneric(t, targetType);
|
||||
}
|
||||
|
||||
// 普通基类
|
||||
return targetType.IsAssignableFrom(t) && t != targetType;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查指定类型是否继承自某个开放泛型基类。
|
||||
/// </summary>
|
||||
/// <param name="type">要检查的类型。</param>
|
||||
/// <param name="generic">开放泛型基类类型,例如 <c>BaseHandler<></c>。</param>
|
||||
/// <returns>
|
||||
/// 如果 <paramref name="type"/> 的继承链中存在指定的开放泛型基类,则返回 <c>true</c>;否则返回 <c>false</c>。
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// 此方法会沿着 <paramref name="type"/> 的继承链向上遍历,
|
||||
/// 并在每一级检查是否为指定的开放泛型基类定义。
|
||||
/// </remarks>
|
||||
private static bool IsSubclassOfRawGeneric(Type type, Type generic)
|
||||
{
|
||||
while (type != null && type != typeof(object))
|
||||
{
|
||||
Type cur = type.IsGenericType ? type.GetGenericTypeDefinition() : type;
|
||||
if (generic == cur)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
type = type.BaseType;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 泛型包装方法,查找所有继承或实现了指定类型 <typeparamref name="T"/> 的非抽象类。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">
|
||||
/// 目标类型,可以是接口、开放泛型接口、基类或开放泛型基类。
|
||||
/// </typeparam>
|
||||
/// <returns>
|
||||
/// 所有满足条件的具体类(非抽象类)的 <see cref="Type"/> 数组。
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// 调用示例:
|
||||
/// <code>
|
||||
/// var handlers = FindAllDerivedTypes<IEnumDisplayHandler<>>();
|
||||
/// var services = FindAllDerivedTypes<IMyService>();
|
||||
/// var subclasses = FindAllDerivedTypes<BaseHandler>();
|
||||
/// var genericSubclasses = FindAllDerivedTypes<BaseHandler<>>();
|
||||
/// </code>
|
||||
/// </remarks>
|
||||
public static Type[] FindAllDerivedTypes<T>() => FindAllDerivedTypes(typeof(T));
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
using MAX.Core.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace MAX.Core.Reflections;
|
||||
|
||||
public class Finder
|
||||
{
|
||||
/// <summary>
|
||||
/// 跳过的程序集
|
||||
/// </summary>
|
||||
private const string SkipAssemblies = "^System|^Microsoft|^mscorlib|^netstandard|^Autofac|^AutoMapper|^EntityFramework|^Newtonsoft|^Castle|^NLog|^Pomelo|^AspectCore|^Xunit|^Nito|^Npgsql|^Exceptionless|^MySqlConnector|^Anonymously|^libuv|^api-ms|^clrcompression|^clretwrc|^clrjit|^coreclr|^dbgshim|^e_sqlite3|^hostfxr|^hostpolicy|^MessagePack|^mscordaccore|^mscordbi|^mscorrc|^sni|^sos|^SOS\\.NETCore|^sos_amd64|^SQLitePCLRaw|^StackExchange|^Swashbuckle|^WindowsBase|^ucrtbase|^DotNetCore\\.CAP|^MongoDB|^Confluent\\.Kafka|^librdkafka|^EasyCaching|^RabbitMQ|^Consul|^Dapper|^EnyimMemcachedCore|^Pipelines|^DnsClient|^IdentityModel|^zlib|^Runtime\\.|^Google|^Grpc|^Internal\\.|^Azure|^DevExpress\\.|^FreeSql\\.|^PresentationFramework|^PresentationCore|^Prism|^DirectWriteForwarder|^MAX\\.Common|^ReflectionHelperTypesPublicWrappers|^UIAutomation|^WindowsFormsIntegration";
|
||||
|
||||
/// <summary>
|
||||
/// 获取程序集列表
|
||||
/// </summary>
|
||||
public virtual List<Assembly> GetAssemblies()
|
||||
{
|
||||
LoadAssemblies(AppDomain.CurrentDomain.BaseDirectory);
|
||||
return GetAssembliesFromCurrentAppDomain();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载程序集到当前应用程序域
|
||||
/// </summary>
|
||||
/// <param name="path">目录绝对路径</param>
|
||||
protected void LoadAssemblies(string path)
|
||||
{
|
||||
foreach (string file in Directory.GetFiles(path, "*.dll"))
|
||||
{
|
||||
if (Match(Path.GetFileName(file)) == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
LoadAssemblyToAppDomain(file, out _);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 程序集是否匹配
|
||||
/// </summary>
|
||||
protected virtual bool Match(string assemblyName)
|
||||
{
|
||||
return Regex.IsMatch(assemblyName, SkipAssemblies, RegexOptions.IgnoreCase | RegexOptions.Compiled) == false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将程序集添加当前应用程序域
|
||||
/// </summary>
|
||||
protected Exception LoadAssemblyToAppDomain(string file, out Assembly assembly)
|
||||
{
|
||||
try
|
||||
{
|
||||
//Debug.WriteLine($"Load Assembly : {Path.GetFileName(file)}");
|
||||
AssemblyName assemblyName = AssemblyName.GetAssemblyName(file);
|
||||
assembly = AppDomain.CurrentDomain.Load(assemblyName);
|
||||
return null;
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
// 如果找不到文件,回退到 LoadFrom 方式
|
||||
try
|
||||
{
|
||||
assembly = Assembly.LoadFrom(file);
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
assembly = null;
|
||||
return ex;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
assembly = null;
|
||||
return ex;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从当前应用程序域获取程序集列表
|
||||
/// </summary>
|
||||
protected virtual List<Assembly> GetAssembliesFromCurrentAppDomain()
|
||||
{
|
||||
List<Assembly> result = [];
|
||||
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
if (Match(assembly))
|
||||
{
|
||||
result.Add(assembly);
|
||||
}
|
||||
}
|
||||
return result.Distinct().ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 程序集是否匹配
|
||||
/// </summary>
|
||||
private bool Match(Assembly assembly)
|
||||
{
|
||||
return !Regex.IsMatch(assembly.FullName, SkipAssemblies, RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类型列表
|
||||
/// </summary>
|
||||
/// <typeparam name="T">查找类型</typeparam>
|
||||
/// <param name="assemblies">在指定的程序集列表中查找</param>
|
||||
public List<Type> Find<T>(List<Assembly> assemblies = null)
|
||||
{
|
||||
return Find(typeof(T), assemblies);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类型列表
|
||||
/// </summary>
|
||||
/// <param name="findType">查找类型</param>
|
||||
/// <param name="assemblies">在指定的程序集列表中查找</param>
|
||||
public List<Type> Find(Type findType, List<Assembly> assemblies = null)
|
||||
{
|
||||
assemblies ??= GetAssemblies();
|
||||
return ReflectionHelper.FindTypes(findType, assemblies.ToArray());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/***
|
||||
* _ooOoo_
|
||||
* o8888888o
|
||||
* 88" . "88
|
||||
* (| -_- |)
|
||||
* O\ = /O
|
||||
* ____/`---'\____
|
||||
* . ' \\| |// `.
|
||||
* / \\||| : |||// \
|
||||
* / _||||| -:- |||||- \
|
||||
* | | \\\ - /// | |
|
||||
* | \_| ''\---/'' | |
|
||||
* \ .-\__ `-` ___/-. /
|
||||
* ___`. .' /--.--\ `. . __
|
||||
* ."" '< `.___\_<|>_/___.' >'"".
|
||||
* | | : `- \`.;`\ _ /`;.`/ - ` : | |
|
||||
* \ \ `-. \_ __\ /__ _/ .-` / /
|
||||
* ======`-.____`-.___\_____/___.-`____.-'======
|
||||
* `=---='
|
||||
*
|
||||
* .............................................
|
||||
* 佛祖保佑 永无BUG
|
||||
* 快加工资 不改需求
|
||||
*/
|
||||
|
||||
using MAX.Core.DependencyInjection;
|
||||
using MAX.Core.Interfaces;
|
||||
|
||||
namespace MAX.Core;
|
||||
|
||||
public class Startup : IStartup
|
||||
{
|
||||
public int Priority => int.MaxValue;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Register(IServiceRegistrar registrar)
|
||||
{
|
||||
// 示例:恢复 LazyServiceProvider 后,可在这里注册为单例
|
||||
// registrar.RegisterSingleton<ILazyServiceProvider, LazyServiceProvider>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Store.Contracts;
|
||||
|
||||
public class Class1
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Store.Contracts.Order.Entitys;
|
||||
|
||||
/// <summary>
|
||||
/// 拼多多买手订单表
|
||||
/// </summary>
|
||||
[Table(Name = "wxxd.order_pdd_buyer_order")]
|
||||
public class OrderPddBuyerOrderEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// id
|
||||
/// </summary>
|
||||
[Column(Name = "id", IsPrimary = true, IsIdentity = true)]
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 微信订单
|
||||
/// </summary>
|
||||
[Column(Name = "wx_order_id")]
|
||||
public string WxOrderId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 微信订单sku
|
||||
/// </summary>
|
||||
[Column(Name = "wx_sku_id")]
|
||||
public string WxSkuId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 微信订单发货类型 0 中转仓,1店铺后台直发
|
||||
/// </summary>
|
||||
[Column(Name = "wx_send_type")]
|
||||
public byte WxSendType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 中转单创建时间
|
||||
/// </summary>
|
||||
[Column(Name = "TransitCreateTime")]
|
||||
public DateTime? TransitCreateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 中转仓取号状态
|
||||
/// </summary>
|
||||
[Column(Name = "pre_allocated_order_no")]
|
||||
public int? PreAllocatedOrderNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 买手编号
|
||||
/// </summary>
|
||||
[Column(Name = "buyerId")]
|
||||
public string BuyerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 买手名称
|
||||
/// </summary>
|
||||
[Column(Name = "buyerName")]
|
||||
public string BuyerName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 买手单号
|
||||
/// </summary>
|
||||
[Column(Name = "order_sn")]
|
||||
public string OrderSn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 拍单订单金额
|
||||
/// </summary>
|
||||
[Column(Name = "order_amount")]
|
||||
public int? OrderAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 拍单时间
|
||||
/// </summary>
|
||||
[Column(Name = "order_time")]
|
||||
public long? OrderTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 物流公司名称缩写
|
||||
/// </summary>
|
||||
[Column(Name = "outExpressCompanyCode")]
|
||||
public string OutExpressCompanyCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 拍单物流单号
|
||||
/// </summary>
|
||||
[Column(Name = "tracking_number")]
|
||||
public string TrackingNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单状态
|
||||
/// </summary>
|
||||
[Column(Name = "order_status_prompt")]
|
||||
public string OrderStatusPrompt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 买手售后状态 2, 3, 4, 5, 7, 8, 10, 31 // 为售后,不支持修改物流 0:无售后 2:买家申请退款,待商家处理 3:退货退款,待商家处理 4:商家同意退款,退款中 5:平台同意退款,退款中 6:驳回退款,待买家处理 7:已同意退货退款,待用户发货 8:平台处理中 9:平台拒绝退款,退款关闭 10:退款成功 11:买家撤销 12:买家逾期未处理,退款失败 13:买家逾期,超过有效期 14:换货补寄待商家处理 15:换货补寄待用户处理 16:换货补寄成功 17:换货补寄失败 18:换货补寄待用户确认完成 21:待商家同意维修 22:待用户确认发货 24:维修关闭 25:维修成功 27:待用户确认收货 31:已同意拒收退款,待用户拒收 32:补寄待商家发货
|
||||
/// </summary>
|
||||
[Column(Name = "after_sales_status")]
|
||||
public int? AfterSalesStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 买手订单详情
|
||||
/// </summary>
|
||||
[Column(Name = "order_detail")]
|
||||
public string OrderDetail { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// add_time
|
||||
/// </summary>
|
||||
[Column(Name = "add_time")]
|
||||
public DateTime AddTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// mdy_time
|
||||
/// </summary>
|
||||
[Column(Name = "mdy_time")]
|
||||
public DateTime MdyTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 取件码
|
||||
/// </summary>
|
||||
[Column(Name = "pickup_code")]
|
||||
public string PickupCode { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,416 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Store.Contracts.Order.Entitys;
|
||||
|
||||
/// <summary>
|
||||
/// 微信订单表
|
||||
/// </summary>
|
||||
[Table(Name = "erp.oms_wei_order")]
|
||||
public class WeiOrderEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// id
|
||||
/// </summary>
|
||||
[Column(Name = "id", IsPrimary = true, IsIdentity = true)]
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 店铺id
|
||||
/// </summary>
|
||||
[Column(Name = "shop_id")]
|
||||
public long ShopId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 店铺名称
|
||||
/// </summary>
|
||||
[Column(Name = "shop_name")]
|
||||
public string ShopName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商户id
|
||||
/// </summary>
|
||||
[Column(Name = "merchant_id")]
|
||||
public long MerchantId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单号
|
||||
/// </summary>
|
||||
[Column(Name = "order_id")]
|
||||
public string OrderId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 买家身份标识
|
||||
/// </summary>
|
||||
[Column(Name = "openid")]
|
||||
public string Openid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 秒级时间戳
|
||||
/// </summary>
|
||||
[Column(Name = "create_time")]
|
||||
public int? CreateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 秒级时间戳
|
||||
/// </summary>
|
||||
[Column(Name = "update_time")]
|
||||
public int? UpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// unionid
|
||||
/// </summary>
|
||||
[Column(Name = "unionid")]
|
||||
public string Unionid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态10 待付款;20 待发货;21 部分发货;30 待收货;100 完成;200 全部商品售后之后,订单取消;250 未付款用户主动取消或超时未付款订单自动取消;
|
||||
/// </summary>
|
||||
[Column(Name = "status")]
|
||||
public int? Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 售后信息json
|
||||
/// </summary>
|
||||
[Column(Name = "aftersale_detail")]
|
||||
public string AftersaleDetail { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付信息json
|
||||
/// </summary>
|
||||
[Column(Name = "pay_info")]
|
||||
public string PayInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 额外信息
|
||||
/// </summary>
|
||||
[Column(Name = "ext_info")]
|
||||
public string ExtInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商品总价,单位为分
|
||||
/// </summary>
|
||||
[Column(Name = "product_price")]
|
||||
public int? ProductPrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单金额,单位为分,order_price=original_order_price-discounted_price-deduction_price-change_down_price
|
||||
/// </summary>
|
||||
[Column(Name = "order_price")]
|
||||
public int? OrderPrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 采购价,单位为分
|
||||
/// </summary>
|
||||
[Column(Name = "purchase_price")]
|
||||
public int? PurchasePrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 采购时间
|
||||
/// </summary>
|
||||
[Column(Name = "purchase_time")]
|
||||
public int? PurchaseTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 运费,单位为分
|
||||
/// </summary>
|
||||
[Column(Name = "freight")]
|
||||
public int? Freight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 平台服务费(微信小店:预计技术服务费),单位为分
|
||||
/// </summary>
|
||||
[Column(Name = "predict_commission_fee")]
|
||||
public int? PredictCommissionFee { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 达人佣金(微信小店:分账金额),单位为分
|
||||
/// </summary>
|
||||
[Column(Name = "commission_amount")]
|
||||
public int CommissionAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 优惠券优惠金额,单位为分
|
||||
/// </summary>
|
||||
[Column(Name = "discounted_price")]
|
||||
public int? DiscountedPrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 利润(实付金额-采购价-平台服务费-达人佣金,达人佣金、采购价为空值则为0)
|
||||
/// </summary>
|
||||
[Column(Name = "profit")]
|
||||
public int? Profit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 采购状态,默认值为:0未采购,推送仓库时修改为1采购
|
||||
/// </summary>
|
||||
[Column(Name = "purchase_status")]
|
||||
public int PurchaseStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 延迟发货时间(微信小店:商品发货时效,超时此时间未发货即为发货超时)
|
||||
/// </summary>
|
||||
[Column(Name = "delivery_deadline")]
|
||||
public int? DeliveryDeadline { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 发货时间
|
||||
/// </summary>
|
||||
[Column(Name = "delivery_time")]
|
||||
public int? DeliveryTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 收货人姓名
|
||||
/// </summary>
|
||||
[Column(Name = "user_name")]
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 邮编
|
||||
/// </summary>
|
||||
[Column(Name = "postal_code")]
|
||||
public string PostalCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 省份
|
||||
/// </summary>
|
||||
[Column(Name = "province_name")]
|
||||
public string ProvinceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 城市
|
||||
/// </summary>
|
||||
[Column(Name = "city_name")]
|
||||
public string CityName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 区
|
||||
/// </summary>
|
||||
[Column(Name = "county_name")]
|
||||
public string CountyName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 详细地址
|
||||
/// </summary>
|
||||
[Column(Name = "detail_info")]
|
||||
public string DetailInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 联系方式
|
||||
/// </summary>
|
||||
[Column(Name = "tel_number")]
|
||||
public string TelNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 门牌号码
|
||||
/// </summary>
|
||||
[Column(Name = "house_number")]
|
||||
public string HouseNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 虚拟发货订单联系方式(deliver_method=1时返回)
|
||||
/// </summary>
|
||||
[Column(Name = "virtual_order_tel_number")]
|
||||
public string VirtualOrderTelNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 额外的联系方式信息(虚拟号码相关)
|
||||
/// </summary>
|
||||
[Column(Name = "tel_number_ext_info")]
|
||||
public string TelNumberExtInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 0:不使用虚拟号码,1:使用虚拟号码
|
||||
/// </summary>
|
||||
[Column(Name = "use_tel_number")]
|
||||
public int? UseTelNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标识当前店铺下一个唯一的用户收货地址
|
||||
/// </summary>
|
||||
[Column(Name = "hash_code")]
|
||||
public string HashCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 发货物流信息JSON
|
||||
/// </summary>
|
||||
[Column(Name = "delivery_product_info")]
|
||||
public string DeliveryProductInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 发货完成时间,秒级时间戳
|
||||
/// </summary>
|
||||
[Column(Name = "ship_done_time")]
|
||||
public int? ShipDoneTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 电子面单代发时的订单密文
|
||||
/// </summary>
|
||||
[Column(Name = "ewaybill_order_code")]
|
||||
public string EwaybillOrderCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 结算信息json
|
||||
/// </summary>
|
||||
[Column(Name = "settle_info")]
|
||||
public string SettleInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单审核状态(0待审核1已审核)
|
||||
/// </summary>
|
||||
[Column(Name = "audit_status")]
|
||||
public int? AuditStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单审核时间
|
||||
/// </summary>
|
||||
[Column(Name = "audit_time")]
|
||||
public DateTime? AuditTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// erp发货快递公司
|
||||
/// </summary>
|
||||
[Column(Name = "erp_send_company")]
|
||||
public string ErpSendCompany { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// erp发货快递单号
|
||||
/// </summary>
|
||||
[Column(Name = "erp_send_code")]
|
||||
public string ErpSendCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// erp发货状态
|
||||
/// </summary>
|
||||
[Column(Name = "erp_send_status")]
|
||||
public int? ErpSendStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// erp发货时间
|
||||
/// </summary>
|
||||
[Column(Name = "erp_send_time")]
|
||||
public DateTime? ErpSendTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 旗帜颜色备注,1:灰旗,2:红旗,3:橙旗,4:绿旗,5:天蓝旗,6:紫旗
|
||||
/// </summary>
|
||||
[Column(Name = "colour_flag")]
|
||||
public int? ColourFlag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 旗帜备注时间
|
||||
/// </summary>
|
||||
[Column(Name = "colour_flag_update_time")]
|
||||
public DateTime? ColourFlagUpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 供应商备注异常单
|
||||
/// </summary>
|
||||
[Column(Name = "supplier_remark_exception")]
|
||||
public string SupplierRemarkException { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 礼物单状态,默认值0:不存在礼物单,1:礼物单已发货,2:礼物单信息已更正,3:礼物单发货失败
|
||||
/// </summary>
|
||||
[Column(Name = "gift_order_status")]
|
||||
public byte GiftOrderStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 店铺备注:取微信ext_info.merchant_notes
|
||||
/// </summary>
|
||||
[Column(Name = "shop_remark")]
|
||||
public string ShopRemark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商家的系统备注
|
||||
/// </summary>
|
||||
[Column(Name = "soft_remark")]
|
||||
public string SoftRemark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外采金额(单位:分,整数存储)
|
||||
/// </summary>
|
||||
[Column(Name = "out_amount")]
|
||||
public int OutAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外采账户
|
||||
/// </summary>
|
||||
[Column(Name = "out_account")]
|
||||
public string OutAccount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外采订单号
|
||||
/// </summary>
|
||||
[Column(Name = "out_order_no")]
|
||||
public string OutOrderNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外采快递公司
|
||||
/// </summary>
|
||||
[Column(Name = "out_express_company")]
|
||||
public string OutExpressCompany { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外采快递单号
|
||||
/// </summary>
|
||||
[Column(Name = "out_express_no")]
|
||||
public string OutExpressNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外采是否发货(0 未发货,1 已发货)
|
||||
/// </summary>
|
||||
[Column(Name = "out_shipped")]
|
||||
public byte OutShipped { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否优化过发货0 未优化, 1已优化
|
||||
/// </summary>
|
||||
[Column(Name = "is_shipment_optimized")]
|
||||
public int IsShipmentOptimized { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否优随机使用快递单号0 未使用, 1已使用
|
||||
/// </summary>
|
||||
[Column(Name = "is_express_no_used")]
|
||||
public int IsExpressNoUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外采订单售后状态
|
||||
/// </summary>
|
||||
[Column(Name = "out_after_sale_status")]
|
||||
public string OutAfterSaleStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否支持运费险:0-不支持,1-支持
|
||||
/// </summary>
|
||||
[Column(Name = "has_freight_insurance")]
|
||||
public byte HasFreightInsurance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 运费险金额(单位:元)
|
||||
/// </summary>
|
||||
[Column(Name = "freight_insurance_amount")]
|
||||
public decimal FreightInsuranceAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否外采礼物单:0-否,1-是(外采订单)
|
||||
/// </summary>
|
||||
[Column(Name = "external_gift")]
|
||||
public byte ExternalGift { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 中转仓的状态 0未使用,1已创建,2创建失败(购买失败),3已创建未有上游快递单号,4已创建有上游快递单号
|
||||
/// </summary>
|
||||
[Column(Name = "transfer_warehouse_status")]
|
||||
public byte? TransferWarehouseStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商品运费(由店铺买家支付的)
|
||||
/// </summary>
|
||||
[Column(Name = "postage_price")]
|
||||
public int? PostagePrice { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Store.Contracts.Order.Entitys;
|
||||
|
||||
/// <summary>
|
||||
/// 微信订单商品明细表
|
||||
/// </summary>
|
||||
[Table(Name = "erp.oms_wei_order_item")]
|
||||
public class WeiOrderItemEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// id
|
||||
/// </summary>
|
||||
[Column(Name = "id", IsPrimary = true, IsIdentity = true)]
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 店铺id
|
||||
/// </summary>
|
||||
[Column(Name = "shop_id")]
|
||||
public long ShopId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商户id
|
||||
/// </summary>
|
||||
[Column(Name = "merchant_id")]
|
||||
public long MerchantId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单id(平台订单id)
|
||||
/// </summary>
|
||||
[Column(Name = "order_id")]
|
||||
public string OrderId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商品spuid
|
||||
/// </summary>
|
||||
[Column(Name = "product_id")]
|
||||
public string ProductId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商品skuid
|
||||
/// </summary>
|
||||
[Column(Name = "sku_id")]
|
||||
public string SkuId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// sku小图
|
||||
/// </summary>
|
||||
[Column(Name = "thumb_img")]
|
||||
public string ThumbImg { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// sku数量
|
||||
/// </summary>
|
||||
[Column(Name = "sku_cnt")]
|
||||
public int SkuCnt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 售卖单价(单位:分)
|
||||
/// </summary>
|
||||
[Column(Name = "sale_price")]
|
||||
public int? SalePrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商品标题
|
||||
/// </summary>
|
||||
[Column(Name = "title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 正在售后/退款流程中的 sku 数量
|
||||
/// </summary>
|
||||
[Column(Name = "on_aftersale_sku_cnt")]
|
||||
public int? OnAftersaleSkuCnt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 完成售后/退款的 sku 数量
|
||||
/// </summary>
|
||||
[Column(Name = "finish_aftersale_sku_cnt")]
|
||||
public int? FinishAftersaleSkuCnt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商品编码
|
||||
/// </summary>
|
||||
[Column(Name = "sku_code")]
|
||||
public string SkuCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 市场单价(单位:分)
|
||||
/// </summary>
|
||||
[Column(Name = "market_price")]
|
||||
public int? MarketPrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// sku属性JSON
|
||||
/// </summary>
|
||||
[Column(Name = "sku_attrs")]
|
||||
public string SkuAttrs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// sku实付总价,取estimate_price和change_price中较小值
|
||||
/// </summary>
|
||||
[Column(Name = "real_price")]
|
||||
public int? RealPrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商品外部spuid
|
||||
/// </summary>
|
||||
[Column(Name = "out_product_id")]
|
||||
public string OutProductId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 采购价
|
||||
/// </summary>
|
||||
[Column(Name = "purchase_price")]
|
||||
public int? PurchasePrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 运费
|
||||
/// </summary>
|
||||
[Column(Name = "freight")]
|
||||
public int? Freight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商品外部skuid
|
||||
/// </summary>
|
||||
[Column(Name = "out_sku_id")]
|
||||
public string OutSkuId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否有优惠金额,非必填,默认为false
|
||||
/// </summary>
|
||||
[Column(Name = "is_discounted")]
|
||||
public string IsDiscounted { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 优惠后sku总价,非必填,is_discounted为true时有值
|
||||
/// </summary>
|
||||
[Column(Name = "estimate_price")]
|
||||
public int? EstimatePrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否修改过价格,非必填,默认为false
|
||||
/// </summary>
|
||||
[Column(Name = "is_change_price")]
|
||||
public string IsChangePrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 改价后sku总价,非必填,is_change_price为true时有值
|
||||
/// </summary>
|
||||
[Column(Name = "change_price")]
|
||||
public int? ChangePrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单内商品维度平台券优惠金额 (利润需要计算这个金额在内)
|
||||
/// </summary>
|
||||
[Column(Name = "cash_coupon_discounted_price")]
|
||||
public int? CashCouponDiscountedPrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 区域库存id
|
||||
/// </summary>
|
||||
[Column(Name = "out_warehouse_id")]
|
||||
public string OutWarehouseId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 退货地址
|
||||
/// </summary>
|
||||
[Column(Name = "return_address")]
|
||||
public string ReturnAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商品发货信息JSON
|
||||
/// </summary>
|
||||
[Column(Name = "sku_deliver_info")]
|
||||
public string SkuDeliverInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商品额外服务信息JSON
|
||||
/// </summary>
|
||||
[Column(Name = "extra_service")]
|
||||
public string ExtraService { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用了会员积分抵扣
|
||||
/// </summary>
|
||||
[Column(Name = "use_deduction")]
|
||||
public string UseDeduction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 会员积分抵扣金额,单位为分
|
||||
/// </summary>
|
||||
[Column(Name = "deduction_price")]
|
||||
public int? DeductionPrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 平台服务费(微信小店:预计技术服务费),单位为分
|
||||
/// </summary>
|
||||
[Column(Name = "predict_commission_fee")]
|
||||
public int? PredictCommissionFee { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 达人佣金(微信小店:分账金额),单位为分
|
||||
/// </summary>
|
||||
[Column(Name = "commission_amount")]
|
||||
public int? CommissionAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商品优惠券信息,逐步替换 order.order_detail.coupon_info
|
||||
/// </summary>
|
||||
[Column(Name = "order_product_coupon_info_list")]
|
||||
public string OrderProductCouponInfoList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商品id(o_goods外键)
|
||||
/// </summary>
|
||||
[Column(Name = "erp_goods_id")]
|
||||
public long ErpGoodsId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商品skuid(o_goods_sku外键)
|
||||
/// </summary>
|
||||
[Column(Name = "erp_goods_sku_id")]
|
||||
public long ErpGoodsSkuId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 售后状态 1:无售后或售后关闭,2:售后处理中,3:退款中,4: 退款成功 11 已取消
|
||||
/// </summary>
|
||||
[Column(Name = "refund_status")]
|
||||
public int RefundStatus { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Store.Contracts.Order.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// 拼多多买手号订单服务
|
||||
/// </summary>
|
||||
public interface IOrderPddBuyerService
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取微信订单号,从品多多订单号
|
||||
/// </summary>
|
||||
/// <param name="orderId"></param>
|
||||
/// <returns></returns>
|
||||
string GetWeChatOrderIdByPddOrderId(string orderId);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MAX.Core\MAX.Core.csproj" />
|
||||
<ProjectReference Include="..\Store.Framework\Store.Framework.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="User\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,59 @@
|
||||
using KJD_Web.Utils;
|
||||
using Newtonsoft.Json;
|
||||
using Store.Framework.Dtos;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Web.Http;
|
||||
using System.Web.Http.Controllers;
|
||||
|
||||
namespace Store.Framework.Base;
|
||||
|
||||
public abstract class ApiControllerBase : ApiController
|
||||
{
|
||||
|
||||
protected bool ValidateSign(SignRequestBase request, bool isUserLogin = false)
|
||||
{
|
||||
if (request == null || string.IsNullOrEmpty(request.time) || string.IsNullOrEmpty(request.code))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int time;
|
||||
if (!int.TryParse(request.time, out time))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (request.code != EncrypUtil.Encryption(time))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!isUserLogin && string.IsNullOrWhiteSpace(request.UserName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
private bool IsAllowAnonymous(HttpActionContext context)
|
||||
{
|
||||
// Action 上
|
||||
if (context.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any())
|
||||
return true;
|
||||
// Controller 上
|
||||
if (context.ControllerContext.ControllerDescriptor.ControllerType
|
||||
.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Any())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
private async Task<HttpResponseMessage> OkResponseAsync(object content)
|
||||
{
|
||||
IHttpActionResult result = Ok(content);
|
||||
return await result.ExecuteAsync(CancellationToken.None);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Store.Framework;
|
||||
|
||||
public class Class1
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using MAX.Core.Reflections;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Store.Framework.Commons
|
||||
{
|
||||
public sealed class StoreAppTypeFinder : AppTypeFinder
|
||||
{
|
||||
public static StoreAppTypeFinder Current { get; } = new();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取程序集列表
|
||||
/// </summary>
|
||||
public override List<Assembly> GetAssemblies()
|
||||
{
|
||||
LoadAssemblies(Environment.CurrentDirectory);
|
||||
return GetAssembliesFromCurrentAppDomain();
|
||||
}
|
||||
|
||||
protected override List<string> AvailablePrefix()
|
||||
{
|
||||
return ["Max", "Store"];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
using Autofac;
|
||||
using Autofac.Core;
|
||||
using Autofac.Integration.WebApi;
|
||||
using FreeSql;
|
||||
using MAX.Core.DependencyInjection;
|
||||
using MAX.Core.Helpers;
|
||||
using MAX.Core.Interfaces;
|
||||
using MAX.Core.Logger;
|
||||
using MAX.Framework.Logger;
|
||||
using Store.Framework.Commons;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Store.Framework.DependencyInjection;
|
||||
|
||||
public class ContainerConfig
|
||||
{
|
||||
|
||||
public static IContainer BuildContainer()
|
||||
{
|
||||
var builder = new ContainerBuilder();
|
||||
var appAssembly = StoreAppTypeFinder.Current.GetAssemblies().ToArray();
|
||||
|
||||
var connection = ConfigurationManager.ConnectionStrings["ConnKJD"];
|
||||
if (connection == null || string.IsNullOrWhiteSpace(connection.ConnectionString))
|
||||
{
|
||||
throw new ConfigurationErrorsException("未配置连接字符串:ConnKJD");
|
||||
}
|
||||
// ImageCacheService 使用独立的 imagecache 数据库。
|
||||
builder.Register(_ =>
|
||||
{
|
||||
return new FreeSqlBuilder()
|
||||
.UseConnectionString(
|
||||
DataType.MySql,
|
||||
connection.ConnectionString)
|
||||
.Build();
|
||||
})
|
||||
.As<IFreeSql>()
|
||||
.SingleInstance();
|
||||
|
||||
|
||||
// 注册 Web API 所有 Controller
|
||||
builder.RegisterApiControllers(appAssembly);
|
||||
builder.RegisterInstance(NLogger.Instance).As<ILoggerFacade>().SingleInstance();
|
||||
|
||||
|
||||
|
||||
|
||||
#region 注册所有IOC接口
|
||||
|
||||
Type typeSingleton = typeof(ISingletonDependency);
|
||||
builder.RegisterAssemblyTypes(appAssembly)
|
||||
.Where(a =>
|
||||
typeSingleton.IsAssignableFrom(a)
|
||||
&& a.IsClass
|
||||
&& !a.IsAbstract
|
||||
)
|
||||
.AsImplementedInterfaces()
|
||||
.AsSelf()
|
||||
.SingleInstance();
|
||||
|
||||
Type typeTransient = typeof(ITransientDependency);
|
||||
builder.RegisterAssemblyTypes(appAssembly)
|
||||
.Where(a =>
|
||||
typeTransient.IsAssignableFrom(a)
|
||||
&& a.IsClass
|
||||
&& !a.IsAbstract
|
||||
)
|
||||
.AsImplementedInterfaces()
|
||||
.AsSelf()
|
||||
.InstancePerDependency();
|
||||
|
||||
Type typeScoped = typeof(IScopedDependency);
|
||||
builder.RegisterAssemblyTypes(appAssembly)
|
||||
.Where(a => typeScoped.IsAssignableFrom(a) && a.IsClass && !a.IsAbstract)
|
||||
.AsImplementedInterfaces()
|
||||
.AsSelf()
|
||||
.InstancePerRequest();
|
||||
|
||||
#endregion
|
||||
IServiceRegistrar registrar = new ServiceRegistrarProxy(builder);
|
||||
IEnumerable<IStartup> startupList = ReflectionHelper.GetInstancesByInterface<IStartup>(appAssembly);
|
||||
foreach (IStartup item in startupList.OrderByDescending(a => a.Priority))
|
||||
{
|
||||
Debug.WriteLine($"Startup : {item.GetType()}");
|
||||
item.Initialize();
|
||||
item.Register(registrar);
|
||||
}
|
||||
|
||||
var app = builder.Build();
|
||||
return app;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
using Autofac;
|
||||
using Autofac.Core;
|
||||
using MAX.Core.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Store.Framework.DependencyInjection;
|
||||
|
||||
internal class ServiceRegistrarProxy : IServiceRegistrar
|
||||
{
|
||||
private readonly ContainerBuilder _services;
|
||||
|
||||
public object Services => _services;
|
||||
|
||||
public ServiceRegistrarProxy(ContainerBuilder builder)
|
||||
{
|
||||
_services = builder ?? throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
// ---------------- Scoped ----------------
|
||||
|
||||
public void RegisterScoped<TService>(Func<IServiceProvider, TService> factory)
|
||||
where TService : class
|
||||
{
|
||||
_services.Register(c => factory(c.Resolve<IServiceProvider>()))
|
||||
.As<TService>()
|
||||
.InstancePerLifetimeScope();
|
||||
}
|
||||
|
||||
public void RegisterScoped<TService>(object? serviceKey,
|
||||
Func<IServiceProvider, object?, TService> factory)
|
||||
where TService : class
|
||||
{
|
||||
_services.Register(c => factory(c.Resolve<IServiceProvider>(), serviceKey))
|
||||
.Keyed<TService>(serviceKey ?? throw new ArgumentNullException(nameof(serviceKey)))
|
||||
.InstancePerLifetimeScope();
|
||||
}
|
||||
|
||||
void IServiceRegistrar.RegisterScoped<TService, TImplementation>()
|
||||
{
|
||||
_services.RegisterType<TImplementation>()
|
||||
.As<TService>()
|
||||
.InstancePerLifetimeScope();
|
||||
}
|
||||
|
||||
void IServiceRegistrar.RegisterScoped<TService, TImplementation>(object? serviceKey)
|
||||
{
|
||||
_services.RegisterType<TImplementation>()
|
||||
.Keyed<TService>(serviceKey ?? throw new ArgumentNullException(nameof(serviceKey)))
|
||||
.InstancePerLifetimeScope();
|
||||
}
|
||||
|
||||
// ---------------- Singleton ----------------
|
||||
|
||||
public void RegisterSingleton<TService>(TService instance)
|
||||
where TService : class
|
||||
{
|
||||
_services.RegisterInstance(instance)
|
||||
.As<TService>()
|
||||
.SingleInstance();
|
||||
}
|
||||
|
||||
public void RegisterSingleton<TService>(Func<IServiceProvider, TService> factory)
|
||||
where TService : class
|
||||
{
|
||||
_services.Register(c => factory(c.Resolve<IServiceProvider>()))
|
||||
.As<TService>()
|
||||
.SingleInstance();
|
||||
}
|
||||
|
||||
public void RegisterSingleton<TService>(object? serviceKey, TService instance)
|
||||
where TService : class
|
||||
{
|
||||
_services.RegisterInstance(instance)
|
||||
.Keyed<TService>(serviceKey ?? throw new ArgumentNullException(nameof(serviceKey)))
|
||||
.SingleInstance();
|
||||
}
|
||||
|
||||
public void RegisterSingleton<TService>(object? serviceKey,
|
||||
Func<IServiceProvider, object?, TService> factory)
|
||||
where TService : class
|
||||
{
|
||||
_services.Register(c => factory(c.Resolve<IServiceProvider>(), serviceKey))
|
||||
.Keyed<TService>(serviceKey ?? throw new ArgumentNullException(nameof(serviceKey)))
|
||||
.SingleInstance();
|
||||
}
|
||||
|
||||
void IServiceRegistrar.RegisterSingleton<TService, TImplementation>()
|
||||
{
|
||||
_services.RegisterType<TImplementation>()
|
||||
.As<TService>()
|
||||
.SingleInstance();
|
||||
}
|
||||
|
||||
void IServiceRegistrar.RegisterSingleton<TService, TImplementation>(object? serviceKey)
|
||||
{
|
||||
_services.RegisterType<TImplementation>()
|
||||
.Keyed<TService>(serviceKey ?? throw new ArgumentNullException(nameof(serviceKey)))
|
||||
.SingleInstance();
|
||||
}
|
||||
|
||||
// ---------------- Transient ----------------
|
||||
|
||||
public void RegisterTransient<TService>(Func<IServiceProvider, TService> factory)
|
||||
where TService : class
|
||||
{
|
||||
_services.Register(c => factory(c.Resolve<IServiceProvider>()))
|
||||
.As<TService>()
|
||||
.InstancePerDependency();
|
||||
}
|
||||
|
||||
public void RegisterTransient<TService>(object? serviceKey,
|
||||
Func<IServiceProvider, object?, TService> factory)
|
||||
where TService : class
|
||||
{
|
||||
_services.Register(c => factory(c.Resolve<IServiceProvider>(), serviceKey))
|
||||
.Keyed<TService>(serviceKey ?? throw new ArgumentNullException(nameof(serviceKey)))
|
||||
.InstancePerDependency();
|
||||
}
|
||||
|
||||
void IServiceRegistrar.RegisterTransient<TService, TImplementation>()
|
||||
{
|
||||
_services.RegisterType<TImplementation>()
|
||||
.As<TService>()
|
||||
.InstancePerDependency();
|
||||
}
|
||||
|
||||
void IServiceRegistrar.RegisterTransient<TService, TImplementation>(object? serviceKey)
|
||||
{
|
||||
_services.RegisterType<TImplementation>()
|
||||
.Keyed<TService>(serviceKey ?? throw new ArgumentNullException(nameof(serviceKey)))
|
||||
.InstancePerDependency();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace Store.Framework.Dtos;
|
||||
|
||||
/// <summary>
|
||||
/// Sign签名
|
||||
/// </summary>
|
||||
public class SignRequestBase
|
||||
{
|
||||
public string time { get; set; }
|
||||
public string code { get; set; }
|
||||
public string code_version { get; set; }
|
||||
public string version { get; set; }
|
||||
[JsonProperty("user_name")]
|
||||
public string UserName { get; set; }
|
||||
public string path { get; set; }
|
||||
}
|
||||
|
||||
File renamed without changes.
@@ -1,8 +1,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace KJD_Web.Model
|
||||
namespace Store.Framework.Models
|
||||
{
|
||||
public static class ResultCode
|
||||
{
|
||||
@@ -0,0 +1,25 @@
|
||||
using MAX.Core.DependencyInjection;
|
||||
using MAX.Core.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Store.Framework;
|
||||
|
||||
internal class Startup : IStartup
|
||||
{
|
||||
public int Priority => IntPriority.Normal;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
|
||||
}
|
||||
|
||||
public void Register(IServiceRegistrar registrar)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,24 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Autofac" Version="9.3.2" />
|
||||
<PackageReference Include="Autofac.WebApi2" Version="6.2.0" />
|
||||
<PackageReference Include="AutoMapper" Version="10.1.1" />
|
||||
<PackageReference Include="FreeSql.Provider.MySql" Version="3.5.311" />
|
||||
<PackageReference Include="FreeSql.Repository" Version="3.5.311" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
<PackageReference Include="NLog" Version="6.2.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MAX.Core\MAX.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Web" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,5 +1,4 @@
|
||||
using KJD_Web.Upload.Prod;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
@@ -185,7 +185,8 @@ namespace KJD_Web.Utils
|
||||
else
|
||||
request = (HttpWebRequest)WebRequest.Create(url);
|
||||
|
||||
request.KeepAlive = true;
|
||||
|
||||
request.KeepAlive = true;
|
||||
request.Headers.Add("sec-ch-ua", @"""Not(A:Brand"";v=""8"", ""Chromium"";v=""144"", ""Google Chrome"";v=""144""");
|
||||
request.Headers.Add("sec-ch-ua-mobile", @"?0");
|
||||
request.Headers.Add("sec-ch-ua-platform", @"""Windows""");
|
||||
File renamed without changes.
@@ -7,7 +7,6 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.UI.WebControls.WebParts;
|
||||
|
||||
namespace KJD_Web.Utils
|
||||
{
|
||||
File renamed without changes.
Loaded 100 of 120 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user