框架分层
This commit is contained in:
@@ -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]")]
|
||||
@@ -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
|
||||
{
|
||||
@@ -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,
|
||||
@@ -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();
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Yi.Framework
|
||||
namespace Yi.Framework.ApiMicroservice
|
||||
{
|
||||
public class WeatherForecast
|
||||
{
|
||||
8
Yi.Framework/Yi.Framework.Common/Class1.cs
Normal file
8
Yi.Framework/Yi.Framework.Common/Class1.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace Yi.Framework.Common
|
||||
{
|
||||
public class Class1
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Yi.Framework/Yi.Framework.Common/IOCOptions/KafkaOptions.cs
Normal file
15
Yi.Framework/Yi.Framework.Common/IOCOptions/KafkaOptions.cs
Normal file
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace Yi.Framework.Common.IOCOptions
|
||||
{
|
||||
public class MySqlConnOptions
|
||||
{
|
||||
public string Url { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
///// <summary>
|
||||
///// exchange---queue
|
||||
///// </summary>
|
||||
//private static Dictionary<string, string> RabbitMQ_Mapping = new Dictionary<string, string>();
|
||||
//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
|
||||
{
|
||||
/// <summary>
|
||||
/// 生产者指定,交换机
|
||||
/// </summary>
|
||||
public string ExchangeName { get; set; }
|
||||
/// <summary>
|
||||
/// 自己起的名字
|
||||
/// </summary>
|
||||
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";
|
||||
|
||||
/// <summary>
|
||||
/// 订单创建后的交换机
|
||||
/// </summary>
|
||||
public static readonly string OrderCreate_Exchange = "Zhaoxi.MSACormmerce.OrderCreate.Exchange";
|
||||
public static readonly string OrderCreate_Queue_CleanCart = "Zhaoxi.MSACormmerce.OrderCreate.Queue.CleanCart";
|
||||
|
||||
/// <summary>
|
||||
/// 订单创建后的交换机,支付状态的
|
||||
/// </summary>
|
||||
public static readonly string OrderPay_Exchange = "Zhaoxi.MSACormmerce.OrderPay.Exchange";
|
||||
public static readonly string OrderPay_Queue_RefreshPay = "Zhaoxi.MSACormmerce.OrderPay.Queue.RefreshPay";
|
||||
|
||||
/// <summary>
|
||||
/// 创建订单后的延时队列配置
|
||||
/// </summary>
|
||||
public static readonly string OrderCreate_Delay_Exchange = "Zhaoxi.MSACormmerce.OrderCreate.DelayExchange";
|
||||
public static readonly string OrderCreate_Delay_Queue_CancelOrder = "Zhaoxi.MSACormmerce.OrderCreate.DelayQueue.CancelOrder";
|
||||
|
||||
/// <summary>
|
||||
/// 秒杀异步的
|
||||
/// </summary>
|
||||
public static readonly string Seckill_Exchange = "Zhaoxi.MSACormmerce.Seckill.Exchange";
|
||||
public static readonly string Seckill_Order_Queue = "Zhaoxi.MSACormmerce.Seckill.Order.Queue";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// CAP队列名称
|
||||
/// </summary>
|
||||
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";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
18
Yi.Framework/Yi.Framework.Common/Models/LogModel.cs
Normal file
18
Yi.Framework/Yi.Framework.Common/Models/LogModel.cs
Normal file
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 写入分布式日志需要的字段
|
||||
/// </summary>
|
||||
public class LogModel
|
||||
{
|
||||
public string OriginalClassName { get; set; }
|
||||
public string OriginalMethodName { get; set; }
|
||||
public string Remark { get; set; }
|
||||
}
|
||||
}
|
||||
66
Yi.Framework/Yi.Framework.Common/Models/Result.cs
Normal file
66
Yi.Framework/Yi.Framework.Common/Models/Result.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Yi.Framework.Common.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// 结果数据
|
||||
/// </summary>
|
||||
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<T>
|
||||
{
|
||||
public bool status { get; set; }
|
||||
public int code { get; set; }
|
||||
public string msg { get; set; }
|
||||
public T data { get; set; }
|
||||
|
||||
public static Result<T> Instance(bool status, string msg)
|
||||
{
|
||||
return new Result<T>() { status = status, code = 500, msg = msg };
|
||||
}
|
||||
public static Result<T> Error(string msg = "fail")
|
||||
{
|
||||
return new Result<T> { status = false, code = 500, msg = msg };
|
||||
}
|
||||
public static Result<T> Success(string msg = "succeed")
|
||||
{
|
||||
return new Result<T> { status = true, code = 200, msg = msg };
|
||||
}
|
||||
public Result<T> SetData(T TValue)
|
||||
{
|
||||
this.data = TValue;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
1074
Yi.Framework/Yi.Framework.Core/CacheClientDB.cs
Normal file
1074
Yi.Framework/Yi.Framework.Core/CacheClientDB.cs
Normal file
File diff suppressed because it is too large
Load Diff
8
Yi.Framework/Yi.Framework.Core/Class1.cs
Normal file
8
Yi.Framework/Yi.Framework.Core/Class1.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace Yi.Framework.Core
|
||||
{
|
||||
public class Class1
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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<string, AgentService>[] _CurrentAgentServiceDictionary = null;
|
||||
|
||||
public AbstractConsulDispatcher(IOptionsMonitor<ConsulClientOption> consulClientOption)
|
||||
{
|
||||
this._ConsulClientOption = consulClientOption.CurrentValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 负载均衡获取地址
|
||||
/// </summary>
|
||||
/// <param name="mappingUrl">Consul映射后的地址</param>
|
||||
/// <returns></returns>
|
||||
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<KeyValuePair<string, AgentService>> serviceList = new List<KeyValuePair<string, AgentService>>();
|
||||
for (int i = 0; i < entrys.Length; i++)
|
||||
{
|
||||
serviceList.Add(new KeyValuePair<string, AgentService>(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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 平均
|
||||
/// </summary>
|
||||
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> consulClientOption) : base(consulClientOption)
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 平均
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override int GetIndex()
|
||||
{
|
||||
return new Random(iTotalCount++).Next(0, base._CurrentAgentServiceDictionary.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 轮询
|
||||
/// </summary>
|
||||
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> consulClientOption) : base(consulClientOption)
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 轮询
|
||||
/// </summary>
|
||||
/// <param name="serviceCount"></param>
|
||||
/// <returns></returns>
|
||||
protected override int GetIndex()
|
||||
{
|
||||
return iTotalCount++ % base._CurrentAgentServiceDictionary.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 权重
|
||||
/// </summary>
|
||||
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> 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<AgentService>();
|
||||
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}";
|
||||
}
|
||||
/// <summary>
|
||||
/// 不需要了
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override int GetIndex()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CC.ElectronicCommerce.Core.ConsulExtend
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用Consul时需要配置
|
||||
/// </summary>
|
||||
public class ConsulClientOption
|
||||
{
|
||||
public string IP { get; set; }
|
||||
public int Port { get; set; }
|
||||
public string Datacenter { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务自身IP
|
||||
/// </summary>
|
||||
public string IP { get; set; }
|
||||
/// <summary>
|
||||
/// 服务自身Port
|
||||
/// </summary>
|
||||
public int Port { get; set; }
|
||||
/// <summary>
|
||||
/// 组名称
|
||||
/// </summary>
|
||||
public string GroupName { get; set; }
|
||||
/// <summary>
|
||||
/// 心跳检查地址
|
||||
/// </summary>
|
||||
public string HealthCheckUrl { get; set; }
|
||||
/// <summary>
|
||||
/// 心跳频率
|
||||
/// </summary>
|
||||
public int Interval { get; set; }
|
||||
/// <summary>
|
||||
/// 心跳超时
|
||||
/// </summary>
|
||||
public int Timeout { get; set; }
|
||||
/// <summary>
|
||||
/// 移除延迟时间
|
||||
/// </summary>
|
||||
public int DeregisterCriticalServiceAfter { get; set; }
|
||||
/// <summary>
|
||||
/// 标签,额外信息,用于权重
|
||||
/// </summary>
|
||||
public string Tag { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// HTTP模式
|
||||
/// </summary>
|
||||
public static class ConsulRegiterExtend
|
||||
{
|
||||
/// <summary>
|
||||
/// 自动读取配置文件完成注册
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
/// <param name="configuration"></param>
|
||||
/// <returns></returns>
|
||||
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);
|
||||
}
|
||||
/// <summary>
|
||||
/// 基于提供信息完成注册
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
/// <param name="healthService"></param>
|
||||
/// <returns></returns>
|
||||
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)} 完成注册");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 设置心跳响应
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
/// <param name="checkPath">默认是/Health</param>
|
||||
/// <returns></returns>
|
||||
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");
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Binary file not shown.
BIN
Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Common.dll
Normal file
BIN
Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Common.dll
Normal file
Binary file not shown.
Binary file not shown.
BIN
Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Redis.dll
Normal file
BIN
Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Redis.dll
Normal file
Binary file not shown.
BIN
Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Text.dll
Normal file
BIN
Yi.Framework/Yi.Framework.Core/Library/ServiceStack.Text.dll
Normal file
Binary file not shown.
47
Yi.Framework/Yi.Framework.Core/MD5Helper.cs
Normal file
47
Yi.Framework/Yi.Framework.Core/MD5Helper.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace CC.ElectronicCommerce.Core
|
||||
|
||||
{
|
||||
/// <summary>
|
||||
/// 加密用的
|
||||
/// </summary>
|
||||
public class MD5Helper
|
||||
{
|
||||
/// <summary>
|
||||
/// MD5 加密字符串
|
||||
/// </summary>
|
||||
/// <param name="content">源字符串</param>
|
||||
/// <returns>加密后字符串</returns>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MD5盐值加密
|
||||
/// </summary>
|
||||
/// <param name="content">源字符串</param>
|
||||
/// <param name="salt">盐值</param>
|
||||
/// <returns>加密后字符串</returns>
|
||||
public static string MD5EncodingWithSalt(string content, string salt)
|
||||
{
|
||||
if (salt == null) return content;
|
||||
return MD5EncodingOnly(content + "{" + salt.ToString() + "}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
253
Yi.Framework/Yi.Framework.Core/RabbitMQInvoker.cs
Normal file
253
Yi.Framework/Yi.Framework.Core/RabbitMQInvoker.cs
Normal file
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 一个Exchange----多个Queue-----弄个缓存映射关系,初始化+支持全新绑定
|
||||
/// 全局单例使用
|
||||
///
|
||||
/// 关系应该是直接配置到RabbitMQ了---程序只是向某个位置写入即可
|
||||
///
|
||||
///
|
||||
/// 全量更新--耗时---阻塞实时更新---换不同的exchange?
|
||||
/// </summary>
|
||||
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<RabbitMQOptions> 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<string, bool> RabbitMQInvoker_ExchangeQueue = new Dictionary<string, bool>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 必须先声明exchange--检查+初始化
|
||||
/// </summary>
|
||||
/// <param name="rabbitMQConsumerModel"></param>
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// 只管exchange---
|
||||
/// 4种路由类型?
|
||||
///
|
||||
/// Send前完成交换机初始化
|
||||
/// </summary>
|
||||
/// <param name="exchangeName"></param>
|
||||
/// <param name="message">建议Json格式</param>
|
||||
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(); //事务回滚--前面的所有操作就全部作废了。。。。
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 固定无消费队列名字---转移到目标队列---定好时间
|
||||
/// </summary>
|
||||
/// <param name="targetExchangeName"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="delaySecond"></param>
|
||||
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<string, object> args = new Dictionary<string, object>();
|
||||
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
|
||||
/// <summary>
|
||||
/// 注册处理动作
|
||||
/// </summary>
|
||||
/// <param name="rabbitMQConsumerMode"></param>
|
||||
/// <param name="func"></param>
|
||||
public void RegistReciveAction(RabbitMQConsumerModel rabbitMQConsumerMode, Func<string, bool> 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
|
||||
|
||||
}
|
||||
}
|
||||
99
Yi.Framework/Yi.Framework.Core/SnowflakeHelper.cs
Normal file
99
Yi.Framework/Yi.Framework.Core/SnowflakeHelper.cs
Normal file
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 机器码
|
||||
/// </summary>
|
||||
/// <param name="workerId"></param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取下一微秒时间戳
|
||||
/// </summary>
|
||||
/// <param name="lastTimestamp"></param>
|
||||
/// <returns></returns>
|
||||
private long TillNextMillis(long lastTimestamp)
|
||||
{
|
||||
long timestamp = TimeGen();
|
||||
while (timestamp <= lastTimestamp)
|
||||
{
|
||||
timestamp = TimeGen();
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成当前时间戳
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private long TimeGen()
|
||||
{
|
||||
return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
7
Yi.Framework/Yi.Framework.Core/Yi.Framework.Core.csproj
Normal file
7
Yi.Framework/Yi.Framework.Core/Yi.Framework.Core.csproj
Normal file
@@ -0,0 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
8
Yi.Framework/Yi.Framework.DTOModel/Class1.cs
Normal file
8
Yi.Framework/Yi.Framework.DTOModel/Class1.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace Yi.Framework.DTOModel
|
||||
{
|
||||
public class Class1
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
8
Yi.Framework/Yi.Framework.Interface/Class1.cs
Normal file
8
Yi.Framework/Yi.Framework.Interface/Class1.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace Yi.Framework.Interface
|
||||
{
|
||||
public class Class1
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
8
Yi.Framework/Yi.Framework.Model/Class1.cs
Normal file
8
Yi.Framework/Yi.Framework.Model/Class1.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace Yi.Framework.Model
|
||||
{
|
||||
public class Class1
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
8
Yi.Framework/Yi.Framework.Service/Class1.cs
Normal file
8
Yi.Framework/Yi.Framework.Service/Class1.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace Yi.Framework.Service
|
||||
{
|
||||
public class Class1
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
8
Yi.Framework/Yi.Framework.WebCore/Class1.cs
Normal file
8
Yi.Framework/Yi.Framework.WebCore/Class1.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace Yi.Framework.WebCore
|
||||
{
|
||||
public class Class1
|
||||
{
|
||||
}
|
||||
}
|
||||
36
Yi.Framework/Yi.Framework.WebCore/CommonExtend.cs
Normal file
36
Yi.Framework/Yi.Framework.WebCore/CommonExtend.cs
Normal file
@@ -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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 基于HttpContext,当前鉴权方式解析,获取用户信息
|
||||
/// </summary>
|
||||
/// <param name="httpContext"></param>
|
||||
/// <returns></returns>
|
||||
public static UserInfo GetCurrentUserInfo(this HttpContext httpContext)
|
||||
{
|
||||
IEnumerable<Claim> 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 ?? "匿名"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Yi.Framework/Yi.Framework.WebCore/FilterExtend/CORSFilter.cs
Normal file
18
Yi.Framework/Yi.Framework.WebCore/FilterExtend/CORSFilter.cs
Normal file
@@ -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");
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -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<CustomAction2CommitFilterAttribute> _logger;
|
||||
private readonly CacheClientDB _cacheClientDB;
|
||||
private static string KeyPrefix = "2CommitFilter";
|
||||
|
||||
public CustomAction2CommitFilterAttribute(ILogger<CustomAction2CommitFilterAttribute> logger, CacheClientDB cacheClientDB)
|
||||
{
|
||||
this._logger = logger;
|
||||
this._cacheClientDB = cacheClientDB;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 防重复提交周期 单位秒
|
||||
/// </summary>
|
||||
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<string>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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}");
|
||||
// }
|
||||
// }
|
||||
|
||||
//}
|
||||
@@ -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<CustomActionCheckFilterAttribute> _logger;
|
||||
// private readonly IModelMetadataProvider _modelMetadataProvider;
|
||||
// public CustomActionCheckFilterAttribute(ILogger<CustomActionCheckFilterAttribute> 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);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -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<CustomExceptionFilterAttribute> _logger = null;
|
||||
public CustomExceptionFilterAttribute(ILogger<CustomExceptionFilterAttribute> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
//{
|
||||
// /// <summary>
|
||||
// /// 基于完成Filter的依赖注入
|
||||
// /// </summary>
|
||||
// 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);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
//}
|
||||
@@ -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
|
||||
//{
|
||||
// /// <summary>
|
||||
// ///
|
||||
// /// </summary>
|
||||
// public class CustomResourceFilterAttribute : Attribute, IResourceFilter, IFilterMetadata
|
||||
// {
|
||||
// private static Dictionary<string, IActionResult> CustomCache = new Dictionary<string, IActionResult>();
|
||||
// /// <summary>
|
||||
// /// 发生在其他动作之前
|
||||
// /// </summary>
|
||||
// /// <param name="context"></param>
|
||||
// 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
|
||||
// }
|
||||
// }
|
||||
// /// <summary>
|
||||
// /// 发生在其他动作之后
|
||||
// /// </summary>
|
||||
// /// <param name="context"></param>
|
||||
// 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);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -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<LogActionFilterAttribute> _logger = null;
|
||||
public LogActionFilterAttribute(ILogger<LogActionFilterAttribute> 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}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Axios会触发,需要做个状态返回,还需要指定跨域信息,这里放在网关了
|
||||
///
|
||||
/// OPTIONS请求即预检请求,可用于检测服务器允许的http方法。当发起跨域请求时,由于安全原因,触发一定条件时浏览器会在正式请求之前自动先发起OPTIONS请求,即CORS预检请求,服务器若接受该跨域请求,浏览器才继续发起正式请求。
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 扩展中间件
|
||||
/// </summary>
|
||||
public static class PreOptionsRequestMiddlewareExtensions
|
||||
{
|
||||
public static IApplicationBuilder UsePreOptionsRequest(this IApplicationBuilder app)
|
||||
{
|
||||
return app.UseMiddleware<PreOptionRequestMiddleware>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 支持在返回HTML时,将返回的Stream保存到指定目录
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除某个页面
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="index"></param>
|
||||
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}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理文件,支持重试
|
||||
/// </summary>
|
||||
/// <param name="index">最多重试次数</param>
|
||||
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--);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 扩展中间件
|
||||
/// </summary>
|
||||
public static class StaticPageMiddlewareExtensions
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
/// <param name="directoryPath">文件写入地址,文件夹目录</param>
|
||||
/// <param name="supportDelete">是否支持删除</param>
|
||||
/// <param name="supportClear">是否支持全量删除</param>
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder UseStaticPageMiddleware(this IApplicationBuilder app, string directoryPath, bool supportDelete, bool supportClear)
|
||||
{
|
||||
return app.UseMiddleware<StaticPageMiddleware>(directoryPath, supportDelete, supportClear);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user