From bfd4fd8e4a05a681ec10a47992294cf752a764c4 Mon Sep 17 00:00:00 2001
From: wanshenmean <cathay_xy@163.com>
Date: 星期一, 02 三月 2026 15:10:58 +0800
Subject: [PATCH] 添加Redis服务与缓存增强
---
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Bitmap/RedisBitmapService.cs | 46
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Lock/IDistributedLockService.cs | 34
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Cache/RedisCacheService.cs | 174 ++
Code/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v18/DocumentLayout.json | 191 ++
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Leaderboard/RedisLeaderboardService.cs | 75 +
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Bitmap/RedisBloomFilterService.cs | 96 +
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Session/ISessionStorage.cs | 12
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/RateLimiting/RedisRateLimitingService.cs | 113 +
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Geo/RedisGeoLocationService.cs | 65
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Configuration/RedisConfigurationCenterService.cs | 65
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Configuration/IConfigurationCenterService.cs | 30
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/appsettings.json | 47
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Monitoring/IRedisMonitorService.cs | 39
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Serialization/NewtonsoftRedisSerializer.cs | 31
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/DelayQueue/RedisDelayQueueService.cs | 60
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Geo/IGeoLocationService.cs | 43
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Session/RedisSessionStorage.cs | 63
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/PubSub/RedisMessageQueueService.cs | 64
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Connection/IRedisConnectionManager.cs | 17
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs | 39
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server.csproj | 5
Code/WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/v18/DocumentLayout.backup.json | 149 +
Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs | 11
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/ICacheService.cs | 49
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/IdGenerator/RedisDistributedIdGenerator.cs | 56
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/WIDESEAWCS_RedisService.csproj | 21
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLine/CheckPalletPosition.cs | 9
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/MemoryCacheService.cs | 75 +
Code/WMS/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs | 7
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Stream/RedisStreamProcessingService.cs | 76 +
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/IdGenerator/IDistributedIdGenerator.cs | 25
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Extensions/RedisServiceSetup.cs | 77 +
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Serialization/IRedisSerializer.cs | 11
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Http/HTTP/HttpClientHelper.cs | 6
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/PubSub/IMessageQueueService.cs | 35
Code/WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/v18/DocumentLayout.json | 134 +
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Lock/RedisDistributedLockService.cs | 112 +
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Options/RedisOptions.cs | 49
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Connection/RedisConnectionManager.cs | 111 +
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs | 47
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Counter/RedisCounterService.cs | 57
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Cache/HybridCacheService.cs | 266 ++++
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Leaderboard/ILeaderboardService.cs | 52
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Counter/ICounterService.cs | 30
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/RateLimiting/IRateLimitingService.cs | 25
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Bitmap/IBitmapService.cs | 28
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/DelayQueue/IDelayQueueService.cs | 25
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Program.cs | 44
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotJob.cs | 149 +-
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Storage/RedisObjectStorageService.cs | 71 +
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Monitoring/RedisMonitorService.cs | 91 +
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Storage/IObjectStorageService.cs | 40
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server.sln | 178 ++
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Redis使用案例.md | 380 +++++
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Stream/IStreamProcessingService.cs | 41
Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/StockEnum/StockStatusEmun.cs | 3
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/RouterService.cs | 78
57 files changed, 3,668 insertions(+), 259 deletions(-)
diff --git a/Code/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v18/DocumentLayout.json b/Code/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v18/DocumentLayout.json
index e593f80..1b17578 100644
--- a/Code/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v18/DocumentLayout.json
+++ b/Code/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v18/DocumentLayout.json
@@ -5,6 +5,50 @@
{
"AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\robotjob\\robotjob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\robotjob\\robotjob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\socketserver\\tcpsocketserver.clients.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\socketserver\\tcpsocketserver.clients.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{F9886971-C3B2-4334-B014-D5109F2041DE}|WIDESEAWCS_RedisService\\WIDESEAWCS_RedisService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_redisservice\\cache\\hybridcacheservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{F9886971-C3B2-4334-B014-D5109F2041DE}|WIDESEAWCS_RedisService\\WIDESEAWCS_RedisService.csproj|solutionrelative:wideseawcs_redisservice\\cache\\hybridcacheservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{F9886971-C3B2-4334-B014-D5109F2041DE}|WIDESEAWCS_RedisService\\WIDESEAWCS_RedisService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_redisservice\\connection\\redisconnectionmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{F9886971-C3B2-4334-B014-D5109F2041DE}|WIDESEAWCS_RedisService\\WIDESEAWCS_RedisService.csproj|solutionrelative:wideseawcs_redisservice\\connection\\redisconnectionmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_server\\appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}",
+ "RelativeMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|solutionrelative:wideseawcs_server\\appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{F9886971-C3B2-4334-B014-D5109F2041DE}|WIDESEAWCS_RedisService\\WIDESEAWCS_RedisService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_redisservice\\extensions\\redisservicesetup.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{F9886971-C3B2-4334-B014-D5109F2041DE}|WIDESEAWCS_RedisService\\WIDESEAWCS_RedisService.csproj|solutionrelative:wideseawcs_redisservice\\extensions\\redisservicesetup.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{F9886971-C3B2-4334-B014-D5109F2041DE}|WIDESEAWCS_RedisService\\WIDESEAWCS_RedisService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_redisservice\\cache\\rediscacheservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{F9886971-C3B2-4334-B014-D5109F2041DE}|WIDESEAWCS_RedisService\\WIDESEAWCS_RedisService.csproj|solutionrelative:wideseawcs_redisservice\\cache\\rediscacheservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_server\\redis\u4F7F\u7528\u6848\u4F8B.md||{EFC0BB08-EA7D-40C6-A696-C870411A895B}",
+ "RelativeMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|solutionrelative:wideseawcs_server\\redis\u4F7F\u7528\u6848\u4F8B.md||{EFC0BB08-EA7D-40C6-A696-C870411A895B}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_server\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|solutionrelative:wideseawcs_server\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}|WIDESEAWCS_Core\\WIDESEAWCS_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_core\\http\\http\\httpclienthelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}|WIDESEAWCS_Core\\WIDESEAWCS_Core.csproj|solutionrelative:wideseawcs_core\\http\\http\\httpclienthelper.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\conveyorlinenewjob\\conveyorline\\checkpalletposition.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\conveyorlinenewjob\\conveyorline\\checkpalletposition.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|d:\\git\\shanmeixinnengyuan\\code\\wcs\\wideseawcs_server\\wideseawcs_tasks\\conveyorlinenewjob\\commonconveyorlinenewjob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\conveyorlinenewjob\\commonconveyorlinenewjob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"DocumentGroupContainers": [
@@ -14,7 +58,7 @@
"DocumentGroups": [
{
"DockedWidth": 200,
- "SelectedChildIndex": 3,
+ "SelectedChildIndex": 14,
"Children": [
{
"$type": "Bookmark",
@@ -30,13 +74,156 @@
},
{
"$type": "Document",
+ "DocumentIndex": 1,
+ "Title": "TcpSocketServer.Clients.cs",
+ "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Clients.cs",
+ "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Clients.cs",
+ "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Clients.cs",
+ "RelativeToolTip": "WIDESEAWCS_Tasks\\SocketServer\\TcpSocketServer.Clients.cs",
+ "ViewState": "AgIAAEkAAAAAAAAAAAAIwAkAAAAZAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-03-02T04:08:38.428Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 3,
+ "Title": "RedisConnectionManager.cs",
+ "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Connection\\RedisConnectionManager.cs",
+ "RelativeDocumentMoniker": "WIDESEAWCS_RedisService\\Connection\\RedisConnectionManager.cs",
+ "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Connection\\RedisConnectionManager.cs",
+ "RelativeToolTip": "WIDESEAWCS_RedisService\\Connection\\RedisConnectionManager.cs",
+ "ViewState": "AgIAAD0AAAAAAAAAAAAuwE8AAAAIAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-03-02T03:52:53.567Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 2,
+ "Title": "HybridCacheService.cs",
+ "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Cache\\HybridCacheService.cs",
+ "RelativeDocumentMoniker": "WIDESEAWCS_RedisService\\Cache\\HybridCacheService.cs",
+ "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Cache\\HybridCacheService.cs",
+ "RelativeToolTip": "WIDESEAWCS_RedisService\\Cache\\HybridCacheService.cs",
+ "ViewState": "AgIAAOkAAAAAAAAAAAAqwPoAAAAjAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-03-02T03:39:18.734Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 5,
+ "Title": "RedisServiceSetup.cs",
+ "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Extensions\\RedisServiceSetup.cs",
+ "RelativeDocumentMoniker": "WIDESEAWCS_RedisService\\Extensions\\RedisServiceSetup.cs",
+ "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Extensions\\RedisServiceSetup.cs",
+ "RelativeToolTip": "WIDESEAWCS_RedisService\\Extensions\\RedisServiceSetup.cs",
+ "ViewState": "AgIAADgAAAAAAAAAAAAmwCIAAAAMAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-03-02T03:33:54.548Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 8,
+ "Title": "Program.cs",
+ "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Program.cs",
+ "RelativeDocumentMoniker": "WIDESEAWCS_Server\\Program.cs",
+ "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Program.cs",
+ "RelativeToolTip": "WIDESEAWCS_Server\\Program.cs",
+ "ViewState": "AgIAACQAAAAAAAAAAAAqwDYAAAAeAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-03-02T03:16:21.765Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 6,
+ "Title": "RedisCacheService.cs",
+ "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Cache\\RedisCacheService.cs",
+ "RelativeDocumentMoniker": "WIDESEAWCS_RedisService\\Cache\\RedisCacheService.cs",
+ "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_RedisService\\Cache\\RedisCacheService.cs",
+ "RelativeToolTip": "WIDESEAWCS_RedisService\\Cache\\RedisCacheService.cs",
+ "ViewState": "AgIAABoAAAAAAAAAAAAmwCkAAAAoAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-03-02T03:06:06.952Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 7,
+ "Title": "Redis\u4F7F\u7528\u6848\u4F8B.md",
+ "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Redis\u4F7F\u7528\u6848\u4F8B.md",
+ "RelativeDocumentMoniker": "WIDESEAWCS_Server\\Redis\u4F7F\u7528\u6848\u4F8B.md",
+ "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Redis\u4F7F\u7528\u6848\u4F8B.md",
+ "RelativeToolTip": "WIDESEAWCS_Server\\Redis\u4F7F\u7528\u6848\u4F8B.md",
+ "ViewState": "AgIAAAgBAAAAAAAAAAAAABcBAAAPAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001818|",
+ "WhenOpened": "2026-03-02T02:59:29.028Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 9,
+ "Title": "HttpClientHelper.cs",
+ "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Core\\Http\\HTTP\\HttpClientHelper.cs",
+ "RelativeDocumentMoniker": "WIDESEAWCS_Core\\Http\\HTTP\\HttpClientHelper.cs",
+ "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Core\\Http\\HTTP\\HttpClientHelper.cs",
+ "RelativeToolTip": "WIDESEAWCS_Core\\Http\\HTTP\\HttpClientHelper.cs",
+ "ViewState": "AgIAABQAAAAAAAAAAADwvygAAABLAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-03-02T02:58:50.075Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 10,
+ "Title": "CheckPalletPosition.cs",
+ "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\ConveyorLineNewJob\\ConveyorLine\\CheckPalletPosition.cs",
+ "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\ConveyorLineNewJob\\ConveyorLine\\CheckPalletPosition.cs",
+ "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\ConveyorLineNewJob\\ConveyorLine\\CheckPalletPosition.cs",
+ "RelativeToolTip": "WIDESEAWCS_Tasks\\ConveyorLineNewJob\\ConveyorLine\\CheckPalletPosition.cs",
+ "ViewState": "AgIAAAAAAAAAAAAAAAAAAAYAAAAeAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-02-28T08:42:47.236Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 4,
+ "Title": "appsettings.json",
+ "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\appsettings.json",
+ "RelativeDocumentMoniker": "WIDESEAWCS_Server\\appsettings.json",
+ "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\appsettings.json",
+ "RelativeToolTip": "WIDESEAWCS_Server\\appsettings.json",
+ "ViewState": "AgIAACUAAAAAAAAAAAAYwCsAAAAeAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|",
+ "WhenOpened": "2026-02-28T05:50:10.851Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 11,
+ "Title": "CommonConveyorLineNewJob.cs",
+ "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\ConveyorLineNewJob\\CommonConveyorLineNewJob.cs",
+ "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\ConveyorLineNewJob\\CommonConveyorLineNewJob.cs",
+ "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\ConveyorLineNewJob\\CommonConveyorLineNewJob.cs",
+ "RelativeToolTip": "WIDESEAWCS_Tasks\\ConveyorLineNewJob\\CommonConveyorLineNewJob.cs",
+ "ViewState": "AgIAAEoAAAAAAAAAAAAAwGAAAABTAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-02-28T05:48:06.526Z",
+ "EditorCaption": ""
+ },
+ {
+ "$type": "Document",
"DocumentIndex": 0,
"Title": "RobotJob.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\RobotJob\\RobotJob.cs",
"RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\RobotJob\\RobotJob.cs",
"ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\RobotJob\\RobotJob.cs",
"RelativeToolTip": "WIDESEAWCS_Tasks\\RobotJob\\RobotJob.cs",
- "ViewState": "AgIAAAEAAAAAAAAAAAAuwBoAAAAAAAAAAAAAAA==",
+ "ViewState": "AgIAADgAAAAAAAAAAAAtwEIAAAAPAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-05T05:38:04.031Z",
"EditorCaption": ""
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/ICacheService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/ICacheService.cs
index 2c076d7..d733532 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/ICacheService.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/ICacheService.cs
@@ -60,5 +60,54 @@
/// <param name="key">缂撳瓨Key</param>
/// <returns></returns>
string? Get(string key);
+
+ #region ConcurrentDictionary椋庢牸鏂规硶
+
+ /// <summary>
+ /// 灏濊瘯娣诲姞锛屼粎褰揔ey涓嶅瓨鍦ㄦ椂娣诲姞鎴愬姛
+ /// </summary>
+ bool TryAdd(string key, string value, int expireSeconds = -1);
+
+ /// <summary>
+ /// 灏濊瘯娣诲姞瀵硅薄锛屼粎褰揔ey涓嶅瓨鍦ㄦ椂娣诲姞鎴愬姛
+ /// </summary>
+ bool TryAdd<T>(string key, T value, int expireSeconds = -1) where T : class;
+
+ /// <summary>
+ /// 灏濊瘯鑾峰彇鍊硷紝杩斿洖鏄惁瀛樺湪
+ /// </summary>
+ bool TryGetValue(string key, out string? value);
+
+ /// <summary>
+ /// 灏濊瘯鑾峰彇瀵硅薄锛岃繑鍥炴槸鍚﹀瓨鍦�
+ /// </summary>
+ bool TryGetValue<T>(string key, out T? value) where T : class;
+
+ /// <summary>
+ /// 灏濊瘯绉婚櫎骞惰繑鍥炶绉婚櫎鐨勫��
+ /// </summary>
+ bool TryRemove(string key, out string? value);
+
+ /// <summary>
+ /// 灏濊瘯鏇存柊锛屼粎褰揔ey瀛樺湪鏃舵洿鏂�
+ /// </summary>
+ bool TryUpdate(string key, string newValue, int expireSeconds = -1);
+
+ /// <summary>
+ /// 鑾峰彇鎴栨坊鍔狅細Key瀛樺湪鍒欒繑鍥炵幇鏈夊�硷紝涓嶅瓨鍦ㄥ垯娣诲姞骞惰繑鍥炴柊鍊�
+ /// </summary>
+ string GetOrAdd(string key, string value, int expireSeconds = -1);
+
+ /// <summary>
+ /// 鑾峰彇鎴栨坊鍔狅紙宸ュ巶鏂规硶锛夛細Key瀛樺湪鍒欒繑鍥炵幇鏈夊�硷紝涓嶅瓨鍦ㄥ垯閫氳繃宸ュ巶鏂规硶鐢熸垚鍊煎苟娣诲姞
+ /// </summary>
+ string GetOrAdd(string key, Func<string, string> valueFactory, int expireSeconds = -1);
+
+ /// <summary>
+ /// 鑾峰彇鎴栨坊鍔犲璞�
+ /// </summary>
+ T GetOrAdd<T>(string key, Func<string, T> valueFactory, int expireSeconds = -1) where T : class;
+
+ #endregion
}
}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/MemoryCacheService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/MemoryCacheService.cs
index ce7a585..5f6d4ef 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/MemoryCacheService.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/MemoryCacheService.cs
@@ -144,5 +144,80 @@
keys.ToList().ForEach(item => _cache.Remove(item));
}
+
+ public bool TryAdd(string key, string value, int expireSeconds = -1)
+ {
+ if (Exists(key)) return false;
+ return Add(key, value, expireSeconds);
+ }
+
+ public bool TryAdd<T>(string key, T value, int expireSeconds = -1) where T : class
+ {
+ if (Exists(key)) return false;
+ return AddObject(key, value, expireSeconds);
+ }
+
+ public bool TryGetValue(string key, out string? value)
+ {
+ value = _cache.Get(key)?.ToString();
+ return value != null;
+ }
+
+ public bool TryGetValue<T>(string key, out T? value) where T : class
+ {
+ if (_cache.TryGetValue(key, out object? obj) && obj != null)
+ {
+ value = obj as T ?? JsonConvert.DeserializeObject<T>(obj.ToString() ?? "");
+ return value != null;
+ }
+ value = default;
+ return false;
+ }
+
+ public bool TryRemove(string key, out string? value)
+ {
+ value = _cache.Get(key)?.ToString();
+ if (value == null) return false;
+ _cache.Remove(key);
+ return true;
+ }
+
+ public bool TryUpdate(string key, string newValue, int expireSeconds = -1)
+ {
+ if (!Exists(key)) return false;
+ Remove(key);
+ Add(key, newValue, expireSeconds);
+ return true;
+ }
+
+ public string GetOrAdd(string key, string value, int expireSeconds = -1)
+ {
+ var existing = _cache.Get(key)?.ToString();
+ if (existing != null) return existing;
+ Add(key, value, expireSeconds);
+ return value;
+ }
+
+ public string GetOrAdd(string key, Func<string, string> valueFactory, int expireSeconds = -1)
+ {
+ var existing = _cache.Get(key)?.ToString();
+ if (existing != null) return existing;
+ var value = valueFactory(key);
+ Add(key, value, expireSeconds);
+ return value;
+ }
+
+ public T GetOrAdd<T>(string key, Func<string, T> valueFactory, int expireSeconds = -1) where T : class
+ {
+ if (_cache.TryGetValue(key, out object? obj) && obj != null)
+ {
+ if (obj is T t) return t;
+ var deserialized = JsonConvert.DeserializeObject<T>(obj.ToString() ?? "");
+ if (deserialized != null) return deserialized;
+ }
+ var value = valueFactory(key);
+ AddObject(key, value, expireSeconds);
+ return value;
+ }
}
}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Http/HTTP/HttpClientHelper.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Http/HTTP/HttpClientHelper.cs
index fc0cd5b..4b08204 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Http/HTTP/HttpClientHelper.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Http/HTTP/HttpClientHelper.cs
@@ -10,16 +10,19 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
+using WIDESEAWCS_Core.Caches;
namespace WIDESEA_Core
{
public class HttpClientHelper
{
private readonly IHttpClientFactory _httpClientFactory;
+ private readonly ICacheService _cache;
- public HttpClientHelper(IHttpClientFactory httpClientFactory, IConfiguration configuration = null)
+ public HttpClientHelper(IHttpClientFactory httpClientFactory, ICacheService cache, IConfiguration configuration = null)
{
_httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
+ _cache = cache ?? throw new ArgumentNullException(nameof(cache));
}
/// <summary>
@@ -32,6 +35,7 @@
/// <returns></returns>
public HttpResponseResult Post(string url, string content, string contentType = "application/json", HttpRequestConfig? config = null)
{
+ url = _cache.Get(url);
HttpResponseResult httpResponseResult = ExecuteAsync(async (client) =>
{
var request = new HttpRequestMessage(HttpMethod.Post, url);
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/RouterService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/RouterService.cs
index 3cdd283..c63f06e 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/RouterService.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/RouterService.cs
@@ -11,6 +11,7 @@
using WIDESEAWCS_DTO.BasicInfo;
using WIDESEAWCS_QuartzJob.Models;
using WIDESEAWCS_QuartzJob.Repository;
+using ICacheService = WIDESEAWCS_Core.Caches.ICacheService;
namespace WIDESEAWCS_QuartzJob.Service
{
@@ -21,6 +22,7 @@
{
private readonly IDeviceProtocolRepository _deviceProtocolRepository;
private readonly IDeviceInfoRepository _deviceInfoRepository;
+ private readonly ICacheService _cacheService;
/// <summary>
/// 璺敱閰嶇疆涓氬姟灞�
@@ -28,10 +30,11 @@
/// <param name="BaseDal"></param>
/// <param name="deviceProtocolRepository"></param>
/// <param name="deviceInfoRepository"></param>
- public RouterService(IRouterRepository BaseDal, IDeviceProtocolRepository deviceProtocolRepository, IDeviceInfoRepository deviceInfoRepository) : base(BaseDal)
+ public RouterService(IRouterRepository BaseDal, IDeviceProtocolRepository deviceProtocolRepository, IDeviceInfoRepository deviceInfoRepository, ICacheService cacheService) : base(BaseDal)
{
_deviceProtocolRepository = deviceProtocolRepository;
_deviceInfoRepository = deviceInfoRepository;
+ _cacheService = cacheService;
}
/// <summary>
@@ -47,10 +50,10 @@
{
// 涓�娆℃�ф煡璇㈡墍鏈夎矾鐢辨暟鎹埌鍐呭瓨
List<Dt_Router> allRouters = BaseDal.QueryData(x => true);
-
+
// 鍦ㄥ唴瀛樹腑杩涜璺緞鎼滅储
routers = FindRoutesInMemory(startPosi, endPosi, allRouters, null);
-
+
if (routers.Count == 0)
{
throw new Exception($"璇ヨ矾寰勬湭閰嶇疆鎴栭厤缃敊璇�,璇锋鏌ヨ澶囪矾鐢变俊鎭�,璧风偣:銆恵startPosi}銆�,缁堢偣:銆恵endPosi}銆�");
@@ -77,10 +80,10 @@
{
// 涓�娆℃�ф煡璇㈡寚瀹氱被鍨嬬殑鎵�鏈夎矾鐢辨暟鎹埌鍐呭瓨
List<Dt_Router> allRouters = BaseDal.QueryData(x => x.InOutType == routeType);
-
+
// 鍦ㄥ唴瀛樹腑杩涜璺緞鎼滅储
routers = FindRoutesInMemory(startPosi, endPosi, allRouters, routeType);
-
+
if (routers.Count == 0)
{
throw new Exception($"璇ヨ矾寰勬湭閰嶇疆鎴栭厤缃敊璇�,璇锋鏌ヨ澶囪矾鐢变俊鎭�,璧风偣:銆恵startPosi}銆�,缁堢偣:銆恵endPosi}銆�");
@@ -110,7 +113,7 @@
var routersByNext = allRouters
.GroupBy(r => r.NextPosi)
.ToDictionary(g => g.Key, g => g.ToList());
-
+
var routersByChild = allRouters
.GroupBy(r => r.ChildPosi)
.ToDictionary(g => g.Key, g => g.ToList());
@@ -127,7 +130,7 @@
// 浣跨敤闃熷垪杩涜骞垮害浼樺厛鎼滅储
Queue<(Dt_Router router, List<Dt_Router> path)> queue = new Queue<(Dt_Router, List<Dt_Router>)>();
-
+
// 灏嗘墍鏈夌粓鐐硅矾鐢卞姞鍏ラ槦鍒�
foreach (var endRouter in endRouters)
{
@@ -186,9 +189,9 @@
try
{
// 鏌ヨ浠庤捣鐐瑰嚭鍙戠殑鎵�鏈夎矾鐢�
- List<Dt_Router> routes = BaseDal.QueryData(x => x.StartPosi == startPosi,
+ List<Dt_Router> routes = BaseDal.QueryData(x => x.StartPosi == startPosi,
new Dictionary<string, OrderByType> { { nameof(Dt_Router.IsEnd), OrderByType.Desc } });
-
+
// 杩斿洖绗竴涓矾鐢�
return routes.FirstOrDefault();
}
@@ -210,9 +213,9 @@
try
{
// 鏌ヨ浠庤捣鐐瑰嚭鍙戠殑鎸囧畾绫诲瀷璺敱
- List<Dt_Router> routes = BaseDal.QueryData(x => x.StartPosi == startPosi && x.InOutType == routeType,
+ List<Dt_Router> routes = BaseDal.QueryData(x => x.StartPosi == startPosi && x.InOutType == routeType,
new Dictionary<string, OrderByType> { { nameof(Dt_Router.IsEnd), OrderByType.Desc } });
-
+
// 杩斿洖绗竴涓矾鐢�
return routes.FirstOrDefault();
}
@@ -235,9 +238,9 @@
try
{
// 鏌ヨ浠庤捣鐐瑰嚭鍙戠殑鎸囧畾绫诲瀷璺敱
- List<Dt_Router> routes = BaseDal.QueryData(x => x.StartPosi == startPosi && x.InOutType == routeType,
+ List<Dt_Router> routes = BaseDal.QueryData(x => x.StartPosi == startPosi && x.InOutType == routeType,
new Dictionary<string, OrderByType> { { nameof(Dt_Router.IsEnd), OrderByType.Desc } });
-
+
if (routes.Count == 0)
return null;
@@ -278,7 +281,7 @@
List<Dt_Router> path = new List<Dt_Router>();
string currentPosi = startPosi;
HashSet<string> visitedPositions = new HashSet<string>();
-
+
try
{
while (currentPosi != endPosi)
@@ -290,21 +293,21 @@
visitedPositions.Add(currentPosi);
Dt_Router nextRoute = QueryNextRoute(currentPosi, endPosi, routeType);
-
+
if (nextRoute == null)
{
break;
}
-
+
path.Add(nextRoute);
currentPosi = nextRoute.NextPosi;
-
+
if (path.Count > 1000)
{
break;
}
}
-
+
if (currentPosi != endPosi)
{
return new List<Dt_Router>();
@@ -314,7 +317,7 @@
{
return new List<Dt_Router>();
}
-
+
return path;
}
@@ -327,24 +330,31 @@
{
// 鍒涘缓涓�涓瓧绗︿覆鍒楄〃锛岀敤浜庡瓨鍌ㄦ墍鏈変綅缃�
List<string> positions = new List<string>();
- try
- {
- // 鏌ヨ鎵�鏈夎繘鍏ヨ矾鐢卞櫒鐨勪綅缃�
- List<string> inRouterPositions = BaseDal.QueryData(x => x.ChildPosiDeviceCode == deviceCode && x.InOutType == RouterInOutType.In.ObjToInt()).GroupBy(x => x.StartPosi).Select(x => x.Key).ToList();
-
- // 鏌ヨ鎵�鏈夌寮�璺敱鍣ㄧ殑浣嶇疆
- List<string> outRouterPositions = BaseDal.QueryData(x => x.ChildPosiDeviceCode == deviceCode && x.InOutType == RouterInOutType.Out.ObjToInt()).GroupBy(x => x.ChildPosi).Select(x => x.Key).ToList();
-
- // 灏嗚繘鍏ュ拰绂诲紑璺敱鍣ㄧ殑浣嶇疆娣诲姞鍒板垪琛ㄤ腑
- positions.AddRange(inRouterPositions);
- positions.AddRange(outRouterPositions);
- // 杩斿洖鍘婚噸鍚庣殑浣嶇疆鍒楄〃
- return positions.GroupBy(x => x).Select(x => x.Key).ToList();
- }
- catch
+ var device = _cacheService.Get<List<string>>($"DevicePositions:{deviceCode}");
+ if (device.IsNullOrEmpty())
{
+ try
+ {
+ // 鏌ヨ鎵�鏈夎繘鍏ヨ矾鐢卞櫒鐨勪綅缃�
+ List<string> inRouterPositions = BaseDal.QueryData(x => x.ChildPosiDeviceCode == deviceCode && x.InOutType == RouterInOutType.In.ObjToInt()).GroupBy(x => x.StartPosi).Select(x => x.Key).ToList();
+
+ // 鏌ヨ鎵�鏈夌寮�璺敱鍣ㄧ殑浣嶇疆
+ List<string> outRouterPositions = BaseDal.QueryData(x => x.ChildPosiDeviceCode == deviceCode && x.InOutType == RouterInOutType.Out.ObjToInt()).GroupBy(x => x.ChildPosi).Select(x => x.Key).ToList();
+
+ // 灏嗚繘鍏ュ拰绂诲紑璺敱鍣ㄧ殑浣嶇疆娣诲姞鍒板垪琛ㄤ腑
+ positions.AddRange(inRouterPositions);
+ positions.AddRange(outRouterPositions);
+ // 杩斿洖鍘婚噸鍚庣殑浣嶇疆鍒楄〃
+ return positions.GroupBy(x => x).Select(x => x.Key).ToList();
+ }
+ catch
+ {
+
+ }
}
+ else
+ positions = device;
// 杩斿洖浣嶇疆鍒楄〃
return positions;
}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Bitmap/IBitmapService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Bitmap/IBitmapService.cs
new file mode 100644
index 0000000..9351b73
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Bitmap/IBitmapService.cs
@@ -0,0 +1,28 @@
+namespace WIDESEAWCS_RedisService.Bitmap
+{
+ public interface IBitmapService
+ {
+ bool SetBit(string key, long offset, bool value);
+ bool GetBit(string key, long offset);
+ long BitCount(string key);
+ long BitCount(string key, long start, long end);
+ }
+
+ public interface IBloomFilterService
+ {
+ /// <summary>
+ /// 娣诲姞鍏冪礌鍒板竷闅嗚繃婊ゅ櫒
+ /// </summary>
+ void Add(string filterName, string value);
+
+ /// <summary>
+ /// 妫�鏌ュ厓绱犳槸鍚﹀彲鑳藉瓨鍦�
+ /// </summary>
+ bool MayExist(string filterName, string value);
+
+ /// <summary>
+ /// 鎵归噺娣诲姞
+ /// </summary>
+ void AddRange(string filterName, IEnumerable<string> values);
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Bitmap/RedisBitmapService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Bitmap/RedisBitmapService.cs
new file mode 100644
index 0000000..b0b5d73
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Bitmap/RedisBitmapService.cs
@@ -0,0 +1,46 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using WIDESEAWCS_RedisService.Connection;
+using WIDESEAWCS_RedisService.Options;
+
+namespace WIDESEAWCS_RedisService.Bitmap
+{
+ public class RedisBitmapService : IBitmapService
+ {
+ private readonly IRedisConnectionManager _connectionManager;
+ private readonly RedisOptions _options;
+ private readonly ILogger<RedisBitmapService> _logger;
+
+ public RedisBitmapService(
+ IRedisConnectionManager connectionManager,
+ IOptions<RedisOptions> options,
+ ILogger<RedisBitmapService> logger)
+ {
+ _connectionManager = connectionManager;
+ _options = options.Value;
+ _logger = logger;
+ }
+
+ private string BuildKey(string key) => $"{_options.KeyPrefix}bitmap:{key}";
+
+ public bool SetBit(string key, long offset, bool value)
+ {
+ return _connectionManager.GetDatabase().StringSetBit(BuildKey(key), offset, value);
+ }
+
+ public bool GetBit(string key, long offset)
+ {
+ return _connectionManager.GetDatabase().StringGetBit(BuildKey(key), offset);
+ }
+
+ public long BitCount(string key)
+ {
+ return _connectionManager.GetDatabase().StringBitCount(BuildKey(key));
+ }
+
+ public long BitCount(string key, long start, long end)
+ {
+ return _connectionManager.GetDatabase().StringBitCount(BuildKey(key), start, end);
+ }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Bitmap/RedisBloomFilterService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Bitmap/RedisBloomFilterService.cs
new file mode 100644
index 0000000..b329731
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Bitmap/RedisBloomFilterService.cs
@@ -0,0 +1,96 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using WIDESEAWCS_RedisService.Connection;
+using WIDESEAWCS_RedisService.Options;
+using System.Text;
+
+namespace WIDESEAWCS_RedisService.Bitmap
+{
+ public class RedisBloomFilterService : IBloomFilterService
+ {
+ private readonly IRedisConnectionManager _connectionManager;
+ private readonly RedisOptions _options;
+ private readonly ILogger<RedisBloomFilterService> _logger;
+ private const int HashCount = 5;
+ private const long BitSize = 1_000_000;
+
+ public RedisBloomFilterService(
+ IRedisConnectionManager connectionManager,
+ IOptions<RedisOptions> options,
+ ILogger<RedisBloomFilterService> logger)
+ {
+ _connectionManager = connectionManager;
+ _options = options.Value;
+ _logger = logger;
+ }
+
+ private string BuildKey(string key) => $"{_options.KeyPrefix}bloom:{key}";
+
+ public void Add(string filterName, string value)
+ {
+ var db = _connectionManager.GetDatabase();
+ var fullKey = BuildKey(filterName);
+ var offsets = GetHashOffsets(value);
+ foreach (var offset in offsets)
+ db.StringSetBit(fullKey, offset, true);
+ }
+
+ public bool MayExist(string filterName, string value)
+ {
+ var db = _connectionManager.GetDatabase();
+ var fullKey = BuildKey(filterName);
+ var offsets = GetHashOffsets(value);
+ return offsets.All(offset => db.StringGetBit(fullKey, offset));
+ }
+
+ public void AddRange(string filterName, IEnumerable<string> values)
+ {
+ foreach (var value in values) Add(filterName, value);
+ }
+
+ private long[] GetHashOffsets(string value)
+ {
+ var offsets = new long[HashCount];
+ var bytes = Encoding.UTF8.GetBytes(value);
+ for (int i = 0; i < HashCount; i++)
+ {
+ uint hash = MurmurHash(bytes, (uint)i);
+ offsets[i] = hash % BitSize;
+ }
+ return offsets;
+ }
+
+ private static uint MurmurHash(byte[] data, uint seed)
+ {
+ const uint c1 = 0xcc9e2d51;
+ const uint c2 = 0x1b873593;
+ uint h1 = seed;
+ int len = data.Length;
+ int blocks = len / 4;
+
+ for (int i = 0; i < blocks; i++)
+ {
+ uint k1 = BitConverter.ToUInt32(data, i * 4);
+ k1 *= c1; k1 = RotateLeft(k1, 15); k1 *= c2;
+ h1 ^= k1; h1 = RotateLeft(h1, 13); h1 = h1 * 5 + 0xe6546b64;
+ }
+
+ uint tail = 0;
+ int tailIdx = blocks * 4;
+ switch (len & 3)
+ {
+ case 3: tail ^= (uint)data[tailIdx + 2] << 16; goto case 2;
+ case 2: tail ^= (uint)data[tailIdx + 1] << 8; goto case 1;
+ case 1: tail ^= data[tailIdx]; tail *= c1; tail = RotateLeft(tail, 15); tail *= c2; h1 ^= tail; break;
+ }
+
+ h1 ^= (uint)len;
+ h1 ^= h1 >> 16; h1 *= 0x85ebca6b;
+ h1 ^= h1 >> 13; h1 *= 0xc2b2ae35;
+ h1 ^= h1 >> 16;
+ return h1;
+ }
+
+ private static uint RotateLeft(uint x, byte r) => (x << r) | (x >> (32 - r));
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Cache/HybridCacheService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Cache/HybridCacheService.cs
new file mode 100644
index 0000000..55c3c22
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Cache/HybridCacheService.cs
@@ -0,0 +1,266 @@
+using Microsoft.Extensions.Caching.Memory;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using WIDESEAWCS_Core.Caches;
+using WIDESEAWCS_RedisService.Connection;
+using WIDESEAWCS_RedisService.Options;
+using WIDESEAWCS_RedisService.Serialization;
+
+namespace WIDESEAWCS_RedisService.Cache
+{
+ public class HybridCacheService : ICacheService
+ {
+ private readonly IMemoryCache _memoryCache;
+ private readonly IRedisConnectionManager _connectionManager;
+ private readonly IRedisSerializer _serializer;
+ private readonly RedisOptions _options;
+ private readonly ILogger<HybridCacheService> _logger;
+ private bool _disposed;
+
+ private bool RedisAvailable => _connectionManager.IsConnected;
+
+ public HybridCacheService(
+ IMemoryCache memoryCache,
+ IRedisConnectionManager connectionManager,
+ IRedisSerializer serializer,
+ IOptions<RedisOptions> options,
+ ILogger<HybridCacheService> logger)
+ {
+ _memoryCache = memoryCache;
+ _connectionManager = connectionManager;
+ _serializer = serializer;
+ _options = options.Value;
+ _logger = logger;
+ }
+
+ private string BuildKey(string key) => $"{_options.KeyPrefix}{key}";
+
+ public bool Exists(string key)
+ {
+ if (_memoryCache.TryGetValue(BuildKey(key), out _)) return true;
+ if (!RedisAvailable) return false;
+ try
+ {
+ return _connectionManager.GetDatabase().KeyExists(BuildKey(key));
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "Redis Exists澶辫触, key={Key}", key);
+ return false;
+ }
+ }
+
+ public bool Add(string key, string value, int expireSeconds = -1, bool isSliding = false)
+ {
+ var fullKey = BuildKey(key);
+ SetMemoryCache(fullKey, value, expireSeconds, isSliding);
+ if (!RedisAvailable)
+ {
+ _logger.LogWarning("Redis涓嶅彲鐢紝浠呬娇鐢ㄥ唴瀛樼紦瀛�, key={Key}", key);
+ return true;
+ }
+ try
+ {
+ var expiry = expireSeconds > 0 ? TimeSpan.FromSeconds(expireSeconds) : (TimeSpan?)null;
+ var result = _connectionManager.GetDatabase().StringSet(fullKey, value, expiry);
+ _logger.LogInformation("Redis鍐欏叆鎴愬姛: key={Key}, result={Result}", fullKey, result);
+ return result;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "Redis Add澶辫触, key={Key}", key);
+ return _options.FallbackToMemory;
+ }
+ }
+
+ public bool AddObject(string key, object value, int expireSeconds = -1, bool isSliding = false)
+ {
+ return Add(key, _serializer.Serialize(value), expireSeconds, isSliding);
+ }
+
+ public void AddOrUpdate(string key, string value, int expireSeconds = -1, bool isSliding = false)
+ {
+ Add(key, value, expireSeconds, isSliding);
+ }
+
+ public void AddOrUpdate(string key, object value, int expireSeconds = -1, bool isSliding = false)
+ {
+ AddObject(key, value, expireSeconds, isSliding);
+ }
+
+ public bool Remove(string key)
+ {
+ var fullKey = BuildKey(key);
+ _memoryCache.Remove(fullKey);
+ if (!RedisAvailable) return true;
+ try
+ {
+ return _connectionManager.GetDatabase().KeyDelete(fullKey);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "Redis Remove澶辫触, key={Key}", key);
+ return true;
+ }
+ }
+
+ public void Remove(IEnumerable<string> keys)
+ {
+ foreach (var key in keys) Remove(key);
+ }
+
+ public T? Get<T>(string key) where T : class
+ {
+ var fullKey = BuildKey(key);
+ if (_memoryCache.TryGetValue(fullKey, out string? cached) && cached != null)
+ return _serializer.Deserialize<T>(cached);
+
+ if (!RedisAvailable) return default;
+ try
+ {
+ var value = _connectionManager.GetDatabase().StringGet(fullKey);
+ if (value.IsNullOrEmpty) return default;
+ var str = value.ToString();
+ SetMemoryCache(fullKey, str, 300, false);
+ return _serializer.Deserialize<T>(str);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "Redis Get<T>澶辫触, key={Key}", key);
+ return default;
+ }
+ }
+
+ public object? Get(Type type, string key)
+ {
+ var fullKey = BuildKey(key);
+ if (_memoryCache.TryGetValue(fullKey, out string? cached) && cached != null)
+ return _serializer.Deserialize(cached, type);
+
+ if (!RedisAvailable) return null;
+ try
+ {
+ var value = _connectionManager.GetDatabase().StringGet(fullKey);
+ if (value.IsNullOrEmpty) return null;
+ var str = value.ToString();
+ SetMemoryCache(fullKey, str, 300, false);
+ return _serializer.Deserialize(str, type);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "Redis Get(Type)澶辫触, key={Key}", key);
+ return null;
+ }
+ }
+
+ public string? Get(string key)
+ {
+ var fullKey = BuildKey(key);
+ if (_memoryCache.TryGetValue(fullKey, out string? cached))
+ return cached;
+
+ if (!RedisAvailable) return null;
+ try
+ {
+ var value = _connectionManager.GetDatabase().StringGet(fullKey);
+ if (value.IsNullOrEmpty) return null;
+ var str = value.ToString();
+ SetMemoryCache(fullKey, str, 300, false);
+ return str;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "Redis Get澶辫触, key={Key}", key);
+ return null;
+ }
+ }
+
+ private void SetMemoryCache(string fullKey, string value, int expireSeconds, bool isSliding)
+ {
+ var entryOptions = new MemoryCacheEntryOptions();
+ if (expireSeconds > 0)
+ {
+ if (isSliding)
+ entryOptions.SetSlidingExpiration(TimeSpan.FromSeconds(expireSeconds));
+ else
+ entryOptions.SetAbsoluteExpiration(TimeSpan.FromSeconds(expireSeconds));
+ }
+ _memoryCache.Set(fullKey, value, entryOptions);
+ }
+
+ #region ConcurrentDictionary椋庢牸鏂规硶
+
+ public bool TryAdd(string key, string value, int expireSeconds = -1)
+ {
+ if (Exists(key)) return false;
+ return Add(key, value, expireSeconds);
+ }
+
+ public bool TryAdd<T>(string key, T value, int expireSeconds = -1) where T : class
+ {
+ if (Exists(key)) return false;
+ return AddObject(key, value, expireSeconds);
+ }
+
+ public bool TryGetValue(string key, out string? value)
+ {
+ value = Get(key);
+ return value != null;
+ }
+
+ public bool TryGetValue<T>(string key, out T? value) where T : class
+ {
+ value = Get<T>(key);
+ return value != null;
+ }
+
+ public bool TryRemove(string key, out string? value)
+ {
+ value = Get(key);
+ if (value == null) return false;
+ Remove(key);
+ return true;
+ }
+
+ public bool TryUpdate(string key, string newValue, int expireSeconds = -1)
+ {
+ if (!Exists(key)) return false;
+ Add(key, newValue, expireSeconds);
+ return true;
+ }
+
+ public string GetOrAdd(string key, string value, int expireSeconds = -1)
+ {
+ var existing = Get(key);
+ if (existing != null) return existing;
+ Add(key, value, expireSeconds);
+ return value;
+ }
+
+ public string GetOrAdd(string key, Func<string, string> valueFactory, int expireSeconds = -1)
+ {
+ var existing = Get(key);
+ if (existing != null) return existing;
+ var value = valueFactory(key);
+ Add(key, value, expireSeconds);
+ return value;
+ }
+
+ public T GetOrAdd<T>(string key, Func<string, T> valueFactory, int expireSeconds = -1) where T : class
+ {
+ var existing = Get<T>(key);
+ if (existing != null) return existing;
+ var value = valueFactory(key);
+ AddObject(key, value, expireSeconds);
+ return value;
+ }
+
+ #endregion
+
+ public void Dispose()
+ {
+ if (_disposed) return;
+ _disposed = true;
+ }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Cache/RedisCacheService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Cache/RedisCacheService.cs
new file mode 100644
index 0000000..fe19c5f
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Cache/RedisCacheService.cs
@@ -0,0 +1,174 @@
+using Microsoft.Extensions.Logging;
+using StackExchange.Redis;
+using WIDESEAWCS_Core.Caches;
+using WIDESEAWCS_RedisService.Connection;
+using WIDESEAWCS_RedisService.Options;
+using WIDESEAWCS_RedisService.Serialization;
+using Microsoft.Extensions.Options;
+
+namespace WIDESEAWCS_RedisService.Cache
+{
+ public class RedisCacheService : ICacheService
+ {
+ private readonly IRedisConnectionManager _connectionManager;
+ private readonly IRedisSerializer _serializer;
+ private readonly RedisOptions _options;
+ private readonly ILogger<RedisCacheService> _logger;
+ private bool _disposed;
+
+ public RedisCacheService(
+ IRedisConnectionManager connectionManager,
+ IRedisSerializer serializer,
+ IOptions<RedisOptions> options,
+ ILogger<RedisCacheService> logger)
+ {
+ _connectionManager = connectionManager;
+ _serializer = serializer;
+ _options = options.Value;
+ _logger = logger;
+ }
+
+ private string BuildKey(string key) => $"{_options.KeyPrefix}{key}";
+
+ private IDatabase Db => _connectionManager.GetDatabase();
+
+ public bool Exists(string key)
+ {
+ return Db.KeyExists(BuildKey(key));
+ }
+
+ public bool Add(string key, string value, int expireSeconds = -1, bool isSliding = false)
+ {
+ var fullKey = BuildKey(key);
+ var expiry = expireSeconds > 0 ? TimeSpan.FromSeconds(expireSeconds) : (TimeSpan?)null;
+ return Db.StringSet(fullKey, value, expiry);
+ }
+
+ public bool AddObject(string key, object value, int expireSeconds = -1, bool isSliding = false)
+ {
+ return Add(key, _serializer.Serialize(value), expireSeconds, isSliding);
+ }
+
+ public void AddOrUpdate(string key, string value, int expireSeconds = -1, bool isSliding = false)
+ {
+ Add(key, value, expireSeconds, isSliding);
+ }
+
+ public void AddOrUpdate(string key, object value, int expireSeconds = -1, bool isSliding = false)
+ {
+ AddObject(key, value, expireSeconds, isSliding);
+ }
+
+ public bool Remove(string key)
+ {
+ return Db.KeyDelete(BuildKey(key));
+ }
+
+ public void Remove(IEnumerable<string> keys)
+ {
+ var redisKeys = keys.Select(k => (RedisKey)BuildKey(k)).ToArray();
+ Db.KeyDelete(redisKeys);
+ }
+
+ public T? Get<T>(string key) where T : class
+ {
+ var value = Db.StringGet(BuildKey(key));
+ if (value.IsNullOrEmpty) return default;
+ return _serializer.Deserialize<T>(value!);
+ }
+
+ public object? Get(Type type, string key)
+ {
+ var value = Db.StringGet(BuildKey(key));
+ if (value.IsNullOrEmpty) return null;
+ return _serializer.Deserialize(value!, type);
+ }
+
+ public string? Get(string key)
+ {
+ var value = Db.StringGet(BuildKey(key));
+ return value.IsNullOrEmpty ? null : value.ToString();
+ }
+
+ public void Dispose()
+ {
+ if (_disposed) return;
+ _disposed = true;
+ }
+
+ public bool TryAdd(string key, string value, int expireSeconds = -1)
+ {
+ var fullKey = BuildKey(key);
+ var expiry = expireSeconds > 0 ? TimeSpan.FromSeconds(expireSeconds) : (TimeSpan?)null;
+ return Db.StringSet(fullKey, value, expiry, When.NotExists);
+ }
+
+ public bool TryAdd<T>(string key, T value, int expireSeconds = -1) where T : class
+ {
+ return TryAdd(key, _serializer.Serialize(value), expireSeconds);
+ }
+
+ public bool TryGetValue(string key, out string? value)
+ {
+ var val = Db.StringGet(BuildKey(key));
+ value = val.IsNullOrEmpty ? null : val.ToString();
+ return !val.IsNullOrEmpty;
+ }
+
+ public bool TryGetValue<T>(string key, out T? value) where T : class
+ {
+ var val = Db.StringGet(BuildKey(key));
+ if (val.IsNullOrEmpty) { value = default; return false; }
+ value = _serializer.Deserialize<T>(val!);
+ return value != null;
+ }
+
+ public bool TryRemove(string key, out string? value)
+ {
+ var fullKey = BuildKey(key);
+ value = Db.StringGet(fullKey).ToString();
+ if (value == null) return false;
+ return Db.KeyDelete(fullKey);
+ }
+
+ public bool TryUpdate(string key, string newValue, int expireSeconds = -1)
+ {
+ var fullKey = BuildKey(key);
+ if (!Db.KeyExists(fullKey)) return false;
+ var expiry = expireSeconds > 0 ? TimeSpan.FromSeconds(expireSeconds) : (TimeSpan?)null;
+ return Db.StringSet(fullKey, newValue, expiry, When.Exists);
+ }
+
+ public string GetOrAdd(string key, string value, int expireSeconds = -1)
+ {
+ var fullKey = BuildKey(key);
+ var existing = Db.StringGet(fullKey);
+ if (!existing.IsNullOrEmpty) return existing.ToString();
+ var expiry = expireSeconds > 0 ? TimeSpan.FromSeconds(expireSeconds) : (TimeSpan?)null;
+ Db.StringSet(fullKey, value, expiry, When.NotExists);
+ return Db.StringGet(fullKey).ToString();
+ }
+
+ public string GetOrAdd(string key, Func<string, string> valueFactory, int expireSeconds = -1)
+ {
+ var fullKey = BuildKey(key);
+ var existing = Db.StringGet(fullKey);
+ if (!existing.IsNullOrEmpty) return existing.ToString();
+ var value = valueFactory(key);
+ var expiry = expireSeconds > 0 ? TimeSpan.FromSeconds(expireSeconds) : (TimeSpan?)null;
+ Db.StringSet(fullKey, value, expiry, When.NotExists);
+ return Db.StringGet(fullKey).ToString();
+ }
+
+ public T GetOrAdd<T>(string key, Func<string, T> valueFactory, int expireSeconds = -1) where T : class
+ {
+ var fullKey = BuildKey(key);
+ var existing = Db.StringGet(fullKey);
+ if (!existing.IsNullOrEmpty) return _serializer.Deserialize<T>(existing!)!;
+ var value = valueFactory(key);
+ var expiry = expireSeconds > 0 ? TimeSpan.FromSeconds(expireSeconds) : (TimeSpan?)null;
+ Db.StringSet(fullKey, _serializer.Serialize(value), expiry, When.NotExists);
+ return value;
+ }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Configuration/IConfigurationCenterService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Configuration/IConfigurationCenterService.cs
new file mode 100644
index 0000000..8d9eab3
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Configuration/IConfigurationCenterService.cs
@@ -0,0 +1,30 @@
+namespace WIDESEAWCS_RedisService.Configuration
+{
+ public interface IConfigurationCenterService
+ {
+ /// <summary>
+ /// 璁剧疆閰嶇疆椤�
+ /// </summary>
+ bool Set(string section, string key, string value);
+
+ /// <summary>
+ /// 鑾峰彇閰嶇疆椤�
+ /// </summary>
+ string? Get(string section, string key);
+
+ /// <summary>
+ /// 鑾峰彇鏁翠釜閰嶇疆鑺�
+ /// </summary>
+ Dictionary<string, string> GetSection(string section);
+
+ /// <summary>
+ /// 鍒犻櫎閰嶇疆椤�
+ /// </summary>
+ bool Delete(string section, string key);
+
+ /// <summary>
+ /// 璁㈤槄閰嶇疆鍙樻洿
+ /// </summary>
+ void Subscribe(string section, Action<string, string> onChange);
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Configuration/RedisConfigurationCenterService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Configuration/RedisConfigurationCenterService.cs
new file mode 100644
index 0000000..2eeb049
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Configuration/RedisConfigurationCenterService.cs
@@ -0,0 +1,65 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using StackExchange.Redis;
+using WIDESEAWCS_RedisService.Connection;
+using WIDESEAWCS_RedisService.Options;
+
+namespace WIDESEAWCS_RedisService.Configuration
+{
+ public class RedisConfigurationCenterService : IConfigurationCenterService
+ {
+ private readonly IRedisConnectionManager _connectionManager;
+ private readonly RedisOptions _options;
+ private readonly ILogger<RedisConfigurationCenterService> _logger;
+
+ public RedisConfigurationCenterService(
+ IRedisConnectionManager connectionManager,
+ IOptions<RedisOptions> options,
+ ILogger<RedisConfigurationCenterService> logger)
+ {
+ _connectionManager = connectionManager;
+ _options = options.Value;
+ _logger = logger;
+ }
+
+ private string BuildKey(string section) => $"{_options.KeyPrefix}config:{section}";
+
+ public bool Set(string section, string key, string value)
+ {
+ var db = _connectionManager.GetDatabase();
+ var result = db.HashSet(BuildKey(section), key, value);
+ // 鍙戝竷鍙樻洿閫氱煡
+ _connectionManager.GetSubscriber()
+ .Publish(RedisChannel.Literal($"{_options.KeyPrefix}config:change:{section}"), key);
+ return result;
+ }
+
+ public string? Get(string section, string key)
+ {
+ var val = _connectionManager.GetDatabase().HashGet(BuildKey(section), key);
+ return val.IsNullOrEmpty ? null : val.ToString();
+ }
+
+ public Dictionary<string, string> GetSection(string section)
+ {
+ var entries = _connectionManager.GetDatabase().HashGetAll(BuildKey(section));
+ return entries.ToDictionary(e => e.Name.ToString(), e => e.Value.ToString());
+ }
+
+ public bool Delete(string section, string key)
+ {
+ return _connectionManager.GetDatabase().HashDelete(BuildKey(section), key);
+ }
+
+ public void Subscribe(string section, Action<string, string> onChange)
+ {
+ _connectionManager.GetSubscriber()
+ .Subscribe(RedisChannel.Literal($"{_options.KeyPrefix}config:change:{section}"), (_, msg) =>
+ {
+ var changedKey = msg.ToString();
+ var value = Get(section, changedKey) ?? string.Empty;
+ onChange(changedKey, value);
+ });
+ }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Connection/IRedisConnectionManager.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Connection/IRedisConnectionManager.cs
new file mode 100644
index 0000000..04be0f3
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Connection/IRedisConnectionManager.cs
@@ -0,0 +1,17 @@
+using StackExchange.Redis;
+
+namespace WIDESEAWCS_RedisService.Connection
+{
+ public interface IRedisConnectionManager : IDisposable
+ {
+ IDatabase GetDatabase(int db = -1);
+
+ IServer GetServer();
+
+ ISubscriber GetSubscriber();
+
+ ConnectionMultiplexer GetConnection();
+
+ bool IsConnected { get; }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Connection/RedisConnectionManager.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Connection/RedisConnectionManager.cs
new file mode 100644
index 0000000..bc37709
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Connection/RedisConnectionManager.cs
@@ -0,0 +1,111 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using StackExchange.Redis;
+using System.Linq;
+using WIDESEAWCS_RedisService.Options;
+
+namespace WIDESEAWCS_RedisService.Connection
+{
+ public class RedisConnectionManager : IRedisConnectionManager
+ {
+ private readonly RedisOptions _options;
+ private readonly ILogger<RedisConnectionManager> _logger;
+ private readonly Lazy<ConnectionMultiplexer> _connection;
+ private bool _disposed;
+
+ public bool IsConnected
+ {
+ get
+ {
+ try
+ {
+ // 寮哄埗璁块棶Value鏉ヨЕ鍙戣繛鎺ュ垱寤�
+ var connected = _connection.Value.IsConnected;
+ _logger.LogDebug("IsConnected妫�鏌�: IsValueCreated={IsValueCreated}, IsConnected={Connected}",
+ _connection.IsValueCreated, connected);
+ return connected;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "IsConnected妫�鏌ュけ璐�");
+ return false;
+ }
+ }
+ }
+
+ public RedisConnectionManager(IOptions<RedisOptions> options, ILogger<RedisConnectionManager> logger)
+ {
+ _options = options.Value;
+ _logger = logger;
+ _logger.LogInformation("RedisConnectionManager鏋勯�犲紑濮�, ConnectionString={ConnectionString}, Enabled={Enabled}",
+ _options.ConnectionString, _options.Enabled);
+ _connection = new Lazy<ConnectionMultiplexer>(CreateConnection);
+ _logger.LogInformation("RedisConnectionManager鏋勯�犲畬鎴�, Lazy宸插垱寤�");
+ }
+
+ private ConnectionMultiplexer CreateConnection()
+ {
+ try
+ {
+ _logger.LogInformation("寮�濮嬪垱寤篟edis杩炴帴, ConnectionString={ConnectionString}", _options.ConnectionString);
+ var configOptions = ConfigurationOptions.Parse(_options.ConnectionString);
+ configOptions.AbortOnConnectFail = false;
+ configOptions.ConnectRetry = _options.ConnectRetry;
+ configOptions.DefaultDatabase = _options.DefaultDatabase;
+ _logger.LogInformation("ConfigurationOptions瑙f瀽瀹屾垚, EndPoints={EndPoints}", string.Join(",", configOptions.EndPoints.Select(e => e.ToString())));
+
+ if (_options.EnableSentinel && _options.SentinelEndpoints.Count > 0)
+ {
+ configOptions.ServiceName = _options.SentinelMasterName;
+ foreach (var endpoint in _options.SentinelEndpoints)
+ {
+ configOptions.EndPoints.Add(endpoint);
+ }
+ }
+
+ var connection = ConnectionMultiplexer.Connect(configOptions);
+ connection.ConnectionFailed += (_, e) =>
+ _logger.LogError("Redis杩炴帴澶辫触: {FailureType}", e.FailureType);
+ connection.ConnectionRestored += (_, e) =>
+ _logger.LogInformation("Redis杩炴帴鎭㈠: {EndPoint}", e.EndPoint);
+
+ _logger.LogInformation("Redis杩炴帴鎴愬姛: {EndPoints}", string.Join(",", configOptions.EndPoints));
+ return connection;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Redis杩炴帴鍒涘缓澶辫触");
+ throw;
+ }
+ }
+
+ public IDatabase GetDatabase(int db = -1)
+ {
+ return _connection.Value.GetDatabase(db == -1 ? _options.DefaultDatabase : db);
+ }
+
+ public IServer GetServer()
+ {
+ var endpoints = _connection.Value.GetEndPoints();
+ return _connection.Value.GetServer(endpoints[0]);
+ }
+
+ public ISubscriber GetSubscriber()
+ {
+ return _connection.Value.GetSubscriber();
+ }
+
+ public ConnectionMultiplexer GetConnection()
+ {
+ return _connection.Value;
+ }
+
+ public void Dispose()
+ {
+ if (_disposed) return;
+ _disposed = true;
+ if (_connection.IsValueCreated)
+ _connection.Value.Dispose();
+ }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Counter/ICounterService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Counter/ICounterService.cs
new file mode 100644
index 0000000..60939c3
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Counter/ICounterService.cs
@@ -0,0 +1,30 @@
+namespace WIDESEAWCS_RedisService.Counter
+{
+ public interface ICounterService
+ {
+ /// <summary>
+ /// 閫掑
+ /// </summary>
+ long Increment(string key, long value = 1);
+
+ /// <summary>
+ /// 閫掑噺
+ /// </summary>
+ long Decrement(string key, long value = 1);
+
+ /// <summary>
+ /// 鑾峰彇褰撳墠鍊�
+ /// </summary>
+ long GetCount(string key);
+
+ /// <summary>
+ /// 閲嶇疆璁℃暟鍣�
+ /// </summary>
+ bool Reset(string key);
+
+ /// <summary>
+ /// 璁剧疆甯﹁繃鏈熸椂闂寸殑璁℃暟鍣�
+ /// </summary>
+ long IncrementWithExpiry(string key, TimeSpan expiry, long value = 1);
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Counter/RedisCounterService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Counter/RedisCounterService.cs
new file mode 100644
index 0000000..dc17483
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Counter/RedisCounterService.cs
@@ -0,0 +1,57 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using WIDESEAWCS_RedisService.Connection;
+using WIDESEAWCS_RedisService.Options;
+
+namespace WIDESEAWCS_RedisService.Counter
+{
+ public class RedisCounterService : ICounterService
+ {
+ private readonly IRedisConnectionManager _connectionManager;
+ private readonly RedisOptions _options;
+ private readonly ILogger<RedisCounterService> _logger;
+
+ public RedisCounterService(
+ IRedisConnectionManager connectionManager,
+ IOptions<RedisOptions> options,
+ ILogger<RedisCounterService> logger)
+ {
+ _connectionManager = connectionManager;
+ _options = options.Value;
+ _logger = logger;
+ }
+
+ private string BuildKey(string key) => $"{_options.KeyPrefix}counter:{key}";
+
+ public long Increment(string key, long value = 1)
+ {
+ return _connectionManager.GetDatabase().StringIncrement(BuildKey(key), value);
+ }
+
+ public long Decrement(string key, long value = 1)
+ {
+ return _connectionManager.GetDatabase().StringDecrement(BuildKey(key), value);
+ }
+
+ public long GetCount(string key)
+ {
+ var val = _connectionManager.GetDatabase().StringGet(BuildKey(key));
+ return val.IsNullOrEmpty ? 0 : (long)val;
+ }
+
+ public bool Reset(string key)
+ {
+ return _connectionManager.GetDatabase().KeyDelete(BuildKey(key));
+ }
+
+ public long IncrementWithExpiry(string key, TimeSpan expiry, long value = 1)
+ {
+ var db = _connectionManager.GetDatabase();
+ var fullKey = BuildKey(key);
+ var result = db.StringIncrement(fullKey, value);
+ if (result == value)
+ db.KeyExpire(fullKey, expiry);
+ return result;
+ }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/DelayQueue/IDelayQueueService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/DelayQueue/IDelayQueueService.cs
new file mode 100644
index 0000000..b220290
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/DelayQueue/IDelayQueueService.cs
@@ -0,0 +1,25 @@
+namespace WIDESEAWCS_RedisService.DelayQueue
+{
+ public interface IDelayQueueService
+ {
+ /// <summary>
+ /// 娣诲姞寤惰繜浠诲姟
+ /// </summary>
+ bool Enqueue(string queueName, string message, TimeSpan delay);
+
+ /// <summary>
+ /// 鑾峰彇鍒版湡鐨勪换鍔�
+ /// </summary>
+ List<string> DequeueDue(string queueName, int count = 10);
+
+ /// <summary>
+ /// 绉婚櫎浠诲姟
+ /// </summary>
+ bool Remove(string queueName, string message);
+
+ /// <summary>
+ /// 鑾峰彇闃熷垪闀垮害
+ /// </summary>
+ long GetQueueLength(string queueName);
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/DelayQueue/RedisDelayQueueService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/DelayQueue/RedisDelayQueueService.cs
new file mode 100644
index 0000000..5d12390
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/DelayQueue/RedisDelayQueueService.cs
@@ -0,0 +1,60 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using StackExchange.Redis;
+using WIDESEAWCS_RedisService.Connection;
+using WIDESEAWCS_RedisService.Options;
+
+namespace WIDESEAWCS_RedisService.DelayQueue
+{
+ public class RedisDelayQueueService : IDelayQueueService
+ {
+ private readonly IRedisConnectionManager _connectionManager;
+ private readonly RedisOptions _options;
+ private readonly ILogger<RedisDelayQueueService> _logger;
+
+ public RedisDelayQueueService(
+ IRedisConnectionManager connectionManager,
+ IOptions<RedisOptions> options,
+ ILogger<RedisDelayQueueService> logger)
+ {
+ _connectionManager = connectionManager;
+ _options = options.Value;
+ _logger = logger;
+ }
+
+ private string BuildKey(string key) => $"{_options.KeyPrefix}delay:{key}";
+
+ public bool Enqueue(string queueName, string message, TimeSpan delay)
+ {
+ var score = DateTimeOffset.UtcNow.Add(delay).ToUnixTimeMilliseconds();
+ return _connectionManager.GetDatabase().SortedSetAdd(BuildKey(queueName), message, score);
+ }
+
+ public List<string> DequeueDue(string queueName, int count = 10)
+ {
+ var db = _connectionManager.GetDatabase();
+ var fullKey = BuildKey(queueName);
+ var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+
+ var entries = db.SortedSetRangeByScore(fullKey, 0, now, take: count);
+ var result = new List<string>();
+
+ foreach (var entry in entries)
+ {
+ if (db.SortedSetRemove(fullKey, entry))
+ result.Add(entry.ToString());
+ }
+ return result;
+ }
+
+ public bool Remove(string queueName, string message)
+ {
+ return _connectionManager.GetDatabase().SortedSetRemove(BuildKey(queueName), message);
+ }
+
+ public long GetQueueLength(string queueName)
+ {
+ return _connectionManager.GetDatabase().SortedSetLength(BuildKey(queueName));
+ }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Extensions/RedisServiceSetup.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Extensions/RedisServiceSetup.cs
new file mode 100644
index 0000000..bd5d40a
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Extensions/RedisServiceSetup.cs
@@ -0,0 +1,77 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using System.Linq;
+using WIDESEAWCS_Core.Caches;
+using WIDESEAWCS_RedisService.Bitmap;
+using WIDESEAWCS_RedisService.Cache;
+using WIDESEAWCS_RedisService.Configuration;
+using WIDESEAWCS_RedisService.Connection;
+using WIDESEAWCS_RedisService.Counter;
+using WIDESEAWCS_RedisService.DelayQueue;
+using WIDESEAWCS_RedisService.IdGenerator;
+using WIDESEAWCS_RedisService.Leaderboard;
+using WIDESEAWCS_RedisService.Geo;
+using WIDESEAWCS_RedisService.Lock;
+using WIDESEAWCS_RedisService.Monitoring;
+using WIDESEAWCS_RedisService.Options;
+using WIDESEAWCS_RedisService.PubSub;
+using WIDESEAWCS_RedisService.RateLimiting;
+using WIDESEAWCS_RedisService.Serialization;
+using WIDESEAWCS_RedisService.Session;
+using WIDESEAWCS_RedisService.Storage;
+using WIDESEAWCS_RedisService.Stream;
+
+namespace WIDESEAWCS_RedisService.Extensions
+{
+ public static class RedisServiceSetup
+ {
+ public static IServiceCollection AddRedisSetup(this IServiceCollection services, IConfiguration configuration)
+ {
+ var section = configuration.GetSection("RedisConfig");
+ services.Configure<RedisOptions>(section);
+
+ var options = section.Get<RedisOptions>() ?? new RedisOptions();
+
+ if (!options.Enabled)
+ {
+ // Redis鏈惎鐢紝浣跨敤鍐呭瓨缂撳瓨
+ services.AddMemoryCache();
+ return services;
+ }
+
+ // 绉婚櫎宸叉湁鐨処CacheService娉ㄥ唽锛圡emoryCacheService锛夛紝閬垮厤鍐茬獊
+ var existingDescriptor = services.FirstOrDefault(d => d.ServiceType == typeof(ICacheService));
+ if (existingDescriptor != null)
+ {
+ services.Remove(existingDescriptor);
+ }
+
+ // 鍩虹璁炬柦
+ services.AddMemoryCache();
+ services.AddSingleton<IRedisSerializer, NewtonsoftRedisSerializer>();
+ services.AddSingleton<IRedisConnectionManager, RedisConnectionManager>();
+
+ // 缂撳瓨锛堟浛鎹㈠師鏈塎emoryCacheService锛�
+ services.AddSingleton<ICacheService, HybridCacheService>();
+
+ // 鍔熻兘妯″潡
+ services.AddSingleton<IDistributedLockService, RedisDistributedLockService>();
+ services.AddSingleton<ICounterService, RedisCounterService>();
+ services.AddSingleton<IMessageQueueService, RedisMessageQueueService>();
+ services.AddSingleton<IDelayQueueService, RedisDelayQueueService>();
+ services.AddSingleton<IStreamProcessingService, RedisStreamProcessingService>();
+ services.AddSingleton<ILeaderboardService, RedisLeaderboardService>();
+ services.AddSingleton<IGeoLocationService, RedisGeoLocationService>();
+ services.AddSingleton<IBitmapService, RedisBitmapService>();
+ services.AddSingleton<IBloomFilterService, RedisBloomFilterService>();
+ services.AddSingleton<IObjectStorageService, RedisObjectStorageService>();
+ services.AddSingleton<IDistributedIdGenerator, RedisDistributedIdGenerator>();
+ services.AddSingleton<IRateLimitingService, RedisRateLimitingService>();
+ services.AddSingleton<IConfigurationCenterService, RedisConfigurationCenterService>();
+ services.AddSingleton<ISessionStorage, RedisSessionStorage>();
+ services.AddSingleton<IRedisMonitorService, RedisMonitorService>();
+
+ return services;
+ }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Geo/IGeoLocationService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Geo/IGeoLocationService.cs
new file mode 100644
index 0000000..165a091
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Geo/IGeoLocationService.cs
@@ -0,0 +1,43 @@
+namespace WIDESEAWCS_RedisService.Geo
+{
+ public interface IGeoLocationService
+ {
+ /// <summary>
+ /// 娣诲姞鍦扮悊浣嶇疆
+ /// </summary>
+ bool Add(string key, double longitude, double latitude, string member);
+
+ /// <summary>
+ /// 鑾峰彇鎴愬憳浣嶇疆
+ /// </summary>
+ GeoPosition? GetPosition(string key, string member);
+
+ /// <summary>
+ /// 璁$畻涓や釜鎴愬憳涔嬮棿鐨勮窛绂伙紙绫筹級
+ /// </summary>
+ double? GetDistance(string key, string member1, string member2);
+
+ /// <summary>
+ /// 鎼滅储鎸囧畾鍗婂緞鍐呯殑鎴愬憳
+ /// </summary>
+ List<GeoRadiusResult> SearchRadius(string key, double longitude, double latitude, double radiusMeters, int count = 10);
+
+ /// <summary>
+ /// 绉婚櫎鎴愬憳
+ /// </summary>
+ bool Remove(string key, string member);
+ }
+
+ public class GeoPosition
+ {
+ public double Longitude { get; set; }
+ public double Latitude { get; set; }
+ }
+
+ public class GeoRadiusResult
+ {
+ public string Member { get; set; } = string.Empty;
+ public double? Distance { get; set; }
+ public GeoPosition? Position { get; set; }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Geo/RedisGeoLocationService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Geo/RedisGeoLocationService.cs
new file mode 100644
index 0000000..45bd564
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Geo/RedisGeoLocationService.cs
@@ -0,0 +1,65 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using StackExchange.Redis;
+using WIDESEAWCS_RedisService.Connection;
+using WIDESEAWCS_RedisService.Options;
+
+namespace WIDESEAWCS_RedisService.Geo
+{
+ public class RedisGeoLocationService : IGeoLocationService
+ {
+ private readonly IRedisConnectionManager _connectionManager;
+ private readonly RedisOptions _options;
+ private readonly ILogger<RedisGeoLocationService> _logger;
+
+ public RedisGeoLocationService(
+ IRedisConnectionManager connectionManager,
+ IOptions<RedisOptions> options,
+ ILogger<RedisGeoLocationService> logger)
+ {
+ _connectionManager = connectionManager;
+ _options = options.Value;
+ _logger = logger;
+ }
+
+ private string BuildKey(string key) => $"{_options.KeyPrefix}geo:{key}";
+
+ public bool Add(string key, double longitude, double latitude, string member)
+ {
+ return _connectionManager.GetDatabase().GeoAdd(BuildKey(key), longitude, latitude, member);
+ }
+
+ public GeoPosition? GetPosition(string key, string member)
+ {
+ var pos = _connectionManager.GetDatabase().GeoPosition(BuildKey(key), member);
+ if (pos == null) return null;
+ return new GeoPosition { Longitude = pos.Value.Longitude, Latitude = pos.Value.Latitude };
+ }
+
+ public double? GetDistance(string key, string member1, string member2)
+ {
+ return _connectionManager.GetDatabase().GeoDistance(BuildKey(key), member1, member2, GeoUnit.Meters);
+ }
+
+ public List<GeoRadiusResult> SearchRadius(string key, double longitude, double latitude, double radiusMeters, int count = 10)
+ {
+ var results = _connectionManager.GetDatabase()
+ .GeoRadius(BuildKey(key), longitude, latitude, radiusMeters, GeoUnit.Meters,
+ count, Order.Ascending, GeoRadiusOptions.WithDistance | GeoRadiusOptions.WithCoordinates);
+
+ return results.Select(r => new GeoRadiusResult
+ {
+ Member = r.Member.ToString(),
+ Distance = r.Distance,
+ Position = r.Position.HasValue
+ ? new GeoPosition { Longitude = r.Position.Value.Longitude, Latitude = r.Position.Value.Latitude }
+ : null
+ }).ToList();
+ }
+
+ public bool Remove(string key, string member)
+ {
+ return _connectionManager.GetDatabase().SortedSetRemove(BuildKey(key), member);
+ }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/IdGenerator/IDistributedIdGenerator.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/IdGenerator/IDistributedIdGenerator.cs
new file mode 100644
index 0000000..28c53b1
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/IdGenerator/IDistributedIdGenerator.cs
@@ -0,0 +1,25 @@
+namespace WIDESEAWCS_RedisService.IdGenerator
+{
+ public interface IDistributedIdGenerator
+ {
+ /// <summary>
+ /// 鐢熸垚鑷ID
+ /// </summary>
+ long NextId(string sequenceName);
+
+ /// <summary>
+ /// 鐢熸垚甯︽棩鏈熷墠缂�鐨処D锛堝 20260228000001锛�
+ /// </summary>
+ string NextIdWithDate(string sequenceName);
+
+ /// <summary>
+ /// 鑾峰彇褰撳墠搴忓垪鍊�
+ /// </summary>
+ long GetCurrentId(string sequenceName);
+
+ /// <summary>
+ /// 閲嶇疆搴忓垪
+ /// </summary>
+ bool Reset(string sequenceName);
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/IdGenerator/RedisDistributedIdGenerator.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/IdGenerator/RedisDistributedIdGenerator.cs
new file mode 100644
index 0000000..0897e73
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/IdGenerator/RedisDistributedIdGenerator.cs
@@ -0,0 +1,56 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using WIDESEAWCS_RedisService.Connection;
+using WIDESEAWCS_RedisService.Options;
+
+namespace WIDESEAWCS_RedisService.IdGenerator
+{
+ public class RedisDistributedIdGenerator : IDistributedIdGenerator
+ {
+ private readonly IRedisConnectionManager _connectionManager;
+ private readonly RedisOptions _options;
+ private readonly ILogger<RedisDistributedIdGenerator> _logger;
+
+ public RedisDistributedIdGenerator(
+ IRedisConnectionManager connectionManager,
+ IOptions<RedisOptions> options,
+ ILogger<RedisDistributedIdGenerator> logger)
+ {
+ _connectionManager = connectionManager;
+ _options = options.Value;
+ _logger = logger;
+ }
+
+ private string BuildKey(string name) => $"{_options.KeyPrefix}id:{name}";
+
+ public long NextId(string sequenceName)
+ {
+ return _connectionManager.GetDatabase().StringIncrement(BuildKey(sequenceName));
+ }
+
+ public string NextIdWithDate(string sequenceName)
+ {
+ var datePrefix = DateTime.Now.ToString("yyyyMMdd");
+ var dailyKey = $"{BuildKey(sequenceName)}:{datePrefix}";
+ var db = _connectionManager.GetDatabase();
+ var seq = db.StringIncrement(dailyKey);
+
+ // 姣忔棩棣栨鐢熸垚鏃惰缃繃鏈熸椂闂达紙48灏忔椂锛岀暀浣欓噺锛�
+ if (seq == 1)
+ db.KeyExpire(dailyKey, TimeSpan.FromHours(48));
+
+ return $"{datePrefix}{seq:D6}";
+ }
+
+ public long GetCurrentId(string sequenceName)
+ {
+ var val = _connectionManager.GetDatabase().StringGet(BuildKey(sequenceName));
+ return val.IsNullOrEmpty ? 0 : (long)val;
+ }
+
+ public bool Reset(string sequenceName)
+ {
+ return _connectionManager.GetDatabase().KeyDelete(BuildKey(sequenceName));
+ }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Leaderboard/ILeaderboardService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Leaderboard/ILeaderboardService.cs
new file mode 100644
index 0000000..4a3d93c
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Leaderboard/ILeaderboardService.cs
@@ -0,0 +1,52 @@
+namespace WIDESEAWCS_RedisService.Leaderboard
+{
+ public interface ILeaderboardService
+ {
+ /// <summary>
+ /// 娣诲姞鎴栨洿鏂版垚鍛樺垎鏁�
+ /// </summary>
+ bool AddOrUpdate(string boardName, string member, double score);
+
+ /// <summary>
+ /// 澧炲姞鎴愬憳鍒嗘暟
+ /// </summary>
+ double IncrementScore(string boardName, string member, double increment);
+
+ /// <summary>
+ /// 鑾峰彇鎺掑悕锛堜粠楂樺埌浣庯紝0寮�濮嬶級
+ /// </summary>
+ long? GetRank(string boardName, string member);
+
+ /// <summary>
+ /// 鑾峰彇鎴愬憳鍒嗘暟
+ /// </summary>
+ double? GetScore(string boardName, string member);
+
+ /// <summary>
+ /// 鑾峰彇鎺掕姒滐紙浠庨珮鍒颁綆锛�
+ /// </summary>
+ List<LeaderboardEntry> GetTopN(string boardName, int count);
+
+ /// <summary>
+ /// 鑾峰彇鎸囧畾鎺掑悕鑼冨洿
+ /// </summary>
+ List<LeaderboardEntry> GetRange(string boardName, long start, long stop);
+
+ /// <summary>
+ /// 绉婚櫎鎴愬憳
+ /// </summary>
+ bool Remove(string boardName, string member);
+
+ /// <summary>
+ /// 鑾峰彇鎺掕姒滄�讳汉鏁�
+ /// </summary>
+ long GetCount(string boardName);
+ }
+
+ public class LeaderboardEntry
+ {
+ public string Member { get; set; } = string.Empty;
+ public double Score { get; set; }
+ public long Rank { get; set; }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Leaderboard/RedisLeaderboardService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Leaderboard/RedisLeaderboardService.cs
new file mode 100644
index 0000000..00e5d1a
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Leaderboard/RedisLeaderboardService.cs
@@ -0,0 +1,75 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using StackExchange.Redis;
+using WIDESEAWCS_RedisService.Connection;
+using WIDESEAWCS_RedisService.Options;
+
+namespace WIDESEAWCS_RedisService.Leaderboard
+{
+ public class RedisLeaderboardService : ILeaderboardService
+ {
+ private readonly IRedisConnectionManager _connectionManager;
+ private readonly RedisOptions _options;
+ private readonly ILogger<RedisLeaderboardService> _logger;
+
+ public RedisLeaderboardService(
+ IRedisConnectionManager connectionManager,
+ IOptions<RedisOptions> options,
+ ILogger<RedisLeaderboardService> logger)
+ {
+ _connectionManager = connectionManager;
+ _options = options.Value;
+ _logger = logger;
+ }
+
+ private string BuildKey(string key) => $"{_options.KeyPrefix}board:{key}";
+
+ public bool AddOrUpdate(string boardName, string member, double score)
+ {
+ return _connectionManager.GetDatabase().SortedSetAdd(BuildKey(boardName), member, score);
+ }
+
+ public double IncrementScore(string boardName, string member, double increment)
+ {
+ return _connectionManager.GetDatabase().SortedSetIncrement(BuildKey(boardName), member, increment);
+ }
+
+ public long? GetRank(string boardName, string member)
+ {
+ return _connectionManager.GetDatabase().SortedSetRank(BuildKey(boardName), member, Order.Descending);
+ }
+
+ public double? GetScore(string boardName, string member)
+ {
+ return _connectionManager.GetDatabase().SortedSetScore(BuildKey(boardName), member);
+ }
+
+ public List<LeaderboardEntry> GetTopN(string boardName, int count)
+ {
+ return GetRange(boardName, 0, count - 1);
+ }
+
+ public List<LeaderboardEntry> GetRange(string boardName, long start, long stop)
+ {
+ var entries = _connectionManager.GetDatabase()
+ .SortedSetRangeByRankWithScores(BuildKey(boardName), start, stop, Order.Descending);
+
+ return entries.Select((e, i) => new LeaderboardEntry
+ {
+ Member = e.Element.ToString(),
+ Score = e.Score,
+ Rank = start + i
+ }).ToList();
+ }
+
+ public bool Remove(string boardName, string member)
+ {
+ return _connectionManager.GetDatabase().SortedSetRemove(BuildKey(boardName), member);
+ }
+
+ public long GetCount(string boardName)
+ {
+ return _connectionManager.GetDatabase().SortedSetLength(BuildKey(boardName));
+ }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Lock/IDistributedLockService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Lock/IDistributedLockService.cs
new file mode 100644
index 0000000..fdb24f2
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Lock/IDistributedLockService.cs
@@ -0,0 +1,34 @@
+namespace WIDESEAWCS_RedisService.Lock
+{
+ public interface IDistributedLockService
+ {
+ /// <summary>
+ /// 鑾峰彇鍒嗗竷寮忛攣
+ /// </summary>
+ /// <param name="lockKey">閿佺殑Key</param>
+ /// <param name="expiry">閿佽繃鏈熸椂闂�</param>
+ /// <param name="waitTimeout">绛夊緟鑾峰彇閿佺殑瓒呮椂鏃堕棿</param>
+ /// <returns>閿乀oken锛岄噴鏀炬椂闇�瑕佷紶鍏ワ紱鑾峰彇澶辫触杩斿洖null</returns>
+ string? AcquireLock(string lockKey, TimeSpan expiry, TimeSpan? waitTimeout = null);
+
+ /// <summary>
+ /// 閲婃斁鍒嗗竷寮忛攣
+ /// </summary>
+ bool ReleaseLock(string lockKey, string lockToken);
+
+ /// <summary>
+ /// 缁湡閿�
+ /// </summary>
+ bool RenewLock(string lockKey, string lockToken, TimeSpan expiry);
+
+ /// <summary>
+ /// 浣跨敤閿佹墽琛屾搷浣�
+ /// </summary>
+ T? ExecuteWithLock<T>(string lockKey, TimeSpan expiry, Func<T> action, TimeSpan? waitTimeout = null);
+
+ /// <summary>
+ /// 浣跨敤閿佹墽琛屾搷浣滐紙鏃犺繑鍥炲�硷級
+ /// </summary>
+ bool ExecuteWithLock(string lockKey, TimeSpan expiry, Action action, TimeSpan? waitTimeout = null);
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Lock/RedisDistributedLockService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Lock/RedisDistributedLockService.cs
new file mode 100644
index 0000000..7b4fbbe
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Lock/RedisDistributedLockService.cs
@@ -0,0 +1,112 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using StackExchange.Redis;
+using WIDESEAWCS_RedisService.Connection;
+using WIDESEAWCS_RedisService.Options;
+
+namespace WIDESEAWCS_RedisService.Lock
+{
+ public class RedisDistributedLockService : IDistributedLockService
+ {
+ private readonly IRedisConnectionManager _connectionManager;
+ private readonly RedisOptions _options;
+ private readonly ILogger<RedisDistributedLockService> _logger;
+
+ // Lua鑴氭湰锛氬畨鍏ㄩ噴鏀鹃攣锛堝彧鏈夋寔鏈夎�呮墠鑳介噴鏀撅級
+ private const string ReleaseLockScript = @"
+ if redis.call('get', KEYS[1]) == ARGV[1] then
+ return redis.call('del', KEYS[1])
+ else
+ return 0
+ end";
+
+ // Lua鑴氭湰锛氬畨鍏ㄧ画鏈熼攣
+ private const string RenewLockScript = @"
+ if redis.call('get', KEYS[1]) == ARGV[1] then
+ return redis.call('pexpire', KEYS[1], ARGV[2])
+ else
+ return 0
+ end";
+
+ public RedisDistributedLockService(
+ IRedisConnectionManager connectionManager,
+ IOptions<RedisOptions> options,
+ ILogger<RedisDistributedLockService> logger)
+ {
+ _connectionManager = connectionManager;
+ _options = options.Value;
+ _logger = logger;
+ }
+
+ private string BuildKey(string key) => $"{_options.KeyPrefix}lock:{key}";
+
+ public string? AcquireLock(string lockKey, TimeSpan expiry, TimeSpan? waitTimeout = null)
+ {
+ var fullKey = BuildKey(lockKey);
+ var token = Guid.NewGuid().ToString("N");
+ var db = _connectionManager.GetDatabase();
+ var deadline = DateTime.UtcNow + (waitTimeout ?? TimeSpan.Zero);
+
+ do
+ {
+ if (db.StringSet(fullKey, token, expiry, When.NotExists))
+ return token;
+
+ if (waitTimeout == null) return null;
+ Thread.Sleep(50);
+ }
+ while (DateTime.UtcNow < deadline);
+
+ return null;
+ }
+
+ public bool ReleaseLock(string lockKey, string lockToken)
+ {
+ var db = _connectionManager.GetDatabase();
+ var result = db.ScriptEvaluate(
+ ReleaseLockScript,
+ new RedisKey[] { BuildKey(lockKey) },
+ new RedisValue[] { lockToken });
+ return (long)result == 1;
+ }
+
+ public bool RenewLock(string lockKey, string lockToken, TimeSpan expiry)
+ {
+ var db = _connectionManager.GetDatabase();
+ var result = db.ScriptEvaluate(
+ RenewLockScript,
+ new RedisKey[] { BuildKey(lockKey) },
+ new RedisValue[] { lockToken, (long)expiry.TotalMilliseconds });
+ return (long)result == 1;
+ }
+
+ public T? ExecuteWithLock<T>(string lockKey, TimeSpan expiry, Func<T> action, TimeSpan? waitTimeout = null)
+ {
+ var token = AcquireLock(lockKey, expiry, waitTimeout);
+ if (token == null) return default;
+ try
+ {
+ return action();
+ }
+ finally
+ {
+ ReleaseLock(lockKey, token);
+ }
+ }
+
+ public bool ExecuteWithLock(string lockKey, TimeSpan expiry, Action action, TimeSpan? waitTimeout = null)
+ {
+ var token = AcquireLock(lockKey, expiry, waitTimeout);
+ if (token == null) return false;
+ try
+ {
+ action();
+ return true;
+ }
+ finally
+ {
+ ReleaseLock(lockKey, token);
+ }
+ }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Monitoring/IRedisMonitorService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Monitoring/IRedisMonitorService.cs
new file mode 100644
index 0000000..c7ba7d5
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Monitoring/IRedisMonitorService.cs
@@ -0,0 +1,39 @@
+namespace WIDESEAWCS_RedisService.Monitoring
+{
+ public interface IRedisMonitorService
+ {
+ /// <summary>
+ /// 鑾峰彇Redis鏈嶅姟鍣ㄤ俊鎭�
+ /// </summary>
+ Dictionary<string, string> GetServerInfo();
+
+ /// <summary>
+ /// 鑾峰彇鍐呭瓨浣跨敤淇℃伅
+ /// </summary>
+ RedisMemoryInfo GetMemoryInfo();
+
+ /// <summary>
+ /// 鍋ュ悍妫�鏌�
+ /// </summary>
+ bool HealthCheck();
+
+ /// <summary>
+ /// 鑾峰彇鏁版嵁搴揔ey鏁伴噺
+ /// </summary>
+ long GetDbSize();
+
+ /// <summary>
+ /// 鑾峰彇瀹㈡埛绔繛鎺ユ暟
+ /// </summary>
+ long GetClientCount();
+ }
+
+ public class RedisMemoryInfo
+ {
+ public long UsedMemory { get; set; }
+ public string UsedMemoryHuman { get; set; } = string.Empty;
+ public long MaxMemory { get; set; }
+ public string MaxMemoryHuman { get; set; } = string.Empty;
+ public double UsagePercent { get; set; }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Monitoring/RedisMonitorService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Monitoring/RedisMonitorService.cs
new file mode 100644
index 0000000..55bb693
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Monitoring/RedisMonitorService.cs
@@ -0,0 +1,91 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using WIDESEAWCS_RedisService.Connection;
+using WIDESEAWCS_RedisService.Options;
+
+namespace WIDESEAWCS_RedisService.Monitoring
+{
+ public class RedisMonitorService : IRedisMonitorService
+ {
+ private readonly IRedisConnectionManager _connectionManager;
+ private readonly RedisOptions _options;
+ private readonly ILogger<RedisMonitorService> _logger;
+
+ public RedisMonitorService(
+ IRedisConnectionManager connectionManager,
+ IOptions<RedisOptions> options,
+ ILogger<RedisMonitorService> logger)
+ {
+ _connectionManager = connectionManager;
+ _options = options.Value;
+ _logger = logger;
+ }
+
+ public Dictionary<string, string> GetServerInfo()
+ {
+ var server = _connectionManager.GetServer();
+ var info = server.Info();
+ var result = new Dictionary<string, string>();
+ foreach (var group in info)
+ {
+ foreach (var item in group)
+ result[$"{group.Key}:{item.Key}"] = item.Value;
+ }
+ return result;
+ }
+
+ public RedisMemoryInfo GetMemoryInfo()
+ {
+ var server = _connectionManager.GetServer();
+ var info = server.Info("memory");
+ var memorySection = info.FirstOrDefault();
+
+ var memInfo = new RedisMemoryInfo();
+ if (memorySection == null) return memInfo;
+
+ var dict = memorySection.ToDictionary(x => x.Key, x => x.Value);
+ if (dict.TryGetValue("used_memory", out var used))
+ memInfo.UsedMemory = long.Parse(used);
+ if (dict.TryGetValue("used_memory_human", out var usedH))
+ memInfo.UsedMemoryHuman = usedH;
+ if (dict.TryGetValue("maxmemory", out var max))
+ memInfo.MaxMemory = long.Parse(max);
+ if (dict.TryGetValue("maxmemory_human", out var maxH))
+ memInfo.MaxMemoryHuman = maxH;
+
+ if (memInfo.MaxMemory > 0)
+ memInfo.UsagePercent = Math.Round((double)memInfo.UsedMemory / memInfo.MaxMemory * 100, 2);
+
+ return memInfo;
+ }
+
+ public bool HealthCheck()
+ {
+ try
+ {
+ var db = _connectionManager.GetDatabase();
+ var pong = db.Ping();
+ return pong.TotalMilliseconds < 5000;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Redis鍋ュ悍妫�鏌ュけ璐�");
+ return false;
+ }
+ }
+
+ public long GetDbSize()
+ {
+ return _connectionManager.GetServer().DatabaseSize();
+ }
+
+ public long GetClientCount()
+ {
+ var info = _connectionManager.GetServer().Info("clients");
+ var section = info.FirstOrDefault();
+ if (section == null) return 0;
+ var dict = section.ToDictionary(x => x.Key, x => x.Value);
+ return dict.TryGetValue("connected_clients", out var count) ? long.Parse(count) : 0;
+ }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Options/RedisOptions.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Options/RedisOptions.cs
new file mode 100644
index 0000000..8b8a824
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Options/RedisOptions.cs
@@ -0,0 +1,49 @@
+namespace WIDESEAWCS_RedisService.Options
+{
+ public class RedisOptions
+ {
+ public bool Enabled { get; set; } = true;
+
+ public string ConnectionString { get; set; } = "127.0.0.1:6379,defaultDatabase=0,connectTimeout=5000,abortConnect=false";
+
+ public string InstanceName { get; set; } = "WIDESEAWCS:";
+
+ public int DefaultDatabase { get; set; } = 0;
+
+ public bool EnableSentinel { get; set; } = false;
+
+ public string SentinelMasterName { get; set; } = "mymaster";
+
+ public List<string> SentinelEndpoints { get; set; } = new();
+
+ public int PoolSize { get; set; } = 10;
+
+ public int ConnectRetry { get; set; } = 3;
+
+ public string SerializerType { get; set; } = "Newtonsoft";
+
+ public bool FallbackToMemory { get; set; } = true;
+
+ public string KeyPrefix { get; set; } = "wcs:";
+
+ public MonitoringOptions Monitoring { get; set; } = new();
+
+ public EvictionOptions Eviction { get; set; } = new();
+ }
+
+ public class MonitoringOptions
+ {
+ public bool Enabled { get; set; } = false;
+
+ public int SlowLogThresholdMs { get; set; } = 100;
+
+ public int HealthCheckIntervalSeconds { get; set; } = 30;
+ }
+
+ public class EvictionOptions
+ {
+ public int DefaultExpirationSeconds { get; set; } = 3600;
+
+ public string MaxMemoryPolicy { get; set; } = "allkeys-lru";
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/PubSub/IMessageQueueService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/PubSub/IMessageQueueService.cs
new file mode 100644
index 0000000..0f33418
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/PubSub/IMessageQueueService.cs
@@ -0,0 +1,35 @@
+namespace WIDESEAWCS_RedisService.PubSub
+{
+ public interface IMessageQueueService
+ {
+ /// <summary>
+ /// 鍙戝竷娑堟伅
+ /// </summary>
+ long Publish(string channel, string message);
+
+ /// <summary>
+ /// 璁㈤槄棰戦亾
+ /// </summary>
+ void Subscribe(string channel, Action<string, string> handler);
+
+ /// <summary>
+ /// 鍙栨秷璁㈤槄
+ /// </summary>
+ void Unsubscribe(string channel);
+
+ /// <summary>
+ /// 鎺ㄩ�佹秷鎭埌鍙潬闃熷垪锛圠ist锛�
+ /// </summary>
+ long Enqueue(string queueName, string message);
+
+ /// <summary>
+ /// 浠庡彲闈犻槦鍒楀脊鍑烘秷鎭�
+ /// </summary>
+ string? Dequeue(string queueName, TimeSpan? timeout = null);
+
+ /// <summary>
+ /// 鑾峰彇闃熷垪闀垮害
+ /// </summary>
+ long GetQueueLength(string queueName);
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/PubSub/RedisMessageQueueService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/PubSub/RedisMessageQueueService.cs
new file mode 100644
index 0000000..9d1076a
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/PubSub/RedisMessageQueueService.cs
@@ -0,0 +1,64 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using StackExchange.Redis;
+using WIDESEAWCS_RedisService.Connection;
+using WIDESEAWCS_RedisService.Options;
+
+namespace WIDESEAWCS_RedisService.PubSub
+{
+ public class RedisMessageQueueService : IMessageQueueService
+ {
+ private readonly IRedisConnectionManager _connectionManager;
+ private readonly RedisOptions _options;
+ private readonly ILogger<RedisMessageQueueService> _logger;
+
+ public RedisMessageQueueService(
+ IRedisConnectionManager connectionManager,
+ IOptions<RedisOptions> options,
+ ILogger<RedisMessageQueueService> logger)
+ {
+ _connectionManager = connectionManager;
+ _options = options.Value;
+ _logger = logger;
+ }
+
+ private string BuildKey(string key) => $"{_options.KeyPrefix}queue:{key}";
+
+ public long Publish(string channel, string message)
+ {
+ var sub = _connectionManager.GetSubscriber();
+ return sub.Publish(RedisChannel.Literal($"{_options.KeyPrefix}{channel}"), message);
+ }
+
+ public void Subscribe(string channel, Action<string, string> handler)
+ {
+ var sub = _connectionManager.GetSubscriber();
+ sub.Subscribe(RedisChannel.Literal($"{_options.KeyPrefix}{channel}"), (ch, msg) =>
+ {
+ handler(ch!, msg!);
+ });
+ }
+
+ public void Unsubscribe(string channel)
+ {
+ var sub = _connectionManager.GetSubscriber();
+ sub.Unsubscribe(RedisChannel.Literal($"{_options.KeyPrefix}{channel}"));
+ }
+
+ public long Enqueue(string queueName, string message)
+ {
+ return _connectionManager.GetDatabase().ListLeftPush(BuildKey(queueName), message);
+ }
+
+ public string? Dequeue(string queueName, TimeSpan? timeout = null)
+ {
+ var val = _connectionManager.GetDatabase().ListRightPop(BuildKey(queueName));
+ return val.IsNullOrEmpty ? null : val.ToString();
+ }
+
+ public long GetQueueLength(string queueName)
+ {
+ return _connectionManager.GetDatabase().ListLength(BuildKey(queueName));
+ }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/RateLimiting/IRateLimitingService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/RateLimiting/IRateLimitingService.cs
new file mode 100644
index 0000000..ff0d52c
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/RateLimiting/IRateLimitingService.cs
@@ -0,0 +1,25 @@
+namespace WIDESEAWCS_RedisService.RateLimiting
+{
+ public interface IRateLimitingService
+ {
+ /// <summary>
+ /// 鍥哄畾绐楀彛闄愭祦
+ /// </summary>
+ bool IsAllowed(string key, int maxRequests, TimeSpan window);
+
+ /// <summary>
+ /// 婊戝姩绐楀彛闄愭祦
+ /// </summary>
+ bool IsAllowedSliding(string key, int maxRequests, TimeSpan window);
+
+ /// <summary>
+ /// 浠ょ墝妗堕檺娴�
+ /// </summary>
+ bool TryAcquireToken(string key, int maxTokens, int refillRate, TimeSpan refillInterval);
+
+ /// <summary>
+ /// 鑾峰彇鍓╀綑璇锋眰鏁�
+ /// </summary>
+ long GetRemainingRequests(string key, int maxRequests, TimeSpan window);
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/RateLimiting/RedisRateLimitingService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/RateLimiting/RedisRateLimitingService.cs
new file mode 100644
index 0000000..ec3c47f
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/RateLimiting/RedisRateLimitingService.cs
@@ -0,0 +1,113 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using StackExchange.Redis;
+using WIDESEAWCS_RedisService.Connection;
+using WIDESEAWCS_RedisService.Options;
+
+namespace WIDESEAWCS_RedisService.RateLimiting
+{
+ public class RedisRateLimitingService : IRateLimitingService
+ {
+ private readonly IRedisConnectionManager _connectionManager;
+ private readonly RedisOptions _options;
+ private readonly ILogger<RedisRateLimitingService> _logger;
+
+ private const string FixedWindowScript = @"
+ local key = KEYS[1]
+ local limit = tonumber(ARGV[1])
+ local window = tonumber(ARGV[2])
+ local current = tonumber(redis.call('GET', key) or '0')
+ if current < limit then
+ redis.call('INCR', key)
+ if current == 0 then
+ redis.call('PEXPIRE', key, window)
+ end
+ return 1
+ end
+ return 0";
+
+ public RedisRateLimitingService(
+ IRedisConnectionManager connectionManager,
+ IOptions<RedisOptions> options,
+ ILogger<RedisRateLimitingService> logger)
+ {
+ _connectionManager = connectionManager;
+ _options = options.Value;
+ _logger = logger;
+ }
+
+ private string BuildKey(string key) => $"{_options.KeyPrefix}rate:{key}";
+
+ public bool IsAllowed(string key, int maxRequests, TimeSpan window)
+ {
+ var db = _connectionManager.GetDatabase();
+ var result = db.ScriptEvaluate(
+ FixedWindowScript,
+ new RedisKey[] { BuildKey(key) },
+ new RedisValue[] { maxRequests, (long)window.TotalMilliseconds });
+ return (long)result == 1;
+ }
+
+ public bool IsAllowedSliding(string key, int maxRequests, TimeSpan window)
+ {
+ var db = _connectionManager.GetDatabase();
+ var fullKey = BuildKey(key);
+ var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+ var windowMs = (long)window.TotalMilliseconds;
+
+ var tran = db.CreateTransaction();
+ tran.SortedSetRemoveRangeByScoreAsync(fullKey, 0, now - windowMs);
+ tran.SortedSetAddAsync(fullKey, now.ToString(), now);
+ tran.KeyExpireAsync(fullKey, window.Add(TimeSpan.FromSeconds(1)));
+ tran.Execute();
+
+ var count = db.SortedSetLength(fullKey);
+ if (count > maxRequests)
+ {
+ db.SortedSetRemove(fullKey, now.ToString());
+ return false;
+ }
+ return true;
+ }
+
+ public bool TryAcquireToken(string key, int maxTokens, int refillRate, TimeSpan refillInterval)
+ {
+ var db = _connectionManager.GetDatabase();
+ var fullKey = BuildKey($"token:{key}");
+ var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
+
+ var script = @"
+ local key = KEYS[1]
+ local max = tonumber(ARGV[1])
+ local rate = tonumber(ARGV[2])
+ local interval = tonumber(ARGV[3])
+ local now = tonumber(ARGV[4])
+ local info = redis.call('HMGET', key, 'tokens', 'last')
+ local tokens = tonumber(info[1]) or max
+ local last = tonumber(info[2]) or now
+ local elapsed = now - last
+ local refill = math.floor(elapsed / interval) * rate
+ tokens = math.min(max, tokens + refill)
+ if tokens > 0 then
+ tokens = tokens - 1
+ redis.call('HMSET', key, 'tokens', tokens, 'last', now)
+ redis.call('PEXPIRE', key, interval * max / rate * 2)
+ return 1
+ end
+ return 0";
+
+ var result = db.ScriptEvaluate(script,
+ new RedisKey[] { fullKey },
+ new RedisValue[] { maxTokens, refillRate, (long)refillInterval.TotalMilliseconds, now });
+ return (long)result == 1;
+ }
+
+ public long GetRemainingRequests(string key, int maxRequests, TimeSpan window)
+ {
+ var db = _connectionManager.GetDatabase();
+ var val = db.StringGet(BuildKey(key));
+ if (val.IsNullOrEmpty) return maxRequests;
+ return Math.Max(0, maxRequests - (long)val);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Serialization/IRedisSerializer.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Serialization/IRedisSerializer.cs
new file mode 100644
index 0000000..d93ef7e
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Serialization/IRedisSerializer.cs
@@ -0,0 +1,11 @@
+namespace WIDESEAWCS_RedisService.Serialization
+{
+ public interface IRedisSerializer
+ {
+ string Serialize<T>(T value);
+
+ T? Deserialize<T>(string value);
+
+ object? Deserialize(string value, Type type);
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Serialization/NewtonsoftRedisSerializer.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Serialization/NewtonsoftRedisSerializer.cs
new file mode 100644
index 0000000..c2a11ff
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Serialization/NewtonsoftRedisSerializer.cs
@@ -0,0 +1,31 @@
+using Newtonsoft.Json;
+
+namespace WIDESEAWCS_RedisService.Serialization
+{
+ public class NewtonsoftRedisSerializer : IRedisSerializer
+ {
+ private static readonly JsonSerializerSettings _settings = new()
+ {
+ ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
+ NullValueHandling = NullValueHandling.Ignore,
+ DateFormatString = "yyyy-MM-dd HH:mm:ss"
+ };
+
+ public string Serialize<T>(T value)
+ {
+ return JsonConvert.SerializeObject(value, _settings);
+ }
+
+ public T? Deserialize<T>(string value)
+ {
+ if (string.IsNullOrEmpty(value)) return default;
+ return JsonConvert.DeserializeObject<T>(value, _settings);
+ }
+
+ public object? Deserialize(string value, Type type)
+ {
+ if (string.IsNullOrEmpty(value)) return null;
+ return JsonConvert.DeserializeObject(value, type, _settings);
+ }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Session/ISessionStorage.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Session/ISessionStorage.cs
new file mode 100644
index 0000000..82e2c73
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Session/ISessionStorage.cs
@@ -0,0 +1,12 @@
+namespace WIDESEAWCS_RedisService.Session
+{
+ public interface ISessionStorage
+ {
+ bool Set(string sessionId, string key, string value, TimeSpan? expiry = null);
+ string? Get(string sessionId, string key);
+ bool Remove(string sessionId, string key);
+ bool DestroySession(string sessionId);
+ bool SessionExists(string sessionId);
+ bool RefreshSession(string sessionId, TimeSpan expiry);
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Session/RedisSessionStorage.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Session/RedisSessionStorage.cs
new file mode 100644
index 0000000..953ddb7
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Session/RedisSessionStorage.cs
@@ -0,0 +1,63 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using StackExchange.Redis;
+using WIDESEAWCS_RedisService.Connection;
+using WIDESEAWCS_RedisService.Options;
+
+namespace WIDESEAWCS_RedisService.Session
+{
+ public class RedisSessionStorage : ISessionStorage
+ {
+ private readonly IRedisConnectionManager _connectionManager;
+ private readonly RedisOptions _options;
+ private readonly ILogger<RedisSessionStorage> _logger;
+
+ public RedisSessionStorage(
+ IRedisConnectionManager connectionManager,
+ IOptions<RedisOptions> options,
+ ILogger<RedisSessionStorage> logger)
+ {
+ _connectionManager = connectionManager;
+ _options = options.Value;
+ _logger = logger;
+ }
+
+ private string BuildKey(string sessionId) => $"{_options.KeyPrefix}session:{sessionId}";
+
+ public bool Set(string sessionId, string key, string value, TimeSpan? expiry = null)
+ {
+ var db = _connectionManager.GetDatabase();
+ var fullKey = BuildKey(sessionId);
+ db.HashSet(fullKey, key, value);
+ if (expiry.HasValue)
+ db.KeyExpire(fullKey, expiry);
+ return true;
+ }
+
+ public string? Get(string sessionId, string key)
+ {
+ var val = _connectionManager.GetDatabase().HashGet(BuildKey(sessionId), key);
+ return val.IsNullOrEmpty ? null : val.ToString();
+ }
+
+ public bool Remove(string sessionId, string key)
+ {
+ return _connectionManager.GetDatabase().HashDelete(BuildKey(sessionId), key);
+ }
+
+ public bool DestroySession(string sessionId)
+ {
+ return _connectionManager.GetDatabase().KeyDelete(BuildKey(sessionId));
+ }
+
+ public bool SessionExists(string sessionId)
+ {
+ return _connectionManager.GetDatabase().KeyExists(BuildKey(sessionId));
+ }
+
+ public bool RefreshSession(string sessionId, TimeSpan expiry)
+ {
+ return _connectionManager.GetDatabase().KeyExpire(BuildKey(sessionId), expiry);
+ }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Storage/IObjectStorageService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Storage/IObjectStorageService.cs
new file mode 100644
index 0000000..b5db548
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Storage/IObjectStorageService.cs
@@ -0,0 +1,40 @@
+namespace WIDESEAWCS_RedisService.Storage
+{
+ public interface IObjectStorageService
+ {
+ /// <summary>
+ /// 瀛樺偍瀵硅薄锛圚ash缁撴瀯锛�
+ /// </summary>
+ bool SetObject<T>(string key, T value, TimeSpan? expiry = null) where T : class;
+
+ /// <summary>
+ /// 鑾峰彇瀵硅薄
+ /// </summary>
+ T? GetObject<T>(string key) where T : class;
+
+ /// <summary>
+ /// 璁剧疆瀵硅薄鐨勬煇涓瓧娈�
+ /// </summary>
+ bool SetField(string key, string field, string value);
+
+ /// <summary>
+ /// 鑾峰彇瀵硅薄鐨勬煇涓瓧娈�
+ /// </summary>
+ string? GetField(string key, string field);
+
+ /// <summary>
+ /// 鍒犻櫎瀵硅薄
+ /// </summary>
+ bool Delete(string key);
+
+ /// <summary>
+ /// 鍒犻櫎瀵硅薄鐨勬煇涓瓧娈�
+ /// </summary>
+ bool DeleteField(string key, string field);
+
+ /// <summary>
+ /// 鍒ゆ柇瀵硅薄鏄惁瀛樺湪
+ /// </summary>
+ bool Exists(string key);
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Storage/RedisObjectStorageService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Storage/RedisObjectStorageService.cs
new file mode 100644
index 0000000..fb176d9
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Storage/RedisObjectStorageService.cs
@@ -0,0 +1,71 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using StackExchange.Redis;
+using WIDESEAWCS_RedisService.Connection;
+using WIDESEAWCS_RedisService.Options;
+using WIDESEAWCS_RedisService.Serialization;
+
+namespace WIDESEAWCS_RedisService.Storage
+{
+ public class RedisObjectStorageService : IObjectStorageService
+ {
+ private readonly IRedisConnectionManager _connectionManager;
+ private readonly IRedisSerializer _serializer;
+ private readonly RedisOptions _options;
+ private readonly ILogger<RedisObjectStorageService> _logger;
+
+ public RedisObjectStorageService(
+ IRedisConnectionManager connectionManager,
+ IRedisSerializer serializer,
+ IOptions<RedisOptions> options,
+ ILogger<RedisObjectStorageService> logger)
+ {
+ _connectionManager = connectionManager;
+ _serializer = serializer;
+ _options = options.Value;
+ _logger = logger;
+ }
+
+ private string BuildKey(string key) => $"{_options.KeyPrefix}obj:{key}";
+
+ public bool SetObject<T>(string key, T value, TimeSpan? expiry = null) where T : class
+ {
+ var db = _connectionManager.GetDatabase();
+ var fullKey = BuildKey(key);
+ var json = _serializer.Serialize(value);
+ return db.StringSet(fullKey, json, expiry);
+ }
+
+ public T? GetObject<T>(string key) where T : class
+ {
+ var val = _connectionManager.GetDatabase().StringGet(BuildKey(key));
+ return val.IsNullOrEmpty ? default : _serializer.Deserialize<T>(val!);
+ }
+
+ public bool SetField(string key, string field, string value)
+ {
+ return _connectionManager.GetDatabase().HashSet(BuildKey(key), field, value);
+ }
+
+ public string? GetField(string key, string field)
+ {
+ var val = _connectionManager.GetDatabase().HashGet(BuildKey(key), field);
+ return val.IsNullOrEmpty ? null : val.ToString();
+ }
+
+ public bool Delete(string key)
+ {
+ return _connectionManager.GetDatabase().KeyDelete(BuildKey(key));
+ }
+
+ public bool DeleteField(string key, string field)
+ {
+ return _connectionManager.GetDatabase().HashDelete(BuildKey(key), field);
+ }
+
+ public bool Exists(string key)
+ {
+ return _connectionManager.GetDatabase().KeyExists(BuildKey(key));
+ }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Stream/IStreamProcessingService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Stream/IStreamProcessingService.cs
new file mode 100644
index 0000000..c938546
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Stream/IStreamProcessingService.cs
@@ -0,0 +1,41 @@
+namespace WIDESEAWCS_RedisService.Stream
+{
+ public interface IStreamProcessingService
+ {
+ /// <summary>
+ /// 鍙戦�佹秷鎭埌Stream
+ /// </summary>
+ string AddMessage(string streamKey, Dictionary<string, string> fields);
+
+ /// <summary>
+ /// 鍒涘缓娑堣垂鑰呯粍
+ /// </summary>
+ bool CreateConsumerGroup(string streamKey, string groupName, string startId = "$");
+
+ /// <summary>
+ /// 璇诲彇娑堟伅锛堟秷璐硅�呯粍妯″紡锛�
+ /// </summary>
+ List<StreamEntry> ReadGroup(string streamKey, string groupName, string consumerName, int count = 10);
+
+ /// <summary>
+ /// 纭娑堟伅
+ /// </summary>
+ long Acknowledge(string streamKey, string groupName, params string[] messageIds);
+
+ /// <summary>
+ /// 鑾峰彇Stream闀垮害
+ /// </summary>
+ long GetStreamLength(string streamKey);
+
+ /// <summary>
+ /// 瑁佸壀Stream
+ /// </summary>
+ long TrimStream(string streamKey, int maxLength);
+ }
+
+ public class StreamEntry
+ {
+ public string Id { get; set; } = string.Empty;
+ public Dictionary<string, string> Fields { get; set; } = new();
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Stream/RedisStreamProcessingService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Stream/RedisStreamProcessingService.cs
new file mode 100644
index 0000000..a10c568
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/Stream/RedisStreamProcessingService.cs
@@ -0,0 +1,76 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using StackExchange.Redis;
+using WIDESEAWCS_RedisService.Connection;
+using WIDESEAWCS_RedisService.Options;
+
+namespace WIDESEAWCS_RedisService.Stream
+{
+ public class RedisStreamProcessingService : IStreamProcessingService
+ {
+ private readonly IRedisConnectionManager _connectionManager;
+ private readonly RedisOptions _options;
+ private readonly ILogger<RedisStreamProcessingService> _logger;
+
+ public RedisStreamProcessingService(
+ IRedisConnectionManager connectionManager,
+ IOptions<RedisOptions> options,
+ ILogger<RedisStreamProcessingService> logger)
+ {
+ _connectionManager = connectionManager;
+ _options = options.Value;
+ _logger = logger;
+ }
+
+ private string BuildKey(string key) => $"{_options.KeyPrefix}stream:{key}";
+
+ public string AddMessage(string streamKey, Dictionary<string, string> fields)
+ {
+ var entries = fields.Select(f => new NameValueEntry(f.Key, f.Value)).ToArray();
+ var id = _connectionManager.GetDatabase().StreamAdd(BuildKey(streamKey), entries);
+ return id.ToString();
+ }
+
+ public bool CreateConsumerGroup(string streamKey, string groupName, string startId = "$")
+ {
+ try
+ {
+ return _connectionManager.GetDatabase()
+ .StreamCreateConsumerGroup(BuildKey(streamKey), groupName, startId, true);
+ }
+ catch (RedisServerException ex) when (ex.Message.Contains("BUSYGROUP"))
+ {
+ _logger.LogWarning("娑堣垂鑰呯粍 {Group} 宸插瓨鍦�", groupName);
+ return true;
+ }
+ }
+
+ public List<StreamEntry> ReadGroup(string streamKey, string groupName, string consumerName, int count = 10)
+ {
+ var entries = _connectionManager.GetDatabase()
+ .StreamReadGroup(BuildKey(streamKey), groupName, consumerName, ">", count);
+
+ return entries?.Select(e => new StreamEntry
+ {
+ Id = e.Id.ToString(),
+ Fields = e.Values.ToDictionary(v => v.Name.ToString(), v => v.Value.ToString())
+ }).ToList() ?? new List<StreamEntry>();
+ }
+
+ public long Acknowledge(string streamKey, string groupName, params string[] messageIds)
+ {
+ var ids = messageIds.Select(id => new RedisValue(id)).ToArray();
+ return _connectionManager.GetDatabase().StreamAcknowledge(BuildKey(streamKey), groupName, ids);
+ }
+
+ public long GetStreamLength(string streamKey)
+ {
+ return _connectionManager.GetDatabase().StreamLength(BuildKey(streamKey));
+ }
+
+ public long TrimStream(string streamKey, int maxLength)
+ {
+ return _connectionManager.GetDatabase().StreamTrim(BuildKey(streamKey), maxLength);
+ }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/WIDESEAWCS_RedisService.csproj b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/WIDESEAWCS_RedisService.csproj
new file mode 100644
index 0000000..428d0ea
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_RedisService/WIDESEAWCS_RedisService.csproj
@@ -0,0 +1,21 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>net6.0</TargetFramework>
+ <ImplicitUsings>enable</ImplicitUsings>
+ <Nullable>enable</Nullable>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="StackExchange.Redis" Version="2.7.33" />
+ <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
+ <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
+ <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="6.0.0" />
+ <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\WIDESEAWCS_Core\WIDESEAWCS_Core.csproj" />
+ </ItemGroup>
+
+</Project>
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server.sln b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server.sln
index 476b4cd..795321d 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server.sln
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server.sln
@@ -64,92 +64,270 @@
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WIDESEAWCS_BasicInfoService", "WIDESEAWCS_BasicInfoService\WIDESEAWCS_BasicInfoService.csproj", "{FFAB2C76-1C9E-4006-95C8-A0B2AA53139D}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WIDESEAWCS_RedisService", "WIDESEAWCS_RedisService\WIDESEAWCS_RedisService.csproj", "{F9886971-C3B2-4334-B014-D5109F2041DE}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}.Debug|x64.Build.0 = Debug|Any CPU
+ {487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}.Debug|x86.Build.0 = Debug|Any CPU
{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}.Release|x64.ActiveCfg = Release|Any CPU
+ {487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}.Release|x64.Build.0 = Release|Any CPU
+ {487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}.Release|x86.ActiveCfg = Release|Any CPU
+ {487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}.Release|x86.Build.0 = Release|Any CPU
{294E4915-0241-4C8C-BA99-7588B945863A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{294E4915-0241-4C8C-BA99-7588B945863A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {294E4915-0241-4C8C-BA99-7588B945863A}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {294E4915-0241-4C8C-BA99-7588B945863A}.Debug|x64.Build.0 = Debug|Any CPU
+ {294E4915-0241-4C8C-BA99-7588B945863A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {294E4915-0241-4C8C-BA99-7588B945863A}.Debug|x86.Build.0 = Debug|Any CPU
{294E4915-0241-4C8C-BA99-7588B945863A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{294E4915-0241-4C8C-BA99-7588B945863A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {294E4915-0241-4C8C-BA99-7588B945863A}.Release|x64.ActiveCfg = Release|Any CPU
+ {294E4915-0241-4C8C-BA99-7588B945863A}.Release|x64.Build.0 = Release|Any CPU
+ {294E4915-0241-4C8C-BA99-7588B945863A}.Release|x86.ActiveCfg = Release|Any CPU
+ {294E4915-0241-4C8C-BA99-7588B945863A}.Release|x86.Build.0 = Release|Any CPU
{6236BFFF-173D-44A8-9FC3-7C001EA30347}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6236BFFF-173D-44A8-9FC3-7C001EA30347}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6236BFFF-173D-44A8-9FC3-7C001EA30347}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {6236BFFF-173D-44A8-9FC3-7C001EA30347}.Debug|x64.Build.0 = Debug|Any CPU
+ {6236BFFF-173D-44A8-9FC3-7C001EA30347}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6236BFFF-173D-44A8-9FC3-7C001EA30347}.Debug|x86.Build.0 = Debug|Any CPU
{6236BFFF-173D-44A8-9FC3-7C001EA30347}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6236BFFF-173D-44A8-9FC3-7C001EA30347}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6236BFFF-173D-44A8-9FC3-7C001EA30347}.Release|x64.ActiveCfg = Release|Any CPU
+ {6236BFFF-173D-44A8-9FC3-7C001EA30347}.Release|x64.Build.0 = Release|Any CPU
+ {6236BFFF-173D-44A8-9FC3-7C001EA30347}.Release|x86.ActiveCfg = Release|Any CPU
+ {6236BFFF-173D-44A8-9FC3-7C001EA30347}.Release|x86.Build.0 = Release|Any CPU
{7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}.Debug|x64.Build.0 = Debug|Any CPU
+ {7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}.Debug|x86.Build.0 = Debug|Any CPU
{7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}.Release|x64.ActiveCfg = Release|Any CPU
+ {7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}.Release|x64.Build.0 = Release|Any CPU
+ {7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}.Release|x86.ActiveCfg = Release|Any CPU
+ {7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}.Release|x86.Build.0 = Release|Any CPU
{C2D3D138-9109-481B-8BEB-A27597890B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C2D3D138-9109-481B-8BEB-A27597890B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C2D3D138-9109-481B-8BEB-A27597890B2C}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C2D3D138-9109-481B-8BEB-A27597890B2C}.Debug|x64.Build.0 = Debug|Any CPU
+ {C2D3D138-9109-481B-8BEB-A27597890B2C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C2D3D138-9109-481B-8BEB-A27597890B2C}.Debug|x86.Build.0 = Debug|Any CPU
{C2D3D138-9109-481B-8BEB-A27597890B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C2D3D138-9109-481B-8BEB-A27597890B2C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C2D3D138-9109-481B-8BEB-A27597890B2C}.Release|x64.ActiveCfg = Release|Any CPU
+ {C2D3D138-9109-481B-8BEB-A27597890B2C}.Release|x64.Build.0 = Release|Any CPU
+ {C2D3D138-9109-481B-8BEB-A27597890B2C}.Release|x86.ActiveCfg = Release|Any CPU
+ {C2D3D138-9109-481B-8BEB-A27597890B2C}.Release|x86.Build.0 = Release|Any CPU
{BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}.Debug|x64.Build.0 = Debug|Any CPU
+ {BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}.Debug|x86.Build.0 = Debug|Any CPU
{BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}.Release|x64.ActiveCfg = Release|Any CPU
+ {BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}.Release|x64.Build.0 = Release|Any CPU
+ {BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}.Release|x86.ActiveCfg = Release|Any CPU
+ {BFFDD936-2E61-4D3A-ABFE-7CF77FE0B184}.Release|x86.Build.0 = Release|Any CPU
{861C4D0B-A478-48DB-A0FA-AE70F5BA210A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{861C4D0B-A478-48DB-A0FA-AE70F5BA210A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {861C4D0B-A478-48DB-A0FA-AE70F5BA210A}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {861C4D0B-A478-48DB-A0FA-AE70F5BA210A}.Debug|x64.Build.0 = Debug|Any CPU
+ {861C4D0B-A478-48DB-A0FA-AE70F5BA210A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {861C4D0B-A478-48DB-A0FA-AE70F5BA210A}.Debug|x86.Build.0 = Debug|Any CPU
{861C4D0B-A478-48DB-A0FA-AE70F5BA210A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{861C4D0B-A478-48DB-A0FA-AE70F5BA210A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {861C4D0B-A478-48DB-A0FA-AE70F5BA210A}.Release|x64.ActiveCfg = Release|Any CPU
+ {861C4D0B-A478-48DB-A0FA-AE70F5BA210A}.Release|x64.Build.0 = Release|Any CPU
+ {861C4D0B-A478-48DB-A0FA-AE70F5BA210A}.Release|x86.ActiveCfg = Release|Any CPU
+ {861C4D0B-A478-48DB-A0FA-AE70F5BA210A}.Release|x86.Build.0 = Release|Any CPU
{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9FBC654C-51DE-422D-9E1E-6A38268DE1E2}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {9FBC654C-51DE-422D-9E1E-6A38268DE1E2}.Debug|x64.Build.0 = Debug|Any CPU
+ {9FBC654C-51DE-422D-9E1E-6A38268DE1E2}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {9FBC654C-51DE-422D-9E1E-6A38268DE1E2}.Debug|x86.Build.0 = Debug|Any CPU
{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9FBC654C-51DE-422D-9E1E-6A38268DE1E2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9FBC654C-51DE-422D-9E1E-6A38268DE1E2}.Release|x64.ActiveCfg = Release|Any CPU
+ {9FBC654C-51DE-422D-9E1E-6A38268DE1E2}.Release|x64.Build.0 = Release|Any CPU
+ {9FBC654C-51DE-422D-9E1E-6A38268DE1E2}.Release|x86.ActiveCfg = Release|Any CPU
+ {9FBC654C-51DE-422D-9E1E-6A38268DE1E2}.Release|x86.Build.0 = Release|Any CPU
{F302E6D6-5A95-4D22-8DC2-21BE2CB30275}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F302E6D6-5A95-4D22-8DC2-21BE2CB30275}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F302E6D6-5A95-4D22-8DC2-21BE2CB30275}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {F302E6D6-5A95-4D22-8DC2-21BE2CB30275}.Debug|x64.Build.0 = Debug|Any CPU
+ {F302E6D6-5A95-4D22-8DC2-21BE2CB30275}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F302E6D6-5A95-4D22-8DC2-21BE2CB30275}.Debug|x86.Build.0 = Debug|Any CPU
{F302E6D6-5A95-4D22-8DC2-21BE2CB30275}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F302E6D6-5A95-4D22-8DC2-21BE2CB30275}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F302E6D6-5A95-4D22-8DC2-21BE2CB30275}.Release|x64.ActiveCfg = Release|Any CPU
+ {F302E6D6-5A95-4D22-8DC2-21BE2CB30275}.Release|x64.Build.0 = Release|Any CPU
+ {F302E6D6-5A95-4D22-8DC2-21BE2CB30275}.Release|x86.ActiveCfg = Release|Any CPU
+ {F302E6D6-5A95-4D22-8DC2-21BE2CB30275}.Release|x86.Build.0 = Release|Any CPU
{5777BDEC-4726-4425-85F2-A090524F692D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5777BDEC-4726-4425-85F2-A090524F692D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5777BDEC-4726-4425-85F2-A090524F692D}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {5777BDEC-4726-4425-85F2-A090524F692D}.Debug|x64.Build.0 = Debug|Any CPU
+ {5777BDEC-4726-4425-85F2-A090524F692D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5777BDEC-4726-4425-85F2-A090524F692D}.Debug|x86.Build.0 = Debug|Any CPU
{5777BDEC-4726-4425-85F2-A090524F692D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5777BDEC-4726-4425-85F2-A090524F692D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5777BDEC-4726-4425-85F2-A090524F692D}.Release|x64.ActiveCfg = Release|Any CPU
+ {5777BDEC-4726-4425-85F2-A090524F692D}.Release|x64.Build.0 = Release|Any CPU
+ {5777BDEC-4726-4425-85F2-A090524F692D}.Release|x86.ActiveCfg = Release|Any CPU
+ {5777BDEC-4726-4425-85F2-A090524F692D}.Release|x86.Build.0 = Release|Any CPU
{09D05F35-CEA2-48D9-86D0-FB95982BA511}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{09D05F35-CEA2-48D9-86D0-FB95982BA511}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {09D05F35-CEA2-48D9-86D0-FB95982BA511}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {09D05F35-CEA2-48D9-86D0-FB95982BA511}.Debug|x64.Build.0 = Debug|Any CPU
+ {09D05F35-CEA2-48D9-86D0-FB95982BA511}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {09D05F35-CEA2-48D9-86D0-FB95982BA511}.Debug|x86.Build.0 = Debug|Any CPU
{09D05F35-CEA2-48D9-86D0-FB95982BA511}.Release|Any CPU.ActiveCfg = Release|Any CPU
{09D05F35-CEA2-48D9-86D0-FB95982BA511}.Release|Any CPU.Build.0 = Release|Any CPU
+ {09D05F35-CEA2-48D9-86D0-FB95982BA511}.Release|x64.ActiveCfg = Release|Any CPU
+ {09D05F35-CEA2-48D9-86D0-FB95982BA511}.Release|x64.Build.0 = Release|Any CPU
+ {09D05F35-CEA2-48D9-86D0-FB95982BA511}.Release|x86.ActiveCfg = Release|Any CPU
+ {09D05F35-CEA2-48D9-86D0-FB95982BA511}.Release|x86.Build.0 = Release|Any CPU
{35054AA5-CF40-4F38-9414-C76742C29382}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{35054AA5-CF40-4F38-9414-C76742C29382}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {35054AA5-CF40-4F38-9414-C76742C29382}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {35054AA5-CF40-4F38-9414-C76742C29382}.Debug|x64.Build.0 = Debug|Any CPU
+ {35054AA5-CF40-4F38-9414-C76742C29382}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {35054AA5-CF40-4F38-9414-C76742C29382}.Debug|x86.Build.0 = Debug|Any CPU
{35054AA5-CF40-4F38-9414-C76742C29382}.Release|Any CPU.ActiveCfg = Release|Any CPU
{35054AA5-CF40-4F38-9414-C76742C29382}.Release|Any CPU.Build.0 = Release|Any CPU
+ {35054AA5-CF40-4F38-9414-C76742C29382}.Release|x64.ActiveCfg = Release|Any CPU
+ {35054AA5-CF40-4F38-9414-C76742C29382}.Release|x64.Build.0 = Release|Any CPU
+ {35054AA5-CF40-4F38-9414-C76742C29382}.Release|x86.ActiveCfg = Release|Any CPU
+ {35054AA5-CF40-4F38-9414-C76742C29382}.Release|x86.Build.0 = Release|Any CPU
{9E4BFF47-52BF-4FD8-9CC7-3763BF19D9E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9E4BFF47-52BF-4FD8-9CC7-3763BF19D9E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9E4BFF47-52BF-4FD8-9CC7-3763BF19D9E0}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {9E4BFF47-52BF-4FD8-9CC7-3763BF19D9E0}.Debug|x64.Build.0 = Debug|Any CPU
+ {9E4BFF47-52BF-4FD8-9CC7-3763BF19D9E0}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {9E4BFF47-52BF-4FD8-9CC7-3763BF19D9E0}.Debug|x86.Build.0 = Debug|Any CPU
{9E4BFF47-52BF-4FD8-9CC7-3763BF19D9E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9E4BFF47-52BF-4FD8-9CC7-3763BF19D9E0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9E4BFF47-52BF-4FD8-9CC7-3763BF19D9E0}.Release|x64.ActiveCfg = Release|Any CPU
+ {9E4BFF47-52BF-4FD8-9CC7-3763BF19D9E0}.Release|x64.Build.0 = Release|Any CPU
+ {9E4BFF47-52BF-4FD8-9CC7-3763BF19D9E0}.Release|x86.ActiveCfg = Release|Any CPU
+ {9E4BFF47-52BF-4FD8-9CC7-3763BF19D9E0}.Release|x86.Build.0 = Release|Any CPU
{A14242DD-DA06-4DC3-8598-1761AA7C76D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A14242DD-DA06-4DC3-8598-1761AA7C76D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A14242DD-DA06-4DC3-8598-1761AA7C76D1}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {A14242DD-DA06-4DC3-8598-1761AA7C76D1}.Debug|x64.Build.0 = Debug|Any CPU
+ {A14242DD-DA06-4DC3-8598-1761AA7C76D1}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A14242DD-DA06-4DC3-8598-1761AA7C76D1}.Debug|x86.Build.0 = Debug|Any CPU
{A14242DD-DA06-4DC3-8598-1761AA7C76D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A14242DD-DA06-4DC3-8598-1761AA7C76D1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A14242DD-DA06-4DC3-8598-1761AA7C76D1}.Release|x64.ActiveCfg = Release|Any CPU
+ {A14242DD-DA06-4DC3-8598-1761AA7C76D1}.Release|x64.Build.0 = Release|Any CPU
+ {A14242DD-DA06-4DC3-8598-1761AA7C76D1}.Release|x86.ActiveCfg = Release|Any CPU
+ {A14242DD-DA06-4DC3-8598-1761AA7C76D1}.Release|x86.Build.0 = Release|Any CPU
{7279A2AE-8D1F-4E66-A73A-01AF7927A336}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7279A2AE-8D1F-4E66-A73A-01AF7927A336}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7279A2AE-8D1F-4E66-A73A-01AF7927A336}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {7279A2AE-8D1F-4E66-A73A-01AF7927A336}.Debug|x64.Build.0 = Debug|Any CPU
+ {7279A2AE-8D1F-4E66-A73A-01AF7927A336}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7279A2AE-8D1F-4E66-A73A-01AF7927A336}.Debug|x86.Build.0 = Debug|Any CPU
{7279A2AE-8D1F-4E66-A73A-01AF7927A336}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7279A2AE-8D1F-4E66-A73A-01AF7927A336}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7279A2AE-8D1F-4E66-A73A-01AF7927A336}.Release|x64.ActiveCfg = Release|Any CPU
+ {7279A2AE-8D1F-4E66-A73A-01AF7927A336}.Release|x64.Build.0 = Release|Any CPU
+ {7279A2AE-8D1F-4E66-A73A-01AF7927A336}.Release|x86.ActiveCfg = Release|Any CPU
+ {7279A2AE-8D1F-4E66-A73A-01AF7927A336}.Release|x86.Build.0 = Release|Any CPU
{83F18A31-5983-4587-A0B2-414BF70E50B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{83F18A31-5983-4587-A0B2-414BF70E50B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {83F18A31-5983-4587-A0B2-414BF70E50B5}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {83F18A31-5983-4587-A0B2-414BF70E50B5}.Debug|x64.Build.0 = Debug|Any CPU
+ {83F18A31-5983-4587-A0B2-414BF70E50B5}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {83F18A31-5983-4587-A0B2-414BF70E50B5}.Debug|x86.Build.0 = Debug|Any CPU
{83F18A31-5983-4587-A0B2-414BF70E50B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{83F18A31-5983-4587-A0B2-414BF70E50B5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {83F18A31-5983-4587-A0B2-414BF70E50B5}.Release|x64.ActiveCfg = Release|Any CPU
+ {83F18A31-5983-4587-A0B2-414BF70E50B5}.Release|x64.Build.0 = Release|Any CPU
+ {83F18A31-5983-4587-A0B2-414BF70E50B5}.Release|x86.ActiveCfg = Release|Any CPU
+ {83F18A31-5983-4587-A0B2-414BF70E50B5}.Release|x86.Build.0 = Release|Any CPU
{266D07B7-3648-4F3D-818A-89EDA7D84C58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{266D07B7-3648-4F3D-818A-89EDA7D84C58}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {266D07B7-3648-4F3D-818A-89EDA7D84C58}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {266D07B7-3648-4F3D-818A-89EDA7D84C58}.Debug|x64.Build.0 = Debug|Any CPU
+ {266D07B7-3648-4F3D-818A-89EDA7D84C58}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {266D07B7-3648-4F3D-818A-89EDA7D84C58}.Debug|x86.Build.0 = Debug|Any CPU
{266D07B7-3648-4F3D-818A-89EDA7D84C58}.Release|Any CPU.ActiveCfg = Release|Any CPU
{266D07B7-3648-4F3D-818A-89EDA7D84C58}.Release|Any CPU.Build.0 = Release|Any CPU
+ {266D07B7-3648-4F3D-818A-89EDA7D84C58}.Release|x64.ActiveCfg = Release|Any CPU
+ {266D07B7-3648-4F3D-818A-89EDA7D84C58}.Release|x64.Build.0 = Release|Any CPU
+ {266D07B7-3648-4F3D-818A-89EDA7D84C58}.Release|x86.ActiveCfg = Release|Any CPU
+ {266D07B7-3648-4F3D-818A-89EDA7D84C58}.Release|x86.Build.0 = Release|Any CPU
{206FDF79-9BF3-433A-B7FF-627287BBD760}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{206FDF79-9BF3-433A-B7FF-627287BBD760}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {206FDF79-9BF3-433A-B7FF-627287BBD760}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {206FDF79-9BF3-433A-B7FF-627287BBD760}.Debug|x64.Build.0 = Debug|Any CPU
+ {206FDF79-9BF3-433A-B7FF-627287BBD760}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {206FDF79-9BF3-433A-B7FF-627287BBD760}.Debug|x86.Build.0 = Debug|Any CPU
{206FDF79-9BF3-433A-B7FF-627287BBD760}.Release|Any CPU.ActiveCfg = Release|Any CPU
{206FDF79-9BF3-433A-B7FF-627287BBD760}.Release|Any CPU.Build.0 = Release|Any CPU
+ {206FDF79-9BF3-433A-B7FF-627287BBD760}.Release|x64.ActiveCfg = Release|Any CPU
+ {206FDF79-9BF3-433A-B7FF-627287BBD760}.Release|x64.Build.0 = Release|Any CPU
+ {206FDF79-9BF3-433A-B7FF-627287BBD760}.Release|x86.ActiveCfg = Release|Any CPU
+ {206FDF79-9BF3-433A-B7FF-627287BBD760}.Release|x86.Build.0 = Release|Any CPU
{8C2CC25B-DE5D-433E-A550-63864C7A716D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8C2CC25B-DE5D-433E-A550-63864C7A716D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8C2CC25B-DE5D-433E-A550-63864C7A716D}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {8C2CC25B-DE5D-433E-A550-63864C7A716D}.Debug|x64.Build.0 = Debug|Any CPU
+ {8C2CC25B-DE5D-433E-A550-63864C7A716D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {8C2CC25B-DE5D-433E-A550-63864C7A716D}.Debug|x86.Build.0 = Debug|Any CPU
{8C2CC25B-DE5D-433E-A550-63864C7A716D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8C2CC25B-DE5D-433E-A550-63864C7A716D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8C2CC25B-DE5D-433E-A550-63864C7A716D}.Release|x64.ActiveCfg = Release|Any CPU
+ {8C2CC25B-DE5D-433E-A550-63864C7A716D}.Release|x64.Build.0 = Release|Any CPU
+ {8C2CC25B-DE5D-433E-A550-63864C7A716D}.Release|x86.ActiveCfg = Release|Any CPU
+ {8C2CC25B-DE5D-433E-A550-63864C7A716D}.Release|x86.Build.0 = Release|Any CPU
{FFAB2C76-1C9E-4006-95C8-A0B2AA53139D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FFAB2C76-1C9E-4006-95C8-A0B2AA53139D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FFAB2C76-1C9E-4006-95C8-A0B2AA53139D}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {FFAB2C76-1C9E-4006-95C8-A0B2AA53139D}.Debug|x64.Build.0 = Debug|Any CPU
+ {FFAB2C76-1C9E-4006-95C8-A0B2AA53139D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {FFAB2C76-1C9E-4006-95C8-A0B2AA53139D}.Debug|x86.Build.0 = Debug|Any CPU
{FFAB2C76-1C9E-4006-95C8-A0B2AA53139D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FFAB2C76-1C9E-4006-95C8-A0B2AA53139D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FFAB2C76-1C9E-4006-95C8-A0B2AA53139D}.Release|x64.ActiveCfg = Release|Any CPU
+ {FFAB2C76-1C9E-4006-95C8-A0B2AA53139D}.Release|x64.Build.0 = Release|Any CPU
+ {FFAB2C76-1C9E-4006-95C8-A0B2AA53139D}.Release|x86.ActiveCfg = Release|Any CPU
+ {FFAB2C76-1C9E-4006-95C8-A0B2AA53139D}.Release|x86.Build.0 = Release|Any CPU
+ {F9886971-C3B2-4334-B014-D5109F2041DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F9886971-C3B2-4334-B014-D5109F2041DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F9886971-C3B2-4334-B014-D5109F2041DE}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {F9886971-C3B2-4334-B014-D5109F2041DE}.Debug|x64.Build.0 = Debug|Any CPU
+ {F9886971-C3B2-4334-B014-D5109F2041DE}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F9886971-C3B2-4334-B014-D5109F2041DE}.Debug|x86.Build.0 = Debug|Any CPU
+ {F9886971-C3B2-4334-B014-D5109F2041DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F9886971-C3B2-4334-B014-D5109F2041DE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F9886971-C3B2-4334-B014-D5109F2041DE}.Release|x64.ActiveCfg = Release|Any CPU
+ {F9886971-C3B2-4334-B014-D5109F2041DE}.Release|x64.Build.0 = Release|Any CPU
+ {F9886971-C3B2-4334-B014-D5109F2041DE}.Release|x86.ActiveCfg = Release|Any CPU
+ {F9886971-C3B2-4334-B014-D5109F2041DE}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Program.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Program.cs
index 9e0ec7e..a33363b 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Program.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Program.cs
@@ -27,14 +27,15 @@
using WIDESEAWCS_Server.Filter;
using WIDESEAWCS_Server.HostedService;
using WIDESEAWCS_Tasks.SocketServer;
+using WIDESEAWCS_RedisService.Extensions;
using WIDESEAWCS_WCSServer.Filter;
var builder = WebApplication.CreateBuilder(args);
-// 1、配置服务容器
+// 1锟斤拷锟斤拷锟矫凤拷锟斤拷锟斤拷锟斤拷
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()).ConfigureContainer<ContainerBuilder>(builder =>
{
- builder.RegisterModule(new AutofacModuleRegister());//带有接口层的服务注入
+ builder.RegisterModule(new AutofacModuleRegister());//锟斤拷锟叫接口诧拷姆锟斤拷锟阶拷锟�
builder.RegisterModule(new QuartzJobAutofacModuleRegister());
builder.RegisterModule<AutofacPropertityModuleReg>();//
}).ConfigureAppConfiguration((hostingContext, config) =>
@@ -45,20 +46,21 @@
});
builder.ConfigureApplication();
-// 2、配置服务
-builder.Services.AddSingleton(new AppSettings(builder.Configuration));//注册
-builder.Services.AddAllOptionRegister();//读取配置文件
+// 2锟斤拷锟斤拷锟矫凤拷锟斤拷
+builder.Services.AddSingleton(new AppSettings(builder.Configuration));//注锟斤拷
+builder.Services.AddAllOptionRegister();//锟斤拷取锟斤拷锟斤拷锟侥硷拷
-builder.Services.AddMemoryCacheSetup();//缓存
-builder.Services.AddSqlsugarSetup();//SqlSugar 启动服务
-builder.Services.AddInitializationHostServiceSetup();//应用初始化服务注入
-builder.Services.AddHostedService<SeedDataHostedService>();//初始化数据库
+builder.Services.AddMemoryCacheSetup();//锟斤拷锟斤拷
+builder.Services.AddRedisSetup(builder.Configuration);//Redis缂撳瓨
+builder.Services.AddSqlsugarSetup();//SqlSugar 锟斤拷锟斤拷锟斤拷锟斤拷
+builder.Services.AddInitializationHostServiceSetup();//应锟矫筹拷始锟斤拷锟斤拷锟斤拷注锟斤拷
+builder.Services.AddHostedService<SeedDataHostedService>();//锟斤拷始锟斤拷锟斤拷锟捷匡拷
-builder.Services.AddDbSetup();//Db 启动服务
+builder.Services.AddDbSetup();//Db 锟斤拷锟斤拷锟斤拷锟斤拷
-builder.Services.AddScoped<QuartzJobCreateDataTabel>();//任务调度 注入创建QuartzJob数据库表类
-builder.Services.AddHostedService<QuartzJobDataTableHostedService>();//任务调度 映射QuartzJob数据库表
+builder.Services.AddScoped<QuartzJobCreateDataTabel>();//锟斤拷锟斤拷锟斤拷锟� 注锟诫创锟斤拷QuartzJob锟斤拷锟捷匡拷锟斤拷锟�
+builder.Services.AddHostedService<QuartzJobDataTableHostedService>();//锟斤拷锟斤拷锟斤拷锟� 映锟斤拷QuartzJob锟斤拷锟捷匡拷锟�
builder.Services.AddWebSocketSetup();
@@ -70,11 +72,11 @@
builder.Services.AddSwaggerSetup();
-builder.Services.AddJobSetup();//任务调度 注入反射获取依赖对象
+builder.Services.AddJobSetup();//锟斤拷锟斤拷锟斤拷锟� 注锟诫反锟斤拷锟饺★拷锟斤拷锟斤拷锟斤拷锟�
builder.Services.AddHttpContextSetup();
-builder.Services.AddHostedService<QuartzJobHostedService>();//任务调度 启动服务
+builder.Services.AddHostedService<QuartzJobHostedService>();//锟斤拷锟斤拷锟斤拷锟� 锟斤拷锟斤拷锟斤拷锟斤拷
builder.Services.AddSingleton<TcpSocketServer>();
builder.Services.AddHostedService<SocketServerHostedService>();
@@ -89,7 +91,7 @@
builder.Services.AddAuthorizationSetup();
-builder.Services.AddIpPolicyRateLimitSetup(builder.Configuration);//IPLimit限流 启动服务
+builder.Services.AddIpPolicyRateLimitSetup(builder.Configuration);//IPLimit锟斤拷锟斤拷 锟斤拷锟斤拷锟斤拷锟斤拷
builder.Services.AddScoped<UseServiceDIAttribute>();
@@ -99,7 +101,7 @@
builder.Services.AddControllers(o =>
{
- o.Filters.Add(typeof(GlobalExceptionsFilter));//全局异常
+ o.Filters.Add(typeof(GlobalExceptionsFilter));//全锟斤拷锟届常
})
.AddNewtonsoftJson(options =>
{
@@ -120,17 +122,17 @@
var app = builder.Build();
-// 3、配置中间件
-app.UseMiniProfiler();//性能分析器
-app.ConfigureApplication();//配置文件
-app.UseApplicationSetup();//启动配置
+// 3锟斤拷锟斤拷锟斤拷锟叫硷拷锟�
+app.UseMiniProfiler();//锟斤拷锟杰凤拷锟斤拷锟斤拷
+app.ConfigureApplication();//锟斤拷锟斤拷锟侥硷拷
+app.UseApplicationSetup();//锟斤拷锟斤拷锟斤拷锟斤拷
app.UseAllServicesMiddle(builder.Services);
app.UseSession();
app.UseSwaggerAuthorized();
-app.UseSwaggerMiddle(() => Assembly.GetExecutingAssembly().GetManifestResourceStream("WIDESEAWCS_Server.index.html") ?? throw new Exception("未找到WIDESEAWCS_Server.index.html文件"));
+app.UseSwaggerMiddle(() => Assembly.GetExecutingAssembly().GetManifestResourceStream("WIDESEAWCS_Server.index.html") ?? throw new Exception("未锟揭碉拷WIDESEAWCS_Server.index.html锟侥硷拷"));
app.UseIpLimitMiddle();
app.UseApiLogMiddleware();
diff --git "a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Redis\344\275\277\347\224\250\346\241\210\344\276\213.md" "b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Redis\344\275\277\347\224\250\346\241\210\344\276\213.md"
new file mode 100644
index 0000000..8f86a1b
--- /dev/null
+++ "b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Redis\344\275\277\347\224\250\346\241\210\344\276\213.md"
@@ -0,0 +1,380 @@
+# Redis 鏈嶅姟浣跨敤妗堜緥
+
+## 1. 缂撳瓨锛圛CacheService锛�
+
+閫氳繃鏋勯�犲嚱鏁版敞鍏� `ICacheService`锛孒ybridCacheService 鑷姩瀹炵幇 L1(鍐呭瓨) + L2(Redis) 鍙屽眰缂撳瓨銆�
+
+```csharp
+public class MyService
+{
+ private readonly ICacheService _cache;
+
+ public MyService(ICacheService cache)
+ {
+ _cache = cache;
+ }
+
+ // 缂撳瓨瀛楃涓诧紝60绉掕繃鏈�
+ public void CacheString()
+ {
+ _cache.Add("token:10001", "abc123", 60);
+ var token = _cache.Get("token:10001");
+ }
+
+ // 缂撳瓨瀵硅薄
+ public void CacheObject()
+ {
+ var user = new { Id = 1, Name = "寮犱笁" };
+ _cache.AddObject("user:1", user, 300);
+ var cached = _cache.Get<dynamic>("user:1");
+ }
+
+ // 鍒犻櫎缂撳瓨
+ public void RemoveCache()
+ {
+ _cache.Remove("user:1");
+ _cache.Remove(new[] { "token:10001", "token:10002" });
+ }
+}
+```
+
+## 2. 鍒嗗竷寮忛攣锛圛DistributedLockService锛�
+
+```csharp
+public class OrderService
+{
+ private readonly IDistributedLockService _lock;
+
+ public OrderService(IDistributedLockService lockService)
+ {
+ _lock = lockService;
+ }
+
+ // 鏂瑰紡涓�锛氭墜鍔ㄨ幏鍙栧拰閲婃斁閿�
+ public void ProcessOrder(string orderId)
+ {
+ var token = _lock.AcquireLock($"order:{orderId}", TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(5));
+ if (token == null)
+ {
+ Console.WriteLine("鑾峰彇閿佸け璐ワ紝鍏朵粬杩涚▼姝e湪澶勭悊");
+ return;
+ }
+ try
+ {
+ // 涓氬姟閫昏緫...
+ }
+ finally
+ {
+ _lock.ReleaseLock($"order:{orderId}", token);
+ }
+ }
+
+ // 鏂瑰紡浜岋細鑷姩绠$悊閿佺殑鐢熷懡鍛ㄦ湡
+ public void ProcessOrderAuto(string orderId)
+ {
+ var success = _lock.ExecuteWithLock($"order:{orderId}", TimeSpan.FromSeconds(30), () =>
+ {
+ // 涓氬姟閫昏緫...
+ });
+ }
+}
+```
+
+## 3. 璁℃暟鍣紙ICounterService锛�
+
+```csharp
+public class StatisticsService
+{
+ private readonly ICounterService _counter;
+
+ public StatisticsService(ICounterService counter)
+ {
+ _counter = counter;
+ }
+
+ // 浠诲姟璁℃暟
+ public void OnTaskCompleted()
+ {
+ _counter.Increment("task:completed");
+ var total = _counter.GetCount("task:completed");
+ }
+
+ // 甯﹁繃鏈熸椂闂寸殑璁℃暟锛堝锛氭瘡灏忔椂璇锋眰鏁帮級
+ public void OnApiRequest()
+ {
+ var count = _counter.IncrementWithExpiry("api:hourly", TimeSpan.FromHours(1));
+ }
+}
+```
+
+## 4. 鍙戝竷/璁㈤槄锛圛MessageQueueService锛�
+
+```csharp
+public class NotificationService
+{
+ private readonly IMessageQueueService _mq;
+
+ public NotificationService(IMessageQueueService mq)
+ {
+ _mq = mq;
+ }
+
+ // 鍙戝竷娑堟伅
+ public void NotifyTaskComplete(int taskId)
+ {
+ _mq.Publish("task:complete", $"{{\"taskId\":{taskId}}}");
+ }
+
+ // 璁㈤槄娑堟伅
+ public void SubscribeTaskEvents()
+ {
+ _mq.Subscribe("task:complete", (channel, message) =>
+ {
+ Console.WriteLine($"鏀跺埌浠诲姟瀹屾垚閫氱煡: {message}");
+ });
+ }
+
+ // 绠�鍗曢槦鍒楋細鍏ラ槦/鍑洪槦
+ public void UseQueue()
+ {
+ _mq.Enqueue("pending-tasks", "task_001");
+ var task = _mq.Dequeue("pending-tasks");
+ }
+}
+```
+
+## 5. 闄愭祦锛圛RateLimitingService锛�
+
+```csharp
+public class ApiController
+{
+ private readonly IRateLimitingService _rateLimiter;
+
+ public ApiController(IRateLimitingService rateLimiter)
+ {
+ _rateLimiter = rateLimiter;
+ }
+
+ // 鍥哄畾绐楀彛闄愭祦锛氭瘡鍒嗛挓鏈�澶�100娆�
+ public bool CheckRateLimit(string clientIp)
+ {
+ return _rateLimiter.IsAllowed($"api:{clientIp}", 100, TimeSpan.FromMinutes(1));
+ }
+
+ // 婊戝姩绐楀彛闄愭祦
+ public bool CheckSlidingRateLimit(string clientIp)
+ {
+ return _rateLimiter.IsAllowedSliding($"api:{clientIp}", 100, TimeSpan.FromMinutes(1));
+ }
+
+ // 浠ょ墝妗堕檺娴侊細妗跺閲�50锛屾瘡绉掕ˉ鍏�10涓�
+ public bool CheckTokenBucket(string clientIp)
+ {
+ return _rateLimiter.TryAcquireToken($"api:{clientIp}", 50, 10, TimeSpan.FromSeconds(1));
+ }
+}
+```
+
+## 6. 鍒嗗竷寮廔D鐢熸垚鍣紙IDistributedIdGenerator锛�
+
+```csharp
+public class TaskService
+{
+ private readonly IDistributedIdGenerator _idGen;
+
+ public TaskService(IDistributedIdGenerator idGen)
+ {
+ _idGen = idGen;
+ }
+
+ // 鑷ID
+ public long CreateTask()
+ {
+ var id = _idGen.NextId("task");
+ return id; // 1, 2, 3...
+ }
+
+ // 甯︽棩鏈熷墠缂�鐨処D
+ public string CreateTaskCode()
+ {
+ var code = _idGen.NextIdWithDate("task");
+ return code; // 20260302000001
+ }
+}
+```
+
+## 7. 鎺掕姒滐紙ILeaderboardService锛�
+
+```csharp
+public class LeaderboardDemo
+{
+ private readonly ILeaderboardService _board;
+
+ public LeaderboardDemo(ILeaderboardService board)
+ {
+ _board = board;
+ }
+
+ public void Demo()
+ {
+ // 娣诲姞/鏇存柊鍒嗘暟
+ _board.AddOrUpdate("efficiency", "璁惧A", 95.5);
+ _board.AddOrUpdate("efficiency", "璁惧B", 88.0);
+
+ // 澧炲姞鍒嗘暟
+ _board.IncrementScore("efficiency", "璁惧A", 2.0);
+
+ // 鑾峰彇鎺掑悕鍜孴op N
+ var rank = _board.GetRank("efficiency", "璁惧A"); // 0 = 绗竴鍚�
+ var top10 = _board.GetTopN("efficiency", 10);
+ }
+}
+```
+
+## 8. 瀵硅薄瀛樺偍锛圛ObjectStorageService锛�
+
+```csharp
+public class DeviceService
+{
+ private readonly IObjectStorageService _storage;
+
+ public DeviceService(IObjectStorageService storage)
+ {
+ _storage = storage;
+ }
+
+ public void Demo()
+ {
+ // 瀛樺偍瀹屾暣瀵硅薄
+ var device = new { Id = 1, Name = "鍫嗗灈鏈�01", Status = "Running" };
+ _storage.SetObject("device:1", device, TimeSpan.FromMinutes(30));
+
+ // 璇诲彇瀵硅薄
+ var cached = _storage.GetObject<dynamic>("device:1");
+
+ // Hash瀛楁鎿嶄綔
+ _storage.SetField("device:1:props", "temperature", "36.5");
+ var temp = _storage.GetField("device:1:props", "temperature");
+ }
+}
+```
+
+## 9. 閰嶇疆涓績锛圛ConfigurationCenterService锛�
+
+```csharp
+public class ConfigDemo
+{
+ private readonly IConfigurationCenterService _config;
+
+ public ConfigDemo(IConfigurationCenterService config)
+ {
+ _config = config;
+ }
+
+ public void Demo()
+ {
+ // 璁剧疆閰嶇疆
+ _config.Set("system", "MaxTaskCount", "100");
+ _config.Set("system", "EnableAutoDispatch", "true");
+
+ // 璇诲彇閰嶇疆
+ var maxTask = _config.Get("system", "MaxTaskCount");
+ var allConfig = _config.GetSection("system");
+
+ // 鐩戝惉閰嶇疆鍙樻洿
+ _config.Subscribe("system", (key, value) =>
+ {
+ Console.WriteLine($"閰嶇疆鍙樻洿: {key} = {value}");
+ });
+ }
+}
+```
+
+## 10. 鐩戞帶锛圛RedisMonitorService锛�
+
+```csharp
+public class MonitorDemo
+{
+ private readonly IRedisMonitorService _monitor;
+
+ public MonitorDemo(IRedisMonitorService monitor)
+ {
+ _monitor = monitor;
+ }
+
+ public void Demo()
+ {
+ // 鍋ュ悍妫�鏌�
+ var healthy = _monitor.HealthCheck();
+
+ // 鍐呭瓨淇℃伅
+ var mem = _monitor.GetMemoryInfo();
+ Console.WriteLine($"鍐呭瓨浣跨敤: {mem.UsedMemoryHuman}, 浣跨敤鐜�: {mem.UsagePercent}%");
+
+ // 杩炴帴鏁板拰Key鏁伴噺
+ var clients = _monitor.GetClientCount();
+ var dbSize = _monitor.GetDbSize();
+ }
+}
+```
+
+## 11. Session瀛樺偍锛圛SessionStorage锛�
+
+```csharp
+public class SessionDemo
+{
+ private readonly ISessionStorage _session;
+
+ public SessionDemo(ISessionStorage session)
+ {
+ _session = session;
+ }
+
+ public void Demo()
+ {
+ var sid = Guid.NewGuid().ToString("N");
+
+ // 璁剧疆Session鏁版嵁锛�30鍒嗛挓杩囨湡
+ _session.Set(sid, "userId", "10001", TimeSpan.FromMinutes(30));
+ _session.Set(sid, "role", "admin");
+
+ // 璇诲彇
+ var userId = _session.Get(sid, "userId");
+
+ // 缁湡
+ _session.RefreshSession(sid, TimeSpan.FromMinutes(30));
+
+ // 閿�姣�
+ _session.DestroySession(sid);
+ }
+}
+```
+
+## 12. 甯冮殕杩囨护鍣紙IBloomFilterService锛�
+
+```csharp
+public class BloomFilterDemo
+{
+ private readonly IBloomFilterService _bloom;
+
+ public BloomFilterDemo(IBloomFilterService bloom)
+ {
+ _bloom = bloom;
+ }
+
+ // 闃叉缂撳瓨绌块��
+ public void Demo()
+ {
+ // 棰勭儹锛氬皢宸叉湁鏁版嵁鍔犲叆杩囨护鍣�
+ _bloom.AddRange("task:ids", new[] { "T001", "T002", "T003" });
+
+ // 鏌ヨ鍓嶅厛妫�鏌�
+ if (!_bloom.MayExist("task:ids", "T999"))
+ {
+ // 涓�瀹氫笉瀛樺湪锛岀洿鎺ヨ繑鍥烇紝閬垮厤鏌ヨ鏁版嵁搴�
+ return;
+ }
+ // 鍙兘瀛樺湪锛岀户缁煡璇㈡暟鎹簱...
+ }
+}
+```
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server.csproj b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server.csproj
index 25ba69c..69ecb81 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server.csproj
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server.csproj
@@ -73,6 +73,7 @@
<ProjectReference Include="..\WIDESEAWCS_SystemServices\WIDESEAWCS_SystemServices.csproj" />
<ProjectReference Include="..\WIDESEAWCs_TaskInfoService\WIDESEAWCs_TaskInfoService.csproj" />
<ProjectReference Include="..\WIDESEAWCS_Tasks\WIDESEAWCS_Tasks.csproj" />
+ <ProjectReference Include="..\WIDESEAWCS_RedisService\WIDESEAWCS_RedisService.csproj" />
</ItemGroup>
<ItemGroup>
@@ -105,4 +106,8 @@
</EmbeddedResource>
</ItemGroup>
+ <ItemGroup>
+ <Folder Include="Log\" />
+ </ItemGroup>
+
</Project>
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/appsettings.json b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/appsettings.json
index 95b9cd2..d3da09b 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/appsettings.json
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/appsettings.json
@@ -41,19 +41,48 @@
"DBSeedEnable": false,
"QuartzDBSeedEnable": false,
"LogDeubgEnable": false, //鏄惁璁板綍璋冭瘯鏃ュ織
- "PrintSql": true, //鎵撳嵃SQL璇彞
- "LogAOPEnable": true, //鏄惁璁板綍AOP鏃ュ織
+ "PrintSql": false, //鎵撳嵃SQL璇彞
+ "LogAOPEnable": false, //鏄惁璁板綍AOP鏃ュ織
"WebSocketEnable": true, //鏄惁寮�鍚疻ebSocket鏈嶅姟
"WebSocketPort": 9296, //WebSocket鏈嶅姟绔彛
"SocketServer": {
"Enabled": true, //鏄惁鍚敤Socket鏈嶅姟鍣�
- "Port": 2000, //鐩戝惉绔彛
+ "Port": 2000, //鐩戝惉绔彛
"IpAddress": "0.0.0.0", //鐩戝惉鍦板潃锛�
- "Backlog": 1000, //鏈�澶ц繛鎺ユ暟
- "EncodingName": "utf-8", //缂栫爜鏂瑰紡
- "AutoDetectEncoding": true, //鏄惁鑷姩妫�娴嬬紪鐮�
- "IdleTimeoutSeconds": 0, //绌洪棽瓒呮椂鏃堕棿锛屽崟浣嶇锛�0琛ㄧず涓嶈秴鏃�
- "EnableHeartbeat": true, //鏄惁鍚敤蹇冭烦妫�娴�
- "LogFilePath": "socketserver.log" //鏃ュ織鏂囦欢璺緞
+ "Backlog": 1000, //鏈�澶ц繛鎺ユ暟
+ "EncodingName": "utf-8", //缂栫爜鏂瑰紡
+ "AutoDetectEncoding": true, //鏄惁鑷姩妫�娴嬬紪鐮�
+ "IdleTimeoutSeconds": 0, //绌洪棽瓒呮椂鏃堕棿锛屽崟浣嶇锛�0琛ㄧず涓嶈秴鏃�
+ "EnableHeartbeat": true, //鏄惁鍚敤蹇冭烦妫�娴�
+ "LogFilePath": "socketserver.log" //鏃ュ織鏂囦欢璺緞
+ },
+ "CheckPalletPositions": [
+ {
+ "Code": "11068",
+ "WarehouseId": 1
+ }
+ ],
+ "RedisConfig": {
+ "Enabled": true, //鏄惁鍚敤Redis锛宖alse鏃朵粎浣跨敤鍐呭瓨缂撳瓨
+ "ConnectionString": "127.0.0.1:6379,password=P@ssw0rd,defaultDatabase=0,connectTimeout=5000,abortConnect=false", //Redis杩炴帴瀛楃涓�
+ "InstanceName": "WIDESEAWCS:", //瀹炰緥鍚嶇О锛岀敤浜庡尯鍒嗕笉鍚屽簲鐢�
+ "DefaultDatabase": 0, //榛樿鏁版嵁搴撶储寮曪紙0-15锛�
+ "EnableSentinel": false, //鏄惁鍚敤鍝ㄥ叺妯″紡
+ "SentinelMasterName": "mymaster", //鍝ㄥ叺涓昏妭鐐瑰悕绉�
+ "SentinelEndpoints": [], //鍝ㄥ叺鑺傜偣鍦板潃鍒楄〃锛屽 ["sentinel1:26379","sentinel2:26379"]
+ "PoolSize": 10, //杩炴帴姹犲ぇ灏�
+ "ConnectRetry": 3, //杩炴帴澶辫触閲嶈瘯娆℃暟
+ "SerializerType": "Newtonsoft", //搴忓垪鍖栨柟寮忥細Newtonsoft
+ "FallbackToMemory": true, //Redis涓嶅彲鐢ㄦ椂鏄惁闄嶇骇鍒板唴瀛樼紦瀛�
+ "KeyPrefix": "wcs:", //鍏ㄥ眬Key鍓嶇紑锛岀敤浜庨殧绂讳笉鍚岀郴缁熺殑鏁版嵁
+ "Monitoring": {
+ "Enabled": false, //鏄惁鍚敤鐩戞帶
+ "SlowLogThresholdMs": 100, //鎱㈡煡璇㈤槇鍊硷紙姣锛�
+ "HealthCheckIntervalSeconds": 30 //鍋ュ悍妫�鏌ラ棿闅旓紙绉掞級
+ },
+ "Eviction": {
+ "DefaultExpirationSeconds": 3600, //榛樿缂撳瓨杩囨湡鏃堕棿锛堢锛�
+ "MaxMemoryPolicy": "allkeys-lru" //鍐呭瓨娣樻卑绛栫暐锛歛llkeys-lru, volatile-lru, noeviction绛�
+ }
}
}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs
index cb2da11..f8219c9 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs
@@ -18,10 +18,15 @@
#endregion << 鐗� 鏈� 娉� 閲� >>
using AutoMapper;
+using Microsoft.Extensions.Configuration;
using Quartz;
+using SqlSugar;
+using System.Text.Json;
+using WIDESEA_Core;
using WIDESEAWCS_Common.TaskEnum;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.Helper;
+using WIDESEAWCS_DTO.TaskInfo;
using WIDESEAWCS_ITaskInfoService;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
@@ -36,15 +41,17 @@
private readonly ITaskExecuteDetailService _taskExecuteDetailService;
private readonly IRouterService _routerService;
private readonly IMapper _mapper;
- ConveyorLineDispatchHandler _conveyorLineDispatch;
+ private ConveyorLineDispatchHandler _conveyorLineDispatch;
+ private readonly HttpClientHelper _httpClientHelper;
- public CommonConveyorLineNewJob(ITaskService taskService, ITaskExecuteDetailService taskExecuteDetailService, IRouterService routerService, IMapper mapper)
+ public CommonConveyorLineNewJob(ITaskService taskService, ITaskExecuteDetailService taskExecuteDetailService, IRouterService routerService, IMapper mapper, HttpClientHelper httpClientHelper)
{
_taskService = taskService;
_taskExecuteDetailService = taskExecuteDetailService;
_routerService = routerService;
_mapper = mapper;
_conveyorLineDispatch = new ConveyorLineDispatchHandler(_taskService, _taskExecuteDetailService, _routerService, _mapper);
+ _httpClientHelper = httpClientHelper;
}
public Task Execute(IJobExecutionContext context)
@@ -73,6 +80,38 @@
try
{
ConveyorLineTaskCommandNew command = conveyorLine.ReadCustomer<ConveyorLineTaskCommandNew>(childDeviceCode);
+
+ #region 妫�鏌ョ壒瀹氫綅缃槸鍚︽湁鎵樼洏
+
+ var checkPalletPositions = App.Configuration.GetSection("CheckPalletPositions")
+ .Get<List<CheckPalletPosition>>() ?? new List<CheckPalletPosition>();
+
+ if (checkPalletPositions.Any(x => x.Code == childDeviceCode))
+ {
+ if (command.CV_State.ObjToBool())
+ {
+ var existingTask = _taskService.Repository.QueryFirst(x => x.TargetAddress == childDeviceCode);
+ if (existingTask.IsNullOrEmpty())
+ {
+ var position = checkPalletPositions.FirstOrDefault(x => x.Code == childDeviceCode);
+ var responseResult = _httpClientHelper.Post<WebResponseContent>("GetOutBoundTrayTaskAsync", new CreateTaskDto()
+ {
+ WarehouseId = position.WarehouseId,
+ TargetAddress = childDeviceCode
+ }.Serialize());
+
+ if (responseResult.IsSuccess && responseResult.Data.Status)
+ {
+ var wmsTask = JsonSerializer.Deserialize<List<WMSTaskDTO>>(responseResult.Data.Data.Serialize());
+ if (wmsTask != null)
+ _taskService.ReceiveWMSTask(wmsTask);
+ }
+ }
+ }
+ }
+
+ #endregion
+
if (command == null || command.PLC_STB != 1)
{
return;
@@ -97,7 +136,6 @@
// 澶勭悊浠诲姟鐘舵��
ProcessTaskState(conveyorLine, command, task, childDeviceCode);
}
-
}
catch (Exception innerEx)
{
@@ -112,7 +150,6 @@
}
return Task.CompletedTask;
}
-
/// <summary>
/// 澶勭悊浠诲姟鐘舵��
@@ -158,7 +195,5 @@
break;
}
}
-
-
}
}
\ No newline at end of file
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLine/CheckPalletPosition.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLine/CheckPalletPosition.cs
new file mode 100644
index 0000000..85a4ade
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLine/CheckPalletPosition.cs
@@ -0,0 +1,9 @@
+namespace WIDESEAWCS_Tasks
+{
+ public class CheckPalletPosition
+ {
+ public string Code { get; set; } = string.Empty;
+
+ public int WarehouseId { get; set; } = 0;
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotJob.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotJob.cs
index 7efce62..497a7ed 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotJob.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotJob.cs
@@ -7,6 +7,7 @@
using WIDESEAWCS_Common.HttpEnum;
using WIDESEAWCS_Common.TaskEnum;
using WIDESEAWCS_Core;
+using WIDESEAWCS_Core.Caches;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.Http;
using WIDESEAWCS_DTO.Stock;
@@ -26,20 +27,22 @@
private const int MaxTaskTotalNum = 48;
private readonly TcpSocketServer _TcpSocket;
- private static readonly ConcurrentDictionary<string, RobotSocketState> _socketStates = new();
+ //private static readonly ConcurrentDictionary<string, RobotSocketState> _socketStates = new();
private static int _eventSubscribedFlag;
private readonly ITaskService _taskService;
private readonly IRobotTaskService _robotTaskService;
+ private readonly ICacheService _cache;
private static IRobotTaskService _latestRobotTaskService = null!;
private static ITaskService _latestTaskService = null!;
- public RobotJob(TcpSocketServer TcpSocket, IRobotTaskService RobottaskService, ITaskService TaskService)
+ public RobotJob(TcpSocketServer TcpSocket, IRobotTaskService RobottaskService, ITaskService TaskService, ICacheService cache)
{
_TcpSocket = TcpSocket;
_robotTaskService = RobottaskService;
_taskService = TaskService;
+ _cache = cache;
_latestRobotTaskService = RobottaskService;
_latestTaskService = TaskService;
@@ -57,7 +60,7 @@
string ipAddress = robotCrane.IPAddress;
// 鑾峰彇鎴栧垱寤虹姸鎬�
- RobotSocketState state = _socketStates.GetOrAdd(ipAddress, _ => new RobotSocketState
+ RobotSocketState state = _cache.GetOrAdd(ipAddress, _ => new RobotSocketState
{
IPAddress = ipAddress,
RobotCrane = robotCrane
@@ -66,87 +69,101 @@
// 鏇存柊璁惧淇℃伅
state.RobotCrane = robotCrane;
- // 妫�鏌ユ槸鍚︽湁璇ュ鎴风杩炴帴
- var clientIds = _TcpSocket.GetClientIds();
- if (!clientIds.Contains(ipAddress))
+ try
{
- return;
- }
- // 璁㈤槄涓�娆� message 浜嬩欢锛堝叏灞�涓�娆★級
- if (Interlocked.CompareExchange(ref _eventSubscribedFlag, 1, 0) == 0)
- {
- _TcpSocket.MessageReceived += _TcpSocket_MessageReceived;
- _TcpSocket.RobotReceived += _TcpSocket_RobotReceived;
- }
-
- if (!state.IsEventSubscribed)
- {
- if (_TcpSocket._clients.TryGetValue(ipAddress, out TcpClient client))
+ // 妫�鏌ユ槸鍚︽湁璇ュ鎴风杩炴帴
+ var clientIds = _TcpSocket.GetClientIds();
+ if (!clientIds.Contains(ipAddress))
{
- _ = _TcpSocket.HandleClientAsync(client, robotCrane.IPAddress, _TcpSocket._cts.Token, state)
- .ContinueWith(t =>
- {
- if (t.IsFaulted)
- Console.WriteLine($"HandleClientAsync error: {t.Exception?.GetBaseException().Message}");
- }, TaskContinuationOptions.OnlyOnFaulted);
- state.IsEventSubscribed = true;
+ return;
}
- }
- // 鑾峰彇浠诲姟骞剁紦瀛樺埌鐘舵�佷腑
- Dt_RobotTask? task = GetTask(robotCrane);
- if (task != null)
- {
- state.IsSplitPallet = task.RobotTaskType == RobotTaskTypeEnum.SplitPallet.GetHashCode();
- state.IsGroupPallet = task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode() || task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode();
- state.CurrentTask = task;
- if (task.RobotTaskTotalNum <= MaxTaskTotalNum)
+ // 璁㈤槄涓�娆� message 浜嬩欢锛堝叏灞�涓�娆★級
+ if (Interlocked.CompareExchange(ref _eventSubscribedFlag, 1, 0) == 0)
{
- // 澶勭悊姝e湪鎵ц鐨勪换鍔�
- if (state.RobotRunMode == 2 && state.RobotControlMode == 1 && state.OperStatus != "Running")
+ _TcpSocket.MessageReceived += _TcpSocket_MessageReceived;
+ _TcpSocket.RobotReceived += _TcpSocket_RobotReceived;
+ }
+
+ if (!state.IsEventSubscribed)
+ {
+ if (_TcpSocket._clients.TryGetValue(ipAddress, out TcpClient client))
{
- await Task.Delay(1000);
- if (state.CurrentAction == "PickFinished" && state.RobotArmObject == 1 && task.RobotTaskState != TaskRobotStatusEnum.RobotExecuting.GetHashCode())
+ _ = _TcpSocket.HandleClientAsync(client, robotCrane.IPAddress, _TcpSocket._cts.Token, state)
+ .ContinueWith(t =>
+ {
+ if (t.IsFaulted)
+ Console.WriteLine($"HandleClientAsync error: {t.Exception?.GetBaseException().Message}");
+ }, TaskContinuationOptions.OnlyOnFaulted);
+ state.IsEventSubscribed = true;
+ }
+ }
+
+ // 鑾峰彇浠诲姟骞剁紦瀛樺埌鐘舵�佷腑
+ Dt_RobotTask? task = GetTask(robotCrane);
+ if (task != null)
+ {
+ state.IsSplitPallet = task.RobotTaskType == RobotTaskTypeEnum.SplitPallet.GetHashCode();
+ state.IsGroupPallet = task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode() || task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode();
+ state.CurrentTask = task;
+ if (task.RobotTaskTotalNum <= MaxTaskTotalNum)
+ {
+ // 澶勭悊姝e湪鎵ц鐨勪换鍔�
+ if (state.RobotRunMode == 2 && state.RobotControlMode == 1 && state.OperStatus != "Running")
{
- string taskString = $"Putbattery,{task.RobotTargetAddress}";
- bool result = await _TcpSocket.SendToClientAsync(ipAddress, taskString);
- if (result)
+ await Task.Delay(1000);
+ if (state.CurrentAction == "PickFinished" && state.RobotArmObject == 1 && task.RobotTaskState != TaskRobotStatusEnum.RobotExecuting.GetHashCode())
+ {
+ string taskString = $"Putbattery,{task.RobotTargetAddress}";
+ bool result = await _TcpSocket.SendToClientAsync(ipAddress, taskString);
+ if (result)
+ {
+ task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode();
+ await _robotTaskService.UpdateRobotTaskAsync(task);
+ }
+ }
+ else if (state.CurrentAction == "PutFinished" && state.RobotArmObject == 0 && task.RobotTaskState != TaskRobotStatusEnum.RobotExecuting.GetHashCode())
{
task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode();
await _robotTaskService.UpdateRobotTaskAsync(task);
}
- }
- else if (state.CurrentAction == "PutFinished" && state.RobotArmObject == 0 && task.RobotTaskState != TaskRobotStatusEnum.RobotExecuting.GetHashCode())
- {
- task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode();
- await _robotTaskService.UpdateRobotTaskAsync(task);
- }
- else if (state.OperStatus == "Homed" && state.RobotArmObject == 0 && task.RobotTaskState != TaskRobotStatusEnum.RobotExecuting.GetHashCode())
- {
- // TODO 璇诲彇绾夸綋鐢垫睜鏉$爜锛屽彂閫佸彇鐢垫睜鎸囦护
- // 闅忔満鐢熸垚涓ゅぉ鎵樼洏鏉$爜瀛樻斁鍒颁袱涓彉閲忛噷闈�
- // 瀹氫箟鍓嶇紑锛堜緥濡傦細TRAY浠h〃鎵樼洏锛�
- string prefix = "TRAY";
-
- // 鐢熸垚涓や釜鎵樼洏鏉$爜
- string trayBarcode1 = GenerateTrayBarcode(state, prefix);
- string trayBarcode2 = GenerateTrayBarcode(state, prefix);
- if (!trayBarcode1.IsNullOrEmpty() && !trayBarcode2.IsNullOrEmpty())
+ else if (state.OperStatus == "Homed" && state.RobotArmObject == 0 && task.RobotTaskState != TaskRobotStatusEnum.RobotExecuting.GetHashCode())
{
- string taskString = $"Pickbattery,{task.RobotSourceAddress}";
- // 鍙戦�佷换鍔℃寚浠�
- bool result = await _TcpSocket.SendToClientAsync(ipAddress, taskString);
- if (result)
+ // TODO 璇诲彇绾夸綋鐢垫睜鏉$爜锛屽彂閫佸彇鐢垫睜鎸囦护
+ // 闅忔満鐢熸垚涓ゅぉ鎵樼洏鏉$爜瀛樻斁鍒颁袱涓彉閲忛噷闈�
+ // 瀹氫箟鍓嶇紑锛堜緥濡傦細TRAY浠h〃鎵樼洏锛�
+ string prefix = "TRAY";
+
+ // 鐢熸垚涓や釜鎵樼洏鏉$爜
+ string trayBarcode1 = GenerateTrayBarcode(state, prefix);
+ string trayBarcode2 = GenerateTrayBarcode(state, prefix);
+ if (!trayBarcode1.IsNullOrEmpty() && !trayBarcode2.IsNullOrEmpty())
{
- // TODO 澶勭悊鎴愬姛鍙戦�佷换鍔℃寚浠ゅ悗鐨勯�昏緫
- task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode();
- result = await _robotTaskService.UpdateRobotTaskAsync(task);
+ string taskString = $"Pickbattery,{task.RobotSourceAddress}";
+ // 鍙戦�佷换鍔℃寚浠�
+ bool result = await _TcpSocket.SendToClientAsync(ipAddress, taskString);
+ if (result)
+ {
+ // TODO 澶勭悊鎴愬姛鍙戦�佷换鍔℃寚浠ゅ悗鐨勯�昏緫
+ task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode();
+ result = await _robotTaskService.UpdateRobotTaskAsync(task);
+ }
}
}
}
}
}
+ }
+ catch (Exception)
+ {
+
+ }
+ finally
+ {
+ // 鍙�夛細鍦ㄨ繖閲屽鐞嗕换浣曢渶瑕佸湪浠诲姟瀹屾垚鍚庢墽琛岀殑娓呯悊宸ヤ綔
+ // 鏇存柊缂撳瓨涓殑鐘舵��
+ _cache.AddOrUpdate(ipAddress, state);
}
}
@@ -176,7 +193,7 @@
/// <returns></returns>
private Task<string?> _TcpSocket_RobotReceived(string clientId)
{
- _socketStates.TryRemove(clientId, out _);
+ _cache.TryRemove(clientId, out _);
return Task.FromResult<string?>(null);
}
diff --git a/Code/WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/v18/DocumentLayout.backup.json b/Code/WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/v18/DocumentLayout.backup.json
index 2f3b2b8..84b0fd5 100644
--- a/Code/WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/v18/DocumentLayout.backup.json
+++ b/Code/WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/v18/DocumentLayout.backup.json
@@ -3,24 +3,44 @@
"WorkspaceRootPath": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\",
"Documents": [
{
- "AbsoluteMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|solutionrelative:widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
"AbsoluteMoniker": "D:0:0:{7D7534D4-51D9-46DC-A6B7-6430042F4E12}|WIDESEA_TaskInfoService\\WIDESEA_TaskInfoService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{7D7534D4-51D9-46DC-A6B7-6430042F4E12}|WIDESEA_TaskInfoService\\WIDESEA_TaskInfoService.csproj|solutionrelative:widesea_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
- "AbsoluteMoniker": "D:0:0:{5F260E03-095A-4870-8419-5B72CB62929E}|WIDESEA_IBasicService\\WIDESEA_IBasicService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_ibasicservice\\ilocationinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{5F260E03-095A-4870-8419-5B72CB62929E}|WIDESEA_IBasicService\\WIDESEA_IBasicService.csproj|solutionrelative:widesea_ibasicservice\\ilocationinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|solutionrelative:widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\controllers\\taskinfo\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\controllers\\taskinfo\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{CE0DB91F-5A68-448E-A419-4C26B5039F51}|WIDESEA_ITaskInfoService\\WIDESEA_ITaskInfoService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_itaskinfoservice\\itaskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{CE0DB91F-5A68-448E-A419-4C26B5039F51}|WIDESEA_ITaskInfoService\\WIDESEA_ITaskInfoService.csproj|solutionrelative:widesea_itaskinfoservice\\itaskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
- "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\controllers\\taskinfo\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\controllers\\taskinfo\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ "AbsoluteMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_core\\baserepository\\repositorybase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|solutionrelative:widesea_core\\baserepository\\repositorybase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_common\\stockenum\\stockstatusemun.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|solutionrelative:widesea_common\\stockenum\\stockstatusemun.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{00CE9885-9F24-4B6C-A7E8-0DE8C9ED7128}|WIDESEA_Model\\WIDESEA_Model.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_model\\models\\stock\\dt_stockinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{00CE9885-9F24-4B6C-A7E8-0DE8C9ED7128}|WIDESEA_Model\\WIDESEA_Model.csproj|solutionrelative:widesea_model\\models\\stock\\dt_stockinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\task\\createtaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\task\\createtaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{5F260E03-095A-4870-8419-5B72CB62929E}|WIDESEA_IBasicService\\WIDESEA_IBasicService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_ibasicservice\\ilocationinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{5F260E03-095A-4870-8419-5B72CB62929E}|WIDESEA_IBasicService\\WIDESEA_IBasicService.csproj|solutionrelative:widesea_ibasicservice\\ilocationinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_common\\locationenum\\locationstatusenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
@@ -43,10 +63,6 @@
"RelativeMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|solutionrelative:widesea_stockservice\\stockinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
- "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
"AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
@@ -61,14 +77,6 @@
{
"AbsoluteMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_core\\helper\\http\\httpresponseresult.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|solutionrelative:widesea_core\\helper\\http\\httpresponseresult.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\task\\createtaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\task\\createtaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{00CE9885-9F24-4B6C-A7E8-0DE8C9ED7128}|WIDESEA_Model\\WIDESEA_Model.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_model\\models\\stock\\dt_stockinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{00CE9885-9F24-4B6C-A7E8-0DE8C9ED7128}|WIDESEA_Model\\WIDESEA_Model.csproj|solutionrelative:widesea_model\\models\\stock\\dt_stockinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{D11C804C-2FF4-4C18-A3EE-2F0574427BB3}|WIDESEA_BasicService\\WIDESEA_BasicService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_basicservice\\locationinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
@@ -89,10 +97,6 @@
{
"AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\gradingmachine\\outputdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\gradingmachine\\outputdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_core\\baserepository\\repositorybase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|solutionrelative:widesea_core\\baserepository\\repositorybase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"DocumentGroupContainers": [
@@ -105,6 +109,19 @@
"SelectedChildIndex": 24,
"Children": [
{
+ "$type": "Document",
+ "DocumentIndex": 6,
+ "Title": "StockStatusEmun.cs",
+ "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\StockEnum\\StockStatusEmun.cs",
+ "RelativeDocumentMoniker": "WIDESEA_Common\\StockEnum\\StockStatusEmun.cs",
+ "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\StockEnum\\StockStatusEmun.cs",
+ "RelativeToolTip": "WIDESEA_Common\\StockEnum\\StockStatusEmun.cs",
+ "ViewState": "AgIAACQAAAAAAAAAAAAgwDoAAAAeAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-02-28T06:15:43.313Z",
+ "EditorCaption": ""
+ },
+ {
"$type": "Bookmark",
"Name": "ST:128:0:{116d2292-e37d-41cd-a077-ebacac4c8cc4}"
},
@@ -113,8 +130,12 @@
"Name": "ST:0:0:{40ea2e6b-2121-4bb8-a43e-c83c04b51041}"
},
{
+ "$type": "Bookmark",
+ "Name": "ST:0:0:{aa2115a1-9712-457b-9047-dbb71ca2cdd2}"
+ },
+ {
"$type": "Document",
- "DocumentIndex": 5,
+ "DocumentIndex": 10,
"Title": "LocationStatusEnum.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\LocationEnum\\LocationStatusEnum.cs",
"RelativeDocumentMoniker": "WIDESEA_Common\\LocationEnum\\LocationStatusEnum.cs",
@@ -126,7 +147,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 8,
+ "DocumentIndex": 13,
"Title": "IStockService.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_IStockService\\IStockService.cs",
"RelativeDocumentMoniker": "WIDESEA_IStockService\\IStockService.cs",
@@ -138,7 +159,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 7,
+ "DocumentIndex": 12,
"Title": "StockController.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\Stock\\StockController.cs",
"RelativeDocumentMoniker": "WIDESEA_WMSServer\\Controllers\\Stock\\StockController.cs",
@@ -150,7 +171,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 11,
+ "DocumentIndex": 15,
"Title": "Program.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Program.cs",
"RelativeDocumentMoniker": "WIDESEA_WMSServer\\Program.cs",
@@ -162,7 +183,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 14,
+ "DocumentIndex": 18,
"Title": "HttpResponseResult.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\Helper\\HTTP\\HttpResponseResult.cs",
"RelativeDocumentMoniker": "WIDESEA_Core\\Helper\\HTTP\\HttpResponseResult.cs",
@@ -174,7 +195,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 13,
+ "DocumentIndex": 17,
"Title": "HttpRequestConfig.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\Helper\\HTTP\\HttpRequestConfig.cs",
"RelativeDocumentMoniker": "WIDESEA_Core\\Helper\\HTTP\\HttpRequestConfig.cs",
@@ -186,7 +207,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 12,
+ "DocumentIndex": 16,
"Title": "HttpClientHelper.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\Helper\\HTTP\\HttpClientHelper.cs",
"RelativeDocumentMoniker": "WIDESEA_Core\\Helper\\HTTP\\HttpClientHelper.cs",
@@ -198,7 +219,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 21,
+ "DocumentIndex": 23,
"Title": "OutPutDto.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\GradingMachine\\OutPutDto.cs",
"RelativeDocumentMoniker": "WIDESEA_DTO\\GradingMachine\\OutPutDto.cs",
@@ -210,7 +231,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 20,
+ "DocumentIndex": 22,
"Title": "InputDto.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\GradingMachine\\InputDto.cs",
"RelativeDocumentMoniker": "WIDESEA_DTO\\GradingMachine\\InputDto.cs",
@@ -222,19 +243,20 @@
},
{
"$type": "Document",
- "DocumentIndex": 22,
+ "DocumentIndex": 5,
"Title": "RepositoryBase.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseRepository\\RepositoryBase.cs",
"RelativeDocumentMoniker": "WIDESEA_Core\\BaseRepository\\RepositoryBase.cs",
"ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseRepository\\RepositoryBase.cs",
"RelativeToolTip": "WIDESEA_Core\\BaseRepository\\RepositoryBase.cs",
- "ViewState": "AgIAALgDAAAAAAAAAAAhwMsDAAAZAAAAAAAAAA==",
+ "ViewState": "AgIAALgDAAAAAAAAAAAawMsDAAAZAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-14T08:55:16.1Z"
+ "WhenOpened": "2026-02-14T08:55:16.1Z",
+ "EditorCaption": ""
},
{
"$type": "Document",
- "DocumentIndex": 19,
+ "DocumentIndex": 21,
"Title": "IRepository.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseRepository\\IRepository.cs",
"RelativeDocumentMoniker": "WIDESEA_Core\\BaseRepository\\IRepository.cs",
@@ -246,7 +268,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 18,
+ "DocumentIndex": 20,
"Title": "StockViewService.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockViewService.cs",
"RelativeDocumentMoniker": "WIDESEA_StockService\\StockViewService.cs",
@@ -258,7 +280,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 2,
+ "DocumentIndex": 9,
"Title": "ILocationInfoService.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_IBasicService\\ILocationInfoService.cs",
"RelativeDocumentMoniker": "WIDESEA_IBasicService\\ILocationInfoService.cs",
@@ -270,7 +292,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 17,
+ "DocumentIndex": 19,
"Title": "LocationInfoService.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_BasicService\\LocationInfoService.cs",
"RelativeDocumentMoniker": "WIDESEA_BasicService\\LocationInfoService.cs",
@@ -282,19 +304,20 @@
},
{
"$type": "Document",
- "DocumentIndex": 16,
+ "DocumentIndex": 7,
"Title": "Dt_StockInfo.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Model\\Models\\Stock\\Dt_StockInfo.cs",
"RelativeDocumentMoniker": "WIDESEA_Model\\Models\\Stock\\Dt_StockInfo.cs",
"ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Model\\Models\\Stock\\Dt_StockInfo.cs",
"RelativeToolTip": "WIDESEA_Model\\Models\\Stock\\Dt_StockInfo.cs",
- "ViewState": "AgIAAEAAAAAAAAAAAAAkwFIAAAAeAAAAAAAAAA==",
+ "ViewState": "AgIAAEAAAAAAAAAAAAAkwFIAAAAuAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-11T01:38:37.887Z"
+ "WhenOpened": "2026-02-11T01:38:37.887Z",
+ "EditorCaption": ""
},
{
"$type": "Document",
- "DocumentIndex": 9,
+ "DocumentIndex": 14,
"Title": "StockInfoService.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockInfoService.cs",
"RelativeDocumentMoniker": "WIDESEA_StockService\\StockInfoService.cs",
@@ -306,7 +329,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 6,
+ "DocumentIndex": 11,
"Title": "IStockInfoService.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_IStockService\\IStockInfoService.cs",
"RelativeDocumentMoniker": "WIDESEA_IStockService\\IStockInfoService.cs",
@@ -318,74 +341,78 @@
},
{
"$type": "Document",
- "DocumentIndex": 4,
+ "DocumentIndex": 3,
"Title": "TaskController.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs",
"RelativeDocumentMoniker": "WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs",
"ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs",
"RelativeToolTip": "WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs",
- "ViewState": "AgIAACcAAAAAAAAAAAAIwDcAAABAAAAAAAAAAA==",
+ "ViewState": "AgIAAD0AAAAAAAAAAAAUwFUAAABJAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-09T01:23:19.844Z"
+ "WhenOpened": "2026-02-09T01:23:19.844Z",
+ "EditorCaption": ""
},
{
"$type": "Document",
- "DocumentIndex": 15,
+ "DocumentIndex": 8,
"Title": "CreateTaskDto.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Task\\CreateTaskDto.cs",
"RelativeDocumentMoniker": "WIDESEA_DTO\\Task\\CreateTaskDto.cs",
"ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Task\\CreateTaskDto.cs",
"RelativeToolTip": "WIDESEA_DTO\\Task\\CreateTaskDto.cs",
- "ViewState": "AgIAABEAAAAAAAAAAADwvw4AAAARAAAAAAAAAA==",
+ "ViewState": "AgIAABsAAAAAAAAAAAAywA4AAAARAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-06T07:58:13.932Z"
+ "WhenOpened": "2026-02-06T07:58:13.932Z",
+ "EditorCaption": ""
},
{
"$type": "Document",
- "DocumentIndex": 3,
+ "DocumentIndex": 4,
"Title": "ITaskService.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_ITaskInfoService\\ITaskService.cs",
"RelativeDocumentMoniker": "WIDESEA_ITaskInfoService\\ITaskService.cs",
"ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_ITaskInfoService\\ITaskService.cs",
"RelativeToolTip": "WIDESEA_ITaskInfoService\\ITaskService.cs",
- "ViewState": "AgIAAC0AAAAAAAAAAAAAAEkAAAAIAAAAAAAAAA==",
+ "ViewState": "AgIAAEAAAAAAAAAAAAAUwFEAAAAVAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-06T07:00:19.697Z"
+ "WhenOpened": "2026-02-06T07:00:19.697Z",
+ "EditorCaption": ""
},
{
"$type": "Document",
- "DocumentIndex": 1,
+ "DocumentIndex": 0,
"Title": "TaskService.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_TaskInfoService\\TaskService.cs",
"RelativeDocumentMoniker": "WIDESEA_TaskInfoService\\TaskService.cs",
"ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_TaskInfoService\\TaskService.cs",
"RelativeToolTip": "WIDESEA_TaskInfoService\\TaskService.cs",
- "ViewState": "AgIAADkAAAAAAAAAAAAUwEkAAAAoAAAAAAAAAA==",
+ "ViewState": "AgIAAAEBAAAAAAAAAAAxwPABAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-06T06:34:59.734Z",
"EditorCaption": ""
},
{
"$type": "Document",
- "DocumentIndex": 10,
+ "DocumentIndex": 1,
"Title": "StockDTO.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Stock\\StockDTO.cs",
"RelativeDocumentMoniker": "WIDESEA_DTO\\Stock\\StockDTO.cs",
"ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Stock\\StockDTO.cs",
"RelativeToolTip": "WIDESEA_DTO\\Stock\\StockDTO.cs",
- "ViewState": "AgIAACMAAAAAAAAAAAAAADoAAAASAAAAAAAAAA==",
+ "ViewState": "AgIAACMAAAAAAAAAAAAAADYAAAAuAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-06T02:56:51.397Z"
+ "WhenOpened": "2026-02-06T02:56:51.397Z",
+ "EditorCaption": ""
},
{
"$type": "Document",
- "DocumentIndex": 0,
+ "DocumentIndex": 2,
"Title": "StockSerivce.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockSerivce.cs",
"RelativeDocumentMoniker": "WIDESEA_StockService\\StockSerivce.cs",
"ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockSerivce.cs",
"RelativeToolTip": "WIDESEA_StockService\\StockSerivce.cs",
- "ViewState": "AgIAACQAAAAAAAAAAAAYwIgAAAAdAAAAAAAAAA==",
+ "ViewState": "AgIAAAAAAAAAAAAAAAAAAD8AAAApAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-06T01:53:49.077Z",
"EditorCaption": ""
diff --git a/Code/WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/v18/DocumentLayout.json b/Code/WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/v18/DocumentLayout.json
index ded488e..7935bb9 100644
--- a/Code/WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/v18/DocumentLayout.json
+++ b/Code/WMS/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/v18/DocumentLayout.json
@@ -3,24 +3,44 @@
"WorkspaceRootPath": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\",
"Documents": [
{
- "AbsoluteMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|solutionrelative:widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
"AbsoluteMoniker": "D:0:0:{7D7534D4-51D9-46DC-A6B7-6430042F4E12}|WIDESEA_TaskInfoService\\WIDESEA_TaskInfoService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{7D7534D4-51D9-46DC-A6B7-6430042F4E12}|WIDESEA_TaskInfoService\\WIDESEA_TaskInfoService.csproj|solutionrelative:widesea_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
- "AbsoluteMoniker": "D:0:0:{5F260E03-095A-4870-8419-5B72CB62929E}|WIDESEA_IBasicService\\WIDESEA_IBasicService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_ibasicservice\\ilocationinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{5F260E03-095A-4870-8419-5B72CB62929E}|WIDESEA_IBasicService\\WIDESEA_IBasicService.csproj|solutionrelative:widesea_ibasicservice\\ilocationinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|solutionrelative:widesea_stockservice\\stockserivce.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\controllers\\taskinfo\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\controllers\\taskinfo\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{CE0DB91F-5A68-448E-A419-4C26B5039F51}|WIDESEA_ITaskInfoService\\WIDESEA_ITaskInfoService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_itaskinfoservice\\itaskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{CE0DB91F-5A68-448E-A419-4C26B5039F51}|WIDESEA_ITaskInfoService\\WIDESEA_ITaskInfoService.csproj|solutionrelative:widesea_itaskinfoservice\\itaskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
- "AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\controllers\\taskinfo\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\controllers\\taskinfo\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ "AbsoluteMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_core\\baserepository\\repositorybase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|solutionrelative:widesea_core\\baserepository\\repositorybase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_common\\stockenum\\stockstatusemun.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|solutionrelative:widesea_common\\stockenum\\stockstatusemun.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{00CE9885-9F24-4B6C-A7E8-0DE8C9ED7128}|WIDESEA_Model\\WIDESEA_Model.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_model\\models\\stock\\dt_stockinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{00CE9885-9F24-4B6C-A7E8-0DE8C9ED7128}|WIDESEA_Model\\WIDESEA_Model.csproj|solutionrelative:widesea_model\\models\\stock\\dt_stockinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\task\\createtaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\task\\createtaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{5F260E03-095A-4870-8419-5B72CB62929E}|WIDESEA_IBasicService\\WIDESEA_IBasicService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_ibasicservice\\ilocationinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
+ "RelativeMoniker": "D:0:0:{5F260E03-095A-4870-8419-5B72CB62929E}|WIDESEA_IBasicService\\WIDESEA_IBasicService.csproj|solutionrelative:widesea_ibasicservice\\ilocationinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{AF8F3D65-1D75-4B8F-AFD9-4150E591C44D}|WIDESEA_Common\\WIDESEA_Common.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_common\\locationenum\\locationstatusenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
@@ -43,10 +63,6 @@
"RelativeMoniker": "D:0:0:{7DC26D42-D8EE-46F0-BA66-A13457086885}|WIDESEA_StockService\\WIDESEA_StockService.csproj|solutionrelative:widesea_stockservice\\stockinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
- "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\stock\\stockdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
"AbsoluteMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_wmsserver\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{D81A65B5-47D1-40C1-8FDE-7D24FF003F51}|WIDESEA_WMSServer\\WIDESEA_WMSServer.csproj|solutionrelative:widesea_wmsserver\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
@@ -61,14 +77,6 @@
{
"AbsoluteMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_core\\helper\\http\\httpresponseresult.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|solutionrelative:widesea_core\\helper\\http\\httpresponseresult.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\task\\createtaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\task\\createtaskdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{00CE9885-9F24-4B6C-A7E8-0DE8C9ED7128}|WIDESEA_Model\\WIDESEA_Model.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_model\\models\\stock\\dt_stockinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{00CE9885-9F24-4B6C-A7E8-0DE8C9ED7128}|WIDESEA_Model\\WIDESEA_Model.csproj|solutionrelative:widesea_model\\models\\stock\\dt_stockinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{D11C804C-2FF4-4C18-A3EE-2F0574427BB3}|WIDESEA_BasicService\\WIDESEA_BasicService.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_basicservice\\locationinfoservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
@@ -89,10 +97,6 @@
{
"AbsoluteMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_dto\\gradingmachine\\outputdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{929DF936-042C-4EEC-8722-A831FC2F0AEA}|WIDESEA_DTO\\WIDESEA_DTO.csproj|solutionrelative:widesea_dto\\gradingmachine\\outputdto.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|d:\\git\\shanmeixinnengyuan\\code\\wms\\widesea_wmsserver\\widesea_core\\baserepository\\repositorybase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{111BD7AA-9749-4506-9772-79F9EF14754C}|WIDESEA_Core\\WIDESEA_Core.csproj|solutionrelative:widesea_core\\baserepository\\repositorybase.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"DocumentGroupContainers": [
@@ -102,7 +106,7 @@
"DocumentGroups": [
{
"DockedWidth": 200,
- "SelectedChildIndex": 25,
+ "SelectedChildIndex": 24,
"Children": [
{
"$type": "Bookmark",
@@ -118,7 +122,19 @@
},
{
"$type": "Document",
- "DocumentIndex": 5,
+ "DocumentIndex": 6,
+ "Title": "StockStatusEmun.cs",
+ "DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\StockEnum\\StockStatusEmun.cs",
+ "RelativeDocumentMoniker": "WIDESEA_Common\\StockEnum\\StockStatusEmun.cs",
+ "ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\StockEnum\\StockStatusEmun.cs",
+ "RelativeToolTip": "WIDESEA_Common\\StockEnum\\StockStatusEmun.cs",
+ "ViewState": "AgIAACQAAAAAAAAAAAAgwDoAAAAeAAAAAAAAAA==",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-02-28T06:15:43.313Z"
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 10,
"Title": "LocationStatusEnum.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Common\\LocationEnum\\LocationStatusEnum.cs",
"RelativeDocumentMoniker": "WIDESEA_Common\\LocationEnum\\LocationStatusEnum.cs",
@@ -130,7 +146,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 8,
+ "DocumentIndex": 13,
"Title": "IStockService.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_IStockService\\IStockService.cs",
"RelativeDocumentMoniker": "WIDESEA_IStockService\\IStockService.cs",
@@ -142,7 +158,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 7,
+ "DocumentIndex": 12,
"Title": "StockController.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\Stock\\StockController.cs",
"RelativeDocumentMoniker": "WIDESEA_WMSServer\\Controllers\\Stock\\StockController.cs",
@@ -154,7 +170,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 11,
+ "DocumentIndex": 15,
"Title": "Program.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Program.cs",
"RelativeDocumentMoniker": "WIDESEA_WMSServer\\Program.cs",
@@ -166,7 +182,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 14,
+ "DocumentIndex": 18,
"Title": "HttpResponseResult.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\Helper\\HTTP\\HttpResponseResult.cs",
"RelativeDocumentMoniker": "WIDESEA_Core\\Helper\\HTTP\\HttpResponseResult.cs",
@@ -178,7 +194,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 13,
+ "DocumentIndex": 17,
"Title": "HttpRequestConfig.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\Helper\\HTTP\\HttpRequestConfig.cs",
"RelativeDocumentMoniker": "WIDESEA_Core\\Helper\\HTTP\\HttpRequestConfig.cs",
@@ -190,7 +206,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 12,
+ "DocumentIndex": 16,
"Title": "HttpClientHelper.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\Helper\\HTTP\\HttpClientHelper.cs",
"RelativeDocumentMoniker": "WIDESEA_Core\\Helper\\HTTP\\HttpClientHelper.cs",
@@ -202,7 +218,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 21,
+ "DocumentIndex": 23,
"Title": "OutPutDto.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\GradingMachine\\OutPutDto.cs",
"RelativeDocumentMoniker": "WIDESEA_DTO\\GradingMachine\\OutPutDto.cs",
@@ -214,7 +230,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 20,
+ "DocumentIndex": 22,
"Title": "InputDto.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\GradingMachine\\InputDto.cs",
"RelativeDocumentMoniker": "WIDESEA_DTO\\GradingMachine\\InputDto.cs",
@@ -226,19 +242,19 @@
},
{
"$type": "Document",
- "DocumentIndex": 22,
+ "DocumentIndex": 5,
"Title": "RepositoryBase.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseRepository\\RepositoryBase.cs",
"RelativeDocumentMoniker": "WIDESEA_Core\\BaseRepository\\RepositoryBase.cs",
"ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseRepository\\RepositoryBase.cs",
"RelativeToolTip": "WIDESEA_Core\\BaseRepository\\RepositoryBase.cs",
- "ViewState": "AgIAALgDAAAAAAAAAAAhwMsDAAAZAAAAAAAAAA==",
+ "ViewState": "AgIAALgDAAAAAAAAAAAawMsDAAAZAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-14T08:55:16.1Z"
},
{
"$type": "Document",
- "DocumentIndex": 19,
+ "DocumentIndex": 21,
"Title": "IRepository.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Core\\BaseRepository\\IRepository.cs",
"RelativeDocumentMoniker": "WIDESEA_Core\\BaseRepository\\IRepository.cs",
@@ -250,7 +266,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 18,
+ "DocumentIndex": 20,
"Title": "StockViewService.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockViewService.cs",
"RelativeDocumentMoniker": "WIDESEA_StockService\\StockViewService.cs",
@@ -262,7 +278,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 2,
+ "DocumentIndex": 9,
"Title": "ILocationInfoService.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_IBasicService\\ILocationInfoService.cs",
"RelativeDocumentMoniker": "WIDESEA_IBasicService\\ILocationInfoService.cs",
@@ -274,7 +290,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 17,
+ "DocumentIndex": 19,
"Title": "LocationInfoService.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_BasicService\\LocationInfoService.cs",
"RelativeDocumentMoniker": "WIDESEA_BasicService\\LocationInfoService.cs",
@@ -286,19 +302,19 @@
},
{
"$type": "Document",
- "DocumentIndex": 16,
+ "DocumentIndex": 7,
"Title": "Dt_StockInfo.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Model\\Models\\Stock\\Dt_StockInfo.cs",
"RelativeDocumentMoniker": "WIDESEA_Model\\Models\\Stock\\Dt_StockInfo.cs",
"ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_Model\\Models\\Stock\\Dt_StockInfo.cs",
"RelativeToolTip": "WIDESEA_Model\\Models\\Stock\\Dt_StockInfo.cs",
- "ViewState": "AgIAAEAAAAAAAAAAAAAkwFIAAAAeAAAAAAAAAA==",
+ "ViewState": "AgIAAEAAAAAAAAAAAAAkwFIAAAAuAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-11T01:38:37.887Z"
},
{
"$type": "Document",
- "DocumentIndex": 9,
+ "DocumentIndex": 14,
"Title": "StockInfoService.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockInfoService.cs",
"RelativeDocumentMoniker": "WIDESEA_StockService\\StockInfoService.cs",
@@ -310,7 +326,7 @@
},
{
"$type": "Document",
- "DocumentIndex": 6,
+ "DocumentIndex": 11,
"Title": "IStockInfoService.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_IStockService\\IStockInfoService.cs",
"RelativeDocumentMoniker": "WIDESEA_IStockService\\IStockInfoService.cs",
@@ -322,76 +338,76 @@
},
{
"$type": "Document",
- "DocumentIndex": 4,
+ "DocumentIndex": 3,
"Title": "TaskController.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs",
"RelativeDocumentMoniker": "WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs",
"ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs",
"RelativeToolTip": "WIDESEA_WMSServer\\Controllers\\TaskInfo\\TaskController.cs",
- "ViewState": "AgIAACcAAAAAAAAAAAAIwDcAAABAAAAAAAAAAA==",
+ "ViewState": "AgIAAD0AAAAAAAAAAAAUwFUAAABJAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-09T01:23:19.844Z"
},
{
"$type": "Document",
- "DocumentIndex": 15,
+ "DocumentIndex": 8,
"Title": "CreateTaskDto.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Task\\CreateTaskDto.cs",
"RelativeDocumentMoniker": "WIDESEA_DTO\\Task\\CreateTaskDto.cs",
"ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Task\\CreateTaskDto.cs",
"RelativeToolTip": "WIDESEA_DTO\\Task\\CreateTaskDto.cs",
- "ViewState": "AgIAABEAAAAAAAAAAADwvw4AAAARAAAAAAAAAA==",
+ "ViewState": "AgIAABsAAAAAAAAAAAAywA4AAAARAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-06T07:58:13.932Z"
},
{
"$type": "Document",
- "DocumentIndex": 3,
+ "DocumentIndex": 4,
"Title": "ITaskService.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_ITaskInfoService\\ITaskService.cs",
"RelativeDocumentMoniker": "WIDESEA_ITaskInfoService\\ITaskService.cs",
"ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_ITaskInfoService\\ITaskService.cs",
"RelativeToolTip": "WIDESEA_ITaskInfoService\\ITaskService.cs",
- "ViewState": "AgIAAC0AAAAAAAAAAAAAAEkAAAAIAAAAAAAAAA==",
+ "ViewState": "AgIAAEAAAAAAAAAAAAAUwFEAAAAVAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-06T07:00:19.697Z"
},
{
"$type": "Document",
- "DocumentIndex": 1,
+ "DocumentIndex": 0,
"Title": "TaskService.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_TaskInfoService\\TaskService.cs",
"RelativeDocumentMoniker": "WIDESEA_TaskInfoService\\TaskService.cs",
"ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_TaskInfoService\\TaskService.cs",
"RelativeToolTip": "WIDESEA_TaskInfoService\\TaskService.cs",
- "ViewState": "AgIAADkAAAAAAAAAAAAUwEkAAAAoAAAAAAAAAA==",
+ "ViewState": "AgIAANcAAAAAAAAAAAAgwBYBAABGAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-06T06:34:59.734Z"
+ "WhenOpened": "2026-02-06T06:34:59.734Z",
+ "EditorCaption": ""
},
{
"$type": "Document",
- "DocumentIndex": 10,
+ "DocumentIndex": 1,
"Title": "StockDTO.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Stock\\StockDTO.cs",
"RelativeDocumentMoniker": "WIDESEA_DTO\\Stock\\StockDTO.cs",
"ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_DTO\\Stock\\StockDTO.cs",
"RelativeToolTip": "WIDESEA_DTO\\Stock\\StockDTO.cs",
- "ViewState": "AgIAACMAAAAAAAAAAAAAADoAAAASAAAAAAAAAA==",
+ "ViewState": "AgIAACMAAAAAAAAAAAAAADYAAAAuAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-06T02:56:51.397Z"
},
{
"$type": "Document",
- "DocumentIndex": 0,
+ "DocumentIndex": 2,
"Title": "StockSerivce.cs",
"DocumentMoniker": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockSerivce.cs",
"RelativeDocumentMoniker": "WIDESEA_StockService\\StockSerivce.cs",
"ToolTip": "D:\\Git\\ShanMeiXinNengYuan\\Code\\WMS\\WIDESEA_WMSServer\\WIDESEA_StockService\\StockSerivce.cs",
"RelativeToolTip": "WIDESEA_StockService\\StockSerivce.cs",
- "ViewState": "AgIAACUAAAAAAAAAAAAowD8AAAApAAAAAAAAAA==",
+ "ViewState": "AgIAAAAAAAAAAAAAAAAAAD8AAAApAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-02-06T01:53:49.077Z",
- "EditorCaption": ""
+ "WhenOpened": "2026-02-06T01:53:49.077Z"
}
]
}
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/StockEnum/StockStatusEmun.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/StockEnum/StockStatusEmun.cs
index 65ea267..d8b39a4 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/StockEnum/StockStatusEmun.cs
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_Common/StockEnum/StockStatusEmun.cs
@@ -56,6 +56,9 @@
[Description("閫�搴�")]
MES閫�搴� = 21,
+ [Description("绌烘墭鐩樺簱瀛�")]
+ 绌烘墭鐩樺簱瀛� = 22,
+
[Description("缁勭洏鎾ら攢")]
缁勭洏鎾ら攢 = 99,
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs
index d7b3fa3..4dfe3a3 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs
@@ -79,6 +79,13 @@
Task<WebResponseContent> CreateTaskInboundTrayAsync(CreateTaskDto taskDto);
/// <summary>
+ /// 鍒涘缓绌烘墭鐩樺嚭搴撲换鍔�
+ /// </summary>
+ /// <param name="taskDto"></param>
+ /// <returns></returns>
+ Task<WebResponseContent> GetOutBoundTrayTaskAsync(CreateTaskDto taskDto);
+
+ /// <summary>
/// 鍫嗗灈鏈哄彇鏀捐揣瀹屾垚鍚庣墿娴侀�氱煡鍖栨垚鍒嗗鏌滃畬鎴愪俊鍙�
/// </summary>
/// <param name="input"></param>
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
index 797986d..2a799c9 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
@@ -3,6 +3,7 @@
using SqlSugar;
using System.Text.Json;
using WIDESEA_Common.LocationEnum;
+using WIDESEA_Common.StockEnum;
using WIDESEA_Common.TaskEnum;
using WIDESEA_Core;
using WIDESEA_Core.BaseRepository;
@@ -270,6 +271,44 @@
}
}
+ /// <summary>
+ /// 鍒涘缓绌烘墭鐩樺嚭搴撲换鍔�
+ /// </summary>
+ /// <param name="taskDto"></param>
+ /// <returns></returns>
+ public async Task<WebResponseContent> GetOutBoundTrayTaskAsync(CreateTaskDto taskDto)
+ {
+ try
+ {
+ var stockInfo = await _stockInfoService.Repository.QueryFirstAsync(x => x.LocationDetails.WarehouseId == taskDto.WarehouseId && x.LocationDetails.LocationStatus == LocationStatusEnum.InStock.GetHashCode() && x.StockStatus == StockStatusEmun.绌烘墭鐩樺簱瀛�.GetHashCode());
+ if(stockInfo == null)
+ return WebResponseContent.Instance.Error("鏈壘鍒板搴旂殑搴撳瓨淇℃伅");
+
+ var task = new Dt_Task()
+ {
+ WarehouseId = stockInfo.LocationDetails.WarehouseId,
+ PalletCode = stockInfo.PalletCode,
+ PalletType = stockInfo.PalletType,
+ SourceAddress = stockInfo.LocationCode,
+ CurrentAddress = stockInfo.LocationCode,
+ NextAddress = taskDto.TargetAddress,
+ TargetAddress = taskDto.TargetAddress,
+ Roadway = stockInfo.LocationDetails.RoadwayNo,
+ TaskType = TaskTypeEnum.OutEmpty.GetHashCode(),
+ TaskStatus = TaskStatusEnum.New.GetHashCode(),
+ Grade = 1,
+ TaskNum = await BaseDal.GetTaskNo(),
+ Creater = "system",
+ };
+ var taskDtos = _mapper.Map<List<WMSTaskDTO>>(task);
+ return WebResponseContent.Instance.OK("鏌ヨ鎴愬姛", taskDtos);
+ }
+ catch (Exception ex)
+ {
+ return WebResponseContent.Instance.Error($"鏌ヨ浠诲姟澶辫触: {ex.Message}");
+ }
+ }
+
#region 鍒嗗鏌滄帴鍙�
/// <summary>
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs
index 8df930c..5f0f297 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs
@@ -79,6 +79,17 @@
}
/// <summary>
+ /// 鍒涘缓绌烘墭鐩樺嚭搴撲换鍔�
+ /// </summary>
+ /// <param name="taskDto"></param>
+ /// <returns></returns>
+ [HttpGet, HttpPost, Route("GetOutBoundTrayTask"), AllowAnonymous]
+ public async Task<WebResponseContent?> GetOutBoundTrayTaskAsync([FromBody] CreateTaskDto taskDto)
+ {
+ return await Service.GetOutBoundTrayTaskAsync(taskDto);
+ }
+
+ /// <summary>
/// 鍫嗗灈鏈哄彇鏀捐揣瀹屾垚鍚庣墿娴侀�氱煡鍖栨垚鍒嗗鏌滃畬鎴愪俊鍙�
/// </summary>
/// <param name="input"></param>
--
Gitblit v1.9.3