From cf062cadcdde591bb7039ec18cdde8bec5be2f46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=99=E5=AD=90?= <454313500@qq.com> Date: Sun, 10 Oct 2021 17:30:31 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A1=86=E6=9E=B6=E5=88=86=E5=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/WeatherForecastController.cs | 2 +- .../Program.cs | 2 +- .../Properties/launchSettings.json | 6 +- .../Startup.cs | 6 +- .../WeatherForecast.cs | 2 +- .../Yi.Framework.ApiMicroservice.csproj} | 0 .../appsettings.Development.json | 0 .../appsettings.json | 0 Yi.Framework/Yi.Framework.Common/Class1.cs | 8 + .../IOCOptions/ElasticSearchOptions.cs | 14 + .../IOCOptions/JWTTokenOptions.cs | 32 + .../IOCOptions/KafkaOptions.cs | 15 + .../IOCOptions/MySqlConnOptions.cs | 9 + .../IOCOptions/RabbitMQOptions.cs | 88 ++ .../IOCOptions/RedisConnOptions.cs | 18 + .../Yi.Framework.Common/Models/LogModel.cs | 18 + .../Yi.Framework.Common/Models/Result.cs | 66 + .../Yi.Framework.Common.csproj | 7 + .../Yi.Framework.Core/CacheClientDB.cs | 1074 +++++++++++++++++ Yi.Framework/Yi.Framework.Core/Class1.cs | 8 + .../ClienExtend/AbstractConsulDispatcher.cs | 71 ++ .../ClienExtend/AverageDispatcher.cs | 44 + .../ClienExtend/PollingDispatcher.cs | 44 + .../ClienExtend/WeightDispatcher.cs | 66 + .../ConsulExtend/ConsulClientOption.cs | 16 + .../ServerExtend/ConsulRegisterOption.cs | 44 + .../ServerExtend/ConsulRegiterExtend.cs | 69 ++ .../ServerExtend/HealthCheckMiddleware.cs | 31 + .../Library/Microsoft.Bcl.AsyncInterfaces.dll | Bin 0 -> 14920 bytes .../Library/ServiceStack.Common.dll | Bin 0 -> 1039872 bytes .../Library/ServiceStack.Interfaces.dll | Bin 0 -> 259584 bytes .../Library/ServiceStack.Redis.dll | Bin 0 -> 872960 bytes .../Library/ServiceStack.Text.dll | Bin 0 -> 658944 bytes Yi.Framework/Yi.Framework.Core/MD5Helper.cs | 47 + .../Yi.Framework.Core/RabbitMQInvoker.cs | 253 ++++ .../Yi.Framework.Core/SnowflakeHelper.cs | 99 ++ .../Yi.Framework.Core.csproj | 7 + Yi.Framework/Yi.Framework.DTOModel/Class1.cs | 8 + .../Yi.Framework.DTOModel.csproj | 7 + Yi.Framework/Yi.Framework.Interface/Class1.cs | 8 + .../Yi.Framework.Interface.csproj | 7 + Yi.Framework/Yi.Framework.Model/Class1.cs | 8 + .../Yi.Framework.Model.csproj | 7 + Yi.Framework/Yi.Framework.Service/Class1.cs | 8 + .../Yi.Framework.Service.csproj | 7 + Yi.Framework/Yi.Framework.WebCore/Class1.cs | 8 + .../Yi.Framework.WebCore/CommonExtend.cs | 36 + .../FilterExtend/CORSFilter.cs | 18 + .../CustomAction2CommitFilterAttribute.cs | 78 ++ .../CustomActionCacheFilterAttribute.cs | 30 + .../CustomActionCheckFilterAttribute.cs | 45 + .../CustomExceptionFilterAttribute.cs | 41 + .../CustomIOCFilterFactoryAttribute.cs | 31 + .../CustomResourceFilterAttribute.cs | 45 + .../FilterExtend/LogActionFilterAttribute.cs | 80 ++ .../PreOptionRequestMiddleware.cs | 49 + .../MiddlewareExtend/StaticPageMiddleware.cs | 156 +++ .../Yi.Framework.WebCore.csproj | 7 + Yi.Framework/Yi.Framework.sln | 72 +- 59 files changed, 2908 insertions(+), 14 deletions(-) rename Yi.Framework/{Yi.Framework => Yi.Framework.ApiMicroservice}/Controllers/WeatherForecastController.cs (95%) rename Yi.Framework/{Yi.Framework => Yi.Framework.ApiMicroservice}/Program.cs (94%) rename Yi.Framework/{Yi.Framework => Yi.Framework.ApiMicroservice}/Properties/launchSettings.json (86%) rename Yi.Framework/{Yi.Framework => Yi.Framework.ApiMicroservice}/Startup.cs (91%) rename Yi.Framework/{Yi.Framework => Yi.Framework.ApiMicroservice}/WeatherForecast.cs (87%) rename Yi.Framework/{Yi.Framework/Yi.Framework.csproj => Yi.Framework.ApiMicroservice/Yi.Framework.ApiMicroservice.csproj} (100%) rename Yi.Framework/{Yi.Framework => Yi.Framework.ApiMicroservice}/appsettings.Development.json (100%) rename Yi.Framework/{Yi.Framework => Yi.Framework.ApiMicroservice}/appsettings.json (100%) create mode 100644 Yi.Framework/Yi.Framework.Common/Class1.cs create mode 100644 Yi.Framework/Yi.Framework.Common/IOCOptions/ElasticSearchOptions.cs create mode 100644 Yi.Framework/Yi.Framework.Common/IOCOptions/JWTTokenOptions.cs create mode 100644 Yi.Framework/Yi.Framework.Common/IOCOptions/KafkaOptions.cs create mode 100644 Yi.Framework/Yi.Framework.Common/IOCOptions/MySqlConnOptions.cs create mode 100644 Yi.Framework/Yi.Framework.Common/IOCOptions/RabbitMQOptions.cs create mode 100644 Yi.Framework/Yi.Framework.Common/IOCOptions/RedisConnOptions.cs create mode 100644 Yi.Framework/Yi.Framework.Common/Models/LogModel.cs create mode 100644 Yi.Framework/Yi.Framework.Common/Models/Result.cs create mode 100644 Yi.Framework/Yi.Framework.Common/Yi.Framework.Common.csproj create mode 100644 Yi.Framework/Yi.Framework.Core/CacheClientDB.cs create mode 100644 Yi.Framework/Yi.Framework.Core/Class1.cs create mode 100644 Yi.Framework/Yi.Framework.Core/ConsulExtend/ClienExtend/AbstractConsulDispatcher.cs create mode 100644 Yi.Framework/Yi.Framework.Core/ConsulExtend/ClienExtend/AverageDispatcher.cs create mode 100644 Yi.Framework/Yi.Framework.Core/ConsulExtend/ClienExtend/PollingDispatcher.cs create mode 100644 Yi.Framework/Yi.Framework.Core/ConsulExtend/ClienExtend/WeightDispatcher.cs create mode 100644 Yi.Framework/Yi.Framework.Core/ConsulExtend/ConsulClientOption.cs create mode 100644 Yi.Framework/Yi.Framework.Core/ConsulExtend/ServerExtend/ConsulRegisterOption.cs create mode 100644 Yi.Framework/Yi.Framework.Core/ConsulExtend/ServerExtend/ConsulRegiterExtend.cs create mode 100644 Yi.Framework/Yi.Framework.Core/ConsulExtend/ServerExtend/HealthCheckMiddleware.cs create mode 100644 Yi.Framework/Yi.Framework.Core/Library/Microsoft.Bcl.AsyncInterfaces.dll create mode 100644 Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Common.dll create mode 100644 Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Interfaces.dll create mode 100644 Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Redis.dll create mode 100644 Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Text.dll create mode 100644 Yi.Framework/Yi.Framework.Core/MD5Helper.cs create mode 100644 Yi.Framework/Yi.Framework.Core/RabbitMQInvoker.cs create mode 100644 Yi.Framework/Yi.Framework.Core/SnowflakeHelper.cs create mode 100644 Yi.Framework/Yi.Framework.Core/Yi.Framework.Core.csproj create mode 100644 Yi.Framework/Yi.Framework.DTOModel/Class1.cs create mode 100644 Yi.Framework/Yi.Framework.DTOModel/Yi.Framework.DTOModel.csproj create mode 100644 Yi.Framework/Yi.Framework.Interface/Class1.cs create mode 100644 Yi.Framework/Yi.Framework.Interface/Yi.Framework.Interface.csproj create mode 100644 Yi.Framework/Yi.Framework.Model/Class1.cs create mode 100644 Yi.Framework/Yi.Framework.Model/Yi.Framework.Model.csproj create mode 100644 Yi.Framework/Yi.Framework.Service/Class1.cs create mode 100644 Yi.Framework/Yi.Framework.Service/Yi.Framework.Service.csproj create mode 100644 Yi.Framework/Yi.Framework.WebCore/Class1.cs create mode 100644 Yi.Framework/Yi.Framework.WebCore/CommonExtend.cs create mode 100644 Yi.Framework/Yi.Framework.WebCore/FilterExtend/CORSFilter.cs create mode 100644 Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomAction2CommitFilterAttribute.cs create mode 100644 Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomActionCacheFilterAttribute.cs create mode 100644 Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomActionCheckFilterAttribute.cs create mode 100644 Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomExceptionFilterAttribute.cs create mode 100644 Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomIOCFilterFactoryAttribute.cs create mode 100644 Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomResourceFilterAttribute.cs create mode 100644 Yi.Framework/Yi.Framework.WebCore/FilterExtend/LogActionFilterAttribute.cs create mode 100644 Yi.Framework/Yi.Framework.WebCore/MiddlewareExtend/PreOptionRequestMiddleware.cs create mode 100644 Yi.Framework/Yi.Framework.WebCore/MiddlewareExtend/StaticPageMiddleware.cs create mode 100644 Yi.Framework/Yi.Framework.WebCore/Yi.Framework.WebCore.csproj diff --git a/Yi.Framework/Yi.Framework/Controllers/WeatherForecastController.cs b/Yi.Framework/Yi.Framework.ApiMicroservice/Controllers/WeatherForecastController.cs similarity index 95% rename from Yi.Framework/Yi.Framework/Controllers/WeatherForecastController.cs rename to Yi.Framework/Yi.Framework.ApiMicroservice/Controllers/WeatherForecastController.cs index 85f9e9ed..021a0750 100644 --- a/Yi.Framework/Yi.Framework/Controllers/WeatherForecastController.cs +++ b/Yi.Framework/Yi.Framework.ApiMicroservice/Controllers/WeatherForecastController.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -namespace Yi.Framework.Controllers +namespace Yi.Framework.ApiMicroservice.Controllers { [ApiController] [Route("[controller]")] diff --git a/Yi.Framework/Yi.Framework/Program.cs b/Yi.Framework/Yi.Framework.ApiMicroservice/Program.cs similarity index 94% rename from Yi.Framework/Yi.Framework/Program.cs rename to Yi.Framework/Yi.Framework.ApiMicroservice/Program.cs index a67477ef..6543d16f 100644 --- a/Yi.Framework/Yi.Framework/Program.cs +++ b/Yi.Framework/Yi.Framework.ApiMicroservice/Program.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -namespace Yi.Framework +namespace Yi.Framework.ApiMicroservice { public class Program { diff --git a/Yi.Framework/Yi.Framework/Properties/launchSettings.json b/Yi.Framework/Yi.Framework.ApiMicroservice/Properties/launchSettings.json similarity index 86% rename from Yi.Framework/Yi.Framework/Properties/launchSettings.json rename to Yi.Framework/Yi.Framework.ApiMicroservice/Properties/launchSettings.json index 6758692d..394d1b04 100644 --- a/Yi.Framework/Yi.Framework/Properties/launchSettings.json +++ b/Yi.Framework/Yi.Framework.ApiMicroservice/Properties/launchSettings.json @@ -4,8 +4,8 @@ "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { - "applicationUrl": "http://localhost:52790", - "sslPort": 44379 + "applicationUrl": "http://localhost:56243", + "sslPort": 44329 } }, "profiles": { @@ -17,7 +17,7 @@ "ASPNETCORE_ENVIRONMENT": "Development" } }, - "Yi.Framework": { + "Yi.Framework.ApiMicroservice": { "commandName": "Project", "dotnetRunMessages": "true", "launchBrowser": true, diff --git a/Yi.Framework/Yi.Framework/Startup.cs b/Yi.Framework/Yi.Framework.ApiMicroservice/Startup.cs similarity index 91% rename from Yi.Framework/Yi.Framework/Startup.cs rename to Yi.Framework/Yi.Framework.ApiMicroservice/Startup.cs index 90cf0fbd..d2e6dcb3 100644 --- a/Yi.Framework/Yi.Framework/Startup.cs +++ b/Yi.Framework/Yi.Framework.ApiMicroservice/Startup.cs @@ -12,7 +12,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -namespace Yi.Framework +namespace Yi.Framework.ApiMicroservice { public class Startup { @@ -30,7 +30,7 @@ namespace Yi.Framework services.AddControllers(); services.AddSwaggerGen(c => { - c.SwaggerDoc("v1", new OpenApiInfo { Title = "Yi.Framework", Version = "v1" }); + c.SwaggerDoc("v1", new OpenApiInfo { Title = "Yi.Framework.ApiMicroservice", Version = "v1" }); }); } @@ -41,7 +41,7 @@ namespace Yi.Framework { app.UseDeveloperExceptionPage(); app.UseSwagger(); - app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Yi.Framework v1")); + app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Yi.Framework.ApiMicroservice v1")); } app.UseHttpsRedirection(); diff --git a/Yi.Framework/Yi.Framework/WeatherForecast.cs b/Yi.Framework/Yi.Framework.ApiMicroservice/WeatherForecast.cs similarity index 87% rename from Yi.Framework/Yi.Framework/WeatherForecast.cs rename to Yi.Framework/Yi.Framework.ApiMicroservice/WeatherForecast.cs index 149144ca..a317faba 100644 --- a/Yi.Framework/Yi.Framework/WeatherForecast.cs +++ b/Yi.Framework/Yi.Framework.ApiMicroservice/WeatherForecast.cs @@ -1,6 +1,6 @@ using System; -namespace Yi.Framework +namespace Yi.Framework.ApiMicroservice { public class WeatherForecast { diff --git a/Yi.Framework/Yi.Framework/Yi.Framework.csproj b/Yi.Framework/Yi.Framework.ApiMicroservice/Yi.Framework.ApiMicroservice.csproj similarity index 100% rename from Yi.Framework/Yi.Framework/Yi.Framework.csproj rename to Yi.Framework/Yi.Framework.ApiMicroservice/Yi.Framework.ApiMicroservice.csproj diff --git a/Yi.Framework/Yi.Framework/appsettings.Development.json b/Yi.Framework/Yi.Framework.ApiMicroservice/appsettings.Development.json similarity index 100% rename from Yi.Framework/Yi.Framework/appsettings.Development.json rename to Yi.Framework/Yi.Framework.ApiMicroservice/appsettings.Development.json diff --git a/Yi.Framework/Yi.Framework/appsettings.json b/Yi.Framework/Yi.Framework.ApiMicroservice/appsettings.json similarity index 100% rename from Yi.Framework/Yi.Framework/appsettings.json rename to Yi.Framework/Yi.Framework.ApiMicroservice/appsettings.json diff --git a/Yi.Framework/Yi.Framework.Common/Class1.cs b/Yi.Framework/Yi.Framework.Common/Class1.cs new file mode 100644 index 00000000..0c3f5493 --- /dev/null +++ b/Yi.Framework/Yi.Framework.Common/Class1.cs @@ -0,0 +1,8 @@ +using System; + +namespace Yi.Framework.Common +{ + public class Class1 + { + } +} diff --git a/Yi.Framework/Yi.Framework.Common/IOCOptions/ElasticSearchOptions.cs b/Yi.Framework/Yi.Framework.Common/IOCOptions/ElasticSearchOptions.cs new file mode 100644 index 00000000..9eca69cd --- /dev/null +++ b/Yi.Framework/Yi.Framework.Common/IOCOptions/ElasticSearchOptions.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Common.IOCOptions +{ + public class ElasticSearchOptions + { + public string Url { get; set; } + public string IndexName { get; set; } + } +} diff --git a/Yi.Framework/Yi.Framework.Common/IOCOptions/JWTTokenOptions.cs b/Yi.Framework/Yi.Framework.Common/IOCOptions/JWTTokenOptions.cs new file mode 100644 index 00000000..1ecad49a --- /dev/null +++ b/Yi.Framework/Yi.Framework.Common/IOCOptions/JWTTokenOptions.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CC.ElectronicCommerce.Common.IOCOptions +{ + public class JWTTokenOptions + { + public string Audience + { + get; + set; + } + public string SecurityKey + { + get; + set; + } + //public SigningCredentials Credentials + //{ + // get; + // set; + //} + public string Issuer + { + get; + set; + } + } +} diff --git a/Yi.Framework/Yi.Framework.Common/IOCOptions/KafkaOptions.cs b/Yi.Framework/Yi.Framework.Common/IOCOptions/KafkaOptions.cs new file mode 100644 index 00000000..89b3a440 --- /dev/null +++ b/Yi.Framework/Yi.Framework.Common/IOCOptions/KafkaOptions.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CC.ElectronicCommerce.Common.IOCOptions +{ + public class KafkaOptions + { + + public string BrokerList { get; set; } + public string TopicName { get; set; } + } +} diff --git a/Yi.Framework/Yi.Framework.Common/IOCOptions/MySqlConnOptions.cs b/Yi.Framework/Yi.Framework.Common/IOCOptions/MySqlConnOptions.cs new file mode 100644 index 00000000..f6a981f0 --- /dev/null +++ b/Yi.Framework/Yi.Framework.Common/IOCOptions/MySqlConnOptions.cs @@ -0,0 +1,9 @@ +using System; + +namespace Yi.Framework.Common.IOCOptions +{ + public class MySqlConnOptions + { + public string Url { get; set; } + } +} diff --git a/Yi.Framework/Yi.Framework.Common/IOCOptions/RabbitMQOptions.cs b/Yi.Framework/Yi.Framework.Common/IOCOptions/RabbitMQOptions.cs new file mode 100644 index 00000000..dd716f86 --- /dev/null +++ b/Yi.Framework/Yi.Framework.Common/IOCOptions/RabbitMQOptions.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Common.IOCOptions +{ + public class RabbitMQOptions + { + ///// + ///// exchange---queue + ///// + //private static Dictionary RabbitMQ_Mapping = new Dictionary(); + //private static readonly object RabbitMQOptions_Lock = new object(); + //public void Init(string exchangeName, string queueName) + //{ + // lock (RabbitMQOptions_Lock) + // { + // RabbitMQ_Mapping[exchangeName] = queueName; + // } + //} + + public string HostName { get; set; } + public string UserName { get; set; } + public string Password { get; set; } + + } + + public class RabbitMQConsumerModel + { + /// + /// 生产者指定,交换机 + /// + public string ExchangeName { get; set; } + /// + /// 自己起的名字 + /// + public string QueueName { get; set; } + } + + public class RabbitMQExchangeQueueName + { + public static readonly string SKUCQRS_Exchange = "Zhaoxi.MSACormmerce.SKUCQRS.Exchange"; + public static readonly string SKUCQRS_Queue_StaticPage = "Zhaoxi.MSACormmerce.SKUCQRS.Queue.StaticPage"; + public static readonly string SKUCQRS_Queue_ESIndex = "Zhaoxi.MSACormmerce.SKUCQRS.Queue.ESIndex"; + + + public static readonly string SKUWarmup_Exchange = "Zhaoxi.MSACormmerce.Warmup.Exchange"; + public static readonly string SKUWarmup_Queue_StaticPage = "Zhaoxi.MSACormmerce.Warmup.Queue.StaticPage"; + public static readonly string SKUWarmup_Queue_ESIndex = "Zhaoxi.MSACormmerce.Warmup.Queue.ESIndex"; + + /// + /// 订单创建后的交换机 + /// + public static readonly string OrderCreate_Exchange = "Zhaoxi.MSACormmerce.OrderCreate.Exchange"; + public static readonly string OrderCreate_Queue_CleanCart = "Zhaoxi.MSACormmerce.OrderCreate.Queue.CleanCart"; + + /// + /// 订单创建后的交换机,支付状态的 + /// + public static readonly string OrderPay_Exchange = "Zhaoxi.MSACormmerce.OrderPay.Exchange"; + public static readonly string OrderPay_Queue_RefreshPay = "Zhaoxi.MSACormmerce.OrderPay.Queue.RefreshPay"; + + /// + /// 创建订单后的延时队列配置 + /// + public static readonly string OrderCreate_Delay_Exchange = "Zhaoxi.MSACormmerce.OrderCreate.DelayExchange"; + public static readonly string OrderCreate_Delay_Queue_CancelOrder = "Zhaoxi.MSACormmerce.OrderCreate.DelayQueue.CancelOrder"; + + /// + /// 秒杀异步的 + /// + public static readonly string Seckill_Exchange = "Zhaoxi.MSACormmerce.Seckill.Exchange"; + public static readonly string Seckill_Order_Queue = "Zhaoxi.MSACormmerce.Seckill.Order.Queue"; + + + /// + /// CAP队列名称 + /// + public const string Order_Stock_Decrease = "RabbitMQ.MySQL.Order-Stock.Decrease"; + public const string Order_Stock_Resume = "RabbitMQ.MySQL.Order-Stock.Resume"; + public const string Stock_Logistics = "RabbitMQ.MySQL.Stock-Logistics"; + + public const string Pay_Order_UpdateStatus = "RabbitMQ.MySQL.Pay_Order.UpdateStatus"; + } + +} diff --git a/Yi.Framework/Yi.Framework.Common/IOCOptions/RedisConnOptions.cs b/Yi.Framework/Yi.Framework.Common/IOCOptions/RedisConnOptions.cs new file mode 100644 index 00000000..031509a3 --- /dev/null +++ b/Yi.Framework/Yi.Framework.Common/IOCOptions/RedisConnOptions.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Common.IOCOptions +{ + public class RedisConnOptions + { + public string Host { get; set; } + public int DB { get; set; } = 0; + public int Prot { get; set; } + public string Password { get; set; } + } + + +} diff --git a/Yi.Framework/Yi.Framework.Common/Models/LogModel.cs b/Yi.Framework/Yi.Framework.Common/Models/LogModel.cs new file mode 100644 index 00000000..1c7b779f --- /dev/null +++ b/Yi.Framework/Yi.Framework.Common/Models/LogModel.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Common.Models +{ + /// + /// 写入分布式日志需要的字段 + /// + public class LogModel + { + public string OriginalClassName { get; set; } + public string OriginalMethodName { get; set; } + public string Remark { get; set; } + } +} diff --git a/Yi.Framework/Yi.Framework.Common/Models/Result.cs b/Yi.Framework/Yi.Framework.Common/Models/Result.cs new file mode 100644 index 00000000..6b7f1e2f --- /dev/null +++ b/Yi.Framework/Yi.Framework.Common/Models/Result.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace Yi.Framework.Common.Models +{ + /// + /// 结果数据 + /// + public class Result + { + public bool status { get; set; } + public int code { get; set; } + public string msg { get; set; } + public object data { get; set; } + public static Result Instance(bool status, string msg) + { + return new Result() { status = status, code = 500, msg = msg }; + } + public static Result Error(string msg = "fail") + { + return new Result() { status = false, code = 500, msg = msg }; + } + public static Result Success(string msg = "succeed") + { + return new Result() { status = true, code = 200, msg = msg }; + } + public Result SetData(object obj) + { + this.data = obj; + return this; + } + public Result SetCode(int Code) + { + this.code = Code; + return this; + } + } + public class Result + { + public bool status { get; set; } + public int code { get; set; } + public string msg { get; set; } + public T data { get; set; } + + public static Result Instance(bool status, string msg) + { + return new Result() { status = status, code = 500, msg = msg }; + } + public static Result Error(string msg = "fail") + { + return new Result { status = false, code = 500, msg = msg }; + } + public static Result Success(string msg = "succeed") + { + return new Result { status = true, code = 200, msg = msg }; + } + public Result SetData(T TValue) + { + this.data = TValue; + return this; + } + } + +} \ No newline at end of file diff --git a/Yi.Framework/Yi.Framework.Common/Yi.Framework.Common.csproj b/Yi.Framework/Yi.Framework.Common/Yi.Framework.Common.csproj new file mode 100644 index 00000000..f208d303 --- /dev/null +++ b/Yi.Framework/Yi.Framework.Common/Yi.Framework.Common.csproj @@ -0,0 +1,7 @@ + + + + net5.0 + + + diff --git a/Yi.Framework/Yi.Framework.Core/CacheClientDB.cs b/Yi.Framework/Yi.Framework.Core/CacheClientDB.cs new file mode 100644 index 00000000..7508d9d4 --- /dev/null +++ b/Yi.Framework/Yi.Framework.Core/CacheClientDB.cs @@ -0,0 +1,1074 @@ +using Microsoft.Extensions.Options; +using ServiceStack; +using ServiceStack.Redis; +using ServiceStack.Redis.Pipeline; +using ServiceStack.Text; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO; +using CC.ElectronicCommerce.Common.IOCOptions; + +namespace CC.ElectronicCommerce.Core +{ + public class CacheClientDB : IDisposable + { + private readonly RedisConnOptions _RedisOptions; + + #region TestRedisCrack + //static CacheClientDB() + //{ + // try + // { + // Parallel.For(0, 10000, (i) => + // { + // using (RedisClient client = new RedisClient("192.168.3.254")) + // { + // client.Set("name" + i, i); + // client.Incr("name" + i); + // Console.WriteLine(i); + // } + + // }); + // Console.WriteLine("ok"); + + // Console.WriteLine("Hello World!"); + // } + // catch (Exception ex) + // { + // Console.WriteLine(ex.Message); + // } + //} + #endregion + public CacheClientDB(IOptionsMonitor jwtTokenOptions) + { + this._RedisOptions = jwtTokenOptions.CurrentValue; + client = new RedisClient(_RedisOptions.Host, _RedisOptions.Prot, _RedisOptions.Password, _RedisOptions.DB); + } + // 管道模式 三种模式 + public IRedisClient GetClient() + { + return client; + } + private IRedisClient client; + + public void Dispose() + { + + this.TryCatchException(delegate + { + this.client.Dispose(); + }, string.Empty); + } + // 为了以后全链路做准备 + private void TryCatchException(Action action, string key) + { + try + { + action(); + } + catch (Exception e) + { + + Console.WriteLine(e.Message); + } + } + + private T TryCatch(Func action, string key) + { + Stopwatch sw = Stopwatch.StartNew(); + //Exception ex = null; + //bool isError = false; + T result; + try + { + result = action(); + } + catch (Exception exinfo) + { + object p=null; + result =(T)p; + //isError = true; + Console.WriteLine(exinfo); + + } + finally + { + + sw.Stop(); + + } + + return result; + } + + private void TryCatch(Action action, string key) + { + + Stopwatch sw = Stopwatch.StartNew(); + //bool isError = false; + //Exception ex = null; + try + { + action(); + } + catch (Exception exinfo) + { + + //isError = true; + Console.WriteLine(exinfo); + } + finally + { + sw.Stop(); + + } + } + public bool Add(string key, T value) + { + + return this.TryCatch(() => this.client.Add(key, value), key); + } + /// + /// 简单模式 事务模式 + /// + /// + /// + /// + /// + /// + public bool Add(string key, T value, DateTime expiresAt) + { + + return this.TryCatch(() => this.client.Add(key, value, expiresAt), key); + } + + public bool Add(string key, T value, TimeSpan expiresIn) + { + return this.TryCatch(() => this.client.Add(key, value, expiresIn), key); + } + + public long Decrement(string key, uint amount) + { + return this.TryCatch(() => this.client.Decrement(key, amount), key); + } + + public void FlushAll() + { + this.TryCatch(delegate + { + this.client.FlushAll(); + }, string.Empty); + } + + public T Get(string key) + { + return this.TryCatch(() => this.client.Get(key), key); + } + + public IDictionary GetAll(IEnumerable keys) + { + return this.TryCatch>(() => this.client.GetAll(keys), keys.FirstOrDefault()); + } + + public long Increment(string key, uint amount) + { + return this.TryCatch(() => this.client.Increment(key, amount), key); + } + + public bool Remove(string key) + { + return this.TryCatch(() => this.client.Remove(key), key); + } + + public void RemoveAll(IEnumerable keys) + { + this.TryCatch(delegate + { + this.client.RemoveAll(keys); + }, keys.FirstOrDefault()); + } + + public bool Replace(string key, T value) + { + return this.TryCatch(() => this.client.Replace(key, value), key); + } + + public bool Replace(string key, T value, DateTime expiresAt) + { + return this.TryCatch(() => this.client.Replace(key, value, expiresAt), key); + } + + public bool Replace(string key, T value, TimeSpan expiresIn) + { + return this.TryCatch(() => this.client.Replace(key, value, expiresIn), key); + } + + public bool Set(string key, T value) + { + return this.TryCatch(() => this.client.Set(key, value), key); + } + + public bool Set(string key, T value, DateTime expiresAt) + { + return this.TryCatch(() => this.client.Set(key, value, expiresAt), key); + } + + public bool Set(string key, T value, TimeSpan expiresIn) + { + return this.TryCatch(() => this.client.Set(key, value, expiresIn), key); + } + + public void SetAll(IDictionary values) + { + this.TryCatch(delegate + { + this.client.SetAll(values); + }, values.Keys.FirstOrDefault()); + } + + + public void Delete(T entity) where T : class, new() + { + this.TryCatch(delegate + { + this.client.Delete(entity); + }, string.Empty); + } + + public void DeleteAll() where TEntity : class, new() + { + this.TryCatch(delegate + { + this.client.DeleteAll(); + }, string.Empty); + } + + public void DeleteById(object id) where T : class, new() + { + this.TryCatch(delegate + { + this.client.DeleteById(id); + }, string.Empty); + } + + public void DeleteByIds(ICollection ids) where T : class, new() + { + this.TryCatch(delegate + { + this.client.DeleteById(ids); + }, string.Empty); + } + + public T GetById(object id) where T : class, new() + { + return this.TryCatch(() => this.client.GetById(id), string.Empty); + } + + public IList GetByIds(ICollection ids) where T : class, new() + { + return this.TryCatch>(() => this.client.GetByIds(ids), string.Empty); + } + + public T Store(T entity) where T : class, new() + { + return this.TryCatch(() => this.client.Store(entity), string.Empty); + } + + public void StoreAll(IEnumerable entities) where TEntity : class, new() + { + this.TryCatch(delegate + { + this.client.StoreAll(entities); + }, string.Empty); + } + + public void AddItemToList(string listId, string value) + { + this.TryCatch(delegate + { + this.client.AddItemToList(listId, value); + }, listId); + } + + public void AddItemToSet(string setId, string item) + { + this.TryCatch(delegate + { + this.client.AddItemToSet(setId, item); + }, setId); + } + + public bool AddItemToSortedSet(string setId, string value) + { + return this.TryCatch(() => this.client.AddItemToSortedSet(setId, value), setId); + } + + public bool AddItemToSortedSet(string setId, string value, double score) + { + return this.TryCatch(() => this.client.AddItemToSortedSet(setId, value, score), setId); + } + + public void AddRangeToList(string listId, List values) + { + this.TryCatch(delegate + { + this.client.AddRangeToList(listId, values); + }, listId); + } + + public void AddRangeToSet(string setId, List items) + { + this.TryCatch(delegate + { + this.client.AddRangeToSet(setId, items); + }, setId); + } + + public bool AddRangeToSortedSet(string setId, List values, double score) + { + return this.TryCatch(() => this.client.AddRangeToSortedSet(setId, values, score), setId); + } + + public bool AddRangeToSortedSet(string setId, List values, long score) + { + return this.TryCatch(() => this.client.AddRangeToSortedSet(setId, values, score), setId); + } + + public long AppendToValue(string key, string value) + { + return this.TryCatch(() => this.client.AppendToValue(key, value), key); + } + + public string BlockingDequeueItemFromList(string listId, TimeSpan? timeOut) + { + return this.TryCatch(() => this.client.BlockingDequeueItemFromList(listId, timeOut), listId); + } + + public KeyValuePair BlockingDequeueItemFromLists(string[] listIds, TimeSpan? timeOut) + { + return this.TryCatch>(delegate + { + ItemRef item = this.client.BlockingDequeueItemFromLists(listIds, timeOut); + return new KeyValuePair(item.Id, item.Item); + }, listIds[0]); + } + + public string BlockingPopAndPushItemBetweenLists(string fromListId, string toListId, TimeSpan? timeOut) + { + return this.TryCatch(() => this.client.BlockingPopAndPushItemBetweenLists(fromListId, toListId, timeOut), fromListId); + } + + public string BlockingPopItemFromList(string listId, TimeSpan? timeOut) + { + return this.TryCatch(() => this.client.BlockingPopItemFromList(listId, timeOut), listId); + } + + public KeyValuePair BlockingPopItemFromLists(string[] listIds, TimeSpan? timeOut) + { + return this.TryCatch>(delegate + { + ItemRef item = this.client.BlockingPopItemFromLists(listIds, timeOut); + return new KeyValuePair(item.Id, item.Item); + }, listIds[0]); + } + + public string BlockingRemoveStartFromList(string listId, TimeSpan? timeOut) + { + return this.TryCatch(() => this.client.BlockingRemoveStartFromList(listId, timeOut), listId); + } + + public KeyValuePair BlockingRemoveStartFromLists(string[] listIds, TimeSpan? timeOut) + { + return this.TryCatch>(delegate + { + ItemRef item = this.client.BlockingRemoveStartFromLists(listIds, timeOut); + return new KeyValuePair(item.Id, item.Item); + }, listIds[0]); + } + + public bool ContainsKey(string key) + { + return this.TryCatch(() => this.client.ContainsKey(key), key); + } + + public long DecrementValue(string key) + { + return this.TryCatch(() => this.client.DecrementValue(key), key); + } + + public long DecrementValueBy(string key, int count) + { + return this.TryCatch(() => this.client.DecrementValueBy(key, count), key); + } + + public string DequeueItemFromList(string listId) + { + return this.TryCatch(() => this.client.DequeueItemFromList(listId), listId); + } + + public void EnqueueItemOnList(string listId, string value) + { + this.TryCatch(delegate + { + this.client.EnqueueItemOnList(listId, value); + }, listId); + } + + public bool ExpireEntryAt(string key, DateTime expireAt) + { + return this.TryCatch(() => this.client.ExpireEntryAt(key, expireAt), key); + } + + public bool ExpireEntryIn(string key, TimeSpan expireIn) + { + return this.TryCatch(() => this.client.ExpireEntryIn(key, expireIn), key); + } + + public Dictionary GetAllEntriesFromHash(string hashId) + { + return this.TryCatch>(() => this.client.GetAllEntriesFromHash(hashId), hashId); + } + + public List GetAllItemsFromList(string listId) + { + return this.TryCatch>(() => this.client.GetAllItemsFromList(listId), listId); + } + + public HashSet GetAllItemsFromSet(string setId) + { + return this.TryCatch>(() => this.client.GetAllItemsFromSet(setId), setId); + } + + public List GetAllItemsFromSortedSet(string setId) + { + return this.TryCatch>(() => this.client.GetAllItemsFromSortedSet(setId), setId); + } + + public List GetAllItemsFromSortedSetDesc(string setId) + { + return this.TryCatch>(() => this.client.GetAllItemsFromSortedSetDesc(setId), setId); + } + + public List GetAllKeys() + { + return this.TryCatch>(() => this.client.GetAllKeys(), string.Empty); + } + + public IDictionary GetAllWithScoresFromSortedSet(string setId) + { + return this.TryCatch>(() => this.client.GetAllWithScoresFromSortedSet(setId), setId); + } + + public string GetAndSetEntry(string key, string value) + { + return this.TryCatch(() => this.client.GetAndSetValue(key, value), key); + } + + public HashSet GetDifferencesFromSet(string fromSetId, params string[] withSetIds) + { + return this.TryCatch>(() => this.client.GetDifferencesFromSet(fromSetId, withSetIds), fromSetId); + } + + public T GetFromHash(object id) + { + return this.TryCatch(() => this.client.GetFromHash(id), string.Empty); + } + + public long GetHashCount(string hashId) + { + return this.TryCatch(() => this.client.GetHashCount(hashId), hashId); + } + + public List GetHashKeys(string hashId) + { + return this.TryCatch>(() => this.client.GetHashKeys(hashId), hashId); + } + + public List GetHashValues(string hashId) + { + return this.TryCatch>(() => this.client.GetHashValues(hashId), hashId); + } + + public HashSet GetIntersectFromSets(params string[] setIds) + { + return this.TryCatch>(() => this.client.GetIntersectFromSets(setIds), setIds[0]); + } + + public string GetItemFromList(string listId, int listIndex) + { + return this.TryCatch(() => this.client.GetItemFromList(listId, listIndex), listId); + } + + public long GetItemIndexInSortedSet(string setId, string value) + { + return this.TryCatch(() => this.client.GetItemIndexInSortedSet(setId, value), setId); + } + + public long GetItemIndexInSortedSetDesc(string setId, string value) + { + return this.TryCatch(() => this.client.GetItemIndexInSortedSetDesc(setId, value), setId); + } + + public double GetItemScoreInSortedSet(string setId, string value) + { + return this.TryCatch(() => this.client.GetItemScoreInSortedSet(setId, value), setId); + } + + public long GetListCount(string listId) + { + return this.TryCatch(() => this.client.GetListCount(listId), listId); + } + + public string GetRandomItemFromSet(string setId) + { + return this.TryCatch(() => this.client.GetRandomItemFromSet(setId), setId); + } + + public List GetRangeFromList(string listId, int startingFrom, int endingAt) + { + return this.TryCatch>(() => this.client.GetRangeFromList(listId, startingFrom, endingAt), listId); + } + + public List GetRangeFromSortedList(string listId, int startingFrom, int endingAt) + { + return this.TryCatch>(() => this.client.GetRangeFromSortedList(listId, startingFrom, endingAt), listId); + } + + public List GetRangeFromSortedSet(string setId, int fromRank, int toRank) + { + return this.TryCatch>(() => this.client.GetRangeFromSortedSet(setId, fromRank, toRank), setId); + } + + public List GetRangeFromSortedSetByHighestScore(string setId, double fromScore, double toScore) + { + return this.TryCatch>(() => this.client.GetRangeFromSortedSetByHighestScore(setId, fromScore, toScore), setId); + } + + public List GetRangeFromSortedSetByHighestScore(string setId, long fromScore, long toScore) + { + return this.TryCatch>(() => this.client.GetRangeFromSortedSetByHighestScore(setId, fromScore, toScore), setId); + } + + public List GetRangeFromSortedSetByHighestScore(string setId, string fromStringScore, string toStringScore) + { + return this.TryCatch>(() => this.client.GetRangeFromSortedSetByHighestScore(setId, fromStringScore, toStringScore), setId); + } + + public List GetRangeFromSortedSetByHighestScore(string setId, double fromScore, double toScore, int? skip, int? take) + { + return this.TryCatch>(() => this.client.GetRangeFromSortedSetByHighestScore(setId, fromScore, toScore, skip, take), setId); + } + + public List GetRangeFromSortedSetByHighestScore(string setId, long fromScore, long toScore, int? skip, int? take) + { + return this.TryCatch>(() => this.client.GetRangeFromSortedSetByHighestScore(setId, fromScore, toScore, skip, take), setId); + } + + public List GetRangeFromSortedSetByHighestScore(string setId, string fromStringScore, string toStringScore, int? skip, int? take) + { + return this.TryCatch>(() => this.client.GetRangeFromSortedSetByHighestScore(setId, fromStringScore, toStringScore, skip, take), setId); + } + + public List GetRangeFromSortedSetByLowestScore(string setId, double fromScore, double toScore) + { + return this.TryCatch>(() => this.client.GetRangeFromSortedSetByLowestScore(setId, fromScore, toScore), setId); + } + + public List GetRangeFromSortedSetByLowestScore(string setId, long fromScore, long toScore) + { + return this.TryCatch>(() => this.client.GetRangeFromSortedSetByLowestScore(setId, fromScore, toScore), setId); + } + + public List GetRangeFromSortedSetByLowestScore(string setId, string fromStringScore, string toStringScore) + { + return this.TryCatch>(() => this.client.GetRangeFromSortedSetByLowestScore(setId, fromStringScore, toStringScore), setId); + } + + public List GetRangeFromSortedSetByLowestScore(string setId, double fromScore, double toScore, int? skip, int? take) + { + return this.TryCatch>(() => this.client.GetRangeFromSortedSetByLowestScore(setId, fromScore, toScore, skip, take), setId); + } + + public List GetRangeFromSortedSetByLowestScore(string setId, long fromScore, long toScore, int? skip, int? take) + { + return this.TryCatch>(() => this.client.GetRangeFromSortedSetByLowestScore(setId, fromScore, toScore, skip, take), setId); + } + + public List GetRangeFromSortedSetByLowestScore(string setId, string fromStringScore, string toStringScore, int? skip, int? take) + { + return this.TryCatch>(() => this.client.GetRangeFromSortedSetByLowestScore(setId, fromStringScore, toStringScore, skip, take), setId); + } + + public List GetRangeFromSortedSetDesc(string setId, int fromRank, int toRank) + { + return this.TryCatch>(() => this.client.GetRangeFromSortedSetDesc(setId, fromRank, toRank), setId); + } + + public IDictionary GetRangeWithScoresFromSortedSet(string setId, int fromRank, int toRank) + { + return this.TryCatch>(() => this.client.GetRangeWithScoresFromSortedSet(setId, fromRank, toRank), setId); + } + + public IDictionary GetRangeWithScoresFromSortedSetByHighestScore(string setId, double fromScore, double toScore) + { + return this.TryCatch>(() => this.client.GetRangeWithScoresFromSortedSetByHighestScore(setId, fromScore, toScore), setId); + } + + public IDictionary GetRangeWithScoresFromSortedSetByHighestScore(string setId, long fromScore, long toScore) + { + return this.TryCatch>(() => this.client.GetRangeWithScoresFromSortedSetByHighestScore(setId, fromScore, toScore), setId); + } + + public IDictionary GetRangeWithScoresFromSortedSetByHighestScore(string setId, string fromStringScore, string toStringScore) + { + return this.TryCatch>(() => this.client.GetRangeWithScoresFromSortedSetByHighestScore(setId, fromStringScore, toStringScore), setId); + } + + public IDictionary GetRangeWithScoresFromSortedSetByHighestScore(string setId, double fromScore, double toScore, int? skip, int? take) + { + return this.TryCatch>(() => this.client.GetRangeWithScoresFromSortedSetByHighestScore(setId, fromScore, toScore, skip, take), setId); + } + + public IDictionary GetRangeWithScoresFromSortedSetByHighestScore(string setId, long fromScore, long toScore, int? skip, int? take) + { + return this.TryCatch>(() => this.client.GetRangeWithScoresFromSortedSetByHighestScore(setId, fromScore, toScore, skip, take), setId); + } + + public IDictionary GetRangeWithScoresFromSortedSetByHighestScore(string setId, string fromStringScore, string toStringScore, int? skip, int? take) + { + return this.TryCatch>(() => this.client.GetRangeWithScoresFromSortedSetByHighestScore(setId, fromStringScore, toStringScore, skip, take), setId); + } + + public IDictionary GetRangeWithScoresFromSortedSetByLowestScore(string setId, double fromScore, double toScore) + { + return this.TryCatch>(() => this.client.GetRangeWithScoresFromSortedSetByHighestScore(setId, fromScore, toScore), setId); + } + + public IDictionary GetRangeWithScoresFromSortedSetByLowestScore(string setId, long fromScore, long toScore) + { + return this.TryCatch>(() => this.client.GetRangeWithScoresFromSortedSetByLowestScore(setId, fromScore, toScore), setId); + } + + public IDictionary GetRangeWithScoresFromSortedSetByLowestScore(string setId, string fromStringScore, string toStringScore) + { + return this.TryCatch>(() => this.client.GetRangeWithScoresFromSortedSetByLowestScore(setId, fromStringScore, toStringScore), setId); + } + + public IDictionary GetRangeWithScoresFromSortedSetByLowestScore(string setId, double fromScore, double toScore, int? skip, int? take) + { + return this.TryCatch>(() => this.client.GetRangeWithScoresFromSortedSetByLowestScore(setId, fromScore, toScore, skip, take), setId); + } + + public IDictionary GetRangeWithScoresFromSortedSetByLowestScore(string setId, long fromScore, long toScore, int? skip, int? take) + { + return this.TryCatch>(() => this.client.GetRangeWithScoresFromSortedSetByLowestScore(setId, fromScore, toScore, skip, take), setId); + } + + public IDictionary GetRangeWithScoresFromSortedSetByLowestScore(string setId, string fromStringScore, string toStringScore, int? skip, int? take) + { + return this.TryCatch>(() => this.client.GetRangeWithScoresFromSortedSetByLowestScore(setId, fromStringScore, toStringScore, skip, take), setId); + } + + public IDictionary GetRangeWithScoresFromSortedSetDesc(string setId, int fromRank, int toRank) + { + return this.TryCatch>(() => this.client.GetRangeWithScoresFromSortedSetDesc(setId, fromRank, toRank), setId); + } + + public long GetSetCount(string setId) + { + return this.TryCatch(() => this.client.GetSetCount(setId), setId); + } + + public List GetSortedEntryValues(string key, int startingFrom, int endingAt) + { + return this.TryCatch>(() => this.client.GetSortedEntryValues(key, startingFrom, endingAt), key); + } + + public long GetSortedSetCount(string setId) + { + return this.TryCatch(() => this.client.GetSortedSetCount(setId), setId); + } + + public long GetSortedSetCount(string setId, double fromScore, double toScore) + { + return this.TryCatch(() => this.client.GetSortedSetCount(setId, fromScore, toScore), setId); + } + + public long GetSortedSetCount(string setId, long fromScore, long toScore) + { + return this.TryCatch(() => this.client.GetSortedSetCount(setId, fromScore, toScore), setId); + } + + public long GetSortedSetCount(string setId, string fromStringScore, string toStringScore) + { + return this.TryCatch(() => this.client.GetSortedSetCount(setId, fromStringScore, toStringScore), setId); + } + + public string GetSubstring(string key, int fromIndex, int toIndex) + { + return this.TryCatch(delegate + { + byte[] bytes = ((RedisClient)this.client).GetRange(key, fromIndex, toIndex); + if (bytes != null) + { + return StringExtensions.FromUtf8Bytes(bytes); + } + return null; + }, key); + } + + public TimeSpan GetTimeToLive(string key) + { + return this.TryCatch(delegate + { + TimeSpan? t = this.client.GetTimeToLive(key); + if (!t.HasValue) + { + return TimeSpan.Zero; + } + return t.Value; + }, key); + } + + public HashSet GetUnionFromSets(params string[] setIds) + { + return this.TryCatch>(() => this.client.GetUnionFromSets(setIds), setIds[0]); + } + + public string GetValue(string key) + { + return this.TryCatch(() => this.client.GetValue(key), key); + } + + public string GetValueFromHash(string hashId, string key) + { + return this.TryCatch(() => this.client.GetValueFromHash(hashId, key), hashId); + } + + public List GetValues(List keys) + { + return this.TryCatch>(() => this.client.GetValues(keys), keys[0]); + } + + public List GetValues(List keys) + { + return this.TryCatch>(() => this.client.GetValues(keys), keys[0]); + } + + public List GetValuesFromHash(string hashId, params string[] keys) + { + return this.TryCatch>(() => this.client.GetValuesFromHash(hashId, keys), hashId); + } + + public Dictionary GetValuesMap(List keys) + { + return this.TryCatch>(() => this.client.GetValuesMap(keys), keys[0]); + } + + public Dictionary GetValuesMap(List keys) + { + return this.TryCatch>(() => this.client.GetValuesMap(keys), keys[0]); + } + + public bool HashContainsEntry(string hashId, string key) + { + return this.TryCatch(() => this.client.HashContainsEntry(hashId, key), hashId); + } + + public double IncrementItemInSortedSet(string setId, string value, double incrementBy) + { + return this.TryCatch(() => this.client.IncrementItemInSortedSet(setId, value, incrementBy), setId); + } + + public double IncrementItemInSortedSet(string setId, string value, long incrementBy) + { + return this.TryCatch(() => this.client.IncrementItemInSortedSet(setId, value, incrementBy), setId); + } + + public long IncrementValue(string key) + { + return this.TryCatch(() => this.client.IncrementValue(key), key); + } + + public long IncrementValueBy(string key, int count) + { + return this.TryCatch(() => this.client.IncrementValueBy(key, count), key); + } + + public long IncrementValueInHash(string hashId, string key, int incrementBy) + { + return this.TryCatch(() => this.client.IncrementValueInHash(hashId, key, incrementBy), hashId); + } + + public void MoveBetweenSets(string fromSetId, string toSetId, string item) + { + this.TryCatch(delegate + { + this.client.MoveBetweenSets(fromSetId, toSetId, item); + }, fromSetId); + } + + public string PopAndPushItemBetweenLists(string fromListId, string toListId) + { + return this.TryCatch(() => this.client.PopAndPushItemBetweenLists(fromListId, toListId), fromListId); + } + + public string PopItemFromList(string listId) + { + return this.TryCatch(() => this.client.PopItemFromList(listId), listId); + } + + public string PopItemFromSet(string setId) + { + return this.TryCatch(() => this.client.PopItemFromSet(setId), setId); + } + + public string PopItemWithHighestScoreFromSortedSet(string setId) + { + return this.TryCatch(() => this.client.PopItemWithHighestScoreFromSortedSet(setId), setId); + } + + public string PopItemWithLowestScoreFromSortedSet(string setId) + { + return this.TryCatch(() => this.client.PopItemWithLowestScoreFromSortedSet(setId), setId); + } + + public void PrependItemToList(string listId, string value) + { + this.TryCatch(delegate + { + this.client.PrependItemToList(listId, value); + }, listId); + } + + public void PrependRangeToList(string listId, List values) + { + this.TryCatch(delegate + { + this.client.PrependRangeToList(listId, values); + }, listId); + } + + public long PublishMessage(string toChannel, string message) + { + return this.TryCatch(() => this.client.PublishMessage(toChannel, message), string.Empty); + } + + public void PushItemToList(string listId, string value) + { + this.TryCatch(delegate + { + this.client.PushItemToList(listId, value); + }, listId); + } + + public void RemoveAllFromList(string listId) + { + this.TryCatch(delegate + { + this.client.Remove(listId); + }, listId); + } + + public string RemoveEndFromList(string listId) + { + return this.TryCatch(() => this.client.RemoveEndFromList(listId), listId); + } + + public bool RemoveEntry(params string[] args) + { + return this.TryCatch(() => this.client.RemoveEntry(args), args[0]); + } + + public bool RemoveEntryFromHash(string hashId, string key) + { + return this.TryCatch(() => this.client.RemoveEntryFromHash(hashId, key), hashId); + } + + public long RemoveItemFromList(string listId, string value) + { + return this.TryCatch(() => this.client.RemoveItemFromList(listId, value), listId); + } + + public long RemoveItemFromList(string listId, string value, int noOfMatches) + { + return this.TryCatch(() => this.client.RemoveItemFromList(listId, value, noOfMatches), listId); + } + + public void RemoveItemFromSet(string setId, string item) + { + this.TryCatch(delegate + { + this.client.RemoveItemFromSet(setId, item); + }, setId); + } + + public bool RemoveItemFromSortedSet(string setId, string value) + { + return this.TryCatch(() => this.client.RemoveItemFromSortedSet(setId, value), setId); + } + /// + /// 骚操作-- redis 连接池-- 如果出现高并发,客户端的连接数量会上限,为了节省资源,重复利用连接对象,通过线程池去获取连接 + /// + /// + /// + /// + /// + public static IRedisClientsManager GetPoolClient(string host, int port, int db) + { + return new PooledRedisClientManager(db, host + ":" + port); + } + public long RemoveRangeFromSortedSet(string setId, int minRank, int maxRank) + { + return this.TryCatch(() => this.client.RemoveRangeFromSortedSet(setId, minRank, maxRank), setId); + } + + public long RemoveRangeFromSortedSetByScore(string setId, double fromScore, double toScore) + { + return this.TryCatch(() => this.client.RemoveRangeFromSortedSetByScore(setId, fromScore, toScore), setId); + } + + public long RemoveRangeFromSortedSetByScore(string setId, long fromScore, long toScore) + { + return this.TryCatch(() => this.client.RemoveRangeFromSortedSetByScore(setId, fromScore, toScore), setId); + } + + public string RemoveStartFromList(string listId) + { + return this.TryCatch(() => this.client.RemoveStartFromList(listId), listId); + } + + public void RenameKey(string fromName, string toName) + { + this.TryCatch(delegate + { + this.client.RenameKey(fromName, toName); + }, string.Empty); + } + + public List SearchKeys(string pattern) + { + return this.TryCatch>(() => this.client.SearchKeys(pattern), pattern); + } + + public void SetAll(Dictionary map) + { + this.TryCatch(delegate + { + this.client.SetAll(map); + }, string.Empty); + } + + public void SetAll(IEnumerable keys, IEnumerable values) + { + this.TryCatch(delegate + { + this.client.SetAll(keys, values); + }, string.Empty); + } + + public bool SetContainsItem(string setId, string item) + { + return this.TryCatch(() => this.client.SetContainsItem(setId, item), setId); + } + + public void SetEntry(string key, string value) + { + this.TryCatch(delegate + { + this.client.SetValue(key, value); + }, key); + } + + public void SetEntry(string key, string value, TimeSpan expireIn) + { + this.TryCatch(delegate + { + this.client.SetValue(key, value, expireIn); + }, key); + } + + public bool SetEntryIfNotExists(string key, string value) + { + return this.TryCatch(() => this.client.SetValueIfNotExists(key, value), key); + } + + public bool SetEntryInHash(string hashId, string key, string value) + { + return this.TryCatch(() => this.client.SetEntryInHash(hashId, key, value), hashId); + } + + public bool SetEntryInHashIfNotExists(string hashId, string key, string value) + { + return this.TryCatch(() => this.client.SetEntryInHashIfNotExists(hashId, key, value), hashId); + } + + public void SetItemInList(string listId, int listIndex, string value) + { + this.TryCatch(delegate + { + this.client.SetItemInList(listId, listIndex, value); + }, listId); + } + + public void SetRangeInHash(string hashId, IEnumerable> keyValuePairs) + { + this.TryCatch(delegate + { + this.client.SetRangeInHash(hashId, keyValuePairs); + }, hashId); + } + + public bool SortedSetContainsItem(string setId, string value) + { + return this.TryCatch(() => this.client.SortedSetContainsItem(setId, value), setId); + } + + public void StoreAsHash(T entity) + { + this.TryCatch(delegate + { + this.client.StoreAsHash(entity); + }, string.Empty); + } + + + public bool SetEntryInHash(string hashId, string key, T value) + { + return this.TryCatch(() => this.client.SetEntryInHash(hashId, key, TextExtensions.SerializeToString(value)), hashId); + } + + public T GetValueFromHash(string hashId, string key) + { + return this.TryCatch(() => JsonSerializer.DeserializeFromString(this.client.GetValueFromHash(hashId, key)), hashId); + } + + public bool SetEntryInHashIfNotExists(string hashId, string key, T value) + { + return this.TryCatch(() => this.client.SetEntryInHashIfNotExists(hashId, key, TextExtensions.SerializeToString(value)), hashId); + } + + public IDisposable AcquireLock(string key) + { + return this.TryCatch(() => this.client.AcquireLock(key), key); + } + + public IDisposable AcquireLock(string key, TimeSpan timeOut) + { + return this.TryCatch(() => this.client.AcquireLock(key, timeOut), key); + } + + + public DateTime GetServerTime() + { + return this.TryCatch(() => this.client.GetServerTime(), string.Empty); + } + + + } +} diff --git a/Yi.Framework/Yi.Framework.Core/Class1.cs b/Yi.Framework/Yi.Framework.Core/Class1.cs new file mode 100644 index 00000000..1c0fddf7 --- /dev/null +++ b/Yi.Framework/Yi.Framework.Core/Class1.cs @@ -0,0 +1,8 @@ +using System; + +namespace Yi.Framework.Core +{ + public class Class1 + { + } +} diff --git a/Yi.Framework/Yi.Framework.Core/ConsulExtend/ClienExtend/AbstractConsulDispatcher.cs b/Yi.Framework/Yi.Framework.Core/ConsulExtend/ClienExtend/AbstractConsulDispatcher.cs new file mode 100644 index 00000000..f9449e94 --- /dev/null +++ b/Yi.Framework/Yi.Framework.Core/ConsulExtend/ClienExtend/AbstractConsulDispatcher.cs @@ -0,0 +1,71 @@ +using Consul; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CC.ElectronicCommerce.Core.ConsulExtend +{ + public abstract class AbstractConsulDispatcher + { + protected ConsulClientOption _ConsulClientOption = null; + protected KeyValuePair[] _CurrentAgentServiceDictionary = null; + + public AbstractConsulDispatcher(IOptionsMonitor consulClientOption) + { + this._ConsulClientOption = consulClientOption.CurrentValue; + } + + /// + /// 负载均衡获取地址 + /// + /// Consul映射后的地址 + /// + public string GetAddress(string mappingUrl) + { + Uri uri = new Uri(mappingUrl); + string serviceName = uri.Host; + string addressPort = this.ChooseAddress(serviceName); + return $"{uri.Scheme}://{addressPort}{uri.PathAndQuery}"; + } + + protected virtual string ChooseAddress(string serviceName) + { + ConsulClient client = new ConsulClient(c => + { + c.Address = new Uri($"http://{this._ConsulClientOption.IP}:{this._ConsulClientOption.Port}/"); + c.Datacenter = this._ConsulClientOption.Datacenter; + }); + AgentService agentService = null; + //var response = client.Agent.Services().Result.Response; + ////foreach (var item in response) + ////{ + //// Console.WriteLine("***************************************"); + //// Console.WriteLine(item.Key); + //// var service = item.Value; + //// Console.WriteLine($"{service.Address}--{service.Port}--{service.Service}"); + //// Console.WriteLine("***************************************"); + ////} + + //this._CurrentAgentServiceDictionary = response.Where(s => s.Value.Service.Equals(serviceName, StringComparison.OrdinalIgnoreCase)).ToArray(); + + //升级consul实例获取 + var entrys = client.Health.Service(serviceName).Result.Response; + List> serviceList = new List>(); + for (int i = 0; i < entrys.Length; i++) + { + serviceList.Add(new KeyValuePair(i.ToString(), entrys[i].Service)); + } + this._CurrentAgentServiceDictionary = serviceList.ToArray(); + + int index = this.GetIndex(); + agentService = this._CurrentAgentServiceDictionary[index].Value; + + return $"{agentService.Address}:{agentService.Port}"; + } + + protected abstract int GetIndex(); + } +} diff --git a/Yi.Framework/Yi.Framework.Core/ConsulExtend/ClienExtend/AverageDispatcher.cs b/Yi.Framework/Yi.Framework.Core/ConsulExtend/ClienExtend/AverageDispatcher.cs new file mode 100644 index 00000000..0bd2d5da --- /dev/null +++ b/Yi.Framework/Yi.Framework.Core/ConsulExtend/ClienExtend/AverageDispatcher.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Consul; +using Microsoft.Extensions.Options; + +namespace CC.ElectronicCommerce.Core.ConsulExtend +{ + /// + /// 平均 + /// + public class AverageDispatcher : AbstractConsulDispatcher + { + #region Identity + private static int _iTotalCount = 0; + private static int iTotalCount + { + get + { + return _iTotalCount; + } + set + { + _iTotalCount = value >= Int32.MaxValue ? 0 : value; + } + } + + + public AverageDispatcher(IOptionsMonitor consulClientOption) : base(consulClientOption) + { + } + #endregion + + /// + /// 平均 + /// + /// + protected override int GetIndex() + { + return new Random(iTotalCount++).Next(0, base._CurrentAgentServiceDictionary.Length); + } + } +} diff --git a/Yi.Framework/Yi.Framework.Core/ConsulExtend/ClienExtend/PollingDispatcher.cs b/Yi.Framework/Yi.Framework.Core/ConsulExtend/ClienExtend/PollingDispatcher.cs new file mode 100644 index 00000000..2d8039c5 --- /dev/null +++ b/Yi.Framework/Yi.Framework.Core/ConsulExtend/ClienExtend/PollingDispatcher.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Consul; +using Microsoft.Extensions.Options; + +namespace CC.ElectronicCommerce.Core.ConsulExtend +{ + /// + /// 轮询 + /// + public class PollingDispatcher : AbstractConsulDispatcher + { + #region Identity + private static int _iTotalCount = 0; + private static int iTotalCount + { + get + { + return _iTotalCount; + } + set + { + _iTotalCount = value >= Int32.MaxValue ? 0 : value; + } + } + + public PollingDispatcher(IOptionsMonitor consulClientOption) : base(consulClientOption) + { + } + #endregion + + /// + /// 轮询 + /// + /// + /// + protected override int GetIndex() + { + return iTotalCount++ % base._CurrentAgentServiceDictionary.Length; + } + } +} diff --git a/Yi.Framework/Yi.Framework.Core/ConsulExtend/ClienExtend/WeightDispatcher.cs b/Yi.Framework/Yi.Framework.Core/ConsulExtend/ClienExtend/WeightDispatcher.cs new file mode 100644 index 00000000..9d482312 --- /dev/null +++ b/Yi.Framework/Yi.Framework.Core/ConsulExtend/ClienExtend/WeightDispatcher.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Consul; +using Microsoft.Extensions.Options; + +namespace CC.ElectronicCommerce.Core.ConsulExtend +{ + /// + /// 权重 + /// + public class WeightDispatcher : AbstractConsulDispatcher + { + #region Identity + private static int _iTotalCount = 0; + private static int iTotalCount + { + get + { + return _iTotalCount; + } + set + { + _iTotalCount = value >= Int32.MaxValue ? 0 : value; + } + } + public WeightDispatcher(IOptionsMonitor consulClientOption) : base(consulClientOption) + { + + } + #endregion + + protected override string ChooseAddress(string serviceName) + { + ConsulClient client = new ConsulClient(c => + { + c.Address = new Uri($"http://{base._ConsulClientOption.IP}:{base._ConsulClientOption.Port}/"); + c.Datacenter = base._ConsulClientOption.Datacenter; + }); + AgentService agentService = null; + var response = client.Agent.Services().Result.Response; + + this._CurrentAgentServiceDictionary = response.Where(s => s.Value.Service.Equals(serviceName, StringComparison.OrdinalIgnoreCase)).ToArray(); + + + var serviceDictionaryNew = new List(); + foreach (var service in base._CurrentAgentServiceDictionary) + { + serviceDictionaryNew.AddRange(Enumerable.Repeat(service.Value, int.TryParse(service.Value.Tags?[0], out int iWeight) ? 1 : iWeight)); + } + int index = new Random(DateTime.Now.Millisecond).Next(0, int.MaxValue) % serviceDictionaryNew.Count; + agentService = serviceDictionaryNew[index]; + + return $"{agentService.Address}:{agentService.Port}"; + } + /// + /// 不需要了 + /// + /// + protected override int GetIndex() + { + throw new NotImplementedException(); + } + } +} diff --git a/Yi.Framework/Yi.Framework.Core/ConsulExtend/ConsulClientOption.cs b/Yi.Framework/Yi.Framework.Core/ConsulExtend/ConsulClientOption.cs new file mode 100644 index 00000000..5eebc512 --- /dev/null +++ b/Yi.Framework/Yi.Framework.Core/ConsulExtend/ConsulClientOption.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CC.ElectronicCommerce.Core.ConsulExtend +{ + /// + /// 使用Consul时需要配置 + /// + public class ConsulClientOption + { + public string IP { get; set; } + public int Port { get; set; } + public string Datacenter { get; set; } + } +} diff --git a/Yi.Framework/Yi.Framework.Core/ConsulExtend/ServerExtend/ConsulRegisterOption.cs b/Yi.Framework/Yi.Framework.Core/ConsulExtend/ServerExtend/ConsulRegisterOption.cs new file mode 100644 index 00000000..0cb6847d --- /dev/null +++ b/Yi.Framework/Yi.Framework.Core/ConsulExtend/ServerExtend/ConsulRegisterOption.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CC.ElectronicCommerce.Core.ConsulExtend +{ + public class ConsulRegisterOption + { + /// + /// 服务自身IP + /// + public string IP { get; set; } + /// + /// 服务自身Port + /// + public int Port { get; set; } + /// + /// 组名称 + /// + public string GroupName { get; set; } + /// + /// 心跳检查地址 + /// + public string HealthCheckUrl { get; set; } + /// + /// 心跳频率 + /// + public int Interval { get; set; } + /// + /// 心跳超时 + /// + public int Timeout { get; set; } + /// + /// 移除延迟时间 + /// + public int DeregisterCriticalServiceAfter { get; set; } + /// + /// 标签,额外信息,用于权重 + /// + public string Tag { get; set; } + } +} diff --git a/Yi.Framework/Yi.Framework.Core/ConsulExtend/ServerExtend/ConsulRegiterExtend.cs b/Yi.Framework/Yi.Framework.Core/ConsulExtend/ServerExtend/ConsulRegiterExtend.cs new file mode 100644 index 00000000..b38fccda --- /dev/null +++ b/Yi.Framework/Yi.Framework.Core/ConsulExtend/ServerExtend/ConsulRegiterExtend.cs @@ -0,0 +1,69 @@ +using Consul; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CC.ElectronicCommerce.Core.ConsulExtend +{ + /// + /// HTTP模式 + /// + public static class ConsulRegiterExtend + { + /// + /// 自动读取配置文件完成注册 + /// + /// + /// + /// + public static async Task UseConsulConfiguration(this IApplicationBuilder app, IConfiguration configuration) + { + ConsulRegisterOption consulRegisterOption = new ConsulRegisterOption(); + configuration.Bind("ConsulRegisterOption", consulRegisterOption); + + ConsulClientOption consulClientOption = new ConsulClientOption(); + configuration.Bind("ConsulClientOption", consulClientOption); + + await UseConsul(app, consulClientOption, consulRegisterOption); + } + /// + /// 基于提供信息完成注册 + /// + /// + /// + /// + public static async Task UseConsul(this IApplicationBuilder app, ConsulClientOption consulClientOption, ConsulRegisterOption consulRegisterOption) + { + using (ConsulClient client = new ConsulClient(c => + { + c.Address = new Uri($"http://{consulClientOption.IP}:{consulClientOption.Port}/"); + c.Datacenter = consulClientOption.Datacenter; + })) + { + await client.Agent.ServiceRegister(new AgentServiceRegistration() + { + ID = $"{consulRegisterOption.IP}-{consulRegisterOption.Port}-{Guid.NewGuid()}",//唯一Id + Name = consulRegisterOption.GroupName,//组名称-Group + Address = consulRegisterOption.IP, + Port = consulRegisterOption.Port, + Tags = new string[] { consulRegisterOption.Tag }, + Check = new AgentServiceCheck() + { + Interval = TimeSpan.FromSeconds(consulRegisterOption.Interval), + HTTP = $"http://{consulRegisterOption.IP}:{consulRegisterOption.Port}{consulRegisterOption.HealthCheckUrl}", + Timeout = TimeSpan.FromSeconds(consulRegisterOption.Timeout), + DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(consulRegisterOption.DeregisterCriticalServiceAfter) + } + }); + Console.WriteLine($"{JsonConvert.SerializeObject(consulRegisterOption)} 完成注册"); + } + } + + + } +} diff --git a/Yi.Framework/Yi.Framework.Core/ConsulExtend/ServerExtend/HealthCheckMiddleware.cs b/Yi.Framework/Yi.Framework.Core/ConsulExtend/ServerExtend/HealthCheckMiddleware.cs new file mode 100644 index 00000000..b952fef1 --- /dev/null +++ b/Yi.Framework/Yi.Framework.Core/ConsulExtend/ServerExtend/HealthCheckMiddleware.cs @@ -0,0 +1,31 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace CC.ElectronicCommerce.Core.ConsulExtend +{ + public static class HealthCheckMiddleware + { + /// + /// 设置心跳响应 + /// + /// + /// 默认是/Health + /// + public static void UseHealthCheckMiddleware(this IApplicationBuilder app, string checkPath = "/Health") + { + app.Map(checkPath, applicationBuilder => applicationBuilder.Run(async context => + { + Console.WriteLine($"This is Health Check"); + context.Response.StatusCode = (int)HttpStatusCode.OK; + await context.Response.WriteAsync("OK"); + })); + } + + } +} diff --git a/Yi.Framework/Yi.Framework.Core/Library/Microsoft.Bcl.AsyncInterfaces.dll b/Yi.Framework/Yi.Framework.Core/Library/Microsoft.Bcl.AsyncInterfaces.dll new file mode 100644 index 0000000000000000000000000000000000000000..c695bdd5965b0b687fdee8984d5d36e1a33fb642 GIT binary patch literal 14920 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 literal 0 HcmV?d00001 diff --git a/Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Common.dll b/Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Common.dll new file mode 100644 index 0000000000000000000000000000000000000000..f10b87b43853c83f27dd617a9bfc76bf56150c2a GIT binary patch literal 1039872 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