Compare commits

...

48 Commits

Author SHA1 Message Date
2248356998 qq.com
0e44bc67cd feat: 系统总/可用内存读取 适配docker容器,硬件信息页面增加GC数据显示 2025-10-22 23:24:28 +08:00
2248356998 qq.com
12dfbba42c build: 10.12.6 2025-10-22 15:30:56 +08:00
2248356998 qq.com
96b4287f3a fix: operResult隐式转换递归错误 2025-10-22 13:43:39 +08:00
2248356998 qq.com
7d406de29f 调整 runtimeconfig.template.json 文件 2025-10-22 00:47:33 +08:00
2248356998 qq.com
81f0ef466a perf: 优化文本日志性能 2025-10-21 17:40:21 +08:00
2248356998 qq.com
3f2d6b133c 更新依赖包 2025-10-21 17:26:46 +08:00
Diego
e776dc67eb Remove language support from wiki.json
Removed supported languages and default language settings.
2025-10-21 15:58:01 +08:00
devin-ai-integration[bot]
bc5827d140 Update wiki.json (#26)
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-10-21 15:54:04 +08:00
2248356998 qq.com
21838bf4af perf: 异步池化性能 2025-10-21 10:56:11 +08:00
2248356998 qq.com
6090108597 build: 10.11.118 2025-10-20 22:15:24 +08:00
2248356998 qq.com
b47b9e6f43 build: 10.11.118 2025-10-20 22:15:10 +08:00
2248356998 qq.com
18d1cffb2d perf: 异步池化性能 2025-10-20 20:32:31 +08:00
2248356998 qq.com
516fd7f235 build: 10.11.116
fix: 网关监控页面 js释放
test: Benchmark编译错误
2025-10-20 15:10:50 +08:00
2248356998 qq.com
2ee16c3533 test: Benchmark编译错误 2025-10-20 14:38:05 +08:00
2248356998 qq.com
7d22f5c78e test: Benchmark编译错误 2025-10-20 14:36:52 +08:00
2248356998 qq.com
3e604ee2fd refactor: 变量删除创建机构等信息,改用绑定的设备的机构信息 2025-10-19 19:39:42 +08:00
2248356998 qq.com
47e442874c pref: 异步状态机优化 2025-10-18 23:14:55 +08:00
2248356998 qq.com
2a8c0cbab1 pref: 异步状态机优化 2025-10-18 03:18:45 +08:00
2248356998 qq.com
c26898b49d feat: 网关监控变量在线状态醒目显示 2025-10-17 12:30:05 +08:00
2248356998 qq.com
00c24d06a3 chore: 更新TouchSocket依赖 2025-10-17 00:50:36 +08:00
2248356998 qq.com
3461f34240 feat: 网关监控页面树节点js更新状态
perf: 优化变量页面刷新性能
perf: 优化热点方法异步性能
2025-10-17 00:41:47 +08:00
2248356998 qq.com
aa1ce08c02 perf: 优化变量页面刷新性能 2025-10-16 18:15:42 +08:00
2248356998 qq.com
9c230c2da9 chore: ui json显示不缩进 2025-10-16 17:39:57 +08:00
2248356998 qq.com
21215d0379 build: 10.11.109
feat: js刷新变量表数据
chore: 更新BootstrapBlazor.Chart依赖
2025-10-16 16:16:07 +08:00
Diego
7448183791 !78 feat: js刷新变量表数据
* 调整列宽
* feat: js刷新变量表数据
2025-10-16 08:09:29 +00:00
Diego
35edd7dc43 !77 update src/Admin/ThingsGateway.Common/Common/ConcurrentList.cs.
Merge pull request !77 from Sunny/v10
2025-10-16 06:14:04 +00:00
Sunny
bd178831e3 update src/Admin/ThingsGateway.Common/Common/ConcurrentList.cs.
修改 ConcurrentList.cs 一处错误代码

Signed-off-by: Sunny <yhuse@163.com>
2025-10-16 04:36:31 +00:00
2248356998 qq.com
fe9ec6ad10 fix: s7连接错误 2025-10-16 12:00:08 +08:00
2248356998 qq.com
6f9ec2e24b feat: 并发字典替换为 NonBlockingDictionary 类型 2025-10-15 17:40:33 +08:00
2248356998 qq.com
c0337e2b19 build: 10.11.105
feat: json添加AllowNamedFloatingPointLiterals
2025-10-15 11:16:18 +08:00
2248356998 qq.com
8a95f48f5a 适配 net10 rc2 2025-10-15 10:02:11 +08:00
2248356998 qq.com
14f3c31265 build: 10.11.102 2025-10-14 22:22:06 +08:00
2248356998 qq.com
1bad65378f build: 10.11.101 2025-10-14 11:46:26 +08:00
2248356998 qq.com
db3affc67e build: 10.11.100
feat(VariablePage): 优化UI性能
2025-10-14 10:18:09 +08:00
2248356998 qq.com
5ee8b50a92 build: 10.11.99 2025-10-13 22:11:05 +08:00
2248356998 qq.com
301beda2a2 build: 10.11.98 2025-10-13 21:10:39 +08:00
2248356998 qq.com
628b51a353 build: 10.11.97 2025-10-12 15:15:42 +08:00
2248356998 qq.com
f03445bc83 更新依赖 2025-10-12 00:25:57 +08:00
2248356998 qq.com
55a2ff5487 build: 10.11.96 2025-10-11 13:38:28 +08:00
2248356998 qq.com
0fef7dcf3b 更新依赖 2025-10-10 21:41:24 +08:00
2248356998 qq.com
19d9702606 fix: sqlite 批量更新 2025-10-10 14:19:43 +08:00
2248356998 qq.com
a8a9774932 fix: orm 序列化 2025-10-10 12:26:35 +08:00
2248356998 qq.com
aad0f0e8c3 fix: orm批量插入 2025-10-10 11:19:14 +08:00
2248356998 qq.com
e74eae50a7 build: 10.11.87 2025-10-09 20:58:16 +08:00
2248356998 qq.com
3b16d7019f feat: 优化orm 批量插入 2025-10-09 20:57:18 +08:00
2248356998 qq.com
3e038028c2 feat: 优化orm 批量插入 2025-10-09 19:19:18 +08:00
2248356998 qq.com
b1d8041f7e feat: 优化orm BulkCopy 2025-10-09 19:05:33 +08:00
2248356998 qq.com
53a98b26cd fix: 数据库插件保留天数逻辑错误 2025-10-09 08:52:02 +08:00
542 changed files with 15896 additions and 5367 deletions

View File

@@ -1,11 +1,18 @@
# ThingsGateway # ThingsGateway
 [![star](https://gitee.com/ThingsGateway/ThingsGateway/badge/star.svg?theme=gvp)](https://gitee.com/ThingsGateway/ThingsGateway/stargazers)
[![star](https://img.shields.io/github/stars/ThingsGateway/ThingsGateway?logo=github)](https://github.com/ThingsGateway/ThingsGateway)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/ThingsGateway/ThingsGateway)
[![NuGet(ThingsGateway)](https://img.shields.io/nuget/v/ThingsGateway.Foundation.svg?label=ThingsGateway)](https://www.nuget.org/packages/ThingsGateway.Foundation/)
[![NuGet(ThingsGateway)](https://img.shields.io/nuget/dt/ThingsGateway.Foundation.svg)](https://www.nuget.org/packages/ThingsGateway.Foundation/)
[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://thingsgateway.cn/docs/1)
<a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=NnBjPO-8kcNFzo_RzSbdICflb97u2O1i&authKey=V1MI3iJtpDMHc08myszP262kDykbx2Yev6ebE4Me0elTe0P0IFAmtU5l7Sy5w0jx&noverify=0&group_code=605534569">
<img src="https://img.shields.io/badge/QQ群-605534569-red" alt="QQ">
</a>
## Introduction ## Introduction
 
A cross-platform, high-performance edge data collection gateway based on net9. A cross-platform, high-performance edge data collection gateway based on net8/10.
 
## Documentation ## Documentation
@@ -29,7 +36,6 @@ Account: **SuperAdmin**
Password: **111111** Password: **111111**
 
**In the upper-right corner, switch to the IoT Gateway module in the personal popup box**
## Docker ## Docker

View File

@@ -1,8 +1,18 @@
# ThingsGateway # ThingsGateway
[![star](https://gitee.com/ThingsGateway/ThingsGateway/badge/star.svg?theme=gvp)](https://gitee.com/ThingsGateway/ThingsGateway/stargazers)
[![star](https://img.shields.io/github/stars/ThingsGateway/ThingsGateway?logo=github)](https://github.com/ThingsGateway/ThingsGateway)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/ThingsGateway/ThingsGateway)
[![NuGet(ThingsGateway)](https://img.shields.io/nuget/v/ThingsGateway.Foundation.svg?label=ThingsGateway)](https://www.nuget.org/packages/ThingsGateway.Foundation/)
[![NuGet(ThingsGateway)](https://img.shields.io/nuget/dt/ThingsGateway.Foundation.svg)](https://www.nuget.org/packages/ThingsGateway.Foundation/)
[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://thingsgateway.cn/docs/1)
<a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=NnBjPO-8kcNFzo_RzSbdICflb97u2O1i&authKey=V1MI3iJtpDMHc08myszP262kDykbx2Yev6ebE4Me0elTe0P0IFAmtU5l7Sy5w0jx&noverify=0&group_code=605534569">
<img src="https://img.shields.io/badge/QQ群-605534569-red" alt="QQ">
</a>
## 介绍 ## 介绍
基于net9的跨平台高性能边缘采集网关 基于net8/10的跨平台高性能边缘采集网关
## 文档 ## 文档
@@ -19,7 +29,6 @@
密码 : **111111** 密码 : **111111**
**右上角个人弹出框中,切换到物联网关模块**
## Docker ## Docker

View File

@@ -251,11 +251,13 @@ public class RequestAuditFilter : IAsyncActionFilter, IOrderedFilter
if (exception == null) if (exception == null)
{ {
logger.Log(LogLevel.Information, $"{logData.Method}:{logData.Path}-{logData.Operation}"); if (logger.IsEnabled(LogLevel.Information))
logger.Log(LogLevel.Information, $"{logData.Method}:{logData.Path}-{logData.Operation}");
} }
else else
{ {
logger.Log(LogLevel.Warning, $"{logData.Method}:{logData.Path}-{logData.Operation}{Environment.NewLine}{logData.Exception?.ToSystemTextJsonString()}{Environment.NewLine}{logData.Validation?.ToSystemTextJsonString()}"); if (logger.IsEnabled(LogLevel.Warning))
logger.Log(LogLevel.Warning, $"{logData.Method}:{logData.Path}-{logData.Operation}{Environment.NewLine}{logData.Exception?.ToSystemTextJsonString()}{Environment.NewLine}{logData.Validation?.ToSystemTextJsonString()}");
} }
} }

View File

@@ -8,6 +8,9 @@
// QQ群605534569 // QQ群605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
using System.ComponentModel;
using System.Runtime;
using ThingsGateway.NewLife; using ThingsGateway.NewLife;
namespace ThingsGateway.Admin.Application; namespace ThingsGateway.Admin.Application;
@@ -19,11 +22,7 @@ public class HardwareInfo
/// 当前磁盘信息 /// 当前磁盘信息
/// </summary> /// </summary>
public DriveInfo DriveInfo { get; set; } public DriveInfo DriveInfo { get; set; }
/// <summary>
/// 硬件信息获取
/// </summary>
public MachineInfo? MachineInfo { get; set; }
/// <summary> /// <summary>
/// 主机环境 /// 主机环境
@@ -40,19 +39,118 @@ public class HardwareInfo
/// </summary> /// </summary>
public string OsArchitecture { get; set; } public string OsArchitecture { get; set; }
/// <summary>
/// 唯一编码
/// </summary>
public string UUID { get; set; }
/// <summary> /// <summary>系统名称</summary>
/// 进程占用内存 public String OSName { get; set; }
/// </summary>
[AutoGenerateColumn(Ignore = true)] /// <summary>系统版本</summary>
public int WorkingSet { get; set; } public String OSVersion { get; set; }
public String UUID { get; set; }
/// <summary>内存总量。单位MB</summary>
public UInt64 Memory { get; set; }
/// <summary>可用内存。单位MB</summary>
public UInt64 AvailableMemory { get; set; }
/// <summary>CPU占用率</summary>
public Double CpuRate { get; set; }
public Double Battery { get; set; }
public Double Temperature { get; set; }
/// <summary>处理器型号</summary>
public String? Processor { get; set; }
#region GC与进程内存信息
/// <summary>GC 认为“内存吃紧”的阈值。单位MB</summary>
[DisplayName("GC高内存阈值")]
public UInt64 HighMemoryLoadThreshold { get; set; }
/// <summary>GC 可用内存上限。单位MB</summary>
[DisplayName("GC可用内存上限")]
public UInt64 TotalAvailableMemory { get; set; }
/// <summary>当前托管堆容量。单位MB</summary>
[DisplayName("托管堆容量")]
public UInt64 HeapSize { get; set; }
/// <summary>托管堆已用内存。单位MB</summary>
[DisplayName("托管堆已用")]
public UInt64 TotalMemory { get; set; }
/// <summary>托管堆碎片大小。单位MB</summary>
[DisplayName("托管堆碎片")]
public UInt64 FragmentedBytes { get; set; }
/// <summary>GC识别可用内存。单位MB</summary>
[DisplayName("GC识别可用内存")]
public UInt64 GCAvailableMemory { get; set; }
/// <summary>GC 已提交的内存。单位MB</summary>
[DisplayName("GC已提交内存")]
public UInt64 CommittedBytes { get; set; }
/// <summary>GC 累计分配的托管内存。单位MB</summary>
[DisplayName("GC累计分配")]
public UInt64 TotalAllocatedBytes { get; set; }
/// <summary>GC 暂停累计时间。单位:毫秒</summary>
[DisplayName("GC累计暂停时间")]
public UInt64 TotalPauseDurationMs { get; set; }
/// <summary>GC 代0收集次数</summary>
[DisplayName("GC Gen0 次数")]
public Int32 GcGen0Count { get; set; }
/// <summary>GC 代1收集次数</summary>
[DisplayName("GC Gen1 次数")]
public Int32 GcGen1Count { get; set; }
/// <summary>GC 代2收集次数</summary>
[DisplayName("GC Gen2 次数")]
public Int32 GcGen2Count { get; set; }
/// <summary>Server GC 是否启用</summary>
[DisplayName("是否使用Server GC")]
public Boolean IsServerGC { get; set; }
/// <summary>GC 延迟模式</summary>
[DisplayName("GC延迟模式")]
public GCLatencyMode? GCLatencyMode { get; set; }
/// <summary>GC 固定对象数</summary>
[DisplayName("固定对象数")]
public Int64 PinnedObjectsCount { get; set; }
/// <summary>终结队列挂起对象数</summary>
[DisplayName("终结挂起数")]
public Int64 FinalizationPendingCount { get; set; }
#endregion
#region
/// <summary>进程虚拟内存使用量。单位MB</summary>
[DisplayName("虚拟内存")]
public UInt64 VirtualMemory { get; set; }
/// <summary>进程私有内存使用量。单位MB</summary>
[DisplayName("私有内存")]
public UInt64 PrivateMemory { get; set; }
/// <summary>进程峰值工作集。单位MB</summary>
[DisplayName("峰值工作集")]
public UInt64 PeakWorkingSet { get; set; }
/// <summary>进程当前工作集。单位MB</summary>
[DisplayName("当前工作集")]
public UInt64 WorkingSet { get; set; }
#endregion
/// <summary> /// <summary>
/// 更新时间 /// 更新时间
/// </summary> /// </summary>
public string UpdateTime { get; set; } public DateTime UpdateTime { get; set; }
public ulong AppRunTotalMinute { get; set; }
public ulong SystemRunTotalMinute { get; set; }
} }

View File

@@ -8,12 +8,10 @@
// QQ群605534569 // QQ群605534569
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using ThingsGateway.Extension;
using ThingsGateway.NewLife; using ThingsGateway.NewLife;
using ThingsGateway.NewLife.Caching; using ThingsGateway.NewLife.Caching;
using ThingsGateway.NewLife.Threading; using ThingsGateway.NewLife.Threading;
@@ -43,7 +41,7 @@ public class HardwareJob : IJob, IHardwareJob
/// <summary> /// <summary>
/// 运行信息获取 /// 运行信息获取
/// </summary> /// </summary>
public HardwareInfo HardwareInfo { get; } = new(); public HardwareInfo HardwareInfo { get; private set; }
/// <inheritdoc/> /// <inheritdoc/>
public HardwareInfoOptions HardwareInfoOptions { get; private set; } public HardwareInfoOptions HardwareInfoOptions { get; private set; }
@@ -76,9 +74,10 @@ public class HardwareJob : IJob, IHardwareJob
{ {
try try
{ {
if (HardwareInfo.MachineInfo == null) var machine = MachineInfo.GetCurrent();
if (HardwareInfo == null)
{ {
HardwareInfo.MachineInfo = MachineInfo.GetCurrent(); HardwareInfo=machine.AdaptHardwareInfo();
string currentPath = Directory.GetCurrentDirectory(); string currentPath = Directory.GetCurrentDirectory();
DriveInfo drive = new(Path.GetPathRoot(currentPath)); DriveInfo drive = new(Path.GetPathRoot(currentPath));
@@ -88,10 +87,9 @@ public class HardwareJob : IJob, IHardwareJob
HardwareInfo.DriveInfo = drive; HardwareInfo.DriveInfo = drive;
HardwareInfo.OsArchitecture = Environment.OSVersion.Platform.ToString() + " " + RuntimeInformation.OSArchitecture.ToString(); // 系统架构 HardwareInfo.OsArchitecture = Environment.OSVersion.Platform.ToString() + " " + RuntimeInformation.OSArchitecture.ToString(); // 系统架构
HardwareInfo.FrameworkDescription = RuntimeInformation.FrameworkDescription; // NET框架 HardwareInfo.FrameworkDescription = RuntimeInformation.FrameworkDescription; // NET框架
HardwareInfo.Environment = App.HostEnvironment.IsDevelopment() ? "Development" : "Production"; HardwareInfo.Environment = App.HostEnvironment.EnvironmentName;
HardwareInfo.UUID = HardwareInfo.MachineInfo.UUID;
HardwareInfo.UpdateTime = TimerX.Now.ToDefaultDateTimeFormat(); HardwareInfo.UpdateTime = TimerX.Now;
} }
} }
catch catch
@@ -99,9 +97,12 @@ public class HardwareJob : IJob, IHardwareJob
} }
try try
{ {
HardwareInfo.MachineInfo.Refresh(); var machine = MachineInfo.GetCurrent();
HardwareInfo.UpdateTime = TimerX.Now.ToDefaultDateTimeFormat(); machine.Refresh();
HardwareInfo.WorkingSet = (Environment.WorkingSet / 1024.0 / 1024.0).ToInt(); machine.AdaptHardwareInfo(HardwareInfo);
HardwareInfo.AppRunTotalMinute = (ulong)Runtime.AppTickCount64 / 1000 /60;
HardwareInfo.SystemRunTotalMinute = (ulong)Runtime.TickCount64 / 1000 /60;
HardwareInfo.UpdateTime = TimerX.Now;
error = false; error = false;
} }
catch (Exception ex) catch (Exception ex)
@@ -123,10 +124,10 @@ public class HardwareJob : IJob, IHardwareJob
{ {
Date = TimerX.Now, Date = TimerX.Now,
DriveUsage = (100 - (HardwareInfo.DriveInfo.TotalFreeSpace * 100.00 / HardwareInfo.DriveInfo.TotalSize)).ToInt(), DriveUsage = (100 - (HardwareInfo.DriveInfo.TotalFreeSpace * 100.00 / HardwareInfo.DriveInfo.TotalSize)).ToInt(),
Battery = (HardwareInfo.MachineInfo.Battery * 100).ToInt(), Battery = (HardwareInfo.Battery * 100).ToInt(),
MemoryUsage = (HardwareInfo.WorkingSet), MemoryUsage = (HardwareInfo.WorkingSet),
CpuUsage = (HardwareInfo.MachineInfo.CpuRate * 100).ToInt(), CpuUsage = (HardwareInfo.CpuRate * 100).ToInt(),
Temperature = (HardwareInfo.MachineInfo.Temperature).ToInt(), Temperature = (HardwareInfo.Temperature).ToInt(),
}; };
await _db.InsertableT(his).ExecuteCommandAsync(stoppingToken).ConfigureAwait(false); await _db.InsertableT(his).ExecuteCommandAsync(stoppingToken).ConfigureAwait(false);
MemoryCache.Remove(CacheKey); MemoryCache.Remove(CacheKey);

View File

@@ -21,7 +21,7 @@ public class HistoryHardwareInfo
/// <inheritdoc/> /// <inheritdoc/>
[SugarColumn(ColumnDescription = "内存")] [SugarColumn(ColumnDescription = "内存")]
public int MemoryUsage { get; set; } public UInt64 MemoryUsage { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
[SugarColumn(ColumnDescription = "CPU使用率")] [SugarColumn(ColumnDescription = "CPU使用率")]

View File

@@ -21,7 +21,7 @@
"UserNoModule": "This account has not been assigned a module. Please contact the administrator", "UserNoModule": "This account has not been assigned a module. Please contact the administrator",
"UserNull": "User {0} does not exist" "UserNull": "User {0} does not exist"
}, },
"ThingsGateway.Admin.Application.BlazorAuthenticationHandler": { "ThingsGateway.Admin.Application.BlazorAuthenticationHandler": {
"UserExpire": "User expired, please login again" "UserExpire": "User expired, please login again"
}, },
@@ -46,12 +46,44 @@
"FileTypeError": "Not supported format {0}" "FileTypeError": "Not supported format {0}"
}, },
"ThingsGateway.Admin.Application.HardwareInfo": { "ThingsGateway.Admin.Application.HardwareInfo": {
"Environment": "HostEnvironment", "DriveInfo": "Current Disk Info",
"FrameworkDescription": ".NETFramework", "AppRunTotalMinute": "AppRunTotalMinute(min)",
"OsArchitecture": "System Architecture", "SystemRunTotalMinute": "SystemRunTotalMinute(min)",
"UpdateTime": "UpdateTime", "Environment": "Host Environment",
"UUID": "UUID" "FrameworkDescription": ".NET Framework",
"OsArchitecture": "OS Architecture",
"OSName": "OS Name",
"OSVersion": "OS Version",
"UUID": "UUID",
"Memory": "Total Memory",
"AvailableMemory": "Available Memory",
"CpuRate": "CPU Usage",
"Battery": "Battery Level",
"Temperature": "Temperature",
"Processor": "Processor Model",
"HighMemoryLoadThreshold": "GC High Memory Threshold",
"TotalAvailableMemory": "GC Total Available Memory",
"HeapSize": "Managed Heap Size",
"TotalMemory": "Managed Heap Used",
"FragmentedBytes": "Managed Heap Fragmented",
"GCAvailableMemory": "GC Available Memory",
"CommittedBytes": "GC Committed Bytes",
"TotalAllocatedBytes": "GC Total Allocated (MB)",
"TotalPauseDurationMs": "GC Total Pause Duration (ms)",
"GcGen0Count": "GC Gen0 Count",
"GcGen1Count": "GC Gen1 Count",
"GcGen2Count": "GC Gen2 Count",
"IsServerGC": "Server GC",
"GCLatencyMode": "GC Latency Mode",
"PinnedObjectsCount": "Pinned Objects Count",
"FinalizationPendingCount": "Finalization Pending Count",
"VirtualMemory": "Virtual Memory",
"PrivateMemory": "Private Memory",
"PeakWorkingSet": "Peak Working Set",
"WorkingSet": "Current Working Set",
"UpdateTime": "Update Time"
}, },
"ThingsGateway.Admin.Application.HardwareJob": { "ThingsGateway.Admin.Application.HardwareJob": {
"GetHardwareInfoFail": "Get Hardwareinfo Fail" "GetHardwareInfoFail": "Get Hardwareinfo Fail"
}, },

View File

@@ -46,11 +46,42 @@
"FileTypeError": "不支持 {0} 格式" "FileTypeError": "不支持 {0} 格式"
}, },
"ThingsGateway.Admin.Application.HardwareInfo": { "ThingsGateway.Admin.Application.HardwareInfo": {
"DriveInfo": "当前磁盘信息",
"AppRunTotalMinute": "软件运行时长(min)",
"SystemRunTotalMinute": "系统运行时长(min)",
"Environment": "主机环境", "Environment": "主机环境",
"FrameworkDescription": "NET框架", "FrameworkDescription": ".NET 框架",
"OsArchitecture": "系统架构", "OsArchitecture": "系统架构",
"UpdateTime": "更新时间", "OSName": "系统名称",
"UUID": "唯一编码" "OSVersion": "系统版本",
"UUID": "UUID",
"Memory": "系统总内存",
"AvailableMemory": "系统可用内存",
"CpuRate": "CPU 占用率",
"Battery": "电池电量",
"Temperature": "温度",
"Processor": "处理器型号",
"HighMemoryLoadThreshold": "GC 高内存阈值",
"TotalAvailableMemory": "GC 总内存阈值",
"HeapSize": "托管堆容量",
"TotalMemory": "托管对象占用",
"FragmentedBytes": "托管堆碎片",
"GCAvailableMemory": "GC 可用内存",
"CommittedBytes": "GC 提交内存总量",
"TotalAllocatedBytes": "GC 累计分配(MB)",
"TotalPauseDurationMs": "GC 累计暂停时间(ms)",
"GcGen0Count": "GC Gen0 次数",
"GcGen1Count": "GC Gen1 次数",
"GcGen2Count": "GC Gen2 次数",
"IsServerGC": "Server GC",
"GCLatencyMode": "GC 延迟模式",
"PinnedObjectsCount": "固定对象数",
"FinalizationPendingCount": "终结挂起数",
"VirtualMemory": "虚拟内存",
"PrivateMemory": "私有内存",
"PeakWorkingSet": "峰值工作集",
"WorkingSet": "当前工作集",
"UpdateTime": "更新时间"
}, },
"ThingsGateway.Admin.Application.HardwareJob": { "ThingsGateway.Admin.Application.HardwareJob": {
"GetHardwareInfoFail": "获取硬件信息出错" "GetHardwareInfoFail": "获取硬件信息出错"

View File

@@ -8,13 +8,20 @@
// QQ群605534569 // QQ群605534569
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
using BootstrapBlazor.Components;
using Riok.Mapperly.Abstractions; using Riok.Mapperly.Abstractions;
using ThingsGateway.NewLife;
namespace ThingsGateway.Admin.Application; namespace ThingsGateway.Admin.Application;
[Mapper(UseDeepCloning = true, EnumMappingStrategy = EnumMappingStrategy.ByName, RequiredMappingStrategy = RequiredMappingStrategy.None)] [Mapper(UseDeepCloning = true, EnumMappingStrategy = EnumMappingStrategy.ByName, RequiredMappingStrategy = RequiredMappingStrategy.None)]
public static partial class AdminMapper public static partial class AdminMapper
{ {
public static partial HardwareInfo AdaptHardwareInfo(this MachineInfo src);
public static partial void AdaptHardwareInfo(this MachineInfo src, HardwareInfo dto);
public static partial LoginInput AdaptLoginInput(this OpenApiLoginInput src); public static partial LoginInput AdaptLoginInput(this OpenApiLoginInput src);
public static partial OpenApiLoginOutput AdaptOpenApiLoginOutput(this LoginOutput src); public static partial OpenApiLoginOutput AdaptOpenApiLoginOutput(this LoginOutput src);
public static partial SessionOutput AdaptSessionOutput(this SysUser src); public static partial SessionOutput AdaptSessionOutput(this SysUser src);

View File

@@ -20,7 +20,7 @@ namespace ThingsGateway.Admin.Application;
/// <typeparam name="TEntry"></typeparam> /// <typeparam name="TEntry"></typeparam>
public class EventService<TEntry> : IEventService<TEntry>, IDisposable public class EventService<TEntry> : IEventService<TEntry>, IDisposable
{ {
private ConcurrentDictionary<string, Func<TEntry, Task>> Cache = new(); private NonBlockingDictionary<string, Func<TEntry, Task>> Cache = new();
public void Dispose() public void Dispose()
{ {

View File

@@ -19,12 +19,14 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Riok.Mapperly" Version="4.2.1" ExcludeAssets="runtime" PrivateAssets="all" /> <PackageReference Include="Riok.Mapperly" Version="4.3.0" ExcludeAssets="runtime" PrivateAssets="all">
<PackageReference Include="Rougamo.Fody" Version="5.0.1" /> <IncludeAssets>compile; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Rougamo.Fody" Version="5.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' "> <ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" />
<PackageReference Include="System.Formats.Asn1" Version="8.0.2" /> <PackageReference Include="System.Formats.Asn1" Version="9.0.10" />
<PackageReference Include="System.Threading.RateLimiting" Version="8.0.0" /> <PackageReference Include="System.Threading.RateLimiting" Version="8.0.0" />
</ItemGroup> </ItemGroup>

View File

@@ -4,8 +4,8 @@
<div class="tg-table h-100"> <div class="tg-table h-100">
<Table TItem="TItem" IsBordered="true" IsStriped="true" TableSize="TableSize.Compact" SelectedRows=SelectedRows SelectedRowsChanged=privateSelectedRowsChanged IsMultipleSelect="IsMultipleSelect" @ref="Instance" SearchTemplate="SearchTemplate" <Table Id=@Id TItem="TItem" IsBordered="true" IsStriped="true" TableSize="TableSize.Compact" SelectedRows=SelectedRows SelectedRowsChanged=privateSelectedRowsChanged IsMultipleSelect="IsMultipleSelect" @ref="Instance" SearchTemplate="SearchTemplate"
DataService="DataService" CreateItemCallback="CreateItemCallback!" DataService="DataService" CreateItemCallback="CreateItemCallback!" RenderMode=RenderMode OnColumnCreating=OnColumnCreating
IsPagination="IsPagination" PageItemsSource="PageItemsSource" IsFixedHeader="IsFixedHeader" IndentSize=24 RowHeight=RowHeight ShowSearchText="ShowSearchText" ShowSearchButton="ShowSearchButton" DisableEditButtonCallback="DisableEditButtonCallback" DisableDeleteButtonCallback="DisableDeleteButtonCallback" BeforeShowEditDialogCallback=" BeforeShowEditDialogCallback!" IsPagination="IsPagination" PageItemsSource="PageItemsSource" IsFixedHeader="IsFixedHeader" IndentSize=24 RowHeight=RowHeight ShowSearchText="ShowSearchText" ShowSearchButton="ShowSearchButton" DisableEditButtonCallback="DisableEditButtonCallback" DisableDeleteButtonCallback="DisableDeleteButtonCallback" BeforeShowEditDialogCallback=" BeforeShowEditDialogCallback!"
IsTree="IsTree" OnTreeExpand="OnTreeExpand!" TreeNodeConverter="TreeNodeConverter!" TreeIcon="fa-solid fa-circle-chevron-right" TreeExpandIcon="fa-solid fa-circle-chevron-right fa-rotate-90" IsAutoQueryFirstRender=IsAutoQueryFirstRender IsTree="IsTree" OnTreeExpand="OnTreeExpand!" TreeNodeConverter="TreeNodeConverter!" TreeIcon="fa-solid fa-circle-chevron-right" TreeExpandIcon="fa-solid fa-circle-chevron-right fa-rotate-90" IsAutoQueryFirstRender=IsAutoQueryFirstRender
ShowDefaultButtons="ShowDefaultButtons" ShowAdvancedSearch="ShowAdvancedSearch" ShowResetButton=ShowResetButton ShowDefaultButtons="ShowDefaultButtons" ShowAdvancedSearch="ShowAdvancedSearch" ShowResetButton=ShowResetButton
@@ -14,7 +14,7 @@
ShowSkeleton="true" ShowLoading="ShowLoading" ShowSearch="ShowSearch" SearchModel=@SearchModel ShowLineNo ShowSkeleton="true" ShowLoading="ShowLoading" ShowSearch="ShowSearch" SearchModel=@SearchModel ShowLineNo
SearchMode=SearchMode ShowExportPdfButton=ShowExportPdfButton ExportButtonText=@ExportButtonText SearchMode=SearchMode ShowExportPdfButton=ShowExportPdfButton ExportButtonText=@ExportButtonText
ShowExportButton=@ShowExportButton Items=Items ClickToSelect=ClickToSelect ScrollMode=ScrollMode ShowExportButton=@ShowExportButton Items=Items ClickToSelect=ClickToSelect ScrollMode=ScrollMode
ShowExportCsvButton=@ShowExportCsvButton ShowCardView=ShowCardView ShowExportCsvButton=@ShowExportCsvButton ShowCardView=ShowCardView OnColumnVisibleChanged=OnColumnVisibleChanged
FixedExtendButtonsColumn=FixedExtendButtonsColumn FixedMultipleColumn=FixedMultipleColumn FixedDetailRowHeaderColumn=FixedDetailRowHeaderColumn FixedLineNoColumn=FixedLineNoColumn FixedExtendButtonsColumn=FixedExtendButtonsColumn FixedMultipleColumn=FixedMultipleColumn FixedDetailRowHeaderColumn=FixedDetailRowHeaderColumn FixedLineNoColumn=FixedLineNoColumn
IsAutoRefresh=IsAutoRefresh AutoRefreshInterval=AutoRefreshInterval IsAutoRefresh=IsAutoRefresh AutoRefreshInterval=AutoRefreshInterval
AllowDragColumn=@AllowDragColumn Height=@Height ShowRefresh=ShowRefresh AllowDragColumn=@AllowDragColumn Height=@Height ShowRefresh=ShowRefresh
@@ -41,6 +41,7 @@
DoubleClickToEdit="DoubleClickToEdit" DoubleClickToEdit="DoubleClickToEdit"
OnDoubleClickCellCallback="OnDoubleClickCellCallback" OnDoubleClickCellCallback="OnDoubleClickCellCallback"
OnDoubleClickRowCallback="OnDoubleClickRowCallback" OnDoubleClickRowCallback="OnDoubleClickRowCallback"
RowContentTemplate="RowContentTemplate"
OnClickRowCallback="OnClickRowCallback"> OnClickRowCallback="OnClickRowCallback">
</Table> </Table>
</div> </div>

View File

@@ -13,6 +13,23 @@ namespace ThingsGateway.Admin.Razor;
[CascadingTypeParameter(nameof(TItem))] [CascadingTypeParameter(nameof(TItem))]
public partial class AdminTable<TItem> where TItem : class, new() public partial class AdminTable<TItem> where TItem : class, new()
{ {
/// <inheritdoc cref="Table{TItem}.OnColumnVisibleChanged"/>
[Parameter]
public Func<string, bool, Task> OnColumnVisibleChanged { get; set; }
/// <inheritdoc cref="Table{TItem}.OnColumnCreating"/>
[Parameter]
public Func<List<ITableColumn>, Task> OnColumnCreating { get; set; }
/// <inheritdoc cref="Table{TItem}.RenderMode"/>
[Parameter]
public TableRenderMode RenderMode { get; set; }
public List<ITableColumn> Columns => Instance?.Columns;
public IEnumerable<ITableColumn> GetVisibleColumns => Instance?.GetVisibleColumns();
public List<TItem> Rows => Instance?.Rows;
/// <inheritdoc cref="Table{TItem}.SelectedRowsChanged"/> /// <inheritdoc cref="Table{TItem}.SelectedRowsChanged"/>
[Parameter] [Parameter]
public EventCallback<List<TItem>> SelectedRowsChanged { get; set; } public EventCallback<List<TItem>> SelectedRowsChanged { get; set; }
@@ -40,6 +57,10 @@ public partial class AdminTable<TItem> where TItem : class, new()
/// <inheritdoc cref="Table{TItem}.OnDoubleClickRowCallback"/> /// <inheritdoc cref="Table{TItem}.OnDoubleClickRowCallback"/>
[Parameter] [Parameter]
public Func<TItem, Task>? OnDoubleClickRowCallback { get; set; } public Func<TItem, Task>? OnDoubleClickRowCallback { get; set; }
/// <inheritdoc cref="Table{TItem}.RowContentTemplate"/>
[Parameter]
public RenderFragment<TableRowContext<TItem>>? RowContentTemplate { get; set; }
/// <inheritdoc cref="Table{TItem}.OnClickRowCallback"/> /// <inheritdoc cref="Table{TItem}.OnClickRowCallback"/>
[Parameter] [Parameter]
public Func<TItem, Task>? OnClickRowCallback { get; set; } public Func<TItem, Task>? OnClickRowCallback { get; set; }
@@ -146,6 +167,9 @@ public partial class AdminTable<TItem> where TItem : class, new()
[Parameter] [Parameter]
public IDataService<TItem> DataService { get; set; } public IDataService<TItem> DataService { get; set; }
[Parameter]
public string? Id { get; set; }
/// <inheritdoc cref="Table{TItem}.CreateItemCallback"/> /// <inheritdoc cref="Table{TItem}.CreateItemCallback"/>
[Parameter] [Parameter]
public Func<TItem> CreateItemCallback { get; set; } public Func<TItem> CreateItemCallback { get; set; }

View File

@@ -22,6 +22,9 @@
"SetDefaultModule": "Set as default module" "SetDefaultModule": "Set as default module"
}, },
"ThingsGateway.Admin.Razor.HardwareInfoPage": { "ThingsGateway.Admin.Razor.HardwareInfoPage": {
"GCMemoryInfoConfig": "GCMemoryInfoConfig(MB)",
"GCMemoryInfo": "GCMemoryInfo(MB)",
"GCAnalyzeInfo": "GCAnalyzeInfo",
"AvailableDisk": "Available Disk", "AvailableDisk": "Available Disk",
"AvailableMemory": "Available Memory", "AvailableMemory": "Available Memory",
"CpuUsage": "CPU Usage", "CpuUsage": "CPU Usage",

View File

@@ -22,6 +22,10 @@
"SetDefaultModule": "设置为默认模块" "SetDefaultModule": "设置为默认模块"
}, },
"ThingsGateway.Admin.Razor.HardwareInfoPage": { "ThingsGateway.Admin.Razor.HardwareInfoPage": {
"GCMemoryInfoConfig": "GC配置信息(MB)",
"GCMemoryInfo": "GC内存信息(MB)",
"GCAnalyzeInfo": "GC统计",
"AvailableDisk": "可用磁盘", "AvailableDisk": "可用磁盘",
"AvailableMemory": "可用内存", "AvailableMemory": "可用内存",
"CpuUsage": "CPU使用率", "CpuUsage": "CPU使用率",

View File

@@ -5,131 +5,189 @@
@using ThingsGateway.Admin.Application @using ThingsGateway.Admin.Application
@namespace ThingsGateway.Admin.Razor @namespace ThingsGateway.Admin.Razor
<div class="row g-2 mx-1 form-inline"> <div class="row g-2 mx-1 form-inline">
<div class="col-12 col-md-12">
<div class="col-12 col-md-4">
<Card IsShadow=true class="m-2 flex-fill" Color="Color.Primary"> <Card IsShadow=true class="m-2 flex-fill" Color="Color.Primary">
<HeaderTemplate> <HeaderTemplate>
@Localizer["SystemInfo"] <div class="d-flex justify-content-between align-items-center w-100">
</HeaderTemplate> <span>@Localizer["SystemInfo"]</span>
<small class="text-muted">
<BodyTemplate> @HardwareJob.HardwareInfo.UpdateTime.ToString("yyyy-MM-dd HH:mm:ss")
<EditorFormObject IsDisplay Model="HardwareJob.HardwareInfo" ItemsPerRow="1" RowType=RowType.Inline LabelWidth="160"> </small>
<FieldItems>
<EditorItem @bind-Field="@context.MachineInfo">
<EditTemplate Context="value">
<div class="col-12 col-md-12">
<Display @bind-Value="@value.MachineInfo.OSName" DisplayText="@Localizer[nameof(value.MachineInfo.OSName)]" ShowTooltip ShowLabel=true>
</Display>
</div>
<div class="col-12 col-md-12">
<Display @bind-Value="@value.MachineInfo.OSVersion" DisplayText="@Localizer[nameof(value.MachineInfo.OSVersion)]" ShowTooltip ShowLabel=true>
</Display>
</div>
</EditTemplate>
</EditorItem>
<EditorItem @bind-Field="@context.UUID">
<EditTemplate Context="value">
<div class="col-12 col-md-12">
<Display @bind-Value="@value.UUID" ShowTooltip ShowLabel=true>
</Display>
</div>
</EditTemplate>
</EditorItem>
<EditorItem @bind-Field="@context.DriveInfo" Ignore=true>
</EditorItem>
</FieldItems>
</EditorFormObject>
</BodyTemplate>
</Card>
</div>
<div class="col-12 col-md-8">
<Card IsShadow=true class="m-2 flex-fill" Color="Color.Primary">
<HeaderTemplate>
@Localizer["HardwareInfo"]
</HeaderTemplate>
<BodyTemplate>
<div class="d-flex align-items-center justify-content-center w-100 h-100" >
<div class="row g-2 mx-1 form-inline d-flex justify-content-center w-100">
<div class="col-12 col-md-4 justify-content-center h-100" >
@{
var item = HardwareJob.HardwareInfo.MachineInfo.CpuRate;
}
<div class="d-flex flex-column align-items-center">
<Circle Width="200" class="m-3"
Value=@((int)(item*100<=100?item*100:100))
Color=@((item*100>70?Color.Warning:Color.Success))
StrokeWidth="4" ShowProgress=false>
<div class="circle-hardware">
<span>
@Localizer["CpuUsage"] <i> @((item * 100).ToString("F0") + " %")</i>
</span>
</div>
</Circle>
<div class="mt-1">
<span>@(HardwareJob.HardwareInfo.MachineInfo.Processor)</span>
</div>
</div>
</div>
<div class="col-12 col-md-4 justify-content-center h-100">
@{
var availableMemory = HardwareJob.HardwareInfo.MachineInfo.AvailableMemory;
var memory = HardwareJob.HardwareInfo.MachineInfo.Memory;
}
<div class="d-flex flex-column align-items-center ">
<Circle Width="200" class="m-3"
Value=@((int)(memory>availableMemory?100 - (availableMemory * 100.00 / memory):100))
Color=@((availableMemory * 100.00 / memory<20?Color.Warning:Color.Success))
StrokeWidth="4">
<div class="circle-hardware">
<h6> @((100 - (availableMemory * 100.00 / memory)).ToString("F2") + " %") </h6>
<span> @Localizer["WorkingSet"] <i> @(HardwareJob.HardwareInfo.WorkingSet + " MB")</i></span>
<span> @Localizer["AvailableMemory"] <i> @((availableMemory / 1024.00 / 1024).ToString("F2") + " GB")</i></span>
<span> @Localizer["TotalMemory"] <i> @((memory / 1024.00 / 1024).ToString("F2") + " GB")</i></span>
</div>
</Circle>
<div class="mt-1">
<span> @Localizer["MemoryUsage"] </span>
</div>
</div>
</div>
<div class="col-12 col-md-4 justify-content-center h-100">
@{
var totalFreeSpace = HardwareJob.HardwareInfo.DriveInfo.TotalFreeSpace;
var totalSize = HardwareJob.HardwareInfo.DriveInfo.TotalSize;
}
<div class="d-flex flex-column align-items-center ">
<Circle Width="200" class="m-3"
Value=@((int)(totalSize>totalFreeSpace?100 - (totalFreeSpace * 100.00 / totalSize):100))
Color=@((totalFreeSpace * 100.00 / totalSize<20?Color.Warning:Color.Success))
StrokeWidth="4">
<div class="circle-hardware">
<h6> @((100 - (totalFreeSpace * 100.00 / totalSize)).ToString("F2") + " %")</h6>
<span> @(HardwareJob.HardwareInfo.DriveInfo.VolumeLabel) </span>
<span> @Localizer["AvailableDisk"] <i> @((totalFreeSpace / 1024.00 / 1024 / 1024).ToString("F2") + " GB")</i></span>
<span> @Localizer["TotalDisk"] <i> @((totalSize / 1024.00 / 1024 / 1024).ToString("F2") + " GB")</i></span>
</div>
</Circle>
<div class="mt-1">
<span> @Localizer["DiskUsage"] </span>
</div>
</div>
</div>
</div>
</div> </div>
</HeaderTemplate>
<BodyTemplate>
<EditorForm class="mt-3" AutoGenerateAllItem="false" IsDisplay Model="HardwareJob.HardwareInfo" ItemsPerRow=3 RowType=RowType.Inline LabelWidth=300>
<FieldItems>
<EditorItem @bind-Field="@context.OSName" GroupName="@Localizer["SystemInfo"]" />
<EditorItem @bind-Field="@context.OsArchitecture" GroupName="@Localizer["SystemInfo"]" />
<EditorItem @bind-Field="@context.OSVersion" GroupName="@Localizer["SystemInfo"]" />
<EditorItem @bind-Field="@context.Environment" GroupName="@Localizer["SystemInfo"]" />
<EditorItem @bind-Field="@context.FrameworkDescription" GroupName="@Localizer["SystemInfo"]" />
<EditorItem @bind-Field="@context.UUID" GroupName="@Localizer["SystemInfo"]" />
<EditorItem @bind-Field="@context.SystemRunTotalMinute" GroupName="@Localizer["SystemInfo"]" />
<EditorItem @bind-Field="@context.AppRunTotalMinute" GroupName="@Localizer["SystemInfo"]" />
<EditorItem @bind-Field="@context.Memory" GroupName="@Localizer["GCMemoryInfoConfig"]" GroupOrder=2 />
<EditorItem @bind-Field="@context.TotalAvailableMemory" GroupName="@Localizer["GCMemoryInfoConfig"]" GroupOrder=2 />
<EditorItem @bind-Field="@context.HighMemoryLoadThreshold" GroupName="@Localizer["GCMemoryConfig"]" GroupOrder=2 />
<EditorItem TValue="bool" TModel="HardwareInfo" @bind-Field="@context.IsServerGC" GroupName="@Localizer["GCMemoryConfig"]" GroupOrder=2>
<EditTemplate Context="value">
<div class="col-12">
<h6></h6>
</div>
</EditTemplate>
</EditorItem>
<EditorItem @bind-Field="@context.IsServerGC" GroupName="@Localizer["GCMemoryInfoConfig"]" GroupOrder=2 />
<EditorItem @bind-Field="@context.GCLatencyMode" GroupName="@Localizer["GCMemoryInfoConfig"]" GroupOrder=2 />
<EditorItem @bind-Field="@context.WorkingSet" GroupName="@Localizer["GCMemoryInfo"]" GroupOrder=3 />
<EditorItem @bind-Field="@context.PrivateMemory" GroupName="@Localizer["GCMemoryInfo"]" GroupOrder=3 />
<EditorItem @bind-Field="@context.PeakWorkingSet" GroupName="@Localizer["GCMemoryInfo"]" GroupOrder=3 />
<EditorItem TValue="ulong" TModel="HardwareInfo" @bind-Field="@context.HeapSize" GroupName="@Localizer["GCMemoryInfo"]" GroupOrder=3>
<EditTemplate Context="value">
<div class="col-12">
<h6></h6>
</div>
</EditTemplate>
</EditorItem>
<EditorItem @bind-Field="@context.HeapSize" GroupName="@Localizer["GCMemoryInfo"]" GroupOrder=3 />
<EditorItem @bind-Field="@context.TotalMemory" GroupName="@Localizer["GCMemoryInfo"]" GroupOrder=3 />
<EditorItem @bind-Field="@context.FragmentedBytes" GroupName="@Localizer["GCMemoryInfo"]" GroupOrder=3 />
<EditorItem @bind-Field="@context.CommittedBytes" GroupName="@Localizer["GCMemoryInfo"]" GroupOrder=3 />
<EditorItem TValue="ulong" TModel="HardwareInfo" @bind-Field="@context.AvailableMemory" GroupName="@Localizer["GCMemoryInfo"]" GroupOrder=3>
<EditTemplate Context="value">
<div class="col-12">
<h6></h6>
</div>
</EditTemplate>
</EditorItem>
<EditorItem @bind-Field="@context.AvailableMemory" GroupName="@Localizer["GCMemoryInfo"]" GroupOrder=3 />
<EditorItem @bind-Field="@context.GCAvailableMemory" GroupName="@Localizer["GCMemoryInfo"]" GroupOrder=3 />
<EditorItem @bind-Field="@context.VirtualMemory" GroupName="@Localizer["GCMemoryInfo"]" GroupOrder=3 />
<EditorItem @bind-Field="@context.GcGen0Count" GroupName="@Localizer["GCAnalyzeInfo"]" GroupOrder=4 />
<EditorItem @bind-Field="@context.GcGen1Count" GroupName="@Localizer["GCAnalyzeInfo"]" GroupOrder=4 />
<EditorItem @bind-Field="@context.GcGen2Count" GroupName="@Localizer["GCAnalyzeInfo"]" GroupOrder=4 />
<EditorItem TValue="ulong" TModel="HardwareInfo" @bind-Field="@context.TotalAllocatedBytes" GroupName="@Localizer["GCAnalyzeInfo"]" GroupOrder=4>
<EditTemplate Context="value">
<div class="col-12">
<h6></h6>
</div>
</EditTemplate>
</EditorItem>
<EditorItem @bind-Field="@context.TotalAllocatedBytes" GroupName="@Localizer["GCAnalyzeInfo"]" GroupOrder=4 />
<EditorItem @bind-Field="@context.TotalPauseDurationMs" GroupName="@Localizer["GCAnalyzeInfo"]" GroupOrder=4 />
</FieldItems>
</EditorForm>
</BodyTemplate> </BodyTemplate>
</Card> </Card>
</div> </div>
</div> </div>
<div class="row g-2 mx-1 form-inline mt-2">
<div class="col-12 col-md-12">
<Card IsShadow=true class="m-2 flex-fill" Color="Color.Primary">
<HeaderTemplate>
@Localizer["HardwareInfo"]
</HeaderTemplate>
<BodyTemplate>
<div class="d-flex align-items-center justify-content-center w-100 h-100">
<div class="row g-2 mx-1 form-inline d-flex justify-content-center w-100">
<!-- ✅ CPU 使用率 -->
<div class="col-12 col-md-4 justify-content-center h-100">
@{
var cpuUsage = HardwareJob.HardwareInfo.CpuRate;
}
<div class="d-flex flex-column align-items-center">
<Circle Width="200" class="m-3"
Value=@((int)(cpuUsage*100<=100?cpuUsage*100:100))
Color=@((cpuUsage*100>70?Color.Warning:Color.Success))
StrokeWidth="4" ShowProgress=false>
<div class="circle-hardware">
<span>
@Localizer["CpuUsage"] <i>@((cpuUsage * 100).ToString("F0") + " %")</i>
</span>
</div>
</Circle>
<div class="mt-1">
<span>@(HardwareJob.HardwareInfo.Processor)</span>
</div>
</div>
</div>
<!-- ✅ 内存使用率 -->
<div class="col-12 col-md-4 justify-content-center h-100">
@{
var availableMemory = HardwareJob.HardwareInfo.AvailableMemory;
var memory = HardwareJob.HardwareInfo.Memory;
}
<div class="d-flex flex-column align-items-center">
<Circle Width="200" class="m-3"
Value=@((int)(memory>availableMemory?100 - (availableMemory * 100.00 / memory):100))
Color=@((availableMemory * 100.00 / memory<20?Color.Warning:Color.Success))
StrokeWidth="4">
<div class="circle-hardware">
<h6>@((100 - (availableMemory * 100.00 / memory)).ToString("F2") + " %")</h6>
<span>@Localizer["WorkingSet"] <i>@(HardwareJob.HardwareInfo.WorkingSet + " MB")</i></span>
<span>@Localizer["AvailableMemory"] <i>@((availableMemory / 1024.00).ToString("F2") + " GB")</i></span>
<span>@Localizer["TotalMemory"] <i>@((memory / 1024.00).ToString("F2") + " GB")</i></span>
</div>
</Circle>
<div class="mt-1">
<span>@Localizer["MemoryUsage"]</span>
</div>
</div>
</div>
<!-- ✅ 磁盘使用率 -->
<div class="col-12 col-md-4 justify-content-center h-100">
@{
var totalFreeSpace = HardwareJob.HardwareInfo.DriveInfo.TotalFreeSpace;
var totalSize = HardwareJob.HardwareInfo.DriveInfo.TotalSize;
}
<div class="d-flex flex-column align-items-center">
<Circle Width="200" class="m-3"
Value=@((int)(totalSize>totalFreeSpace?100 - (totalFreeSpace * 100.00 / totalSize):100))
Color=@((totalFreeSpace * 100.00 / totalSize<20?Color.Warning:Color.Success))
StrokeWidth="4">
<div class="circle-hardware">
<h6>@((100 - (totalFreeSpace * 100.00 / totalSize)).ToString("F2") + " %")</h6>
<span>@(HardwareJob.HardwareInfo.DriveInfo.VolumeLabel)</span>
<span>@Localizer["AvailableDisk"] <i>@((totalFreeSpace / 1024.00 / 1024 / 1024).ToString("F2") + " GB")</i></span>
<span>@Localizer["TotalDisk"] <i>@((totalSize / 1024.00 / 1024 / 1024).ToString("F2") + " GB")</i></span>
</div>
</Circle>
<div class="mt-1">
<span>@Localizer["DiskUsage"]</span>
</div>
</div>
</div>
</div>
</div>
</BodyTemplate>
</Card>
</div>
</div>
<div class="row g-2 mx-1 form-inline"> <div class="row g-2 mx-1 form-inline">
<div class="col-12 col-md-12"> <div class="col-12 col-md-12">
@@ -140,7 +198,7 @@
</HeaderTemplate> </HeaderTemplate>
<BodyTemplate> <BodyTemplate>
<Chart @ref=LineChart OnInitAsync="OnInit" Height="var(--line-chart-height)" Width="100%" OnAfterInitAsync="()=>{chartInit=true;return Task.CompletedTask;}" /> <Chart @ref=LineChart OnInitAsync="OnInit" Height="var(--line-chart-height)" Width="100%" OnAfterInitAsync="() => { chartInit = true; return Task.CompletedTask; }" />
</BodyTemplate> </BodyTemplate>
</Card> </Card>
</div> </div>

View File

@@ -72,7 +72,7 @@ public partial class HardwareInfoPage : IDisposable
ChartDataSource.Options.Title = Localizer[nameof(HistoryHardwareInfo)]; ChartDataSource.Options.Title = Localizer[nameof(HistoryHardwareInfo)];
ChartDataSource.Options.X.Title = Localizer["DateTime"]; ChartDataSource.Options.X.Title = Localizer["DateTime"];
ChartDataSource.Options.Y.Title = Localizer["Data"]; ChartDataSource.Options.Y.Title = Localizer["Data"];
ChartDataSource.Labels = hisHardwareInfos.Select(a => a.Date.ToString("dd HH:mm zz")); ChartDataSource.Labels = hisHardwareInfos.Select(a => a.Date.ToString("dd-HH:mm"));
ChartDataSource.Data.Add(new ChartDataset() ChartDataSource.Data.Add(new ChartDataset()
{ {
Tension = 0.4f, Tension = 0.4f,
@@ -116,7 +116,7 @@ public partial class HardwareInfoPage : IDisposable
else else
{ {
var hisHardwareInfos = await HardwareJob.GetHistoryHardwareInfos(); var hisHardwareInfos = await HardwareJob.GetHistoryHardwareInfos();
ChartDataSource.Labels = hisHardwareInfos.Select(a => a.Date.ToString("dd HH:mm zz")); ChartDataSource.Labels = hisHardwareInfos.Select(a => a.Date.ToString("dd-HH:mm"));
ChartDataSource.Data[0].Data = hisHardwareInfos.Select(a => (object)a.CpuUsage); ChartDataSource.Data[0].Data = hisHardwareInfos.Select(a => (object)a.CpuUsage);
ChartDataSource.Data[1].Data = hisHardwareInfos.Select(a => (object)a.MemoryUsage); ChartDataSource.Data[1].Data = hisHardwareInfos.Select(a => (object)a.MemoryUsage);
ChartDataSource.Data[2].Data = hisHardwareInfos.Select(a => (object)a.DriveUsage); ChartDataSource.Data[2].Data = hisHardwareInfos.Select(a => (object)a.DriveUsage);

View File

@@ -5,7 +5,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ThingsGateway.Admin.Application\ThingsGateway.Admin.Application.csproj" /> <ProjectReference Include="..\ThingsGateway.Admin.Application\ThingsGateway.Admin.Application.csproj" />
<PackageReference Include="BootstrapBlazor.Chart" Version="9.0.1" /> <PackageReference Include="BootstrapBlazor.Chart" Version="9.0.4" />
<PackageReference Include="BootstrapBlazor.UniverSheet" Version="9.0.5" /> <PackageReference Include="BootstrapBlazor.UniverSheet" Version="9.0.5" />
<PackageReference Include="BootstrapBlazor.WinBox" Version="9.0.7" /> <PackageReference Include="BootstrapBlazor.WinBox" Version="9.0.7" />
<PackageReference Include="BootstrapBlazor.CodeEditor" Version="9.0.3" /> <PackageReference Include="BootstrapBlazor.CodeEditor" Version="9.0.3" />

View File

@@ -92,7 +92,8 @@ public class Startup : AppStartup
options.RootComponents.MaxJSRootComponents = 500; options.RootComponents.MaxJSRootComponents = 500;
options.JSInteropDefaultCallTimeout = TimeSpan.FromMinutes(2); options.JSInteropDefaultCallTimeout = TimeSpan.FromMinutes(2);
options.MaxBufferedUnacknowledgedRenderBatches = 20; options.MaxBufferedUnacknowledgedRenderBatches = 20;
options.DisconnectedCircuitRetentionPeriod = TimeSpan.FromMinutes(10); options.DisconnectedCircuitMaxRetained = 1;
options.DisconnectedCircuitRetentionPeriod = TimeSpan.FromSeconds(10);
}) })
.AddHubOptions(options => .AddHubOptions(options =>
{ {
@@ -103,6 +104,7 @@ public class Startup : AppStartup
options.ClientTimeoutInterval = TimeSpan.FromMinutes(2); options.ClientTimeoutInterval = TimeSpan.FromMinutes(2);
options.KeepAliveInterval = TimeSpan.FromSeconds(15); options.KeepAliveInterval = TimeSpan.FromSeconds(15);
options.HandshakeTimeout = TimeSpan.FromSeconds(30); options.HandshakeTimeout = TimeSpan.FromSeconds(30);
}); });
#else #else
@@ -112,7 +114,8 @@ public class Startup : AppStartup
options.RootComponents.MaxJSRootComponents = 500; options.RootComponents.MaxJSRootComponents = 500;
options.JSInteropDefaultCallTimeout = TimeSpan.FromMinutes(2); options.JSInteropDefaultCallTimeout = TimeSpan.FromMinutes(2);
options.MaxBufferedUnacknowledgedRenderBatches = 20; options.MaxBufferedUnacknowledgedRenderBatches = 20;
options.DisconnectedCircuitRetentionPeriod = TimeSpan.FromMinutes(10); options.DisconnectedCircuitMaxRetained = 1;
options.DisconnectedCircuitRetentionPeriod = TimeSpan.FromSeconds(10);
}).AddHubOptions(options => }).AddHubOptions(options =>
{ {
//单个传入集线器消息的最大大小。默认 32 KB //单个传入集线器消息的最大大小。默认 32 KB

View File

@@ -15,15 +15,11 @@
<PublishReadyToRunComposite>true</PublishReadyToRunComposite> <PublishReadyToRunComposite>true</PublishReadyToRunComposite>
<ApplicationIcon>wwwroot\favicon.ico</ApplicationIcon> <ApplicationIcon>wwwroot\favicon.ico</ApplicationIcon>
<CETCompat>false</CETCompat>
<ServerGarbageCollection>true</ServerGarbageCollection>
<!--动态适用GC--> <!--动态适用GC-->
<GarbageCollectionAdaptationMode>1</GarbageCollectionAdaptationMode> <GarbageCollectionAdaptationMode>1</GarbageCollectionAdaptationMode>
<CETCompat>false</CETCompat>
<!--使用自托管线程池-->
<!--<UseWindowsThreadPool>false</UseWindowsThreadPool> -->
<!--使用工作站GC-->
<!--<ServerGarbageCollection>true</ServerGarbageCollection>-->
<!--<PlatformTarget>x86</PlatformTarget>--> <!--<PlatformTarget>x86</PlatformTarget>-->
</PropertyGroup> </PropertyGroup>

View File

@@ -1,4 +1,4 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 // 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有 // 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议 // 源代码使用协议遵循本仓库的开源协议及附加协议
@@ -477,7 +477,7 @@ public class ConcurrentList<T> : IList<T>, IReadOnlyList<T>
{ {
lock (((ICollection)m_list).SyncRoot) lock (((ICollection)m_list).SyncRoot)
{ {
return m_list.IndexOf(item); return m_list.LastIndexOf(item);
} }
} }

View File

@@ -16,6 +16,8 @@ using System.Runtime.CompilerServices;
using System.Text.Json; using System.Text.Json;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using ThingsGateway.Extension;
namespace ThingsGateway.Common.Extension; namespace ThingsGateway.Common.Extension;
/// <summary> /// <summary>
/// 对象拓展类 /// 对象拓展类
@@ -48,113 +50,7 @@ public static class ObjectExtensions
bool IsTheRawGenericType(Type type) => generic == (type.IsGenericType ? type.GetGenericTypeDefinition() : type); bool IsTheRawGenericType(Type type) => generic == (type.IsGenericType ? type.GetGenericTypeDefinition() : type);
} }
/// <summary>
/// 将 DateTimeOffset 转换成本地 DateTime
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTime ConvertToDateTime(this DateTimeOffset dateTime)
{
if (dateTime.Offset.Equals(TimeSpan.Zero))
return dateTime.UtcDateTime;
if (dateTime.Offset.Equals(TimeZoneInfo.Local.GetUtcOffset(dateTime.DateTime)))
return dateTime.ToLocalTime().DateTime;
else
return dateTime.DateTime;
}
/// <summary>
/// 将 DateTimeOffset? 转换成本地 DateTime?
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTime? ConvertToDateTime(this DateTimeOffset? dateTime)
{
return dateTime.HasValue ? dateTime.Value.ConvertToDateTime() : null;
}
/// <summary>
/// 将 DateTime 转换成 DateTimeOffset
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTimeOffset ConvertToDateTimeOffset(this DateTime dateTime)
{
return DateTime.SpecifyKind(dateTime, DateTimeKind.Local);
}
/// <summary>
/// 将 DateTime? 转换成 DateTimeOffset?
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTimeOffset? ConvertToDateTimeOffset(this DateTime? dateTime)
{
return dateTime.HasValue ? dateTime.Value.ConvertToDateTimeOffset() : null;
}
/// <summary>
/// 将流保存到本地磁盘
/// </summary>
/// <param name="stream"></param>
/// <param name="path"></param>
/// <returns></returns>
public static void CopyToSave(this Stream stream, string path)
{
// 空检查
if (string.IsNullOrWhiteSpace(path)) throw new ArgumentNullException(nameof(path));
using var fileStream = File.Create(path);
stream.CopyTo(fileStream);
}
/// <summary>
/// 将字节数组保存到本地磁盘
/// </summary>
/// <param name="bytes"></param>
/// <param name="path"></param>
/// <returns></returns>
public static void CopyToSave(this byte[] bytes, string path)
{
using var stream = new MemoryStream(bytes);
stream.CopyToSave(path);
}
/// <summary>
/// 将流保存到本地磁盘
/// </summary>
/// <param name="stream"></param>
/// <param name="path">需包含文件名完整路径</param>
/// <returns></returns>
public static async Task CopyToSaveAsync(this Stream stream, string path)
{
// 空检查
if (string.IsNullOrWhiteSpace(path))
{
throw new ArgumentNullException(nameof(path));
}
// 文件名判断
if (string.IsNullOrWhiteSpace(Path.GetFileName(path)))
{
throw new ArgumentException("The parameter of <path> parameter must include the complete file name.");
}
using var fileStream = File.Create(path);
await stream.CopyToAsync(fileStream).ConfigureAwait(false);
}
/// <summary>
/// 将字节数组保存到本地磁盘
/// </summary>
/// <param name="bytes"></param>
/// <param name="path"></param>
/// <returns></returns>
public static async Task CopyToSaveAsync(this byte[] bytes, string path)
{
using var stream = new MemoryStream(bytes);
await stream.CopyToSaveAsync(path).ConfigureAwait(false);
}
/// <summary> /// <summary>
/// 合并两个字典 /// 合并两个字典
@@ -186,7 +82,7 @@ public static class ObjectExtensions
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
/// <param name="dic">字典</param> /// <param name="dic">字典</param>
/// <param name="newDic">新字典</param> /// <param name="newDic">新字典</param>
internal static void AddOrUpdate<T>(this ConcurrentDictionary<string, T> dic, Dictionary<string, T> newDic) internal static void AddOrUpdate<T>(this NonBlockingDictionary<string, T> dic, Dictionary<string, T> newDic)
{ {
foreach (var (key, value) in newDic) foreach (var (key, value) in newDic)
{ {

View File

@@ -27,7 +27,7 @@ internal class CacheManager
{ {
private IMemoryCache Cache { get; set; } private IMemoryCache Cache { get; set; }
private IServiceProvider Provider { get; set; } private static IServiceProvider Provider => App.RootServices;
[NotNull] [NotNull]
private static CacheManager? Instance { get; set; } private static CacheManager? Instance { get; set; }
@@ -40,8 +40,7 @@ internal class CacheManager
static CacheManager() static CacheManager()
{ {
Instance = new(); Instance = new();
Instance.Provider = App.RootServices; Instance.Cache = Provider.GetRequiredService<IMemoryCache>();
Instance.Cache = Instance.Provider.GetRequiredService<IMemoryCache>();
Options = App.RootServices.GetRequiredService<IOptions<BootstrapBlazorOptions>>().Value; Options = App.RootServices.GetRequiredService<IOptions<BootstrapBlazorOptions>>().Value;
} }
@@ -105,37 +104,6 @@ internal class CacheManager
} }
} }
/// <summary>
/// 设置 App 开始时间
/// </summary>
public void SetStartTime() => SetStartTime(DateTimeOffset.Now);
/// <summary>
/// 设置 App 开始时间
/// </summary>
private void SetStartTime(DateTimeOffset startDateTimeOffset)
{
GetOrCreate("BootstrapBlazor_StartTime", entry =>
{
entry.Priority = CacheItemPriority.NeverRemove;
return startDateTimeOffset;
});
}
/// <summary>
/// 获取 App 开始时间
/// </summary>
/// <returns></returns>
public DateTimeOffset GetStartTime()
{
var ret = DateTimeOffset.MinValue;
if (Cache.TryGetValue("BootstrapBlazor_StartTime", out var v) && v is DateTimeOffset d)
{
ret = d;
}
return ret;
}
/// <summary> /// <summary>
/// 获得 缓存数量 /// 获得 缓存数量
/// </summary> /// </summary>
@@ -236,7 +204,7 @@ internal class CacheManager
/// <returns></returns> /// <returns></returns>
public static IStringLocalizer? CreateLocalizerByType(Type resourceSource) => resourceSource.Assembly.IsDynamic public static IStringLocalizer? CreateLocalizerByType(Type resourceSource) => resourceSource.Assembly.IsDynamic
? null ? null
: Instance.Provider.GetRequiredService<IStringLocalizerFactory>().Create(resourceSource); : Provider.GetRequiredService<IStringLocalizerFactory>().Create(resourceSource);
/// <summary> /// <summary>
/// 获得 <see cref="JsonLocalizationOptions"/> 值 /// 获得 <see cref="JsonLocalizationOptions"/> 值
@@ -244,7 +212,7 @@ internal class CacheManager
/// <returns></returns> /// <returns></returns>
private static JsonLocalizationOptions GetJsonLocalizationOption() private static JsonLocalizationOptions GetJsonLocalizationOption()
{ {
var localizationOptions = Instance.Provider.GetRequiredService<IOptions<JsonLocalizationOptions>>(); var localizationOptions = Provider.GetRequiredService<IOptions<JsonLocalizationOptions>>();
return localizationOptions.Value; return localizationOptions.Value;
} }
/// <summary> /// <summary>
@@ -253,7 +221,7 @@ internal class CacheManager
/// <returns></returns> /// <returns></returns>
private static BootstrapBlazorOptions GetBootstrapBlazorOption() private static BootstrapBlazorOptions GetBootstrapBlazorOption()
{ {
var localizationOptions = Instance.Provider.GetRequiredService<IOptions<BootstrapBlazorOptions>>(); var localizationOptions = Provider.GetRequiredService<IOptions<BootstrapBlazorOptions>>();
return localizationOptions.Value; return localizationOptions.Value;
} }
/// <summary> /// <summary>
@@ -269,7 +237,7 @@ internal class CacheManager
return null; return null;
} }
IStringLocalizer? ret = null; IStringLocalizer? ret = null;
var factories = Instance.Provider.GetServices<IStringLocalizerFactory>(); var factories = Provider.GetServices<IStringLocalizerFactory>();
var factory = factories.LastOrDefault(a => a is not JsonStringLocalizerFactory); var factory = factories.LastOrDefault(a => a is not JsonStringLocalizerFactory);
if (factory != null) if (factory != null)
{ {
@@ -345,7 +313,7 @@ internal class CacheManager
/// <param name="typeName"></param> /// <param name="typeName"></param>
/// <param name="includeParentCultures"></param> /// <param name="includeParentCultures"></param>
/// <returns></returns> /// <returns></returns>
public static IEnumerable<LocalizedString> GetTypeStringsFromResolve(string typeName, bool includeParentCultures = true) => Instance.Provider.GetRequiredService<ILocalizationResolve>().GetAllStringsByType(typeName, includeParentCultures); public static IEnumerable<LocalizedString> GetTypeStringsFromResolve(string typeName, bool includeParentCultures = true) => Provider.GetRequiredService<ILocalizationResolve>().GetAllStringsByType(typeName, includeParentCultures);
#endregion #endregion
#region DisplayName #region DisplayName

View File

@@ -66,7 +66,8 @@ internal class JsonStringLocalizer(Assembly assembly, string typeName, string ba
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.LogError(ex, "{JsonStringLocalizerName} searched for '{Name}' in '{typeName}' with culture '{CultureName}' throw exception.", nameof(JsonStringLocalizer), name, typeName, CultureInfo.CurrentUICulture.Name); if (Logger?.IsEnabled(LogLevel.Error) == true)
Logger.LogError(ex, "{JsonStringLocalizerName} searched for '{Name}' in '{typeName}' with culture '{CultureName}' throw exception.", nameof(JsonStringLocalizer), name, typeName, CultureInfo.CurrentUICulture.Name);
} }
return ret; return ret;
} }
@@ -176,7 +177,8 @@ internal class JsonStringLocalizer(Assembly assembly, string typeName, string ba
localizationMissingItemHandler.HandleMissingItem(name, typeName, CultureInfo.CurrentUICulture.Name); localizationMissingItemHandler.HandleMissingItem(name, typeName, CultureInfo.CurrentUICulture.Name);
if (jsonLocalizationOptions.IgnoreLocalizerMissing == false) if (jsonLocalizationOptions.IgnoreLocalizerMissing == false)
{ {
Logger.LogInformation("{JsonStringLocalizerName} searched for '{Name}' in '{TypeName}' with culture '{CultureName}' not found.", nameof(JsonStringLocalizer), name, typeName, CultureInfo.CurrentUICulture.Name); if (Logger?.IsEnabled(LogLevel.Information) == true)
Logger.LogInformation("{JsonStringLocalizerName} searched for '{Name}' in '{TypeName}' with culture '{CultureName}' not found.", nameof(JsonStringLocalizer), name, typeName, CultureInfo.CurrentUICulture.Name);
} }
_missingManifestCache.TryAdd($"name={name}&culture={CultureInfo.CurrentUICulture.Name}"); _missingManifestCache.TryAdd($"name={name}&culture={CultureInfo.CurrentUICulture.Name}");
} }

View File

@@ -14,7 +14,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="BootstrapBlazor.TableExport" Version="9.2.7" /> <PackageReference Include="BootstrapBlazor.TableExport" Version="9.2.7" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" /> <PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
<PackageReference Include="BootstrapBlazor" Version="9.11.0" /> <PackageReference Include="BootstrapBlazor" Version="9.11.4" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -12,7 +12,7 @@
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using ThingsGateway; using ThingsGateway;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using ThingsGateway.Reflection; using ThingsGateway.Reflection;
namespace Microsoft.Extensions.Hosting; namespace Microsoft.Extensions.Hosting;

View File

@@ -20,7 +20,7 @@ using System.Text.RegularExpressions;
using ThingsGateway.NewLife; using ThingsGateway.NewLife;
namespace ThingsGateway.Extensions; namespace ThingsGateway.Extension;
/// <summary> /// <summary>
/// 对象拓展类 /// 对象拓展类
@@ -28,70 +28,10 @@ namespace ThingsGateway.Extensions;
[SuppressSniffer] [SuppressSniffer]
public static class ObjectExtensions public static class ObjectExtensions
{ {
/// <summary>
/// 将 DateTimeOffset 转换成本地 DateTime
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTime ConvertToDateTime(this DateTimeOffset dateTime)
{
if (dateTime.Offset.Equals(TimeSpan.Zero))
return dateTime.UtcDateTime;
if (dateTime.Offset.Equals(TimeZoneInfo.Local.GetUtcOffset(dateTime.DateTime)))
return dateTime.ToLocalTime().DateTime;
else
return dateTime.DateTime;
}
/// <summary>
/// 将 DateTimeOffset? 转换成本地 DateTime?
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTime? ConvertToDateTime(this DateTimeOffset? dateTime)
{
return dateTime.HasValue ? dateTime.Value.ConvertToDateTime() : null;
}
/// <summary>
/// 将 DateTime 转换成 DateTimeOffset
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTimeOffset ConvertToDateTimeOffset(this DateTime dateTime)
{
return DateTime.SpecifyKind(dateTime, DateTimeKind.Local);
}
/// <summary>
/// 将 DateTime? 转换成 DateTimeOffset?
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTimeOffset? ConvertToDateTimeOffset(this DateTime? dateTime)
{
return dateTime.HasValue ? dateTime.Value.ConvertToDateTimeOffset() : null;
}
/// <summary>
/// 将时间戳转换为 DateTime
/// </summary>
/// <param name="timestamp"></param>
/// <returns></returns>
internal static DateTime ConvertToDateTime(this long timestamp)
{
var timeStampDateTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var digitCount = (int)Math.Floor(Math.Log10(timestamp) + 1);
if (digitCount != 13 && digitCount != 10)
{
throw new ArgumentException("Data is not a valid timestamp format.");
}
return (digitCount == 13
? timeStampDateTime.AddMilliseconds(timestamp) // 13 位时间戳
: timeStampDateTime.AddSeconds(timestamp)).ToLocalTime(); // 10 位时间戳
}
/// <summary> /// <summary>
/// 将 IFormFile 转换成 byte[] /// 将 IFormFile 转换成 byte[]
@@ -265,7 +205,7 @@ public static class ObjectExtensions
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
/// <param name="dic">字典</param> /// <param name="dic">字典</param>
/// <param name="newDic">新字典</param> /// <param name="newDic">新字典</param>
internal static void AddOrUpdate<T>(this ConcurrentDictionary<string, T> dic, Dictionary<string, T> newDic) internal static void AddOrUpdate<T>(this NonBlockingDictionary<string, T> dic, Dictionary<string, T> newDic)
{ {
foreach (var (key, value) in newDic) foreach (var (key, value) in newDic)
{ {

View File

@@ -94,7 +94,7 @@ public static class AspNetCoreBuilderServiceCollectionExtensions
/// <param name="mvcBuilder"></param> /// <param name="mvcBuilder"></param>
/// <param name="configure"></param> /// <param name="configure"></param>
/// <returns></returns> /// <returns></returns>
public static IMvcBuilder AddFromConvertBinding(this IMvcBuilder mvcBuilder, Action<ConcurrentDictionary<Type, Type>> configure = default) public static IMvcBuilder AddFromConvertBinding(this IMvcBuilder mvcBuilder, Action<NonBlockingDictionary<Type, Type>> configure = default)
{ {
mvcBuilder.Services.AddFromConvertBinding(configure); mvcBuilder.Services.AddFromConvertBinding(configure);
@@ -107,13 +107,13 @@ public static class AspNetCoreBuilderServiceCollectionExtensions
/// <param name="services"></param> /// <param name="services"></param>
/// <param name="configure"></param> /// <param name="configure"></param>
/// <returns></returns> /// <returns></returns>
public static IServiceCollection AddFromConvertBinding(this IServiceCollection services, Action<ConcurrentDictionary<Type, Type>> configure = default) public static IServiceCollection AddFromConvertBinding(this IServiceCollection services, Action<NonBlockingDictionary<Type, Type>> configure = default)
{ {
// 非 Web 环境跳过注册 // 非 Web 环境跳过注册
if (App.WebHostEnvironment == default) return services; if (App.WebHostEnvironment == default) return services;
// 定义模型绑定转换器集合 // 定义模型绑定转换器集合
var modelBinderConverts = new ConcurrentDictionary<Type, Type>(); var modelBinderConverts = new NonBlockingDictionary<Type, Type>();
modelBinderConverts.TryAdd(typeof(DateTime), typeof(DateTimeModelConvertBinder)); modelBinderConverts.TryAdd(typeof(DateTime), typeof(DateTimeModelConvertBinder));
modelBinderConverts.TryAdd(typeof(DateTimeOffset), typeof(DateTimeOffsetModelConvertBinder)); modelBinderConverts.TryAdd(typeof(DateTimeOffset), typeof(DateTimeOffsetModelConvertBinder));

View File

@@ -11,7 +11,7 @@
using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
namespace ThingsGateway.AspNetCore; namespace ThingsGateway.AspNetCore;

View File

@@ -27,13 +27,13 @@ public class FromConvertBinder : IModelBinder
/// <summary> /// <summary>
/// 定义模型绑定转换器集合 /// 定义模型绑定转换器集合
/// </summary> /// </summary>
private readonly ConcurrentDictionary<Type, Type> _modelBinderConverts; private readonly NonBlockingDictionary<Type, Type> _modelBinderConverts;
/// <summary> /// <summary>
/// 构造函数 /// 构造函数
/// </summary> /// </summary>
/// <param name="modelBinderConverts">定义模型绑定转换器集合</param> /// <param name="modelBinderConverts">定义模型绑定转换器集合</param>
public FromConvertBinder(ConcurrentDictionary<Type, Type> modelBinderConverts) public FromConvertBinder(NonBlockingDictionary<Type, Type> modelBinderConverts)
{ {
_modelBinderConverts = modelBinderConverts; _modelBinderConverts = modelBinderConverts;
} }

View File

@@ -28,13 +28,13 @@ public class FromConvertBinderProvider : IModelBinderProvider
/// <summary> /// <summary>
/// 定义模型绑定转换器集合 /// 定义模型绑定转换器集合
/// </summary> /// </summary>
private readonly ConcurrentDictionary<Type, Type> _modelBinderConverts; private readonly NonBlockingDictionary<Type, Type> _modelBinderConverts;
/// <summary> /// <summary>
/// 构造函数 /// 构造函数
/// </summary> /// </summary>
/// <param name="modelBinderConverts">定义模型绑定转换器集合</param> /// <param name="modelBinderConverts">定义模型绑定转换器集合</param>
public FromConvertBinderProvider(ConcurrentDictionary<Type, Type> modelBinderConverts) public FromConvertBinderProvider(NonBlockingDictionary<Type, Type> modelBinderConverts)
{ {
_modelBinderConverts = modelBinderConverts; _modelBinderConverts = modelBinderConverts;
} }

View File

@@ -11,7 +11,7 @@
using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
namespace ThingsGateway.AspNetCore; namespace ThingsGateway.AspNetCore;

View File

@@ -12,7 +12,7 @@
using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
namespace ThingsGateway.AspNetCore; namespace ThingsGateway.AspNetCore;

View File

@@ -18,7 +18,7 @@ using System.Reflection;
using ThingsGateway; using ThingsGateway;
using ThingsGateway.ConfigurableOptions; using ThingsGateway.ConfigurableOptions;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
namespace Microsoft.Extensions.DependencyInjection; namespace Microsoft.Extensions.DependencyInjection;

View File

@@ -16,7 +16,7 @@ using System.ComponentModel.DataAnnotations;
using System.Reflection; using System.Reflection;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using ThingsGateway.Templates.Extensions; using ThingsGateway.Templates.Extensions;
namespace ThingsGateway.DataValidation; namespace ThingsGateway.DataValidation;
@@ -40,7 +40,7 @@ public static class DataValidator
/// <summary> /// <summary>
/// 验证类型正则表达式 /// 验证类型正则表达式
/// </summary> /// </summary>
private static readonly ConcurrentDictionary<string, ValidationItemMetadataAttribute> ValidationItemMetadatas; private static readonly NonBlockingDictionary<string, ValidationItemMetadataAttribute> ValidationItemMetadatas;
/// <summary> /// <summary>
/// 构造函数 /// 构造函数
@@ -57,7 +57,7 @@ public static class DataValidator
ValidationItemMetadatas = GetValidationValidationItemMetadatas(); ValidationItemMetadatas = GetValidationValidationItemMetadatas();
// 缓存所有正则表达式 // 缓存所有正则表达式
GetValidationTypeValidationItemMetadataCached = new ConcurrentDictionary<object, (string, ValidationItemMetadataAttribute)>(); GetValidationTypeValidationItemMetadataCached = new NonBlockingDictionary<object, (string, ValidationItemMetadataAttribute)>();
} }
/// <summary> /// <summary>
@@ -203,7 +203,7 @@ public static class DataValidator
/// <summary> /// <summary>
/// 获取验证类型验证Item集合 /// 获取验证类型验证Item集合
/// </summary> /// </summary>
private static readonly ConcurrentDictionary<object, (string, ValidationItemMetadataAttribute)> GetValidationTypeValidationItemMetadataCached; private static readonly NonBlockingDictionary<object, (string, ValidationItemMetadataAttribute)> GetValidationTypeValidationItemMetadataCached;
/// <summary> /// <summary>
/// 获取验证类型正则表达式(需要缓存) /// 获取验证类型正则表达式(需要缓存)
@@ -267,9 +267,9 @@ public static class DataValidator
/// 获取验证类型所有有效的正则表达式 /// 获取验证类型所有有效的正则表达式
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
private static ConcurrentDictionary<string, ValidationItemMetadataAttribute> GetValidationValidationItemMetadatas() private static NonBlockingDictionary<string, ValidationItemMetadataAttribute> GetValidationValidationItemMetadatas()
{ {
var vaidationItems = new ConcurrentDictionary<string, ValidationItemMetadataAttribute>(); var vaidationItems = new NonBlockingDictionary<string, ValidationItemMetadataAttribute>();
// 查找所有 [ValidationMessageType] 类型中的 [ValidationMessage] 消息定义 // 查找所有 [ValidationMessageType] 类型中的 [ValidationMessage] 消息定义
var customErrorMessages = ValidationMessageTypes.SelectMany(u => u.GetFields() var customErrorMessages = ValidationMessageTypes.SelectMany(u => u.GetFields()

View File

@@ -353,7 +353,7 @@ public static class DependencyInjectionServiceCollectionExtensions
/// <summary> /// <summary>
/// 类型名称集合 /// 类型名称集合
/// </summary> /// </summary>
private static readonly ConcurrentDictionary<string, Type> TypeNamedCollection; private static readonly NonBlockingDictionary<string, Type> TypeNamedCollection;
/// <summary> /// <summary>
/// 创建代理方法 /// 创建代理方法
@@ -374,7 +374,7 @@ public static class DependencyInjectionServiceCollectionExtensions
GlobalServiceProxyType = App.EffectiveTypes GlobalServiceProxyType = App.EffectiveTypes
.FirstOrDefault(u => typeof(AspectDispatchProxy).IsAssignableFrom(u) && typeof(IGlobalDispatchProxy).IsAssignableFrom(u) && u.IsClass && !u.IsInterface && !u.IsAbstract); .FirstOrDefault(u => typeof(AspectDispatchProxy).IsAssignableFrom(u) && typeof(IGlobalDispatchProxy).IsAssignableFrom(u) && u.IsClass && !u.IsInterface && !u.IsAbstract);
TypeNamedCollection = new ConcurrentDictionary<string, Type>(); TypeNamedCollection = new NonBlockingDictionary<string, Type>();
DispatchCreateMethod = typeof(AspectDispatchProxy).GetMethod(nameof(AspectDispatchProxy.Create)); DispatchCreateMethod = typeof(AspectDispatchProxy).GetMethod(nameof(AspectDispatchProxy.Create));
} }
} }

View File

@@ -21,7 +21,7 @@ using System.Collections.Concurrent;
using System.Reflection; using System.Reflection;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using ThingsGateway.UnifyResult; using ThingsGateway.UnifyResult;
namespace ThingsGateway.DynamicApiController; namespace ThingsGateway.DynamicApiController;

View File

@@ -28,21 +28,21 @@ internal static class Penetrates
/// <summary> /// <summary>
/// 请求动词映射字典 /// 请求动词映射字典
/// </summary> /// </summary>
internal static ConcurrentDictionary<string, string> VerbToHttpMethods { get; private set; } internal static NonBlockingDictionary<string, string> VerbToHttpMethods { get; private set; }
/// <summary> /// <summary>
/// 控制器排序集合 /// 控制器排序集合
/// </summary> /// </summary>
internal static ConcurrentDictionary<string, (string, int, Type)> ControllerOrderCollection { get; set; } internal static NonBlockingDictionary<string, (string, int, Type)> ControllerOrderCollection { get; set; }
/// <summary> /// <summary>
/// 构造函数 /// 构造函数
/// </summary> /// </summary>
static Penetrates() static Penetrates()
{ {
ControllerOrderCollection = new ConcurrentDictionary<string, (string, int, Type)>(); ControllerOrderCollection = new NonBlockingDictionary<string, (string, int, Type)>();
VerbToHttpMethods = new ConcurrentDictionary<string, string> VerbToHttpMethods = new NonBlockingDictionary<string, string>
{ {
["post"] = "POST", ["post"] = "POST",
["add"] = "POST", ["add"] = "POST",
@@ -67,13 +67,13 @@ internal static class Penetrates
["patch"] = "PATCH" ["patch"] = "PATCH"
}; };
//IsApiControllerCached = new ConcurrentDictionary<Type, bool>(); //IsApiControllerCached = new NonBlockingDictionary<Type, bool>();
} }
///// <summary> ///// <summary>
///// <see cref="IsApiController(Type)"/> 缓存集合 ///// <see cref="IsApiController(Type)"/> 缓存集合
///// </summary> ///// </summary>
//private static readonly ConcurrentDictionary<Type, bool> IsApiControllerCached; //private static readonly NonBlockingDictionary<Type, bool> IsApiControllerCached;
/// <summary> /// <summary>
/// 是否是Api控制器 /// 是否是Api控制器

View File

@@ -61,7 +61,7 @@ internal sealed class EventBusHostedService : BackgroundService
/// <summary> /// <summary>
/// 事件处理程序集合 /// 事件处理程序集合
/// </summary> /// </summary>
private readonly ConcurrentDictionary<EventHandlerWrapper, EventHandlerWrapper> _eventHandlers = new(); private readonly NonBlockingDictionary<EventHandlerWrapper, EventHandlerWrapper> _eventHandlers = new();
/// <summary> /// <summary>
/// 构造函数 /// 构造函数
@@ -295,7 +295,8 @@ internal sealed class EventBusHostedService : BackgroundService
, retryAction: (total, times) => , retryAction: (total, times) =>
{ {
// 输出重试日志 // 输出重试日志
_logger.LogWarning("Retrying {times}/{total} times for {EventId}", times, total, eventSource.EventId); if (_logger?.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Warning) == true)
_logger.LogWarning("Retrying {times}/{total} times for {EventId}", times, total, eventSource.EventId);
}).ConfigureAwait(false); }).ConfigureAwait(false);
} }
else else

View File

@@ -17,7 +17,7 @@ using System.ComponentModel.DataAnnotations;
using System.Diagnostics; using System.Diagnostics;
using System.Reflection; using System.Reflection;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using ThingsGateway.Templates.Extensions; using ThingsGateway.Templates.Extensions;
namespace ThingsGateway.FriendlyException; namespace ThingsGateway.FriendlyException;
@@ -31,7 +31,7 @@ public static class Oops
/// <summary> /// <summary>
/// 方法错误异常特性 /// 方法错误异常特性
/// </summary> /// </summary>
private static readonly ConcurrentDictionary<MethodBase, MethodIfException> _errorMethods; private static readonly NonBlockingDictionary<MethodBase, MethodIfException> _errorMethods;
/// <summary> /// <summary>
/// 错误代码类型 /// 错误代码类型
@@ -41,7 +41,7 @@ public static class Oops
/// <summary> /// <summary>
/// 错误消息字典 /// 错误消息字典
/// </summary> /// </summary>
private static readonly ConcurrentDictionary<string, string> _errorCodeMessages; private static readonly NonBlockingDictionary<string, string> _errorCodeMessages;
/// <summary> /// <summary>
/// 友好异常设置 /// 友好异常设置
@@ -53,7 +53,7 @@ public static class Oops
/// </summary> /// </summary>
static Oops() static Oops()
{ {
_errorMethods = new ConcurrentDictionary<MethodBase, MethodIfException>(); _errorMethods = new NonBlockingDictionary<MethodBase, MethodIfException>();
_friendlyExceptionSettings = App.GetConfig<FriendlyExceptionSettingsOptions>("FriendlyExceptionSettings", true); _friendlyExceptionSettings = App.GetConfig<FriendlyExceptionSettingsOptions>("FriendlyExceptionSettings", true);
_errorCodeTypes = GetErrorCodeTypes(); _errorCodeTypes = GetErrorCodeTypes();
_errorCodeMessages = GetErrorCodeMessages(); _errorCodeMessages = GetErrorCodeMessages();
@@ -258,9 +258,9 @@ public static class Oops
/// 获取所有错误消息 /// 获取所有错误消息
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
private static ConcurrentDictionary<string, string> GetErrorCodeMessages() private static NonBlockingDictionary<string, string> GetErrorCodeMessages()
{ {
var defaultErrorCodeMessages = new ConcurrentDictionary<string, string>(); var defaultErrorCodeMessages = new NonBlockingDictionary<string, string>();
// 查找所有 [ErrorCodeType] 类型中的 [ErrorCodeMetadata] 元数据定义 // 查找所有 [ErrorCodeType] 类型中的 [ErrorCodeMetadata] 元数据定义
var errorCodeMessages = _errorCodeTypes.SelectMany(u => u.GetFields().Where(u => u.IsDefined(typeof(ErrorCodeItemMetadataAttribute)))) var errorCodeMessages = _errorCodeTypes.SelectMany(u => u.GetFields().Where(u => u.IsDefined(typeof(ErrorCodeItemMetadataAttribute))))

View File

@@ -16,7 +16,7 @@ using Microsoft.AspNetCore.SignalR;
using System.Reflection; using System.Reflection;
using ThingsGateway; using ThingsGateway;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using ThingsGateway.InstantMessaging; using ThingsGateway.InstantMessaging;
namespace Microsoft.AspNetCore.Builder; namespace Microsoft.AspNetCore.Builder;

View File

@@ -23,7 +23,7 @@ public static class ILoggerExtensions
/// 设置日志上下文 /// 设置日志上下文
/// </summary> /// </summary>
/// <param name="logger"></param> /// <param name="logger"></param>
/// <param name="properties">建议使用 ConcurrentDictionary 类型</param> /// <param name="properties">建议使用 NonBlockingDictionary 类型</param>
/// <returns></returns> /// <returns></returns>
public static IDisposable ScopeContext(this ILogger logger, IDictionary<string, object> properties) public static IDisposable ScopeContext(this ILogger logger, IDictionary<string, object> properties)
{ {

View File

@@ -9,7 +9,7 @@
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。 // 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
using ThingsGateway.Extensions; using ThingsGateway.Extension;
namespace ThingsGateway.Logging; namespace ThingsGateway.Logging;

View File

@@ -82,7 +82,7 @@ public static class StringLoggingExtensions
/// 配置日志上下文 /// 配置日志上下文
/// </summary> /// </summary>
/// <param name="message"></param> /// <param name="message"></param>
/// <param name="properties">建议使用 ConcurrentDictionary 类型</param> /// <param name="properties">建议使用 NonBlockingDictionary 类型</param>
/// <returns></returns> /// <returns></returns>
public static StringLoggingPart ScopeContext(this string message, IDictionary<string, object> properties) public static StringLoggingPart ScopeContext(this string message, IDictionary<string, object> properties)
{ {

View File

@@ -44,7 +44,7 @@ public sealed class FileLoggerProvider : ILoggerProvider, ISupportExternalScope
/// 记录日志所有滚动文件名 /// 记录日志所有滚动文件名
/// </summary> /// </summary>
/// <remarks>只有 MaxRollingFiles 和 FileSizeLimitBytes 大于 0 有效</remarks> /// <remarks>只有 MaxRollingFiles 和 FileSizeLimitBytes 大于 0 有效</remarks>
internal readonly ConcurrentDictionary<string, FileInfo> _rollingFileNames = new(); internal readonly NonBlockingDictionary<string, FileInfo> _rollingFileNames = new();
/// <summary> /// <summary>
/// 文件日志写入器 /// 文件日志写入器

View File

@@ -36,7 +36,7 @@ using System.Text.Json;
using ThingsGateway; using ThingsGateway;
using ThingsGateway.DataValidation; using ThingsGateway.DataValidation;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using ThingsGateway.FriendlyException; using ThingsGateway.FriendlyException;
using ThingsGateway.JsonSerialization; using ThingsGateway.JsonSerialization;
using ThingsGateway.Logging; using ThingsGateway.Logging;

View File

@@ -94,7 +94,7 @@ public sealed partial class StringLoggingPart
/// <summary> /// <summary>
/// 配置日志上下文 /// 配置日志上下文
/// </summary> /// </summary>
/// <param name="properties">建议使用 ConcurrentDictionary 类型</param> /// <param name="properties">建议使用 NonBlockingDictionary 类型</param>
/// <returns></returns> /// <returns></returns>
public StringLoggingPart ScopeContext(IDictionary<string, object> properties) public StringLoggingPart ScopeContext(IDictionary<string, object> properties)
{ {

View File

@@ -57,7 +57,7 @@ public static class Log
/// <summary> /// <summary>
/// 配置日志上下文 /// 配置日志上下文
/// </summary> /// </summary>
/// <param name="properties">建议使用 ConcurrentDictionary 类型</param> /// <param name="properties">建议使用 NonBlockingDictionary 类型</param>
/// <returns></returns> /// <returns></returns>
public static (ILogger logger, IDisposable scope) ScopeContext(IDictionary<string, object> properties) public static (ILogger logger, IDisposable scope) ScopeContext(IDictionary<string, object> properties)
{ {

View File

@@ -16,7 +16,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using ThingsGateway.Options; using ThingsGateway.Options;
namespace Microsoft.Extensions.Options; namespace Microsoft.Extensions.Options;

View File

@@ -21,7 +21,7 @@ internal sealed class JobCancellationToken : IJobCancellationToken
/// <summary> /// <summary>
/// 取消作业执行 Token 集合 /// 取消作业执行 Token 集合
/// </summary> /// </summary>
private readonly ConcurrentDictionary<string, CancellationTokenSource> _cancellationTokenSources; private readonly NonBlockingDictionary<string, CancellationTokenSource> _cancellationTokenSources;
/// <summary> /// <summary>
/// 作业调度器日志服务 /// 作业调度器日志服务

View File

@@ -167,7 +167,7 @@ public partial class JobDetail
/// <summary> /// <summary>
/// 带命名规则的数据库列名 /// 带命名规则的数据库列名
/// </summary> /// </summary>
private readonly ConcurrentDictionary<NamingConventions, string[]> _namingColumnNames = new(); private readonly NonBlockingDictionary<NamingConventions, string[]> _namingColumnNames = new();
/// <summary> /// <summary>
/// 获取数据库列名 /// 获取数据库列名

View File

@@ -65,7 +65,7 @@ internal sealed partial class SchedulerFactory : ISchedulerFactory
/// <summary> /// <summary>
/// 作业计划集合 /// 作业计划集合
/// </summary> /// </summary>
private readonly ConcurrentDictionary<string, Scheduler> _schedulers = new(); private readonly NonBlockingDictionary<string, Scheduler> _schedulers = new();
/// <summary> /// <summary>
/// 作业计划构建器集合 /// 作业计划构建器集合

View File

@@ -369,11 +369,13 @@ internal sealed class ScheduleHostedService : BackgroundService
// 写入作业执行详细日志 // 写入作业执行详细日志
if (executionException == null) if (executionException == null)
{ {
jobLogger?.LogInformation("{jobExecutingContext}", jobExecutingContext); if (jobLogger?.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Information) == true)
jobLogger?.LogInformation("{jobExecutingContext}", jobExecutingContext);
} }
else else
{ {
jobLogger?.LogError(executionException, "{jobExecutingContext}", jobExecutingContext); if (jobLogger?.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Error) == true)
jobLogger?.LogError(executionException, "{jobExecutingContext}", jobExecutingContext);
} }
// 记录作业触发器运行信息 // 记录作业触发器运行信息

View File

@@ -380,7 +380,7 @@ public partial class Trigger
/// <summary> /// <summary>
/// 带命名规则的数据库列名 /// 带命名规则的数据库列名
/// </summary> /// </summary>
private readonly ConcurrentDictionary<NamingConventions, string[]> _namingColumnNames = new(); private readonly NonBlockingDictionary<NamingConventions, string[]> _namingColumnNames = new();
/// <summary> /// <summary>
/// 获取数据库列名 /// 获取数据库列名

View File

@@ -31,7 +31,7 @@ using System.Xml.Linq;
using System.Xml.XPath; using System.Xml.XPath;
using ThingsGateway.DynamicApiController; using ThingsGateway.DynamicApiController;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using ThingsGateway.Reflection; using ThingsGateway.Reflection;
namespace ThingsGateway.SpecificationDocument; namespace ThingsGateway.SpecificationDocument;
@@ -83,11 +83,11 @@ public static class SpecificationDocumentBuilder
// 初始化常量 // 初始化常量
_groupOrderRegex = new Regex(@"@(?<order>[0-9]+$)"); _groupOrderRegex = new Regex(@"@(?<order>[0-9]+$)");
GetActionGroupsCached = new ConcurrentDictionary<MethodInfo, IEnumerable<GroupExtraInfo>>(); GetActionGroupsCached = new NonBlockingDictionary<MethodInfo, IEnumerable<GroupExtraInfo>>();
GetControllerGroupsCached = new ConcurrentDictionary<Type, IEnumerable<GroupExtraInfo>>(); GetControllerGroupsCached = new NonBlockingDictionary<Type, IEnumerable<GroupExtraInfo>>();
GetGroupOpenApiInfoCached = new ConcurrentDictionary<string, SpecificationOpenApiInfo>(); GetGroupOpenApiInfoCached = new NonBlockingDictionary<string, SpecificationOpenApiInfo>();
GetControllerTagCached = new ConcurrentDictionary<ControllerActionDescriptor, string>(); GetControllerTagCached = new NonBlockingDictionary<ControllerActionDescriptor, string>();
GetActionTagCached = new ConcurrentDictionary<ApiDescription, string>(); GetActionTagCached = new NonBlockingDictionary<ApiDescription, string>();
// 默认分组,支持多个逗号分割 // 默认分组,支持多个逗号分割
DocumentGroupExtras = new List<GroupExtraInfo> { ResolveGroupExtraInfo(_specificationDocumentSettings.DefaultGroupName) }; DocumentGroupExtras = new List<GroupExtraInfo> { ResolveGroupExtraInfo(_specificationDocumentSettings.DefaultGroupName) };
@@ -143,7 +143,7 @@ public static class SpecificationDocumentBuilder
/// <summary> /// <summary>
/// 获取分组信息缓存集合 /// 获取分组信息缓存集合
/// </summary> /// </summary>
private static readonly ConcurrentDictionary<string, SpecificationOpenApiInfo> GetGroupOpenApiInfoCached; private static readonly NonBlockingDictionary<string, SpecificationOpenApiInfo> GetGroupOpenApiInfoCached;
/// <summary> /// <summary>
/// 获取分组配置信息 /// 获取分组配置信息
@@ -738,7 +738,7 @@ public static class SpecificationDocumentBuilder
/// <summary> /// <summary>
/// 获取控制器组缓存集合 /// 获取控制器组缓存集合
/// </summary> /// </summary>
private static readonly ConcurrentDictionary<Type, IEnumerable<GroupExtraInfo>> GetControllerGroupsCached; private static readonly NonBlockingDictionary<Type, IEnumerable<GroupExtraInfo>> GetControllerGroupsCached;
/// <summary> /// <summary>
/// 获取控制器分组列表 /// 获取控制器分组列表
@@ -773,7 +773,7 @@ public static class SpecificationDocumentBuilder
/// <summary> /// <summary>
/// <see cref="GetActionGroups(MethodInfo)"/> 缓存集合 /// <see cref="GetActionGroups(MethodInfo)"/> 缓存集合
/// </summary> /// </summary>
private static readonly ConcurrentDictionary<MethodInfo, IEnumerable<GroupExtraInfo>> GetActionGroupsCached; private static readonly NonBlockingDictionary<MethodInfo, IEnumerable<GroupExtraInfo>> GetActionGroupsCached;
/// <summary> /// <summary>
/// 获取动作方法分组列表 /// 获取动作方法分组列表
@@ -808,7 +808,7 @@ public static class SpecificationDocumentBuilder
/// <summary> /// <summary>
/// <see cref="GetActionTag(ApiDescription)"/> 缓存集合 /// <see cref="GetActionTag(ApiDescription)"/> 缓存集合
/// </summary> /// </summary>
private static readonly ConcurrentDictionary<ControllerActionDescriptor, string> GetControllerTagCached; private static readonly NonBlockingDictionary<ControllerActionDescriptor, string> GetControllerTagCached;
/// <summary> /// <summary>
/// 获取控制器标签 /// 获取控制器标签
@@ -835,7 +835,7 @@ public static class SpecificationDocumentBuilder
/// <summary> /// <summary>
/// <see cref="GetActionTag(ApiDescription)"/> 缓存集合 /// <see cref="GetActionTag(ApiDescription)"/> 缓存集合
/// </summary> /// </summary>
private static readonly ConcurrentDictionary<ApiDescription, string> GetActionTagCached; private static readonly NonBlockingDictionary<ApiDescription, string> GetActionTagCached;
/// <summary> /// <summary>
/// 获取动作方法标签 /// 获取动作方法标签

View File

@@ -20,7 +20,7 @@ using System.Reflection;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
namespace ThingsGateway.SpecificationDocument; namespace ThingsGateway.SpecificationDocument;

View File

@@ -11,7 +11,7 @@
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
namespace ThingsGateway.Templates.Extensions; namespace ThingsGateway.Templates.Extensions;

View File

@@ -13,7 +13,7 @@ using Microsoft.AspNetCore.Http;
using System.Reflection; using System.Reflection;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using ThingsGateway.UnifyResult; using ThingsGateway.UnifyResult;
namespace Microsoft.AspNetCore.Mvc; namespace Microsoft.AspNetCore.Mvc;

View File

@@ -22,7 +22,7 @@ using Microsoft.Extensions.Options;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Reflection; using System.Reflection;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using ThingsGateway.FriendlyException; using ThingsGateway.FriendlyException;
namespace ThingsGateway.UnifyResult; namespace ThingsGateway.UnifyResult;
@@ -51,12 +51,12 @@ public static class UnifyContext
/// <summary> /// <summary>
/// 规范化结果提供器 /// 规范化结果提供器
/// </summary> /// </summary>
internal static ConcurrentDictionary<string, UnifyMetadata> UnifyProviders = new(); internal static NonBlockingDictionary<string, UnifyMetadata> UnifyProviders = new();
/// <summary> /// <summary>
/// 规范化序列化配置 /// 规范化序列化配置
/// </summary> /// </summary>
internal static ConcurrentDictionary<string, object> UnifySerializerSettings = new(); internal static NonBlockingDictionary<string, object> UnifySerializerSettings = new();
/// <summary> /// <summary>
/// 获取异常元数据 /// 获取异常元数据

View File

@@ -12,7 +12,7 @@
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
namespace ThingsGateway.Converters.Json; namespace ThingsGateway.Converters.Json;

View File

@@ -11,7 +11,7 @@
using System.Reflection; using System.Reflection;
namespace ThingsGateway.Extensions; namespace ThingsGateway.Extension;
/// <summary> /// <summary>
/// <see cref="Assembly" /> 拓展类 /// <see cref="Assembly" /> 拓展类

View File

@@ -11,10 +11,10 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
namespace ThingsGateway.Extensions; namespace ThingsGateway.Extension;
/// <summary> /// <summary>
/// <see cref="ConcurrentDictionary{TKey, TValue}" /> 拓展类 /// <see cref="NonBlockingDictionary{TKey, TValue}" /> 拓展类
/// </summary> /// </summary>
internal static class ConcurrentDictionaryExtensions internal static class ConcurrentDictionaryExtensions
{ {
@@ -24,7 +24,7 @@ internal static class ConcurrentDictionaryExtensions
/// <typeparam name="TKey">字典键类型</typeparam> /// <typeparam name="TKey">字典键类型</typeparam>
/// <typeparam name="TValue">字典值类型</typeparam> /// <typeparam name="TValue">字典值类型</typeparam>
/// <param name="dictionary"> /// <param name="dictionary">
/// <see cref="ConcurrentDictionary{TKey, TValue}" /> /// <see cref="NonBlockingDictionary{TKey, TValue}" />
/// </param> /// </param>
/// <param name="key"> /// <param name="key">
/// <typeparamref name="TKey" /> /// <typeparamref name="TKey" />
@@ -36,7 +36,7 @@ internal static class ConcurrentDictionaryExtensions
/// <returns> /// <returns>
/// <see cref="bool" /> /// <see cref="bool" />
/// </returns> /// </returns>
internal static bool TryUpdate<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> dictionary internal static bool TryUpdate<TKey, TValue>(this NonBlockingDictionary<TKey, TValue> dictionary
, TKey key , TKey key
, Func<TValue, TValue> updateFactory , Func<TValue, TValue> updateFactory
, out TValue? value) , out TValue? value)

View File

@@ -15,7 +15,7 @@ using Microsoft.Extensions.Hosting;
using System.Reflection; using System.Reflection;
namespace ThingsGateway.Extensions; namespace ThingsGateway.Extension;
/// <summary> /// <summary>
/// 核心模块 <see cref="IServiceCollection" /> 拓展类 /// 核心模块 <see cref="IServiceCollection" /> 拓展类

View File

@@ -11,7 +11,7 @@
using System.Data; using System.Data;
namespace ThingsGateway.Extensions; namespace ThingsGateway.Extension;
/// <summary> /// <summary>
/// <see cref="DataTable" /> 和 <see cref="DataSet" /> 拓展类 /// <see cref="DataTable" /> 和 <see cref="DataSet" /> 拓展类

View File

@@ -9,7 +9,7 @@
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。 // 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
namespace ThingsGateway.Extensions; namespace ThingsGateway.Extension;
/// <summary> /// <summary>
/// 委托拓展类 /// 委托拓展类

View File

@@ -12,7 +12,7 @@
using System.ComponentModel; using System.ComponentModel;
using System.Reflection; using System.Reflection;
namespace ThingsGateway.Extensions; namespace ThingsGateway.Extension;
/// <summary> /// <summary>
/// 枚举拓展类 /// 枚举拓展类

View File

@@ -9,7 +9,7 @@
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。 // 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
namespace ThingsGateway.Extensions; namespace ThingsGateway.Extension;
/// <summary> /// <summary>
/// <see cref="EventHandler{TEventArgs}" /> 拓展类 /// <see cref="EventHandler{TEventArgs}" /> 拓展类

View File

@@ -11,7 +11,7 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
namespace ThingsGateway.Extensions; namespace ThingsGateway.Extension;
/// <summary> /// <summary>
/// <see cref="ICollection{T}" /> 拓展类 /// <see cref="ICollection{T}" /> 拓展类

View File

@@ -11,7 +11,7 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
namespace ThingsGateway.Extensions; namespace ThingsGateway.Extension;
/// <summary> /// <summary>
/// <see cref="IDictionary{TKey, TValue}" /> 拓展类 /// <see cref="IDictionary{TKey, TValue}" /> 拓展类
@@ -241,7 +241,7 @@ internal static class IDictionaryExtensions
/// </summary> /// </summary>
/// <remarks>其中键是由值通过给定的选择器函数生成的。</remarks> /// <remarks>其中键是由值通过给定的选择器函数生成的。</remarks>
/// <param name="dictionary"> /// <param name="dictionary">
/// <see cref="ConcurrentDictionary{TKey, TValue}" /> /// <see cref="NonBlockingDictionary{TKey, TValue}" />
/// </param> /// </param>
/// <param name="values"> /// <param name="values">
/// <see cref="IEnumerable{T}" /> /// <see cref="IEnumerable{T}" />
@@ -249,7 +249,7 @@ internal static class IDictionaryExtensions
/// <param name="keySelector">键选择器</param> /// <param name="keySelector">键选择器</param>
/// <typeparam name="TKey">字典键类型</typeparam> /// <typeparam name="TKey">字典键类型</typeparam>
/// <typeparam name="TValue">字典值类型</typeparam> /// <typeparam name="TValue">字典值类型</typeparam>
internal static void TryAdd<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> dictionary, internal static void TryAdd<TKey, TValue>(this NonBlockingDictionary<TKey, TValue> dictionary,
IEnumerable<TValue>? values, Func<TValue, TKey> keySelector) IEnumerable<TValue>? values, Func<TValue, TKey> keySelector)
where TKey : notnull where TKey : notnull
{ {

View File

@@ -9,7 +9,7 @@
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。 // 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
namespace ThingsGateway.Extensions; namespace ThingsGateway.Extension;
/// <summary> /// <summary>
/// <see cref="IEnumerable" /> 拓展类 /// <see cref="IEnumerable" /> 拓展类

View File

@@ -18,7 +18,7 @@ using System.Text.RegularExpressions;
using System.Xml; using System.Xml;
using System.Xml.Linq; using System.Xml.Linq;
namespace ThingsGateway.Extensions; namespace ThingsGateway.Extension;
/// <summary> /// <summary>
/// System.Text.Json 拓展类 /// System.Text.Json 拓展类

View File

@@ -12,7 +12,7 @@
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
namespace ThingsGateway.Extensions; namespace ThingsGateway.Extension;
/// <summary> /// <summary>
/// <see cref="Expression" /> 拓展类 /// <see cref="Expression" /> 拓展类

View File

@@ -12,7 +12,7 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Reflection; using System.Reflection;
namespace ThingsGateway.Extensions; namespace ThingsGateway.Extension;
/// <summary> /// <summary>
/// <see cref="MethodInfo" /> 拓展类 /// <see cref="MethodInfo" /> 拓展类

View File

@@ -9,7 +9,7 @@
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。 // 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
namespace ThingsGateway.Extensions; namespace ThingsGateway.Extension;
/// <summary> /// <summary>
/// 数值类型拓展类 /// 数值类型拓展类

View File

@@ -17,7 +17,7 @@ using System.Reflection;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace ThingsGateway.Extensions; namespace ThingsGateway.Extension;
/// <summary> /// <summary>
/// <see cref="string" /> 拓展类 /// <see cref="string" /> 拓展类

View File

@@ -15,7 +15,7 @@ using System.Reflection;
using System.Reflection.Emit; using System.Reflection.Emit;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace ThingsGateway.Extensions; namespace ThingsGateway.Extension;
/// <summary> /// <summary>
/// <see cref="Type" /> 拓展类 /// <see cref="Type" /> 拓展类

View File

@@ -13,7 +13,7 @@ using System.Buffers;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
namespace ThingsGateway.Extensions; namespace ThingsGateway.Extension;
/// <summary> /// <summary>
/// <see cref="Utf8JsonReader" /> 拓展类 /// <see cref="Utf8JsonReader" /> 拓展类

View File

@@ -16,7 +16,7 @@ using System.Text.Json;
using ThingsGateway.Utilities; using ThingsGateway.Utilities;
namespace ThingsGateway.Extensions; namespace ThingsGateway.Extension;
/// <summary> /// <summary>
/// <see cref="object" /> 拓展类 /// <see cref="object" /> 拓展类

View File

@@ -21,20 +21,20 @@ internal sealed class CoreOptions
/// <summary> /// <summary>
/// 已注册的组件元数据集合 /// 已注册的组件元数据集合
/// </summary> /// </summary>
internal readonly ConcurrentDictionary<string, ComponentMetadata> _metadataOfRegistered; internal readonly NonBlockingDictionary<string, ComponentMetadata> _metadataOfRegistered;
/// <summary> /// <summary>
/// 子选项集合 /// 子选项集合
/// </summary> /// </summary>
internal readonly ConcurrentDictionary<Type, object> _optionsInstances; internal readonly NonBlockingDictionary<Type, object> _optionsInstances;
/// <summary> /// <summary>
/// <inheritdoc cref="CoreOptions" /> /// <inheritdoc cref="CoreOptions" />
/// </summary> /// </summary>
internal CoreOptions() internal CoreOptions()
{ {
_optionsInstances = new ConcurrentDictionary<Type, object>(); _optionsInstances = new NonBlockingDictionary<Type, object>();
_metadataOfRegistered = new ConcurrentDictionary<string, ComponentMetadata>(StringComparer.OrdinalIgnoreCase); _metadataOfRegistered = new NonBlockingDictionary<string, ComponentMetadata>(StringComparer.OrdinalIgnoreCase);
EntryComponentTypes = []; EntryComponentTypes = [];
} }

View File

@@ -13,7 +13,7 @@ using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Reflection; using System.Reflection;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
namespace ThingsGateway.Reflection; namespace ThingsGateway.Reflection;
@@ -32,7 +32,7 @@ public sealed class ObjectPropertyGetter<T> where T : class
/// <summary> /// <summary>
/// 对象类型实例属性值访问器集合 /// 对象类型实例属性值访问器集合
/// </summary> /// </summary>
internal readonly ConcurrentDictionary<string, Func<object, object?>> _propertyGetters = new(); internal readonly NonBlockingDictionary<string, Func<object, object?>> _propertyGetters = new();
/// <summary> /// <summary>
/// <inheritdoc cref="ObjectPropertyGetter{T}" /> /// <inheritdoc cref="ObjectPropertyGetter{T}" />

View File

@@ -13,7 +13,7 @@ using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Reflection; using System.Reflection;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
namespace ThingsGateway.Reflection; namespace ThingsGateway.Reflection;
@@ -32,7 +32,7 @@ public sealed class ObjectPropertySetter<T> where T : class
/// <summary> /// <summary>
/// 对象类型实例属性值设置器集合 /// 对象类型实例属性值设置器集合
/// </summary> /// </summary>
internal readonly ConcurrentDictionary<string, Action<object, object?>> _propertySetters = new(); internal readonly NonBlockingDictionary<string, Action<object, object?>> _propertySetters = new();
/// <summary> /// <summary>
/// <inheritdoc cref="ObjectPropertySetter{T}" /> /// <inheritdoc cref="ObjectPropertySetter{T}" />

View File

@@ -11,7 +11,7 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
namespace ThingsGateway.Utilities; namespace ThingsGateway.Utilities;

View File

@@ -11,7 +11,7 @@
using System.Text; using System.Text;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
namespace ThingsGateway.Utilities; namespace ThingsGateway.Utilities;

View File

@@ -18,7 +18,7 @@ using Microsoft.Net.Http.Headers;
using System.Net.Mime; using System.Net.Mime;
using ThingsGateway.AspNetCore.Extensions; using ThingsGateway.AspNetCore.Extensions;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using MediaTypeHeaderValue = System.Net.Http.Headers.MediaTypeHeaderValue; using MediaTypeHeaderValue = System.Net.Http.Headers.MediaTypeHeaderValue;

View File

@@ -12,7 +12,7 @@
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Threading.Channels; using System.Threading.Channels;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using ThingsGateway.Utilities; using ThingsGateway.Utilities;
namespace ThingsGateway.HttpRemote; namespace ThingsGateway.HttpRemote;

View File

@@ -16,7 +16,7 @@ using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Threading.Channels; using System.Threading.Channels;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using ThingsGateway.Utilities; using ThingsGateway.Utilities;
namespace ThingsGateway.HttpRemote; namespace ThingsGateway.HttpRemote;

View File

@@ -16,7 +16,7 @@ using Microsoft.Extensions.Logging;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
namespace ThingsGateway.HttpRemote; namespace ThingsGateway.HttpRemote;

View File

@@ -17,7 +17,7 @@ using System.Net.Mime;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using ThingsGateway.Utilities; using ThingsGateway.Utilities;
using MediaTypeHeaderValue = System.Net.Http.Headers.MediaTypeHeaderValue; using MediaTypeHeaderValue = System.Net.Http.Headers.MediaTypeHeaderValue;

View File

@@ -16,7 +16,7 @@ using System.Globalization;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Net.Mime; using System.Net.Mime;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using CacheControlHeaderValue = System.Net.Http.Headers.CacheControlHeaderValue; using CacheControlHeaderValue = System.Net.Http.Headers.CacheControlHeaderValue;
using StringWithQualityHeaderValue = System.Net.Http.Headers.StringWithQualityHeaderValue; using StringWithQualityHeaderValue = System.Net.Http.Headers.StringWithQualityHeaderValue;

View File

@@ -14,7 +14,7 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Reflection; using System.Reflection;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
namespace ThingsGateway.HttpRemote; namespace ThingsGateway.HttpRemote;
@@ -27,7 +27,7 @@ public sealed class HttpDeclarativeBuilder
/// <summary> /// <summary>
/// HTTP 声明式 <see cref="IHttpDeclarativeExtractor" /> 提取器集合 /// HTTP 声明式 <see cref="IHttpDeclarativeExtractor" /> 提取器集合
/// </summary> /// </summary>
internal static readonly ConcurrentDictionary<Type, IHttpDeclarativeExtractor> _extractors = new([ internal static readonly NonBlockingDictionary<Type, IHttpDeclarativeExtractor> _extractors = new([
new(typeof(BaseAddressDeclarativeExtractor), new BaseAddressDeclarativeExtractor()), new(typeof(BaseAddressDeclarativeExtractor), new BaseAddressDeclarativeExtractor()),
new(typeof(ValidationDeclarativeExtractor), new ValidationDeclarativeExtractor()), new(typeof(ValidationDeclarativeExtractor), new ValidationDeclarativeExtractor()),
new(typeof(AutoSetHostHeaderDeclarativeExtractor), new AutoSetHostHeaderDeclarativeExtractor()), new(typeof(AutoSetHostHeaderDeclarativeExtractor), new AutoSetHostHeaderDeclarativeExtractor()),
@@ -56,7 +56,7 @@ public sealed class HttpDeclarativeBuilder
/// HTTP 声明式 <see cref="IHttpDeclarativeExtractor" /> 提取器集合(冻结) /// HTTP 声明式 <see cref="IHttpDeclarativeExtractor" /> 提取器集合(冻结)
/// </summary> /// </summary>
/// <remarks>该集合用于确保某些 HTTP 声明式提取器始终位于最后。</remarks> /// <remarks>该集合用于确保某些 HTTP 声明式提取器始终位于最后。</remarks>
internal static readonly ConcurrentDictionary<Type, IFrozenHttpDeclarativeExtractor> _frozenExtractors = new([ internal static readonly NonBlockingDictionary<Type, IFrozenHttpDeclarativeExtractor> _frozenExtractors = new([
new(typeof(MultipartDeclarativeExtractor), new MultipartDeclarativeExtractor()), new(typeof(MultipartDeclarativeExtractor), new MultipartDeclarativeExtractor()),
new(typeof(HttpMultipartFormDataBuilderDeclarativeExtractor), new(typeof(HttpMultipartFormDataBuilderDeclarativeExtractor),
new HttpMultipartFormDataBuilderDeclarativeExtractor()), new HttpMultipartFormDataBuilderDeclarativeExtractor()),

View File

@@ -12,7 +12,7 @@
using System.Net.Mime; using System.Net.Mime;
using System.Reflection; using System.Reflection;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
namespace ThingsGateway.HttpRemote; namespace ThingsGateway.HttpRemote;

View File

@@ -11,7 +11,7 @@
using System.Reflection; using System.Reflection;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using ThingsGateway.Utilities; using ThingsGateway.Utilities;
namespace ThingsGateway.HttpRemote; namespace ThingsGateway.HttpRemote;

View File

@@ -11,7 +11,7 @@
using System.Reflection; using System.Reflection;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using ThingsGateway.Utilities; using ThingsGateway.Utilities;
namespace ThingsGateway.HttpRemote; namespace ThingsGateway.HttpRemote;

View File

@@ -14,7 +14,7 @@ using System.Net.Mime;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
namespace ThingsGateway.HttpRemote; namespace ThingsGateway.HttpRemote;

View File

@@ -9,7 +9,7 @@
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。 // 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using ThingsGateway.Utilities; using ThingsGateway.Utilities;
namespace ThingsGateway.HttpRemote; namespace ThingsGateway.HttpRemote;

View File

@@ -11,7 +11,7 @@
using System.Reflection; using System.Reflection;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using ThingsGateway.Utilities; using ThingsGateway.Utilities;
namespace ThingsGateway.HttpRemote; namespace ThingsGateway.HttpRemote;

View File

@@ -11,7 +11,7 @@
using System.Reflection; using System.Reflection;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
using ThingsGateway.Utilities; using ThingsGateway.Utilities;
namespace ThingsGateway.HttpRemote; namespace ThingsGateway.HttpRemote;

View File

@@ -12,7 +12,7 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Reflection; using System.Reflection;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
namespace ThingsGateway.HttpRemote; namespace ThingsGateway.HttpRemote;

View File

@@ -12,7 +12,7 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Reflection; using System.Reflection;
using ThingsGateway.Extensions; using ThingsGateway.Extension;
namespace ThingsGateway.HttpRemote; namespace ThingsGateway.HttpRemote;

View File

@@ -251,7 +251,8 @@ public sealed class ProfilerDelegatingHandler(ILogger<Logging> logger, IOptions<
// 检查是否配置(注册)了日志程序 // 检查是否配置(注册)了日志程序
if (remoteOptions.IsLoggingRegistered) if (remoteOptions.IsLoggingRegistered)
{ {
logger.Log(remoteOptions.ProfilerLogLevel, "{message}", message); if (logger?.IsEnabled(remoteOptions.ProfilerLogLevel) == true)
logger.Log(remoteOptions.ProfilerLogLevel, "{message}", message);
} }
else else
{ {

Some files were not shown because too many files have changed in this diff Show More