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 00000000..c695bdd5 Binary files /dev/null and b/Yi.Framework/Yi.Framework.Core/Library/Microsoft.Bcl.AsyncInterfaces.dll differ 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 00000000..f10b87b4 Binary files /dev/null and b/Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Common.dll differ diff --git a/Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Interfaces.dll b/Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Interfaces.dll new file mode 100644 index 00000000..4dbba7ef Binary files /dev/null and b/Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Interfaces.dll differ diff --git a/Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Redis.dll b/Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Redis.dll new file mode 100644 index 00000000..5faefa26 Binary files /dev/null and b/Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Redis.dll differ diff --git a/Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Text.dll b/Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Text.dll new file mode 100644 index 00000000..2f701811 Binary files /dev/null and b/Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Text.dll differ diff --git a/Yi.Framework/Yi.Framework.Core/MD5Helper.cs b/Yi.Framework/Yi.Framework.Core/MD5Helper.cs new file mode 100644 index 00000000..52d7c582 --- /dev/null +++ b/Yi.Framework/Yi.Framework.Core/MD5Helper.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Text; + +namespace CC.ElectronicCommerce.Core + +{ + /// + /// 加密用的 + /// + public class MD5Helper + { + /// + /// MD5 加密字符串 + /// + /// 源字符串 + /// 加密后字符串 + public static string MD5EncodingOnly(string content) + { + // 创建MD5类的默认实例:MD5CryptoServiceProvider + MD5 md5 = MD5.Create(); + byte[] bs = Encoding.UTF8.GetBytes(content); + byte[] hs = md5.ComputeHash(bs); + StringBuilder stb = new StringBuilder(); + foreach (byte b in hs) + { + // 以十六进制格式格式化 + stb.Append(b.ToString("x2")); + } + return stb.ToString(); + } + + /// + /// MD5盐值加密 + /// + /// 源字符串 + /// 盐值 + /// 加密后字符串 + public static string MD5EncodingWithSalt(string content, string salt) + { + if (salt == null) return content; + return MD5EncodingOnly(content + "{" + salt.ToString() + "}"); + } + } +} + diff --git a/Yi.Framework/Yi.Framework.Core/RabbitMQInvoker.cs b/Yi.Framework/Yi.Framework.Core/RabbitMQInvoker.cs new file mode 100644 index 00000000..3e7e6e2c --- /dev/null +++ b/Yi.Framework/Yi.Framework.Core/RabbitMQInvoker.cs @@ -0,0 +1,253 @@ +using CC.ElectronicCommerce.Common.IOCOptions; +using Microsoft.Extensions.Options; +using RabbitMQ.Client; +using RabbitMQ.Client.Events; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CC.ElectronicCommerce.Core +{ + /// + /// 一个Exchange----多个Queue-----弄个缓存映射关系,初始化+支持全新绑定 + /// 全局单例使用 + /// + /// 关系应该是直接配置到RabbitMQ了---程序只是向某个位置写入即可 + /// + /// + /// 全量更新--耗时---阻塞实时更新---换不同的exchange? + /// + public class RabbitMQInvoker + { + #region Identity + private readonly RabbitMQOptions _rabbitMQOptions; + private readonly string _HostName = null; + private readonly string _UserName = null; + private readonly string _Password = null; + public RabbitMQInvoker(IOptionsMonitor optionsMonitor) : this(optionsMonitor.CurrentValue.HostName, optionsMonitor.CurrentValue.UserName, optionsMonitor.CurrentValue.Password) + { + this._rabbitMQOptions = optionsMonitor.CurrentValue; + } + + public RabbitMQInvoker(string hostName, string userName = "cc", string password = "cc") + { + this._HostName = hostName; + this._UserName = userName; + this._Password = password; + } + #endregion + + #region Init + private static object RabbitMQInvoker_BindQueueLock = new object(); + private static Dictionary RabbitMQInvoker_ExchangeQueue = new Dictionary(); + private void InitBindQueue(RabbitMQConsumerModel rabbitMQConsumerModel) + { + if (!RabbitMQInvoker_ExchangeQueue.ContainsKey($"InitBindQueue_{rabbitMQConsumerModel.ExchangeName}_{rabbitMQConsumerModel.QueueName}")) + { + lock (RabbitMQInvoker_BindQueueLock) + { + if (!RabbitMQInvoker_ExchangeQueue.ContainsKey($"InitBindQueue_{rabbitMQConsumerModel.ExchangeName}_{rabbitMQConsumerModel.QueueName}")) + { + this.InitConnection(); + using (IModel channel = _CurrentConnection.CreateModel()) + { + channel.ExchangeDeclare(exchange: rabbitMQConsumerModel.ExchangeName, type: ExchangeType.Fanout, durable: true, autoDelete: false, arguments: null); + channel.QueueDeclare(queue: rabbitMQConsumerModel.QueueName, durable: true, exclusive: false, autoDelete: false, arguments: null); + channel.QueueBind(queue: rabbitMQConsumerModel.QueueName, exchange: rabbitMQConsumerModel.ExchangeName, routingKey: string.Empty, arguments: null); + } + RabbitMQInvoker_ExchangeQueue[$"InitBindQueue_{rabbitMQConsumerModel.ExchangeName}_{rabbitMQConsumerModel.QueueName}"] = true; + } + } + } + } + /// + /// 必须先声明exchange--检查+初始化 + /// + /// + private void InitExchange(string exchangeName) + { + if (!RabbitMQInvoker_ExchangeQueue.ContainsKey($"InitExchange_{exchangeName}"))//没用api确认 + { + lock (RabbitMQInvoker_BindQueueLock) + { + if (!RabbitMQInvoker_ExchangeQueue.ContainsKey($"InitExchange_{exchangeName}")) + { + this.InitConnection(); + using (IModel channel = _CurrentConnection.CreateModel()) + { + channel.ExchangeDeclare(exchange: exchangeName, type: ExchangeType.Fanout, durable: true, autoDelete: false, arguments: null); + } + RabbitMQInvoker_ExchangeQueue[$"InitExchange_{exchangeName}"] = true; + } + } + } + } + //public void UnBindQueue(string exchangeName, string queueName) + //{ + //} + + private static object RabbitMQInvoker_InitLock = new object(); + private static IConnection _CurrentConnection = null;//链接做成单例重用--channel是新的 + private void InitConnection() + { + //https://blog.csdn.net/weixin_30646315/article/details/99101279 + if (_CurrentConnection == null || !_CurrentConnection.IsOpen) + { + lock (RabbitMQInvoker_InitLock) + { + if (_CurrentConnection == null || !_CurrentConnection.IsOpen) + { + var factory = new ConnectionFactory() + { + HostName = this._HostName, + Password = this._Password, + UserName = this._UserName + }; + _CurrentConnection = factory.CreateConnection(); + } + } + } + } + #endregion + + /// + /// 只管exchange--- + /// 4种路由类型? + /// + /// Send前完成交换机初始化 + /// + /// + /// 建议Json格式 + public void Send(RabbitMQConsumerModel rabbitMQConsumerModel, string message) + { + this.InitExchange(rabbitMQConsumerModel.ExchangeName); + this.InitBindQueue(rabbitMQConsumerModel); + if (_CurrentConnection == null || !_CurrentConnection.IsOpen) + { + this.InitConnection(); + } + using (var channel = _CurrentConnection.CreateModel())//开辟新的信道通信 + { + try + { + channel.TxSelect();//开启Tx事务---RabbitMQ协议级的事务-----强事务 + + var body = Encoding.UTF8.GetBytes(message); + channel.BasicPublish(exchange: rabbitMQConsumerModel.ExchangeName, + routingKey: string.Empty, + basicProperties: null, + body: body); + channel.TxCommit();//提交 + Console.WriteLine($" [x] Sent {body.Length}"); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + Console.WriteLine($"【{message}】发送到Broker失败!{ex.Message}"); + channel.TxRollback(); //事务回滚--前面的所有操作就全部作废了。。。。 + } + } + } + + /// + /// 固定无消费队列名字---转移到目标队列---定好时间 + /// + /// + /// + /// + public void SendDelay(string targetExchangeName, string message, int delaySecond) + { + this.InitExchange(targetExchangeName); + + if (_CurrentConnection == null || !_CurrentConnection.IsOpen) + { + this.InitConnection(); + } + using (var channel = _CurrentConnection.CreateModel())//开辟新的信道通信 + { + try + { + string delayExchangeName = "ZhaoxiMSA_DelayExchange"; + + //普通交换器 + channel.ExchangeDeclare(delayExchangeName, "fanout", true, false, null); + //参数设置 + Dictionary args = new Dictionary(); + args.Add("x-message-ttl", delaySecond * 1000);//TTL 毫秒 + args.Add("x-dead-letter-exchange", targetExchangeName);//DLX + args.Add("x-dead-letter-routing-key", "routingkey");//routingKey + channel.QueueDeclare("ZhaoxiMSA_DelayQueue", true, false, false, args); + channel.QueueBind(queue: "ZhaoxiMSA_DelayQueue", + exchange: delayExchangeName, + routingKey: string.Empty, + arguments: null); + + ////DLX--- //死信队列绑定 + //channel.ExchangeDeclare("ZhaoxiMSA_exchange_dlx", "fanout", true, false, null); + //channel.QueueDeclare("ZhaoxiMSA_queue_dlx", true, false, false, null); + //channel.QueueBind("ZhaoxiMSA_queue_dlx", "ZhaoxiMSA_exchange_dlx", "routingkey", null); + + + channel.TxSelect();//开启Tx事务---RabbitMQ协议级的事务-----强事务 + var properties = channel.CreateBasicProperties(); + + var body = Encoding.UTF8.GetBytes(message); + channel.BasicPublish(exchange: delayExchangeName, + routingKey: string.Empty, + basicProperties: properties, + body: body); + channel.TxCommit();//提交 + Console.WriteLine($" [x] Sent {body.Length}"); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + Console.WriteLine($"【{message}】发送到Broker失败!{ex.Message}"); + channel.TxRollback(); //事务回滚--前面的所有操作就全部作废了。。。。 + } + } + } + + #region Receive + /// + /// 注册处理动作 + /// + /// + /// + public void RegistReciveAction(RabbitMQConsumerModel rabbitMQConsumerMode, Func func) + { + this.InitBindQueue(rabbitMQConsumerMode); + + Task.Run(() => + { + using (var channel = _CurrentConnection.CreateModel()) + { + var consumer = new EventingBasicConsumer(channel); + channel.BasicQos(0, 0, true); + consumer.Received += (sender, ea) => + { + string str = Encoding.UTF8.GetString(ea.Body.ToArray()); + if (func(str)) + { + channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);//确认已消费 + } + else + { + //channel.BasicReject(deliveryTag: ea.DeliveryTag, requeue: true);//放回队列--重新包装信息,放入其他队列 + } + }; + channel.BasicConsume(queue: rabbitMQConsumerMode.QueueName, + autoAck: false,//不ACK + consumer: consumer); + Console.WriteLine($" Register Consumer To {rabbitMQConsumerMode.ExchangeName}-{rabbitMQConsumerMode.QueueName}"); + Console.ReadLine(); + Console.WriteLine($" After Register Consumer To {rabbitMQConsumerMode.ExchangeName}-{rabbitMQConsumerMode.QueueName}"); + } + }); + } + #endregion + + } +} diff --git a/Yi.Framework/Yi.Framework.Core/SnowflakeHelper.cs b/Yi.Framework/Yi.Framework.Core/SnowflakeHelper.cs new file mode 100644 index 00000000..a163122e --- /dev/null +++ b/Yi.Framework/Yi.Framework.Core/SnowflakeHelper.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CC.ElectronicCommerce.Core +{ + public static class SnowflakeHelper + { + public static long Next() + { + SnowflakeTool snowflakeTool = new SnowflakeTool(1); + return snowflakeTool.NextId(); + } + + private class SnowflakeTool + { + //机器ID + private static long nodeId; + private static long twepoch = 687888001020L; //唯一时间,这是一个避免重复的随机量,自行设定不要大于当前时间戳 + private static long sequence = 0L; + private static int workerIdBits = 4; //机器码字节数。4个字节用来保存机器码(定义为Long类型会出现,最大偏移64位,所以左移64位没有意义) + public static long maxWorkerId = -1L ^ -1L << workerIdBits; //最大机器ID + private static int sequenceBits = 10; //计数器字节数,10个字节用来保存计数码 + private static int workerIdShift = sequenceBits; //机器码数据左移位数,就是后面计数器占用的位数 + private static int timestampLeftShift = sequenceBits + workerIdBits; //时间戳左移动位数就是机器码和计数器总字节数 + public static long sequenceMask = -1L ^ -1L << sequenceBits; //一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成 + private long lastTimestamp = -1L; + + /// + /// 机器码 + /// + /// + public SnowflakeTool(long workerId) + { + if (workerId > maxWorkerId || workerId < 0) + throw new Exception(string.Format("节点id 不能大于 {0} 或者 小于 0 ", workerId)); + SnowflakeTool.nodeId = workerId; + + } + + public long NextId() + { + lock (this) + { + long timestamp = TimeGen(); + if (this.lastTimestamp == timestamp) + { //同一微妙中生成ID + SnowflakeTool.sequence = (SnowflakeTool.sequence + 1) & SnowflakeTool.sequenceMask; //用&运算计算该微秒内产生的计数是否已经到达上限 + if (SnowflakeTool.sequence == 0) + { + //一微妙内产生的ID计数已达上限,等待下一微妙 + timestamp = TillNextMillis(this.lastTimestamp); + } + } + else + { //不同微秒生成ID + SnowflakeTool.sequence = 0; //计数清0 + } + if (timestamp < lastTimestamp) + { //如果当前时间戳比上一次生成ID时时间戳还小,抛出异常,因为不能保证现在生成的ID之前没有生成过 + throw new Exception(string.Format("Clock moved backwards. Refusing to generate id for {0} milliseconds", + this.lastTimestamp - timestamp)); + } + this.lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳 + long nextId = (timestamp - twepoch << timestampLeftShift) | SnowflakeTool.nodeId << SnowflakeTool.workerIdShift | SnowflakeTool.sequence; + return nextId; + } + } + + /// + /// 获取下一微秒时间戳 + /// + /// + /// + private long TillNextMillis(long lastTimestamp) + { + long timestamp = TimeGen(); + while (timestamp <= lastTimestamp) + { + timestamp = TimeGen(); + } + return timestamp; + } + + /// + /// 生成当前时间戳 + /// + /// + private long TimeGen() + { + return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds; + } + } + } + + +} diff --git a/Yi.Framework/Yi.Framework.Core/Yi.Framework.Core.csproj b/Yi.Framework/Yi.Framework.Core/Yi.Framework.Core.csproj new file mode 100644 index 00000000..f208d303 --- /dev/null +++ b/Yi.Framework/Yi.Framework.Core/Yi.Framework.Core.csproj @@ -0,0 +1,7 @@ + + + + net5.0 + + + diff --git a/Yi.Framework/Yi.Framework.DTOModel/Class1.cs b/Yi.Framework/Yi.Framework.DTOModel/Class1.cs new file mode 100644 index 00000000..e25dec52 --- /dev/null +++ b/Yi.Framework/Yi.Framework.DTOModel/Class1.cs @@ -0,0 +1,8 @@ +using System; + +namespace Yi.Framework.DTOModel +{ + public class Class1 + { + } +} diff --git a/Yi.Framework/Yi.Framework.DTOModel/Yi.Framework.DTOModel.csproj b/Yi.Framework/Yi.Framework.DTOModel/Yi.Framework.DTOModel.csproj new file mode 100644 index 00000000..f208d303 --- /dev/null +++ b/Yi.Framework/Yi.Framework.DTOModel/Yi.Framework.DTOModel.csproj @@ -0,0 +1,7 @@ + + + + net5.0 + + + diff --git a/Yi.Framework/Yi.Framework.Interface/Class1.cs b/Yi.Framework/Yi.Framework.Interface/Class1.cs new file mode 100644 index 00000000..197b048a --- /dev/null +++ b/Yi.Framework/Yi.Framework.Interface/Class1.cs @@ -0,0 +1,8 @@ +using System; + +namespace Yi.Framework.Interface +{ + public class Class1 + { + } +} diff --git a/Yi.Framework/Yi.Framework.Interface/Yi.Framework.Interface.csproj b/Yi.Framework/Yi.Framework.Interface/Yi.Framework.Interface.csproj new file mode 100644 index 00000000..f208d303 --- /dev/null +++ b/Yi.Framework/Yi.Framework.Interface/Yi.Framework.Interface.csproj @@ -0,0 +1,7 @@ + + + + net5.0 + + + diff --git a/Yi.Framework/Yi.Framework.Model/Class1.cs b/Yi.Framework/Yi.Framework.Model/Class1.cs new file mode 100644 index 00000000..8cd061ca --- /dev/null +++ b/Yi.Framework/Yi.Framework.Model/Class1.cs @@ -0,0 +1,8 @@ +using System; + +namespace Yi.Framework.Model +{ + public class Class1 + { + } +} diff --git a/Yi.Framework/Yi.Framework.Model/Yi.Framework.Model.csproj b/Yi.Framework/Yi.Framework.Model/Yi.Framework.Model.csproj new file mode 100644 index 00000000..f208d303 --- /dev/null +++ b/Yi.Framework/Yi.Framework.Model/Yi.Framework.Model.csproj @@ -0,0 +1,7 @@ + + + + net5.0 + + + diff --git a/Yi.Framework/Yi.Framework.Service/Class1.cs b/Yi.Framework/Yi.Framework.Service/Class1.cs new file mode 100644 index 00000000..f83e1bec --- /dev/null +++ b/Yi.Framework/Yi.Framework.Service/Class1.cs @@ -0,0 +1,8 @@ +using System; + +namespace Yi.Framework.Service +{ + public class Class1 + { + } +} diff --git a/Yi.Framework/Yi.Framework.Service/Yi.Framework.Service.csproj b/Yi.Framework/Yi.Framework.Service/Yi.Framework.Service.csproj new file mode 100644 index 00000000..f208d303 --- /dev/null +++ b/Yi.Framework/Yi.Framework.Service/Yi.Framework.Service.csproj @@ -0,0 +1,7 @@ + + + + net5.0 + + + diff --git a/Yi.Framework/Yi.Framework.WebCore/Class1.cs b/Yi.Framework/Yi.Framework.WebCore/Class1.cs new file mode 100644 index 00000000..d0f3a77f --- /dev/null +++ b/Yi.Framework/Yi.Framework.WebCore/Class1.cs @@ -0,0 +1,8 @@ +using System; + +namespace Yi.Framework.WebCore +{ + public class Class1 + { + } +} diff --git a/Yi.Framework/Yi.Framework.WebCore/CommonExtend.cs b/Yi.Framework/Yi.Framework.WebCore/CommonExtend.cs new file mode 100644 index 00000000..a6a4712e --- /dev/null +++ b/Yi.Framework/Yi.Framework.WebCore/CommonExtend.cs @@ -0,0 +1,36 @@ +using CC.ElectronicCommerce.Model; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Text; +using System.Threading.Tasks; + +namespace CC.ElectronicCommerce.WebCore +{ + public static class CommonExtend + { + public static bool IsAjaxRequest(this HttpRequest request) + { + string header = request.Headers["X-Requested-With"]; + return "XMLHttpRequest".Equals(header); + } + + /// + /// 基于HttpContext,当前鉴权方式解析,获取用户信息 + /// + /// + /// + public static UserInfo GetCurrentUserInfo(this HttpContext httpContext) + { + IEnumerable claimlist = httpContext.AuthenticateAsync().Result.Principal.Claims; + return new UserInfo() + { + id = long.Parse(claimlist.FirstOrDefault(u => u.Type == "id").Value), + username = claimlist.FirstOrDefault(u => u.Type == "username").Value ?? "匿名" + }; + } + } +} diff --git a/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CORSFilter.cs b/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CORSFilter.cs new file mode 100644 index 00000000..366cfbaa --- /dev/null +++ b/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CORSFilter.cs @@ -0,0 +1,18 @@ +//using Microsoft.AspNetCore.Mvc.Filters; +//using System; +//using System.Collections.Generic; +//using System.Linq; +//using System.Threading.Tasks; + +//namespace Zhaoxi.AgileFramework.WebCore.FilterExtend +//{ +// public class CORSFilter : ActionFilterAttribute +// { +// public override void OnActionExecuting(ActionExecutingContext context) +// { +// context.HttpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*"); +// context.HttpContext.Response.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE,PUT"); +// context.HttpContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true"); +// } +// } +//} diff --git a/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomAction2CommitFilterAttribute.cs b/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomAction2CommitFilterAttribute.cs new file mode 100644 index 00000000..247108b2 --- /dev/null +++ b/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomAction2CommitFilterAttribute.cs @@ -0,0 +1,78 @@ +using CC.ElectronicCommerce.Common.Models; +using CC.ElectronicCommerce.Core; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace CC.ElectronicCommerce.WebCore.FilterExtend +{ + public class CustomAction2CommitFilterAttribute : ActionFilterAttribute + { + #region Identity + private readonly ILogger _logger; + private readonly CacheClientDB _cacheClientDB; + private static string KeyPrefix = "2CommitFilter"; + + public CustomAction2CommitFilterAttribute(ILogger logger, CacheClientDB cacheClientDB) + { + this._logger = logger; + this._cacheClientDB = cacheClientDB; + } + #endregion + + /// + /// 防重复提交周期 单位秒 + /// + public int TimeOut = 3; + + public override void OnActionExecuting(ActionExecutingContext context) + { + string url = context.HttpContext.Request.Path.Value; + string argument = JsonConvert.SerializeObject(context.ActionArguments); + string ip = context.HttpContext.Connection.RemoteIpAddress.ToString(); + string agent = context.HttpContext.Request.Headers["User-Agent"]; + string sInfo = $"{url}-{argument}-{ip}-{agent}"; + string summary = MD5Helper.MD5EncodingOnly(sInfo); + + string totalKey = $"{KeyPrefix}-{summary}"; + + string result = this._cacheClientDB.Get(totalKey); + if (string.IsNullOrEmpty(result)) + { + this._cacheClientDB.Add(totalKey, "1", TimeSpan.FromSeconds(3));//3秒有效期 + this._logger.LogInformation($"CustomAction2CommitFilterAttribute:{sInfo}"); + } + else + { + //已存在 + this._logger.LogWarning($"CustomAction2CommitFilterAttribute重复请求:{sInfo}"); + context.Result = new JsonResult(Result.Error("请勿重复提交")); + } + + //CurrentUser currentUser = context.HttpContext.GetCurrentUserBySession(); + //if (currentUser == null) + //{ + // //if (this.IsAjaxRequest(context.HttpContext.Request)) + // //{ } + // context.Result = new RedirectResult("~/Fourth/Login"); + //} + //else + //{ + // this._logger.LogDebug($"{currentUser.Name} 访问系统"); + //} + } + private bool IsAjaxRequest(HttpRequest request) + { + string header = request.Headers["X-Requested-With"]; + return "XMLHttpRequest".Equals(header); + } + } +} diff --git a/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomActionCacheFilterAttribute.cs b/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomActionCacheFilterAttribute.cs new file mode 100644 index 00000000..3a41fead --- /dev/null +++ b/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomActionCacheFilterAttribute.cs @@ -0,0 +1,30 @@ +//using Microsoft.AspNetCore.Mvc.Filters; +//using System; +//using System.Collections.Generic; +//using System.Linq; +//using System.Threading.Tasks; + +//namespace Zhaoxi.AgileFramework.WebCore.FilterExtend +//{ +// public class CustomActionCacheFilterAttribute : ActionFilterAttribute +// { +// public override void OnActionExecuted(ActionExecutedContext context) +// { +// context.HttpContext.Response.Headers.Add("Cache-Control", "public,max-age=6000"); +// Console.WriteLine($"This {nameof(CustomActionCacheFilterAttribute)} OnActionExecuted{this.Order}"); +// } +// public override void OnActionExecuting(ActionExecutingContext context) +// { +// Console.WriteLine($"This {nameof(CustomActionCacheFilterAttribute)} OnActionExecuting{this.Order}"); +// } +// public override void OnResultExecuting(ResultExecutingContext context) +// { +// Console.WriteLine($"This {nameof(CustomActionCacheFilterAttribute)} OnResultExecuting{this.Order}"); +// } +// public override void OnResultExecuted(ResultExecutedContext context) +// { +// Console.WriteLine($"This {nameof(CustomActionCacheFilterAttribute)} OnResultExecuted{this.Order}"); +// } +// } + +//} diff --git a/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomActionCheckFilterAttribute.cs b/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomActionCheckFilterAttribute.cs new file mode 100644 index 00000000..05883fe9 --- /dev/null +++ b/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomActionCheckFilterAttribute.cs @@ -0,0 +1,45 @@ +//using Microsoft.AspNetCore.Http; +//using Microsoft.AspNetCore.Mvc; +//using Microsoft.AspNetCore.Mvc.Filters; +//using Microsoft.AspNetCore.Mvc.ModelBinding; +//using Microsoft.AspNetCore.Mvc.ViewFeatures; +//using Microsoft.Extensions.Logging; +//using System; +//using System.Collections.Generic; +//using System.Linq; +//using System.Threading.Tasks; + +//namespace Zhaoxi.AgileFramework.WebCore.FilterExtend +//{ +// public class CustomActionCheckFilterAttribute : ActionFilterAttribute +// { +// #region Identity +// private readonly ILogger _logger; +// private readonly IModelMetadataProvider _modelMetadataProvider; +// public CustomActionCheckFilterAttribute(ILogger logger) +// { +// this._logger = logger; +// } +// #endregion + +// public override void OnActionExecuting(ActionExecutingContext context) +// { +// //CurrentUser currentUser = context.HttpContext.GetCurrentUserBySession(); +// //if (currentUser == null) +// //{ +// // //if (this.IsAjaxRequest(context.HttpContext.Request)) +// // //{ } +// // context.Result = new RedirectResult("~/Fourth/Login"); +// //} +// //else +// //{ +// // this._logger.LogDebug($"{currentUser.Name} 访问系统"); +// //} +// } +// private bool IsAjaxRequest(HttpRequest request) +// { +// string header = request.Headers["X-Requested-With"]; +// return "XMLHttpRequest".Equals(header); +// } +// } +//} diff --git a/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomExceptionFilterAttribute.cs b/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomExceptionFilterAttribute.cs new file mode 100644 index 00000000..748d454a --- /dev/null +++ b/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomExceptionFilterAttribute.cs @@ -0,0 +1,41 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using CC.ElectronicCommerce.Common.Models; + +namespace CC.ElectronicCommerce.WebCore.FilterExtend +{ + public class CustomExceptionFilterAttribute : IExceptionFilter + { + private ILogger _logger = null; + public CustomExceptionFilterAttribute(ILogger logger) + { + this._logger = logger; + } + + public void OnException(ExceptionContext context) + { + if (context.ExceptionHandled == false) + { + context.Result = new JsonResult( + Result.Error("操作失败").SetData(context.Exception.Message)); + string url = context.HttpContext.Request.Path.Value; + string actionName = context.ActionDescriptor.DisplayName; + + var logModel = new LogModel() + { + OriginalClassName = "", + OriginalMethodName = actionName, + Remark = $"来源于{nameof(CustomExceptionFilterAttribute)}.{nameof(OnException)}" + }; + this._logger.LogError(context.Exception, $"{url}----->actionName={actionName} Message={context.Exception.Message}", JsonConvert.SerializeObject(logModel)); + } + context.ExceptionHandled = true; + } + } +} diff --git a/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomIOCFilterFactoryAttribute.cs b/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomIOCFilterFactoryAttribute.cs new file mode 100644 index 00000000..c632c220 --- /dev/null +++ b/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomIOCFilterFactoryAttribute.cs @@ -0,0 +1,31 @@ +//using Microsoft.AspNetCore.Mvc.Filters; +//using System; +//using System.Collections.Generic; +//using System.Linq; +//using System.Threading.Tasks; + +//namespace Zhaoxi.AgileFramework.WebCore.FilterExtend +//{ +// /// +// /// 基于完成Filter的依赖注入 +// /// +// public class CustomIOCFilterFactoryAttribute : Attribute, IFilterFactory +// { +// private readonly Type _FilterType = null; + +// public CustomIOCFilterFactoryAttribute(Type type) +// { +// this._FilterType = type; +// } +// public bool IsReusable => true; + +// public IFilterMetadata CreateInstance(IServiceProvider serviceProvider) +// { +// //return (IFilterMetadata)serviceProvider.GetService(typeof(CustomExceptionFilterAttribute)); + +// return (IFilterMetadata)serviceProvider.GetService(this._FilterType); +// } +// } + + +//} diff --git a/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomResourceFilterAttribute.cs b/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomResourceFilterAttribute.cs new file mode 100644 index 00000000..1c27eb5e --- /dev/null +++ b/Yi.Framework/Yi.Framework.WebCore/FilterExtend/CustomResourceFilterAttribute.cs @@ -0,0 +1,45 @@ +//using Microsoft.AspNetCore.Mvc; +//using Microsoft.AspNetCore.Mvc.Filters; +//using System; +//using System.Collections.Generic; +//using System.Linq; +//using System.Threading.Tasks; + +//namespace Zhaoxi.AgileFramework.WebCore.FilterExtend +//{ +// /// +// /// +// /// +// public class CustomResourceFilterAttribute : Attribute, IResourceFilter, IFilterMetadata +// { +// private static Dictionary CustomCache = new Dictionary(); +// /// +// /// 发生在其他动作之前 +// /// +// /// +// public void OnResourceExecuting(ResourceExecutingContext context) +// { +// Console.WriteLine($"This is {nameof(CustomResourceFilterAttribute) }OnResourceExecuting"); +// //if 有缓存,直接返回缓存 +// string key = context.HttpContext.Request.Path; +// if (CustomCache.ContainsKey(key)) +// { +// context.Result = CustomCache[key];//断路器--到Result生成了,但是Result还需要转换成Html +// } +// } +// /// +// /// 发生在其他动作之后 +// /// +// /// +// public void OnResourceExecuted(ResourceExecutedContext context) +// { +// Console.WriteLine($"This is {nameof(CustomResourceFilterAttribute) }OnResourceExecuted"); +// //这个应该缓存起来 +// string key = context.HttpContext.Request.Path; +// if (!CustomCache.ContainsKey(key)) +// { +// CustomCache.Add(key, context.Result); +// } +// } +// } +//} diff --git a/Yi.Framework/Yi.Framework.WebCore/FilterExtend/LogActionFilterAttribute.cs b/Yi.Framework/Yi.Framework.WebCore/FilterExtend/LogActionFilterAttribute.cs new file mode 100644 index 00000000..c44e0186 --- /dev/null +++ b/Yi.Framework/Yi.Framework.WebCore/FilterExtend/LogActionFilterAttribute.cs @@ -0,0 +1,80 @@ +using CC.ElectronicCommerce.Common.Models; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace CC.ElectronicCommerce.WebCore.FilterExtend +{ + public class LogActionFilterAttribute : ActionFilterAttribute + { + private ILogger _logger = null; + public LogActionFilterAttribute(ILogger logger) + { + this._logger = logger; + } + + public override void OnActionExecuting(ActionExecutingContext context) + { + string url = context.HttpContext.Request.Path.Value; + string argument = JsonConvert.SerializeObject(context.ActionArguments); + + string controllerName = context.Controller.GetType().FullName; + string actionName = context.ActionDescriptor.DisplayName; + + LogModel logModel = new LogModel() + { + OriginalClassName = controllerName, + OriginalMethodName = actionName, + Remark = $"来源于{nameof(LogActionFilterAttribute)}.{nameof(OnActionExecuting)}" + }; + + //this._logger.LogInformation($"url={url}---argument={argument}",new object[] { JsonConvert.SerializeObject(logModel) } ); + this._logger.LogInformation($"url={url}---argument={argument}"); + } + } + + public class CustomActionFilterAttribute : ActionFilterAttribute + { + public override void OnActionExecuted(ActionExecutedContext context) + { + Console.WriteLine($"This {nameof(LogActionFilterAttribute)} OnActionExecuted{this.Order}"); + } + public override void OnActionExecuting(ActionExecutingContext context) + { + Console.WriteLine($"This {nameof(LogActionFilterAttribute)} OnActionExecuting{this.Order}"); + } + public override void OnResultExecuting(ResultExecutingContext context) + { + Console.WriteLine($"This {nameof(LogActionFilterAttribute)} OnResultExecuting{this.Order}"); + } + public override void OnResultExecuted(ResultExecutedContext context) + { + Console.WriteLine($"This {nameof(LogActionFilterAttribute)} OnResultExecuted{this.Order}"); + } + } + + public class CustomControllerFilterAttribute : ActionFilterAttribute + { + public override void OnActionExecuted(ActionExecutedContext context) + { + Console.WriteLine($"This {nameof(CustomControllerFilterAttribute)} OnActionExecuted {this.Order}"); + } + public override void OnActionExecuting(ActionExecutingContext context) + { + Console.WriteLine($"This {nameof(CustomControllerFilterAttribute)} OnActionExecuting{this.Order}"); + } + public override void OnResultExecuting(ResultExecutingContext context) + { + Console.WriteLine($"This {nameof(CustomControllerFilterAttribute)} OnResultExecuting{this.Order}"); + } + public override void OnResultExecuted(ResultExecutedContext context) + { + Console.WriteLine($"This {nameof(CustomControllerFilterAttribute)} OnResultExecuted{this.Order}"); + } + } + +} diff --git a/Yi.Framework/Yi.Framework.WebCore/MiddlewareExtend/PreOptionRequestMiddleware.cs b/Yi.Framework/Yi.Framework.WebCore/MiddlewareExtend/PreOptionRequestMiddleware.cs new file mode 100644 index 00000000..2a59d52c --- /dev/null +++ b/Yi.Framework/Yi.Framework.WebCore/MiddlewareExtend/PreOptionRequestMiddleware.cs @@ -0,0 +1,49 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace CC.ElectronicCommerce.WebCore.MiddlewareExtend +{ + /// + /// Axios会触发,需要做个状态返回,还需要指定跨域信息,这里放在网关了 + /// + /// OPTIONS请求即预检请求,可用于检测服务器允许的http方法。当发起跨域请求时,由于安全原因,触发一定条件时浏览器会在正式请求之前自动先发起OPTIONS请求,即CORS预检请求,服务器若接受该跨域请求,浏览器才继续发起正式请求。 + /// + public class PreOptionRequestMiddleware + { + private readonly RequestDelegate _next; + + public PreOptionRequestMiddleware(RequestDelegate next) + { + _next = next; + } + + public async Task Invoke(HttpContext context) + { + if (context.Request.Method.ToUpper() == "OPTIONS") + { + //context.Response.Headers.Add("Access-Control-Allow-Origin", "http://localhost:8070"); + //context.Response.Headers.Add("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,PATCH,OPTIONS"); + //context.Response.Headers.Add("Access-Control-Allow-Headers", "*"); + context.Response.StatusCode = 200; + return; + } + await _next.Invoke(context); + } + } + + /// + /// 扩展中间件 + /// + public static class PreOptionsRequestMiddlewareExtensions + { + public static IApplicationBuilder UsePreOptionsRequest(this IApplicationBuilder app) + { + return app.UseMiddleware(); + } + } + +} diff --git a/Yi.Framework/Yi.Framework.WebCore/MiddlewareExtend/StaticPageMiddleware.cs b/Yi.Framework/Yi.Framework.WebCore/MiddlewareExtend/StaticPageMiddleware.cs new file mode 100644 index 00000000..88bd72f7 --- /dev/null +++ b/Yi.Framework/Yi.Framework.WebCore/MiddlewareExtend/StaticPageMiddleware.cs @@ -0,0 +1,156 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CC.ElectronicCommerce.WebCore.MiddlewareExtend +{ + /// + /// 支持在返回HTML时,将返回的Stream保存到指定目录 + /// + public class StaticPageMiddleware + { + private readonly RequestDelegate _next; + private string _directoryPath = @"D:/cc-ec/"; + private bool _supportDelete = false; + private bool _supportWarmup = false; + + public StaticPageMiddleware(RequestDelegate next, string directoryPath, bool supportDelete, bool supportWarmup) + { + this._next = next; + this._directoryPath = directoryPath; + this._supportDelete = supportDelete; + this._supportWarmup = supportWarmup; + } + + public async Task InvokeAsync(HttpContext context) + { + if (this._supportDelete && "Delete".Equals(context.Request.Query["ActionHeader"])) + { + this.DeleteHmtl(context.Request.Path.Value); + context.Response.StatusCode = 200; + } + else if (this._supportWarmup && "ClearAll".Equals(context.Request.Query["ActionHeader"])) + { + this.ClearDirectory(10);//考虑数据量 + context.Response.StatusCode = 200; + } + else if (!context.Request.IsAjaxRequest()) + { + Console.WriteLine($"This is StaticPageMiddleware InvokeAsync {context.Request.Path.Value}"); + #region context.Response.Body + var originalStream = context.Response.Body; + using (var copyStream = new MemoryStream()) + { + context.Response.Body = copyStream; + await _next(context); + + copyStream.Position = 0; + var reader = new StreamReader(copyStream); + var content = await reader.ReadToEndAsync(); + string url = context.Request.Path.Value; + + this.SaveHmtl(url, content); + + copyStream.Position = 0; + await copyStream.CopyToAsync(originalStream); + context.Response.Body = originalStream; + } + #endregion + } + else + { + await _next(context); + } + } + + private void SaveHmtl(string url, string html) + { + try + { + //Console.WriteLine($"Response: {html}"); + if (string.IsNullOrWhiteSpace(html)) + return; + if (!url.EndsWith(".html")) + return; + + if (Directory.Exists(_directoryPath) == false) + Directory.CreateDirectory(_directoryPath); + + var totalPath = Path.Combine(_directoryPath, url.Split("/").Last()); + File.WriteAllText(totalPath, html);//直接覆盖 + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + /// + /// 删除某个页面 + /// + /// + /// + private void DeleteHmtl(string url) + { + try + { + if (!url.EndsWith(".html")) + return; + var totalPath = Path.Combine(_directoryPath, url.Split("/").Last()); + File.Delete(totalPath);//直接删除 + } + catch (Exception ex) + { + Console.WriteLine($"Delete {url} 异常,{ex.Message}"); + } + } + + /// + /// 清理文件,支持重试 + /// + /// 最多重试次数 + private void ClearDirectory(int index) + { + if (index > 0)//简陋版---重试index次 + { + try + { + var files = Directory.GetFiles(_directoryPath); + foreach (var file in files) + { + File.Delete(file); + } + } + catch (Exception ex) + { + Console.WriteLine($"ClearDirectory failed {ex.Message}"); + ClearDirectory(index--); + } + } + } + } + + /// + /// 扩展中间件 + /// + public static class StaticPageMiddlewareExtensions + { + /// + /// + /// + /// + /// 文件写入地址,文件夹目录 + /// 是否支持删除 + /// 是否支持全量删除 + /// + public static IApplicationBuilder UseStaticPageMiddleware(this IApplicationBuilder app, string directoryPath, bool supportDelete, bool supportClear) + { + return app.UseMiddleware(directoryPath, supportDelete, supportClear); + } + } +} \ No newline at end of file diff --git a/Yi.Framework/Yi.Framework.WebCore/Yi.Framework.WebCore.csproj b/Yi.Framework/Yi.Framework.WebCore/Yi.Framework.WebCore.csproj new file mode 100644 index 00000000..f208d303 --- /dev/null +++ b/Yi.Framework/Yi.Framework.WebCore/Yi.Framework.WebCore.csproj @@ -0,0 +1,7 @@ + + + + net5.0 + + + diff --git a/Yi.Framework/Yi.Framework.sln b/Yi.Framework/Yi.Framework.sln index 1f1b400a..16b49183 100644 --- a/Yi.Framework/Yi.Framework.sln +++ b/Yi.Framework/Yi.Framework.sln @@ -3,7 +3,31 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.31515.178 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework", "Yi.Framework\Yi.Framework.csproj", "{6CFCF22D-B8D2-4828-9550-A81CEC6E648A}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BackGround", "BackGround", "{D6B44435-EAFA-4D55-90D0-3AF80485FB83}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{C90E38FB-69EA-4997-8B3A-2C71EFA65B2B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Domain", "Domain", "{DB2506F5-05FD-4E76-940E-41D7AA148550}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Infrastructure", "Infrastructure", "{9ABAF6B1-6C02-498A-90A2-ABC1140CF89A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MicroServiceInstance", "MicroServiceInstance", "{026D2797-07D1-4BA5-8070-50CDE0258C59}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.DTOModel", "Yi.Framework.DTOModel\Yi.Framework.DTOModel.csproj", "{5B6C87F0-CEBA-4A0A-8C30-02E927AB4AEF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.Interface", "Yi.Framework.Interface\Yi.Framework.Interface.csproj", "{5935EC64-7414-47D8-B934-E5896DD89E4E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.Model", "Yi.Framework.Model\Yi.Framework.Model.csproj", "{F0EE03CF-30C9-4C48-BF32-FED6F3BCFB4C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.Service", "Yi.Framework.Service\Yi.Framework.Service.csproj", "{C5E41276-A30F-4098-BA79-2E8920BBD02A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.Common", "Yi.Framework.Common\Yi.Framework.Common.csproj", "{4816AA7B-7222-4B3B-A178-C2A70713E9D1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.Core", "Yi.Framework.Core\Yi.Framework.Core.csproj", "{07A80C17-E03E-475D-9BBF-98E3B1393652}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.WebCore", "Yi.Framework.WebCore\Yi.Framework.WebCore.csproj", "{E4734315-158C-4D35-AF01-1122C22F2955}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.ApiMicroservice", "Yi.Framework.ApiMicroservice\Yi.Framework.ApiMicroservice.csproj", "{A95157D2-907F-411E-BA1D-A17F48C54A0E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -11,14 +35,52 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6CFCF22D-B8D2-4828-9550-A81CEC6E648A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6CFCF22D-B8D2-4828-9550-A81CEC6E648A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6CFCF22D-B8D2-4828-9550-A81CEC6E648A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6CFCF22D-B8D2-4828-9550-A81CEC6E648A}.Release|Any CPU.Build.0 = Release|Any CPU + {5B6C87F0-CEBA-4A0A-8C30-02E927AB4AEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5B6C87F0-CEBA-4A0A-8C30-02E927AB4AEF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B6C87F0-CEBA-4A0A-8C30-02E927AB4AEF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5B6C87F0-CEBA-4A0A-8C30-02E927AB4AEF}.Release|Any CPU.Build.0 = Release|Any CPU + {5935EC64-7414-47D8-B934-E5896DD89E4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5935EC64-7414-47D8-B934-E5896DD89E4E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5935EC64-7414-47D8-B934-E5896DD89E4E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5935EC64-7414-47D8-B934-E5896DD89E4E}.Release|Any CPU.Build.0 = Release|Any CPU + {F0EE03CF-30C9-4C48-BF32-FED6F3BCFB4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F0EE03CF-30C9-4C48-BF32-FED6F3BCFB4C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F0EE03CF-30C9-4C48-BF32-FED6F3BCFB4C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F0EE03CF-30C9-4C48-BF32-FED6F3BCFB4C}.Release|Any CPU.Build.0 = Release|Any CPU + {C5E41276-A30F-4098-BA79-2E8920BBD02A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C5E41276-A30F-4098-BA79-2E8920BBD02A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C5E41276-A30F-4098-BA79-2E8920BBD02A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C5E41276-A30F-4098-BA79-2E8920BBD02A}.Release|Any CPU.Build.0 = Release|Any CPU + {4816AA7B-7222-4B3B-A178-C2A70713E9D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4816AA7B-7222-4B3B-A178-C2A70713E9D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4816AA7B-7222-4B3B-A178-C2A70713E9D1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4816AA7B-7222-4B3B-A178-C2A70713E9D1}.Release|Any CPU.Build.0 = Release|Any CPU + {07A80C17-E03E-475D-9BBF-98E3B1393652}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {07A80C17-E03E-475D-9BBF-98E3B1393652}.Debug|Any CPU.Build.0 = Debug|Any CPU + {07A80C17-E03E-475D-9BBF-98E3B1393652}.Release|Any CPU.ActiveCfg = Release|Any CPU + {07A80C17-E03E-475D-9BBF-98E3B1393652}.Release|Any CPU.Build.0 = Release|Any CPU + {E4734315-158C-4D35-AF01-1122C22F2955}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E4734315-158C-4D35-AF01-1122C22F2955}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E4734315-158C-4D35-AF01-1122C22F2955}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E4734315-158C-4D35-AF01-1122C22F2955}.Release|Any CPU.Build.0 = Release|Any CPU + {A95157D2-907F-411E-BA1D-A17F48C54A0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A95157D2-907F-411E-BA1D-A17F48C54A0E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A95157D2-907F-411E-BA1D-A17F48C54A0E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A95157D2-907F-411E-BA1D-A17F48C54A0E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {5B6C87F0-CEBA-4A0A-8C30-02E927AB4AEF} = {DB2506F5-05FD-4E76-940E-41D7AA148550} + {5935EC64-7414-47D8-B934-E5896DD89E4E} = {DB2506F5-05FD-4E76-940E-41D7AA148550} + {F0EE03CF-30C9-4C48-BF32-FED6F3BCFB4C} = {DB2506F5-05FD-4E76-940E-41D7AA148550} + {C5E41276-A30F-4098-BA79-2E8920BBD02A} = {DB2506F5-05FD-4E76-940E-41D7AA148550} + {4816AA7B-7222-4B3B-A178-C2A70713E9D1} = {9ABAF6B1-6C02-498A-90A2-ABC1140CF89A} + {07A80C17-E03E-475D-9BBF-98E3B1393652} = {9ABAF6B1-6C02-498A-90A2-ABC1140CF89A} + {E4734315-158C-4D35-AF01-1122C22F2955} = {9ABAF6B1-6C02-498A-90A2-ABC1140CF89A} + {A95157D2-907F-411E-BA1D-A17F48C54A0E} = {026D2797-07D1-4BA5-8070-50CDE0258C59} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {1ED77A6E-377F-4EEF-A3D0-D65C94657DAF} EndGlobalSection