From 75351ca06cde18d2df6851e8ea23b1f620c71dbe Mon Sep 17 00:00:00 2001 From: xiaochanghai Date: Wed, 11 Jun 2025 10:08:27 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Ocelot.Provider.Nacos/Nacos.cs | 79 ++- .../NacosClient/LoadBalance/ILBStrategy.cs | 39 +- .../NacosClient/LoadBalance/LBStrategyName.cs | 31 +- .../NacosClient/LoadBalance/LbKv.cs | 11 +- .../LoadBalance/WeightRandomLBStrategy.cs | 101 ++-- .../LoadBalance/WeightRoundRobinLBStrategy.cs | 120 ++-- Ocelot.Provider.Nacos/NacosClient/UriTool.cs | 198 ++++--- .../NacosClient/V2/NacosAspNetOptions.cs | 150 +++-- .../NacosClient/V2/RegSvcBgTask.cs | 164 +++--- .../V2/ServiceCollectionExtensions.cs | 95 ++-- .../NacosMiddlewareConfigurationProvider.cs | 39 +- Ocelot.Provider.Nacos/NacosProviderFactory.cs | 30 +- .../OcelotBuilderExtensions.cs | 20 +- .../Helper}/ExtensionHelper.cs | 8 +- .../EventBusKafka/EventBusKafka.cs | 177 +++--- .../EventBusKafka/IKafkaConnectionPool.cs | 32 +- .../EventBusKafka/KafkaConnectionPool.cs | 113 ++-- .../EventBusKafka/KafkaConsumerHostService.cs | 243 ++++---- .../EventBusKafka/KafkaOptions.cs | 43 +- .../EventBusKafka/ProtobufTransfer.cs | 45 +- .../InMemoryEventBusSubscriptionsManager.cs | 274 +++++---- .../EventBusSubscriptions/SubscriptionInfo.cs | 42 +- .../IDynamicIntegrationEventHandler.cs | 17 +- Tiobon.Core.EventBus/Eventbus/IEventBus.cs | 81 ++- .../Eventbus/IEventBusSubscriptionsManager.cs | 55 +- .../Eventbus/IIntegrationEventHandler.cs | 35 +- .../Eventbus/IntegrationEvent.cs | 44 +- .../RabbitMQPersistent/EventBusRabbitMQ.cs | 523 +++++++++--------- .../IRabbitMQPersistentConnection.cs | 66 ++- .../RabbitMQPersistentConnection.cs | 331 ++++++----- .../Controllers/UserController.cs | 57 +- .../Extensions/CustomAuthenticationHandler.cs | 69 ++- .../Extensions/CustomOcelotSetup.cs | 43 +- .../Extensions/CustomResultHandler.cs | 81 ++- .../Extensions/CustomSwaggerSetup.cs | 113 ++-- .../Helper/CustomJwtTokenAuthMiddleware.cs | 269 +++++---- Tiobon.Core.Gateway/Program.cs | 41 +- Tiobon.Core.Model/HttpEnum.cs | 7 - Tiobon.Core.Model/ViewModels/EnumDemoDto.cs | 16 - .../ViewModels/TopgbViewModels.cs | 22 - Tiobon.Core.Model/ViewModels/UploadFileDto.cs | 18 - Tiobon.Core.Tasks/GlobalUsings.cs | 7 +- .../QuartzNet/ISchedulerCenter.cs | 7 +- Tiobon.Core.Tasks/QuartzNet/Jobs/JobBase.cs | 5 +- .../QuartzNet/Jobs/Job_AutoClearLog_Quartz.cs | 4 +- .../Jobs/Job_AutoIssueCertificate_Quartz.cs | 4 +- .../Jobs/Job_AutoIssueCredit_Quartz.cs | 3 +- .../Jobs/Job_AutoMarkCompleteStatus_Quartz.cs | 4 +- .../QuartzNet/Jobs/Job_OperateLog_Quartz.cs | 1 - .../QuartzNet/Jobs/Job_URL_Quartz.cs | 4 +- .../QuartzNet/SchedulerCenterServer.cs | 3 - .../Common_Test/DbAccess_Should.cs | 28 +- .../Common_Test/HttpHelper_Should.cs | 31 +- .../Common_Test/SM4Helper_Should.cs | 55 +- .../Controller_Test/LoginController_Should.cs | 133 +++-- .../DependencyInjection/DI_Test.cs | 181 +++--- Tiobon.Core.Tests/Redis_Test/Redis_Should.cs | 31 +- .../MongoRepository_Base_Should.cs | 79 ++- .../Repository_Test/Repository_Base_Should.cs | 113 ++-- Tiobon.Core.sln | 9 - Tiobon.Core/Tiobon.Core.Model.xml | 25 - 61 files changed, 2216 insertions(+), 2453 deletions(-) rename {Tiobon.Core.Services/Extensions => Tiobon.Core.Common/Helper}/ExtensionHelper.cs (94%) delete mode 100644 Tiobon.Core.Model/HttpEnum.cs delete mode 100644 Tiobon.Core.Model/ViewModels/EnumDemoDto.cs delete mode 100644 Tiobon.Core.Model/ViewModels/TopgbViewModels.cs delete mode 100644 Tiobon.Core.Model/ViewModels/UploadFileDto.cs diff --git a/Ocelot.Provider.Nacos/Nacos.cs b/Ocelot.Provider.Nacos/Nacos.cs index b1d4cd4f..ccc96d4f 100644 --- a/Ocelot.Provider.Nacos/Nacos.cs +++ b/Ocelot.Provider.Nacos/Nacos.cs @@ -1,57 +1,56 @@ -using Ocelot.ServiceDiscovery.Providers; -using Ocelot.Values; +using Microsoft.Extensions.Options; using Nacos.V2; -using Microsoft.Extensions.Options; using Ocelot.Provider.Nacos.NacosClient.V2; +using Ocelot.ServiceDiscovery.Providers; +using Ocelot.Values; using NacosConstants = Nacos.V2.Common.Constants; -namespace Ocelot.Provider.Nacos +namespace Ocelot.Provider.Nacos; + +public class Nacos : IServiceDiscoveryProvider { - public class Nacos : IServiceDiscoveryProvider - { - private readonly INacosNamingService _client; - private readonly string _serviceName; - private readonly string _groupName; - private readonly List _clusters; + private readonly INacosNamingService _client; + private readonly string _serviceName; + private readonly string _groupName; + private readonly List _clusters; - public Nacos(string serviceName, INacosNamingService client, IOptions options) - { - _serviceName = serviceName; - _client = client; - _groupName = string.IsNullOrWhiteSpace(options.Value.GroupName) ? - NacosConstants.DEFAULT_GROUP : options.Value.GroupName; - _clusters = (string.IsNullOrWhiteSpace(options.Value.ClusterName) ? NacosConstants.DEFAULT_CLUSTER_NAME : options.Value.ClusterName).Split(",").ToList(); - } + public Nacos(string serviceName, INacosNamingService client, IOptions options) + { + _serviceName = serviceName; + _client = client; + _groupName = string.IsNullOrWhiteSpace(options.Value.GroupName) ? + NacosConstants.DEFAULT_GROUP : options.Value.GroupName; + _clusters = (string.IsNullOrWhiteSpace(options.Value.ClusterName) ? NacosConstants.DEFAULT_CLUSTER_NAME : options.Value.ClusterName).Split(",").ToList(); + } - public async Task> Get() - { - var services = new List(); + public async Task> Get() + { + var services = new List(); - var instances = await _client.GetAllInstances(_serviceName, _groupName, _clusters); + var instances = await _client.GetAllInstances(_serviceName, _groupName, _clusters); - if (instances != null && instances.Any()) + if (instances != null && instances.Any()) + { + foreach (var Sitem in instances) { - foreach (var Sitem in instances) + string sip = Sitem.Ip; + int sport = Sitem.Port; + if (Sitem.Metadata.ContainsKey("endpoint")) { - string sip = Sitem.Ip; - int sport = Sitem.Port; - if (Sitem.Metadata.ContainsKey("endpoint")) - { - string[] ipport = Sitem.Metadata["endpoint"].Split(':'); - sip = ipport[0]; - sport =int.Parse( ipport[1]); - } - services.Add(new Service(Sitem.InstanceId, new ServiceHostAndPort(sip, sport), "", "", new List())); + string[] ipport = Sitem.Metadata["endpoint"].Split(':'); + sip = ipport[0]; + sport =int.Parse( ipport[1]); } - // services.AddRange(instances.Select(i => new Service(i.InstanceId, new ServiceHostAndPort(i.Ip, i.Port), "", "", new List()))); + services.Add(new Service(Sitem.InstanceId, new ServiceHostAndPort(sip, sport), "", "", new List())); } - - return await Task.FromResult(services); + // services.AddRange(instances.Select(i => new Service(i.InstanceId, new ServiceHostAndPort(i.Ip, i.Port), "", "", new List()))); } - public Task> GetAsync() - { - throw new NotImplementedException(); - } + return await Task.FromResult(services); + } + + public Task> GetAsync() + { + throw new NotImplementedException(); } } diff --git a/Ocelot.Provider.Nacos/NacosClient/LoadBalance/ILBStrategy.cs b/Ocelot.Provider.Nacos/NacosClient/LoadBalance/ILBStrategy.cs index 5bae9078..3d60d594 100644 --- a/Ocelot.Provider.Nacos/NacosClient/LoadBalance/ILBStrategy.cs +++ b/Ocelot.Provider.Nacos/NacosClient/LoadBalance/ILBStrategy.cs @@ -2,25 +2,24 @@ using Nacos.V2.Naming.Dtos; using System.Collections.Generic; -namespace Ocelot.Provider.Nacos.NacosClient +namespace Ocelot.Provider.Nacos.NacosClient; + +public interface ILBStrategy { - public interface ILBStrategy - { - /// - /// Strategy Name - /// - LBStrategyName Name { get; } - - /// - /// Get host - /// - /// host list - /// The Host - Instance GetHost(List list); - } - - - - - + /// + /// Strategy Name + /// + LBStrategyName Name { get; } + + /// + /// Get host + /// + /// host list + /// The Host + Instance GetHost(List list); } + + + + + diff --git a/Ocelot.Provider.Nacos/NacosClient/LoadBalance/LBStrategyName.cs b/Ocelot.Provider.Nacos/NacosClient/LoadBalance/LBStrategyName.cs index a01a0136..8cb89cad 100644 --- a/Ocelot.Provider.Nacos/NacosClient/LoadBalance/LBStrategyName.cs +++ b/Ocelot.Provider.Nacos/NacosClient/LoadBalance/LBStrategyName.cs @@ -1,20 +1,19 @@ -namespace Ocelot.Provider.Nacos.NacosClient +namespace Ocelot.Provider.Nacos.NacosClient; + +public enum LBStrategyName { - public enum LBStrategyName - { - /// - /// Weight Round Robin - /// - WeightRoundRobin, + /// + /// Weight Round Robin + /// + WeightRoundRobin, - /// - /// Weight Random - /// - WeightRandom, + /// + /// Weight Random + /// + WeightRandom, - /// - /// Ext1 - /// - Ext1 - } + /// + /// Ext1 + /// + Ext1 } diff --git a/Ocelot.Provider.Nacos/NacosClient/LoadBalance/LbKv.cs b/Ocelot.Provider.Nacos/NacosClient/LoadBalance/LbKv.cs index da3969e4..a9361d91 100644 --- a/Ocelot.Provider.Nacos/NacosClient/LoadBalance/LbKv.cs +++ b/Ocelot.Provider.Nacos/NacosClient/LoadBalance/LbKv.cs @@ -1,9 +1,8 @@ -namespace Ocelot.Provider.Nacos.NacosClient +namespace Ocelot.Provider.Nacos.NacosClient; + +public class LbKv { - public class LbKv - { - public string InstanceId { get; set; } + public string InstanceId { get; set; } - public double Weight { get; set; } - } + public double Weight { get; set; } } diff --git a/Ocelot.Provider.Nacos/NacosClient/LoadBalance/WeightRandomLBStrategy.cs b/Ocelot.Provider.Nacos/NacosClient/LoadBalance/WeightRandomLBStrategy.cs index e6c8fa1b..423f1e9f 100644 --- a/Ocelot.Provider.Nacos/NacosClient/LoadBalance/WeightRandomLBStrategy.cs +++ b/Ocelot.Provider.Nacos/NacosClient/LoadBalance/WeightRandomLBStrategy.cs @@ -1,74 +1,69 @@ -using Nacos; -using Nacos.V2.Naming.Dtos; -using System; -using System.Collections.Generic; -using System.Linq; +using Nacos.V2.Naming.Dtos; -namespace Ocelot.Provider.Nacos.NacosClient +namespace Ocelot.Provider.Nacos.NacosClient; + +public class WeightRandomLBStrategy : ILBStrategy { - public class WeightRandomLBStrategy : ILBStrategy - { - public LBStrategyName Name => LBStrategyName.WeightRandom; + public LBStrategyName Name => LBStrategyName.WeightRandom; - public Instance GetHost(List list) - { - var dict = BuildScore(list); + public Instance GetHost(List list) + { + var dict = BuildScore(list); - Instance instance = null; + Instance instance = null; - var rd = new Random().NextDouble(); + var rd = new Random().NextDouble(); - foreach (var item in dict) + foreach (var item in dict) + { + if (item.Value >= rd) { - if (item.Value >= rd) - { - instance = list.FirstOrDefault(x => x.InstanceId.Equals(item.Key)); + instance = list.FirstOrDefault(x => x.InstanceId.Equals(item.Key)); - if (instance == null) - { - var arr = item.Key.Split("#"); - var ip = arr[0]; - int.TryParse(arr[1], out var port); - var cluster = arr[2]; - - instance = list.First(x => x.Ip.Equals(ip) && x.Port == port && x.ClusterName.Equals(cluster)); - } + if (instance == null) + { + var arr = item.Key.Split("#"); + var ip = arr[0]; + int.TryParse(arr[1], out var port); + var cluster = arr[2]; - break; + instance = list.First(x => x.Ip.Equals(ip) && x.Port == port && x.ClusterName.Equals(cluster)); } - } - return instance; + break; + } } - private Dictionary BuildScore(List list) - { - var dict = new Dictionary(); + return instance; + } - // aliyun sae, the instanceid returns empty string - // when the instanceid is empty, create a new one, but the group was missed. - list.ForEach(x => { x.InstanceId = string.IsNullOrWhiteSpace(x.InstanceId) ? $"{x.Ip}#{x.Port}#{x.ClusterName}#{x.ServiceName}" : x.InstanceId; }); + private Dictionary BuildScore(List list) + { + var dict = new Dictionary(); - var tmp = list.Select(x => new LbKv - { - InstanceId = x.InstanceId, - Weight = x.Weight - }).GroupBy(x => x.InstanceId).Select(x => new LbKv - { - InstanceId = x.Key, - Weight = x.Max(y => y.Weight) - }).ToList(); + // aliyun sae, the instanceid returns empty string + // when the instanceid is empty, create a new one, but the group was missed. + list.ForEach(x => { x.InstanceId = string.IsNullOrWhiteSpace(x.InstanceId) ? $"{x.Ip}#{x.Port}#{x.ClusterName}#{x.ServiceName}" : x.InstanceId; }); - var total = tmp.Sum(x => x.Weight); - var cur = 0d; + var tmp = list.Select(x => new LbKv + { + InstanceId = x.InstanceId, + Weight = x.Weight + }).GroupBy(x => x.InstanceId).Select(x => new LbKv + { + InstanceId = x.Key, + Weight = x.Max(y => y.Weight) + }).ToList(); - foreach (var item in tmp) - { - cur += item.Weight; - dict.TryAdd(item.InstanceId, cur / total); - } + var total = tmp.Sum(x => x.Weight); + var cur = 0d; - return dict; + foreach (var item in tmp) + { + cur += item.Weight; + dict.TryAdd(item.InstanceId, cur / total); } + + return dict; } } diff --git a/Ocelot.Provider.Nacos/NacosClient/LoadBalance/WeightRoundRobinLBStrategy.cs b/Ocelot.Provider.Nacos/NacosClient/LoadBalance/WeightRoundRobinLBStrategy.cs index c6efe7c9..cbb4fdaa 100644 --- a/Ocelot.Provider.Nacos/NacosClient/LoadBalance/WeightRoundRobinLBStrategy.cs +++ b/Ocelot.Provider.Nacos/NacosClient/LoadBalance/WeightRoundRobinLBStrategy.cs @@ -1,71 +1,67 @@ -using Nacos; -using System.Collections.Generic; -using System.Linq; -using Nacos.V2.Naming.Dtos; -namespace Ocelot.Provider.Nacos.NacosClient +using Nacos.V2.Naming.Dtos; +namespace Ocelot.Provider.Nacos.NacosClient; + +public class WeightRoundRobinLBStrategy : ILBStrategy { - public class WeightRoundRobinLBStrategy : ILBStrategy + public LBStrategyName Name => LBStrategyName.WeightRoundRobin; + + private int _pos; + + private static object obj = new object(); + + public Instance GetHost(List list) { - public LBStrategyName Name => LBStrategyName.WeightRoundRobin; + // aliyun sae, the instanceid returns empty string + // when the instanceid is empty, create a new one, but the group was missed. + list.ForEach(x => { x.InstanceId = string.IsNullOrWhiteSpace(x.InstanceId) ? $"{x.Ip}#{x.Port}#{x.ClusterName}#{x.ServiceName}" : x.InstanceId; }); + + var tmp = list.Select(x => new LbKv + { + InstanceId = x.InstanceId, + Weight = x.Weight + }).GroupBy(x => x.InstanceId).Select(x => new LbKv + { + InstanceId = x.Key, + Weight = x.Max(y => y.Weight) + }).ToList(); - private int _pos; + // + var dic = tmp.ToDictionary(k => k.InstanceId, v => (int)v.Weight); - private static object obj = new object(); + var srcInstanceIdList = dic.Keys.ToList(); + var tagInstanceIdList = new List(); - public Instance GetHost(List list) + foreach (var item in srcInstanceIdList) { - // aliyun sae, the instanceid returns empty string - // when the instanceid is empty, create a new one, but the group was missed. - list.ForEach(x => { x.InstanceId = string.IsNullOrWhiteSpace(x.InstanceId) ? $"{x.Ip}#{x.Port}#{x.ClusterName}#{x.ServiceName}" : x.InstanceId; }); - - var tmp = list.Select(x => new LbKv - { - InstanceId = x.InstanceId, - Weight = x.Weight - }).GroupBy(x => x.InstanceId).Select(x => new LbKv - { - InstanceId = x.Key, - Weight = x.Max(y => y.Weight) - }).ToList(); - - // - var dic = tmp.ToDictionary(k => k.InstanceId, v => (int)v.Weight); - - var srcInstanceIdList = dic.Keys.ToList(); - var tagInstanceIdList = new List(); - - foreach (var item in srcInstanceIdList) - { - dic.TryGetValue(item, out var weight); - - for (int i = 0; i < weight; i++) - tagInstanceIdList.Add(item); - } - - var instanceId = string.Empty; - - lock (obj) - { - if (_pos >= tagInstanceIdList.Count) - _pos = 0; - - instanceId = tagInstanceIdList[_pos]; - _pos++; - } - - var instance = list.FirstOrDefault(x => x.InstanceId.Equals(instanceId)); - - if (instance == null) - { - var arr = instanceId.Split("#"); - var ip = arr[0]; - int.TryParse(arr[1], out var port); - var cluster = arr[2]; - - instance = list.First(x => x.Ip.Equals(ip) && x.Port == port && x.ClusterName.Equals(cluster)); - } - - return instance; + dic.TryGetValue(item, out var weight); + + for (int i = 0; i < weight; i++) + tagInstanceIdList.Add(item); } + + var instanceId = string.Empty; + + lock (obj) + { + if (_pos >= tagInstanceIdList.Count) + _pos = 0; + + instanceId = tagInstanceIdList[_pos]; + _pos++; + } + + var instance = list.FirstOrDefault(x => x.InstanceId.Equals(instanceId)); + + if (instance == null) + { + var arr = instanceId.Split("#"); + var ip = arr[0]; + int.TryParse(arr[1], out var port); + var cluster = arr[2]; + + instance = list.First(x => x.Ip.Equals(ip) && x.Port == port && x.ClusterName.Equals(cluster)); + } + + return instance; } } diff --git a/Ocelot.Provider.Nacos/NacosClient/UriTool.cs b/Ocelot.Provider.Nacos/NacosClient/UriTool.cs index dbb7cf8e..ce2bf1f1 100644 --- a/Ocelot.Provider.Nacos/NacosClient/UriTool.cs +++ b/Ocelot.Provider.Nacos/NacosClient/UriTool.cs @@ -1,145 +1,141 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Hosting.Server.Features; +using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http.Features; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; -namespace Ocelot.Provider.Nacos.NacosClient +namespace Ocelot.Provider.Nacos.NacosClient; + +internal static class UriTool { - internal static class UriTool + public static IEnumerable GetUri(IFeatureCollection features, string ip, int port, string preferredNetworks) { - public static IEnumerable GetUri(IFeatureCollection features, string ip, int port, string preferredNetworks) + var splitChars = new char[] { ',', ';' }; + var appPort = port <= 0 ? 80 : port; + + // 1. config + if (!string.IsNullOrWhiteSpace(ip)) { - var splitChars = new char[] { ',', ';' }; - var appPort = port <= 0 ? 80 : port; + // it seems that nacos don't return the scheme + // so here use http only. + return new List { new Uri($"http://{ip}:{appPort}") }; + } - // 1. config - if (!string.IsNullOrWhiteSpace(ip)) - { - // it seems that nacos don't return the scheme - // so here use http only. - return new List { new Uri($"http://{ip}:{appPort}") }; - } + // 1.1. Ip is null && Port has value + if (string.IsNullOrWhiteSpace(ip) && appPort != 80) + { + return new List { new Uri($"http://{GetCurrentIp(preferredNetworks)}:{appPort}") }; + } - // 1.1. Ip is null && Port has value - if (string.IsNullOrWhiteSpace(ip) && appPort != 80) - { - return new List { new Uri($"http://{GetCurrentIp(preferredNetworks)}:{appPort}") }; - } + var address = string.Empty; - var address = string.Empty; + // 2. IServerAddressesFeature + if (features != null) + { + var addresses = features.Get(); + var addressCollection = addresses?.Addresses; - // 2. IServerAddressesFeature - if (features != null) + if (addressCollection != null && addressCollection.Any()) { - var addresses = features.Get(); - var addressCollection = addresses?.Addresses; - - if (addressCollection != null && addressCollection.Any()) + var uris = new List(); + foreach (var item in addressCollection) { - var uris = new List(); - foreach (var item in addressCollection) - { - var url = ReplaceAddress(item, preferredNetworks); - uris.Add(new Uri(url)); - } - - return uris; + var url = ReplaceAddress(item, preferredNetworks); + uris.Add(new Uri(url)); } + + return uris; } + } - // 3. ASPNETCORE_URLS - address = Environment.GetEnvironmentVariable("ASPNETCORE_URLS"); - if (!string.IsNullOrWhiteSpace(address)) + // 3. ASPNETCORE_URLS + address = Environment.GetEnvironmentVariable("ASPNETCORE_URLS"); + if (!string.IsNullOrWhiteSpace(address)) + { + var url = ReplaceAddress(address, preferredNetworks); + + return url.Split(splitChars).Select(x => new Uri(x)); + } + + // 4. --urls + var cmdArgs = Environment.GetCommandLineArgs(); + if (cmdArgs != null && cmdArgs.Any()) + { + var cmd = cmdArgs.FirstOrDefault(x => x.StartsWith("--urls", StringComparison.OrdinalIgnoreCase)); + + if (!string.IsNullOrWhiteSpace(cmd)) { + address = cmd.Split('=')[1]; + var url = ReplaceAddress(address, preferredNetworks); return url.Split(splitChars).Select(x => new Uri(x)); } + } - // 4. --urls - var cmdArgs = Environment.GetCommandLineArgs(); - if (cmdArgs != null && cmdArgs.Any()) - { - var cmd = cmdArgs.FirstOrDefault(x => x.StartsWith("--urls", StringComparison.OrdinalIgnoreCase)); - - if (!string.IsNullOrWhiteSpace(cmd)) - { - address = cmd.Split('=')[1]; - - var url = ReplaceAddress(address, preferredNetworks); + // 5. current ip address third + address = $"http://{GetCurrentIp(preferredNetworks)}:{appPort}"; - return url.Split(splitChars).Select(x => new Uri(x)); - } - } + return new List { new Uri(address) }; + } - // 5. current ip address third - address = $"http://{GetCurrentIp(preferredNetworks)}:{appPort}"; + private static string ReplaceAddress(string address, string preferredNetworks) + { + var ip = GetCurrentIp(preferredNetworks); - return new List { new Uri(address) }; + if (address.Contains("*")) + { + address = address.Replace("*", ip); } - - private static string ReplaceAddress(string address, string preferredNetworks) + else if (address.Contains("+")) + { + address = address.Replace("+", ip); + } + else if (address.Contains("localhost", StringComparison.OrdinalIgnoreCase)) + { + address = address.Replace("localhost", ip, StringComparison.OrdinalIgnoreCase); + } + else if (address.Contains("0.0.0.0", StringComparison.OrdinalIgnoreCase)) { - var ip = GetCurrentIp(preferredNetworks); + address = address.Replace("0.0.0.0", ip, StringComparison.OrdinalIgnoreCase); + } - if (address.Contains("*")) - { - address = address.Replace("*", ip); - } - else if (address.Contains("+")) - { - address = address.Replace("+", ip); - } - else if (address.Contains("localhost", StringComparison.OrdinalIgnoreCase)) - { - address = address.Replace("localhost", ip, StringComparison.OrdinalIgnoreCase); - } - else if (address.Contains("0.0.0.0", StringComparison.OrdinalIgnoreCase)) - { - address = address.Replace("0.0.0.0", ip, StringComparison.OrdinalIgnoreCase); - } + return address; + } - return address; - } + private static string GetCurrentIp(string preferredNetworks) + { + var instanceIp = "127.0.0.1"; - private static string GetCurrentIp(string preferredNetworks) + try { - var instanceIp = "127.0.0.1"; + // 获取可用网卡 + var nics = NetworkInterface.GetAllNetworkInterfaces()?.Where(network => network.OperationalStatus == OperationalStatus.Up); - try - { - // 获取可用网卡 - var nics = NetworkInterface.GetAllNetworkInterfaces()?.Where(network => network.OperationalStatus == OperationalStatus.Up); - - // 获取所有可用网卡IP信息 - var ipCollection = nics?.Select(x => x.GetIPProperties())?.SelectMany(x => x.UnicastAddresses); + // 获取所有可用网卡IP信息 + var ipCollection = nics?.Select(x => x.GetIPProperties())?.SelectMany(x => x.UnicastAddresses); - foreach (var ipadd in ipCollection) + foreach (var ipadd in ipCollection) + { + if (!IPAddress.IsLoopback(ipadd.Address) && ipadd.Address.AddressFamily == AddressFamily.InterNetwork) { - if (!IPAddress.IsLoopback(ipadd.Address) && ipadd.Address.AddressFamily == AddressFamily.InterNetwork) + if (string.IsNullOrEmpty(preferredNetworks)) { - if (string.IsNullOrEmpty(preferredNetworks)) - { - instanceIp = ipadd.Address.ToString(); - break; - } - - if (!ipadd.Address.ToString().StartsWith(preferredNetworks)) continue; instanceIp = ipadd.Address.ToString(); break; } + + if (!ipadd.Address.ToString().StartsWith(preferredNetworks)) continue; + instanceIp = ipadd.Address.ToString(); + break; } } - catch - { - // ignored - } - - return instanceIp; } + catch + { + // ignored + } + + return instanceIp; } } diff --git a/Ocelot.Provider.Nacos/NacosClient/V2/NacosAspNetOptions.cs b/Ocelot.Provider.Nacos/NacosClient/V2/NacosAspNetOptions.cs index 12903962..d75d8a27 100644 --- a/Ocelot.Provider.Nacos/NacosClient/V2/NacosAspNetOptions.cs +++ b/Ocelot.Provider.Nacos/NacosClient/V2/NacosAspNetOptions.cs @@ -1,96 +1,94 @@ using Nacos.V2; using Nacos.V2.Common; -using System.Collections.Generic; -namespace Ocelot.Provider.Nacos.NacosClient.V2 +namespace Ocelot.Provider.Nacos.NacosClient.V2; + +public class NacosAspNetOptions : NacosSdkOptions { - public class NacosAspNetOptions : NacosSdkOptions - { - /// - /// the name of the service. - /// - public string ServiceName { get; set; } + /// + /// the name of the service. + /// + public string ServiceName { get; set; } - /// - /// the name of the group. - /// - public string GroupName { get; set; } = Constants.DEFAULT_GROUP; + /// + /// the name of the group. + /// + public string GroupName { get; set; } = Constants.DEFAULT_GROUP; - /// - /// the name of the cluster. - /// - /// The name of the cluster. - public string ClusterName { get; set; } = Constants.DEFAULT_CLUSTER_NAME; + /// + /// the name of the cluster. + /// + /// The name of the cluster. + public string ClusterName { get; set; } = Constants.DEFAULT_CLUSTER_NAME; - /// - /// the ip of this instance - /// - public string Ip { get; set; } + /// + /// the ip of this instance + /// + public string Ip { get; set; } - /// - /// Select an IP that matches the prefix as the service registration IP - /// like the config of spring.cloud.inetutils.preferred-networks - /// - public string PreferredNetworks { get; set; } + /// + /// Select an IP that matches the prefix as the service registration IP + /// like the config of spring.cloud.inetutils.preferred-networks + /// + public string PreferredNetworks { get; set; } - /// - /// the port of this instance - /// - public int Port { get; set; } + /// + /// the port of this instance + /// + public int Port { get; set; } - /// - /// the weight of this instance. - /// - public double Weight { get; set; } = 100; + /// + /// the weight of this instance. + /// + public double Weight { get; set; } = 100; - /// - /// if you just want to subscribe, but don't want to register your service, set it to false. - /// - public bool RegisterEnabled { get; set; } = true; + /// + /// if you just want to subscribe, but don't want to register your service, set it to false. + /// + public bool RegisterEnabled { get; set; } = true; - /// - /// the metadata of this instance - /// - public Dictionary Metadata { get; set; } = new Dictionary(); + /// + /// the metadata of this instance + /// + public Dictionary Metadata { get; set; } = new Dictionary(); - /// - /// If instance is enabled to accept request. The default value is true. - /// - public bool InstanceEnabled { get; set; } = true; + /// + /// If instance is enabled to accept request. The default value is true. + /// + public bool InstanceEnabled { get; set; } = true; - /// - /// If instance is ephemeral.The default value is true. - /// - public bool Ephemeral { get; set; } = true; + /// + /// If instance is ephemeral.The default value is true. + /// + public bool Ephemeral { get; set; } = true; - /// - /// whether your service is a https service. - /// - public bool Secure { get; set; } = false; + /// + /// whether your service is a https service. + /// + public bool Secure { get; set; } = false; - /// - /// Load Balance Strategy - /// - public string LBStrategy { get; set; } = LBStrategyName.WeightRandom.ToString(); + /// + /// Load Balance Strategy + /// + public string LBStrategy { get; set; } = LBStrategyName.WeightRandom.ToString(); - public NacosSdkOptions BuildSdkOptions() + public NacosSdkOptions BuildSdkOptions() + { + return new NacosSdkOptions { - return new NacosSdkOptions - { - AccessKey = this.AccessKey, - ConfigUseRpc = this.ConfigUseRpc, - ContextPath = this.ContextPath, - DefaultTimeOut = this.DefaultTimeOut, - EndPoint = this.EndPoint, - ListenInterval = this.ListenInterval, - Namespace = this.Namespace, - NamingLoadCacheAtStart = this.NamingLoadCacheAtStart, - NamingUseRpc = this.NamingUseRpc, - Password = this.Password, - SecretKey = this.SecretKey, - ServerAddresses = this.ServerAddresses, - UserName = this.UserName, - }; - } + AccessKey = this.AccessKey, + ConfigUseRpc = this.ConfigUseRpc, + ContextPath = this.ContextPath, + DefaultTimeOut = this.DefaultTimeOut, + EndPoint = this.EndPoint, + ListenInterval = this.ListenInterval, + Namespace = this.Namespace, + NamingLoadCacheAtStart = this.NamingLoadCacheAtStart, + NamingUseRpc = this.NamingUseRpc, + Password = this.Password, + SecretKey = this.SecretKey, + ServerAddresses = this.ServerAddresses, + UserName = this.UserName, + }; } } diff --git a/Ocelot.Provider.Nacos/NacosClient/V2/RegSvcBgTask.cs b/Ocelot.Provider.Nacos/NacosClient/V2/RegSvcBgTask.cs index 63709af1..bcb51139 100644 --- a/Ocelot.Provider.Nacos/NacosClient/V2/RegSvcBgTask.cs +++ b/Ocelot.Provider.Nacos/NacosClient/V2/RegSvcBgTask.cs @@ -1,69 +1,103 @@ using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Http.Features; -using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Nacos.V2; using Nacos.V2.Naming.Core; using Nacos.V2.Naming.Dtos; -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -namespace Ocelot.Provider.Nacos.NacosClient.V2 +namespace Ocelot.Provider.Nacos.NacosClient.V2; + +public class RegSvcBgTask { - public class RegSvcBgTask - { - private static readonly string MetadataNetVersion = "DOTNET_VERSION"; - private static readonly string MetadataHostOs = "HOST_OS"; - private static readonly string MetadataSecure = "secure"; + private static readonly string MetadataNetVersion = "DOTNET_VERSION"; + private static readonly string MetadataHostOs = "HOST_OS"; + private static readonly string MetadataSecure = "secure"; + + private readonly ILogger _logger; + private readonly INacosNamingService _svc; + private readonly IFeatureCollection _features; + private NacosAspNetOptions _options; - private readonly ILogger _logger; - private readonly INacosNamingService _svc; - private readonly IFeatureCollection _features; - private NacosAspNetOptions _options; + private IEnumerable uris = null; - private IEnumerable uris = null; + public RegSvcBgTask( + ILoggerFactory loggerFactory, + INacosNamingService svc, + IServer server, + IOptionsMonitor optionsAccs) + { + _logger = loggerFactory.CreateLogger(); + _svc = svc; + _options = optionsAccs.CurrentValue; + _features = server.Features; + } - public RegSvcBgTask( - ILoggerFactory loggerFactory, - INacosNamingService svc, - IServer server, - IOptionsMonitor optionsAccs) + public async Task StartAsync() + { + if (!_options.RegisterEnabled) { - _logger = loggerFactory.CreateLogger(); - _svc = svc; - _options = optionsAccs.CurrentValue; - _features = server.Features; + _logger.LogInformation("setting RegisterEnabled to false, will not register to nacos"); + return; } - public async Task StartAsync() + uris = UriTool.GetUri(_features, _options.Ip, _options.Port, _options.PreferredNetworks); + + var metadata = new Dictionary() { - if (!_options.RegisterEnabled) + { PreservedMetadataKeys.REGISTER_SOURCE, $"ASPNET_CORE" }, + { MetadataNetVersion, Environment.Version.ToString() }, + { MetadataHostOs, Environment.OSVersion.ToString() }, + }; + + if (_options.Secure) metadata[MetadataSecure] = "true"; + + foreach (var item in _options.Metadata) + { + if (!metadata.ContainsKey(item.Key)) { - _logger.LogInformation("setting RegisterEnabled to false, will not register to nacos"); - return; + metadata.TryAdd(item.Key, item.Value); } + } - uris = UriTool.GetUri(_features, _options.Ip, _options.Port, _options.PreferredNetworks); - - var metadata = new Dictionary() + foreach (var uri in uris) + { + for (int i = 0; i < 3; i++) { - { PreservedMetadataKeys.REGISTER_SOURCE, $"ASPNET_CORE" }, - { MetadataNetVersion, Environment.Version.ToString() }, - { MetadataHostOs, Environment.OSVersion.ToString() }, - }; + try + { + var instance = new Instance + { + Ephemeral = _options.Ephemeral, + ServiceName = _options.ServiceName, + ClusterName = _options.ClusterName, + Enabled = _options.InstanceEnabled, + Healthy = true, + Ip = uri.Host, + Port = uri.Port, + Weight = _options.Weight, + Metadata = metadata, + InstanceId = "" + }; - if (_options.Secure) metadata[MetadataSecure] = "true"; + _logger.LogInformation("register instance to nacos server, 【{0}】", instance); - foreach (var item in _options.Metadata) - { - if (!metadata.ContainsKey(item.Key)) + await _svc.RegisterInstance(_options.ServiceName, _options.GroupName, instance); + break; + } + catch (Exception ex) { - metadata.TryAdd(item.Key, item.Value); + _logger.LogError(ex, "register instance error, count = {0}", i + 1); } } + } + } + + public async Task StopAsync() + { + if (_options.RegisterEnabled) + { + _logger.LogWarning("deregister instance from nacos server, serviceName={0}", _options.ServiceName); foreach (var uri in uris) { @@ -71,54 +105,14 @@ namespace Ocelot.Provider.Nacos.NacosClient.V2 { try { - var instance = new Instance - { - Ephemeral = _options.Ephemeral, - ServiceName = _options.ServiceName, - ClusterName = _options.ClusterName, - Enabled = _options.InstanceEnabled, - Healthy = true, - Ip = uri.Host, - Port = uri.Port, - Weight = _options.Weight, - Metadata = metadata, - InstanceId = "" - }; - - _logger.LogInformation("register instance to nacos server, 【{0}】", instance); - - await _svc.RegisterInstance(_options.ServiceName, _options.GroupName, instance); + _logger.LogWarning("begin to remove instance"); + await _svc.DeregisterInstance(_options.ServiceName, _options.GroupName, uri.Host, uri.Port, _options.ClusterName); + _logger.LogWarning("removed instance"); break; } catch (Exception ex) { - _logger.LogError(ex, "register instance error, count = {0}", i + 1); - } - } - } - } - - public async Task StopAsync() - { - if (_options.RegisterEnabled) - { - _logger.LogWarning("deregister instance from nacos server, serviceName={0}", _options.ServiceName); - - foreach (var uri in uris) - { - for (int i = 0; i < 3; i++) - { - try - { - _logger.LogWarning("begin to remove instance"); - await _svc.DeregisterInstance(_options.ServiceName, _options.GroupName, uri.Host, uri.Port, _options.ClusterName); - _logger.LogWarning("removed instance"); - break; - } - catch (Exception ex) - { - _logger.LogError(ex, "deregister instance error, count = {0}", i + 1); - } + _logger.LogError(ex, "deregister instance error, count = {0}", i + 1); } } } diff --git a/Ocelot.Provider.Nacos/NacosClient/V2/ServiceCollectionExtensions.cs b/Ocelot.Provider.Nacos/NacosClient/V2/ServiceCollectionExtensions.cs index 43abb7e6..c042f48f 100644 --- a/Ocelot.Provider.Nacos/NacosClient/V2/ServiceCollectionExtensions.cs +++ b/Ocelot.Provider.Nacos/NacosClient/V2/ServiceCollectionExtensions.cs @@ -3,57 +3,54 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Nacos.V2.DependencyInjection; -using System; -using System.Threading.Tasks; -namespace Ocelot.Provider.Nacos.NacosClient.V2 +namespace Ocelot.Provider.Nacos.NacosClient.V2; + +public static class ServiceCollectionExtensions { - public static class ServiceCollectionExtensions + /// + /// Add Nacos AspNet. This will register and de-register instance automatically. + /// Mainly for nacos server 2.x + /// + /// services. + /// configuration + /// IServiceCollection + public static IServiceCollection AddNacosAspNet(this IServiceCollection services, IConfiguration configuration) + { + services.Configure(configuration.GetSection("nacos")); + services.AddNacosV2Naming(configuration); + services.AddSingleton(); + + return services; + } + + /// + /// Add Nacos AspNet. This will register and de-register instance automatically. + /// Mainly for nacos server 2.x + /// + /// services + /// optionsAccs + /// IServiceCollection + public static IServiceCollection AddNacosAspNet(this IServiceCollection services, Action optionsAccs) + { + services.Configure(optionsAccs); + + var options = new NacosAspNetOptions(); + optionsAccs.Invoke(options); + services.AddNacosV2Naming(x => options.BuildSdkOptions()); + services.AddSingleton(); + + return services; + } + + + public static async Task UseNacosAspNet(this IApplicationBuilder app, IHostApplicationLifetime lifetime) { - /// - /// Add Nacos AspNet. This will register and de-register instance automatically. - /// Mainly for nacos server 2.x - /// - /// services. - /// configuration - /// IServiceCollection - public static IServiceCollection AddNacosAspNet(this IServiceCollection services, IConfiguration configuration) - { - services.Configure(configuration.GetSection("nacos")); - services.AddNacosV2Naming(configuration); - services.AddSingleton(); - - return services; - } - - /// - /// Add Nacos AspNet. This will register and de-register instance automatically. - /// Mainly for nacos server 2.x - /// - /// services - /// optionsAccs - /// IServiceCollection - public static IServiceCollection AddNacosAspNet(this IServiceCollection services, Action optionsAccs) - { - services.Configure(optionsAccs); - - var options = new NacosAspNetOptions(); - optionsAccs.Invoke(options); - services.AddNacosV2Naming(x => options.BuildSdkOptions()); - services.AddSingleton(); - - return services; - } - - - public static async Task UseNacosAspNet(this IApplicationBuilder app, IHostApplicationLifetime lifetime) - { - RegSvcBgTask regSvcBgTask = app.ApplicationServices.GetRequiredService(); - await regSvcBgTask.StartAsync(); - lifetime.ApplicationStopping.Register(async () => { - await regSvcBgTask.StopAsync(); - }); - return app; - } + RegSvcBgTask regSvcBgTask = app.ApplicationServices.GetRequiredService(); + await regSvcBgTask.StartAsync(); + lifetime.ApplicationStopping.Register(async () => { + await regSvcBgTask.StopAsync(); + }); + return app; } } diff --git a/Ocelot.Provider.Nacos/NacosMiddlewareConfigurationProvider.cs b/Ocelot.Provider.Nacos/NacosMiddlewareConfigurationProvider.cs index f5f78641..6063e0b4 100644 --- a/Ocelot.Provider.Nacos/NacosMiddlewareConfigurationProvider.cs +++ b/Ocelot.Provider.Nacos/NacosMiddlewareConfigurationProvider.cs @@ -1,34 +1,31 @@ -using System; -using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Ocelot.Configuration; using Ocelot.Configuration.Repository; using Ocelot.Middleware; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; using Ocelot.Provider.Nacos.NacosClient.V2; -namespace Ocelot.Provider.Nacos +namespace Ocelot.Provider.Nacos; + +public class NacosMiddlewareConfigurationProvider { - public class NacosMiddlewareConfigurationProvider + public static OcelotMiddlewareConfigurationDelegate Get = builder => { - public static OcelotMiddlewareConfigurationDelegate Get = builder => - { - var internalConfigRepo = builder.ApplicationServices.GetService(); - var config = internalConfigRepo.Get(); - - var hostLifetime = builder.ApplicationServices.GetService(); + var internalConfigRepo = builder.ApplicationServices.GetService(); + var config = internalConfigRepo.Get(); - if (UsingNacosServiceDiscoveryProvider(config.Data)) - { - builder.UseNacosAspNet(hostLifetime).GetAwaiter().GetResult(); - } + var hostLifetime = builder.ApplicationServices.GetService(); - return Task.CompletedTask; - }; - - private static bool UsingNacosServiceDiscoveryProvider(IInternalConfiguration configuration) + if (UsingNacosServiceDiscoveryProvider(config.Data)) { - return configuration?.ServiceProviderConfiguration != null && configuration.ServiceProviderConfiguration.Type?.ToLower() == "nacos"; + builder.UseNacosAspNet(hostLifetime).GetAwaiter().GetResult(); } + + return Task.CompletedTask; + }; + + private static bool UsingNacosServiceDiscoveryProvider(IInternalConfiguration configuration) + { + return configuration?.ServiceProviderConfiguration != null && configuration.ServiceProviderConfiguration.Type?.ToLower() == "nacos"; } } diff --git a/Ocelot.Provider.Nacos/NacosProviderFactory.cs b/Ocelot.Provider.Nacos/NacosProviderFactory.cs index dc3dfb11..458718f2 100644 --- a/Ocelot.Provider.Nacos/NacosProviderFactory.cs +++ b/Ocelot.Provider.Nacos/NacosProviderFactory.cs @@ -1,23 +1,21 @@ -using System; -using Ocelot.ServiceDiscovery; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using Nacos.V2; using Ocelot.Provider.Nacos.NacosClient.V2; -using Microsoft.Extensions.Options; +using Ocelot.ServiceDiscovery; + +namespace Ocelot.Provider.Nacos; -namespace Ocelot.Provider.Nacos +public static class NacosProviderFactory { - public static class NacosProviderFactory + public static ServiceDiscoveryFinderDelegate Get = (provider, config, route) => { - public static ServiceDiscoveryFinderDelegate Get = (provider, config, route) => + var client = provider.GetService(); + if (config.Type?.ToLower() == "nacos" && client != null) { - var client = provider.GetService(); - if (config.Type?.ToLower() == "nacos" && client != null) - { - var option = provider.GetService>(); - return new Nacos(route.ServiceName, client, option); - } - return null; - }; - } + var option = provider.GetService>(); + return new Nacos(route.ServiceName, client, option); + } + return null; + }; } diff --git a/Ocelot.Provider.Nacos/OcelotBuilderExtensions.cs b/Ocelot.Provider.Nacos/OcelotBuilderExtensions.cs index 93b176de..d316bb0b 100644 --- a/Ocelot.Provider.Nacos/OcelotBuilderExtensions.cs +++ b/Ocelot.Provider.Nacos/OcelotBuilderExtensions.cs @@ -1,20 +1,18 @@ -using System.Linq; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Ocelot.DependencyInjection; using Ocelot.Middleware; using Ocelot.Provider.Nacos.NacosClient.V2; using Ocelot.ServiceDiscovery; -namespace Ocelot.Provider.Nacos +namespace Ocelot.Provider.Nacos; + +public static class OcelotBuilderExtensions { - public static class OcelotBuilderExtensions + public static IOcelotBuilder AddNacosDiscovery(this IOcelotBuilder builder) { - public static IOcelotBuilder AddNacosDiscovery(this IOcelotBuilder builder) - { - builder.Services.AddNacosAspNet(builder.Configuration); - builder.Services.AddSingleton(NacosProviderFactory.Get); - builder.Services.AddSingleton(NacosMiddlewareConfigurationProvider.Get); - return builder; - } + builder.Services.AddNacosAspNet(builder.Configuration); + builder.Services.AddSingleton(NacosProviderFactory.Get); + builder.Services.AddSingleton(NacosMiddlewareConfigurationProvider.Get); + return builder; } } diff --git a/Tiobon.Core.Services/Extensions/ExtensionHelper.cs b/Tiobon.Core.Common/Helper/ExtensionHelper.cs similarity index 94% rename from Tiobon.Core.Services/Extensions/ExtensionHelper.cs rename to Tiobon.Core.Common/Helper/ExtensionHelper.cs index fb79f6f5..1b104080 100644 --- a/Tiobon.Core.Services/Extensions/ExtensionHelper.cs +++ b/Tiobon.Core.Common/Helper/ExtensionHelper.cs @@ -1,4 +1,10 @@ -namespace Tiobon.Core.Common.Helper; +using SqlSugar; +using System.Data; +using Tiobon.Core.Helper; +using Tiobon.Core.Model.Entity; +using Tiobon.Core.Model.ViewModels.Extend; + +namespace Tiobon.Core.Common.Helper; public class ExtensionHelper { diff --git a/Tiobon.Core.EventBus/EventBusKafka/EventBusKafka.cs b/Tiobon.Core.EventBus/EventBusKafka/EventBusKafka.cs index 7d593c7c..c204b719 100644 --- a/Tiobon.Core.EventBus/EventBusKafka/EventBusKafka.cs +++ b/Tiobon.Core.EventBus/EventBusKafka/EventBusKafka.cs @@ -4,114 +4,113 @@ using Microsoft.Extensions.Options; using Newtonsoft.Json; using Tiobon.Core.Extensions; -namespace Tiobon.Core.EventBus +namespace Tiobon.Core.EventBus; + +/// +/// 基于Kafka的事件总线 +/// +public class EventBusKafka : IEventBus { + private readonly ILogger _logger; + private readonly IEventBusSubscriptionsManager _subsManager; + private readonly IKafkaConnectionPool _connectionPool; + private readonly KafkaOptions _options; + public EventBusKafka(ILogger logger, + IEventBusSubscriptionsManager subsManager, + IKafkaConnectionPool connectionPool, + IOptions options) + { + _logger = logger; + _subsManager = subsManager; + _connectionPool = connectionPool; + _options = options.Value; + } /// - /// 基于Kafka的事件总线 + /// 发布 /// - public class EventBusKafka : IEventBus + public void Publish(IntegrationEvent @event) { - private readonly ILogger _logger; - private readonly IEventBusSubscriptionsManager _subsManager; - private readonly IKafkaConnectionPool _connectionPool; - private readonly KafkaOptions _options; - public EventBusKafka(ILogger logger, - IEventBusSubscriptionsManager subsManager, - IKafkaConnectionPool connectionPool, - IOptions options) + var producer = _connectionPool.Producer(); + try { - _logger = logger; - _subsManager = subsManager; - _connectionPool = connectionPool; - _options = options.Value; + var eventName = @event.GetType().Name; + var body = Protobuf.Serialize(JsonConvert.SerializeObject(@event)); + DeliveryResult result = producer.ProduceAsync(_options.Topic, new Message + { + Key = eventName, + Value = body + }).ConfigureAwait(false).GetAwaiter().GetResult(); } - /// - /// 发布 - /// - public void Publish(IntegrationEvent @event) + catch (Exception ex) { - var producer = _connectionPool.Producer(); - try - { - var eventName = @event.GetType().Name; - var body = Protobuf.Serialize(JsonConvert.SerializeObject(@event)); - DeliveryResult result = producer.ProduceAsync(_options.Topic, new Message - { - Key = eventName, - Value = body - }).ConfigureAwait(false).GetAwaiter().GetResult(); - } - catch (Exception ex) - { - _logger.LogWarning($"Could not publish event: {@event.Id.ToString("N")} ({ex.Message}); Message:{ JsonConvert.SerializeObject(@event)}"); - } - finally - { - //放入连接池中 - _connectionPool.Return(producer); - } + _logger.LogWarning($"Could not publish event: {@event.Id.ToString("N")} ({ex.Message}); Message:{ JsonConvert.SerializeObject(@event)}"); } - - /// - /// 订阅 - /// 动态 - /// - /// 事件处理器 - /// 事件名 - public void SubscribeDynamic(string eventName) - where TH : IDynamicIntegrationEventHandler + finally { - _logger.LogInformation("Subscribing to dynamic event {EventName} with {EventHandler}", eventName, typeof(TH).GetGenericTypeName()); - - _subsManager.AddDynamicSubscription(eventName); + //放入连接池中 + _connectionPool.Return(producer); } + } - /// - /// 订阅 - /// - /// 约束:事件模型 - /// 约束:事件处理器<事件模型> - public void Subscribe() - where T : IntegrationEvent - where TH : IIntegrationEventHandler - { - var eventName = _subsManager.GetEventKey(); + /// + /// 订阅 + /// 动态 + /// + /// 事件处理器 + /// 事件名 + public void SubscribeDynamic(string eventName) + where TH : IDynamicIntegrationEventHandler + { + _logger.LogInformation("Subscribing to dynamic event {EventName} with {EventHandler}", eventName, typeof(TH).GetGenericTypeName()); - _logger.LogInformation("Subscribing to event {EventName} with {EventHandler}", eventName, typeof(TH).GetGenericTypeName()); + _subsManager.AddDynamicSubscription(eventName); + } - _subsManager.AddSubscription(); - } + /// + /// 订阅 + /// + /// 约束:事件模型 + /// 约束:事件处理器<事件模型> + public void Subscribe() + where T : IntegrationEvent + where TH : IIntegrationEventHandler + { + var eventName = _subsManager.GetEventKey(); - /// - /// 取消订阅 - /// - /// - /// - public void Unsubscribe() - where T : IntegrationEvent - where TH : IIntegrationEventHandler - { - var eventName = _subsManager.GetEventKey(); + _logger.LogInformation("Subscribing to event {EventName} with {EventHandler}", eventName, typeof(TH).GetGenericTypeName()); - _logger.LogInformation("Unsubscribing from event {EventName}", eventName); + _subsManager.AddSubscription(); + } - _subsManager.RemoveSubscription(); - } + /// + /// 取消订阅 + /// + /// + /// + public void Unsubscribe() + where T : IntegrationEvent + where TH : IIntegrationEventHandler + { + var eventName = _subsManager.GetEventKey(); - public void UnsubscribeDynamic(string eventName) - where TH : IDynamicIntegrationEventHandler - { - _subsManager.RemoveDynamicSubscription(eventName); - } + _logger.LogInformation("Unsubscribing from event {EventName}", eventName); - public void Dispose() + _subsManager.RemoveSubscription(); + } + + public void UnsubscribeDynamic(string eventName) + where TH : IDynamicIntegrationEventHandler + { + _subsManager.RemoveDynamicSubscription(eventName); + } + + public void Dispose() + { + if (_connectionPool != null) { - if (_connectionPool != null) - { - _connectionPool.Dispose(); - } - _subsManager.Clear(); + _connectionPool.Dispose(); } - + _subsManager.Clear(); } + } diff --git a/Tiobon.Core.EventBus/EventBusKafka/IKafkaConnectionPool.cs b/Tiobon.Core.EventBus/EventBusKafka/IKafkaConnectionPool.cs index 5b795831..a46b970a 100644 --- a/Tiobon.Core.EventBus/EventBusKafka/IKafkaConnectionPool.cs +++ b/Tiobon.Core.EventBus/EventBusKafka/IKafkaConnectionPool.cs @@ -1,25 +1,23 @@ using Confluent.Kafka; -using System; -namespace Tiobon.Core.EventBus +namespace Tiobon.Core.EventBus; + +/// +/// Kafka连接池 +/// +public interface IKafkaConnectionPool:IDisposable { /// - /// Kafka连接池 + /// 取对象 /// - public interface IKafkaConnectionPool:IDisposable - { - /// - /// 取对象 - /// - /// - IProducer Producer(); + /// + IProducer Producer(); - /// - /// 将对象放入连接池 - /// - /// - /// - bool Return(IProducer producer); - } + /// + /// 将对象放入连接池 + /// + /// + /// + bool Return(IProducer producer); } diff --git a/Tiobon.Core.EventBus/EventBusKafka/KafkaConnectionPool.cs b/Tiobon.Core.EventBus/EventBusKafka/KafkaConnectionPool.cs index c5158dc4..e85d655f 100644 --- a/Tiobon.Core.EventBus/EventBusKafka/KafkaConnectionPool.cs +++ b/Tiobon.Core.EventBus/EventBusKafka/KafkaConnectionPool.cs @@ -1,79 +1,76 @@ using Confluent.Kafka; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System.Collections.Concurrent; -using System.Threading; -namespace Tiobon.Core.EventBus +namespace Tiobon.Core.EventBus; + +/// +/// Kafka producer 连接池管理 +/// 可以使用微软官方的对象池进行构造ObjectPool +/// +public class KafkaConnectionPool : IKafkaConnectionPool { + private readonly KafkaOptions _options; + private ConcurrentQueue> _producerPool = new(); + private int _currentCount; + private int _maxSize; + public KafkaConnectionPool(IOptions options) + { + _options = options.Value; + _maxSize = _options.ConnectionPoolSize; + } + /// - /// Kafka producer 连接池管理 - /// 可以使用微软官方的对象池进行构造ObjectPool + /// 取对象 /// - public class KafkaConnectionPool : IKafkaConnectionPool + /// + public IProducer Producer() { - private readonly KafkaOptions _options; - private ConcurrentQueue> _producerPool = new(); - private int _currentCount; - private int _maxSize; - public KafkaConnectionPool(IOptions options) + if (_producerPool.TryDequeue(out var producer)) { - _options = options.Value; - _maxSize = _options.ConnectionPoolSize; + Interlocked.Decrement(ref _currentCount); + return producer; } - /// - /// 取对象 - /// - /// - public IProducer Producer() + var config = new ProducerConfig() { - if (_producerPool.TryDequeue(out var producer)) - { - Interlocked.Decrement(ref _currentCount); - return producer; - } - - var config = new ProducerConfig() - { - BootstrapServers = _options.Servers, - QueueBufferingMaxMessages = 10, - MessageTimeoutMs = 5000, - RequestTimeoutMs = 3000 - }; + BootstrapServers = _options.Servers, + QueueBufferingMaxMessages = 10, + MessageTimeoutMs = 5000, + RequestTimeoutMs = 3000 + }; - producer = new ProducerBuilder(config) - .Build(); - return producer; - } - /// - /// 将对象放入连接池 - /// - /// - /// - public bool Return(IProducer producer) + producer = new ProducerBuilder(config) + .Build(); + return producer; + } + /// + /// 将对象放入连接池 + /// + /// + /// + public bool Return(IProducer producer) + { + if (Interlocked.Increment(ref _currentCount) <= _maxSize) { - if (Interlocked.Increment(ref _currentCount) <= _maxSize) - { - _producerPool.Enqueue(producer); - return true; - } + _producerPool.Enqueue(producer); + return true; + } - producer.Dispose(); - Interlocked.Decrement(ref _currentCount); + producer.Dispose(); + Interlocked.Decrement(ref _currentCount); - return false; - } - public void Dispose() + return false; + } + public void Dispose() + { + _maxSize = 0; + _currentCount = 0; + while (_producerPool.TryDequeue(out var context)) { - _maxSize = 0; - _currentCount = 0; - while (_producerPool.TryDequeue(out var context)) - { - context?.Dispose(); - } + context?.Dispose(); } - } + } diff --git a/Tiobon.Core.EventBus/EventBusKafka/KafkaConsumerHostService.cs b/Tiobon.Core.EventBus/EventBusKafka/KafkaConsumerHostService.cs index 50835e39..25b3be8f 100644 --- a/Tiobon.Core.EventBus/EventBusKafka/KafkaConsumerHostService.cs +++ b/Tiobon.Core.EventBus/EventBusKafka/KafkaConsumerHostService.cs @@ -6,157 +6,152 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using System; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -namespace Tiobon.Core.EventBus +namespace Tiobon.Core.EventBus; + +/// +/// Kafka consumer 监听服务 +/// +public class KafkaConsumerHostService : BackgroundService { - /// - /// Kafka consumer 监听服务 - /// - public class KafkaConsumerHostService : BackgroundService + private readonly string AUTOFAC_SCOPE_NAME = "Tioboncore_event_bus"; + private readonly ILogger _logger; + private readonly IConsumer _consumer; + private readonly KafkaOptions _options; + private readonly IEventBusSubscriptionsManager _subsManager; + private readonly ILifetimeScope _autofac; + private CancellationTokenSource cts = new(); + public KafkaConsumerHostService(ILogger logger, + IOptions options, + IEventBusSubscriptionsManager eventBusSubscriptionsManager, + ILifetimeScope autofac) { - private readonly string AUTOFAC_SCOPE_NAME = "Tioboncore_event_bus"; - private readonly ILogger _logger; - private readonly IConsumer _consumer; - private readonly KafkaOptions _options; - private readonly IEventBusSubscriptionsManager _subsManager; - private readonly ILifetimeScope _autofac; - private CancellationTokenSource cts = new(); - public KafkaConsumerHostService(ILogger logger, - IOptions options, - IEventBusSubscriptionsManager eventBusSubscriptionsManager, - ILifetimeScope autofac) + _autofac = autofac; + _subsManager = eventBusSubscriptionsManager; + _logger = logger; + _options = options.Value; + _consumer = new ConsumerBuilder(new ConsumerConfig { - _autofac = autofac; - _subsManager = eventBusSubscriptionsManager; - _logger = logger; - _options = options.Value; - _consumer = new ConsumerBuilder(new ConsumerConfig - { - BootstrapServers = _options.Servers, - GroupId = _options.GroupId, - AutoOffsetReset = AutoOffsetReset.Earliest, - AllowAutoCreateTopics = true, - EnableAutoCommit = false, - LogConnectionClose = false - }).SetErrorHandler(ConsumerClient_OnConsumeError) - .Build(); - } - protected override async Task ExecuteAsync(CancellationToken stoppingToken) + BootstrapServers = _options.Servers, + GroupId = _options.GroupId, + AutoOffsetReset = AutoOffsetReset.Earliest, + AllowAutoCreateTopics = true, + EnableAutoCommit = false, + LogConnectionClose = false + }).SetErrorHandler(ConsumerClient_OnConsumeError) + .Build(); + } + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + var result = await FetchTopicAsync(); + if (result) { - var result = await FetchTopicAsync(); - if (result) + _consumer.Subscribe(_options.Topic); + while (!cts.Token.IsCancellationRequested) { - _consumer.Subscribe(_options.Topic); - while (!cts.Token.IsCancellationRequested) + var consumerResult = _consumer.Consume(cts.Token); + try { - var consumerResult = _consumer.Consume(cts.Token); - try - { - if (consumerResult.IsPartitionEOF || consumerResult.Message.Value == null) continue; + if (consumerResult.IsPartitionEOF || consumerResult.Message.Value == null) continue; - var @event = Protobuf.Deserialize(consumerResult.Message.Value); - await ProcessEvent(consumerResult.Message.Key, @event); - } - catch (ConsumeException e) - { - _logger.LogError($"Error occured: {e.Error.Reason}"); - } - finally - { - _consumer.Commit(consumerResult); - } + var @event = Protobuf.Deserialize(consumerResult.Message.Value); + await ProcessEvent(consumerResult.Message.Key, @event); + } + catch (ConsumeException e) + { + _logger.LogError($"Error occured: {e.Error.Reason}"); + } + finally + { + _consumer.Commit(consumerResult); } } } - public override Task StopAsync(CancellationToken cancellationToken) + } + public override Task StopAsync(CancellationToken cancellationToken) + { + cts.Cancel(); + _logger.LogInformation("kafka consumer stop and disposable"); + _consumer.Dispose(); + return base.StopAsync(cancellationToken); + } + /// + /// 检测当前Topic是否存在 + /// + /// + private async Task FetchTopicAsync() + { + if (string.IsNullOrEmpty(_options.Topic)) + throw new ArgumentNullException(nameof(_options.Topic)); + + try { - cts.Cancel(); - _logger.LogInformation("kafka consumer stop and disposable"); - _consumer.Dispose(); - return base.StopAsync(cancellationToken); + var config = new AdminClientConfig { BootstrapServers = _options.Servers }; + using var adminClient = new AdminClientBuilder(config).Build(); + await adminClient.CreateTopicsAsync(Enumerable.Range(0,1).Select(u=> new TopicSpecification + { + Name = _options.Topic, + NumPartitions = _options.NumPartitions + })); } - /// - /// 检测当前Topic是否存在 - /// - /// - private async Task FetchTopicAsync() + catch (CreateTopicsException ex) when (ex.Message.Contains("already exists")) { - if (string.IsNullOrEmpty(_options.Topic)) - throw new ArgumentNullException(nameof(_options.Topic)); - - try - { - var config = new AdminClientConfig { BootstrapServers = _options.Servers }; - using var adminClient = new AdminClientBuilder(config).Build(); - await adminClient.CreateTopicsAsync(Enumerable.Range(0,1).Select(u=> new TopicSpecification - { - Name = _options.Topic, - NumPartitions = _options.NumPartitions - })); - } - catch (CreateTopicsException ex) when (ex.Message.Contains("already exists")) - { - } - catch (Exception ex) - { - _logger.LogError("An error was encountered when automatically creating topic! -->" + ex.Message); - return false; - } - return true; } - /// - /// 接收到消息进行处理 - /// - /// 事件名称 - /// 消息内容 - /// - private async Task ProcessEvent(string eventName, string message) + catch (Exception ex) { - _logger.LogTrace("Processing Kafka event: {EventName}", eventName); + _logger.LogError("An error was encountered when automatically creating topic! -->" + ex.Message); + return false; + } + return true; + } + /// + /// 接收到消息进行处理 + /// + /// 事件名称 + /// 消息内容 + /// + private async Task ProcessEvent(string eventName, string message) + { + _logger.LogTrace("Processing Kafka event: {EventName}", eventName); - if (_subsManager.HasSubscriptionsForEvent(eventName)) + if (_subsManager.HasSubscriptionsForEvent(eventName)) + { + using (var scope = _autofac.BeginLifetimeScope(AUTOFAC_SCOPE_NAME)) { - using (var scope = _autofac.BeginLifetimeScope(AUTOFAC_SCOPE_NAME)) + var subscriptions = _subsManager.GetHandlersForEvent(eventName); + foreach (var subscription in subscriptions) { - var subscriptions = _subsManager.GetHandlersForEvent(eventName); - foreach (var subscription in subscriptions) + if (subscription.IsDynamic) { - if (subscription.IsDynamic) - { - var handler = scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler; - if (handler == null) continue; - dynamic eventData = JObject.Parse(message); + var handler = scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler; + if (handler == null) continue; + dynamic eventData = JObject.Parse(message); - await Task.Yield(); - await handler.Handle(eventData); - } - else - { - var handler = scope.ResolveOptional(subscription.HandlerType); - if (handler == null) continue; - var eventType = _subsManager.GetEventTypeByName(eventName); - var integrationEvent = JsonConvert.DeserializeObject(message, eventType); - var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType); + await Task.Yield(); + await handler.Handle(eventData); + } + else + { + var handler = scope.ResolveOptional(subscription.HandlerType); + if (handler == null) continue; + var eventType = _subsManager.GetEventTypeByName(eventName); + var integrationEvent = JsonConvert.DeserializeObject(message, eventType); + var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType); - await Task.Yield(); - await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent }); - } + await Task.Yield(); + await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent }); } } } - else - { - _logger.LogWarning("No subscription for Kafka event: {EventName}", eventName); - } } - - private void ConsumerClient_OnConsumeError(IConsumer consumer, Error e) + else { - _logger.LogError("An error occurred during connect kafka:" + e.Reason); + _logger.LogWarning("No subscription for Kafka event: {EventName}", eventName); } } + + private void ConsumerClient_OnConsumeError(IConsumer consumer, Error e) + { + _logger.LogError("An error occurred during connect kafka:" + e.Reason); + } } diff --git a/Tiobon.Core.EventBus/EventBusKafka/KafkaOptions.cs b/Tiobon.Core.EventBus/EventBusKafka/KafkaOptions.cs index 0b2874a5..d464f208 100644 --- a/Tiobon.Core.EventBus/EventBusKafka/KafkaOptions.cs +++ b/Tiobon.Core.EventBus/EventBusKafka/KafkaOptions.cs @@ -1,28 +1,27 @@  -namespace Tiobon.Core.EventBus +namespace Tiobon.Core.EventBus; + +/// +/// Kafka 配置项 +/// +public class KafkaOptions { + public int ConnectionPoolSize { get; set; } = 10; + /// + /// 地址 + /// + public string Servers { get; set; } + /// + /// 主题 + /// + public string Topic { get; set; } + /// + /// 消费者组Id + /// + public string GroupId { get; set; } /// - /// Kafka 配置项 + /// 主题分区 /// - public class KafkaOptions - { - public int ConnectionPoolSize { get; set; } = 10; - /// - /// 地址 - /// - public string Servers { get; set; } - /// - /// 主题 - /// - public string Topic { get; set; } - /// - /// 消费者组Id - /// - public string GroupId { get; set; } - /// - /// 主题分区 - /// - public int NumPartitions { get; set; } - } + public int NumPartitions { get; set; } } diff --git a/Tiobon.Core.EventBus/EventBusKafka/ProtobufTransfer.cs b/Tiobon.Core.EventBus/EventBusKafka/ProtobufTransfer.cs index 5506fcb7..1eed9d32 100644 --- a/Tiobon.Core.EventBus/EventBusKafka/ProtobufTransfer.cs +++ b/Tiobon.Core.EventBus/EventBusKafka/ProtobufTransfer.cs @@ -1,32 +1,29 @@ -using System; -using System.IO; -namespace Tiobon.Core.EventBus +namespace Tiobon.Core.EventBus; + +public class Protobuf { - public class Protobuf + /// + /// Protobuf 反序列化 + /// + public static T Deserialize(ReadOnlySpan data) + { + Stream stream = new MemoryStream(data.ToArray()); + var info = ProtoBuf.Serializer.Deserialize(stream); + return info; + } + /// + /// 通过Protobuf 转字节 + /// + public static byte[] Serialize(T data) { - /// - /// Protobuf 反序列化 - /// - public static T Deserialize(ReadOnlySpan data) + byte[] datas; + using (var stream = new MemoryStream()) { - Stream stream = new MemoryStream(data.ToArray()); - var info = ProtoBuf.Serializer.Deserialize(stream); - return info; + ProtoBuf.Serializer.Serialize(stream, data); + datas = stream.ToArray(); } - /// - /// 通过Protobuf 转字节 - /// - public static byte[] Serialize(T data) - { - byte[] datas; - using (var stream = new MemoryStream()) - { - ProtoBuf.Serializer.Serialize(stream, data); - datas = stream.ToArray(); - } - return datas; + return datas; - } } } diff --git a/Tiobon.Core.EventBus/EventBusSubscriptions/InMemoryEventBusSubscriptionsManager.cs b/Tiobon.Core.EventBus/EventBusSubscriptions/InMemoryEventBusSubscriptionsManager.cs index f6dee763..5bba7c7c 100644 --- a/Tiobon.Core.EventBus/EventBusSubscriptions/InMemoryEventBusSubscriptionsManager.cs +++ b/Tiobon.Core.EventBus/EventBusSubscriptions/InMemoryEventBusSubscriptionsManager.cs @@ -1,183 +1,177 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Tiobon.Core.EventBus +namespace Tiobon.Core.EventBus; + +/// +/// 基于内存 +/// 事件总线订阅管理器 +/// 单例模式 +/// +public partial class InMemoryEventBusSubscriptionsManager : IEventBusSubscriptionsManager { + private readonly Dictionary> _handlers; + private readonly List _eventTypes; + + public event EventHandler OnEventRemoved; + + public InMemoryEventBusSubscriptionsManager() + { + _handlers = new Dictionary>(); + _eventTypes = new List(); + } + + public bool IsEmpty => !_handlers.Keys.Any(); + public void Clear() => _handlers.Clear(); + /// - /// 基于内存 - /// 事件总线订阅管理器 - /// 单例模式 + /// 添加动态订阅 /// - public partial class InMemoryEventBusSubscriptionsManager : IEventBusSubscriptionsManager + /// 约束:动态事件处理器接口 + /// + public void AddDynamicSubscription(string eventName) + where TH : IDynamicIntegrationEventHandler { - private readonly Dictionary> _handlers; - private readonly List _eventTypes; + DoAddSubscription(typeof(TH), eventName, isDynamic: true); + } - public event EventHandler OnEventRemoved; + /// + /// 添加订阅 + /// + /// 约束:事件 + /// 约束:事件处理器接口<事件> + public void AddSubscription() + where T : IntegrationEvent + where TH : IIntegrationEventHandler + { + var eventName = GetEventKey(); + + DoAddSubscription(typeof(TH), eventName, isDynamic: false); - public InMemoryEventBusSubscriptionsManager() + if (!_eventTypes.Contains(typeof(T))) { - _handlers = new Dictionary>(); - _eventTypes = new List(); + _eventTypes.Add(typeof(T)); } + } - public bool IsEmpty => !_handlers.Keys.Any(); - public void Clear() => _handlers.Clear(); - - /// - /// 添加动态订阅 - /// - /// 约束:动态事件处理器接口 - /// - public void AddDynamicSubscription(string eventName) - where TH : IDynamicIntegrationEventHandler + private void DoAddSubscription(Type handlerType, string eventName, bool isDynamic) + { + if (!HasSubscriptionsForEvent(eventName)) { - DoAddSubscription(typeof(TH), eventName, isDynamic: true); + _handlers.Add(eventName, new List()); } - /// - /// 添加订阅 - /// - /// 约束:事件 - /// 约束:事件处理器接口<事件> - public void AddSubscription() - where T : IntegrationEvent - where TH : IIntegrationEventHandler + if (_handlers[eventName].Any(s => s.HandlerType == handlerType)) { - var eventName = GetEventKey(); - - DoAddSubscription(typeof(TH), eventName, isDynamic: false); - - if (!_eventTypes.Contains(typeof(T))) - { - _eventTypes.Add(typeof(T)); - } + throw new ArgumentException( + $"Handler Type {handlerType.Name} already registered for '{eventName}'", nameof(handlerType)); } - private void DoAddSubscription(Type handlerType, string eventName, bool isDynamic) + if (isDynamic) { - if (!HasSubscriptionsForEvent(eventName)) - { - _handlers.Add(eventName, new List()); - } - - if (_handlers[eventName].Any(s => s.HandlerType == handlerType)) - { - throw new ArgumentException( - $"Handler Type {handlerType.Name} already registered for '{eventName}'", nameof(handlerType)); - } - - if (isDynamic) - { - _handlers[eventName].Add(SubscriptionInfo.Dynamic(handlerType)); - } - else - { - _handlers[eventName].Add(SubscriptionInfo.Typed(handlerType)); - } + _handlers[eventName].Add(SubscriptionInfo.Dynamic(handlerType)); } - - /// - /// 移除动态订阅 - /// - /// - /// - public void RemoveDynamicSubscription(string eventName) - where TH : IDynamicIntegrationEventHandler + else { - var handlerToRemove = FindDynamicSubscriptionToRemove(eventName); - DoRemoveHandler(eventName, handlerToRemove); + _handlers[eventName].Add(SubscriptionInfo.Typed(handlerType)); } + } + /// + /// 移除动态订阅 + /// + /// + /// + public void RemoveDynamicSubscription(string eventName) + where TH : IDynamicIntegrationEventHandler + { + var handlerToRemove = FindDynamicSubscriptionToRemove(eventName); + DoRemoveHandler(eventName, handlerToRemove); + } - public void RemoveSubscription() - where TH : IIntegrationEventHandler - where T : IntegrationEvent - { - var handlerToRemove = FindSubscriptionToRemove(); - var eventName = GetEventKey(); - DoRemoveHandler(eventName, handlerToRemove); - } + + public void RemoveSubscription() + where TH : IIntegrationEventHandler + where T : IntegrationEvent + { + var handlerToRemove = FindSubscriptionToRemove(); + var eventName = GetEventKey(); + DoRemoveHandler(eventName, handlerToRemove); + } - private void DoRemoveHandler(string eventName, SubscriptionInfo subsToRemove) + private void DoRemoveHandler(string eventName, SubscriptionInfo subsToRemove) + { + if (subsToRemove != null) { - if (subsToRemove != null) + _handlers[eventName].Remove(subsToRemove); + if (!_handlers[eventName].Any()) { - _handlers[eventName].Remove(subsToRemove); - if (!_handlers[eventName].Any()) + _handlers.Remove(eventName); + var eventType = _eventTypes.SingleOrDefault(e => e.Name == eventName); + if (eventType != null) { - _handlers.Remove(eventName); - var eventType = _eventTypes.SingleOrDefault(e => e.Name == eventName); - if (eventType != null) - { - _eventTypes.Remove(eventType); - } - RaiseOnEventRemoved(eventName); + _eventTypes.Remove(eventType); } - + RaiseOnEventRemoved(eventName); } - } - public IEnumerable GetHandlersForEvent() where T : IntegrationEvent - { - var key = GetEventKey(); - return GetHandlersForEvent(key); } - public IEnumerable GetHandlersForEvent(string eventName) => _handlers[eventName]; - - private void RaiseOnEventRemoved(string eventName) - { - var handler = OnEventRemoved; - handler?.Invoke(this, eventName); - } - + } - private SubscriptionInfo FindDynamicSubscriptionToRemove(string eventName) - where TH : IDynamicIntegrationEventHandler - { - return DoFindSubscriptionToRemove(eventName, typeof(TH)); - } + public IEnumerable GetHandlersForEvent() where T : IntegrationEvent + { + var key = GetEventKey(); + return GetHandlersForEvent(key); + } + public IEnumerable GetHandlersForEvent(string eventName) => _handlers[eventName]; - /// - /// 查询订阅并移除 - /// - /// - /// - /// - private SubscriptionInfo FindSubscriptionToRemove() - where T : IntegrationEvent - where TH : IIntegrationEventHandler - { - var eventName = GetEventKey(); - return DoFindSubscriptionToRemove(eventName, typeof(TH)); - } + private void RaiseOnEventRemoved(string eventName) + { + var handler = OnEventRemoved; + handler?.Invoke(this, eventName); + } - private SubscriptionInfo DoFindSubscriptionToRemove(string eventName, Type handlerType) - { - if (!HasSubscriptionsForEvent(eventName)) - { - return null; - } - return _handlers[eventName].SingleOrDefault(s => s.HandlerType == handlerType); + private SubscriptionInfo FindDynamicSubscriptionToRemove(string eventName) + where TH : IDynamicIntegrationEventHandler + { + return DoFindSubscriptionToRemove(eventName, typeof(TH)); + } - } + /// + /// 查询订阅并移除 + /// + /// + /// + /// + private SubscriptionInfo FindSubscriptionToRemove() + where T : IntegrationEvent + where TH : IIntegrationEventHandler + { + var eventName = GetEventKey(); + return DoFindSubscriptionToRemove(eventName, typeof(TH)); + } - public bool HasSubscriptionsForEvent() where T : IntegrationEvent + private SubscriptionInfo DoFindSubscriptionToRemove(string eventName, Type handlerType) + { + if (!HasSubscriptionsForEvent(eventName)) { - var key = GetEventKey(); - return HasSubscriptionsForEvent(key); + return null; } - public bool HasSubscriptionsForEvent(string eventName) => _handlers.ContainsKey(eventName); - public Type GetEventTypeByName(string eventName) => _eventTypes.SingleOrDefault(t => t.Name == eventName); + return _handlers[eventName].SingleOrDefault(s => s.HandlerType == handlerType); - public string GetEventKey() - { - return typeof(T).Name; - } } + public bool HasSubscriptionsForEvent() where T : IntegrationEvent + { + var key = GetEventKey(); + return HasSubscriptionsForEvent(key); + } + public bool HasSubscriptionsForEvent(string eventName) => _handlers.ContainsKey(eventName); + + public Type GetEventTypeByName(string eventName) => _eventTypes.SingleOrDefault(t => t.Name == eventName); + + public string GetEventKey() + { + return typeof(T).Name; + } } diff --git a/Tiobon.Core.EventBus/EventBusSubscriptions/SubscriptionInfo.cs b/Tiobon.Core.EventBus/EventBusSubscriptions/SubscriptionInfo.cs index 69f214da..87b4421c 100644 --- a/Tiobon.Core.EventBus/EventBusSubscriptions/SubscriptionInfo.cs +++ b/Tiobon.Core.EventBus/EventBusSubscriptions/SubscriptionInfo.cs @@ -1,29 +1,25 @@ -using System; +namespace Tiobon.Core.EventBus; -namespace Tiobon.Core.EventBus +/// +/// 订阅信息模型 +/// +public class SubscriptionInfo { - /// - /// 订阅信息模型 - /// - public class SubscriptionInfo - { - public bool IsDynamic { get; } - public Type HandlerType { get; } - - private SubscriptionInfo(bool isDynamic, Type handlerType) - { - IsDynamic = isDynamic; - HandlerType = handlerType; - } + public bool IsDynamic { get; } + public Type HandlerType { get; } - public static SubscriptionInfo Dynamic(Type handlerType) - { - return new SubscriptionInfo(true, handlerType); - } - public static SubscriptionInfo Typed(Type handlerType) - { - return new SubscriptionInfo(false, handlerType); - } + private SubscriptionInfo(bool isDynamic, Type handlerType) + { + IsDynamic = isDynamic; + HandlerType = handlerType; } + public static SubscriptionInfo Dynamic(Type handlerType) + { + return new SubscriptionInfo(true, handlerType); + } + public static SubscriptionInfo Typed(Type handlerType) + { + return new SubscriptionInfo(false, handlerType); + } } diff --git a/Tiobon.Core.EventBus/Eventbus/IDynamicIntegrationEventHandler.cs b/Tiobon.Core.EventBus/Eventbus/IDynamicIntegrationEventHandler.cs index 70e3f493..f35a81d4 100644 --- a/Tiobon.Core.EventBus/Eventbus/IDynamicIntegrationEventHandler.cs +++ b/Tiobon.Core.EventBus/Eventbus/IDynamicIntegrationEventHandler.cs @@ -1,13 +1,10 @@ -using System.Threading.Tasks; +namespace Tiobon.Core.EventBus; -namespace Tiobon.Core.EventBus +/// +/// 动态集成事件处理程序 +/// 接口 +/// +public interface IDynamicIntegrationEventHandler { - /// - /// 动态集成事件处理程序 - /// 接口 - /// - public interface IDynamicIntegrationEventHandler - { - Task Handle(dynamic eventData); - } + Task Handle(dynamic eventData); } diff --git a/Tiobon.Core.EventBus/Eventbus/IEventBus.cs b/Tiobon.Core.EventBus/Eventbus/IEventBus.cs index bbad75a5..8a1b1fb8 100644 --- a/Tiobon.Core.EventBus/Eventbus/IEventBus.cs +++ b/Tiobon.Core.EventBus/Eventbus/IEventBus.cs @@ -1,49 +1,48 @@ -namespace Tiobon.Core.EventBus +namespace Tiobon.Core.EventBus; + +/// +/// 事件总线 +/// 接口 +/// +public interface IEventBus { /// - /// 事件总线 - /// 接口 + /// 发布 /// - public interface IEventBus - { - /// - /// 发布 - /// - /// 事件模型 - void Publish(IntegrationEvent @event); + /// 事件模型 + void Publish(IntegrationEvent @event); - /// - /// 订阅 - /// - /// 约束:事件模型 - /// 约束:事件处理器<事件模型> - void Subscribe() - where T : IntegrationEvent - where TH : IIntegrationEventHandler; + /// + /// 订阅 + /// + /// 约束:事件模型 + /// 约束:事件处理器<事件模型> + void Subscribe() + where T : IntegrationEvent + where TH : IIntegrationEventHandler; - /// - /// 取消订阅 - /// - /// - /// - void Unsubscribe() - where TH : IIntegrationEventHandler - where T : IntegrationEvent; + /// + /// 取消订阅 + /// + /// + /// + void Unsubscribe() + where TH : IIntegrationEventHandler + where T : IntegrationEvent; - /// - /// 动态订阅 - /// - /// 约束:事件处理器 - /// - void SubscribeDynamic(string eventName) - where TH : IDynamicIntegrationEventHandler; + /// + /// 动态订阅 + /// + /// 约束:事件处理器 + /// + void SubscribeDynamic(string eventName) + where TH : IDynamicIntegrationEventHandler; - /// - /// 动态取消订阅 - /// - /// - /// - void UnsubscribeDynamic(string eventName) - where TH : IDynamicIntegrationEventHandler; - } + /// + /// 动态取消订阅 + /// + /// + /// + void UnsubscribeDynamic(string eventName) + where TH : IDynamicIntegrationEventHandler; } diff --git a/Tiobon.Core.EventBus/Eventbus/IEventBusSubscriptionsManager.cs b/Tiobon.Core.EventBus/Eventbus/IEventBusSubscriptionsManager.cs index 1de9fe7a..c6e7d89a 100644 --- a/Tiobon.Core.EventBus/Eventbus/IEventBusSubscriptionsManager.cs +++ b/Tiobon.Core.EventBus/Eventbus/IEventBusSubscriptionsManager.cs @@ -1,36 +1,31 @@ -using System; -using System.Collections.Generic; +namespace Tiobon.Core.EventBus; -namespace Tiobon.Core.EventBus +/// +/// 事件总线订阅管理器 +/// 接口 +/// +public interface IEventBusSubscriptionsManager { - /// - /// 事件总线订阅管理器 - /// 接口 - /// - public interface IEventBusSubscriptionsManager - { - bool IsEmpty { get; } - event EventHandler OnEventRemoved; - void AddDynamicSubscription(string eventName) - where TH : IDynamicIntegrationEventHandler; + bool IsEmpty { get; } + event EventHandler OnEventRemoved; + void AddDynamicSubscription(string eventName) + where TH : IDynamicIntegrationEventHandler; - void AddSubscription() - where T : IntegrationEvent - where TH : IIntegrationEventHandler; + void AddSubscription() + where T : IntegrationEvent + where TH : IIntegrationEventHandler; - void RemoveSubscription() - where TH : IIntegrationEventHandler - where T : IntegrationEvent; - void RemoveDynamicSubscription(string eventName) - where TH : IDynamicIntegrationEventHandler; - - bool HasSubscriptionsForEvent() where T : IntegrationEvent; - bool HasSubscriptionsForEvent(string eventName); - Type GetEventTypeByName(string eventName); - void Clear(); - IEnumerable GetHandlersForEvent() where T : IntegrationEvent; - IEnumerable GetHandlersForEvent(string eventName); - string GetEventKey(); - } + void RemoveSubscription() + where TH : IIntegrationEventHandler + where T : IntegrationEvent; + void RemoveDynamicSubscription(string eventName) + where TH : IDynamicIntegrationEventHandler; + bool HasSubscriptionsForEvent() where T : IntegrationEvent; + bool HasSubscriptionsForEvent(string eventName); + Type GetEventTypeByName(string eventName); + void Clear(); + IEnumerable GetHandlersForEvent() where T : IntegrationEvent; + IEnumerable GetHandlersForEvent(string eventName); + string GetEventKey(); } diff --git a/Tiobon.Core.EventBus/Eventbus/IIntegrationEventHandler.cs b/Tiobon.Core.EventBus/Eventbus/IIntegrationEventHandler.cs index af96493c..814335d0 100644 --- a/Tiobon.Core.EventBus/Eventbus/IIntegrationEventHandler.cs +++ b/Tiobon.Core.EventBus/Eventbus/IIntegrationEventHandler.cs @@ -1,23 +1,20 @@ -using System.Threading.Tasks; +namespace Tiobon.Core.EventBus; -namespace Tiobon.Core.EventBus +/// +/// 集成事件处理程序 +/// 泛型接口 +/// +/// +public interface IIntegrationEventHandler : IIntegrationEventHandler + where TIntegrationEvent : IntegrationEvent { - /// - /// 集成事件处理程序 - /// 泛型接口 - /// - /// - public interface IIntegrationEventHandler : IIntegrationEventHandler - where TIntegrationEvent : IntegrationEvent - { - Task Handle(TIntegrationEvent @event); - } + Task Handle(TIntegrationEvent @event); +} - /// - /// 集成事件处理程序 - /// 基 接口 - /// - public interface IIntegrationEventHandler - { - } +/// +/// 集成事件处理程序 +/// 基 接口 +/// +public interface IIntegrationEventHandler +{ } diff --git a/Tiobon.Core.EventBus/Eventbus/IntegrationEvent.cs b/Tiobon.Core.EventBus/Eventbus/IntegrationEvent.cs index 6b47ea22..3021255c 100644 --- a/Tiobon.Core.EventBus/Eventbus/IntegrationEvent.cs +++ b/Tiobon.Core.EventBus/Eventbus/IntegrationEvent.cs @@ -1,31 +1,29 @@ using Newtonsoft.Json; -using System; -namespace Tiobon.Core.EventBus +namespace Tiobon.Core.EventBus; + +/// +/// 事件模型 +/// 基类 +/// +public class IntegrationEvent { - /// - /// 事件模型 - /// 基类 - /// - public class IntegrationEvent + public IntegrationEvent() { - public IntegrationEvent() - { - Id = Guid.NewGuid(); - CreationDate = DateTime.UtcNow; - } + Id = Guid.NewGuid(); + CreationDate = DateTime.UtcNow; + } - [JsonConstructor] - public IntegrationEvent(Guid id, DateTime createDate) - { - Id = id; - CreationDate = createDate; - } + [JsonConstructor] + public IntegrationEvent(Guid id, DateTime createDate) + { + Id = id; + CreationDate = createDate; + } - [JsonProperty] - public Guid Id { get; private set; } + [JsonProperty] + public Guid Id { get; private set; } - [JsonProperty] - public DateTime CreationDate { get; private set; } - } + [JsonProperty] + public DateTime CreationDate { get; private set; } } diff --git a/Tiobon.Core.EventBus/RabbitMQPersistent/EventBusRabbitMQ.cs b/Tiobon.Core.EventBus/RabbitMQPersistent/EventBusRabbitMQ.cs index 1b3cbf57..9c0ea848 100644 --- a/Tiobon.Core.EventBus/RabbitMQPersistent/EventBusRabbitMQ.cs +++ b/Tiobon.Core.EventBus/RabbitMQPersistent/EventBusRabbitMQ.cs @@ -11,341 +11,340 @@ using System.Net.Sockets; using System.Text; using Tiobon.Core.Extensions; -namespace Tiobon.Core.EventBus +namespace Tiobon.Core.EventBus; + +/// +/// 基于RabbitMQ的事件总线 +/// +public class EventBusRabbitMQ : IEventBus, IDisposable { + const string BROKER_NAME = "Tioboncore_event_bus"; + + private readonly IRabbitMQPersistentConnection _persistentConnection; + private readonly ILogger _logger; + private readonly IEventBusSubscriptionsManager _subsManager; + private readonly ILifetimeScope _autofac; + private readonly string AUTOFAC_SCOPE_NAME = "Tioboncore_event_bus"; + private readonly int _retryCount; + + private IModel _consumerChannel; + private string _queueName; + + /// + /// RabbitMQ事件总线 + /// + /// RabbitMQ持久连接 + /// 日志 + /// autofac容器 + /// 事件总线订阅管理器 + /// 队列名称 + /// 重试次数 + public EventBusRabbitMQ(IRabbitMQPersistentConnection persistentConnection, ILogger logger, + ILifetimeScope autofac, + IEventBusSubscriptionsManager subsManager, + string queueName = null, + int retryCount = 5) + { + _persistentConnection = persistentConnection ?? throw new ArgumentNullException(nameof(persistentConnection)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _subsManager = subsManager ?? new InMemoryEventBusSubscriptionsManager(); + _queueName = queueName; + _consumerChannel = CreateConsumerChannel(); + _autofac = autofac; + _retryCount = retryCount; + _subsManager.OnEventRemoved += SubsManager_OnEventRemoved; + } + /// - /// 基于RabbitMQ的事件总线 + /// 订阅管理器事件 /// - public class EventBusRabbitMQ : IEventBus, IDisposable + /// + /// + private void SubsManager_OnEventRemoved(object sender, string eventName) { - const string BROKER_NAME = "Tioboncore_event_bus"; - - private readonly IRabbitMQPersistentConnection _persistentConnection; - private readonly ILogger _logger; - private readonly IEventBusSubscriptionsManager _subsManager; - private readonly ILifetimeScope _autofac; - private readonly string AUTOFAC_SCOPE_NAME = "Tioboncore_event_bus"; - private readonly int _retryCount; - - private IModel _consumerChannel; - private string _queueName; - - /// - /// RabbitMQ事件总线 - /// - /// RabbitMQ持久连接 - /// 日志 - /// autofac容器 - /// 事件总线订阅管理器 - /// 队列名称 - /// 重试次数 - public EventBusRabbitMQ(IRabbitMQPersistentConnection persistentConnection, ILogger logger, - ILifetimeScope autofac, - IEventBusSubscriptionsManager subsManager, - string queueName = null, - int retryCount = 5) + if (!_persistentConnection.IsConnected) { - _persistentConnection = persistentConnection ?? throw new ArgumentNullException(nameof(persistentConnection)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _subsManager = subsManager ?? new InMemoryEventBusSubscriptionsManager(); - _queueName = queueName; - _consumerChannel = CreateConsumerChannel(); - _autofac = autofac; - _retryCount = retryCount; - _subsManager.OnEventRemoved += SubsManager_OnEventRemoved; + _persistentConnection.TryConnect(); } - /// - /// 订阅管理器事件 - /// - /// - /// - private void SubsManager_OnEventRemoved(object sender, string eventName) + using (var channel = _persistentConnection.CreateModel()) { - if (!_persistentConnection.IsConnected) - { - _persistentConnection.TryConnect(); - } + channel.QueueUnbind(queue: _queueName, + exchange: BROKER_NAME, + routingKey: eventName); - using (var channel = _persistentConnection.CreateModel()) + if (_subsManager.IsEmpty) { - channel.QueueUnbind(queue: _queueName, - exchange: BROKER_NAME, - routingKey: eventName); - - if (_subsManager.IsEmpty) - { - _queueName = string.Empty; - _consumerChannel.Close(); - } + _queueName = string.Empty; + _consumerChannel.Close(); } } + } - /// - /// 发布 - /// - /// 事件模型 - public void Publish(IntegrationEvent @event) + /// + /// 发布 + /// + /// 事件模型 + public void Publish(IntegrationEvent @event) + { + if (!_persistentConnection.IsConnected) { - if (!_persistentConnection.IsConnected) + _persistentConnection.TryConnect(); + } + + var policy = RetryPolicy.Handle() + .Or() + .WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) => { - _persistentConnection.TryConnect(); - } + _logger.LogWarning(ex, "Could not publish event: {EventId} after {Timeout}s ({ExceptionMessage})", @event.Id, $"{time.TotalSeconds:n1}", ex.Message); + }); - var policy = RetryPolicy.Handle() - .Or() - .WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) => - { - _logger.LogWarning(ex, "Could not publish event: {EventId} after {Timeout}s ({ExceptionMessage})", @event.Id, $"{time.TotalSeconds:n1}", ex.Message); - }); + var eventName = @event.GetType().Name; - var eventName = @event.GetType().Name; + _logger.LogTrace("Creating RabbitMQ channel to publish event: {EventId} ({EventName})", @event.Id, eventName); - _logger.LogTrace("Creating RabbitMQ channel to publish event: {EventId} ({EventName})", @event.Id, eventName); + using (var channel = _persistentConnection.CreateModel()) + { - using (var channel = _persistentConnection.CreateModel()) - { + _logger.LogTrace("Declaring RabbitMQ exchange to publish event: {EventId}", @event.Id); - _logger.LogTrace("Declaring RabbitMQ exchange to publish event: {EventId}", @event.Id); + channel.ExchangeDeclare(exchange: BROKER_NAME, type: "direct"); - channel.ExchangeDeclare(exchange: BROKER_NAME, type: "direct"); + var message = JsonConvert.SerializeObject(@event); + var body = Encoding.UTF8.GetBytes(message); - var message = JsonConvert.SerializeObject(@event); - var body = Encoding.UTF8.GetBytes(message); + policy.Execute(() => + { + var properties = channel.CreateBasicProperties(); + properties.DeliveryMode = 2; // persistent - policy.Execute(() => - { - var properties = channel.CreateBasicProperties(); - properties.DeliveryMode = 2; // persistent - - _logger.LogTrace("Publishing event to RabbitMQ: {EventId}", @event.Id); - - channel.BasicPublish( - exchange: BROKER_NAME, - routingKey: eventName, - mandatory: true, - basicProperties: properties, - body: body); - }); - } + _logger.LogTrace("Publishing event to RabbitMQ: {EventId}", @event.Id); + + channel.BasicPublish( + exchange: BROKER_NAME, + routingKey: eventName, + mandatory: true, + basicProperties: properties, + body: body); + }); } + } - /// - /// 订阅 - /// 动态 - /// - /// 事件处理器 - /// 事件名 - public void SubscribeDynamic(string eventName) - where TH : IDynamicIntegrationEventHandler - { - _logger.LogInformation("Subscribing to dynamic event {EventName} with {EventHandler}", eventName, typeof(TH).GetGenericTypeName()); + /// + /// 订阅 + /// 动态 + /// + /// 事件处理器 + /// 事件名 + public void SubscribeDynamic(string eventName) + where TH : IDynamicIntegrationEventHandler + { + _logger.LogInformation("Subscribing to dynamic event {EventName} with {EventHandler}", eventName, typeof(TH).GetGenericTypeName()); - DoInternalSubscription(eventName); - _subsManager.AddDynamicSubscription(eventName); - StartBasicConsume(); - } + DoInternalSubscription(eventName); + _subsManager.AddDynamicSubscription(eventName); + StartBasicConsume(); + } - /// - /// 订阅 - /// - /// 约束:事件模型 - /// 约束:事件处理器<事件模型> - public void Subscribe() - where T : IntegrationEvent - where TH : IIntegrationEventHandler - { - var eventName = _subsManager.GetEventKey(); - DoInternalSubscription(eventName); + /// + /// 订阅 + /// + /// 约束:事件模型 + /// 约束:事件处理器<事件模型> + public void Subscribe() + where T : IntegrationEvent + where TH : IIntegrationEventHandler + { + var eventName = _subsManager.GetEventKey(); + DoInternalSubscription(eventName); - _logger.LogInformation("Subscribing to event {EventName} with {EventHandler}", eventName, typeof(TH).GetGenericTypeName()); + _logger.LogInformation("Subscribing to event {EventName} with {EventHandler}", eventName, typeof(TH).GetGenericTypeName()); - ConsoleHelper.WriteSuccessLine($"Subscribing to event {eventName} with {typeof(TH).GetGenericTypeName()}"); + ConsoleHelper.WriteSuccessLine($"Subscribing to event {eventName} with {typeof(TH).GetGenericTypeName()}"); - _subsManager.AddSubscription(); - StartBasicConsume(); - } + _subsManager.AddSubscription(); + StartBasicConsume(); + } - private void DoInternalSubscription(string eventName) + private void DoInternalSubscription(string eventName) + { + var containsKey = _subsManager.HasSubscriptionsForEvent(eventName); + if (!containsKey) { - var containsKey = _subsManager.HasSubscriptionsForEvent(eventName); - if (!containsKey) + if (!_persistentConnection.IsConnected) { - if (!_persistentConnection.IsConnected) - { - _persistentConnection.TryConnect(); - } + _persistentConnection.TryConnect(); + } - using (var channel = _persistentConnection.CreateModel()) - { - channel.QueueBind(queue: _queueName, - exchange: BROKER_NAME, - routingKey: eventName); - } + using (var channel = _persistentConnection.CreateModel()) + { + channel.QueueBind(queue: _queueName, + exchange: BROKER_NAME, + routingKey: eventName); } } + } - /// - /// 取消订阅 - /// - /// - /// - public void Unsubscribe() - where T : IntegrationEvent - where TH : IIntegrationEventHandler - { - var eventName = _subsManager.GetEventKey(); + /// + /// 取消订阅 + /// + /// + /// + public void Unsubscribe() + where T : IntegrationEvent + where TH : IIntegrationEventHandler + { + var eventName = _subsManager.GetEventKey(); - _logger.LogInformation("Unsubscribing from event {EventName}", eventName); + _logger.LogInformation("Unsubscribing from event {EventName}", eventName); - _subsManager.RemoveSubscription(); - } + _subsManager.RemoveSubscription(); + } + + public void UnsubscribeDynamic(string eventName) + where TH : IDynamicIntegrationEventHandler + { + _subsManager.RemoveDynamicSubscription(eventName); + } - public void UnsubscribeDynamic(string eventName) - where TH : IDynamicIntegrationEventHandler + public void Dispose() + { + if (_consumerChannel != null) { - _subsManager.RemoveDynamicSubscription(eventName); + _consumerChannel.Dispose(); } - public void Dispose() - { - if (_consumerChannel != null) - { - _consumerChannel.Dispose(); - } + _subsManager.Clear(); + } - _subsManager.Clear(); - } + /// + /// 开始基本消费 + /// + private void StartBasicConsume() + { + _logger.LogTrace("Starting RabbitMQ basic consume"); - /// - /// 开始基本消费 - /// - private void StartBasicConsume() + if (_consumerChannel != null) { - _logger.LogTrace("Starting RabbitMQ basic consume"); - - if (_consumerChannel != null) - { - var consumer = new AsyncEventingBasicConsumer(_consumerChannel); + var consumer = new AsyncEventingBasicConsumer(_consumerChannel); - consumer.Received += Consumer_Received; + consumer.Received += Consumer_Received; - _consumerChannel.BasicConsume( - queue: _queueName, - autoAck: false, - consumer: consumer); - } - else - { - _logger.LogError("StartBasicConsume can't call on _consumerChannel == null"); - } + _consumerChannel.BasicConsume( + queue: _queueName, + autoAck: false, + consumer: consumer); } - - /// - /// 消费者接受到 - /// - /// - /// - /// - private async Task Consumer_Received(object sender, BasicDeliverEventArgs eventArgs) + else { - var eventName = eventArgs.RoutingKey; - var message = Encoding.UTF8.GetString(eventArgs.Body.Span); + _logger.LogError("StartBasicConsume can't call on _consumerChannel == null"); + } + } - try - { - if (message.ToLowerInvariant().Contains("throw-fake-exception")) - { - throw new InvalidOperationException($"Fake exception requested: \"{message}\""); - } + /// + /// 消费者接受到 + /// + /// + /// + /// + private async Task Consumer_Received(object sender, BasicDeliverEventArgs eventArgs) + { + var eventName = eventArgs.RoutingKey; + var message = Encoding.UTF8.GetString(eventArgs.Body.Span); - await ProcessEvent(eventName, message); - } - catch (Exception ex) + try + { + if (message.ToLowerInvariant().Contains("throw-fake-exception")) { - _logger.LogWarning(ex, "----- ERROR Processing message \"{Message}\"", message); + throw new InvalidOperationException($"Fake exception requested: \"{message}\""); } - // Even on exception we take the message off the queue. - // in a REAL WORLD app this should be handled with a Dead Letter Exchange (DLX). - // For more information see: https://www.rabbitmq.com/dlx.html - _consumerChannel.BasicAck(eventArgs.DeliveryTag, multiple: false); + await ProcessEvent(eventName, message); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "----- ERROR Processing message \"{Message}\"", message); } - /// - /// 创造消费通道 - /// - /// - private IModel CreateConsumerChannel() + // Even on exception we take the message off the queue. + // in a REAL WORLD app this should be handled with a Dead Letter Exchange (DLX). + // For more information see: https://www.rabbitmq.com/dlx.html + _consumerChannel.BasicAck(eventArgs.DeliveryTag, multiple: false); + } + + /// + /// 创造消费通道 + /// + /// + private IModel CreateConsumerChannel() + { + if (!_persistentConnection.IsConnected) { - if (!_persistentConnection.IsConnected) - { - _persistentConnection.TryConnect(); - } + _persistentConnection.TryConnect(); + } - _logger.LogTrace("Creating RabbitMQ consumer channel"); + _logger.LogTrace("Creating RabbitMQ consumer channel"); - var channel = _persistentConnection.CreateModel(); + var channel = _persistentConnection.CreateModel(); - channel.ExchangeDeclare(exchange: BROKER_NAME, - type: "direct"); + channel.ExchangeDeclare(exchange: BROKER_NAME, + type: "direct"); - channel.QueueDeclare(queue: _queueName, - durable: true, - exclusive: false, - autoDelete: false, - arguments: null); + channel.QueueDeclare(queue: _queueName, + durable: true, + exclusive: false, + autoDelete: false, + arguments: null); - channel.CallbackException += (sender, ea) => - { - _logger.LogWarning(ea.Exception, "Recreating RabbitMQ consumer channel"); + channel.CallbackException += (sender, ea) => + { + _logger.LogWarning(ea.Exception, "Recreating RabbitMQ consumer channel"); - _consumerChannel.Dispose(); - _consumerChannel = CreateConsumerChannel(); - StartBasicConsume(); - }; + _consumerChannel.Dispose(); + _consumerChannel = CreateConsumerChannel(); + StartBasicConsume(); + }; - return channel; - } + return channel; + } - private async Task ProcessEvent(string eventName, string message) - { - _logger.LogTrace("Processing RabbitMQ event: {EventName}", eventName); + private async Task ProcessEvent(string eventName, string message) + { + _logger.LogTrace("Processing RabbitMQ event: {EventName}", eventName); - if (_subsManager.HasSubscriptionsForEvent(eventName)) + if (_subsManager.HasSubscriptionsForEvent(eventName)) + { + using (var scope = _autofac.BeginLifetimeScope(AUTOFAC_SCOPE_NAME)) { - using (var scope = _autofac.BeginLifetimeScope(AUTOFAC_SCOPE_NAME)) + var subscriptions = _subsManager.GetHandlersForEvent(eventName); + foreach (var subscription in subscriptions) { - var subscriptions = _subsManager.GetHandlersForEvent(eventName); - foreach (var subscription in subscriptions) + if (subscription.IsDynamic) { - if (subscription.IsDynamic) - { - var handler = scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler; - if (handler == null) continue; - dynamic eventData = JObject.Parse(message); - - await Task.Yield(); - await handler.Handle(eventData); - } - else - { - var handler = scope.ResolveOptional(subscription.HandlerType); - if (handler == null) continue; - var eventType = _subsManager.GetEventTypeByName(eventName); - var integrationEvent = JsonConvert.DeserializeObject(message, eventType); - var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType); - - await Task.Yield(); - await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent }); - } + var handler = scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler; + if (handler == null) continue; + dynamic eventData = JObject.Parse(message); + + await Task.Yield(); + await handler.Handle(eventData); + } + else + { + var handler = scope.ResolveOptional(subscription.HandlerType); + if (handler == null) continue; + var eventType = _subsManager.GetEventTypeByName(eventName); + var integrationEvent = JsonConvert.DeserializeObject(message, eventType); + var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType); + + await Task.Yield(); + await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent }); } } } - else - { - _logger.LogWarning("No subscription for RabbitMQ event: {EventName}", eventName); - } + } + else + { + _logger.LogWarning("No subscription for RabbitMQ event: {EventName}", eventName); } } } diff --git a/Tiobon.Core.EventBus/RabbitMQPersistent/IRabbitMQPersistentConnection.cs b/Tiobon.Core.EventBus/RabbitMQPersistent/IRabbitMQPersistentConnection.cs index 29fca13b..ba0bfe8d 100644 --- a/Tiobon.Core.EventBus/RabbitMQPersistent/IRabbitMQPersistentConnection.cs +++ b/Tiobon.Core.EventBus/RabbitMQPersistent/IRabbitMQPersistentConnection.cs @@ -1,44 +1,42 @@ using RabbitMQ.Client; -using System; -namespace Tiobon.Core.EventBus +namespace Tiobon.Core.EventBus; + +/// +/// RabbitMQ持久连接 +/// 接口 +/// +public interface IRabbitMQPersistentConnection + : IDisposable { /// - /// RabbitMQ持久连接 - /// 接口 + /// 是否已经连接 /// - public interface IRabbitMQPersistentConnection - : IDisposable - { - /// - /// 是否已经连接 - /// - bool IsConnected { get; } + bool IsConnected { get; } - /// - /// 尝试重连 - /// - /// - bool TryConnect(); + /// + /// 尝试重连 + /// + /// + bool TryConnect(); - /// - /// 创建Model - /// - /// - IModel CreateModel(); + /// + /// 创建Model + /// + /// + IModel CreateModel(); - /// - /// 发布消息 - /// - /// - /// - /// - void PublishMessage(string message, string exchangeName, string routingKey); + /// + /// 发布消息 + /// + /// + /// + /// + void PublishMessage(string message, string exchangeName, string routingKey); - /// - /// 订阅消息 - /// - /// - void StartConsuming(string queueName); - } + /// + /// 订阅消息 + /// + /// + void StartConsuming(string queueName); } diff --git a/Tiobon.Core.EventBus/RabbitMQPersistent/RabbitMQPersistentConnection.cs b/Tiobon.Core.EventBus/RabbitMQPersistent/RabbitMQPersistentConnection.cs index 6e42f5be..829ed707 100644 --- a/Tiobon.Core.EventBus/RabbitMQPersistent/RabbitMQPersistentConnection.cs +++ b/Tiobon.Core.EventBus/RabbitMQPersistent/RabbitMQPersistentConnection.cs @@ -4,208 +4,205 @@ using Polly.Retry; using RabbitMQ.Client; using RabbitMQ.Client.Events; using RabbitMQ.Client.Exceptions; -using System; -using System.IO; using System.Net.Sockets; using System.Text; -namespace Tiobon.Core.EventBus +namespace Tiobon.Core.EventBus; + +/// +/// RabbitMQ持久连接 +/// +public class RabbitMQPersistentConnection + : IRabbitMQPersistentConnection { + private readonly IConnectionFactory _connectionFactory; + private readonly ILogger _logger; + private readonly int _retryCount; + IConnection _connection; + bool _disposed; + + object sync_root = new object(); + + public RabbitMQPersistentConnection(IConnectionFactory connectionFactory, ILogger logger, + int retryCount = 5) + { + _connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _retryCount = retryCount; + } + /// - /// RabbitMQ持久连接 + /// 是否已连接 /// - public class RabbitMQPersistentConnection - : IRabbitMQPersistentConnection + public bool IsConnected { - private readonly IConnectionFactory _connectionFactory; - private readonly ILogger _logger; - private readonly int _retryCount; - IConnection _connection; - bool _disposed; - - object sync_root = new object(); - - public RabbitMQPersistentConnection(IConnectionFactory connectionFactory, ILogger logger, - int retryCount = 5) + get { - _connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _retryCount = retryCount; + return _connection != null && _connection.IsOpen && !_disposed; } + } - /// - /// 是否已连接 - /// - public bool IsConnected + /// + /// 创建Model + /// + /// + public IModel CreateModel() + { + if (!IsConnected) { - get - { - return _connection != null && _connection.IsOpen && !_disposed; - } + throw new InvalidOperationException("No RabbitMQ connections are available to perform this action"); } - /// - /// 创建Model - /// - /// - public IModel CreateModel() - { - if (!IsConnected) - { - throw new InvalidOperationException("No RabbitMQ connections are available to perform this action"); - } + return _connection.CreateModel(); + } - return _connection.CreateModel(); - } + /// + /// 释放 + /// + public void Dispose() + { + if (_disposed) return; - /// - /// 释放 - /// - public void Dispose() + _disposed = true; + + try { - if (_disposed) return; + _connection.Dispose(); + } + catch (IOException ex) + { + _logger.LogCritical(ex.ToString()); + } + } - _disposed = true; + /// + /// 连接 + /// + /// + public bool TryConnect() + { + _logger.LogInformation("RabbitMQ Client is trying to connect"); - try + lock (sync_root) + { + var policy = RetryPolicy.Handle() + .Or() + .WaitAndRetry(_retryCount, + retryAttempt => + TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) => + { + _logger.LogWarning(ex, "RabbitMQ Client could not connect after {TimeOut}s ({ExceptionMessage})", $"{time.TotalSeconds:n1}", ex.Message); + } + ); + + policy.Execute(() => { - _connection.Dispose(); - } - catch (IOException ex) + _connection = _connectionFactory + .CreateConnection(); + }); + + if (IsConnected) { - _logger.LogCritical(ex.ToString()); - } - } + _connection.ConnectionShutdown += OnConnectionShutdown; + _connection.CallbackException += OnCallbackException; + _connection.ConnectionBlocked += OnConnectionBlocked; - /// - /// 连接 - /// - /// - public bool TryConnect() - { - _logger.LogInformation("RabbitMQ Client is trying to connect"); + _logger.LogInformation("RabbitMQ Client acquired a persistent connection to '{HostName}' and is subscribed to failure events", _connection.Endpoint.HostName); - lock (sync_root) + return true; + } + else { - var policy = RetryPolicy.Handle() - .Or() - .WaitAndRetry(_retryCount, - retryAttempt => - TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) => - { - _logger.LogWarning(ex, "RabbitMQ Client could not connect after {TimeOut}s ({ExceptionMessage})", $"{time.TotalSeconds:n1}", ex.Message); - } - ); - - policy.Execute(() => - { - _connection = _connectionFactory - .CreateConnection(); - }); - - if (IsConnected) - { - _connection.ConnectionShutdown += OnConnectionShutdown; - _connection.CallbackException += OnCallbackException; - _connection.ConnectionBlocked += OnConnectionBlocked; - - _logger.LogInformation("RabbitMQ Client acquired a persistent connection to '{HostName}' and is subscribed to failure events", _connection.Endpoint.HostName); - - return true; - } - else - { - _logger.LogCritical("FATAL ERROR: RabbitMQ connections could not be created and opened"); - - return false; - } + _logger.LogCritical("FATAL ERROR: RabbitMQ connections could not be created and opened"); + + return false; } } + } - /// - /// 连接被阻断 - /// - /// - /// - private void OnConnectionBlocked(object sender, ConnectionBlockedEventArgs e) - { - if (_disposed) return; + /// + /// 连接被阻断 + /// + /// + /// + private void OnConnectionBlocked(object sender, ConnectionBlockedEventArgs e) + { + if (_disposed) return; - _logger.LogWarning("A RabbitMQ connection is shutdown. Trying to re-connect..."); + _logger.LogWarning("A RabbitMQ connection is shutdown. Trying to re-connect..."); - TryConnect(); - } + TryConnect(); + } - /// - /// 连接出现异常 - /// - /// - /// - void OnCallbackException(object sender, CallbackExceptionEventArgs e) - { - if (_disposed) return; + /// + /// 连接出现异常 + /// + /// + /// + void OnCallbackException(object sender, CallbackExceptionEventArgs e) + { + if (_disposed) return; - _logger.LogWarning("A RabbitMQ connection throw exception. Trying to re-connect..."); + _logger.LogWarning("A RabbitMQ connection throw exception. Trying to re-connect..."); - TryConnect(); - } + TryConnect(); + } - /// - /// 连接被关闭 - /// - /// - /// - void OnConnectionShutdown(object sender, ShutdownEventArgs reason) - { - if (_disposed) return; + /// + /// 连接被关闭 + /// + /// + /// + void OnConnectionShutdown(object sender, ShutdownEventArgs reason) + { + if (_disposed) return; - _logger.LogWarning("A RabbitMQ connection is on shutdown. Trying to re-connect..."); + _logger.LogWarning("A RabbitMQ connection is on shutdown. Trying to re-connect..."); - TryConnect(); - } + TryConnect(); + } - /// - /// 发布消息 - /// - /// - /// - /// - public void PublishMessage(string message, string exchangeName, string routingKey) - { - using var channel = CreateModel(); - channel.ExchangeDeclare(exchange: exchangeName, type: ExchangeType.Direct, true); - var body = Encoding.UTF8.GetBytes(message); - channel.BasicPublish(exchange: exchangeName, routingKey: routingKey, basicProperties: null, body: body); - } + /// + /// 发布消息 + /// + /// + /// + /// + public void PublishMessage(string message, string exchangeName, string routingKey) + { + using var channel = CreateModel(); + channel.ExchangeDeclare(exchange: exchangeName, type: ExchangeType.Direct, true); + var body = Encoding.UTF8.GetBytes(message); + channel.BasicPublish(exchange: exchangeName, routingKey: routingKey, basicProperties: null, body: body); + } - /// - /// 订阅消息 - /// - /// - public void StartConsuming(string queueName) - { - using var channel = CreateModel(); - channel.QueueDeclare(queue: queueName, durable: true, exclusive: false, autoDelete: false, arguments: null); - - var consumer = new AsyncEventingBasicConsumer(channel); - consumer.Received += new AsyncEventHandler( - async (a, b) => - { - var Headers = b.BasicProperties.Headers; - var msgBody = b.Body.ToArray(); - var message = Encoding.UTF8.GetString(msgBody); - await Task.CompletedTask; - Console.WriteLine("Received message: {0}", message); - - //bool Dealresult = await Dealer(b.Exchange, b.RoutingKey, msgBody, Headers); - //if (Dealresult) channel.BasicAck(b.DeliveryTag, false); - //else channel.BasicNack(b.DeliveryTag, false, true); - } - ); - - channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer); - - Console.WriteLine("Consuming messages..."); - } + /// + /// 订阅消息 + /// + /// + public void StartConsuming(string queueName) + { + using var channel = CreateModel(); + channel.QueueDeclare(queue: queueName, durable: true, exclusive: false, autoDelete: false, arguments: null); + + var consumer = new AsyncEventingBasicConsumer(channel); + consumer.Received += new AsyncEventHandler( + async (a, b) => + { + var Headers = b.BasicProperties.Headers; + var msgBody = b.Body.ToArray(); + var message = Encoding.UTF8.GetString(msgBody); + await Task.CompletedTask; + Console.WriteLine("Received message: {0}", message); + + //bool Dealresult = await Dealer(b.Exchange, b.RoutingKey, msgBody, Headers); + //if (Dealresult) channel.BasicAck(b.DeliveryTag, false); + //else channel.BasicNack(b.DeliveryTag, false, true); + } + ); + + channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer); + + Console.WriteLine("Consuming messages..."); } } diff --git a/Tiobon.Core.Gateway/Controllers/UserController.cs b/Tiobon.Core.Gateway/Controllers/UserController.cs index 975d7210..9efef4aa 100644 --- a/Tiobon.Core.Gateway/Controllers/UserController.cs +++ b/Tiobon.Core.Gateway/Controllers/UserController.cs @@ -3,38 +3,37 @@ using Microsoft.AspNetCore.Mvc; using Tiobon.Core.HttpContextUser; using Tiobon.Core.Model.Entity; -namespace Tiobon.Core.Gateway.Controllers -{ - [Authorize(AuthenticationSchemes = Permissions.GWName)] - [Route("/gateway/[controller]/[action]")] - public class UserController : ControllerBase - { - private readonly IUser _user; +namespace Tiobon.Core.Gateway.Controllers; - public UserController(IUser user) - { - _user = user; - } +[Authorize(AuthenticationSchemes = Permissions.GWName)] +[Route("/gateway/[controller]/[action]")] +public class UserController : ControllerBase +{ + private readonly IUser _user; - [HttpGet] - public ServiceResult> MyClaims() - { - return new ServiceResult>() - { - Success = true, - Data = (_user.GetClaimsIdentity().ToList()).Select(d => - new ClaimDto - { - Type = d.Type, - Value = d.Value - } - ).ToList() - }; - } + public UserController(IUser user) + { + _user = user; } - public class ClaimDto + + [HttpGet] + public ServiceResult> MyClaims() { - public string Type { get; set; } - public string Value { get; set; } + return new ServiceResult>() + { + Success = true, + Data = (_user.GetClaimsIdentity().ToList()).Select(d => + new ClaimDto + { + Type = d.Type, + Value = d.Value + } + ).ToList() + }; } } +public class ClaimDto +{ + public string Type { get; set; } + public string Value { get; set; } +} diff --git a/Tiobon.Core.Gateway/Extensions/CustomAuthenticationHandler.cs b/Tiobon.Core.Gateway/Extensions/CustomAuthenticationHandler.cs index bf39b779..2306c8de 100644 --- a/Tiobon.Core.Gateway/Extensions/CustomAuthenticationHandler.cs +++ b/Tiobon.Core.Gateway/Extensions/CustomAuthenticationHandler.cs @@ -1,53 +1,48 @@ using Microsoft.AspNetCore.Authentication; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.Net.Http.Headers; -using System; -using System.Collections.Generic; using System.Security.Claims; using System.Text.Encodings.Web; -using System.Threading.Tasks; -namespace Tiobon.Core.Gateway.Extensions +namespace Tiobon.Core.Gateway.Extensions; + +public class CustomAuthenticationHandler : AuthenticationHandler { - public class CustomAuthenticationHandler : AuthenticationHandler + public CustomAuthenticationHandler(IOptionsMonitor options, + ILoggerFactory logger, + UrlEncoder encoder, + ISystemClock clock) : base(options, logger, encoder, clock) { - public CustomAuthenticationHandler(IOptionsMonitor options, - ILoggerFactory logger, - UrlEncoder encoder, - ISystemClock clock) : base(options, logger, encoder, clock) - { - } + } - protected override async Task HandleAuthenticateAsync() - { - // 可以查询数据库等操作 - // 获取当前用户不能放到token中的私密信息 - var userPhone = "15010000000"; - - var claims = new List() - { - new Claim("user-phone", userPhone), - new Claim("gw-sign", "gw") - }; - - var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, Scheme.Name)); - var ticket = new AuthenticationTicket(principal, Scheme.Name); - await Task.CompletedTask; - return AuthenticateResult.Success(ticket); - } + protected override async Task HandleAuthenticateAsync() + { + // 可以查询数据库等操作 + // 获取当前用户不能放到token中的私密信息 + var userPhone = "15010000000"; - protected virtual string GetTokenStringFromHeader() + var claims = new List() { - var token = string.Empty; - string authorization = Request.Headers[HeaderNames.Authorization]; + new Claim("user-phone", userPhone), + new Claim("gw-sign", "gw") + }; + + var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, Scheme.Name)); + var ticket = new AuthenticationTicket(principal, Scheme.Name); + await Task.CompletedTask; + return AuthenticateResult.Success(ticket); + } - if (!string.IsNullOrEmpty(authorization) && authorization.StartsWith($"Bearer ", StringComparison.OrdinalIgnoreCase)) - { - token = authorization["Bearer ".Length..].Trim(); - } + protected virtual string GetTokenStringFromHeader() + { + var token = string.Empty; + string authorization = Request.Headers[HeaderNames.Authorization]; - return token; + if (!string.IsNullOrEmpty(authorization) && authorization.StartsWith($"Bearer ", StringComparison.OrdinalIgnoreCase)) + { + token = authorization["Bearer ".Length..].Trim(); } + + return token; } } \ No newline at end of file diff --git a/Tiobon.Core.Gateway/Extensions/CustomOcelotSetup.cs b/Tiobon.Core.Gateway/Extensions/CustomOcelotSetup.cs index 9f67736a..a5a46647 100644 --- a/Tiobon.Core.Gateway/Extensions/CustomOcelotSetup.cs +++ b/Tiobon.Core.Gateway/Extensions/CustomOcelotSetup.cs @@ -1,34 +1,29 @@ -using Tiobon.Core.Extensions; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.DependencyInjection; -using Ocelot.DependencyInjection; +using Ocelot.DependencyInjection; using Ocelot.Middleware; //using Ocelot.Provider.Nacos; using Ocelot.Provider.Polly; -using System; -using System.Threading.Tasks; +using Tiobon.Core.Extensions; -namespace Tiobon.Core.Gateway.Extensions +namespace Tiobon.Core.Gateway.Extensions; + +public static class CustomOcelotSetup { - public static class CustomOcelotSetup + public static void AddCustomOcelotSetup(this IServiceCollection services) { - public static void AddCustomOcelotSetup(this IServiceCollection services) - { - if (services == null) throw new ArgumentNullException(nameof(services)); - - services.AddAuthentication_JWTSetup(); - services.AddOcelot() - .AddDelegatingHandler() - //.AddNacosDiscovery() - //.AddConsul() - .AddPolly(); - } + if (services == null) throw new ArgumentNullException(nameof(services)); - public static async Task UseCustomOcelotMildd(this IApplicationBuilder app) - { - await app.UseOcelot(); - return app; - } + services.AddAuthentication_JWTSetup(); + services.AddOcelot() + .AddDelegatingHandler() + //.AddNacosDiscovery() + //.AddConsul() + .AddPolly(); + } + public static async Task UseCustomOcelotMildd(this IApplicationBuilder app) + { + await app.UseOcelot(); + return app; } + } diff --git a/Tiobon.Core.Gateway/Extensions/CustomResultHandler.cs b/Tiobon.Core.Gateway/Extensions/CustomResultHandler.cs index 2c186a5f..e51a5874 100644 --- a/Tiobon.Core.Gateway/Extensions/CustomResultHandler.cs +++ b/Tiobon.Core.Gateway/Extensions/CustomResultHandler.cs @@ -1,62 +1,57 @@ using Newtonsoft.Json; using Newtonsoft.Json.Serialization; -using System; using System.Net; -using System.Net.Http; using System.Text; -using System.Threading; -using System.Threading.Tasks; -namespace Tiobon.Core.Gateway.Extensions +namespace Tiobon.Core.Gateway.Extensions; + +public class CustomResultHandler : DelegatingHandler { - public class CustomResultHandler : DelegatingHandler + JsonSerializerSettings _camelSettings = new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() }; + + protected async override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { - JsonSerializerSettings _camelSettings = new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() }; + var response = await base.SendAsync(request, cancellationToken); + var contentType = response.Content.Headers.ContentType?.MediaType ?? ""; + if (!contentType.Equals("application/json")) return response; - protected async override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + dynamic result = null; + var resultStr = await response.Content.ReadAsStringAsync(); + try { - var response = await base.SendAsync(request, cancellationToken); - var contentType = response.Content.Headers.ContentType?.MediaType ?? ""; - if (!contentType.Equals("application/json")) return response; - - dynamic result = null; - var resultStr = await response.Content.ReadAsStringAsync(); - try - { - Console.WriteLine(resultStr); - result = JsonConvert.DeserializeObject(resultStr); - } - catch (Exception) - { - return response; - } + Console.WriteLine(resultStr); + result = JsonConvert.DeserializeObject(resultStr); + } + catch (Exception) + { + return response; + } - if (result != null && result.errorCode == 500) resultStr = result.message.ToString(); + if (result != null && result.errorCode == 500) resultStr = result.message.ToString(); - var exception = new Exception(resultStr); + var exception = new Exception(resultStr); - if (response.StatusCode == HttpStatusCode.InternalServerError || result.errorCode == (int)HttpStatusCode.InternalServerError) + if (response.StatusCode == HttpStatusCode.InternalServerError || result.errorCode == (int)HttpStatusCode.InternalServerError) + { + var apiResult = new { - var apiResult = new + Result = false, + Message = "服务器内部错误", + ErrorCode = (int)HttpStatusCode.InternalServerError, + Data = new { - Result = false, - Message = "服务器内部错误", - ErrorCode = (int)HttpStatusCode.InternalServerError, - Data = new - { - exception.Message, - exception.StackTrace - } - }; - response.Content = new StringContent(JsonConvert.SerializeObject(apiResult, _camelSettings), Encoding.UTF8, "application/json"); - } - else - { + exception.Message, + exception.StackTrace + } + }; + response.Content = new StringContent(JsonConvert.SerializeObject(apiResult, _camelSettings), Encoding.UTF8, "application/json"); + } + else + { - } + } - return response; - } + return response; } } diff --git a/Tiobon.Core.Gateway/Extensions/CustomSwaggerSetup.cs b/Tiobon.Core.Gateway/Extensions/CustomSwaggerSetup.cs index 89fcf8ae..78a70473 100644 --- a/Tiobon.Core.Gateway/Extensions/CustomSwaggerSetup.cs +++ b/Tiobon.Core.Gateway/Extensions/CustomSwaggerSetup.cs @@ -1,81 +1,70 @@ -using Tiobon.Core.Common; -using Tiobon.Core.Extensions.Middlewares; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.Filters; -using Swashbuckle.AspNetCore.SwaggerUI; -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using static Tiobon.Core.Extensions.CustomApiVersion; -namespace Tiobon.Core.Gateway.Extensions + +namespace Tiobon.Core.Gateway.Extensions; + +public static class CustomSwaggerSetup { - public static class CustomSwaggerSetup + public static void AddCustomSwaggerSetup(this IServiceCollection services) { - public static void AddCustomSwaggerSetup(this IServiceCollection services) - { - if (services == null) throw new ArgumentNullException(nameof(services)); + if (services == null) throw new ArgumentNullException(nameof(services)); - var basePath = AppContext.BaseDirectory; + var basePath = AppContext.BaseDirectory; - services.AddMvc(option => option.EnableEndpointRouting = false); + services.AddMvc(option => option.EnableEndpointRouting = false); - services.AddSwaggerGen(c => + services.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new OpenApiInfo { - c.SwaggerDoc("v1", new OpenApiInfo - { - Version = "v1", - Title = "自定义网关 接口文档", - }); - - var xmlPath = Path.Combine(basePath, "Tiobon.Core.Gateway.xml"); - c.IncludeXmlComments(xmlPath, true); - - c.OperationFilter(); - c.OperationFilter(); - - c.OperationFilter(); - - c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme - { - Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"", - Name = "Authorization", - In = ParameterLocation.Header, - Type = SecuritySchemeType.ApiKey - }); + Version = "v1", + Title = "自定义网关 接口文档", }); - } - public static void UseCustomSwaggerMildd(this IApplicationBuilder app, Func streamHtml) - { - if (app == null) throw new ArgumentNullException(nameof(app)); + var xmlPath = Path.Combine(basePath, "Tiobon.Core.Gateway.xml"); + c.IncludeXmlComments(xmlPath, true); - var apis = new List { "Tiobon-svc" }; - app.UseSwagger(); - app.UseSwaggerUI(c => - { - c.SwaggerEndpoint($"/swagger/v1/swagger.json", "gateway"); - apis.ForEach(m => - { - c.SwaggerEndpoint($"/swagger/apiswg/{m}/swagger.json", m); - }); + c.OperationFilter(); + c.OperationFilter(); + c.OperationFilter(); - if (streamHtml.Invoke() == null) - { - var msg = "index.html的属性,必须设置为嵌入的资源"; - throw new Exception(msg); - } + c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme + { + Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"", + Name = "Authorization", + In = ParameterLocation.Header, + Type = SecuritySchemeType.ApiKey + }); + }); + } - c.IndexStream = streamHtml; + public static void UseCustomSwaggerMildd(this IApplicationBuilder app, Func streamHtml) + { + if (app == null) throw new ArgumentNullException(nameof(app)); - c.RoutePrefix = ""; + var apis = new List { "Tiobon-svc" }; + app.UseSwagger(); + app.UseSwaggerUI(c => + { + c.SwaggerEndpoint($"/swagger/v1/swagger.json", "gateway"); + apis.ForEach(m => + { + c.SwaggerEndpoint($"/swagger/apiswg/{m}/swagger.json", m); }); - } + if (streamHtml.Invoke() == null) + { + var msg = "index.html的属性,必须设置为嵌入的资源"; + throw new Exception(msg); + } + + c.IndexStream = streamHtml; + + c.RoutePrefix = ""; + }); } + + } diff --git a/Tiobon.Core.Gateway/Helper/CustomJwtTokenAuthMiddleware.cs b/Tiobon.Core.Gateway/Helper/CustomJwtTokenAuthMiddleware.cs index b3dbab09..719516a0 100644 --- a/Tiobon.Core.Gateway/Helper/CustomJwtTokenAuthMiddleware.cs +++ b/Tiobon.Core.Gateway/Helper/CustomJwtTokenAuthMiddleware.cs @@ -4,182 +4,181 @@ using System.Text.RegularExpressions; using Tiobon.Core.Caches; using Tiobon.Core.Helper; -namespace Tiobon.Core.AuthHelper +namespace Tiobon.Core.AuthHelper; + +/// +/// 中间件 +/// 原做为自定义授权中间件 +/// 先做检查 header token的使用 +/// +public class CustomJwtTokenAuthMiddleware { + private readonly ICaching _cache; + + + /// + /// 验证方案提供对象 + /// + public IAuthenticationSchemeProvider Schemes { get; set; } + + /// + /// 请求上下文 + /// + private readonly RequestDelegate _next; + + + public CustomJwtTokenAuthMiddleware(RequestDelegate next, IAuthenticationSchemeProvider schemes, AppSettings appset, ICaching cache) + { + _cache = cache; + _next = next; + Schemes = schemes; + } + /// - /// 中间件 - /// 原做为自定义授权中间件 - /// 先做检查 header token的使用 + /// 网关授权 /// - public class CustomJwtTokenAuthMiddleware + /// + /// + public async Task Invoke(HttpContext httpContext) { - private readonly ICaching _cache; - - - /// - /// 验证方案提供对象 - /// - public IAuthenticationSchemeProvider Schemes { get; set; } - - /// - /// 请求上下文 - /// - private readonly RequestDelegate _next; - - - public CustomJwtTokenAuthMiddleware(RequestDelegate next, IAuthenticationSchemeProvider schemes, AppSettings appset,ICaching cache) + var questUrl = httpContext?.Request.Path.Value.ToLower(); + if (string.IsNullOrEmpty(questUrl)) return; + //白名单验证 + if (CheckWhiteList(questUrl)) { - _cache = cache; - _next = next; - Schemes = schemes; + await _next.Invoke(httpContext); + return; } - - /// - /// 网关授权 - /// - /// - /// - public async Task Invoke(HttpContext httpContext) + //黑名单验证 + if (CheckBlackList(questUrl)) { - var questUrl = httpContext?.Request.Path.Value.ToLower(); - if (string.IsNullOrEmpty(questUrl)) return; - //白名单验证 - if (CheckWhiteList(questUrl)) - { - await _next.Invoke(httpContext); - return; - } - //黑名单验证 - if(CheckBlackList(questUrl)) - { - return; - } + return; + } - List Permissions= new(); + List Permissions = new(); - httpContext.Features.Set(new AuthenticationFeature - { - OriginalPath = httpContext.Request.Path, - OriginalPathBase = httpContext.Request.PathBase - }); + httpContext.Features.Set(new AuthenticationFeature + { + OriginalPath = httpContext.Request.Path, + OriginalPathBase = httpContext.Request.PathBase + }); - //判断请求是否拥有凭据,即有没有登录 - var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync(); - if (defaultAuthenticate != null) + //判断请求是否拥有凭据,即有没有登录 + var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync(); + if (defaultAuthenticate != null) + { + var Authresult = await httpContext.AuthenticateAsync(defaultAuthenticate.Name); + if (Authresult?.Principal != null) { - var Authresult = await httpContext.AuthenticateAsync(defaultAuthenticate.Name); - if (Authresult?.Principal != null) + httpContext.User = Authresult.Principal; + // 获取当前用户的角色信息 + var currentUserRoles = (from item in httpContext.User.Claims + where item.Type == "CofRole" + select item.Value).ToList(); + var isMatchRole = false; + var permisssionRoles = Permissions.Where(w => currentUserRoles.Contains(w.Role)); + foreach (var item in permisssionRoles) { - httpContext.User = Authresult.Principal; - // 获取当前用户的角色信息 - var currentUserRoles = (from item in httpContext.User.Claims - where item.Type == "CofRole" - select item.Value).ToList(); - var isMatchRole = false; - var permisssionRoles = Permissions.Where(w => currentUserRoles.Contains(w.Role)); - foreach (var item in permisssionRoles) + try { - try + if (Regex.IsMatch(questUrl, item.Url, RegexOptions.IgnoreCase)) { - if (Regex.IsMatch(questUrl, item.Url, RegexOptions.IgnoreCase)) - { - isMatchRole = true; - break; - } - } - catch (Exception) - { - // ignored + isMatchRole = true; + break; } } - - //验证权限 - if (currentUserRoles.Count <= 0 || !isMatchRole) + catch (Exception) { - await httpContext.Cof_SendResponse(HttpStatusCode.ServiceUnavailable, "未授权此资源"); - return ; + // ignored } } - else + + //验证权限 + if (currentUserRoles.Count <= 0 || !isMatchRole) { - await httpContext.Cof_SendResponse(HttpStatusCode.Unauthorized, "请重新登录"); - return ; + await httpContext.Cof_SendResponse(HttpStatusCode.ServiceUnavailable, "未授权此资源"); + return; } - } else { - await httpContext.Cof_SendResponse(HttpStatusCode.Unauthorized, "系统鉴权出错"); - return ; + await httpContext.Cof_SendResponse(HttpStatusCode.Unauthorized, "请重新登录"); + return; } - await _next.Invoke(httpContext); - } - /// - /// 返回相应 - /// - /// - /// - /// - /// - private async Task SendResponse(HttpContext context, string message, HttpStatusCode code) + } + else { - context.Response.StatusCode = (int)code; - context.Response.ContentType = "text/plain"; - await context.Response.WriteAsync(message); + await httpContext.Cof_SendResponse(HttpStatusCode.Unauthorized, "系统鉴权出错"); + return; } - - /// - /// 判断是否在白名单内,支持通配符 **** - /// - /// - /// - public bool CheckWhiteList(string url) + await _next.Invoke(httpContext); + } + + /// + /// 返回相应 + /// + /// + /// + /// + /// + private async Task SendResponse(HttpContext context, string message, HttpStatusCode code) + { + context.Response.StatusCode = (int)code; + context.Response.ContentType = "text/plain"; + await context.Response.WriteAsync(message); + } + + /// + /// 判断是否在白名单内,支持通配符 **** + /// + /// + /// + public bool CheckWhiteList(string url) + { + List WhiteList = _cache.Cof_GetICaching>("WhiteList", () => AppSettings.app("WhiteList"), 10); + + if (!WhiteList.Cof_CheckAvailable()) return false; + foreach (var Urlitem in WhiteList) { - List WhiteList = _cache.Cof_GetICaching>("WhiteList", () => AppSettings.app("WhiteList"), 10); + if (Urlitem.url.Equals(url, StringComparison.OrdinalIgnoreCase)) return true; - if (!WhiteList.Cof_CheckAvailable()) return false; - foreach (var Urlitem in WhiteList) + if (Urlitem.url.IndexOf("****") > 0) { - if (Urlitem.url.Equals(url, StringComparison.OrdinalIgnoreCase)) return true; - - if (Urlitem.url.IndexOf("****") > 0) - { - string UrlitemP = Urlitem.url.Replace("****", ""); - if (Regex.IsMatch(url, UrlitemP, RegexOptions.IgnoreCase)) return true; - if (url.Length >= UrlitemP.Length && UrlitemP.ToLower() == url.Substring(0, UrlitemP.Length).ToLower()) return true; + string UrlitemP = Urlitem.url.Replace("****", ""); + if (Regex.IsMatch(url, UrlitemP, RegexOptions.IgnoreCase)) return true; + if (url.Length >= UrlitemP.Length && UrlitemP.ToLower() == url.Substring(0, UrlitemP.Length).ToLower()) return true; - } } - return false; - } + return false; + + } - public bool CheckBlackList(string url) + public bool CheckBlackList(string url) + { + List BlackList = _cache.Cof_GetICaching>("BlackList", () => AppSettings.app("BlackList"), 10); + + if (!BlackList.Cof_CheckAvailable()) return false; + foreach (var Urlitem in BlackList) { - List BlackList = _cache.Cof_GetICaching>("BlackList", () => AppSettings.app("BlackList"), 10); - - if (!BlackList.Cof_CheckAvailable()) return false; - foreach (var Urlitem in BlackList) - { - if (Urlitem.url.Equals(url, StringComparison.OrdinalIgnoreCase)) return true; + if (Urlitem.url.Equals(url, StringComparison.OrdinalIgnoreCase)) return true; - if (Urlitem.url.IndexOf("****") > 0) - { - string UrlitemP = Urlitem.url.Replace("****", ""); - if (Regex.IsMatch(url, UrlitemP, RegexOptions.IgnoreCase)) return true; - if (url.Length >= UrlitemP.Length && UrlitemP.ToLower() == url.Substring(0, UrlitemP.Length).ToLower()) return true; + if (Urlitem.url.IndexOf("****") > 0) + { + string UrlitemP = Urlitem.url.Replace("****", ""); + if (Regex.IsMatch(url, UrlitemP, RegexOptions.IgnoreCase)) return true; + if (url.Length >= UrlitemP.Length && UrlitemP.ToLower() == url.Substring(0, UrlitemP.Length).ToLower()) return true; - } } - return false; - } - } + return false; - public class Urlobj - { - public string url { get; set; } } } +public class Urlobj +{ + public string url { get; set; } +} + diff --git a/Tiobon.Core.Gateway/Program.cs b/Tiobon.Core.Gateway/Program.cs index 5b58b61f..074d0354 100644 --- a/Tiobon.Core.Gateway/Program.cs +++ b/Tiobon.Core.Gateway/Program.cs @@ -1,28 +1,23 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Hosting; +namespace Tiobon.Core.AdminMvc; -namespace Tiobon.Core.AdminMvc +public class Program { - public class Program + public static void Main(string[] args) { - public static void Main(string[] args) - { - CreateHostBuilder(args).Build().Run(); - } - - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureAppConfiguration((hostingContext, config) => - { - config.AddJsonFile("appsettings.gw.json", optional: true, reloadOnChange: false) - .AddJsonFile($"appsettings.gw.{hostingContext.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: false) - .AddJsonFile("ocelot.json", optional: true, reloadOnChange: true) - .AddJsonFile($"ocelot.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true); - }) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup().UseUrls("http://*:9000"); - }); + CreateHostBuilder(args).Build().Run(); } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureAppConfiguration((hostingContext, config) => + { + config.AddJsonFile("appsettings.gw.json", optional: true, reloadOnChange: false) + .AddJsonFile($"appsettings.gw.{hostingContext.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: false) + .AddJsonFile("ocelot.json", optional: true, reloadOnChange: true) + .AddJsonFile($"ocelot.{hostingContext.HostingEnvironment.EnvironmentName}.json", true, true); + }) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup().UseUrls("http://*:9000"); + }); } diff --git a/Tiobon.Core.Model/HttpEnum.cs b/Tiobon.Core.Model/HttpEnum.cs deleted file mode 100644 index fc386293..00000000 --- a/Tiobon.Core.Model/HttpEnum.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Tiobon.Core.Model; - -public enum HttpEnum -{ - Common, - LocalHost -} diff --git a/Tiobon.Core.Model/ViewModels/EnumDemoDto.cs b/Tiobon.Core.Model/ViewModels/EnumDemoDto.cs deleted file mode 100644 index 50684bfc..00000000 --- a/Tiobon.Core.Model/ViewModels/EnumDemoDto.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Tiobon.Core.Model.ViewModels; - -public class EnumDemoDto -{ - public int Id { get; set; } - /// - /// Type Description balabala - /// - public EnumType Type { get; set; } -} - - -public enum EnumType -{ - foo, bar, baz -} diff --git a/Tiobon.Core.Model/ViewModels/TopgbViewModels.cs b/Tiobon.Core.Model/ViewModels/TopgbViewModels.cs deleted file mode 100644 index 1b1c9507..00000000 --- a/Tiobon.Core.Model/ViewModels/TopgbViewModels.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Tiobon.Core.Model.ViewModels; - -/// -/// 留言排名展示类 -/// -public class TopgbViewModels -{ - /// 博客ID - /// - /// - public int? TiobonId { get; set; } - - /// - /// 评论数量 - /// - public int counts { get; set; } - - /// 博客标题 - /// - /// - public string btitle { get; set; } -} diff --git a/Tiobon.Core.Model/ViewModels/UploadFileDto.cs b/Tiobon.Core.Model/ViewModels/UploadFileDto.cs deleted file mode 100644 index e229925b..00000000 --- a/Tiobon.Core.Model/ViewModels/UploadFileDto.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Microsoft.AspNetCore.Http; - -namespace Tiobon.Core.Model.ViewModels; - -public class UploadFileDto -{ - //多文件 - [Required] - public IFormFileCollection file { get; set; } - - //单文件 - //public IFormFile File { get; set; } - - //其他数据 - public string Foo { get; set; } - - -} diff --git a/Tiobon.Core.Tasks/GlobalUsings.cs b/Tiobon.Core.Tasks/GlobalUsings.cs index 88d274bd..27a89df1 100644 --- a/Tiobon.Core.Tasks/GlobalUsings.cs +++ b/Tiobon.Core.Tasks/GlobalUsings.cs @@ -1,2 +1,7 @@ global using Tiobon.Core.IServices; -global using Quartz; \ No newline at end of file +global using Quartz; +global using Microsoft.Extensions.Logging; +global using Tiobon.Core.Model.Entity; +global using Tiobon.Core.Model.Models; +global using Tiobon.Core.Model.ViewModels; +global using Tiobon.Core.Helper; diff --git a/Tiobon.Core.Tasks/QuartzNet/ISchedulerCenter.cs b/Tiobon.Core.Tasks/QuartzNet/ISchedulerCenter.cs index 4fb8d046..b815d3cf 100644 --- a/Tiobon.Core.Tasks/QuartzNet/ISchedulerCenter.cs +++ b/Tiobon.Core.Tasks/QuartzNet/ISchedulerCenter.cs @@ -1,9 +1,4 @@ -using Tiobon.Core.Model; -using Tiobon.Core.Model.Entity; -using Tiobon.Core.Model.Models; -using Tiobon.Core.Model.ViewModels; - -namespace Tiobon.Core.Tasks; +namespace Tiobon.Core.Tasks; /// /// 服务调度接口 diff --git a/Tiobon.Core.Tasks/QuartzNet/Jobs/JobBase.cs b/Tiobon.Core.Tasks/QuartzNet/Jobs/JobBase.cs index da89b7d8..992e1528 100644 --- a/Tiobon.Core.Tasks/QuartzNet/Jobs/JobBase.cs +++ b/Tiobon.Core.Tasks/QuartzNet/Jobs/JobBase.cs @@ -1,7 +1,4 @@ -using Tiobon.Core.Helper; -using Tiobon.Core.Model.Models; - -namespace Tiobon.Core.Tasks; +namespace Tiobon.Core.Tasks; public class JobBase { diff --git a/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_AutoClearLog_Quartz.cs b/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_AutoClearLog_Quartz.cs index d10d555b..7cd9e328 100644 --- a/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_AutoClearLog_Quartz.cs +++ b/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_AutoClearLog_Quartz.cs @@ -1,6 +1,4 @@ -using Microsoft.Extensions.Logging; - -/// +/// /// 这里要注意下,命名空间和程序集是一样的,不然反射不到(任务类要去JobSetup添加注入) /// namespace Tiobon.Core.Tasks; diff --git a/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_AutoIssueCertificate_Quartz.cs b/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_AutoIssueCertificate_Quartz.cs index df1b1ffa..7efba3f2 100644 --- a/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_AutoIssueCertificate_Quartz.cs +++ b/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_AutoIssueCertificate_Quartz.cs @@ -1,6 +1,4 @@ -using Microsoft.Extensions.Logging; - -/// +/// /// 这里要注意下,命名空间和程序集是一样的,不然反射不到(任务类要去JobSetup添加注入) /// namespace Tiobon.Core.Tasks; diff --git a/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_AutoIssueCredit_Quartz.cs b/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_AutoIssueCredit_Quartz.cs index df24a009..5bca2b32 100644 --- a/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_AutoIssueCredit_Quartz.cs +++ b/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_AutoIssueCredit_Quartz.cs @@ -1,5 +1,4 @@ -using Microsoft.Extensions.Logging; - + /// /// 这里要注意下,命名空间和程序集是一样的,不然反射不到(任务类要去JobSetup添加注入) /// diff --git a/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_AutoMarkCompleteStatus_Quartz.cs b/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_AutoMarkCompleteStatus_Quartz.cs index 4752692b..3d6f0e82 100644 --- a/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_AutoMarkCompleteStatus_Quartz.cs +++ b/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_AutoMarkCompleteStatus_Quartz.cs @@ -1,6 +1,4 @@ -using Microsoft.Extensions.Logging; - -/// +/// /// 这里要注意下,命名空间和程序集是一样的,不然反射不到(任务类要去JobSetup添加注入) /// namespace Tiobon.Core.Tasks; diff --git a/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_OperateLog_Quartz.cs b/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_OperateLog_Quartz.cs index cea113ee..98741054 100644 --- a/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_OperateLog_Quartz.cs +++ b/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_OperateLog_Quartz.cs @@ -1,7 +1,6 @@ using Microsoft.AspNetCore.Hosting; using System.Text; using Tiobon.Core.LogHelper; -using Tiobon.Core.Model.Models; /// /// 这里要注意下,命名空间和程序集是一样的,不然反射不到 diff --git a/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_URL_Quartz.cs b/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_URL_Quartz.cs index 2f7a30ff..0ea9ed93 100644 --- a/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_URL_Quartz.cs +++ b/Tiobon.Core.Tasks/QuartzNet/Jobs/Job_URL_Quartz.cs @@ -1,6 +1,4 @@ -using Microsoft.Extensions.Logging; -using Tiobon.Core.Helper; - + /// /// 这里要注意下,命名空间和程序集是一样的,不然反射不到(任务类要去JobSetup添加注入) /// diff --git a/Tiobon.Core.Tasks/QuartzNet/SchedulerCenterServer.cs b/Tiobon.Core.Tasks/QuartzNet/SchedulerCenterServer.cs index d0239586..4943632b 100644 --- a/Tiobon.Core.Tasks/QuartzNet/SchedulerCenterServer.cs +++ b/Tiobon.Core.Tasks/QuartzNet/SchedulerCenterServer.cs @@ -4,9 +4,6 @@ using Quartz.Spi; using System.Collections.Specialized; using System.Reflection; using Tiobon.Core.DB.Dapper; -using Tiobon.Core.Model.Entity; -using Tiobon.Core.Model.Models; -using Tiobon.Core.Model.ViewModels; namespace Tiobon.Core.Tasks; diff --git a/Tiobon.Core.Tests/Common_Test/DbAccess_Should.cs b/Tiobon.Core.Tests/Common_Test/DbAccess_Should.cs index b3d908fa..5beb0668 100644 --- a/Tiobon.Core.Tests/Common_Test/DbAccess_Should.cs +++ b/Tiobon.Core.Tests/Common_Test/DbAccess_Should.cs @@ -1,27 +1,25 @@ using System.Data; using Tiobon.Core.DB.Dapper; -using Tiobon.Core.Model.Models; using Xunit; -namespace Tiobon.Core.Tests.Common_Test +namespace Tiobon.Core.Tests.Common_Test; + +public class DbAccess_Should { - public class DbAccess_Should - { - [Fact] - public async void Test() - { - AppSetting.Init(); + [Fact] + public async void Test() + { + AppSetting.Init(); - string sql = "SELECT * FROM Ghra_Grade"; - DataTable dt = await DbAccess.GetDataTableAsync(sql); + string sql = "SELECT * FROM Ghra_Grade"; + DataTable dt = await DbAccess.GetDataTableAsync(sql); - //var list = await DbAccess.QueryListAsync(sql); + //var list = await DbAccess.QueryListAsync(sql); - //var entity = new Ghra_Grade(); - //DbAccess.Add(entity); + //var entity = new Ghra_Grade(); + //DbAccess.Add(entity); - } - } + } diff --git a/Tiobon.Core.Tests/Common_Test/HttpHelper_Should.cs b/Tiobon.Core.Tests/Common_Test/HttpHelper_Should.cs index d947a4b8..b87c4c57 100644 --- a/Tiobon.Core.Tests/Common_Test/HttpHelper_Should.cs +++ b/Tiobon.Core.Tests/Common_Test/HttpHelper_Should.cs @@ -1,26 +1,25 @@ using Tiobon.Core.Helper; using Xunit; -namespace Tiobon.Core.Tests.Common_Test -{ - public class HttpHelper_Should - { +namespace Tiobon.Core.Tests.Common_Test; - [Fact] - public async void Get_Async_Test() - { - var responseString = (await HttpHelper.GetAsync("http://apk.neters.club/api/Tiobon")); +public class HttpHelper_Should +{ - Assert.NotNull(responseString); - } + [Fact] + public async void Get_Async_Test() + { + var responseString = (await HttpHelper.GetAsync("http://apk.neters.club/api/Tiobon")); - [Fact] - public void Post_Async_Test() - { - var responseString = HttpHelper.PostAsync("http://apk.neters.club/api/Login/swgLogin", "{\"name\":\"admin\",\"pwd\":\"admin\"}"); + Assert.NotNull(responseString); + } - Assert.NotNull(responseString); - } + [Fact] + public void Post_Async_Test() + { + var responseString = HttpHelper.PostAsync("http://apk.neters.club/api/Login/swgLogin", "{\"name\":\"admin\",\"pwd\":\"admin\"}"); + Assert.NotNull(responseString); } + } diff --git a/Tiobon.Core.Tests/Common_Test/SM4Helper_Should.cs b/Tiobon.Core.Tests/Common_Test/SM4Helper_Should.cs index 5e975b3e..edaa6e8e 100644 --- a/Tiobon.Core.Tests/Common_Test/SM4Helper_Should.cs +++ b/Tiobon.Core.Tests/Common_Test/SM4Helper_Should.cs @@ -1,42 +1,39 @@ -using Tiobon.Core.Common.Helper; -using Tiobon.Core.Common.Helper.SM; -using System; +using Tiobon.Core.Common.Helper.SM; using Xunit; -namespace Tiobon.Core.Tests.Common_Test -{ - public class SM4Helper_Should - { +namespace Tiobon.Core.Tests.Common_Test; - [Fact] - public void Encrypt_ECB_Test() - { - var plainText = "暗号"; +public class SM4Helper_Should +{ - var sm4 = new SM4Helper(); + [Fact] + public void Encrypt_ECB_Test() + { + var plainText = "暗号"; - Console.Out.WriteLine("ECB模式"); - var cipherText = sm4.Encrypt_ECB(plainText); - Console.Out.WriteLine("密文: " + cipherText); + var sm4 = new SM4Helper(); - Assert.NotNull(cipherText); - Assert.Equal("VhVDC0KzyZjAVMpwz0GyQA==", cipherText); - } + Console.Out.WriteLine("ECB模式"); + var cipherText = sm4.Encrypt_ECB(plainText); + Console.Out.WriteLine("密文: " + cipherText); - [Fact] - public void Decrypt_ECB_Test() - { - var cipherText = "Y9ygWexdpuLQjW/qsnZNQw=="; + Assert.NotNull(cipherText); + Assert.Equal("VhVDC0KzyZjAVMpwz0GyQA==", cipherText); + } - var sm4 = new SM4Helper(); + [Fact] + public void Decrypt_ECB_Test() + { + var cipherText = "Y9ygWexdpuLQjW/qsnZNQw=="; - Console.Out.WriteLine("ECB模式"); - var plainText = sm4.Decrypt_ECB(cipherText); - Console.Out.WriteLine("明文: " + plainText); + var sm4 = new SM4Helper(); - Assert.NotNull(plainText); - Assert.Equal("老张的哲学", plainText); - } + Console.Out.WriteLine("ECB模式"); + var plainText = sm4.Decrypt_ECB(cipherText); + Console.Out.WriteLine("明文: " + plainText); + Assert.NotNull(plainText); + Assert.Equal("老张的哲学", plainText); } + } diff --git a/Tiobon.Core.Tests/Controller_Test/LoginController_Should.cs b/Tiobon.Core.Tests/Controller_Test/LoginController_Should.cs index 15ee2577..6ef170b5 100644 --- a/Tiobon.Core.Tests/Controller_Test/LoginController_Should.cs +++ b/Tiobon.Core.Tests/Controller_Test/LoginController_Should.cs @@ -5,74 +5,73 @@ using Autofac; using Tiobon.Core.AuthHelper; using Microsoft.Extensions.Logging; -namespace Tiobon.Core.Tests +namespace Tiobon.Core.Tests; + +public class LoginController_Should { - public class LoginController_Should + LoginController loginController; + + private readonly IGhrs_UserServices _ghrs_UserServices; + private readonly IUserRoleServices _userRoleServices; + private readonly IRoleServices _roleServices; + private readonly PermissionRequirement _requirement; + private readonly IRoleModulePermissionServices _roleModulePermissionServices; + private readonly ILogger _logger; + + DI_Test dI_Test = new DI_Test(); + + + public LoginController_Should() { - LoginController loginController; - - private readonly IGhrs_UserServices _ghrs_UserServices; - private readonly IUserRoleServices _userRoleServices; - private readonly IRoleServices _roleServices; - private readonly PermissionRequirement _requirement; - private readonly IRoleModulePermissionServices _roleModulePermissionServices; - private readonly ILogger _logger; - - DI_Test dI_Test = new DI_Test(); - - - public LoginController_Should() - { - var container = dI_Test.DICollections(); - _ghrs_UserServices = container.Resolve(); - _userRoleServices = container.Resolve(); - _roleServices = container.Resolve(); - _requirement = container.Resolve(); - _roleModulePermissionServices = container.Resolve(); - _logger = container.Resolve>(); - loginController = new LoginController(_ghrs_UserServices, _userRoleServices, _roleServices, _requirement, - _roleModulePermissionServices, _logger); - } - - [Fact] - public void GetJwtStrTest() - { - var data = loginController.GetJwtStr("test", "test"); - - Assert.NotNull(data); - } - - [Fact] - public void GetJwtStrForNuxtTest() - { - object Tiobons = loginController.GetJwtStrForNuxt("test", "test"); - - Assert.NotNull(Tiobons); - } - - [Fact] - public async void GetJwtToken3Test() - { - var res = await loginController.GetJwtToken3("test", "test"); - - Assert.NotNull(res); - } - - [Fact] - public async void RefreshTokenTest() - { - var res = await loginController.RefreshToken( - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoidGVzdCIsImp0aSI6IjgiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL2V4cGlyYXRpb24iOiIyMDE5LzEwLzE4IDIzOjI2OjQ5IiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9yb2xlIjoiQWRtaW5UZXN0IiwibmJmIjoxNTcxNDA4ODA5LCJleHAiOjE1NzE0MTI0MDksImlzcyI6IkJsb2cuQ29yZSIsImF1ZCI6IndyIn0.oz-SPz6UCL78fM09bUecw5rmjcNYEY9dWGtuPs2gdBg"); - - Assert.NotNull(res); - } - - [Fact] - public void Md5PasswordTest() - { - var res = loginController.Md5Password("test"); - - Assert.NotNull(res); - } + var container = dI_Test.DICollections(); + _ghrs_UserServices = container.Resolve(); + _userRoleServices = container.Resolve(); + _roleServices = container.Resolve(); + _requirement = container.Resolve(); + _roleModulePermissionServices = container.Resolve(); + _logger = container.Resolve>(); + loginController = new LoginController(_ghrs_UserServices, _userRoleServices, _roleServices, _requirement, + _roleModulePermissionServices, _logger); + } + + [Fact] + public void GetJwtStrTest() + { + var data = loginController.GetJwtStr("test", "test"); + + Assert.NotNull(data); + } + + [Fact] + public void GetJwtStrForNuxtTest() + { + object Tiobons = loginController.GetJwtStrForNuxt("test", "test"); + + Assert.NotNull(Tiobons); + } + + [Fact] + public async void GetJwtToken3Test() + { + var res = await loginController.GetJwtToken3("test", "test"); + + Assert.NotNull(res); + } + + [Fact] + public async void RefreshTokenTest() + { + var res = await loginController.RefreshToken( + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoidGVzdCIsImp0aSI6IjgiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL2V4cGlyYXRpb24iOiIyMDE5LzEwLzE4IDIzOjI2OjQ5IiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9yb2xlIjoiQWRtaW5UZXN0IiwibmJmIjoxNTcxNDA4ODA5LCJleHAiOjE1NzE0MTI0MDksImlzcyI6IkJsb2cuQ29yZSIsImF1ZCI6IndyIn0.oz-SPz6UCL78fM09bUecw5rmjcNYEY9dWGtuPs2gdBg"); + + Assert.NotNull(res); + } + + [Fact] + public void Md5PasswordTest() + { + var res = loginController.Md5Password("test"); + + Assert.NotNull(res); } } \ No newline at end of file diff --git a/Tiobon.Core.Tests/DependencyInjection/DI_Test.cs b/Tiobon.Core.Tests/DependencyInjection/DI_Test.cs index 89848c06..b6421826 100644 --- a/Tiobon.Core.Tests/DependencyInjection/DI_Test.cs +++ b/Tiobon.Core.Tests/DependencyInjection/DI_Test.cs @@ -19,125 +19,124 @@ using Tiobon.Core.IRepository.Base; using Tiobon.Core.Repository.Base; using Tiobon.Core.Repository.MongoRepository; -namespace Tiobon.Core.Tests +namespace Tiobon.Core.Tests; + +public class DI_Test { - public class DI_Test + /// + /// 连接字符串 + /// Tiobon.Core + /// + public static MutiDBOperate GetMainConnectionDb() { - /// - /// 连接字符串 - /// Tiobon.Core - /// - public static MutiDBOperate GetMainConnectionDb() + var mainConnetctDb = BaseDBConfig.MutiConnectionString.allDbs.Find(x => x.ConnId == MainDb.CurrentDbConnId); + if (BaseDBConfig.MutiConnectionString.allDbs.Count > 0) { - var mainConnetctDb = BaseDBConfig.MutiConnectionString.allDbs.Find(x => x.ConnId == MainDb.CurrentDbConnId); - if (BaseDBConfig.MutiConnectionString.allDbs.Count > 0) - { - if (mainConnetctDb == null) - { - mainConnetctDb = BaseDBConfig.MutiConnectionString.allDbs[0]; - } - } - else + if (mainConnetctDb == null) { - throw new Exception("请确保appsettigns.json中配置连接字符串,并设置Enabled为true;"); + mainConnetctDb = BaseDBConfig.MutiConnectionString.allDbs[0]; } - - return mainConnetctDb; } - - public IContainer DICollections() + else { - var basePath = AppContext.BaseDirectory; + throw new Exception("请确保appsettigns.json中配置连接字符串,并设置Enabled为true;"); + } - IServiceCollection services = new ServiceCollection(); - services.AddAutoMapperSetup(); + return mainConnetctDb; + } - services.AddSingleton(new AppSettings(basePath)); - services.AddScoped(); - services.AddScoped(); + public IContainer DICollections() + { + var basePath = AppContext.BaseDirectory; - //读取配置文件 - var symmetricKeyAsBase64 = AppSecretConfig.Audience_Secret_String; - var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64); - var signingKey = new SymmetricSecurityKey(keyByteArray); + IServiceCollection services = new ServiceCollection(); + services.AddAutoMapperSetup(); + services.AddSingleton(new AppSettings(basePath)); + services.AddScoped(); + services.AddScoped(); - var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256); + //读取配置文件 + var symmetricKeyAsBase64 = AppSecretConfig.Audience_Secret_String; + var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64); + var signingKey = new SymmetricSecurityKey(keyByteArray); - var permission = new List(); - var permissionRequirement = new PermissionRequirement( - "/api/denied", - permission, - ClaimTypes.Role, - AppSettings.app(new string[] { "Audience", "Issuer" }), - AppSettings.app(new string[] { "Audience", "Audience" }), - signingCredentials, //签名凭据 - expiration: TimeSpan.FromSeconds(60 * 60) //接口的过期时间 - ); - services.AddSingleton(permissionRequirement); + var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256); - //【授权】 - services.AddAuthorization(options => - { - options.AddPolicy(Permissions.Name, - policy => policy.Requirements.Add(permissionRequirement)); - }); + var permission = new List(); - services.AddScoped(o => + var permissionRequirement = new PermissionRequirement( + "/api/denied", + permission, + ClaimTypes.Role, + AppSettings.app(new string[] { "Audience", "Issuer" }), + AppSettings.app(new string[] { "Audience", "Audience" }), + signingCredentials, //签名凭据 + expiration: TimeSpan.FromSeconds(60 * 60) //接口的过期时间 + ); + services.AddSingleton(permissionRequirement); + + //【授权】 + services.AddAuthorization(options => + { + options.AddPolicy(Permissions.Name, + policy => policy.Requirements.Add(permissionRequirement)); + }); + + services.AddScoped(o => + { + return new SqlSugar.SqlSugarScope(new SqlSugar.ConnectionConfig() { - return new SqlSugar.SqlSugarScope(new SqlSugar.ConnectionConfig() - { - ConnectionString = GetMainConnectionDb().Connection, //必填, 数据库连接字符串 - DbType = (SqlSugar.DbType)GetMainConnectionDb().DbType, //必填, 数据库类型 - IsAutoCloseConnection = true, //默认false, 时候知道关闭数据库连接, 设置为true无需使用using或者Close操作 - }); + ConnectionString = GetMainConnectionDb().Connection, //必填, 数据库连接字符串 + DbType = (SqlSugar.DbType)GetMainConnectionDb().DbType, //必填, 数据库类型 + IsAutoCloseConnection = true, //默认false, 时候知道关闭数据库连接, 设置为true无需使用using或者Close操作 }); + }); - //实例化 AutoFac 容器 - var builder = new ContainerBuilder(); - //builder.RegisterType().As(); - builder.RegisterInstance(new LoggerFactory()) - .As(); + //实例化 AutoFac 容器 + var builder = new ContainerBuilder(); + //builder.RegisterType().As(); + builder.RegisterInstance(new LoggerFactory()) + .As(); - builder.RegisterGeneric(typeof(Logger<>)) - .As(typeof(ILogger<>)) - .SingleInstance(); - //指定已扫描程序集中的类型注册为提供所有其实现的接口。 + builder.RegisterGeneric(typeof(Logger<>)) + .As(typeof(ILogger<>)) + .SingleInstance(); + //指定已扫描程序集中的类型注册为提供所有其实现的接口。 - builder.RegisterGeneric(typeof(BaseRepository<>)).As(typeof(IBaseRepository<>)).InstancePerDependency(); //注册仓储 - builder.RegisterGeneric(typeof(MongoBaseRepository<>)).As(typeof(IMongoBaseRepository<>)).InstancePerDependency(); //注册仓储 + builder.RegisterGeneric(typeof(BaseRepository<>)).As(typeof(IBaseRepository<>)).InstancePerDependency(); //注册仓储 + builder.RegisterGeneric(typeof(MongoBaseRepository<>)).As(typeof(IMongoBaseRepository<>)).InstancePerDependency(); //注册仓储 - // 属性注入 - var controllerBaseType = typeof(ControllerBase); - //builder.RegisterAssemblyTypes(typeof(Program).Assembly) - // .Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType) - // .PropertiesAutowired(); + // 属性注入 + var controllerBaseType = typeof(ControllerBase); + //builder.RegisterAssemblyTypes(typeof(Program).Assembly) + // .Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType) + // .PropertiesAutowired(); - var servicesDllFile = Path.Combine(basePath, "Tiobon.Core.Services.dll"); - var assemblysServices = Assembly.LoadFrom(servicesDllFile); - builder.RegisterAssemblyTypes(assemblysServices) - .AsImplementedInterfaces() - .InstancePerLifetimeScope() - .PropertiesAutowired() - .EnableInterfaceInterceptors(); + var servicesDllFile = Path.Combine(basePath, "Tiobon.Core.Services.dll"); + var assemblysServices = Assembly.LoadFrom(servicesDllFile); + builder.RegisterAssemblyTypes(assemblysServices) + .AsImplementedInterfaces() + .InstancePerLifetimeScope() + .PropertiesAutowired() + .EnableInterfaceInterceptors(); - var repositoryDllFile = Path.Combine(basePath, "Tiobon.Core.Repository.dll"); - var assemblysRepository = Assembly.LoadFrom(repositoryDllFile); - builder.RegisterAssemblyTypes(assemblysRepository) - .PropertiesAutowired().AsImplementedInterfaces(); + var repositoryDllFile = Path.Combine(basePath, "Tiobon.Core.Repository.dll"); + var assemblysRepository = Assembly.LoadFrom(repositoryDllFile); + builder.RegisterAssemblyTypes(assemblysRepository) + .PropertiesAutowired().AsImplementedInterfaces(); - services.Replace(ServiceDescriptor.Transient()); + services.Replace(ServiceDescriptor.Transient()); - services.AddAutoMapperSetup(); + services.AddAutoMapperSetup(); - //将services填充到Autofac容器生成器中 - builder.Populate(services); + //将services填充到Autofac容器生成器中 + builder.Populate(services); - //使用已进行的组件登记创建新容器 - var ApplicationContainer = builder.Build(); + //使用已进行的组件登记创建新容器 + var ApplicationContainer = builder.Build(); - return ApplicationContainer; - } + return ApplicationContainer; } } \ No newline at end of file diff --git a/Tiobon.Core.Tests/Redis_Test/Redis_Should.cs b/Tiobon.Core.Tests/Redis_Test/Redis_Should.cs index fff7ac21..e7b94162 100644 --- a/Tiobon.Core.Tests/Redis_Test/Redis_Should.cs +++ b/Tiobon.Core.Tests/Redis_Test/Redis_Should.cs @@ -1,26 +1,25 @@ using Xunit; -namespace Tiobon.Core.Tests -{ - public class Redis_Should - { - DI_Test dI_Test = new DI_Test(); +namespace Tiobon.Core.Tests; - public Redis_Should() - { - //var container = dI_Test.DICollections(); - //_redisCacheManager = container.Resolve(); +public class Redis_Should +{ + DI_Test dI_Test = new DI_Test(); - } + public Redis_Should() + { + //var container = dI_Test.DICollections(); + //_redisCacheManager = container.Resolve(); - [Fact] - public void Connect_Redis_Test() - { + } - //var redisTiobonCache = _redisCacheManager.Get("Redis.Tiobon"); + [Fact] + public void Connect_Redis_Test() + { - //Assert.Null(redisTiobonCache); - } + //var redisTiobonCache = _redisCacheManager.Get("Redis.Tiobon"); + //Assert.Null(redisTiobonCache); } + } diff --git a/Tiobon.Core.Tests/Repository_Test/MongoRepository_Base_Should.cs b/Tiobon.Core.Tests/Repository_Test/MongoRepository_Base_Should.cs index be094f15..e1de47b3 100644 --- a/Tiobon.Core.Tests/Repository_Test/MongoRepository_Base_Should.cs +++ b/Tiobon.Core.Tests/Repository_Test/MongoRepository_Base_Should.cs @@ -1,60 +1,55 @@ -using Tiobon.Core.Model.Models; -using Xunit; -using System; -using System.Linq; -using Autofac; -using Tiobon.Core.IRepository.Base; -using Tiobon.Core.Repository.MongoRepository; -using MongoDB.Bson.Serialization.Attributes; +using Autofac; using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; using MongoDB.Driver; +using Tiobon.Core.Repository.MongoRepository; +using Xunit; -namespace Tiobon.Core.Tests +namespace Tiobon.Core.Tests; + +public class MongoRepository_Base_Should { - public class MongoRepository_Base_Should + public class MongoTest { - public class MongoTest - { - [BsonId] - public ObjectId id { get; set; } - public string name { get; set; } - public bool isDel { get; set; } - public DateTime time { get; set; } - } + [BsonId] + public ObjectId id { get; set; } + public string name { get; set; } + public bool isDel { get; set; } + public DateTime time { get; set; } + } - private IMongoBaseRepository baseRepository; - DI_Test dI_Test = new DI_Test(); + private IMongoBaseRepository baseRepository; + DI_Test dI_Test = new DI_Test(); - public MongoRepository_Base_Should() - { + public MongoRepository_Base_Should() + { - var container = dI_Test.DICollections(); + var container = dI_Test.DICollections(); - baseRepository = container.Resolve>(); - } + baseRepository = container.Resolve>(); + } - [Fact] - public async void Add_Test() - { - await baseRepository.AddAsync(new MongoTest { isDel = false, name = "test", time = DateTime.UtcNow }); - } + [Fact] + public async void Add_Test() + { + await baseRepository.AddAsync(new MongoTest { isDel = false, name = "test", time = DateTime.UtcNow }); + } - [Fact] - public async void GetObjectId_Test() - { - var data = await baseRepository.GetByObjectIdAsync("612b9b0be677976fa0f0cfa2"); + [Fact] + public async void GetObjectId_Test() + { + var data = await baseRepository.GetByObjectIdAsync("612b9b0be677976fa0f0cfa2"); - Assert.NotNull(data); - } + Assert.NotNull(data); + } - [Fact] - public async void GetListFilter_Test() - { - var data = await baseRepository.GetListFilterAsync(new FilterDefinitionBuilder().Gte("time", DateTime.Parse("2022-06-01"))); + [Fact] + public async void GetListFilter_Test() + { + var data = await baseRepository.GetListFilterAsync(new FilterDefinitionBuilder().Gte("time", DateTime.Parse("2022-06-01"))); - Assert.NotNull(data); - } + Assert.NotNull(data); } } diff --git a/Tiobon.Core.Tests/Repository_Test/Repository_Base_Should.cs b/Tiobon.Core.Tests/Repository_Test/Repository_Base_Should.cs index f04db0bf..240624af 100644 --- a/Tiobon.Core.Tests/Repository_Test/Repository_Base_Should.cs +++ b/Tiobon.Core.Tests/Repository_Test/Repository_Base_Should.cs @@ -1,81 +1,78 @@ -using Tiobon.Core.Model.Models; -using Xunit; -using System; -using System.Linq; -using Autofac; +using Autofac; using Tiobon.Core.IRepository.Base; +using Tiobon.Core.Model.Models; +using Xunit; + +namespace Tiobon.Core.Tests; -namespace Tiobon.Core.Tests +public class Repository_Base_Should { - public class Repository_Base_Should + private IBaseRepository baseRepository; + DI_Test dI_Test = new DI_Test(); + + public Repository_Base_Should() { - private IBaseRepository baseRepository; - DI_Test dI_Test = new DI_Test(); - public Repository_Base_Should() - { + var container = dI_Test.DICollections(); - var container = dI_Test.DICollections(); + baseRepository = container.Resolve>(); + + //DbContext.Init(BaseDBConfig.ConnectionString,(DbType)BaseDBConfig.DbType); + } - baseRepository = container.Resolve>(); - //DbContext.Init(BaseDBConfig.ConnectionString,(DbType)BaseDBConfig.DbType); - } + [Fact] + public async void Get_Tiobons_Test() + { + var data = await baseRepository.Query(); + Assert.NotNull(data); + } - [Fact] - public async void Get_Tiobons_Test() + [Fact] + public async void Add_Tiobon_Test() + { + TiobonArticle TiobonArticle = new TiobonArticle() { - var data = await baseRepository.Query(); + bCreateTime = DateTime.Now, + bUpdateTime = DateTime.Now, + btitle = "xuint test title", + bcontent = "xuint test content", + bsubmitter = "xuint: test repositoryBase add Tiobon", + }; + + var BId = await baseRepository.Add(TiobonArticle); + Assert.True(BId > 0); + } - Assert.NotNull(data); - } - [Fact] - public async void Add_Tiobon_Test() - { - TiobonArticle TiobonArticle = new TiobonArticle() - { - bCreateTime = DateTime.Now, - bUpdateTime = DateTime.Now, - btitle = "xuint test title", - bcontent = "xuint test content", - bsubmitter = "xuint: test repositoryBase add Tiobon", - }; - - var BId = await baseRepository.Add(TiobonArticle); - Assert.True(BId > 0); - } - - - [Fact] - public async void Update_Tiobon_Test() - { - var IsUpd = false; - var updateModel = (await baseRepository.Query(d => d.btitle == "xuint test title")).FirstOrDefault(); + [Fact] + public async void Update_Tiobon_Test() + { + var IsUpd = false; + var updateModel = (await baseRepository.Query(d => d.btitle == "xuint test title")).FirstOrDefault(); - Assert.NotNull(updateModel); + Assert.NotNull(updateModel); - updateModel.bcontent = "xuint: test repositoryBase content update"; - updateModel.bCreateTime = DateTime.Now; - updateModel.bUpdateTime = DateTime.Now; + updateModel.bcontent = "xuint: test repositoryBase content update"; + updateModel.bCreateTime = DateTime.Now; + updateModel.bUpdateTime = DateTime.Now; - IsUpd = await baseRepository.Update(updateModel); + IsUpd = await baseRepository.Update(updateModel); - Assert.True(IsUpd); - } + Assert.True(IsUpd); + } - [Fact] - public async void Delete_Tiobon_Test() - { - var IsDel = false; - var deleteModel = (await baseRepository.Query(d => d.btitle == "xuint test title")).FirstOrDefault(); + [Fact] + public async void Delete_Tiobon_Test() + { + var IsDel = false; + var deleteModel = (await baseRepository.Query(d => d.btitle == "xuint test title")).FirstOrDefault(); - Assert.NotNull(deleteModel); + Assert.NotNull(deleteModel); - IsDel = await baseRepository.Delete(deleteModel); + IsDel = await baseRepository.Delete(deleteModel); - Assert.True(IsDel); - } + Assert.True(IsDel); } } diff --git a/Tiobon.Core.sln b/Tiobon.Core.sln index 62e8c58e..06cb1581 100644 --- a/Tiobon.Core.sln +++ b/Tiobon.Core.sln @@ -8,16 +8,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt .dockerignore = .dockerignore .editorconfig = .editorconfig .gitignore = .gitignore - Blog.Core.Build.bat = Blog.Core.Build.bat - Blog.Core.Publish.bat = Blog.Core.Publish.bat - Blog.Core.Publish.Docker.Jenkins.sh = Blog.Core.Publish.Docker.Jenkins.sh - Blog.Core.Publish.Docker.sh = Blog.Core.Publish.Docker.sh - Blog.Core.Publish.Linux.sh = Blog.Core.Publish.Linux.sh - codecov.yml = codecov.yml build\common.targets = build\common.targets - CreateYourProject.bat = CreateYourProject.bat - DockerBuild.bat = DockerBuild.bat - Dockerfile = Dockerfile nuget.config = nuget.config README.md = README.md EndProjectSection diff --git a/Tiobon.Core/Tiobon.Core.Model.xml b/Tiobon.Core/Tiobon.Core.Model.xml index 2cd41bdf..6e59100b 100644 --- a/Tiobon.Core/Tiobon.Core.Model.xml +++ b/Tiobon.Core/Tiobon.Core.Model.xml @@ -42792,11 +42792,6 @@ - - - Type Description balabala - - bgColor @@ -43662,26 +43657,6 @@ 用来测试 RestSharp Post 请求 - - - 留言排名展示类 - - - - 博客ID - - - - - - 评论数量 - - - - 博客标题 - - - 分组