├── .gitattributes ├── .gitignore ├── Colder.Components.sln ├── Directory.Build.props ├── LICENSE ├── README.md ├── demos ├── Demo.AspnetCore │ ├── Controllers │ │ ├── HomeController.cs │ │ └── UserController.cs │ ├── Demo.AspnetCore.csproj │ ├── Dtos │ │ ├── UserDto.cs │ │ ├── UserExtendDto.cs │ │ └── UserSearchDto.cs │ ├── Entities │ │ ├── DemoDbContext.cs │ │ └── User.cs │ ├── MapperProdiles │ │ └── CommonProfile.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── appsettings.json │ └── db.db ├── Demo.Common │ ├── Demo.Common.csproj │ ├── MessageBusEndpoints.cs │ ├── RequestMessage.cs │ ├── ResponseMessage.cs │ └── SubRequestMessage.cs ├── Demo.DistributedId │ ├── Demo.DistributedId.csproj │ └── Program.cs ├── Demo.DistributedLock │ ├── Demo.DistributedLock.csproj │ └── Program.cs ├── Demo.Logging │ ├── Controllers │ │ └── HomeController.cs │ ├── Demo.Logging.csproj │ ├── Program.cs │ ├── Properties │ │ ├── PublishProfiles │ │ │ └── FolderProfile.pubxml │ │ └── launchSettings.json │ ├── Startup.cs │ └── appsettings.json ├── Demo.MessageBus │ ├── Controllers │ │ └── HomeController.cs │ ├── Demo.MessageBus.csproj │ ├── Handler.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── PublishService.cs │ ├── Startup.cs │ └── appsettings.json ├── Demo.OpenService.Client │ ├── Demo.OpenService.Client.csproj │ └── Program.cs ├── Demo.OpenService.Common │ ├── Demo.OpenService.Common.csproj │ └── IHelloOpenService.cs ├── Demo.OpenService.Server │ ├── Controllers │ │ └── HelloService.cs │ ├── Demo.OpenService.Server.csproj │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Startup.cs │ └── appsettings.json ├── Demo.Orleans │ ├── Bootstrapper.cs │ ├── Demo.Orleans.csproj │ ├── Grains │ │ └── HelloGrain.cs │ ├── IGrains │ │ └── IHello.cs │ ├── Program.cs │ ├── Properties │ │ └── PublishProfiles │ │ │ └── FolderProfile.pubxml │ └── appsettings.json ├── Demo.WebSockets.Server │ ├── Controllers │ │ └── HomeController.cs │ ├── Demo.WebSockets.Server.csproj │ ├── Program.cs │ ├── Properties │ │ ├── PublishProfiles │ │ │ └── FolderProfile.pubxml │ │ └── launchSettings.json │ ├── Startup.cs │ ├── appsettings.Development.json │ ├── appsettings.json │ └── wwwroot │ │ └── index.html └── Domo.Console │ ├── Domo.Console.csproj │ └── Program.cs ├── src ├── Colder.Api.Abstractions │ ├── ApiExtentions.cs │ ├── Colder.Api.Abstractions.csproj │ ├── Controllers │ │ ├── ApiControllerBase.cs │ │ ├── CRUDControllerBase.cs │ │ └── SaveContext.cs │ ├── Filters │ │ ├── ExceptionFilter.cs │ │ └── TransactionFilter.cs │ ├── JwtExtentions.cs │ ├── Middlewares │ │ ├── RealIpMiddleware.cs │ │ ├── RequestInfo.cs │ │ ├── RequestInfoMiddleware.cs │ │ └── RequestLogMiddleware.cs │ ├── Options │ │ ├── ApiOptions.cs │ │ └── SwaggerDocumentOptions.cs │ └── Swagger │ │ ├── ControllerFilterProcessor.cs │ │ └── EnumSchemaProcessor.cs ├── Colder.AutoMapper │ ├── Colder.AutoMapper.csproj │ └── MappingExpressionExtensions.cs ├── Colder.Cache │ ├── CacheExtentions.cs │ ├── Colder.Cache.csproj │ └── Options │ │ ├── CacheOptions.cs │ │ └── CacheTypes.cs ├── Colder.Common.Util │ ├── Colder.Common.Util.csproj │ ├── ElasticClientExtentions.cs │ ├── Helpers │ │ ├── FileZipHelper.cs │ │ ├── JobHelper.cs │ │ ├── LinqHelper.cs │ │ ├── NPOIHelper.cs │ │ ├── ProxyHelper.cs │ │ └── QRCodeHelper.cs │ └── SDKs │ │ └── MiraiClient.cs ├── Colder.Common │ ├── Colder.Common.csproj │ ├── Extentions │ │ ├── ByteExtentions.cs │ │ ├── DataTableExtentions.cs │ │ ├── DateTimeExtentions.cs │ │ ├── DeepCloneExtensions.cs │ │ ├── EnumExtentions.cs │ │ ├── ExpressionExtentions.cs │ │ ├── HttpClientExtentions.cs │ │ ├── IEnumerableExtentions.cs │ │ ├── IQueryableExtentions.cs │ │ ├── ObjectExtentions.cs │ │ ├── ReflectionExtentions.cs │ │ ├── StreamExtentions.cs │ │ ├── StringExtentions.cs │ │ └── TypeExtentions.cs │ ├── Helpers │ │ ├── AsyncHelper.cs │ │ ├── EncodingHelper.cs │ │ ├── EnumHelper.cs │ │ ├── ImgHelper.cs │ │ ├── ImgVerifyCodeHelper.cs │ │ ├── IpHelper.cs │ │ ├── RSAHelper.cs │ │ ├── RandomHelper.cs │ │ ├── TimestampHelper.cs │ │ ├── TrackingHelper.cs │ │ ├── TreeHelper.cs │ │ └── TypeBuilderHelper.cs │ ├── Pipeline.cs │ └── Primitives │ │ ├── ApiResult.cs │ │ ├── IdInput.cs │ │ ├── MemoryMessageHandlerBase.cs │ │ ├── MsgException.cs │ │ ├── PageInput.cs │ │ └── PageList.cs ├── Colder.Dependency │ ├── AOP │ │ ├── BaseAOPAttribute.cs │ │ ├── CastleAOPContext.cs │ │ ├── CastleInterceptor.cs │ │ └── IAOPContext.cs │ ├── Colder.Dependency.csproj │ ├── DependencyExtentions.cs │ ├── IScopedDependency.cs │ ├── ISingletonDependency.cs │ └── ITransientDependency.cs ├── Colder.DistributedId │ ├── AsyncHelper.cs │ ├── Colder.DistributedId.csproj │ ├── DistributedId.cs │ ├── DistributedIdExtentions.cs │ ├── DistributedIdOptions.cs │ ├── Guid │ │ └── GuidHelper.cs │ ├── IDistributedId.cs │ └── Snowflake │ │ ├── DisposableAction.cs │ │ ├── IdWorker.cs │ │ ├── InvalidSystemClock.cs │ │ └── TimeExtensions.cs ├── Colder.DistributedLock.Abstractions │ ├── Colder.DistributedLock.Abstractions.csproj │ ├── DistributedLockOptions.cs │ ├── IDistributedLock.cs │ └── LockTypes.cs ├── Colder.DistributedLock.Hosting │ ├── Colder.DistributedLock.Hosting.csproj │ └── DistributedLockExtentions.cs ├── Colder.DistributedLock.InMemory │ ├── Colder.DistributedLock.InMemory.csproj │ └── InMemoryDistributedLock.cs ├── Colder.DistributedLock.Redis │ ├── Colder.DistributedLock.Redis.csproj │ └── RedisDistributedLock.cs ├── Colder.Domain.Abstractions │ ├── Colder.Domain.Abstractions.csproj │ ├── IAggregateRoot.cs │ ├── IRepositoryBase.cs │ └── IStatefulAggregateRoot.cs ├── Colder.EFCore │ ├── Colder.EFCore.csproj │ └── EFCoreExtentions.cs ├── Colder.Extentions │ ├── AOPTransactionExtentions.cs │ ├── Colder.Extentions.csproj │ └── TransactionalAttribute.cs ├── Colder.ImageSharp │ ├── Colder.ImageSharp.csproj │ └── ImageSharpHelper.cs ├── Colder.Infrastructure.Abstractions │ ├── Colder.Infrastructure.Abstractions.csproj │ └── DbRepositoryBase.cs ├── Colder.Json │ ├── Colder.Json.csproj │ ├── Converters │ │ ├── LongToStringConverter.cs │ │ └── TimestampConverter.cs │ └── JsonExtensions.cs ├── Colder.Logging.Abstractions │ ├── Colder.Logging.Abstractions.csproj │ ├── ElasticsearchOption.cs │ ├── EnableOption.cs │ ├── FileOption.cs │ ├── KafkaOption.cs │ ├── LogOptions.cs │ └── OverrideOption.cs ├── Colder.Logging.Serilog │ ├── Bootstrapper.cs │ ├── Colder.Logging.Serilog.csproj │ └── SerilogExtentions.cs ├── Colder.Mail │ ├── Colder.Mail.csproj │ └── IdleClient.cs ├── Colder.MessageBus.Abstractions │ ├── Colder.MessageBus.Abstractions.csproj │ ├── IMessageBus.cs │ ├── IMessageHandler.cs │ ├── MessageContext.T.cs │ ├── MessageContext.cs │ └── Options │ │ ├── Constant.cs │ │ ├── MessageBusOptions.cs │ │ └── TransportType.cs ├── Colder.MessageBus.Hosting │ ├── AbstractProvider.cs │ ├── Cache.cs │ ├── Colder.MessageBus.Hosting.csproj │ ├── DependencyInjection │ │ ├── DependencyInjectionExtentions.cs │ │ └── MessageBusBootstraper.cs │ ├── MessageBusFactory.cs │ └── Primitives │ │ ├── HandlerClass.cs │ │ └── HandlerMethod.cs ├── Colder.MessageBus.InMemory │ ├── Colder.MessageBus.InMemory.csproj │ ├── InMemoryProvider.cs │ ├── MassTransitMessageBus.cs │ ├── MassTransitProvider.cs │ └── ProxyHandler.cs ├── Colder.MessageBus.MQTT │ ├── Colder.MessageBus.MQTT.csproj │ ├── MQTTProvider.cs │ ├── MassTransit │ │ ├── MqttMessageReceivedEvent.cs │ │ └── MqttMessageReceivedEventHandler.cs │ ├── MqttMessageBus.cs │ ├── Primitives │ │ ├── MessageTypes.cs │ │ ├── Topic.cs │ │ └── Waiter.cs │ └── RequestWaiter.cs ├── Colder.MessageBus.RabbitMQ │ ├── Colder.MessageBus.RabbitMQ.csproj │ └── RabbitMQProvider.cs ├── Colder.MessageBus.Redis │ ├── Colder.MessageBus.Redis.csproj │ ├── Primitives │ │ ├── MessageTypes.cs │ │ ├── Topic.cs │ │ └── Waiter.cs │ ├── RedisMessageBus.cs │ └── RedisProvider.cs ├── Colder.OpenService.Abstractions │ ├── Attributes │ │ └── RouteAttribute.cs │ ├── Colder.OpenService.Abstractions.csproj │ ├── ICRUDOpenService.cs │ ├── IOpenService.cs │ └── Util │ │ ├── Extentions.cs │ │ └── Helper.cs ├── Colder.OpenService.Client │ ├── Colder.OpenService.Client.csproj │ ├── OpenServiceClientExtentions.cs │ ├── OpenServiceClientFactory.cs │ └── OpenServiceOptions.cs ├── Colder.OpenService.Hosting │ ├── Colder.OpenService.Hosting.csproj │ ├── Constant.cs │ ├── DependencyInjection │ │ └── OpenServiceHostDependencyInjectionExtentions.cs │ ├── Filters │ │ └── RPCResultFilter.cs │ ├── OpenServiceBase.cs │ ├── Properties │ │ └── launchSettings.json │ ├── WebApiRPCConvention.cs │ └── WebApiRPCProvider.cs ├── Colder.Orleans.Hosting │ ├── Colder.Orleans.Hosting.csproj │ ├── Options │ │ ├── OrleansOptions.cs │ │ └── ProviderTypes.cs │ └── OrleansExtentions.cs ├── Colder.Pdf │ ├── Colder.Pdf.csproj │ └── PdfHelper.cs ├── Colder.WebSockets.Abstractions │ ├── Colder.WebSockets.Abstractions.csproj │ ├── IWebSocketConnection.cs │ ├── IWebSocketServer.cs │ └── WebSocketServerOptions.cs └── Colder.WebSockets.Server │ ├── Colder.WebSockets.Server.csproj │ ├── MessageReceivedEvent.cs │ ├── WebSocketConnection.cs │ ├── WebSocketServer.cs │ └── WebSocketServerExtentions.cs ├── tests └── Colder.Tests │ ├── CacheTest.cs │ ├── Colder.Tests.csproj │ ├── HelperTest.cs │ ├── InMemoryDistributedLockTest.cs │ └── RedisDistributedLockTest.cs └── version.json /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | latestMajor 5 | 6 | true 7 | https://github.com/Coldairarrow/Colder.Components 8 | Coldairarrow 9 | Coldairarrow 10 | net6.0 11 | 12 | 13 | 14 | 15 | all 16 | 3.5.119 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /demos/Demo.AspnetCore/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using Colder.Common; 2 | using Colder.DistributedId; 3 | using Microsoft.AspNetCore.Mvc; 4 | 5 | namespace Demo.AspnetCore.Controllers 6 | { 7 | [ApiController] 8 | [Route("[controller]")] 9 | [ApiExplorerSettings(GroupName = "default")] 10 | public class HomeController : ControllerBase 11 | { 12 | private readonly IDistributedId _distributedId; 13 | public HomeController(IDistributedId distributedId) 14 | { 15 | _distributedId = distributedId; 16 | } 17 | 18 | [HttpPost] 19 | [Route("test")] 20 | //[AllowAnonymous] 21 | public string Test(IdInput id) 22 | { 23 | return _distributedId.NewLongId().ToString(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /demos/Demo.AspnetCore/Controllers/UserController.cs: -------------------------------------------------------------------------------- 1 | using Colder.Api.Abstractions.Controllers; 2 | using Demo.AspnetCore.Dtos; 3 | using Demo.AspnetCore.Entities; 4 | using Microsoft.AspNetCore.Authorization; 5 | using Microsoft.AspNetCore.Mvc; 6 | using NSwag.Annotations; 7 | using System; 8 | 9 | namespace Demo.AspnetCore.Controllers; 10 | 11 | [AllowAnonymous] 12 | [ApiExplorerSettings(GroupName = "group1")] 13 | public class UserController : CRUDControllerBase 14 | { 15 | public UserController(IServiceProvider serviceProvider) : base(serviceProvider) 16 | { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /demos/Demo.AspnetCore/Demo.AspnetCore.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | CS1591; 6 | disable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | PreserveNewest 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /demos/Demo.AspnetCore/Dtos/UserDto.cs: -------------------------------------------------------------------------------- 1 | namespace Demo.AspnetCore.Dtos; 2 | 3 | public class UserDto 4 | { 5 | public long Id { get; set; } 6 | 7 | public string Name { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /demos/Demo.AspnetCore/Dtos/UserExtendDto.cs: -------------------------------------------------------------------------------- 1 | namespace Demo.AspnetCore.Dtos; 2 | 3 | public class UserExtendDto : UserDto 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /demos/Demo.AspnetCore/Dtos/UserSearchDto.cs: -------------------------------------------------------------------------------- 1 | namespace Demo.AspnetCore.Dtos; 2 | 3 | public class UserSearchDto 4 | { 5 | public string Name { get; set; } 6 | } 7 | -------------------------------------------------------------------------------- /demos/Demo.AspnetCore/Entities/DemoDbContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 3 | using System; 4 | 5 | namespace Demo.AspnetCore.Entities; 6 | 7 | public class DemoDbContext : DbContext 8 | { 9 | static DemoDbContext() 10 | { 11 | //开启兼容模式 https://www.npgsql.org/efcore/release-notes/6.0.html?tabs=annotations 12 | AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); 13 | } 14 | private static readonly ValueConverter _dateTimeConverter 15 | = new ValueConverter(v => v, v => DateTime.SpecifyKind(v, DateTimeKind.Local)); 16 | public DemoDbContext(DbContextOptions options) : base(options) 17 | { 18 | } 19 | 20 | public DbSet Users { get; set; } 21 | 22 | protected override void OnModelCreating(ModelBuilder modelBuilder) 23 | { 24 | base.OnModelCreating(modelBuilder); 25 | //DateTime默认为Local 26 | foreach (var entityType in modelBuilder.Model.GetEntityTypes()) 27 | { 28 | foreach (var property in entityType.GetProperties()) 29 | { 30 | if (property.ClrType == typeof(DateTime) || property.ClrType == typeof(DateTime?)) 31 | property.SetValueConverter(_dateTimeConverter); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /demos/Demo.AspnetCore/Entities/User.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace Demo.AspnetCore.Entities 5 | { 6 | [Table(nameof(User))] 7 | public class User 8 | { 9 | [Key] 10 | public long Id { get; set; } 11 | 12 | public string Name { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /demos/Demo.AspnetCore/MapperProdiles/CommonProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using Demo.AspnetCore.Dtos; 3 | using Demo.AspnetCore.Entities; 4 | 5 | namespace Invest.Api.MapperProdiles; 6 | 7 | public class CommonProfile : Profile 8 | { 9 | public CommonProfile() 10 | { 11 | CreateMap().ReverseMap(); 12 | CreateMap().ReverseMap(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /demos/Demo.AspnetCore/Program.cs: -------------------------------------------------------------------------------- 1 | using Colder.Api.Abstractions; 2 | using Demo.AspnetCore.Entities; 3 | using Microsoft.AspNetCore.Builder; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using System.Reflection; 7 | 8 | WebApplication.CreateBuilder(args).RunWebApiDefaults(services => 9 | { 10 | services.AddDbContext(x => x.UseSqlite("Data Source=db.db")); 11 | services.AddAutoMapper(Assembly.GetExecutingAssembly()); 12 | }); -------------------------------------------------------------------------------- /demos/Demo.AspnetCore/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "profiles": { 4 | "Demo.AspnetCore": { 5 | "commandName": "Project", 6 | "environmentVariables": { 7 | "ASPNETCORE_ENVIRONMENT": "Development" 8 | } 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /demos/Demo.AspnetCore/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "AllowedHosts": "*", 3 | "log": { //日志配置 4 | "Instance": "demo", 5 | "minlevel": "Trace", //定义详见Microsoft.Extensions.Logging.LogLevel 6 | "console": { 7 | "enabled": true 8 | }, 9 | "debug": { 10 | "enabled": true 11 | }, 12 | "file": { 13 | "enabled": true 14 | }, 15 | "elasticsearch": { 16 | "enabled": false, 17 | "nodes": [ "http://localhost:9200/" ], 18 | "indexformat": "log-{0:yyyyMMdd}" 19 | }, 20 | "kafka": { 21 | "enabled": false, 22 | "brokers": "192.168.56.201:9092", 23 | "userName": "user", 24 | "password": "bitnami", 25 | "topic": "log" 26 | }, 27 | "overrides": [ //重写日志输出级别 28 | { 29 | "source": "Microsoft.AspNetCore", 30 | "minlevel": "Information" 31 | } 32 | ] 33 | }, 34 | "api": { 35 | "EnableSwagger": true, 36 | "EnableJwt": false, 37 | "JwtSecret": null, 38 | "Documents": [ 39 | { 40 | "Title": "default", 41 | "DocumentName": "default", 42 | "ApiGroupNames": [ "default" ] 43 | }, 44 | { 45 | "Title": "group1", 46 | "DocumentName": "group1", 47 | "ApiGroupNames": [ "group1" ] 48 | } 49 | ] 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /demos/Demo.AspnetCore/db.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coldairarrow/Colder.Components/b294acc480ed8314299e61cf8a2950d9ab3c42ba/demos/Demo.AspnetCore/db.db -------------------------------------------------------------------------------- /demos/Demo.Common/Demo.Common.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | false 7 | 1701;1702;CS1591 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /demos/Demo.Common/MessageBusEndpoints.cs: -------------------------------------------------------------------------------- 1 | namespace Demo.Common 2 | { 3 | public static class MessageBusEndpoints 4 | { 5 | public static readonly string Consumer = "Consumer"; 6 | public static readonly string Producer = "Producer"; 7 | public static readonly string Gateway = "Gateway"; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /demos/Demo.Common/RequestMessage.cs: -------------------------------------------------------------------------------- 1 | using Colder.MessageBus.Abstractions; 2 | 3 | namespace Demo.Common 4 | { 5 | public class RequestMessage 6 | { 7 | public string Text { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /demos/Demo.Common/ResponseMessage.cs: -------------------------------------------------------------------------------- 1 | namespace Demo.Common 2 | { 3 | public class ResponseMessage 4 | { 5 | public string Text { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /demos/Demo.Common/SubRequestMessage.cs: -------------------------------------------------------------------------------- 1 | namespace Demo.Common 2 | { 3 | public class SubRequestMessage : RequestMessage 4 | { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /demos/Demo.DistributedId/Demo.DistributedId.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /demos/Demo.DistributedId/Program.cs: -------------------------------------------------------------------------------- 1 | using Colder.Cache; 2 | using Colder.DistributedId; 3 | using Colder.DistributedLock.Abstractions; 4 | using Colder.DistributedLock.Hosting; 5 | using Microsoft.Extensions.DependencyInjection; 6 | 7 | namespace Demo.DistributedId 8 | { 9 | class Program 10 | { 11 | static async Task Main(string[] args) 12 | { 13 | await Task.CompletedTask; 14 | 15 | IServiceCollection services = new ServiceCollection(); 16 | services.AddDistributedLock(x => 17 | { 18 | x.LockType = LockTypes.InMemory; 19 | x.RedisEndPoints = new string[] { "localhost:6379" }; 20 | }); 21 | services.AddCache(new CacheOptions 22 | { 23 | CacheType = CacheTypes.Redis, 24 | RedisConnectionString = "localhost:6379" 25 | }); 26 | services.AddDistributedId(new DistributedIdOptions 27 | { 28 | Distributed = true 29 | }); 30 | 31 | var serviceProvider = services.BuildServiceProvider(); 32 | var distributedId = serviceProvider.GetRequiredService(); 33 | var ids = Enumerable.Range(0, 10000).Select(x => distributedId.NewLongId()).ToList(); 34 | 35 | Console.ReadLine(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /demos/Demo.DistributedLock/Demo.DistributedLock.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /demos/Demo.DistributedLock/Program.cs: -------------------------------------------------------------------------------- 1 | using Colder.DistributedLock.Abstractions; 2 | using Colder.DistributedLock.Hosting; 3 | using Microsoft.Extensions.Caching.Distributed; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Threading.Tasks; 8 | 9 | namespace Demo.DistributedLock 10 | { 11 | class Program 12 | { 13 | static async Task Main(string[] args) 14 | { 15 | IServiceCollection services = new ServiceCollection(); 16 | services.AddDistributedLock(x => 17 | { 18 | x.LockType = LockTypes.InMemory; 19 | }); 20 | 21 | var serviceProvider = services.BuildServiceProvider(); 22 | 23 | var theLock = serviceProvider.GetService(); 24 | string key = Guid.NewGuid().ToString(); 25 | 26 | List tasks = new List(); 27 | 28 | int num = 0; 29 | 30 | for (int i = 0; i < 4; i++) 31 | { 32 | tasks.Add(Task.Run(async () => 33 | { 34 | for (int j = 0; j < 10000; j++) 35 | { 36 | using var _ = await theLock.Lock(key); 37 | num++; 38 | Console.WriteLine(num); 39 | } 40 | })); 41 | } 42 | 43 | await Task.WhenAll(tasks); 44 | 45 | Console.ReadLine(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /demos/Demo.Logging/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace Demo.Logging.Controllers 5 | { 6 | [ApiController] 7 | [Route("[controller]/[action]")] 8 | public class HomeController : ControllerBase 9 | { 10 | private readonly ILogger _logger; 11 | public HomeController(ILogger logger) 12 | { 13 | _logger = logger; 14 | } 15 | 16 | [HttpGet] 17 | public string Index() 18 | { 19 | return "OK"; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /demos/Demo.Logging/Demo.Logging.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(DemoNetVersion) 5 | 6 | false 7 | 1701;1702;CS1591 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /demos/Demo.Logging/Program.cs: -------------------------------------------------------------------------------- 1 | using Colder.Logging.Serilog; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Hosting; 4 | 5 | namespace Logging.Demo 6 | { 7 | public class Program 8 | { 9 | public static void Main(string[] args) 10 | { 11 | CreateHostBuilder(args).Build().Run(); 12 | } 13 | 14 | public static IHostBuilder CreateHostBuilder(string[] args) => 15 | Host.CreateDefaultBuilder(args) 16 | .ConfigureLoggingDefaults() 17 | .ConfigureWebHostDefaults(webBuilder => 18 | { 19 | webBuilder.UseStartup(); 20 | }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /demos/Demo.Logging/Properties/PublishProfiles/FolderProfile.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | False 8 | False 9 | True 10 | Release 11 | Any CPU 12 | FileSystem 13 | bin\Release\netcoreapp3.1\publish\ 14 | FileSystem 15 | 16 | -------------------------------------------------------------------------------- /demos/Demo.Logging/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Logging.Demo": { 4 | "commandName": "Project", 5 | "launchUrl": "Home/Index", 6 | "environmentVariables": { 7 | "ASPNETCORE_ENVIRONMENT": "Development" 8 | }, 9 | "applicationUrl": "http://localhost:5000" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /demos/Demo.Logging/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.Hosting; 6 | 7 | namespace Logging.Demo 8 | { 9 | public class Startup 10 | { 11 | public Startup(IConfiguration configuration) 12 | { 13 | Configuration = configuration; 14 | } 15 | 16 | public IConfiguration Configuration { get; } 17 | 18 | // This method gets called by the runtime. Use this method to add services to the container. 19 | public void ConfigureServices(IServiceCollection services) 20 | { 21 | services.AddControllers(); 22 | } 23 | 24 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 25 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 26 | { 27 | if (env.IsDevelopment()) 28 | { 29 | app.UseDeveloperExceptionPage(); 30 | } 31 | 32 | app.UseRouting(); 33 | 34 | app.UseAuthorization(); 35 | 36 | app.UseEndpoints(endpoints => 37 | { 38 | endpoints.MapControllers(); 39 | }); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /demos/Demo.Logging/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "AllowedHosts": "*", 3 | "log": { //日志配置 4 | "Instance": "demo", 5 | "minlevel": "Trace", //定义详见Microsoft.Extensions.Logging.LogLevel 6 | "console": { 7 | "enabled": true 8 | }, 9 | "debug": { 10 | "enabled": true 11 | }, 12 | "file": { 13 | "enabled": true 14 | }, 15 | "elasticsearch": { 16 | "enabled": false, 17 | "nodes": [ "http://localhost:9200/" ], 18 | "indexformat": "log-{0:yyyyMMdd}" 19 | }, 20 | "kafka": { 21 | "enabled": true, 22 | "brokers": "192.168.56.201:9092", 23 | "userName": "user", 24 | "password": "bitnami", 25 | "topic": "log" 26 | }, 27 | "overrides": [ //重写日志输出级别 28 | { 29 | "source": "Microsoft.AspNetCore", 30 | "minlevel": "Information" 31 | } 32 | ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /demos/Demo.MessageBus/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using Colder.MessageBus.Abstractions; 2 | using Demo.Common; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Microsoft.Extensions.Logging; 5 | using System.Threading.Tasks; 6 | 7 | namespace Demo.Logging.Controllers 8 | { 9 | [ApiController] 10 | [Route("[controller]/[action]")] 11 | public class HomeController : ControllerBase 12 | { 13 | private readonly ILogger _logger; 14 | private readonly IMessageBus _messageBus; 15 | public HomeController(ILogger logger, IMessageBus messageBus) 16 | { 17 | _logger = logger; 18 | _messageBus = messageBus; 19 | } 20 | 21 | [HttpGet] 22 | public async Task Index() 23 | { 24 | await _messageBus.Publish(new RequestMessage 25 | { 26 | Text = "小明" 27 | }); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /demos/Demo.MessageBus/Demo.MessageBus.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | $(DemoNetVersion) 6 | 7 | false 8 | 1701;1702;CS1591 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | PreserveNewest 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /demos/Demo.MessageBus/Handler.cs: -------------------------------------------------------------------------------- 1 | using Colder.MessageBus.Abstractions; 2 | using Demo.Common; 3 | using Microsoft.Extensions.Logging; 4 | using Newtonsoft.Json; 5 | using System.Threading.Tasks; 6 | 7 | namespace Demo.MessageBus.Consumer 8 | { 9 | class Handler : IMessageHandler 10 | { 11 | private readonly ILogger _logger; 12 | private readonly IMessageBus _messageBus; 13 | public Handler(ILogger logger, IMessageBus messageBus) 14 | { 15 | _logger = logger; 16 | _messageBus = messageBus; 17 | } 18 | public async Task Handle(MessageContext context) 19 | { 20 | _logger.LogInformation("收到 {EventType} 事件,MessageBody:{MessageBody}", 21 | typeof(RequestMessage).Name, JsonConvert.SerializeObject(context.Message)); 22 | 23 | await Task.CompletedTask; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /demos/Demo.MessageBus/Program.cs: -------------------------------------------------------------------------------- 1 | using Colder.Logging.Serilog; 2 | using Colder.MessageBus.Hosting; 3 | using Logging.Demo; 4 | using Microsoft.AspNetCore.Hosting; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Microsoft.Extensions.Hosting; 7 | using System.Threading.Tasks; 8 | 9 | namespace Demo.MessageBus.Consumer 10 | { 11 | class Program 12 | { 13 | public static async Task Main() 14 | { 15 | await Host.CreateDefaultBuilder() 16 | .ConfigureLoggingDefaults() 17 | .ConfigureMessageBusDefaults() 18 | .ConfigureServices(services => 19 | { 20 | services.AddHostedService(); 21 | }) 22 | .ConfigureWebHostDefaults(webBuilder => 23 | { 24 | webBuilder.UseStartup(); 25 | }) 26 | .RunConsoleAsync(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /demos/Demo.MessageBus/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Demo.MessageBus": { 4 | "commandName": "Project", 5 | "environmentVariables": { 6 | "ASPNETCORE_ENVIRONMENT": "Development" 7 | } 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /demos/Demo.MessageBus/PublishService.cs: -------------------------------------------------------------------------------- 1 | using Colder.MessageBus.Abstractions; 2 | using Demo.Common; 3 | using Microsoft.Extensions.Hosting; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace Demo.MessageBus 8 | { 9 | class PublishService : BackgroundService 10 | { 11 | private readonly IMessageBus _messageBus; 12 | private Timer _timer; 13 | public PublishService(IMessageBus messageBus) 14 | { 15 | _messageBus = messageBus; 16 | } 17 | protected override async Task ExecuteAsync(CancellationToken stoppingToken) 18 | { 19 | await Task.CompletedTask; 20 | 21 | _timer = new Timer(async state => 22 | { 23 | await _messageBus.Publish(new RequestMessage 24 | { 25 | Text = "小明" 26 | }); 27 | }, null, 0, 1000); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /demos/Demo.MessageBus/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.Hosting; 6 | 7 | namespace Logging.Demo 8 | { 9 | public class Startup 10 | { 11 | public Startup(IConfiguration configuration) 12 | { 13 | Configuration = configuration; 14 | } 15 | 16 | public IConfiguration Configuration { get; } 17 | 18 | // This method gets called by the runtime. Use this method to add services to the container. 19 | public void ConfigureServices(IServiceCollection services) 20 | { 21 | services.AddControllers(); 22 | } 23 | 24 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 25 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 26 | { 27 | if (env.IsDevelopment()) 28 | { 29 | app.UseDeveloperExceptionPage(); 30 | } 31 | 32 | app.UseRouting(); 33 | 34 | app.UseAuthorization(); 35 | 36 | app.UseEndpoints(endpoints => 37 | { 38 | endpoints.MapControllers(); 39 | }); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /demos/Demo.MessageBus/appsettings.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coldairarrow/Colder.Components/b294acc480ed8314299e61cf8a2950d9ab3c42ba/demos/Demo.MessageBus/appsettings.json -------------------------------------------------------------------------------- /demos/Demo.OpenService.Client/Demo.OpenService.Client.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | $(DemoNetVersion) 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /demos/Demo.OpenService.Client/Program.cs: -------------------------------------------------------------------------------- 1 | using Colder.Common; 2 | using Colder.OpenService.Client; 3 | using Demo.OpenService.Common; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using System; 6 | using System.Threading.Tasks; 7 | 8 | namespace Demo.OpenService.Client 9 | { 10 | internal class Program 11 | { 12 | static async Task Main(string[] args) 13 | { 14 | IServiceCollection services = new ServiceCollection(); 15 | services.AddOpenServiceClient(typeof(IHelloOpenService).Assembly, new OpenServiceOptions 16 | { 17 | BaseUrl = "http://localhost:5000/api/" 18 | }); 19 | IServiceProvider serviceProvider = services.BuildServiceProvider(); 20 | IHelloOpenService helloOpenService = serviceProvider.GetService(); 21 | var response = await helloOpenService.SayHello(new IdInput { Id = "Hello World" }); 22 | Console.WriteLine($"请求成功 返回参:{response}"); 23 | 24 | Console.ReadLine(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /demos/Demo.OpenService.Common/Demo.OpenService.Common.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(DemoNetVersion) 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /demos/Demo.OpenService.Common/IHelloOpenService.cs: -------------------------------------------------------------------------------- 1 | using Colder.Common; 2 | using Colder.OpenService.Abstractions; 3 | using System.Threading.Tasks; 4 | 5 | namespace Demo.OpenService.Common 6 | { 7 | /// 8 | /// 9 | /// 10 | [Route("hello")] 11 | public interface IHelloOpenService : IOpenService 12 | { 13 | /// 14 | /// 15 | /// 16 | /// 17 | /// 18 | [Route("say")] 19 | Task SayHello(IdInput idInput); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /demos/Demo.OpenService.Server/Controllers/HelloService.cs: -------------------------------------------------------------------------------- 1 | using Colder.Common; 2 | using Colder.OpenService.Hosting; 3 | using Demo.OpenService.Common; 4 | using System.Threading.Tasks; 5 | 6 | namespace Demo.OpenService.Controllers 7 | { 8 | /// 9 | /// 10 | /// 11 | public class HelloService : OpenServiceBase, IHelloOpenService 12 | { 13 | /// 14 | /// 15 | /// 16 | /// 17 | /// 18 | public Task SayHello(IdInput idInput) 19 | { 20 | return Task.FromResult(idInput.Id); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /demos/Demo.OpenService.Server/Demo.OpenService.Server.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(DemoNetVersion) 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demos/Demo.OpenService.Server/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Hosting; 3 | using Colder.OpenService.Client; 4 | using System.Reflection; 5 | 6 | namespace Demo.OpenService 7 | { 8 | internal class Program 9 | { 10 | public static void Main(string[] args) 11 | { 12 | CreateHostBuilder(args).Build().Run(); 13 | } 14 | 15 | public static IHostBuilder CreateHostBuilder(string[] args) => 16 | Host.CreateDefaultBuilder(args) 17 | .ConfigureServices((host, services) => 18 | { 19 | services.AddOpenServiceClient(Assembly.GetEntryAssembly(), new OpenServiceOptions 20 | { 21 | BaseUrl="http://localhost:5000/api/" 22 | }); 23 | }) 24 | .ConfigureWebHostDefaults(webBuilder => 25 | { 26 | webBuilder.UseStartup(); 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /demos/Demo.OpenService.Server/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Demo.OpenService.Server": { 4 | "commandName": "Project", 5 | "dotnetRunMessages": "true", 6 | "launchBrowser": true, 7 | "launchUrl": "swagger", 8 | "applicationUrl": "http://localhost:5000", 9 | "environmentVariables": { 10 | "ASPNETCORE_ENVIRONMENT": "Development" 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /demos/Demo.OpenService.Server/Startup.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coldairarrow/Colder.Components/b294acc480ed8314299e61cf8a2950d9ab3c42ba/demos/Demo.OpenService.Server/Startup.cs -------------------------------------------------------------------------------- /demos/Demo.OpenService.Server/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Information", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | -------------------------------------------------------------------------------- /demos/Demo.Orleans/Bootstrapper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Hosting; 2 | using Microsoft.Extensions.Logging; 3 | using Orleans; 4 | using System; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace Demo.Orleans 9 | { 10 | class Bootstrapper : BackgroundService 11 | { 12 | private readonly IGrainFactory _grainFactory; 13 | private Timer _timer; 14 | private readonly ILogger _logger; 15 | public Bootstrapper(IGrainFactory grainFactory, ILogger logger) 16 | { 17 | _grainFactory = grainFactory; 18 | _logger = logger; 19 | } 20 | protected override Task ExecuteAsync(CancellationToken stoppingToken) 21 | { 22 | Guid id = Guid.NewGuid(); 23 | _timer = new Timer(async _ => 24 | { 25 | try 26 | { 27 | await _grainFactory.GetGrain(0).Say("小明"); 28 | } 29 | catch (Exception ex) 30 | { 31 | _logger.LogError(ex, ex.Message); 32 | } 33 | }, null, 0, 1000); 34 | 35 | return Task.CompletedTask; 36 | } 37 | 38 | public override async Task StopAsync(CancellationToken cancellationToken) 39 | { 40 | await _timer.DisposeAsync(); 41 | 42 | await base.StopAsync(cancellationToken); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /demos/Demo.Orleans/Demo.Orleans.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | $(DemoNetVersion) 6 | 7 | 8 | 9 | 10 | 11 | 12 | all 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | PreserveNewest 25 | true 26 | PreserveNewest 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /demos/Demo.Orleans/Grains/HelloGrain.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Orleans; 3 | using System.Threading.Tasks; 4 | 5 | namespace Demo.Orleans 6 | { 7 | internal class HelloGrain : Grain, IHello 8 | { 9 | private readonly ILogger _logger; 10 | public HelloGrain(ILoggerFactory loggerFactory) 11 | { 12 | _logger = loggerFactory.CreateLogger(GetType()); 13 | } 14 | public Task Say(string name) 15 | { 16 | _logger.LogInformation("{Name} Say Hello", name); 17 | 18 | return Task.CompletedTask; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /demos/Demo.Orleans/IGrains/IHello.cs: -------------------------------------------------------------------------------- 1 | using Orleans; 2 | using System.Threading.Tasks; 3 | 4 | namespace Demo.Orleans 5 | { 6 | internal interface IHello : IGrainWithIntegerKey 7 | { 8 | Task Say(string name); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /demos/Demo.Orleans/Program.cs: -------------------------------------------------------------------------------- 1 | using Colder.Logging.Serilog; 2 | using Colder.Orleans.Hosting; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Hosting; 5 | using Orleans; 6 | using Orleans.Hosting; 7 | using System.Threading.Tasks; 8 | 9 | namespace Demo.Orleans 10 | { 11 | class Program 12 | { 13 | public static async Task Main(string[] args) 14 | { 15 | await Host.CreateDefaultBuilder(args) 16 | .ConfigureLoggingDefaults() 17 | .ConfigureOrleansDefaults() 18 | .ConfigureServices(services => 19 | { 20 | services.AddHostedService(); 21 | }) 22 | .RunConsoleAsync(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /demos/Demo.Orleans/Properties/PublishProfiles/FolderProfile.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | bin\Release\netcoreapp3.1\publish\ 10 | FileSystem 11 | 12 | -------------------------------------------------------------------------------- /demos/Demo.Orleans/appsettings.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coldairarrow/Colder.Components/b294acc480ed8314299e61cf8a2950d9ab3c42ba/demos/Demo.Orleans/appsettings.json -------------------------------------------------------------------------------- /demos/Demo.WebSockets.Server/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using Colder.WebSockets.Abstractions; 2 | using Microsoft.AspNetCore.Mvc; 3 | using System; 4 | using System.Threading.Tasks; 5 | 6 | namespace Demo.WebSockets.Server.Controllers 7 | { 8 | [ApiController] 9 | [Route("[controller]")] 10 | public class HomeController : ControllerBase 11 | { 12 | private readonly IWebSocketServer _webSocketServer; 13 | public HomeController(IWebSocketServer webSocketServer) 14 | { 15 | _webSocketServer = webSocketServer; 16 | } 17 | 18 | [HttpGet] 19 | [Route("/send")] 20 | public async Task Send() 21 | { 22 | foreach (var aConnection in _webSocketServer.GetAllConnections()) 23 | { 24 | await aConnection.Send(DateTime.Now.ToString()); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /demos/Demo.WebSockets.Server/Demo.WebSockets.Server.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(DemoNetVersion) 5 | CS1591; 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /demos/Demo.WebSockets.Server/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Hosting; 3 | 4 | namespace Demo.WebSockets.Server 5 | { 6 | internal class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | CreateHostBuilder(args).Build().Run(); 11 | } 12 | 13 | public static IHostBuilder CreateHostBuilder(string[] args) => 14 | Host.CreateDefaultBuilder(args) 15 | .ConfigureWebHostDefaults(webBuilder => 16 | { 17 | webBuilder.UseStartup(); 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /demos/Demo.WebSockets.Server/Properties/PublishProfiles/FolderProfile.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | False 8 | False 9 | True 10 | Release 11 | Any CPU 12 | FileSystem 13 | bin\Release\net5.0\publish\ 14 | FileSystem 15 | 16 | -------------------------------------------------------------------------------- /demos/Demo.WebSockets.Server/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Demo.WebSockets.Server": { 4 | "commandName": "Project", 5 | "dotnetRunMessages": "true", 6 | "environmentVariables": { 7 | "ASPNETCORE_ENVIRONMENT": "Development" 8 | } 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /demos/Demo.WebSockets.Server/Startup.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coldairarrow/Colder.Components/b294acc480ed8314299e61cf8a2950d9ab3c42ba/demos/Demo.WebSockets.Server/Startup.cs -------------------------------------------------------------------------------- /demos/Demo.WebSockets.Server/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /demos/Demo.WebSockets.Server/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "urls": "http://*:5000", 3 | "Logging": { 4 | "LogLevel": { 5 | "Default": "Information", 6 | "Microsoft": "Warning", 7 | "Microsoft.Hosting.Lifetime": "Information" 8 | } 9 | }, 10 | "AllowedHosts": "*" 11 | } 12 | -------------------------------------------------------------------------------- /demos/Demo.WebSockets.Server/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 菜鸟教程(runoob.com) 6 | 7 | 34 | 35 | 36 | 37 |
38 | 运行 WebSocket 39 |
40 | 41 | -------------------------------------------------------------------------------- /demos/Domo.Console/Domo.Console.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | $(DemoNetVersion) 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /demos/Domo.Console/Program.cs: -------------------------------------------------------------------------------- 1 | using Colder.Common; 2 | using System; 3 | using System.Drawing; 4 | using System.Drawing.Imaging; 5 | 6 | namespace Domo.Console1 7 | { 8 | class Program 9 | { 10 | static void Main(string[] args) 11 | { 12 | Image image = Image.FromFile("1.jpg"); 13 | var newImg = ImgHelper.AddText(image, new Rectangle(0, 0, 50, 50), "测试", Color.White); 14 | newImg.Save("2.jpg", ImageFormat.Jpeg); 15 | 16 | Console.WriteLine("Hello World!"); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Colder.Api.Abstractions/Colder.Api.Abstractions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/Colder.Api.Abstractions/Controllers/ApiControllerBase.cs: -------------------------------------------------------------------------------- 1 | using Colder.Common; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace Colder.Api.Abstractions.Controllers; 5 | 6 | /// 7 | /// Api控制器 8 | /// 9 | [Route("api/[controller]/[action]")] 10 | [ApiController] 11 | public abstract class ApiControllerBase : ControllerBase 12 | { 13 | /// 14 | /// 返回成功 15 | /// 16 | /// 数据类型 17 | /// 数据 18 | /// 19 | protected ApiResult Success(T data) 20 | { 21 | return new ApiResult { Data = data, Code = 200 }; 22 | } 23 | 24 | /// 25 | /// 返回成功 26 | /// 27 | /// 28 | protected ApiResult Success() 29 | { 30 | return new ApiResult { Code = 200 }; 31 | } 32 | 33 | /// 34 | /// 返回失败 35 | /// 36 | /// 错误消息 37 | /// 错误码 38 | /// 39 | protected ApiResult Failure(string msg, int code = 1) 40 | { 41 | return new ApiResult { Msg = msg, Code = code }; 42 | } 43 | 44 | /// 45 | /// 返回失败 46 | /// 47 | /// 数据类型 48 | /// 错误消息 49 | /// 数据 50 | /// 错误码 51 | /// 52 | protected ApiResult Failure(string msg, T data = default, int code = 1) 53 | { 54 | return new ApiResult { Data = data, Msg = msg, Code = code }; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Colder.Api.Abstractions/Controllers/SaveContext.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.Api.Abstractions.Controllers; 2 | 3 | /// 4 | /// 保存上下文 5 | /// 6 | /// Dto数据类型 7 | /// 数据库表实体类型 8 | public class SaveContext 9 | { 10 | /// 11 | /// Dto数据 12 | /// 13 | public TDto Dto { get; set; } 14 | 15 | /// 16 | /// 原实体(更新之前的数据,更新后不会改变) 17 | /// 18 | public TEntity OriginalEntity { get; set; } 19 | 20 | /// 21 | /// 当前实体(跟踪中的数据库实体数据,会随着更新而改变,若数据删除则为null) 22 | /// 23 | public TEntity CurrentEntity { get; set; } 24 | } 25 | -------------------------------------------------------------------------------- /src/Colder.Api.Abstractions/Filters/ExceptionFilter.cs: -------------------------------------------------------------------------------- 1 | using Colder.Common; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.AspNetCore.Mvc.Filters; 4 | using Microsoft.Extensions.Logging; 5 | using System; 6 | using System.Threading.Tasks; 7 | 8 | namespace Logistics.Api; 9 | 10 | /// 11 | /// 12 | /// 13 | public class ExceptionFilter : IAsyncExceptionFilter 14 | { 15 | readonly ILogger _logger; 16 | 17 | /// 18 | /// 19 | /// 20 | /// 21 | public ExceptionFilter(ILogger logger) 22 | { 23 | _logger = logger; 24 | } 25 | 26 | /// 27 | /// 28 | /// 29 | /// 30 | /// 31 | public async Task OnExceptionAsync(ExceptionContext context) 32 | { 33 | Exception ex = context.Exception; 34 | 35 | if (ex is MsgException busEx) 36 | { 37 | _logger.LogInformation(busEx.Message); 38 | context.Result = new JsonResult(new ApiResult { Msg = ex.Message, Code = 1 }); 39 | } 40 | else 41 | { 42 | _logger.LogError(ex, ex.Message); 43 | context.Result = new JsonResult(new ApiResult { Msg = "系统异常", Code = 1 }); 44 | } 45 | 46 | await Task.CompletedTask; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Colder.Api.Abstractions/Filters/TransactionFilter.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc.Filters; 2 | using Microsoft.EntityFrameworkCore; 3 | using System.Threading.Tasks; 4 | using System; 5 | using Microsoft.Extensions.DependencyInjection; 6 | 7 | namespace Colder.Api.Abstractions.Filters; 8 | 9 | /// 10 | /// 11 | /// 12 | public class TransactionFilter : Attribute, IAsyncActionFilter 13 | { 14 | private readonly Type _dbContextType; 15 | 16 | /// 17 | /// 18 | /// 19 | /// 20 | /// 21 | public TransactionFilter(Type dbContextType) 22 | { 23 | if (!dbContextType.IsAssignableTo(typeof(DbContext))) 24 | { 25 | throw new Exception("dbContextType必须为DbContext"); 26 | } 27 | _dbContextType = dbContextType; 28 | } 29 | 30 | /// 31 | /// 32 | /// 33 | /// 34 | /// 35 | /// 36 | public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) 37 | { 38 | IServiceProvider serviceProvider = context.HttpContext.RequestServices; 39 | var dbContext = serviceProvider.GetRequiredService(_dbContextType) as DbContext; 40 | 41 | using var transaction = await dbContext.Database.BeginTransactionAsync(); 42 | 43 | var excuted = await next(); 44 | 45 | if (excuted.Exception == null) 46 | { 47 | await transaction.CommitAsync(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Colder.Api.Abstractions/JwtExtentions.cs: -------------------------------------------------------------------------------- 1 | using Colder.Api.Abstractions.Options; 2 | using Microsoft.AspNetCore.Authentication.JwtBearer; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.IdentityModel.Tokens; 5 | using System; 6 | using System.Text; 7 | 8 | namespace Colder.Api.Abstractions; 9 | 10 | /// 11 | /// 12 | /// 13 | public static class JwtExtentions 14 | { 15 | /// 16 | /// 17 | /// 18 | /// 19 | /// 20 | /// 21 | public static IServiceCollection AddJwt(this IServiceCollection services, ApiOptions apiOption) 22 | { 23 | services.AddAuthentication(x => 24 | { 25 | x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; 26 | x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; 27 | }).AddJwtBearer(x => 28 | { 29 | x.RequireHttpsMetadata = false; 30 | x.SaveToken = false; 31 | //Token Validation Parameters 32 | x.TokenValidationParameters = new TokenValidationParameters 33 | { 34 | ClockSkew = TimeSpan.Zero,//到时间立即过期 35 | ValidateIssuerSigningKey = true, 36 | //获取或设置要使用的Microsoft.IdentityModel.Tokens.SecurityKey用于签名验证。 37 | IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8. 38 | GetBytes(apiOption.JwtSecret)), 39 | ValidateIssuer = false, 40 | ValidateAudience = false, 41 | }; 42 | }); 43 | 44 | return services; 45 | } 46 | } -------------------------------------------------------------------------------- /src/Colder.Api.Abstractions/Middlewares/RealIpMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using System.Threading.Tasks; 3 | using System; 4 | using System.Net; 5 | 6 | namespace Colder.Api.Abstractions.Middlewares; 7 | 8 | internal class RealIpMiddleware 9 | { 10 | private readonly RequestDelegate _next; 11 | 12 | public RealIpMiddleware(RequestDelegate next) 13 | { 14 | _next = next; 15 | } 16 | 17 | public Task Invoke(HttpContext context) 18 | { 19 | var headers = context.Request.Headers; 20 | if (headers.ContainsKey("X-Forwarded-For")) 21 | { 22 | context.Connection.RemoteIpAddress = IPAddress.Parse(headers["X-Forwarded-For"].ToString().Split(',', StringSplitOptions.RemoveEmptyEntries)[0]); 23 | } 24 | return _next(context); 25 | } 26 | } -------------------------------------------------------------------------------- /src/Colder.Api.Abstractions/Middlewares/RequestInfo.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.Api.Abstractions 2 | { 3 | /// 4 | /// 请求信息 5 | /// 6 | public class RequestInfo 7 | { 8 | /// 9 | /// 请求Body 10 | /// 11 | public string RequestBody { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Colder.Api.Abstractions/Middlewares/RequestInfoMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Colder.Common; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Colder.Api.Abstractions 8 | { 9 | internal class RequestInfoMiddleware 10 | { 11 | private readonly RequestDelegate _next; 12 | 13 | public RequestInfoMiddleware(RequestDelegate next) 14 | { 15 | _next = next; 16 | } 17 | 18 | public async Task Invoke(HttpContext context) 19 | { 20 | var contentType = (context.Request.ContentType ?? string.Empty).ToLower(); 21 | if (contentType.Contains("text") 22 | || contentType.Contains("xml") 23 | || contentType.Contains("json") 24 | || contentType.Contains("x-www-form-urlencoded") 25 | || contentType.Contains("form-data")) 26 | { 27 | context.Request.EnableBuffering(); 28 | string body = await context.Request.Body?.ReadToStringAsync(Encoding.UTF8); 29 | context.RequestServices.GetService().RequestBody = body; 30 | } 31 | 32 | await _next(context); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Colder.Api.Abstractions/Options/ApiOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Colder.Api.Abstractions.Options; 4 | 5 | /// 6 | /// 7 | /// 8 | public class ApiOptions 9 | { 10 | /// 11 | /// 启用Jwt 12 | /// 13 | public bool EnableJwt { get; set; } = true; 14 | 15 | /// 16 | /// Jwt密钥 17 | /// 18 | public string JwtSecret { get; set; } 19 | 20 | /// 21 | /// 启用Swagger 22 | /// 23 | public bool EnableSwagger { get; set; } = true; 24 | 25 | /// 26 | /// 文档分组 27 | /// 28 | public SwaggerDocumentOptions[] Documents { get; set; } = Array.Empty(); 29 | } 30 | -------------------------------------------------------------------------------- /src/Colder.Api.Abstractions/Options/SwaggerDocumentOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Colder.Api.Abstractions.Options; 4 | 5 | /// 6 | /// Swagger 文档配置。 7 | /// 8 | public class SwaggerDocumentOptions 9 | { 10 | /// 11 | /// 获取或设置 Swagger 标题。 12 | /// 13 | public string Title { get; set; } 14 | 15 | /// 16 | /// 获取或设置文档名称。 17 | /// 18 | public string DocumentName { get; set; } 19 | 20 | /// 21 | /// 获取或设置 API 分组名称。 22 | /// 23 | public string[] ApiGroupNames { get; set; } = Array.Empty(); 24 | } 25 | -------------------------------------------------------------------------------- /src/Colder.Api.Abstractions/Swagger/ControllerFilterProcessor.cs: -------------------------------------------------------------------------------- 1 | using NSwag.Generation.Processors; 2 | using NSwag.Generation.Processors.Contexts; 3 | using System; 4 | 5 | namespace Colder.Api.Abstractions; 6 | 7 | internal class ControllerFilterProcessor : IOperationProcessor 8 | { 9 | public bool Process(OperationProcessorContext context) 10 | { 11 | Console.WriteLine("[NSWAG] CONTROLLER " + context.ControllerType.Name + " " + context.MethodInfo.Name); 12 | return true; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Colder.Api.Abstractions/Swagger/EnumSchemaProcessor.cs: -------------------------------------------------------------------------------- 1 | using Namotion.Reflection; 2 | using NJsonSchema.Generation; 3 | using System; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Colder.Api.Abstractions.Swagger; 8 | 9 | /// 10 | /// 11 | /// 12 | internal class EnumSchemaProcessor : ISchemaProcessor 13 | { 14 | /// 15 | /// 16 | /// 17 | /// 18 | public void Process(SchemaProcessorContext context) 19 | { 20 | var type = context.ContextualType.Type; 21 | if (!type.IsEnum) 22 | { 23 | return; 24 | } 25 | 26 | var sb = new StringBuilder(); 27 | sb.AppendLine(type.GetXmlDocsSummary()); 28 | 29 | var members = type.GetMembers(); 30 | var schema = context.Schema; 31 | for (var i = 0; i < schema.Enumeration.Count; i++) 32 | { 33 | var item = schema.Enumeration.ElementAt(i); 34 | var enumName = Enum.GetName(type, item); 35 | 36 | var summary = members.FirstOrDefault(a => a.Name == enumName) 37 | .GetXmlDocsSummary(); 38 | 39 | sb.AppendLine($"{item} = {summary}"); 40 | } 41 | 42 | schema.Description = sb.ToString(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Colder.AutoMapper/Colder.AutoMapper.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.1 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Colder.AutoMapper/MappingExpressionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using AutoMapper; 3 | 4 | namespace Colder.AutoMapper; 5 | 6 | /// 7 | /// 8 | /// 9 | public static class AutoMapperExtensions 10 | { 11 | /// 12 | /// 忽略所有不匹配的属性。 13 | /// 14 | /// 15 | /// 16 | /// 17 | /// 18 | public static IMappingExpression IgnoreAllNonExisting(this IMappingExpression expression) 19 | { 20 | var flags = BindingFlags.Public | BindingFlags.Instance; 21 | var sourceType = typeof(TSource); 22 | var destinationProperties = typeof(TDestination).GetProperties(flags); 23 | 24 | foreach (var property in destinationProperties) 25 | { 26 | if (sourceType.GetProperty(property.Name, flags) == null) 27 | { 28 | expression.ForMember(property.Name, opt => opt.Ignore()); 29 | } 30 | } 31 | return expression; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Colder.Cache/Colder.Cache.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 缓存封装 6 | 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Colder.Cache/Options/CacheOptions.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.Cache 2 | { 3 | /// 4 | /// 缓存配置 5 | /// 6 | public class CacheOptions 7 | { 8 | /// 9 | /// 缓存类型 10 | /// 11 | public CacheTypes CacheType { get; set; } 12 | 13 | /// 14 | /// Redis连接字符串 15 | /// 配置参考 https://stackexchange.github.io/StackExchange.Redis/Configuration.html 16 | /// 17 | public string RedisConnectionString { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Colder.Cache/Options/CacheTypes.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.Cache 2 | { 3 | /// 4 | /// 缓存类型 5 | /// 6 | public enum CacheTypes 7 | { 8 | /// 9 | /// 使用内存缓存(不支持分布式) 10 | /// 11 | InMemory = 0, 12 | 13 | /// 14 | /// 使用Redis缓存(支持分布式) 15 | /// 16 | Redis = 1 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Colder.Common.Util/Colder.Common.Util.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 通用工具 6 | 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Colder.Common.Util/ElasticClientExtentions.cs: -------------------------------------------------------------------------------- 1 | using Nest; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace Colder.Common.Util; 7 | 8 | /// 9 | /// ElasticClient拓展 10 | /// 11 | public static class ElasticClientExtentions 12 | { 13 | /// 14 | /// 查询所有数据,通过SearchAfter方式 15 | /// 16 | /// 文档类型 17 | /// es客户端 18 | /// 查询条件 19 | /// Id字段 20 | /// 21 | public static async Task SearchAll( 22 | this IElasticClient elasticClient, 23 | SearchDescriptor searchDescriptor = null, 24 | string idField = "Id" 25 | ) 26 | where TDocument : class 27 | { 28 | List result = new List(); 29 | TDocument last = null; 30 | while (true) 31 | { 32 | searchDescriptor ??= new SearchDescriptor(); 33 | searchDescriptor = searchDescriptor.Sort(y => y.Ascending($"{idField}.keyword")).Size(10000); 34 | if (last != null) 35 | { 36 | searchDescriptor = searchDescriptor.SearchAfter(last.GetType().GetProperty(idField).GetValue(last)); 37 | } 38 | 39 | var response = await elasticClient.SearchAsync(searchDescriptor); 40 | if (!response.ApiCall.Success) 41 | { 42 | throw response.OriginalException; 43 | } 44 | 45 | result.AddRange(response.Documents); 46 | 47 | if (response.Documents.Count < 10000) 48 | { 49 | break; 50 | } 51 | last = response.Documents.LastOrDefault(); 52 | } 53 | 54 | return result.ToArray(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Colder.Common.Util/Helpers/FileZipHelper.cs: -------------------------------------------------------------------------------- 1 | using ICSharpCode.SharpZipLib.Zip; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | 6 | namespace Colder.Common 7 | { 8 | /// 9 | /// 文件压缩帮助类 10 | /// 11 | public class FileZipHelper 12 | { 13 | /// 14 | /// 压缩一个文件 15 | /// 16 | /// 文件信息 17 | /// 18 | public static byte[] ZipFile(FileEntry file) 19 | { 20 | return ZipFile(new List { file }); 21 | } 22 | 23 | /// 24 | /// 压缩多个文件 25 | /// 26 | /// 文件信息列表 27 | /// 28 | public static byte[] ZipFile(List files) 29 | { 30 | using (MemoryStream ms = new MemoryStream()) 31 | { 32 | using (ZipOutputStream zipStream = new ZipOutputStream(ms)) 33 | { 34 | files.ForEach(aFile => 35 | { 36 | byte[] fileBytes = aFile.FileBytes; 37 | ZipEntry entry = new ZipEntry(aFile.FileName) 38 | { 39 | DateTime = DateTime.Now, 40 | IsUnicodeText = true 41 | }; 42 | zipStream.PutNextEntry(entry); 43 | zipStream.Write(fileBytes, 0, fileBytes.Length); 44 | zipStream.CloseEntry(); 45 | }); 46 | 47 | zipStream.IsStreamOwner = false; 48 | zipStream.Finish(); 49 | zipStream.Close(); 50 | ms.Position = 0; 51 | 52 | return ms.ToArray(); 53 | } 54 | } 55 | } 56 | } 57 | 58 | /// 59 | /// 文件信息 60 | /// 61 | public struct FileEntry 62 | { 63 | /// 64 | /// 65 | /// 66 | /// 67 | /// 68 | public FileEntry(string fileName, byte[] fileBytes) 69 | { 70 | FileName = fileName; 71 | FileBytes = fileBytes; 72 | } 73 | 74 | /// 75 | /// 文件名 76 | /// 77 | public string FileName { get; set; } 78 | 79 | /// 80 | /// 文件字节 81 | /// 82 | public byte[] FileBytes { get; set; } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Colder.Common.Util/Helpers/LinqHelper.cs: -------------------------------------------------------------------------------- 1 | using DynamicExpresso; 2 | using System; 3 | using System.Linq.Expressions; 4 | using System.Reflection; 5 | 6 | namespace Colder.Common.Util 7 | { 8 | /// 9 | /// Linq操作帮助类 10 | /// 11 | public static class LinqHelper 12 | { 13 | static LinqHelper() 14 | { 15 | try 16 | { 17 | EFCore = Assembly.Load("Microsoft.EntityFrameworkCore"); 18 | EFCoreNpgsql = Assembly.Load("Npgsql.EntityFrameworkCore.PostgreSQL"); 19 | } 20 | catch 21 | { 22 | 23 | } 24 | } 25 | 26 | 27 | private static readonly Assembly EFCore; 28 | private static readonly Assembly EFCoreNpgsql; 29 | 30 | /// 31 | /// 创建初始条件为True的表达式 32 | /// 33 | /// 34 | /// 35 | public static Expression> True() 36 | { 37 | return x => true; 38 | } 39 | 40 | /// 41 | /// 创建初始条件为False的表达式 42 | /// 43 | /// 44 | /// 45 | public static Expression> False() 46 | { 47 | return x => false; 48 | } 49 | 50 | /// 51 | /// 构建动态表达式 52 | /// 53 | /// 54 | public static Expression> BuildDynamicExpression(string[] paramterNames, string expressionStr, params (string name, object value)[] variables) 55 | { 56 | var interpreter = new Interpreter(); 57 | if (EFCore != null) 58 | { 59 | interpreter.Reference(EFCore.GetType("Microsoft.EntityFrameworkCore.EF")); 60 | interpreter.Reference(EFCore.GetType("Microsoft.EntityFrameworkCore.DbFunctionsExtensions")); 61 | } 62 | if (EFCoreNpgsql != null) 63 | { 64 | interpreter.Reference(EFCoreNpgsql.GetType("Microsoft.EntityFrameworkCore.NpgsqlDbFunctionsExtensions")); 65 | } 66 | if (variables != null) 67 | { 68 | foreach (var (name, value) in variables) 69 | { 70 | interpreter.SetVariable(name, value); 71 | } 72 | } 73 | 74 | return interpreter.ParseAsExpression>(expressionStr, paramterNames); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Colder.Common.Util/Helpers/ProxyHelper.cs: -------------------------------------------------------------------------------- 1 | using Castle.DynamicProxy; 2 | using System; 3 | using System.Threading.Tasks; 4 | 5 | namespace Colder.Common.Util; 6 | 7 | /// 8 | /// 代理帮助类 9 | /// 10 | public static class ProxyHelper 11 | { 12 | private static readonly ProxyGenerator _generator = new ProxyGenerator(); 13 | 14 | /// 15 | /// 创建接口代理 16 | /// 17 | /// 接口类型 18 | /// 接口对象 19 | /// 过滤器,参数依次为上下文、执行委托 20 | /// 21 | public static TInterface CreateProxy(TInterface @interface, Func, Task> filter) 22 | where TInterface : class 23 | { 24 | return _generator.CreateInterfaceProxyWithTarget(@interface, new CastleInterceptor(filter)); 25 | } 26 | 27 | internal class CastleInterceptor : AsyncInterceptorBase 28 | { 29 | private readonly Func, Task> _filter; 30 | public CastleInterceptor(Func, Task> filter) 31 | { 32 | _filter = filter; 33 | } 34 | 35 | protected override async Task InterceptAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func proceed) 36 | { 37 | await _filter(invocation, () => proceed(invocation, proceedInfo)); 38 | } 39 | 40 | protected override async Task InterceptAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func> proceed) 41 | { 42 | TResult result = default; 43 | 44 | await _filter(invocation, async () => 45 | { 46 | result = await proceed(invocation, proceedInfo); 47 | if (typeof(Task).IsAssignableFrom(invocation.Method.ReturnType)) 48 | { 49 | invocation.ReturnValue = Task.FromResult(result); 50 | } 51 | else 52 | { 53 | invocation.ReturnValue = result; 54 | } 55 | }); 56 | 57 | return result; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Colder.Common/Colder.Common.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | true 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Colder.Common/Extentions/DateTimeExtentions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | 4 | namespace Colder.Common 5 | { 6 | /// 7 | /// 8 | /// 9 | public static class DateTimeExtentions 10 | { 11 | /// 12 | /// 获取某一日期是该年中的第几周 13 | /// 14 | /// 日期 15 | /// 该日期在该年中的周数 16 | public static int GetWeekOfYear(this DateTime dateTime) 17 | { 18 | GregorianCalendar gc = new GregorianCalendar(); 19 | return gc.GetWeekOfYear(dateTime, CalendarWeekRule.FirstDay, DayOfWeek.Monday); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Colder.Common/Extentions/EnumExtentions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Linq; 4 | 5 | namespace Colder.Common 6 | { 7 | /// 8 | /// 拓展类 9 | /// 10 | public static class EnumExtentions 11 | { 12 | /// 13 | /// 获取枚举描述 14 | /// 15 | /// 枚举值 16 | /// 17 | public static string GetDescription(this Enum value) 18 | { 19 | DescriptionAttribute attribute = value.GetType() 20 | .GetField(value.ToString()) 21 | .GetCustomAttributes(typeof(DescriptionAttribute), false) 22 | .SingleOrDefault() as DescriptionAttribute; 23 | return attribute == null ? value.ToString() : attribute.Description; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Colder.Common/Extentions/HttpClientExtentions.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | using System.Net.Http.Headers; 3 | using System.Threading.Tasks; 4 | 5 | namespace Colder.Common 6 | { 7 | /// 8 | /// 9 | /// 10 | public static class HttpClientExtentions 11 | { 12 | /// 13 | /// Post请求并获取Json 14 | /// 15 | /// 16 | /// 17 | /// 18 | /// 19 | public static async Task PostJson(this HttpClient httpClient, string url, string body) 20 | { 21 | HttpContent content = new StringContent(body); 22 | content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); 23 | HttpResponseMessage response = await httpClient.PostAsync(url, content); 24 | response.EnsureSuccessStatusCode(); 25 | return await response.Content.ReadAsStringAsync(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Colder.Common/Extentions/IQueryableExtentions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Linq.Expressions; 4 | 5 | namespace Colder.Common 6 | { 7 | /// 8 | /// IQueryable"T"的拓展操作 9 | /// 10 | public static class IQueryableExtentions 11 | { 12 | /// 13 | /// 符合条件则Where 14 | /// 15 | /// 实体类型 16 | /// 数据源 17 | /// 是否符合条件 18 | /// 筛选 19 | /// 20 | public static IQueryable WhereIf(this IQueryable q, bool need, Expression> where) 21 | { 22 | if (need) 23 | { 24 | return q.Where(where); 25 | } 26 | else 27 | { 28 | return q; 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Colder.Common/Extentions/ObjectExtentions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | 6 | namespace Colder.Common 7 | { 8 | /// 9 | /// 10 | /// 11 | public static class ObjectExtentions 12 | { 13 | /// 14 | /// 判断是否为Null或者空 15 | /// 16 | /// 对象 17 | /// 18 | public static bool IsNullOrEmpty(this object obj) 19 | { 20 | if (obj == null) 21 | return true; 22 | else 23 | { 24 | string objStr = obj.ToString(); 25 | return string.IsNullOrEmpty(objStr); 26 | } 27 | } 28 | 29 | /// 30 | /// 改变类型 31 | /// 32 | /// 原对象 33 | /// 目标类型 34 | /// 35 | public static object ChangeTypeByConvert(this object obj, Type targetType) 36 | { 37 | object resObj; 38 | if (targetType.IsGenericType && targetType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 39 | { 40 | NullableConverter newNullableConverter = new NullableConverter(targetType); 41 | resObj = newNullableConverter.ConvertFrom(obj); 42 | } 43 | else 44 | { 45 | resObj = Convert.ChangeType(obj, targetType); 46 | } 47 | 48 | return resObj; 49 | } 50 | 51 | /// 52 | /// 判断是否有效 53 | /// 注:不为null,不为空Guid,不为空集合 54 | /// 55 | /// 对象 56 | /// 57 | public static bool IsValid(this object obj) 58 | { 59 | if (obj == null) 60 | { 61 | return false; 62 | } 63 | if (obj is Guid?) 64 | { 65 | return (Guid?)obj != Guid.Empty; 66 | } 67 | if (obj is Guid guid) 68 | { 69 | return guid != Guid.Empty; 70 | } 71 | if (obj is string str) 72 | { 73 | return !string.IsNullOrEmpty(str); 74 | } 75 | if (obj is IEnumerable enumerable) 76 | { 77 | return enumerable.Cast().Count() >= 1; 78 | } 79 | 80 | return true; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Colder.Common/Extentions/StreamExtentions.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Text; 3 | using System.Threading.Tasks; 4 | 5 | namespace Colder.Common 6 | { 7 | /// 8 | /// 9 | /// 10 | public static class StreamExtentions 11 | { 12 | /// 13 | /// 将流读为字符串 14 | /// 注:默认使用UTF-8编码 15 | /// 16 | /// 流 17 | /// 指定编码 18 | /// 19 | public static async Task ReadToStringAsync(this Stream stream, Encoding encoding = null) 20 | { 21 | if (encoding == null) 22 | encoding = Encoding.UTF8; 23 | 24 | if (stream.CanSeek) 25 | { 26 | stream.Seek(0, SeekOrigin.Begin); 27 | } 28 | string resStr = await new StreamReader(stream, encoding).ReadToEndAsync(); 29 | 30 | if (stream.CanSeek) 31 | { 32 | stream.Seek(0, SeekOrigin.Begin); 33 | } 34 | 35 | return resStr; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Colder.Common/Extentions/TypeExtentions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Colder.Common 4 | { 5 | /// 6 | /// Type拓展 7 | /// 8 | public static class TypeExtentions 9 | { 10 | /// 11 | /// 是否为简单类型,即JSON序列化时直接ToString 12 | /// 13 | /// 类型 14 | /// 15 | public static bool IsSimple(this Type type) 16 | { 17 | if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) 18 | { 19 | // nullable type, check if the nested type is simple. 20 | return IsSimple(type.GetGenericArguments()[0]); 21 | } 22 | return type.IsPrimitive 23 | || type.IsEnum 24 | || type.Equals(typeof(string)) 25 | || type.Equals(typeof(decimal)) 26 | || type.Equals(typeof(DateTime)) 27 | || type.Equals(typeof(DateTimeOffset)) 28 | || type.Equals(typeof(Guid)) 29 | ; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Colder.Common/Helpers/AsyncHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace Colder.Common 6 | { 7 | /// 8 | /// 异步转同步,防止ASP.NET中死锁 9 | /// https://cpratt.co/async-tips-tricks/ 10 | /// 11 | public static class AsyncHelper 12 | { 13 | private static readonly TaskFactory _myTaskFactory = 14 | new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default); 15 | 16 | /// 17 | /// 同步执行 18 | /// 19 | /// 任务 20 | public static void RunSync(Func func) 21 | { 22 | _myTaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult(); 23 | } 24 | 25 | /// 26 | /// 同步执行 27 | /// 28 | /// 返回类型 29 | /// 任务 30 | /// 31 | public static TResult RunSync(Func> func) 32 | { 33 | return _myTaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Colder.Common/Helpers/EnumHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | 4 | namespace Colder.Common.Helpers; 5 | 6 | /// 7 | /// 枚举帮助类 8 | /// 9 | public static class EnumHelper 10 | { 11 | /// 12 | /// 将枚举描述值转换成枚举值。 13 | /// 14 | /// 枚举类型。 15 | /// 枚举值描述 16 | /// 17 | public static T ToEnumByDescription(this string enumDescription) 18 | where T : struct, IConvertible 19 | { 20 | var enumType = typeof(T); 21 | 22 | if (!enumType.IsEnum) 23 | { 24 | throw new InvalidOperationException($"该类型({enumType})并不是一个枚举类型!"); 25 | } 26 | 27 | foreach (var field in enumType.GetFields()) 28 | { 29 | if (Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) is DescriptionAttribute attribute) 30 | { 31 | if (attribute.Description == enumDescription) 32 | { 33 | return (T)field.GetRawConstantValue(); 34 | } 35 | } 36 | } 37 | 38 | throw new Exception($"{enumDescription} 转换为{typeof(T).FullName} 失败"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Colder.Common/Helpers/RandomHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Colder.Common 6 | { 7 | /// 8 | /// Random随机数帮助类 9 | /// 10 | public static class RandomHelper 11 | { 12 | private static Random _random { get; } = new Random(); 13 | 14 | /// 15 | /// 下一个随机数 16 | /// 17 | /// 最小值 18 | /// 最大值 19 | /// 20 | public static int Next(int minValue, int maxValue) 21 | { 22 | return _random.Next(minValue, maxValue); 23 | } 24 | 25 | /// 26 | /// 下一个随机值 27 | /// 28 | /// 值类型 29 | /// 值的集合 30 | /// 31 | public static T Next(IEnumerable source) 32 | { 33 | return source.ToList()[Next(0, source.Count())]; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/Colder.Common/Helpers/TimestampHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Colder.Common 4 | { 5 | /// 6 | /// 时间戳帮助类 7 | /// 8 | public static class TimestampHelper 9 | { 10 | private static readonly long _minTimestamp = DateTimeOffset.MinValue.ToUnixTimeMilliseconds(); 11 | private static readonly long _maxTimestamp = DateTimeOffset.MaxValue.ToUnixTimeMilliseconds(); 12 | 13 | /// 14 | /// 转为Unix时间戳 15 | /// 16 | /// 17 | /// 18 | public static long ToUnixTimeMilliseconds(DateTime dateTime) 19 | { 20 | if (dateTime.Kind == DateTimeKind.Unspecified) 21 | { 22 | dateTime = new DateTime(dateTime.Ticks, DateTimeKind.Local); 23 | } 24 | 25 | return new DateTimeOffset(dateTime).ToUnixTimeMilliseconds(); 26 | } 27 | 28 | /// 29 | /// Unix时间戳转为DateTimeOffset 30 | /// 31 | /// 32 | /// 33 | public static DateTimeOffset FromUnixTimeMilliseconds(long timestamp) 34 | { 35 | //小于最小值或大于最大值,做兼容,防止抛异常 36 | if (timestamp < _minTimestamp) 37 | { 38 | timestamp = _minTimestamp; 39 | } 40 | else if (timestamp > _maxTimestamp) 41 | { 42 | timestamp = _maxTimestamp; 43 | } 44 | 45 | return DateTimeOffset.FromUnixTimeMilliseconds(timestamp); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Colder.Common/Pipeline.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Threading.Tasks; 5 | 6 | namespace Colder.Common 7 | { 8 | /// 9 | /// 管道 10 | /// 11 | public class Pipeline where TContext : IPipelineContext 12 | { 13 | private readonly IServiceProvider _serviceProvider; 14 | private List _valveTypes = new List(); 15 | 16 | /// 17 | /// 18 | /// 19 | /// 20 | public Pipeline(IServiceProvider serviceProvider) 21 | { 22 | _serviceProvider = serviceProvider; 23 | } 24 | 25 | /// 26 | /// 27 | /// 28 | /// 29 | public void Add() where TValve : IAbstractValve 30 | { 31 | _valveTypes.Add(typeof(TValve)); 32 | } 33 | 34 | /// 35 | /// 36 | /// 37 | /// 38 | /// 39 | public async Task Handle(TContext context) 40 | { 41 | foreach (var aType in _valveTypes) 42 | { 43 | var valve = ActivatorUtilities.CreateInstance(_serviceProvider, aType) as IAbstractValve; 44 | await valve.Handle(context); 45 | if (context.Break) 46 | { 47 | break; 48 | } 49 | } 50 | } 51 | } 52 | 53 | /// 54 | /// 抽象阀门 55 | /// 56 | public interface IAbstractValve where TContext : IPipelineContext 57 | { 58 | /// 59 | /// 处理 60 | /// 61 | /// 上下文 62 | /// 63 | Task Handle(TContext context); 64 | } 65 | 66 | /// 67 | /// 管道上下文 68 | /// 69 | public interface IPipelineContext 70 | { 71 | /// 72 | /// 退出 73 | /// 74 | public bool Break { get; set; } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Colder.Common/Primitives/ApiResult.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.Common 2 | { 3 | /// 4 | /// Api请求结果 5 | /// 6 | public class ApiResult 7 | { 8 | /// 9 | /// 代码,默认200表示成功,其余根据业务需求自行定义 10 | /// 11 | public int Code { get; set; } = 200; 12 | 13 | /// 14 | /// 返回消息 15 | /// 16 | public string Msg { get; set; } 17 | } 18 | 19 | /// 20 | /// Api请求结果 21 | /// 22 | /// 返回数据类型 23 | public class ApiResult : ApiResult 24 | { 25 | /// 26 | /// 返回数据 27 | /// 28 | public T Data { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Colder.Common/Primitives/IdInput.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.Common 2 | { 3 | /// 4 | /// Id参数 5 | /// 6 | /// 类型 7 | public class IdInput 8 | { 9 | /// 10 | /// Id 11 | /// 12 | public T Id { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Colder.Common/Primitives/MemoryMessageHandlerBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Threading.Tasks; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Microsoft.Extensions.Logging; 8 | 9 | namespace Colder.Common; 10 | 11 | /// 12 | /// 内存消息队列处理 13 | /// 14 | /// 需要注入为单例 15 | public abstract class MemoryMessageHandlerBase 16 | { 17 | private readonly BlockingCollection _messages = new BlockingCollection(); 18 | private readonly Task[] _tasks; 19 | 20 | /// 21 | /// 22 | /// 23 | protected readonly ILogger Logger; 24 | 25 | /// 26 | /// 27 | /// 28 | protected readonly IServiceProvider ServiceProvider; 29 | 30 | /// 31 | /// 32 | /// 33 | protected readonly IServiceScopeFactory ServiceScopeFactory; 34 | 35 | /// 36 | /// 37 | /// 38 | /// serviceProvider 39 | /// 线程数,默认为1 40 | protected MemoryMessageHandlerBase(IServiceProvider serviceProvider, int threads = 1) 41 | { 42 | ServiceProvider = serviceProvider; 43 | ServiceScopeFactory = serviceProvider.GetRequiredService(); 44 | Logger = serviceProvider.GetRequiredService().CreateLogger(GetType()); 45 | 46 | _tasks = Enumerable.Range(0, threads).Select(_ => Task.Factory.StartNew(async () => 47 | { 48 | foreach (var message in _messages.GetConsumingEnumerable()) 49 | { 50 | try 51 | { 52 | var method = GetType().GetMethods((BindingFlags)63) 53 | .Where(x => x.GetParameters().Length == 1 && x.GetParameters()[0].ParameterType == message.GetType()) 54 | .First(); 55 | 56 | if (method.Invoke(this, new object[] { message }) is Task task) 57 | { 58 | await task; 59 | } 60 | } 61 | catch (Exception ex) 62 | { 63 | Logger.LogError(ex, ex.Message); 64 | } 65 | } 66 | }, TaskCreationOptions.LongRunning)).ToArray(); 67 | } 68 | 69 | /// 70 | /// 71 | /// 72 | /// 73 | public void AddMessage(object message) 74 | { 75 | _messages.Add(message); 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /src/Colder.Common/Primitives/MsgException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Colder.Common 4 | { 5 | /// 6 | /// 业务异常 7 | /// 注:并不会当作真正的异常处理,仅为方便返回前端错误提示信息 8 | /// 9 | public class MsgException : Exception 10 | { 11 | /// 12 | /// 代码 13 | /// 14 | public int Code { get; set; } 15 | 16 | /// 17 | /// 构造函数 18 | /// 19 | public MsgException() 20 | { 21 | 22 | } 23 | 24 | /// 25 | /// 构造函数 26 | /// 27 | /// 错误信息 28 | public MsgException(string message) 29 | : base(message) 30 | { 31 | 32 | } 33 | 34 | /// 35 | /// 构造函数 36 | /// 37 | /// 错误信息 38 | /// 错误代码 39 | public MsgException(string message, int code) 40 | : base(message) 41 | { 42 | Code = code; 43 | } 44 | 45 | /// 46 | /// 47 | /// 48 | /// 49 | /// 50 | /// 51 | public MsgException(string message, int code, Exception innerException) : base(message, innerException) 52 | { 53 | Code = code; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Colder.Common/Primitives/PageInput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Colder.Common 4 | { 5 | /// 6 | /// 分页查询基类 7 | /// 8 | public class PageInput 9 | { 10 | /// 11 | /// 当前页码,默认1 12 | /// 13 | public int PageIndex { get; set; } = 1; 14 | 15 | /// 16 | /// 每页行数,默认30 17 | /// 18 | public int PageRows { get; set; } = 30; 19 | 20 | /// 21 | /// 排序 22 | /// 23 | public OrderByField[] OrderBy { get; set; } = Array.Empty(); 24 | } 25 | 26 | /// 27 | /// 参数 28 | /// 29 | /// 30 | public class PageInput : PageInput where T : new() 31 | { 32 | /// 33 | /// 自定义参数 34 | /// 35 | public T Search { get; set; } = new T(); 36 | } 37 | 38 | /// 39 | /// 排序字段 40 | /// 41 | public class OrderByField 42 | { 43 | /// 44 | /// 排序字段名 45 | /// 46 | public string Field { get; set; } 47 | 48 | /// 49 | /// 排序类型 50 | /// 51 | public OrderByTypes Type { get; set; } 52 | } 53 | 54 | /// 55 | /// 排序类型 56 | /// 57 | public enum OrderByTypes 58 | { 59 | /// 60 | /// 顺序 61 | /// 62 | Asc = 0, 63 | 64 | /// 65 | /// 倒序 66 | /// 67 | Desc = 1 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Colder.Common/Primitives/PageList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Colder.Common 4 | { 5 | /// 6 | /// 分页结果 7 | /// 8 | /// 9 | public class PageList 10 | { 11 | /// 12 | /// 结果 13 | /// 14 | public T[] Items { get; set; } = Array.Empty(); 15 | 16 | /// 17 | /// 总记录数 18 | /// 19 | public int Total { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Colder.Dependency/AOP/BaseAOPAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace Colder.Dependency 5 | { 6 | /// 7 | /// AOP基类 8 | /// 注:不支持控制器,需要定义接口并实现接口,自定义AOP特性放到接口实现类上 9 | /// 10 | public abstract class BaseAOPAttribute : Attribute 11 | { 12 | /// 13 | /// 执行方法前 14 | /// 15 | /// 上下文 16 | /// 17 | public virtual async Task Befor(IAOPContext context) 18 | { 19 | await Task.CompletedTask; 20 | } 21 | 22 | /// 23 | /// 执行方法后 24 | /// 25 | /// 上下文 26 | /// 27 | public virtual async Task After(IAOPContext context) 28 | { 29 | await Task.CompletedTask; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Colder.Dependency/AOP/CastleAOPContext.cs: -------------------------------------------------------------------------------- 1 | using Castle.DynamicProxy; 2 | using System; 3 | using System.Reflection; 4 | 5 | namespace Colder.Dependency 6 | { 7 | internal class CastleAOPContext : IAOPContext 8 | { 9 | private readonly IInvocation _invocation; 10 | public CastleAOPContext(IInvocation invocation, IServiceProvider serviceProvider) 11 | { 12 | _invocation = invocation; 13 | ServiceProvider = serviceProvider; 14 | } 15 | public IServiceProvider ServiceProvider { get; } 16 | 17 | public object[] Arguments => _invocation.Arguments; 18 | 19 | public Type[] GenericArguments => _invocation.GenericArguments; 20 | 21 | public MethodInfo Method => _invocation.Method; 22 | 23 | public MethodInfo MethodInvocationTarget => _invocation.MethodInvocationTarget; 24 | 25 | public object Proxy => _invocation.Proxy; 26 | 27 | public object ReturnValue { get => _invocation.ReturnValue; set => _invocation.ReturnValue = value; } 28 | 29 | public Type TargetType => _invocation.TargetType; 30 | 31 | public object InvocationTarget => _invocation.InvocationTarget; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Colder.Dependency/AOP/IAOPContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace Colder.Dependency 5 | { 6 | /// 7 | /// AOP上下文 8 | /// 9 | public interface IAOPContext 10 | { 11 | /// 12 | /// 容器 13 | /// 14 | IServiceProvider ServiceProvider { get; } 15 | 16 | /// 17 | /// 方法参数 18 | /// 19 | object[] Arguments { get; } 20 | 21 | /// 22 | /// 泛型参数类型 23 | /// 24 | Type[] GenericArguments { get; } 25 | 26 | /// 27 | /// 调用的方法 28 | /// 29 | MethodInfo Method { get; } 30 | 31 | /// 32 | /// 目标调用方法 33 | /// 34 | MethodInfo MethodInvocationTarget { get; } 35 | 36 | /// 37 | /// 代理对象 38 | /// 39 | object Proxy { get; } 40 | 41 | /// 42 | /// 返回值 43 | /// 44 | object ReturnValue { get; set; } 45 | 46 | /// 47 | /// 目标类型 48 | /// 49 | Type TargetType { get; } 50 | 51 | /// 52 | /// 目标对象 53 | /// 54 | object InvocationTarget { get; } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Colder.Dependency/Colder.Dependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 注入 6 | 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Colder.Dependency/IScopedDependency.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.Dependency 2 | { 3 | /// 4 | /// 注入标记,生命周期为Scope 5 | /// 6 | public interface IScopedDependency 7 | { 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Colder.Dependency/ISingletonDependency.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.Dependency 2 | { 3 | /// 4 | /// 注入标记,生命周期为Singleton 5 | /// 6 | public interface ISingletonDependency 7 | { 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Colder.Dependency/ITransientDependency.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.Dependency 2 | { 3 | /// 4 | /// 入标记,生命周期为Transient 5 | /// 6 | public interface ITransientDependency 7 | { 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Colder.DistributedId/AsyncHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace Colder.DistributedId 6 | { 7 | /// 8 | /// 异步转同步,防止ASP.NET中死锁 9 | /// https://cpratt.co/async-tips-tricks/ 10 | /// 11 | internal static class AsyncHelper 12 | { 13 | private static readonly TaskFactory _myTaskFactory = 14 | new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default); 15 | 16 | /// 17 | /// 同步执行 18 | /// 19 | /// 任务 20 | public static void RunSync(Func func) 21 | { 22 | _myTaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult(); 23 | } 24 | 25 | /// 26 | /// 同步执行 27 | /// 28 | /// 返回类型 29 | /// 任务 30 | /// 31 | public static TResult RunSync(Func> func) 32 | { 33 | return _myTaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Colder.DistributedId/Colder.DistributedId.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 分布式Id 6 | 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Colder.DistributedId/DistributedIdExtentions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Hosting; 4 | using System.Linq; 5 | 6 | namespace Colder.DistributedId 7 | { 8 | /// 9 | /// 拓展 10 | /// 11 | public static class DistributedIdExtentions 12 | { 13 | /// 14 | /// 使用默认配置分布式锁 15 | /// 16 | /// 构造器 17 | /// 18 | public static IHostBuilder ConfigureDistributedIdDefaults(this IHostBuilder hostBuilder) 19 | { 20 | hostBuilder.ConfigureServices((host, services) => 21 | { 22 | var option = host.Configuration.GetChildren() 23 | .Where(x => x.Key.ToLower() == "distributedid") 24 | .FirstOrDefault() 25 | ?.Get() ?? new DistributedIdOptions(); 26 | 27 | services.AddDistributedId(option); 28 | }); 29 | 30 | return hostBuilder; 31 | } 32 | 33 | /// 34 | /// 注入分布式Id 35 | /// 36 | /// IServiceCollection 37 | /// 38 | /// 39 | public static IServiceCollection AddDistributedId(this IServiceCollection services, DistributedIdOptions distributedIdOption) 40 | { 41 | services.AddOptions().Configure(x => 42 | { 43 | x.GetType().GetProperties().ToList().ForEach(aProperty => 44 | { 45 | aProperty.SetValue(x, aProperty.GetValue(distributedIdOption)); 46 | }); 47 | }); 48 | 49 | return services.AddSingleton(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Colder.DistributedId/DistributedIdOptions.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.DistributedId 2 | { 3 | /// 4 | /// 分布式Id选项 5 | /// 6 | public class DistributedIdOptions 7 | { 8 | /// 9 | /// Guid序列类型 10 | /// 11 | public SequentialGuidType GuidType { get; set; } = SequentialGuidType.AtBegin; 12 | 13 | /// 14 | /// 指定机器Id,范围1-1023,若不指定则在范围内随机取 15 | /// 16 | public int WorkderId { get; set; } 17 | 18 | /// 19 | /// 是否为分布式(即多实例部署) 20 | /// 若开启则需要提前配置分布式缓存(Colder.Cache)与分布式锁(Colder.DistributedLock) 21 | /// 多实例部署并且使用LongId(即雪花Id)时建议开启此选项 22 | /// 23 | public bool Distributed { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Colder.DistributedId/IDistributedId.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Colder.DistributedId 4 | { 5 | /// 6 | /// 分布式Id 7 | /// 8 | public interface IDistributedId 9 | { 10 | /// 11 | /// 生成有序Guid,使用默认排序类型 12 | /// 13 | /// 14 | Guid NewGuid(); 15 | 16 | /// 17 | /// 生成有序Guid,指定排序类型 18 | /// 19 | /// 排序类型 20 | /// 21 | Guid NewGuid(SequentialGuidType sequentialGuidType); 22 | 23 | /// 24 | /// 生成有序LongId 25 | /// 26 | /// 27 | long NewLongId(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Colder.DistributedId/Snowflake/DisposableAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Colder.DistributedId 4 | { 5 | internal class DisposableAction : IDisposable 6 | { 7 | readonly Action _action; 8 | 9 | public DisposableAction(Action action) 10 | { 11 | if (action == null) 12 | throw new ArgumentNullException("action"); 13 | _action = action; 14 | } 15 | 16 | public void Dispose() 17 | { 18 | _action(); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/Colder.DistributedId/Snowflake/InvalidSystemClock.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Colder.DistributedId 4 | { 5 | internal class InvalidSystemClock : Exception 6 | { 7 | public InvalidSystemClock(string message) : base(message) { } 8 | } 9 | } -------------------------------------------------------------------------------- /src/Colder.DistributedId/Snowflake/TimeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Colder.DistributedId 4 | { 5 | internal static class System 6 | { 7 | public static Func currentTimeFunc = InternalCurrentTimeMillis; 8 | 9 | public static long CurrentTimeMillis() 10 | { 11 | return currentTimeFunc(); 12 | } 13 | 14 | public static IDisposable StubCurrentTime(Func func) 15 | { 16 | currentTimeFunc = func; 17 | return new DisposableAction(() => 18 | { 19 | currentTimeFunc = InternalCurrentTimeMillis; 20 | }); 21 | } 22 | 23 | public static IDisposable StubCurrentTime(long millis) 24 | { 25 | currentTimeFunc = () => millis; 26 | return new DisposableAction(() => 27 | { 28 | currentTimeFunc = InternalCurrentTimeMillis; 29 | }); 30 | } 31 | 32 | private static readonly DateTime Jan1st1970 = new DateTime 33 | (1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 34 | 35 | private static long InternalCurrentTimeMillis() 36 | { 37 | return (long)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Colder.DistributedLock.Abstractions/Colder.DistributedLock.Abstractions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | true 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Colder.DistributedLock.Abstractions/DistributedLockOptions.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.DistributedLock.Abstractions 2 | { 3 | /// 4 | /// 分布式锁选项 5 | /// 6 | public class DistributedLockOptions 7 | { 8 | /// 9 | /// 锁类型 10 | /// 11 | public LockTypes LockType { get; set; } = LockTypes.InMemory; 12 | 13 | /// 14 | /// Redis节点 15 | /// 16 | public string[] RedisEndPoints { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Colder.DistributedLock.Abstractions/IDistributedLock.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace Colder.DistributedLock.Abstractions 5 | { 6 | /// 7 | /// 分布式锁 8 | /// 9 | public interface IDistributedLock 10 | { 11 | /// 12 | /// 获取锁(类似于lock(obj)) 13 | /// 14 | /// 锁键值 15 | /// 超时时间 16 | /// 17 | Task Lock(string key, TimeSpan? timeout = null); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Colder.DistributedLock.Abstractions/LockTypes.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.DistributedLock.Abstractions 2 | { 3 | /// 4 | /// 分布式锁类型 5 | /// 6 | public enum LockTypes 7 | { 8 | /// 9 | /// 内存实现(进程内有效) 10 | /// 11 | InMemory = 1, 12 | 13 | /// 14 | /// Redis实现(分布式) 15 | /// 16 | Redis = 2 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Colder.DistributedLock.Hosting/Colder.DistributedLock.Hosting.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Colder.DistributedLock.InMemory/Colder.DistributedLock.InMemory.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Colder.DistributedLock.InMemory/InMemoryDistributedLock.cs: -------------------------------------------------------------------------------- 1 | using AsyncKeyedLock; 2 | using Colder.DistributedLock.Abstractions; 3 | using System; 4 | using System.Threading.Tasks; 5 | 6 | namespace Colder.DistributedLock.InMemory 7 | { 8 | internal class InMemoryDistributedLock : IDistributedLock 9 | { 10 | private readonly StripedAsyncKeyedLocker _asyncKeyedLocker = new(); 11 | public async Task Lock(string key, TimeSpan? timeout) 12 | { 13 | timeout = timeout ?? TimeSpan.FromSeconds(10); 14 | 15 | var lockResult= await _asyncKeyedLocker.LockAsync(key, timeout.Value); 16 | if (!lockResult.EnteredSemaphore) 17 | { 18 | throw new TimeoutException($"获取锁超时{timeout.Value.TotalSeconds}秒"); 19 | } 20 | 21 | return lockResult; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/Colder.DistributedLock.Redis/Colder.DistributedLock.Redis.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Colder.DistributedLock.Redis/RedisDistributedLock.cs: -------------------------------------------------------------------------------- 1 | using Colder.DistributedLock.Abstractions; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Hosting; 4 | using Microsoft.Extensions.Options; 5 | using RedLockNet.SERedis; 6 | using RedLockNet.SERedis.Configuration; 7 | using StackExchange.Redis; 8 | using System; 9 | using System.Linq; 10 | using System.Threading.Tasks; 11 | 12 | namespace Colder.DistributedLock.InMemory 13 | { 14 | internal class RedisDistributedLock : IDistributedLock 15 | { 16 | public RedisDistributedLock(IOptions options, IServiceProvider serviceProvider) 17 | { 18 | var multiplexers = options.Value.RedisEndPoints 19 | .Select(x => new RedLockMultiplexer(ConnectionMultiplexer.Connect(x))) 20 | .ToList(); 21 | 22 | _redLockFactory = RedLockFactory.Create(multiplexers); 23 | 24 | IHostApplicationLifetime hostApplicationLifetime = serviceProvider.GetService(); 25 | if (hostApplicationLifetime != null) 26 | { 27 | hostApplicationLifetime.ApplicationStopping.Register(() => 28 | { 29 | _redLockFactory.Dispose(); 30 | }); 31 | } 32 | } 33 | 34 | private readonly RedLockFactory _redLockFactory; 35 | public async Task Lock(string key, TimeSpan? timeout) 36 | { 37 | timeout = timeout ?? TimeSpan.FromSeconds(10); 38 | 39 | var expiry = TimeSpan.FromSeconds(30); 40 | var retry = TimeSpan.FromSeconds(1); 41 | 42 | var theLock = await _redLockFactory.CreateLockAsync(key, expiry, timeout.Value, retry); 43 | 44 | if (!theLock.IsAcquired) 45 | { 46 | throw new Exception($"获取分布式锁失败 Key:{key}"); 47 | } 48 | 49 | return theLock; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Colder.Domain.Abstractions/Colder.Domain.Abstractions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | true 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Colder.Domain.Abstractions/IAggregateRoot.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.Domain 2 | { 3 | /// 4 | /// 聚合根标志 5 | /// 6 | public interface IAggregateRoot 7 | { 8 | /// 9 | /// 唯一标志 10 | /// 11 | public TKey Id { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Colder.Domain.Abstractions/IRepositoryBase.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Colder.Domain 4 | { 5 | /// 6 | /// 仓储基接口 7 | /// 8 | /// 聚合根类型 9 | /// 聚合根标志类型 10 | public interface IRepositoryBase where TAggregateRoot : IAggregateRoot 11 | { 12 | /// 13 | /// 获取 14 | /// 15 | /// 唯一标志 16 | /// 17 | Task Get(TKey key); 18 | 19 | /// 20 | /// 添加 21 | /// 22 | /// 聚合根 23 | /// 24 | Task Add(TAggregateRoot aggregateRoot); 25 | 26 | /// 27 | /// 更新 28 | /// 29 | /// 聚合根 30 | /// 31 | Task Update(TAggregateRoot aggregateRoot); 32 | 33 | /// 34 | /// 删除 35 | /// 36 | /// 唯一标志 37 | /// 38 | Task Remove(params TKey[] id); 39 | 40 | /// 41 | /// 删除 42 | /// 43 | /// 聚合根集合 44 | /// 45 | Task Remove(params TAggregateRoot[] items); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Colder.Domain.Abstractions/IStatefulAggregateRoot.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Colder.Domain 4 | { 5 | /// 6 | /// 有状态聚合根 7 | /// 8 | /// 状态 9 | /// 标志类型 10 | public interface IStatefulAggregateRoot where TState : IAggregateRoot 11 | { 12 | /// 13 | /// 获取状态 14 | /// 15 | /// 16 | Task GetState(); 17 | 18 | /// 19 | /// 设置状态 20 | /// 21 | /// 22 | /// 23 | Task SetState(TState state); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Colder.EFCore/Colder.EFCore.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | true 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Colder.Extentions/AOPTransactionExtentions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | 3 | namespace Colder.Extentions 4 | { 5 | /// 6 | /// AOP事务拓展 7 | /// 8 | public static class AOPTransactionExtentions 9 | { 10 | /// 11 | /// 注入AOP事务 12 | /// 13 | /// services 14 | /// 15 | public static IServiceCollection AddAOPTransaction(this IServiceCollection services) 16 | { 17 | return services.AddScoped(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Colder.Extentions/Colder.Extentions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.1 5 | 通用拓展 6 | 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Colder.ImageSharp/Colder.ImageSharp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | true 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Colder.ImageSharp/ImageSharpHelper.cs: -------------------------------------------------------------------------------- 1 | using SixLabors.ImageSharp; 2 | using SixLabors.ImageSharp.Formats.Jpeg; 3 | using SixLabors.ImageSharp.Processing; 4 | using System.IO; 5 | 6 | namespace Colder.ImageSharp; 7 | 8 | /// 9 | /// 10 | /// 11 | public static class ImageSharpHelper 12 | { 13 | /// 14 | /// 等比压缩图片并转为jpg 15 | /// 16 | /// 17 | /// 18 | /// 19 | public static byte[] CompressImage(byte[] imageBytes, int width = 1920) 20 | { 21 | using var imageMs = new MemoryStream(imageBytes); 22 | var image = Image.Load(imageMs); 23 | image.Metadata.ExifProfile = null; 24 | 25 | if (image.Width > width) 26 | { 27 | var rate = (double)width / image.Width; 28 | image.Mutate(x => x.Resize((int)(image.Width * rate), (int)(image.Height * rate))); 29 | } 30 | 31 | var ms = new MemoryStream(); 32 | image.SaveAsJpeg(ms, new JpegEncoder() 33 | { 34 | Quality = 75 35 | }); 36 | 37 | return ms.ToArray(); 38 | } 39 | } -------------------------------------------------------------------------------- /src/Colder.Infrastructure.Abstractions/Colder.Infrastructure.Abstractions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.1 5 | 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Colder.Json/Colder.Json.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Colder.Json/Converters/LongToStringConverter.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Linq; 3 | using System; 4 | 5 | namespace Colder.Json 6 | { 7 | /// 8 | /// 9 | /// 10 | public class LongToStringConverter : JsonConverter 11 | { 12 | /// 13 | /// 14 | /// 15 | /// 16 | /// 17 | /// 18 | /// 19 | /// 20 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 21 | { 22 | JToken jt = JValue.ReadFrom(reader); 23 | 24 | return typeof(long).Equals(objectType) ? jt.Value() : jt.Value(); 25 | } 26 | 27 | /// 28 | /// 29 | /// 30 | /// 31 | /// 32 | public override bool CanConvert(Type objectType) 33 | { 34 | return typeof(long).Equals(objectType) || typeof(long?).Equals(objectType); 35 | } 36 | 37 | /// 38 | /// 39 | /// 40 | /// 41 | /// 42 | /// 43 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 44 | { 45 | serializer.Serialize(writer, value?.ToString()); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Colder.Logging.Abstractions/Colder.Logging.Abstractions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 日志组件抽象 6 | 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Colder.Logging.Abstractions/ElasticsearchOption.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Colder.Logging.Abstractions 4 | { 5 | /// 6 | /// ES配置 7 | /// 8 | public class ElasticsearchOption : EnableOption 9 | { 10 | /// 11 | /// ES节点 12 | /// 13 | public List Nodes { get; set; } = new List(); 14 | 15 | /// 16 | /// 索引格式:custom-index-{0:yyyy.MM} 17 | /// 18 | public string IndexFormat { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Colder.Logging.Abstractions/EnableOption.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.Logging.Abstractions 2 | { 3 | /// 4 | /// 是否启用定义 5 | /// 6 | public class EnableOption 7 | { 8 | /// 9 | /// 是否启用 10 | /// 11 | public bool Enabled { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Colder.Logging.Abstractions/FileOption.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.Logging.Abstractions 2 | { 3 | /// 4 | /// 文件日志配置 5 | /// 6 | public class FileOption : EnableOption 7 | { 8 | /// 9 | /// 保留天数 10 | /// 11 | public int RetainedFileDays { get; set; } = 30; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Colder.Logging.Abstractions/KafkaOption.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.Logging.Abstractions 2 | { 3 | /// 4 | /// Kafka配置 5 | /// 6 | public class KafkaOption : EnableOption 7 | { 8 | /// 9 | /// 服务器地址 10 | /// 11 | public string Brokers { get; set; } 12 | 13 | /// 14 | /// 用户名 15 | /// 16 | public string UserName { get; set; } 17 | 18 | /// 19 | /// 密码 20 | /// 21 | public string Password { get; set; } 22 | 23 | /// 24 | /// Topic 25 | /// 26 | public string Topic { get; set; } = "log"; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Colder.Logging.Abstractions/LogOptions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace Colder.Logging.Abstractions 6 | { 7 | /// 8 | /// 日志配置项 9 | /// 10 | public class LogOptions 11 | { 12 | private string _instance; 13 | 14 | /// 15 | /// 实例名,默认为机器名 16 | /// 17 | public string Instance 18 | { 19 | get => string.IsNullOrEmpty(_instance) ? Environment.MachineName : _instance; 20 | set => _instance = value; 21 | } 22 | 23 | /// 24 | /// 最低日志输出级别 25 | /// 26 | public LogLevel MinLevel { get; set; } = LogLevel.Information; 27 | 28 | /// 29 | /// 输出到控制台 30 | /// 31 | public EnableOption Console { get; set; } = new EnableOption 32 | { 33 | Enabled = true 34 | }; 35 | 36 | /// 37 | /// 输出到调试 38 | /// 39 | public EnableOption Debug { get; set; } = new EnableOption 40 | { 41 | Enabled = true 42 | }; 43 | 44 | /// 45 | /// 输出到文件 46 | /// 47 | public FileOption File { get; set; } = new FileOption 48 | { 49 | Enabled = true 50 | }; 51 | 52 | /// 53 | /// 输出到ES 54 | /// 55 | public ElasticsearchOption Elasticsearch { get; set; } = new ElasticsearchOption(); 56 | 57 | /// 58 | /// 输出到Kafka 59 | /// 60 | public KafkaOption Kafka { get; set; } = new KafkaOption(); 61 | 62 | /// 63 | /// 重写日志级别 64 | /// 65 | public List Overrides { get; set; } = new List(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Colder.Logging.Abstractions/OverrideOption.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | 3 | namespace Colder.Logging.Abstractions 4 | { 5 | /// 6 | /// 重写 7 | /// 8 | public class OverrideOption 9 | { 10 | /// 11 | /// 源 12 | /// 13 | public string Source { get; set; } 14 | 15 | /// 16 | /// 最低级别 17 | /// 18 | public LogLevel MinLevel { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Colder.Logging.Serilog/Bootstrapper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Hosting; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace Colder.Logging.Serilog 8 | { 9 | internal class Bootstrapper : BackgroundService 10 | { 11 | private readonly ILogger _logger; 12 | public Bootstrapper(ILogger logger) 13 | { 14 | _logger = logger; 15 | } 16 | protected override Task ExecuteAsync(CancellationToken stoppingToken) 17 | { 18 | AppDomain.CurrentDomain.UnhandledException += (sender, arg) => 19 | { 20 | _logger.LogError((Exception)arg.ExceptionObject, "程序崩溃"); 21 | //延迟三秒关闭程序,确保崩溃日志已写入完成 22 | Thread.Sleep(3000); 23 | }; 24 | return Task.CompletedTask; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Colder.Logging.Serilog/Colder.Logging.Serilog.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 日志组件Serilog实现 6 | 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Colder.Mail/Colder.Mail.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.Abstractions/Colder.MessageBus.Abstractions.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 消息总线抽象定义 6 | 7 | true 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.Abstractions/IMessageBus.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Colder.MessageBus.Abstractions 4 | { 5 | /// 6 | /// 消息总线接口 7 | /// 8 | public interface IMessageBus 9 | { 10 | /// 11 | /// 发布事件 12 | /// 13 | /// 消息类型 14 | /// 消息 15 | /// 指定消费节点 16 | /// 17 | Task Publish(TMessage message, string endpoint = null) where TMessage : class; 18 | 19 | /// 20 | /// 发送请求 21 | /// 22 | /// 请求数据类型 23 | /// 返回数据类型 24 | /// 消息 25 | /// 指定消费节点 26 | /// 27 | Task Request(TRequest message, string endpoint) 28 | where TRequest : class 29 | where TResponse : class; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.Abstractions/IMessageHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Colder.MessageBus.Abstractions 4 | { 5 | /// 6 | /// 消费者接口 7 | /// 8 | /// 9 | public interface IMessageHandler where TMessage : class 10 | { 11 | /// 12 | /// 消费消息 13 | /// 14 | /// 消息上下文 15 | /// 16 | Task Handle(MessageContext context); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.Abstractions/MessageContext.T.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.MessageBus.Abstractions 2 | { 3 | /// 4 | /// 消息上下文 5 | /// 6 | /// 消息类型 7 | public class MessageContext : MessageContext where TMessage : class 8 | { 9 | /// 10 | /// 消息 11 | /// 12 | public TMessage Message { get; set; } = null; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.Abstractions/MessageContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Colder.MessageBus.Abstractions 5 | { 6 | /// 7 | /// 消息上下文 8 | /// 9 | public class MessageContext 10 | { 11 | /// 12 | /// 消息Id 13 | /// 14 | public Guid? MessageId { get; set; } 15 | 16 | /// 17 | /// 当前容器 18 | /// 19 | public IServiceProvider ServiceProvider { get; set; } 20 | 21 | /// 22 | /// 源地址 23 | /// 24 | public Uri SourceAddress { get; set; } 25 | 26 | /// 27 | /// 源机器名 28 | /// 29 | public string SourceMachineName { get; set; } 30 | 31 | /// 32 | /// 目的地 33 | /// 34 | public Uri DestinationAddress { get; set; } 35 | 36 | /// 37 | /// 返回地址 38 | /// 39 | public Uri ResponseAddress { get; set; } 40 | 41 | /// 42 | /// 失败地址 43 | /// 44 | public Uri FaultAddress { get; set; } 45 | 46 | /// 47 | /// 发送时间 48 | /// 49 | public DateTime? SentTime { get; set; } 50 | 51 | /// 52 | /// 头部 53 | /// 54 | public Dictionary Headers { get; set; } 55 | 56 | /// 57 | /// 消息体 58 | /// 59 | public string MessageBody { get; set; } 60 | 61 | /// 62 | /// 返回消息(仅用于请求) 63 | /// 64 | public object Response { get; set; } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.Abstractions/Options/Constant.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.MessageBus.Abstractions 2 | { 3 | /// 4 | /// 常量 5 | /// 6 | public static class Constant 7 | { 8 | /// 9 | /// 只发消息总线 10 | /// 11 | public const string SENDONLY = "SendOnly"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.Abstractions/Options/MessageBusOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace Colder.MessageBus.Abstractions 5 | { 6 | /// 7 | /// 消息总线配置 8 | /// 9 | public class MessageBusOptions 10 | { 11 | /// 12 | /// 传输介质 13 | /// 14 | public TransportType Transport { get; set; } = TransportType.InMemory; 15 | 16 | /// 17 | /// 地址 18 | /// 19 | public string Host { get; set; } 20 | 21 | /// 22 | /// 用户名 23 | /// 24 | public string Username { get; set; } 25 | 26 | /// 27 | /// 密码 28 | /// 29 | public string Password { get; set; } 30 | 31 | /// 32 | /// 发送消息超时时间,单位(秒) 33 | /// 34 | public int SendMessageTimeout { get; set; } = 30; 35 | 36 | /// 37 | /// 终结点,默认为入口程序集名 38 | /// 39 | public string Endpoint { get; set; } = Assembly.GetEntryAssembly().GetName().Name; 40 | 41 | /// 42 | /// 失败重试次数,默认3 43 | /// 44 | public int RetryCount { get; set; } = 3; 45 | 46 | /// 47 | /// 重试等待间隔(毫秒),默认1000 48 | /// 49 | public int RetryIntervalMilliseconds { get; set; } = 1000; 50 | 51 | private int _concurrency; 52 | 53 | /// 54 | /// 并发处理数(默认根据逻辑处理器数量自动分配,cpu线程数*2) 55 | /// 56 | public int Concurrency 57 | { 58 | get => _concurrency == 0 ? Environment.ProcessorCount * 2 : _concurrency; 59 | set => _concurrency = value; 60 | } 61 | 62 | /// 63 | /// IMessageHandler所在程序集,默认为入口程序集,作用于全局 64 | /// 65 | public static Assembly[] Assemblies { get; set; } = new Assembly[] { Assembly.GetEntryAssembly() }; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.Abstractions/Options/TransportType.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.MessageBus.Abstractions 2 | { 3 | /// 4 | /// 传输介质类型 5 | /// 6 | public enum TransportType 7 | { 8 | /// 9 | /// 内存 10 | /// 11 | InMemory = 1, 12 | 13 | /// 14 | /// RabbitMQ 15 | /// 16 | RabbitMQ = 2, 17 | 18 | /// 19 | /// MQTT 20 | /// 21 | MQTT = 3, 22 | 23 | /// 24 | /// Redis 25 | /// 26 | Redis = 4 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.Hosting/AbstractProvider.cs: -------------------------------------------------------------------------------- 1 | using Colder.MessageBus.Abstractions; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | using Microsoft.Extensions.DependencyInjection; 5 | 6 | namespace Colder.MessageBus.Hosting 7 | { 8 | /// 9 | /// 10 | /// 11 | public abstract class AbstractProvider 12 | { 13 | /// 14 | /// 15 | /// 16 | protected readonly IServiceProvider ServiceProvider; 17 | 18 | /// 19 | /// 20 | /// 21 | protected readonly IServiceScopeFactory ServiceScopeFactory; 22 | 23 | /// 24 | /// 25 | /// 26 | protected readonly ILogger Logger; 27 | 28 | /// 29 | /// 30 | /// 31 | protected readonly ILoggerFactory LoggerFactory; 32 | 33 | /// 34 | /// 35 | /// 36 | protected readonly MessageBusOptions Options; 37 | 38 | /// 39 | /// 40 | /// 41 | /// 42 | /// 43 | protected AbstractProvider(IServiceProvider serviceProvider, MessageBusOptions options) 44 | { 45 | ServiceProvider = serviceProvider; 46 | ServiceScopeFactory = serviceProvider.GetRequiredService(); 47 | Options = options; 48 | LoggerFactory = serviceProvider.GetService(); 49 | Logger = LoggerFactory.CreateLogger(GetType()); 50 | } 51 | 52 | /// 53 | /// 54 | /// 55 | /// 56 | public abstract IMessageBus GetBusInstance(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.Hosting/Cache.cs: -------------------------------------------------------------------------------- 1 | using Colder.MessageBus.Abstractions; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace Colder.MessageBus.Hosting 7 | { 8 | /// 9 | /// 10 | /// 11 | public static class Cache 12 | { 13 | static Cache() 14 | { 15 | HanlderTypes = MessageBusOptions.Assemblies.SelectMany(x => x.GetTypes()).Where(x => 16 | x.IsClass 17 | && !x.IsAbstract 18 | && x.GetInterfaces().Any(y => 19 | y.IsGenericType && y.GetGenericTypeDefinition() == typeof(IMessageHandler<>)) 20 | ).ToList(); 21 | 22 | MessageTypes = HanlderTypes 23 | .SelectMany(x => x.GetInterfaces()) 24 | .Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IMessageHandler<>)) 25 | .Select(x => x.GetGenericArguments()[0]) 26 | .Distinct() 27 | .ToList(); 28 | 29 | MessageTypes.ForEach(aMessageType => 30 | { 31 | var interfaceType = typeof(IMessageHandler<>).MakeGenericType(aMessageType); 32 | var handlers = HanlderTypes.Where(x => interfaceType.IsAssignableFrom(x)) 33 | .ToArray(); 34 | if (handlers.Length > 1) 35 | { 36 | throw new Exception($"消息{aMessageType.Name}有多个订阅者:{string.Join(",", handlers.Select(x => x.Name))}"); 37 | } 38 | Message2Handler.Add(aMessageType, handlers[0]); 39 | }); 40 | } 41 | 42 | /// 43 | /// 44 | /// 45 | public static readonly List HanlderTypes = new List(); 46 | 47 | /// 48 | /// 49 | /// 50 | public static readonly List MessageTypes = new List(); 51 | 52 | /// 53 | /// 54 | /// 55 | public static readonly Dictionary Message2Handler = new Dictionary(); 56 | } 57 | } -------------------------------------------------------------------------------- /src/Colder.MessageBus.Hosting/Colder.MessageBus.Hosting.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.Hosting/DependencyInjection/MessageBusBootstraper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Hosting; 2 | using System; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | 6 | namespace Colder.MessageBus.Hosting 7 | { 8 | /// 9 | /// 消息总线初始化 10 | /// 11 | public class MessageBusBootstraper : BackgroundService 12 | { 13 | /// 14 | /// 初始化 15 | /// 16 | public static Action Bootstrap; 17 | 18 | private readonly IServiceProvider _serviceProvider; 19 | 20 | /// 21 | /// 构造函数 22 | /// 23 | /// 24 | public MessageBusBootstraper(IServiceProvider serviceProvider) 25 | { 26 | _serviceProvider = serviceProvider; 27 | } 28 | 29 | /// 30 | /// 启动 31 | /// 32 | /// 33 | /// 34 | protected override Task ExecuteAsync(CancellationToken stoppingToken) 35 | { 36 | Bootstrap?.Invoke(_serviceProvider); 37 | 38 | return Task.CompletedTask; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.Hosting/MessageBusFactory.cs: -------------------------------------------------------------------------------- 1 | using Colder.MessageBus.Abstractions; 2 | using System; 3 | using System.Reflection; 4 | 5 | namespace Colder.MessageBus.Hosting 6 | { 7 | internal static class MessageBusFactory 8 | { 9 | public static IMessageBus GetBusInstance(IServiceProvider serviceProvider, MessageBusOptions options) 10 | { 11 | AbstractProvider provider; 12 | 13 | string assemblyName = $"Colder.MessageBus.{options.Transport}"; 14 | try 15 | { 16 | Assembly assembly = Assembly.Load(assemblyName); 17 | 18 | var type = assembly.GetType($"{assemblyName}.{options.Transport}Provider"); 19 | 20 | provider = Activator.CreateInstance(type, new object[] { serviceProvider, options }) as AbstractProvider; 21 | } 22 | catch 23 | { 24 | throw new Exception($"请安装nuget包:{assemblyName}"); 25 | } 26 | 27 | return provider.GetBusInstance(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.Hosting/Primitives/HandlerClass.cs: -------------------------------------------------------------------------------- 1 | using Colder.MessageBus.Abstractions; 2 | using System; 3 | using System.Linq; 4 | 5 | namespace Colder.MessageBus.Hosting.Primitives 6 | { 7 | internal class HandlerClass 8 | { 9 | public HandlerClass(Type hanlderType) 10 | { 11 | HanlderType = hanlderType; 12 | 13 | HandlerMethods = hanlderType.GetMethods().Where(x => 14 | x.Name == "Handle" 15 | && x.GetParameters().Length == 1 16 | && x.GetParameters()[0].ParameterType.IsGenericType 17 | && x.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(MessageContext<>) 18 | ).Select(x => new HandlerMethod(this, x)) 19 | .ToArray(); 20 | } 21 | 22 | public Type HanlderType { get; } 23 | public HandlerMethod[] HandlerMethods { get; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.Hosting/Primitives/HandlerMethod.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | 5 | namespace Colder.MessageBus.Hosting.Primitives 6 | { 7 | internal class HandlerMethod 8 | { 9 | public HandlerMethod(HandlerClass handlerClass, MethodInfo method) 10 | { 11 | HandlerClass = handlerClass; 12 | Method = method; 13 | MessageType = method.GetParameters()[0].ParameterType.GetGenericArguments()[0]; 14 | ChildrenMessageTypes = Assembly.GetEntryAssembly().GetTypes() 15 | .Where(x => MessageType.IsAssignableFrom(x) && x != MessageType) 16 | .ToArray(); 17 | 18 | AllMessageTypes = ChildrenMessageTypes.Concat(new Type[] { MessageType }).ToArray(); 19 | } 20 | public HandlerClass HandlerClass { get; set; } 21 | public MethodInfo Method { get; } 22 | public Type MessageType { get; } 23 | public Type[] ChildrenMessageTypes { get; } 24 | public Type[] AllMessageTypes { get; set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.InMemory/Colder.MessageBus.InMemory.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | true 7 | 8 | 9 | 10 | 11 | 12 | <_Parameter1>Colder.MessageBus.RabbitMQ 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.InMemory/InMemoryProvider.cs: -------------------------------------------------------------------------------- 1 | using Colder.MessageBus.Abstractions; 2 | using MassTransit; 3 | using System; 4 | 5 | namespace Colder.MessageBus.InMemory 6 | { 7 | internal class InMemoryProvider : MassTransitProvider 8 | { 9 | public InMemoryProvider(IServiceProvider serviceProvider, MessageBusOptions options) : base(serviceProvider, options) 10 | { 11 | } 12 | 13 | protected override IBusControl BuildBusControl() 14 | { 15 | return Bus.Factory.CreateUsingInMemory(busFactoryBuilder => 16 | { 17 | ConfigBusFactory(busFactoryBuilder); 18 | 19 | busFactoryBuilder.ReceiveEndpoint(Options.Endpoint, endpointBuilder => 20 | { 21 | //并发数配置 22 | if (Options.Concurrency != 0) 23 | { 24 | endpointBuilder.ConcurrencyLimit = Options.Concurrency; 25 | } 26 | 27 | ConfigEndpoint(endpointBuilder); 28 | }); 29 | }); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.InMemory/MassTransitMessageBus.cs: -------------------------------------------------------------------------------- 1 | using Colder.MessageBus.Abstractions; 2 | using MassTransit; 3 | using System; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace Colder.MessageBus.InMemory 8 | { 9 | internal class MassTransitMessageBus : IMessageBus 10 | { 11 | private readonly IBusControl _busControl; 12 | private readonly MessageBusOptions _options; 13 | public MassTransitMessageBus(IBusControl busControl, MessageBusOptions options) 14 | { 15 | _busControl = busControl; 16 | _options = options; 17 | } 18 | private Uri BuildUri(string endpoint) 19 | { 20 | return new Uri($"{_options.Host}{endpoint}"); 21 | } 22 | 23 | public async Task Publish(TMessage message, string endpoint) where TMessage : class 24 | { 25 | using CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); 26 | cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(_options.SendMessageTimeout)); 27 | 28 | if (string.IsNullOrEmpty(endpoint)) 29 | { 30 | await _busControl.Publish(message, cancellationTokenSource.Token); 31 | } 32 | else 33 | { 34 | var channel = await _busControl.GetSendEndpoint(BuildUri(endpoint)); 35 | 36 | await channel.Send(message, cancellationTokenSource.Token); 37 | } 38 | } 39 | public async Task Request(TRequest message, string endpoint) 40 | where TRequest : class 41 | where TResponse : class 42 | { 43 | var reqTimeout = RequestTimeout.After(0, 0, 0, _options.SendMessageTimeout); 44 | var response = await _busControl.Request(BuildUri(endpoint), message, default, reqTimeout); 45 | 46 | return response.Message; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.InMemory/MassTransitProvider.cs: -------------------------------------------------------------------------------- 1 | using Colder.MessageBus.Abstractions; 2 | using Colder.MessageBus.Hosting; 3 | using GreenPipes; 4 | using MassTransit; 5 | using MassTransit.Context; 6 | using Microsoft.Extensions.Logging; 7 | using System; 8 | using System.Linq; 9 | 10 | namespace Colder.MessageBus.InMemory 11 | { 12 | internal abstract class MassTransitProvider : AbstractProvider 13 | { 14 | protected MassTransitProvider(IServiceProvider serviceProvider, MessageBusOptions options) 15 | : base(serviceProvider, options) 16 | { 17 | } 18 | public override IMessageBus GetBusInstance() 19 | { 20 | LogContext.ConfigureCurrentLogContext(LoggerFactory); 21 | Logger.LogInformation("MessageBus:Use {TransportType} Transport", Options.Transport); 22 | IBusControl busControl = BuildBusControl(); 23 | 24 | busControl.Start(); 25 | Logger.LogInformation($"MessageBus:Started"); 26 | 27 | return new MassTransitMessageBus(busControl, Options); 28 | } 29 | protected abstract IBusControl BuildBusControl(); 30 | protected void ConfigBusFactory(IBusFactoryConfigurator busFactoryConfigurator) 31 | { 32 | busFactoryConfigurator.UseRetry(retryCfg => 33 | { 34 | retryCfg.Interval(Options.RetryCount, TimeSpan.FromMilliseconds(Options.RetryIntervalMilliseconds)); 35 | }); 36 | } 37 | protected void ConfigEndpoint(IReceiveEndpointConfigurator receiveEndpointConfigurator) 38 | { 39 | //绑定消费者 40 | if (Options.Endpoint != Constant.SENDONLY) 41 | { 42 | Cache.MessageTypes.ToList().ForEach(messageType => 43 | { 44 | Logger.LogInformation("MessageBus:Subscribe {MessageType}", messageType); 45 | var delegateType = typeof(MessageHandler<>).MakeGenericType(messageType); 46 | var bindMethod = typeof(ProxyHandler) 47 | .GetMethod("Handle") 48 | .MakeGenericMethod(messageType); 49 | ProxyHandler proxyHandler = new ProxyHandler(ServiceProvider); 50 | var theDelegate = Delegate.CreateDelegate(delegateType, proxyHandler, bindMethod); 51 | var method = typeof(HandlerExtensions).GetMethod("Handler") 52 | .MakeGenericMethod(messageType); 53 | method.Invoke(null, new object[] { receiveEndpointConfigurator, theDelegate, null }); 54 | }); 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.InMemory/ProxyHandler.cs: -------------------------------------------------------------------------------- 1 | using Colder.MessageBus.Abstractions; 2 | using Colder.MessageBus.Hosting; 3 | using MassTransit; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Threading.Tasks; 9 | 10 | namespace Colder.MessageBus.InMemory 11 | { 12 | class ProxyHandler 13 | { 14 | private readonly IServiceProvider _serviceProvider; 15 | public ProxyHandler(IServiceProvider serviceProvider) 16 | { 17 | _serviceProvider = serviceProvider; 18 | } 19 | 20 | public async Task Handle(ConsumeContext context) where T : class 21 | { 22 | using var scop = _serviceProvider.CreateScope(); 23 | 24 | MessageContext msgContext = new MessageContext 25 | { 26 | ServiceProvider = _serviceProvider, 27 | Message = context.Message, 28 | DestinationAddress = context.DestinationAddress, 29 | FaultAddress = context.FaultAddress, 30 | Headers = new Dictionary(context.Headers.GetAll().ToDictionary(x => x.Key, x => x.Value)), 31 | MessageId = context.MessageId, 32 | ResponseAddress = context.ResponseAddress, 33 | SentTime = context.SentTime, 34 | SourceAddress = context.SourceAddress, 35 | SourceMachineName = context.Host.MachineName 36 | }; 37 | 38 | var theHandlerType = Cache.Message2Handler[typeof(T)]; 39 | var handlerInstance = ActivatorUtilities.CreateInstance(scop.ServiceProvider, theHandlerType) as IMessageHandler; 40 | await handlerInstance.Handle(msgContext); 41 | 42 | if (msgContext.Response != null) 43 | { 44 | await context.RespondAsync(msgContext.Response); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.MQTT/Colder.MessageBus.MQTT.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.MQTT/MassTransit/MqttMessageReceivedEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.MessageBus.MQTT 2 | { 3 | internal class MqttMessageReceivedEvent 4 | { 5 | public string Topic { get; set; } 6 | public byte[] Payload { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.MQTT/Primitives/MessageTypes.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.MessageBus.MQTT.Primitives 2 | { 3 | internal enum MessageTypes 4 | { 5 | /// 6 | /// 事件(广播) 7 | /// 8 | Event = 0, 9 | 10 | /// 11 | /// 命令(单播) 12 | /// 13 | Command = 1, 14 | 15 | /// 16 | /// 请求响应 17 | /// 18 | Response = 2 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.MQTT/Primitives/Topic.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | 4 | namespace Colder.MessageBus.MQTT.Primitives 5 | { 6 | internal class Topic 7 | { 8 | //Topic格式 9 | //MQTTMessageBus/{SourceClientId}/{TargetClientId}/{SourceEndpoint}/{TargetEndpoint}/{MessageBodyType}/{MessageType}/{MessageId} 10 | public static readonly string RootTopic = "MQTTMessageBus"; 11 | 12 | public static Topic Parse(string topic) 13 | { 14 | string pattern = $"^{RootTopic}/(.*?)/(.*?)/(.*?)/(.*?)/(.*?)/(.*?)/(.*?)$"; 15 | var match = Regex.Match(topic, pattern); 16 | 17 | Enum.TryParse(match.Groups[6].ToString(), out MessageTypes messageType); 18 | return new Topic 19 | { 20 | SourceClientId = match.Groups[1].ToString(), 21 | TargetClientId = match.Groups[2].ToString(), 22 | SourceEndpoint = match.Groups[3].ToString(), 23 | TargetEndpoint = match.Groups[4].ToString(), 24 | MessageBodyType = match.Groups[5].ToString(), 25 | MessageType = messageType, 26 | MessageId = Guid.Parse(match.Groups[7].ToString()), 27 | }; 28 | } 29 | public string SourceClientId { get; set; } 30 | public string TargetClientId { get; set; } 31 | public string SourceEndpoint { get; set; } 32 | public string TargetEndpoint { get; set; } 33 | public string MessageBodyType { get; set; } 34 | public MessageTypes MessageType { get; set; } 35 | public Guid MessageId { get; set; } 36 | 37 | public override string ToString() 38 | { 39 | return $"{RootTopic}/{SourceClientId}/{TargetClientId}/{SourceEndpoint}/{TargetEndpoint}/{MessageBodyType}/{MessageType}/{MessageId}"; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.MQTT/Primitives/Waiter.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | 3 | namespace Colder.MessageBus.MQTT 4 | { 5 | internal class Waiter 6 | { 7 | public Semaphore Sp { get; set; } 8 | public string ResponseJson { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.MQTT/RequestWaiter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | 4 | namespace Colder.MessageBus.MQTT 5 | { 6 | internal static class RequestWaiter 7 | { 8 | public static ConcurrentDictionary WaitingDic 9 | = new ConcurrentDictionary(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.RabbitMQ/Colder.MessageBus.RabbitMQ.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | netstandard2.0 6 | 消息总线MassTransit实现 7 | 1701;1702;CS8602 8 | 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.RabbitMQ/RabbitMQProvider.cs: -------------------------------------------------------------------------------- 1 | using Colder.MessageBus.Abstractions; 2 | using Colder.MessageBus.InMemory; 3 | using MassTransit; 4 | using System; 5 | 6 | namespace Colder.MessageBus.RabbitMQ 7 | { 8 | internal class RabbitMQProvider : MassTransitProvider 9 | { 10 | public RabbitMQProvider(IServiceProvider serviceProvider, MessageBusOptions options) : base(serviceProvider, options) 11 | { 12 | } 13 | 14 | protected override IBusControl BuildBusControl() 15 | { 16 | return Bus.Factory.CreateUsingRabbitMq(busFactoryBuilder => 17 | { 18 | busFactoryBuilder.Host(Options.Host, config => 19 | { 20 | if (!string.IsNullOrEmpty(Options.Username) && !string.IsNullOrEmpty(Options.Password)) 21 | { 22 | config.Username(Options.Username); 23 | config.Password(Options.Password); 24 | } 25 | }); 26 | 27 | ConfigBusFactory(busFactoryBuilder); 28 | 29 | busFactoryBuilder.ReceiveEndpoint(Options.Endpoint, endpointBuilder => 30 | { 31 | //并发数配置 32 | if (Options.Concurrency != 0) 33 | { 34 | endpointBuilder.PrefetchCount = Options.Concurrency; 35 | } 36 | 37 | ConfigEndpoint(endpointBuilder); 38 | }); 39 | }); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.Redis/Colder.MessageBus.Redis.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.Redis/Primitives/MessageTypes.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.MessageBus.Redis 2 | { 3 | internal enum MessageTypes 4 | { 5 | /// 6 | /// 事件(广播) 7 | /// 8 | Event = 0, 9 | 10 | /// 11 | /// 命令(单播) 12 | /// 13 | Command = 1, 14 | 15 | /// 16 | /// 请求响应 17 | /// 18 | Response = 2 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.Redis/Primitives/Topic.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | 4 | namespace Colder.MessageBus.Redis 5 | { 6 | internal class Topic 7 | { 8 | //Topic格式 9 | //MQTTMessageBus/{SourceClientId}/{TargetClientId}/{SourceEndpoint}/{TargetEndpoint}/{MessageBodyType}/{MessageType}/{MessageId} 10 | public static readonly string RootTopic = "RedisMessageBus"; 11 | 12 | public static Topic Parse(string topic) 13 | { 14 | string pattern = $"^{RootTopic}/(.*?)/(.*?)/(.*?)/(.*?)/(.*?)/(.*?)/(.*?)$"; 15 | var match = Regex.Match(topic, pattern); 16 | 17 | Enum.TryParse(match.Groups[6].ToString(), out MessageTypes messageType); 18 | return new Topic 19 | { 20 | SourceClientId = match.Groups[1].ToString(), 21 | TargetClientId = match.Groups[2].ToString(), 22 | SourceEndpoint = match.Groups[3].ToString(), 23 | TargetEndpoint = match.Groups[4].ToString(), 24 | MessageBodyType = match.Groups[5].ToString(), 25 | MessageType = messageType, 26 | MessageId = Guid.Parse(match.Groups[7].ToString()), 27 | }; 28 | } 29 | public string SourceClientId { get; set; } 30 | public string TargetClientId { get; set; } 31 | public string SourceEndpoint { get; set; } 32 | public string TargetEndpoint { get; set; } 33 | public string MessageBodyType { get; set; } 34 | public MessageTypes MessageType { get; set; } 35 | public Guid MessageId { get; set; } 36 | 37 | public override string ToString() 38 | { 39 | return $"{RootTopic}/{SourceClientId}/{TargetClientId}/{SourceEndpoint}/{TargetEndpoint}/{MessageBodyType}/{MessageType}/{MessageId}"; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Colder.MessageBus.Redis/Primitives/Waiter.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | 3 | namespace Colder.MessageBus.Redis 4 | { 5 | internal class Waiter 6 | { 7 | public Semaphore Sp { get; set; } 8 | public string ResponseJson { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Colder.OpenService.Abstractions/Attributes/RouteAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Colder.OpenService.Abstractions 4 | { 5 | /// 6 | /// 仅支持简单路由,禁用api/[controller]这种高级路由 7 | /// 8 | [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Method, AllowMultiple = false)] 9 | public class RouteAttribute : Attribute 10 | { 11 | /// 12 | /// 沟站函数 13 | /// 14 | /// 路由 15 | public RouteAttribute(string template) 16 | { 17 | Template = template; 18 | } 19 | 20 | /// 21 | /// 路由 22 | /// 23 | public string Template { get; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Colder.OpenService.Abstractions/Colder.OpenService.Abstractions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | true 7 | 8 | 9 | 10 | 11 | <_Parameter1>Colder.OpenService.Hosting 12 | 13 | 14 | <_Parameter1>Colder.OpenService.Client 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Colder.OpenService.Abstractions/ICRUDOpenService.cs: -------------------------------------------------------------------------------- 1 | using Colder.Common; 2 | using System.Threading.Tasks; 3 | 4 | namespace Colder.OpenService.Abstractions 5 | { 6 | /// 7 | /// CRUD通用接口 8 | /// 9 | /// 主键类型 10 | /// InfoDto 11 | /// OutputDto 12 | /// QueryParamsDto 13 | public interface ICRUDOpenService where TQueryParamsDto : new() 14 | { 15 | /// 16 | /// 获取分页列表 17 | /// 18 | /// 参数 19 | /// 20 | [Route("get-pagelist")] 21 | Task> GetList(PageInput input); 22 | 23 | /// 24 | /// 获取列表 25 | /// 26 | /// 参数 27 | /// 28 | [Route("get-list")] 29 | Task GetList(TQueryParamsDto input); 30 | 31 | /// 32 | /// 获取详情 33 | /// 34 | /// 主键Id 35 | /// 36 | [Route("get")] 37 | Task Get(IdInput id); 38 | 39 | /// 40 | /// 添加数据 41 | /// 42 | /// 数据 43 | [Route("create")] 44 | Task Create(TInfoDto data); 45 | 46 | /// 47 | /// 修改数据 48 | /// 49 | /// 数据 50 | /// 51 | [Route("update")] 52 | Task Update(TInfoDto data); 53 | 54 | /// 55 | /// 删除数据 56 | /// 57 | /// 主键列表 58 | /// 59 | [Route("delete")] 60 | Task Delete(params TKey[] ids); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Colder.OpenService.Abstractions/IOpenService.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.OpenService.Abstractions 2 | { 3 | /// 4 | /// OpenService接口标记 5 | /// 6 | public interface IOpenService 7 | { 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Colder.OpenService.Abstractions/Util/Extentions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace Colder.OpenService.Abstractions 5 | { 6 | internal static class Extentions 7 | { 8 | public static bool IsSimpleType(this Type type) 9 | { 10 | return 11 | type.IsPrimitive || 12 | new Type[] 13 | { 14 | typeof(string), 15 | typeof(decimal), 16 | typeof(DateTime), 17 | typeof(DateTimeOffset), 18 | typeof(TimeSpan), 19 | typeof(Guid) 20 | }.Contains(type) || 21 | type.IsEnum || 22 | Convert.GetTypeCode(type) != TypeCode.Object || 23 | (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) && IsSimpleType(type.GetGenericArguments()[0])) 24 | ; 25 | } 26 | 27 | public static bool IsNullOrEmpty(this string str) 28 | { 29 | return string.IsNullOrEmpty(str); 30 | } 31 | 32 | public static bool IsWebApiRPCInterface(this Type type) 33 | { 34 | return typeof(IOpenService).IsAssignableFrom(type) && type.IsInterface && type != typeof(IOpenService); 35 | } 36 | 37 | public static bool IsWebApiRPCImplement(this Type type) 38 | { 39 | return typeof(IOpenService).IsAssignableFrom(type) 40 | && !type.IsAbstract 41 | && !type.IsInterface; 42 | } 43 | 44 | public static string BuildUrl(this string url) 45 | { 46 | while (url.Contains("//")) 47 | { 48 | url = url.Replace("//", "/"); 49 | } 50 | 51 | return url; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Colder.OpenService.Abstractions/Util/Helper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | 5 | namespace Colder.OpenService.Abstractions 6 | { 7 | internal static class Helper 8 | { 9 | public static string GetRoute(Type interfaceType, string methodName, Type[] paramterTypes) 10 | { 11 | var controllerRoute = interfaceType.GetCustomAttribute(); 12 | if (controllerRoute == null) 13 | { 14 | throw new Exception($"{interfaceType.Name}缺少Route"); 15 | } 16 | 17 | var method = GetInterfaceMethod(interfaceType, methodName, paramterTypes); 18 | 19 | var actionRoute = method.GetCustomAttribute(); 20 | if (actionRoute == null || string.IsNullOrEmpty(actionRoute.Template)) 21 | { 22 | throw new Exception($"{method.DeclaringType.Name}.{method.Name}缺少Route"); 23 | } 24 | 25 | string fullRoute = $"{controllerRoute.Template}/{actionRoute.Template}"; 26 | 27 | return fullRoute.BuildUrl(); 28 | } 29 | 30 | public static MethodInfo GetInterfaceMethod(Type interfaceType, string methodName, Type[] paramterTypes) 31 | { 32 | return interfaceType.GetInterfaces().ToList().Concat(new Type[] { interfaceType }) 33 | .Where(x => x.GetMethod(methodName, paramterTypes) != null) 34 | .Select(x => x.GetMethod(methodName, paramterTypes)) 35 | .FirstOrDefault(); 36 | } 37 | 38 | public static bool IsJsonParamter(MethodInfo methodInfo) 39 | { 40 | return methodInfo.GetParameters().Length == 1 41 | && !methodInfo.GetParameters()[0].ParameterType.IsSimpleType(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Colder.OpenService.Client/Colder.OpenService.Client.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | true 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Colder.OpenService.Client/OpenServiceClientExtentions.cs: -------------------------------------------------------------------------------- 1 | using Colder.OpenService.Abstractions; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace Colder.OpenService.Client 7 | { 8 | /// 9 | /// OpenService客户端拓展 10 | /// 11 | public static class OpenServiceClientExtentions 12 | { 13 | /// 14 | /// OpenService服务 15 | /// 16 | /// 容器 17 | /// OpenService服务所在程序集 18 | /// 参数 19 | /// 20 | public static IServiceCollection AddOpenServiceClient(this IServiceCollection services, Assembly assembly, OpenServiceOptions openServiceOption) 21 | { 22 | services.AddTransient(); 23 | 24 | var interfaces = assembly.GetTypes().Where(x => typeof(IOpenService).IsAssignableFrom(x)).ToList(); 25 | 26 | //服务接口注入 27 | interfaces.ForEach(aInterface => 28 | { 29 | services.AddTransient(aInterface, serviceProvider => 30 | { 31 | return serviceProvider.GetService().GetClient(aInterface, openServiceOption); 32 | }); 33 | }); 34 | 35 | return services; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Colder.OpenService.Client/OpenServiceOptions.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.OpenService.Client 2 | { 3 | /// 4 | /// OpenService参数 5 | /// 6 | public class OpenServiceOptions 7 | { 8 | /// 9 | /// 基地址,以/结尾 10 | /// 11 | public string BaseUrl { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Colder.OpenService.Hosting/Colder.OpenService.Hosting.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | true 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Colder.OpenService.Hosting/Constant.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.OpenService.Hosting 2 | { 3 | internal static class Constant 4 | { 5 | public static string RoutePrefix { get; set; } = string.Empty; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Colder.OpenService.Hosting/Filters/RPCResultFilter.cs: -------------------------------------------------------------------------------- 1 | using Colder.Common; 2 | using Colder.OpenService.Abstractions; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Microsoft.AspNetCore.Mvc.Filters; 5 | 6 | namespace Colder.OpenService.Hosting 7 | { 8 | internal class RPCResultFilter : IResultFilter 9 | { 10 | public void OnResultExecuting(ResultExecutingContext context) 11 | { 12 | if (context.Controller is IOpenService) 13 | { 14 | if (context.Result is EmptyResult) 15 | { 16 | Success(null); 17 | 18 | return; 19 | } 20 | else if (context.Result is ObjectResult objectResult) 21 | { 22 | if (objectResult.Value is ApiResult) 23 | { 24 | return; 25 | } 26 | else 27 | { 28 | Success(objectResult.Value); 29 | } 30 | } 31 | } 32 | 33 | void Success(object data) 34 | { 35 | ApiResult res = new ApiResult 36 | { 37 | Data = data 38 | }; 39 | 40 | context.Result = new ObjectResult(res); 41 | } 42 | } 43 | 44 | public void OnResultExecuted(ResultExecutedContext context) 45 | { 46 | 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Colder.OpenService.Hosting/OpenServiceBase.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | 3 | namespace Colder.OpenService.Hosting 4 | { 5 | /// 6 | /// OpenService服务基类,具体服务实现必须继承此类 7 | /// 8 | [Route("")] 9 | [ApiController] 10 | public class OpenServiceBase : ControllerBase 11 | { 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Colder.OpenService.Hosting/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:53328/", 7 | "sslPort": 44340 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "Colder.OpenService.Hosting": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "environmentVariables": { 22 | "ASPNETCORE_ENVIRONMENT": "Development" 23 | }, 24 | "applicationUrl": "https://localhost:5001;http://localhost:5000" 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/Colder.OpenService.Hosting/WebApiRPCProvider.cs: -------------------------------------------------------------------------------- 1 | using Colder.OpenService.Abstractions; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.AspNetCore.Mvc.Controllers; 4 | using System.Reflection; 5 | 6 | namespace Colder.OpenService.Hosting 7 | { 8 | internal class WebApiRPCProvider : ControllerFeatureProvider 9 | { 10 | protected override bool IsController(TypeInfo typeInfo) 11 | { 12 | return (typeof(IOpenService).IsAssignableFrom(typeInfo) 13 | || typeof(ControllerBase).IsAssignableFrom(typeInfo)) 14 | && !typeInfo.IsAbstract 15 | && !typeInfo.IsInterface; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Colder.Orleans.Hosting/Colder.Orleans.Hosting.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Colder.Orleans.Hosting/Options/OrleansOptions.cs: -------------------------------------------------------------------------------- 1 | using Colder.Common; 2 | using Orleans.Configuration; 3 | using System.Reflection; 4 | 5 | namespace Colder.Orleans.Hosting 6 | { 7 | /// 8 | /// Orelans参数 9 | /// 10 | public class OrleansOptions 11 | { 12 | private static readonly string _entryAssemblyName = Assembly.GetEntryAssembly().GetName().Name; 13 | 14 | /// 15 | /// 提供类型 16 | /// 17 | public ProviderTypes Provider { get; set; } = ProviderTypes.InMemory; 18 | 19 | /// 20 | /// AdoNet提供器 21 | /// 22 | public string AdoNetInvariant { get; set; } 23 | 24 | /// 25 | /// AdoNet链接字符串 26 | /// 27 | public string AdoNetConString { get; set; } 28 | 29 | private string _clusterId; 30 | /// 31 | /// 集群Id,默认入口程序集名 32 | /// 33 | public string ClusterId { get => string.IsNullOrEmpty(_clusterId) ? _entryAssemblyName : _clusterId; set => _clusterId = value; } 34 | 35 | private string _serviceId; 36 | /// 37 | /// 服务Id,默认入口程序集名 38 | /// 39 | public string ServiceId { get => string.IsNullOrEmpty(_serviceId) ? _entryAssemblyName : _serviceId; set => _serviceId = value; } 40 | 41 | private string _ip; 42 | /// 43 | /// 本机Ip,默认自动扫描获取本机Ip 44 | /// 45 | public string Ip { get => string.IsNullOrEmpty(_ip) ? IpHelper.GetLocalIp() : _ip; set => _ip = value; } 46 | 47 | /// 48 | /// Silo端口 49 | /// 50 | public int Port { get; set; } = EndpointOptions.DEFAULT_SILO_PORT; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Colder.Orleans.Hosting/Options/ProviderTypes.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.Orleans.Hosting 2 | { 3 | /// 4 | /// Orleans提供器类型 5 | /// 6 | public enum ProviderTypes 7 | { 8 | /// 9 | /// 本地内存集群 10 | /// 11 | InMemory = 0, 12 | 13 | /// 14 | /// 使用AdoNet数据库集群 15 | /// 16 | AdoNet = 1 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Colder.Pdf/Colder.Pdf.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | true 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Colder.Pdf/PdfHelper.cs: -------------------------------------------------------------------------------- 1 | using PDFiumSharp; 2 | using SixLabors.ImageSharp; 3 | using SixLabors.ImageSharp.Formats.Jpeg; 4 | using SixLabors.ImageSharp.Processing; 5 | using System.IO; 6 | 7 | namespace Colder.Pdf; 8 | 9 | /// 10 | /// 11 | /// 12 | public static class PdfHelper 13 | { 14 | /// 15 | /// pdf转jpg图片 16 | /// 17 | /// 18 | /// 19 | /// 20 | /// 21 | public static byte[] Pdf2Jpg(byte[] pdfBytes, int width = 1280, int height = 850) 22 | { 23 | using var pdfDocument = new PdfDocument(pdfBytes); 24 | var firstPage = pdfDocument.Pages[0]; 25 | 26 | using var pageBitmap = new PDFiumBitmap(width, height, true); 27 | 28 | firstPage.Render(pageBitmap); 29 | 30 | var image = Image.Load(pageBitmap.AsBmpStream()); 31 | 32 | // Set the background to white, otherwise it's black. https://github.com/SixLabors/ImageSharp/issues/355#issuecomment-333133991 33 | image.Mutate(x => x.BackgroundColor(Color.White)); 34 | 35 | using var ms = new MemoryStream(); 36 | image.Save(ms, new JpegEncoder()); 37 | 38 | return ms.ToArray(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Colder.WebSockets.Abstractions/Colder.WebSockets.Abstractions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | true 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Colder.WebSockets.Abstractions/IWebSocketConnection.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace Colder.WebSockets.Abstractions 4 | { 5 | /// 6 | /// WebSocket连接 7 | /// 8 | public interface IWebSocketConnection 9 | { 10 | /// 11 | /// 唯一Id 12 | /// 13 | string Id { get; set; } 14 | 15 | /// 16 | /// 发送消息 17 | /// 18 | /// 消息 19 | /// 20 | Task Send(string msg); 21 | 22 | /// 23 | /// 关闭连接 24 | /// 25 | /// 26 | Task Close(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Colder.WebSockets.Abstractions/IWebSocketServer.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.WebSockets.Abstractions 2 | { 3 | /// 4 | /// WebSocket服务端 5 | /// 6 | public interface IWebSocketServer 7 | { 8 | /// 9 | /// 通过id获取连接 10 | /// 11 | /// 12 | /// 13 | IWebSocketConnection GetConnection(string id); 14 | 15 | /// 16 | /// 获取所有连接 17 | /// 18 | /// 19 | IWebSocketConnection[] GetAllConnections(); 20 | 21 | /// 22 | /// 连接数 23 | /// 24 | public int ConnectionCount { get; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Colder.WebSockets.Abstractions/WebSocketServerOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace Colder.WebSockets.Abstractions 5 | { 6 | /// 7 | /// SocketServer选项 8 | /// 9 | public class WebSocketServerOptions 10 | { 11 | /// 12 | /// 已收到新连接事件,参数依次为:容器、当前连接、消息 13 | /// 14 | public Func OnConnected { get; set; } 15 | 16 | /// 17 | /// 已收到数据事件,参数依次为:容器、当前连接、消息 18 | /// 19 | public Func OnReceive { get; set; } 20 | 21 | /// 22 | /// 已发送数据事件,参数依次为:容器、当前连接、消息 23 | /// 24 | public Func OnSend { get; set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Colder.WebSockets.Server/Colder.WebSockets.Server.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net5.0;net6.0 5 | 6 | true 7 | NETSDK1138 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Colder.WebSockets.Server/MessageReceivedEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Colder.WebSockets.Server 2 | { 3 | internal class MessageReceivedEvent 4 | { 5 | public string ConnectionId { get; set; } 6 | public string Body { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Colder.WebSockets.Server/WebSocketConnection.cs: -------------------------------------------------------------------------------- 1 | using Colder.WebSockets.Abstractions; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Options; 4 | using System; 5 | using System.Net.WebSockets; 6 | using System.Text; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace Colder.WebSockets.Server 11 | { 12 | internal class WebSocketConnection : IWebSocketConnection, IDisposable 13 | { 14 | private readonly WebSocketServerOptions _webSocketServerOption; 15 | private readonly IServiceProvider _serviceProvider; 16 | private readonly WebSocketServer _webSocketServer; 17 | public WebSocketConnection(WebSocketServer webSocketServer, WebSocket webSocket, string id, IServiceProvider serviceProvider) 18 | { 19 | _webSocketServer = webSocketServer; 20 | WebSocket = webSocket; 21 | Id = id; 22 | _serviceProvider = serviceProvider; 23 | _webSocketServerOption = serviceProvider.GetService>().Value; 24 | } 25 | public readonly WebSocket WebSocket; 26 | public string Id { get; set; } 27 | 28 | public async Task Close() 29 | { 30 | await WebSocket.CloseAsync(WebSocketCloseStatus.Empty, string.Empty, CancellationToken.None); 31 | WebSocket.Dispose(); 32 | _webSocketServer.RemoveConnection(this); 33 | } 34 | 35 | public async Task Send(string msg) 36 | { 37 | await WebSocket.SendAsync(new ArraySegment(Encoding.UTF8.GetBytes(msg)), WebSocketMessageType.Text, true, CancellationToken.None); 38 | if (_webSocketServerOption.OnSend != null) 39 | { 40 | await _webSocketServerOption.OnSend(_serviceProvider, this, msg); 41 | } 42 | } 43 | 44 | public void Dispose() 45 | { 46 | ((IDisposable)WebSocket).Dispose(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Colder.WebSockets.Server/WebSocketServer.cs: -------------------------------------------------------------------------------- 1 | using Colder.WebSockets.Abstractions; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net.WebSockets; 5 | using System.Threading; 6 | 7 | namespace Colder.WebSockets.Server 8 | { 9 | internal class WebSocketServer : IWebSocketServer 10 | { 11 | private readonly SynchronizedCollection _connections = new SynchronizedCollection(); 12 | private readonly ReaderWriterLockSlim _readerWriterLockSlim = new ReaderWriterLockSlim(); 13 | public IWebSocketConnection[] GetAllConnections() 14 | { 15 | try 16 | { 17 | _readerWriterLockSlim.EnterReadLock(); 18 | return _connections.ToArray(); 19 | } 20 | finally 21 | { 22 | _readerWriterLockSlim.ExitReadLock(); 23 | } 24 | } 25 | public void AddConnection(WebSocketConnection connection) 26 | { 27 | try 28 | { 29 | _readerWriterLockSlim.EnterWriteLock(); 30 | _connections.Add(connection); 31 | } 32 | finally 33 | { 34 | _readerWriterLockSlim.ExitWriteLock(); 35 | } 36 | } 37 | public void RemoveConnection(WebSocketConnection connection) 38 | { 39 | try 40 | { 41 | _readerWriterLockSlim.EnterWriteLock(); 42 | _connections.Remove(connection); 43 | } 44 | finally 45 | { 46 | _readerWriterLockSlim.ExitWriteLock(); 47 | } 48 | } 49 | public IWebSocketConnection GetConnection(string id) 50 | { 51 | try 52 | { 53 | _readerWriterLockSlim.EnterReadLock(); 54 | return _connections.Where(x => x.Id == id).FirstOrDefault(); 55 | } 56 | finally 57 | { 58 | _readerWriterLockSlim.ExitReadLock(); 59 | } 60 | } 61 | public IWebSocketConnection GetConnection(WebSocket webSocket) 62 | { 63 | try 64 | { 65 | _readerWriterLockSlim.EnterReadLock(); 66 | return _connections.Where(x => x.WebSocket == webSocket).FirstOrDefault(); 67 | } 68 | finally 69 | { 70 | _readerWriterLockSlim.ExitReadLock(); 71 | } 72 | } 73 | public int ConnectionCount => _connections.Count; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tests/Colder.Tests/Colder.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(DemoNetVersion) 5 | 6 | false 7 | 1701;1702;CS1591 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | all 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/Colder.Tests/InMemoryDistributedLockTest.cs: -------------------------------------------------------------------------------- 1 | using Colder.DistributedLock.Abstractions; 2 | using Colder.DistributedLock.Hosting; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Threading.Tasks; 8 | 9 | namespace Colder.Tests 10 | { 11 | [TestClass] 12 | public class InMemoryDistributedLockTest 13 | { 14 | static InMemoryDistributedLockTest() 15 | { 16 | IServiceCollection services = new ServiceCollection(); 17 | services.AddDistributedLock(x => 18 | { 19 | x.LockType = LockTypes.InMemory; 20 | }); 21 | 22 | _serviceProvider = services.BuildServiceProvider(); 23 | } 24 | private static readonly IServiceProvider _serviceProvider; 25 | 26 | [TestMethod] 27 | public async Task Test() 28 | { 29 | var theLock = _serviceProvider.GetService(); 30 | string key = Guid.NewGuid().ToString(); 31 | 32 | List> tasks = new List>(); 33 | 34 | int num = 0; 35 | for (int i = 0; i < 16; i++) 36 | { 37 | tasks.Add(Task.Factory.StartNew(async () => 38 | { 39 | for (int j = 0; j < 10000; j++) 40 | { 41 | using var _ = await theLock.Lock(key); 42 | num++; 43 | } 44 | }, TaskCreationOptions.LongRunning)); 45 | } 46 | 47 | foreach (var aTask in tasks) 48 | { 49 | await (await aTask); 50 | } 51 | 52 | Assert.AreEqual(num, 160000); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /tests/Colder.Tests/RedisDistributedLockTest.cs: -------------------------------------------------------------------------------- 1 | using Colder.DistributedLock.Abstractions; 2 | using Colder.DistributedLock.Hosting; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Threading.Tasks; 8 | 9 | namespace Colder.Tests 10 | { 11 | [TestClass] 12 | public class RedisDistributedLockTest 13 | { 14 | static RedisDistributedLockTest() 15 | { 16 | IServiceCollection services = new ServiceCollection(); 17 | services.AddDistributedLock(x => 18 | { 19 | x.LockType = LockTypes.Redis; 20 | x.RedisEndPoints = new string[] { "localhost:6379" }; 21 | }); 22 | 23 | _serviceProvider = services.BuildServiceProvider(); 24 | } 25 | private static readonly IServiceProvider _serviceProvider; 26 | 27 | [TestMethod] 28 | public async Task Test() 29 | { 30 | var theLock = _serviceProvider.GetService(); 31 | string key = Guid.NewGuid().ToString(); 32 | 33 | List tasks = new List(); 34 | int num = 0; 35 | for (int i = 0; i < 4; i++) 36 | { 37 | tasks.Add(Task.Run(async () => 38 | { 39 | for (int j = 0; j < 1000; j++) 40 | { 41 | using var _ = await theLock.Lock(key); 42 | num++; 43 | } 44 | })); 45 | } 46 | 47 | await Task.WhenAll(tasks); 48 | 49 | Assert.AreEqual(num, 4000); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "version": "1.3", 4 | "publicReleaseRefSpec": [ 5 | "^refs/heads/master$", 6 | "^refs/heads/main$", 7 | "^refs/heads/v\\d+(?:\\.\\d+)?$" 8 | ] 9 | } --------------------------------------------------------------------------------