diff --git a/src/Admin/ThingsGateway.NewLife.X/Common/MachineInfo.cs b/src/Admin/ThingsGateway.NewLife.X/Common/MachineInfo.cs index 8f6229566..a139a4ff0 100644 --- a/src/Admin/ThingsGateway.NewLife.X/Common/MachineInfo.cs +++ b/src/Admin/ThingsGateway.NewLife.X/Common/MachineInfo.cs @@ -683,36 +683,20 @@ public class MachineInfo : IExtend if (dic.TryGetValue("MemTotal", out var str) && !str.IsNullOrEmpty()) Memory = (UInt64)str.TrimEnd(" kB").ToLong(); - /* -指标 含义 是否可回收 -MemTotal 系统总物理内存 ❌ 固定值 -MemFree 完全未使用的内存(不含缓存/缓冲区) ✅ 100% 可用 -MemAvailable 内核估计的可用内存(含可回收缓存和缓冲区) ✅ 最权威的保守估计 -Cached 文件系统缓存(Page Cache),可完全回收 ✅ 100% 可回收 -SReclaimable Slab 缓存中可回收的部分(如 dentry/inode) ✅ 大部分可回收(80%~90%) -Buffers 磁盘块缓存(现代内核中值较小,可回收) ✅ 可回收 -Slab 内核对象缓存总大小(含可回收和不可回收部分) ⚠️ 需区分 SReclaimable -SwapCached 被缓存到 Swap 的内存(可回收,但性能较差) ✅ 可回收但不建议依赖 + ulong ma = 0; + if (dic.TryGetValue("MemAvailable", out str) && !str.IsNullOrEmpty()) + { + ma = (UInt64)(str.TrimEnd(" kB").ToLong()); + } - */ - - var ma = (UInt64)(dic["MemAvailable"]?.TrimEnd(" kB").ToLong() ?? 0); + //低于3.14内核的版本用 free+cache var mf = (UInt64)(dic["MemFree"]?.TrimEnd(" kB").ToLong() ?? 0); var mc = (UInt64)(dic["Cached"]?.TrimEnd(" kB").ToLong() ?? 0); + var bf = (UInt64)(dic["Buffers"]?.TrimEnd(" kB").ToLong() ?? 0); - if (dic.TryGetValue("SReclaimable", out str) && !str.IsNullOrEmpty()) - { - var sr = (UInt64)(str?.TrimEnd(" kB").ToLong() ?? 0); - mf += (ulong)(sr * 0.9); - } - if (dic.TryGetValue("Buffers", out str) && !str.IsNullOrEmpty()) - { - var bf = (UInt64)(str?.TrimEnd(" kB").ToLong() ?? 0); - mf += bf; - } - mf += mc; + var free = mf + mc + bf; - AvailableMemory = ma > mf ? ma : mf; + AvailableMemory = ma > free ? ma : free; } // A2/A4温度获取,Buildroot,CPU温度和主板温度 diff --git a/src/Directory.Build.props b/src/Directory.Build.props index e0a3464a5..bd0cb1962 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,9 +1,9 @@ - 10.10.1 - 10.10.1 - 10.10.2 + 10.10.2 + 10.10.2 + 10.10.3 2.9.29 10.9.29 8.0.18 diff --git a/src/Foundation.props b/src/Foundation.props index 69967512b..fed403748 100644 --- a/src/Foundation.props +++ b/src/Foundation.props @@ -1,6 +1,6 @@ - net462;netstandard2.0;net6.0; + net462;netstandard2.0;net6.0;net8.0 diff --git a/src/Foundation/ThingsGateway.Foundation/Channel/TcpServiceChannel.cs b/src/Foundation/ThingsGateway.Foundation/Channel/TcpServiceChannel.cs index e37b624ab..8d6e978c7 100644 --- a/src/Foundation/ThingsGateway.Foundation/Channel/TcpServiceChannel.cs +++ b/src/Foundation/ThingsGateway.Foundation/Channel/TcpServiceChannel.cs @@ -134,6 +134,7 @@ public abstract class TcpServiceChannelBase : TcpService, ITcp protected override void SafetyDispose(bool disposing) { + m_transport?.SafeCancel(); m_transport?.SafeDispose(); base.SafetyDispose(disposing); } diff --git a/src/Foundation/ThingsGateway.Foundation/Channel/UdpSessionChannel.cs b/src/Foundation/ThingsGateway.Foundation/Channel/UdpSessionChannel.cs index ca51dc6a9..656090cd3 100644 --- a/src/Foundation/ThingsGateway.Foundation/Channel/UdpSessionChannel.cs +++ b/src/Foundation/ThingsGateway.Foundation/Channel/UdpSessionChannel.cs @@ -204,6 +204,7 @@ public class UdpSessionChannel : UdpSession, IClientChannel /// protected override void SafetyDispose(bool disposing) { + m_transport?.SafeCancel(); m_transport?.SafeDispose(); WaitHandlePool.SafeDispose(); base.SafetyDispose(disposing); diff --git a/src/Foundation/ThingsGateway.Foundation/Device/DeviceBase.cs b/src/Foundation/ThingsGateway.Foundation/Device/DeviceBase.cs index c71bcf150..7be93b63d 100644 --- a/src/Foundation/ThingsGateway.Foundation/Device/DeviceBase.cs +++ b/src/Foundation/ThingsGateway.Foundation/Device/DeviceBase.cs @@ -24,7 +24,7 @@ namespace ThingsGateway.Foundation; /// /// 协议基类 /// -public abstract class DeviceBase : DisposableObject, IDevice +public abstract class DeviceBase : AsyncAndSyncDisposableObject, IDevice { /// public IChannel Channel { get; private set; } @@ -585,13 +585,6 @@ public abstract class DeviceBase : DisposableObject, IDevice } catch (Exception ex) { - if (cancellationToken.IsCancellationRequested) - { - if (!this.DisposedValue) - { - await Task.Delay(timeout, Channel.ClosedToken).ConfigureAwait(false); - } - } return new MessageBase(ex); } var result = waitData.Check(); @@ -1041,6 +1034,56 @@ public abstract class DeviceBase : DisposableObject, IDevice base.Dispose(disposing); } + /// + protected override async Task DisposeAsync(bool disposing) + { + if (Channel != null) + { + Channel.Starting.Remove(ChannelStarting); + Channel.Stoped.Remove(ChannelStoped); + Channel.Started.Remove(ChannelStarted); + Channel.Stoping.Remove(ChannelStoping); + Channel.ChannelReceived.Remove(ChannelReceived); + + if (Channel.Collects.Count == 1) + { + if (Channel is ITcpServiceChannel tcpServiceChannel) + { + tcpServiceChannel.Clients.ForEach(a => a.WaitHandlePool.SafeDispose()); + } + + try + { + //只关闭,不释放 + await Channel.CloseAsync().ConfigureAwait(false); + if (Channel is IClientChannel client) + { + client.WaitHandlePool.SafeDispose(); + } + } + catch (Exception ex) + { + Logger?.LogWarning(ex); + } + } + else + { + if (Channel is ITcpServiceChannel tcpServiceChannel && this is IDtu dtu) + { + if (tcpServiceChannel.TryGetClient($"ID={dtu.DtuId}", out var client)) + { + client.WaitHandlePool?.SafeDispose(); + await client.CloseAsync().ConfigureAwait(false); + } + } + } + + Channel.Collects.Remove(this); + } + + _deviceLogger?.TryDispose(); + base.Dispose(disposing); + } /// public virtual Action ConfigurePlugins(TouchSocketConfig config) { @@ -1058,4 +1101,5 @@ public abstract class DeviceBase : DisposableObject, IDevice return a => { }; } public abstract ValueTask>> ReadAsync(object state, CancellationToken cancellationToken = default); + } diff --git a/src/Foundation/ThingsGateway.Foundation/Device/IDevice.cs b/src/Foundation/ThingsGateway.Foundation/Device/IDevice.cs index 001d2de50..e18ddfbb9 100644 --- a/src/Foundation/ThingsGateway.Foundation/Device/IDevice.cs +++ b/src/Foundation/ThingsGateway.Foundation/Device/IDevice.cs @@ -15,7 +15,7 @@ namespace ThingsGateway.Foundation; /// /// 协议设备接口 /// -public interface IDevice : IDisposable, IDisposableObject +public interface IDevice : IDisposable, IDisposableObject, IAsyncDisposable { #region 属性 diff --git a/src/Foundation/ThingsGateway.Foundation/Extensions/DisposableExtensions.cs b/src/Foundation/ThingsGateway.Foundation/Extensions/DisposableExtensions.cs new file mode 100644 index 000000000..105b670b5 --- /dev/null +++ b/src/Foundation/ThingsGateway.Foundation/Extensions/DisposableExtensions.cs @@ -0,0 +1,73 @@ +// ------------------------------------------------------------------------------ +// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 +// 此代码版权(除特别声明外的代码)归作者本人Diego所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议 +// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway +// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway +// 使用文档:https://thingsgateway.cn/ +// QQ群:605534569 +// ------------------------------------------------------------------------------ + +namespace ThingsGateway; + + +public static class DisposableExtensions +{ + #region IDisposable + + /// + /// 安全性释放(不用判断对象是否为空)。不会抛出任何异常。 + /// + /// + /// 释放状态,当对象为,或者已被释放时,均会返回,只有实际在释放时遇到异常时,才显示其他状态。 + public static async Task SafeDisposeAsync(this IAsyncDisposable dis) + { + if (dis == default) + { + return Result.Success; + } + try + { + await dis.DisposeAsync().ConfigureAwait(false); + return Result.Success; + } + catch (Exception ex) + { + return Result.FromException(ex); + } + } + + #endregion IDisposable + + +#if NET8_0_OR_GREATER + + + /// + /// 安全地取消 ,并返回操作结果。 + /// + /// 要取消的 。 + /// 一个 对象,表示操作的结果。 + public static async Task SafeCancelAsync(this CancellationTokenSource tokenSource) + { + if (tokenSource is null) + { + return Result.Success; + } + try + { + await tokenSource.CancelAsync().ConfigureAwait(false); + return Result.Success; + } + catch (ObjectDisposedException) + { + return Result.Disposed; + } + catch (Exception ex) + { + return Result.FromException(ex); + } + } + +#endif +} diff --git a/src/Foundation/ThingsGateway.Foundation/Extensions/PackHelpers.cs b/src/Foundation/ThingsGateway.Foundation/Extensions/PackHelpers.cs index f3e2ea398..35582b23e 100644 --- a/src/Foundation/ThingsGateway.Foundation/Extensions/PackHelpers.cs +++ b/src/Foundation/ThingsGateway.Foundation/Extensions/PackHelpers.cs @@ -9,6 +9,7 @@ //------------------------------------------------------------------------------ namespace ThingsGateway.Foundation; +#pragma warning disable CA1851 public static class PackHelpers { diff --git a/src/Foundation/ThingsGateway.Foundation/Utils/AsyncAndSyncDisposableObject.cs b/src/Foundation/ThingsGateway.Foundation/Utils/AsyncAndSyncDisposableObject.cs new file mode 100644 index 000000000..9516d7d58 --- /dev/null +++ b/src/Foundation/ThingsGateway.Foundation/Utils/AsyncAndSyncDisposableObject.cs @@ -0,0 +1,109 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://touchsocket.net/ +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ + +using System.Runtime.CompilerServices; + +namespace ThingsGateway.Foundation; + +/// +/// 具有释放的对象。内部实现了,但不包括析构函数相关。 +/// +public abstract partial class AsyncAndSyncDisposableObject : + IDisposableObject, + IAsyncDisposable +{ + /// + /// 判断当前对象是否已经被释放。 + /// 如果已经被释放,则抛出异常。 + /// + /// 当对象已经被释放时抛出此异常 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected void ThrowIfDisposed() + { + // 检查对象是否已经被释放 + if (this.m_disposedValue) + { + // 如果对象已被释放,抛出ObjectDisposedException异常 + throw new ObjectDisposedException($"The object instance with type {this.GetType().FullName} has been released"); + } + } + + private int m_count = 0; + private int m_asyncCount = 0; + /// + /// 判断是否已释放。 + /// + private volatile bool m_disposedValue; + + /// + public bool DisposedValue => this.m_disposedValue; + + /// + /// 处置资源 + /// + /// 一个值,表示是否释放托管资源 + protected virtual void Dispose(bool disposing) + { + // 标记当前对象为已处置状态 + this.m_disposedValue = true; + } + + /// + /// 释放资源。内部已经处理了 + /// + public void Dispose() + { + if (this.DisposedValue) + { + return; + } + + if (Interlocked.Increment(ref this.m_count) == 1) + { + this.Dispose(disposing: true); + } + GC.SuppressFinalize(this); + } + + /// + /// 处置资源 + /// + /// 一个值,表示是否释放托管资源 + protected virtual Task DisposeAsync(bool disposing) + { + // 标记当前对象为已处置状态 + this.m_disposedValue = true; + return Task.CompletedTask; + } + + /// + /// 释放资源。内部已经处理了 + /// + public async ValueTask DisposeAsync() + { + if (this.DisposedValue) + { + return; + } + + //if (Interlocked.Increment(ref this.m_count) == 1) + //{ + // this.Dispose(disposing: true); + //} + + if (Interlocked.Increment(ref this.m_asyncCount) == 1) + { + await this.DisposeAsync(disposing: true).ConfigureAwait(false); + } + GC.SuppressFinalize(this); + } +} \ No newline at end of file diff --git a/src/Foundation/ThingsGateway.Foundation/Utils/AsyncDisposableObject.cs b/src/Foundation/ThingsGateway.Foundation/Utils/AsyncDisposableObject.cs new file mode 100644 index 000000000..481174b06 --- /dev/null +++ b/src/Foundation/ThingsGateway.Foundation/Utils/AsyncDisposableObject.cs @@ -0,0 +1,108 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://touchsocket.net/ +// 交流QQ群:234762506 +// 感谢您的下载和使用 +//------------------------------------------------------------------------------ + +using System.Runtime.CompilerServices; + +namespace ThingsGateway.Foundation; + +/// +/// 具有释放的对象。内部实现了,但不包括析构函数相关。 +/// +public abstract partial class AsyncDisposableObject : + //IDisposableObject, + IAsyncDisposable +{ + /// + /// 判断当前对象是否已经被释放。 + /// 如果已经被释放,则抛出异常。 + /// + /// 当对象已经被释放时抛出此异常 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected void ThrowIfDisposed() + { + // 检查对象是否已经被释放 + if (this.m_disposedValue) + { + // 如果对象已被释放,抛出ObjectDisposedException异常 + throw new ObjectDisposedException($"The object instance with type {this.GetType().FullName} has been released"); + } + } + + private int m_asyncCount = 0; + /// + /// 判断是否已释放。 + /// + private volatile bool m_disposedValue; + + /// + public bool DisposedValue => this.m_disposedValue; + + ///// + ///// 处置资源 + ///// + ///// 一个值,表示是否释放托管资源 + //protected virtual void Dispose(bool disposing) + //{ + // // 标记当前对象为已处置状态 + // this.m_disposedValue = true; + //} + + ///// + ///// 释放资源。内部已经处理了 + ///// + //public void Dispose() + //{ + // if (this.DisposedValue) + // { + // return; + // } + + // if (Interlocked.Increment(ref this.m_count) == 1) + // { + // this.Dispose(disposing: true); + // } + // GC.SuppressFinalize(this); + //} + + /// + /// 处置资源 + /// + /// 一个值,表示是否释放托管资源 + protected virtual Task DisposeAsync(bool disposing) + { + // 标记当前对象为已处置状态 + this.m_disposedValue = true; + return Task.CompletedTask; + } + + /// + /// 释放资源。内部已经处理了 + /// + public async ValueTask DisposeAsync() + { + if (this.DisposedValue) + { + return; + } + + //if (Interlocked.Increment(ref this.m_count) == 1) + //{ + // this.Dispose(disposing: true); + //} + + if (Interlocked.Increment(ref this.m_asyncCount) == 1) + { + await this.DisposeAsync(disposing: true).ConfigureAwait(false); + } + GC.SuppressFinalize(this); + } +} \ No newline at end of file diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Common/AsyncReadWriteLock.cs b/src/Gateway/ThingsGateway.Gateway.Application/Common/AsyncReadWriteLock.cs index 2cc49f29c..f58c6eff1 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Common/AsyncReadWriteLock.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Common/AsyncReadWriteLock.cs @@ -54,7 +54,7 @@ public class AsyncReadWriteLock { var cancellationTokenSource = _cancellationTokenSource; _cancellationTokenSource = new(); - await cancellationTokenSource.CancelAsync().ConfigureAwait(false); // 取消读取 + await cancellationTokenSource.SafeCancelAsync().ConfigureAwait(false); // 取消读取 cancellationTokenSource.SafeDispose(); } diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Driver/Business/Cache/BusinessBaseWithCacheAlarm.cs b/src/Gateway/ThingsGateway.Gateway.Application/Driver/Business/Cache/BusinessBaseWithCacheAlarm.cs index 95ca7b2ce..c20dbb7b7 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Driver/Business/Cache/BusinessBaseWithCacheAlarm.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Driver/Business/Cache/BusinessBaseWithCacheAlarm.cs @@ -59,10 +59,10 @@ public abstract class BusinessBaseWithCacheAlarm : BusinessBaseWithCache await base.InitChannelAsync(channel, cancellationToken).ConfigureAwait(false); } - protected override void Dispose(bool disposing) + protected override Task DisposeAsync(bool disposing) { GlobalData.AlarmChangedEvent -= AlarmValueChange; - base.Dispose(disposing); + return base.DisposeAsync(disposing); } /// /// 当报警值发生变化时触发此事件处理方法。该方法内部会检查是否需要进行报警上传,如果需要,则调用 方法。 diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Driver/Business/Cache/BusinessBaseWithCacheInterval.cs b/src/Gateway/ThingsGateway.Gateway.Application/Driver/Business/Cache/BusinessBaseWithCacheInterval.cs index 82e1a2c75..d6a69db52 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Driver/Business/Cache/BusinessBaseWithCacheInterval.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Driver/Business/Cache/BusinessBaseWithCacheInterval.cs @@ -130,7 +130,7 @@ public abstract class BusinessBaseWithCacheInterval : BusinessBaseWithCache /// /// 释放资源方法 /// - protected override void Dispose(bool disposing) + protected override Task DisposeAsync(bool disposing) { // 解绑事件 GlobalData.AlarmChangedEvent -= AlarmValueChange; @@ -142,7 +142,7 @@ public abstract class BusinessBaseWithCacheInterval : BusinessBaseWithCache _memoryDevModelQueue.Clear(); _memoryVarModelQueue.Clear(); _memoryVarModelsQueue.Clear(); - base.Dispose(disposing); + return base.DisposeAsync(disposing); } /// diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Driver/Collect/CollectFoundationBase.cs b/src/Gateway/ThingsGateway.Gateway.Application/Driver/Collect/CollectFoundationBase.cs index 1819922dc..78cbc8c02 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Driver/Collect/CollectFoundationBase.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Driver/Collect/CollectFoundationBase.cs @@ -47,10 +47,11 @@ public abstract class CollectFoundationBase : CollectBase } /// - protected override void Dispose(bool disposing) + protected override async Task DisposeAsync(bool disposing) { - FoundationDevice?.Dispose(); - base.Dispose(disposing); + if (FoundationDevice != null) + await FoundationDevice.SafeDisposeAsync().ConfigureAwait(false); + await base.DisposeAsync(disposing).ConfigureAwait(false); } /// /// 开始通讯执行的方法 diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Driver/DriverBase.cs b/src/Gateway/ThingsGateway.Gateway.Application/Driver/DriverBase.cs index bc133edf5..f5856a9c7 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Driver/DriverBase.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Driver/DriverBase.cs @@ -26,11 +26,12 @@ namespace ThingsGateway.Gateway.Application; /// /// 插件基类 /// -public abstract class DriverBase : DisposableObject, IDriver +public abstract class DriverBase : AsyncDisposableObject, IDriver { /// public DriverBase() { + Localizer = App.CreateLocalizerByType(typeof(DriverBase))!; } @@ -312,38 +313,44 @@ public abstract class DriverBase : DisposableObject, IDriver protected abstract List ProtectedGetTasks(CancellationToken cancellationToken); - protected object stopLock = new(); + protected WaitLock stopLock = new(nameof(DriverBase)); /// /// 已停止任务,释放插件 /// - internal virtual void Stop() + internal virtual async Task StopAsync() { if (!DisposedValue) { - lock (stopLock) + await stopLock.WaitAsync().ConfigureAwait(false); + try { + + if (!DisposedValue) { - try - { - // 执行资源释放操作 - Dispose(); - } - catch (Exception ex) - { - // 记录 Dispose 方法执行失败的错误信息 - LogMessage?.LogError(ex, "Dispose"); - } + + // 执行资源释放操作 + await this.SafeDisposeAsync().ConfigureAwait(false); + // 记录设备线程已停止的信息 LogMessage?.LogInformation(string.Format(AppResource.DeviceTaskStop, DeviceName)); } } + catch (Exception ex) + { + // 记录 Dispose 方法执行失败的错误信息 + LogMessage?.LogError(ex, "Dispose"); + } + finally + { + stopLock.Release(); + } } } - protected override void Dispose(bool disposing) + protected override async Task DisposeAsync(bool disposing) { - base.Dispose(disposing); + await base.DisposeAsync(disposing).ConfigureAwait(false); if (TaskSchedulerLoop != null) { lock (TaskSchedulerLoop) diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Driver/IDriver.cs b/src/Gateway/ThingsGateway.Gateway.Application/Driver/IDriver.cs index 7a3ac15d8..7b5297865 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Driver/IDriver.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Driver/IDriver.cs @@ -14,7 +14,7 @@ using TouchSocket.Core; namespace ThingsGateway.Gateway.Application { - public interface IDriver : IDisposable + public interface IDriver : IAsyncDisposable { bool DisposedValue { get; } ChannelRuntime CurrentChannel { get; } diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Entity/Channel.cs b/src/Gateway/ThingsGateway.Gateway.Application/Entity/Channel.cs index 4f953f2de..802fa76bb 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Entity/Channel.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Entity/Channel.cs @@ -17,6 +17,7 @@ using TouchSocket.Core; using TouchSocket.Sockets; namespace ThingsGateway.Gateway.Application; +#pragma warning disable CS0649 /// /// 通道表 diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Entity/Device.cs b/src/Gateway/ThingsGateway.Gateway.Application/Entity/Device.cs index 10677289e..d926701a8 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Entity/Device.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Entity/Device.cs @@ -17,6 +17,7 @@ using System.ComponentModel.DataAnnotations; using ThingsGateway.NewLife.Extension; namespace ThingsGateway.Gateway.Application; +#pragma warning disable CS0649 /// /// 设备表 diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Entity/Variable.cs b/src/Gateway/ThingsGateway.Gateway.Application/Entity/Variable.cs index b101e9adb..faf4150af 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Entity/Variable.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Entity/Variable.cs @@ -16,6 +16,7 @@ using System.Collections.Concurrent; using System.ComponentModel.DataAnnotations; namespace ThingsGateway.Gateway.Application; +#pragma warning disable CS0649 /// /// 设备变量表 diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/Alarm/AlarmTask.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/Alarm/AlarmTask.cs index 72792d844..f449aa875 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/Alarm/AlarmTask.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/Alarm/AlarmTask.cs @@ -12,9 +12,10 @@ using Microsoft.Extensions.Logging; using ThingsGateway.Common.Extension; using ThingsGateway.Gateway.Application.Extensions; -using ThingsGateway.NewLife; using ThingsGateway.NewLife.Extension; +using TouchSocket.Core; + namespace ThingsGateway.Gateway.Application; /// @@ -44,7 +45,7 @@ internal sealed class AlarmTask : IDisposable public void Dispose() { StopTask(); - scheduledTask?.TryDispose(); + scheduledTask?.SafeDispose(); } #region 核心实现 diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/GatewayMonitor/ChannelManage/ChannelThreadManage.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/GatewayMonitor/ChannelManage/ChannelThreadManage.cs index 77e6a2a1e..0ddde6e24 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/GatewayMonitor/ChannelManage/ChannelThreadManage.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/GatewayMonitor/ChannelManage/ChannelThreadManage.cs @@ -43,7 +43,7 @@ internal sealed class ChannelThreadManage : IChannelThreadManage { if (!DeviceThreadManages.TryRemove(channelId, out var deviceThreadManage)) return; - await deviceThreadManage.DisposeAsync().ConfigureAwait(false); + await deviceThreadManage.SafeDisposeAsync().ConfigureAwait(false); } catch (Exception ex) { diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/GatewayMonitor/DeviceManage/DeviceThreadManage.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/GatewayMonitor/DeviceManage/DeviceThreadManage.cs index 84c33fb7e..8cabd611f 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/GatewayMonitor/DeviceManage/DeviceThreadManage.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/GatewayMonitor/DeviceManage/DeviceThreadManage.cs @@ -326,7 +326,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage { try { - await oldCts.CancelAsync().ConfigureAwait(false); + await oldCts.SafeCancelAsync().ConfigureAwait(false); oldCts.SafeDispose(); } catch @@ -340,7 +340,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage CancellationTokenSources.TryAdd(driver.DeviceId, cts); _ = Task.Factory.StartNew((state) => DriverStart(state, token), driver, token, TaskCreationOptions.None, TaskScheduler.Default); - }).ConfigureAwait(false); + }, App.HostApplicationLifetime.ApplicationStopping).ConfigureAwait(false); } catch (Exception ex) { @@ -393,45 +393,48 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage try { ConcurrentList saveVariableRuntimes = new(); - deviceIds.ParallelForEach((deviceId) => - { - var now = DateTime.Now; - // 查找具有指定设备ID的驱动程序对象 - if (Drivers.TryRemove(deviceId, out var driver)) - { - driver.CurrentDevice.SetDeviceStatus(now, false, "Communication connection has been removed"); - if (IsCollectChannel == true) - { - foreach (var a in driver.IdVariableRuntimes) - { - a.Value.SetValue(a.Value.Value, now, false); - a.Value.SetErrorMessage("Communication connection has been removed"); - if (a.Value.SaveValue && !a.Value.DynamicVariable) - { - saveVariableRuntimes.Add(a.Value); - } - } + await deviceIds.ParallelForEachAsync(async (deviceId, cancellationToken) => + { + var now = DateTime.Now; + // 查找具有指定设备ID的驱动程序对象 + if (Drivers.TryRemove(deviceId, out var driver)) + { + driver.CurrentDevice.SetDeviceStatus(now, false, "Communication connection has been removed"); + if (IsCollectChannel == true) + { + foreach (var a in driver.IdVariableRuntimes) + { + a.Value.SetValue(a.Value.Value, now, false); + a.Value.SetErrorMessage("Communication connection has been removed"); + if (a.Value.SaveValue && !a.Value.DynamicVariable) + { + saveVariableRuntimes.Add(a.Value); + } + } - } + } - } + } - // 取消驱动程序的操作 - if (CancellationTokenSources.TryRemove(deviceId, out var token)) - { - if (token != null) - { - driver.Stop(); - token.Cancel(); - token.Dispose(); - } - } + // 取消驱动程序的操作 + if (CancellationTokenSources.TryRemove(deviceId, out var token)) + { + if (token != null) + { + await token.SafeCancelAsync().ConfigureAwait(false); + token.SafeDispose(); + if (driver != null) + { + await driver.StopAsync().ConfigureAwait(false); + } + } + } - if (DriverTasks.TryRemove(deviceId, out var task)) - { - task.Stop(); - } - }); + if (DriverTasks.TryRemove(deviceId, out var task)) + { + task.Stop(); + } + }).ConfigureAwait(false); await Task.Delay(100).ConfigureAwait(false); @@ -796,7 +799,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage Disposed = true; try { - await CancellationTokenSource.CancelAsync().ConfigureAwait(false); + await CancellationTokenSource.SafeCancelAsync().ConfigureAwait(false); CancellationTokenSource.SafeDispose(); GlobalData.DeviceStatusChangeEvent -= GlobalData_DeviceStatusChangeEvent; await NewDeviceLock.WaitAsync().ConfigureAwait(false); diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/GatewayMonitor/GatewayMonitorHostedService.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/GatewayMonitor/GatewayMonitorHostedService.cs index 5f17731fd..d8f57d57c 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/GatewayMonitor/GatewayMonitorHostedService.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/GatewayMonitor/GatewayMonitorHostedService.cs @@ -78,7 +78,7 @@ internal sealed class GatewayMonitorHostedService : BackgroundService, IGatewayM public override async Task StopAsync(CancellationToken cancellationToken) { - await ChannelThreadManage.DisposeAsync().ConfigureAwait(false); + await ChannelThreadManage.SafeDisposeAsync().ConfigureAwait(false); await base.StopAsync(cancellationToken).ConfigureAwait(false); } } diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/Management/Redundant/RedundancyTask.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/Management/Redundant/RedundancyTask.cs index 0d899d1d4..f57de1c2f 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/Management/Redundant/RedundancyTask.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/Management/Redundant/RedundancyTask.cs @@ -312,10 +312,10 @@ internal sealed class RedundancyTask : IRpcDriver, IAsyncDisposable { await StopTaskAsync().ConfigureAwait(false); TextLogger?.TryDispose(); - scheduledTask?.TryDispose(); + scheduledTask?.SafeDispose(); - _tcpDmtpService?.TryDispose(); - _tcpDmtpClient?.TryDispose(); + _tcpDmtpService?.SafeDispose(); + _tcpDmtpClient?.SafeDispose(); _tcpDmtpService = null; _tcpDmtpClient = null; } diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/Plugin/PluginService.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/Plugin/PluginService.cs index 2ec39f136..306943538 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/Plugin/PluginService.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/Plugin/PluginService.cs @@ -78,12 +78,12 @@ internal sealed class PluginService : IPluginService public Type GetDebugUI(string pluginName) { - using var driver = GetDriver(pluginName); + var driver = GetDriver(pluginName); return driver?.DriverDebugUIType; } public Type GetAddressUI(string pluginName) { - using var driver = GetDriver(pluginName); + var driver = GetDriver(pluginName); return driver?.DriverVariableAddressUIType; } @@ -167,7 +167,6 @@ internal sealed class PluginService : IPluginService { string cacheKey = $"{nameof(PluginService)}_{nameof(GetDriverMethodInfos)}_{CultureInfo.CurrentUICulture.Name}"; // 如果未提供驱动基类对象,则尝试根据插件名称获取驱动对象 - var dispose = driver == null; // 标记是否需要释放驱动对象 driver ??= GetDriver(pluginName); // 如果未提供驱动对象,则根据插件名称获取驱动对象 // 检查插件名称是否为空或null @@ -183,10 +182,10 @@ internal sealed class PluginService : IPluginService } // 如果未从缓存中获取到指定插件的属性信息,则尝试从驱动基类对象中获取 - return SetDriverMethodInfosCache(driver, pluginName, cacheKey, dispose); // 获取并设置属性信息缓存 + return SetDriverMethodInfosCache(driver, pluginName, cacheKey); // 获取并设置属性信息缓存 // 用于设置驱动方法信息缓存的内部方法 - List SetDriverMethodInfosCache(IDriver driver, string pluginName, string cacheKey, bool dispose) + List SetDriverMethodInfosCache(IDriver driver, string pluginName, string cacheKey) { // 获取驱动对象的方法信息,并筛选出带有 DynamicMethodAttribute 特性的方法 var dependencyPropertyWithInfos = driver.GetType().GetMethods()?.SelectMany(it => @@ -206,10 +205,6 @@ internal sealed class PluginService : IPluginService var result = dependencyPropertyWithInfos.ToList(); App.CacheService.HashAdd(cacheKey, pluginName, result); - // 如果是通过方法内部创建的驱动对象,则在方法执行完成后释放该驱动对象 - if (dispose) - driver.SafeDispose(); - // 返回获取到的属性信息字典 return result; } @@ -228,7 +223,6 @@ internal sealed class PluginService : IPluginService { string cacheKey = $"{nameof(PluginService)}_{nameof(GetDriverPropertyTypes)}_{CultureInfo.CurrentUICulture.Name}"; - var dispose = driver == null; driver ??= GetDriver(pluginName); // 如果 driver 为 null, 获取驱动实例 // 检查插件名称是否为空或空字符串 if (!pluginName.IsNullOrEmpty()) @@ -245,17 +239,15 @@ internal sealed class PluginService : IPluginService } // 如果缓存中不存在该插件的数据,则重新获取并缓存 - return (SetCache(driver, pluginName, cacheKey, dispose), driver.DriverProperties, driver.DriverPropertyUIType); // 调用 SetCache 方法进行缓存并返回结果 + return (SetCache(driver, pluginName, cacheKey), driver.DriverProperties, driver.DriverPropertyUIType); // 调用 SetCache 方法进行缓存并返回结果 // 定义 SetCache 方法,用于设置缓存并返回 - IEnumerable SetCache(IDriver driver, string pluginName, string cacheKey, bool dispose) + IEnumerable SetCache(IDriver driver, string pluginName, string cacheKey) { var editorItems = PluginServiceUtil.GetEditorItems(driver.DriverProperties?.GetType()).ToList(); // 将结果存入缓存中,键为插件名称 App.CacheService.HashAdd(cacheKey, pluginName, editorItems); - // 如果 dispose 参数为 true,则释放 driver 对象 - if (dispose) - driver.SafeDispose(); + return editorItems; } } @@ -291,7 +283,6 @@ internal sealed class PluginService : IPluginService { string cacheKey = $"{nameof(PluginService)}_{nameof(GetVariablePropertyTypes)}_{CultureInfo.CurrentUICulture.Name}"; - var dispose = businessBase == null; businessBase ??= (BusinessBase)GetDriver(pluginName); // 如果 driver 为 null, 获取驱动实例 var data = App.CacheService.HashGetAll>(cacheKey); @@ -309,8 +300,6 @@ internal sealed class PluginService : IPluginService // 将结果存入缓存中,键为插件名称 App.CacheService.HashAdd(cacheKey, pluginName, editorItems); // 如果 dispose 参数为 true,则释放 driver 对象 - if (dispose) - businessBase.SafeDispose(); return editorItems; } } diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/RulesEngine/Node/Trigger/TimeIntervalTriggerNode.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/RulesEngine/Node/Trigger/TimeIntervalTriggerNode.cs index 9cc978dcd..2400cb0cd 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/RulesEngine/Node/Trigger/TimeIntervalTriggerNode.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/RulesEngine/Node/Trigger/TimeIntervalTriggerNode.cs @@ -47,7 +47,7 @@ public class TimeIntervalTriggerNode : TextNode, ITriggerNode, IDisposable public void Dispose() { _task?.Stop(); - _task.TryDispose(); + _task?.TryDispose(); GC.SuppressFinalize(this); } diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableService.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableService.cs index 2e38c8527..32235a84b 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableService.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableService.cs @@ -468,7 +468,7 @@ internal sealed class VariableService : BaseService, IVariableService if (deviceDicts.TryGetValue(a.Key, out var device) && channelDicts.TryGetValue(device.ChannelId, out var channel)) { var pluginKey = channel?.PluginName; - using var businessBase = (BusinessBase)GlobalData.PluginService.GetDriver(pluginKey); + var businessBase = (BusinessBase)GlobalData.PluginService.GetDriver(pluginKey); return new KeyValuePair(pluginKey, businessBase.VariablePropertys); } return new KeyValuePair(string.Empty, null); @@ -500,7 +500,7 @@ internal sealed class VariableService : BaseService, IVariableService if (deviceDicts.TryGetValue(a.Key, out var device) && channelDicts.TryGetValue(device.ChannelId, out var channel)) { var pluginKey = channel?.PluginName; - using var businessBase = (BusinessBase)GlobalData.PluginService.GetDriver(pluginKey); + var businessBase = (BusinessBase)GlobalData.PluginService.GetDriver(pluginKey); return new KeyValuePair(pluginKey, businessBase.VariablePropertys); } return new KeyValuePair(string.Empty, null); diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableServiceHelpers.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableServiceHelpers.cs index 91b3b6e13..013670c0d 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableServiceHelpers.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableServiceHelpers.cs @@ -30,7 +30,7 @@ public static class VariableServiceHelpers if (deviceDicts.TryGetValue(a.Key, out var device) && channelDicts.TryGetValue(device.ChannelId, out var channel)) { var pluginKey = channel?.PluginName; - using var businessBase = (BusinessBase)GlobalData.PluginService.GetDriver(pluginKey); + var businessBase = (BusinessBase)GlobalData.PluginService.GetDriver(pluginKey); return new KeyValuePair(pluginKey, businessBase.VariablePropertys); } return new KeyValuePair(string.Empty, null); diff --git a/src/Plugin/ThingsGateway.Foundation.Dlt645/Dlt645/Helper/PackHelper.cs b/src/Plugin/ThingsGateway.Foundation.Dlt645/Dlt645/Helper/PackHelper.cs index e110ce369..19ab92522 100644 --- a/src/Plugin/ThingsGateway.Foundation.Dlt645/Dlt645/Helper/PackHelper.cs +++ b/src/Plugin/ThingsGateway.Foundation.Dlt645/Dlt645/Helper/PackHelper.cs @@ -9,6 +9,7 @@ //------------------------------------------------------------------------------ namespace ThingsGateway.Foundation.Dlt645; +#pragma warning disable CA1851 internal static class PackHelper { diff --git a/src/Plugin/ThingsGateway.Foundation.Modbus/Helper/PackHelper.cs b/src/Plugin/ThingsGateway.Foundation.Modbus/Helper/PackHelper.cs index 085b64169..74275b313 100644 --- a/src/Plugin/ThingsGateway.Foundation.Modbus/Helper/PackHelper.cs +++ b/src/Plugin/ThingsGateway.Foundation.Modbus/Helper/PackHelper.cs @@ -11,6 +11,7 @@ using ThingsGateway.NewLife.Extension; namespace ThingsGateway.Foundation.Modbus; +#pragma warning disable CA1851 /// /// PackHelper diff --git a/src/Plugin/ThingsGateway.Foundation.Modbus/Slave/ModbusSlave.cs b/src/Plugin/ThingsGateway.Foundation.Modbus/Slave/ModbusSlave.cs index 902ef500b..935896dad 100644 --- a/src/Plugin/ThingsGateway.Foundation.Modbus/Slave/ModbusSlave.cs +++ b/src/Plugin/ThingsGateway.Foundation.Modbus/Slave/ModbusSlave.cs @@ -155,7 +155,7 @@ public class ModbusSlave : DeviceBase, IModbusAddress } /// - protected override void Dispose(bool disposing) + protected override Task DisposeAsync(bool disposing) { foreach (var item in ModbusServer01ByteBlocks) { @@ -177,7 +177,7 @@ public class ModbusSlave : DeviceBase, IModbusAddress ModbusServer02ByteBlocks.Clear(); ModbusServer03ByteBlocks.Clear(); ModbusServer04ByteBlocks.Clear(); - base.Dispose(disposing); + return base.DisposeAsync(disposing); } /// diff --git a/src/Plugin/ThingsGateway.Foundation.OpcDa/ThingsGateway.Foundation.OpcDa.csproj b/src/Plugin/ThingsGateway.Foundation.OpcDa/ThingsGateway.Foundation.OpcDa.csproj index 6a7f0820e..8bdea7eef 100644 --- a/src/Plugin/ThingsGateway.Foundation.OpcDa/ThingsGateway.Foundation.OpcDa.csproj +++ b/src/Plugin/ThingsGateway.Foundation.OpcDa/ThingsGateway.Foundation.OpcDa.csproj @@ -3,7 +3,7 @@ - net462;netstandard2.0;net6.0; + net462;netstandard2.0;net6.0;net8.0; 工业设备通讯协议-OpcDa协议 True diff --git a/src/Plugin/ThingsGateway.Foundation.OpcUa/OpcUaMaster/OpcUaMaster.cs b/src/Plugin/ThingsGateway.Foundation.OpcUa/OpcUaMaster/OpcUaMaster.cs index 355d98278..e372d5e55 100644 --- a/src/Plugin/ThingsGateway.Foundation.OpcUa/OpcUaMaster/OpcUaMaster.cs +++ b/src/Plugin/ThingsGateway.Foundation.OpcUa/OpcUaMaster/OpcUaMaster.cs @@ -28,7 +28,7 @@ public delegate void LogEventHandler(byte level, object sender, string message, /// /// OpcUaMaster /// -public class OpcUaMaster : IDisposable +public class OpcUaMaster : IDisposable, IAsyncDisposable { #region 属性,变量等 @@ -405,6 +405,18 @@ public class OpcUaMaster : IDisposable } } + /// + /// 断开连接。 + /// + public async Task DisconnectAsync() + { + await PrivateDisconnectAsync().ConfigureAwait(false); + // disconnect any existing session. + if (m_session != null) + { + m_session = null; + } + } /// public void Dispose() { @@ -412,7 +424,12 @@ public class OpcUaMaster : IDisposable _variableDicts?.Clear(); _subscriptionDicts?.Clear(); } - + public async ValueTask DisposeAsync() + { + await DisconnectAsync().ConfigureAwait(false); + _variableDicts?.Clear(); + _subscriptionDicts?.Clear(); + } /// /// 获取变量说明 /// @@ -865,7 +882,7 @@ public class OpcUaMaster : IDisposable { return; } - PrivateDisconnect(); + await PrivateDisconnectAsync().ConfigureAwait(false); if (LastServerUrl != serverUrl) { _variableDicts.Clear(); @@ -944,6 +961,29 @@ public class OpcUaMaster : IDisposable DoConnectComplete(false); } } + private async Task PrivateDisconnectAsync() + { + bool state = m_session?.Connected == true; + + if (m_reConnectHandler != null) + { + try { m_reConnectHandler.Dispose(); } catch { } + m_reConnectHandler = null; + } + if (m_session != null) + { + m_session.KeepAlive -= Session_KeepAlive; + await m_session.CloseAsync(10000).ConfigureAwait(false); + m_session.Dispose(); + m_session = null; + } + + if (state) + { + Log(2, null, "Disconnected"); + DoConnectComplete(false); + } + } #endregion 连接 @@ -1376,5 +1416,7 @@ public class OpcUaMaster : IDisposable } } + + #endregion 私有方法 } diff --git a/src/Plugin/ThingsGateway.Foundation.SiemensS7/S7/Helper/PackHelper.cs b/src/Plugin/ThingsGateway.Foundation.SiemensS7/S7/Helper/PackHelper.cs index 525b1cec1..09b2a7c05 100644 --- a/src/Plugin/ThingsGateway.Foundation.SiemensS7/S7/Helper/PackHelper.cs +++ b/src/Plugin/ThingsGateway.Foundation.SiemensS7/S7/Helper/PackHelper.cs @@ -9,6 +9,7 @@ //------------------------------------------------------------------------------ namespace ThingsGateway.Foundation.SiemensS7; +#pragma warning disable CA1851 internal static class PackHelper { diff --git a/src/Plugin/ThingsGateway.Foundation.SiemensS7/S7/SiemensS7Master.cs b/src/Plugin/ThingsGateway.Foundation.SiemensS7/S7/SiemensS7Master.cs index dc05260b4..f3ee8760f 100644 --- a/src/Plugin/ThingsGateway.Foundation.SiemensS7/S7/SiemensS7Master.cs +++ b/src/Plugin/ThingsGateway.Foundation.SiemensS7/S7/SiemensS7Master.cs @@ -417,13 +417,15 @@ public partial class SiemensS7Master : DeviceBase //本地TSAP if (SiemensS7Type == SiemensTypeEnum.S200 || SiemensS7Type == SiemensTypeEnum.S200Smart) { - ISO_CR[13] = BitConverter.GetBytes(LocalTSAP)[1]; - ISO_CR[14] = BitConverter.GetBytes(LocalTSAP)[0]; + var data = s7BitConverter.GetBytes(LocalTSAP); + ISO_CR[13] = data[0]; + ISO_CR[14] = data[1]; } else { - ISO_CR[16] = BitConverter.GetBytes(LocalTSAP)[1]; - ISO_CR[17] = BitConverter.GetBytes(LocalTSAP)[0]; + var data = s7BitConverter.GetBytes(LocalTSAP); + ISO_CR[16] = data[0]; + ISO_CR[17] = data[1]; } } if (Rack > 0 || Slot > 0) diff --git a/src/Plugin/ThingsGateway.Plugin.DB/QuestDB/QuestDBProducer.cs b/src/Plugin/ThingsGateway.Plugin.DB/QuestDB/QuestDBProducer.cs index 50dc0c520..0d67e3fe8 100644 --- a/src/Plugin/ThingsGateway.Plugin.DB/QuestDB/QuestDBProducer.cs +++ b/src/Plugin/ThingsGateway.Plugin.DB/QuestDB/QuestDBProducer.cs @@ -49,10 +49,10 @@ public partial class QuestDBProducer : BusinessBaseWithCacheIntervalVariable, ID private SqlSugarClient _db; - protected override void Dispose(bool disposing) + protected override Task DisposeAsync(bool disposing) { _db?.TryDispose(); - base.Dispose(disposing); + return base.DisposeAsync(disposing); } protected override async Task InitChannelAsync(IChannel? channel, CancellationToken cancellationToken) diff --git a/src/Plugin/ThingsGateway.Plugin.DB/SqlDB/SqlDBProducer.cs b/src/Plugin/ThingsGateway.Plugin.DB/SqlDB/SqlDBProducer.cs index 6919ddebb..c6ae03ffd 100644 --- a/src/Plugin/ThingsGateway.Plugin.DB/SqlDB/SqlDBProducer.cs +++ b/src/Plugin/ThingsGateway.Plugin.DB/SqlDB/SqlDBProducer.cs @@ -51,10 +51,10 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariable, IDBH protected override BusinessPropertyWithCacheInterval _businessPropertyWithCacheInterval => _driverPropertys; private SqlSugarClient _db; - protected override void Dispose(bool disposing) + protected override Task DisposeAsync(bool disposing) { _db?.TryDispose(); - base.Dispose(disposing); + return base.DisposeAsync(disposing); } public async Task> GetDBHistoryValuePagesAsync(DBHistoryValuePageInput input) { diff --git a/src/Plugin/ThingsGateway.Plugin.DB/SqlHistoryAlarm/SqlHistoryAlarm.cs b/src/Plugin/ThingsGateway.Plugin.DB/SqlHistoryAlarm/SqlHistoryAlarm.cs index 337dcf941..2410d366c 100644 --- a/src/Plugin/ThingsGateway.Plugin.DB/SqlHistoryAlarm/SqlHistoryAlarm.cs +++ b/src/Plugin/ThingsGateway.Plugin.DB/SqlHistoryAlarm/SqlHistoryAlarm.cs @@ -47,10 +47,10 @@ public partial class SqlHistoryAlarm : BusinessBaseWithCacheAlarm, IDBHistoryAla /// public override bool IsConnected() => success; - protected override void Dispose(bool disposing) + protected override Task DisposeAsync(bool disposing) { _db?.TryDispose(); - base.Dispose(disposing); + return base.DisposeAsync(disposing); } protected override Task ProtectedStartAsync(CancellationToken cancellationToken) diff --git a/src/Plugin/ThingsGateway.Plugin.DB/TDengineDB/TDengineDBProducer.cs b/src/Plugin/ThingsGateway.Plugin.DB/TDengineDB/TDengineDBProducer.cs index 38cc024de..4c395a201 100644 --- a/src/Plugin/ThingsGateway.Plugin.DB/TDengineDB/TDengineDBProducer.cs +++ b/src/Plugin/ThingsGateway.Plugin.DB/TDengineDB/TDengineDBProducer.cs @@ -53,10 +53,10 @@ public partial class TDengineDBProducer : BusinessBaseWithCacheIntervalVariable, protected override BusinessPropertyWithCacheInterval _businessPropertyWithCacheInterval => _driverPropertys; - protected override void Dispose(bool disposing) + protected override Task DisposeAsync(bool disposing) { _db?.TryDispose(); - base.Dispose(disposing); + return base.DisposeAsync(disposing); } protected override async Task InitChannelAsync(IChannel? channel, CancellationToken cancellationToken) diff --git a/src/Plugin/ThingsGateway.Plugin.Dlt645/Dlt645_2007/Dlt645_2007Master.cs b/src/Plugin/ThingsGateway.Plugin.Dlt645/Dlt645_2007/Dlt645_2007Master.cs index 52a627eb2..2825c415b 100644 --- a/src/Plugin/ThingsGateway.Plugin.Dlt645/Dlt645_2007/Dlt645_2007Master.cs +++ b/src/Plugin/ThingsGateway.Plugin.Dlt645/Dlt645_2007/Dlt645_2007Master.cs @@ -10,8 +10,6 @@ using ThingsGateway.Gateway.Application; -using TouchSocket.Core; - namespace ThingsGateway.Plugin.Dlt645; /// @@ -52,7 +50,8 @@ public class Dlt645_2007Master : CollectFoundationBase var plc = _plc; _plc = new(); - plc?.SafeDispose(); + if (plc != null) + await plc.SafeDisposeAsync().ConfigureAwait(false); //载入配置 _plc.DtuId = _driverPropertys.DtuId; diff --git a/src/Plugin/ThingsGateway.Plugin.Kafka/Kafka/KafkaProducer.cs b/src/Plugin/ThingsGateway.Plugin.Kafka/Kafka/KafkaProducer.cs index 15441c0db..9b90bc4c7 100644 --- a/src/Plugin/ThingsGateway.Plugin.Kafka/Kafka/KafkaProducer.cs +++ b/src/Plugin/ThingsGateway.Plugin.Kafka/Kafka/KafkaProducer.cs @@ -73,7 +73,7 @@ public partial class KafkaProducer : BusinessBaseWithCacheIntervalScriptAll } /// - protected override void Dispose(bool disposing) + protected override Task DisposeAsync(bool disposing) { try { @@ -83,7 +83,7 @@ public partial class KafkaProducer : BusinessBaseWithCacheIntervalScriptAll { } _producer?.SafeDispose(); - base.Dispose(disposing); + return base.DisposeAsync(disposing); } protected override Task ProtectedExecuteAsync(object? state, CancellationToken cancellationToken) diff --git a/src/Plugin/ThingsGateway.Plugin.Modbus/ModbusMaster/ModbusMaster.cs b/src/Plugin/ThingsGateway.Plugin.Modbus/ModbusMaster/ModbusMaster.cs index b917efdf8..b4325638a 100644 --- a/src/Plugin/ThingsGateway.Plugin.Modbus/ModbusMaster/ModbusMaster.cs +++ b/src/Plugin/ThingsGateway.Plugin.Modbus/ModbusMaster/ModbusMaster.cs @@ -11,8 +11,6 @@ using ThingsGateway.Debug; using ThingsGateway.Gateway.Application; -using TouchSocket.Core; - namespace ThingsGateway.Plugin.Modbus; /// @@ -65,7 +63,8 @@ public class ModbusMaster : CollectFoundationBase ArgumentNullException.ThrowIfNull(channel); var plc = _plc; _plc = new(); - plc?.SafeDispose(); + if (plc != null) + await plc.SafeDisposeAsync().ConfigureAwait(false); //载入配置 _plc.DataFormat = _driverPropertys.DataFormat; _plc.DtuId = _driverPropertys.DtuId; diff --git a/src/Plugin/ThingsGateway.Plugin.Modbus/ModbusSlave/ModbusSlave.cs b/src/Plugin/ThingsGateway.Plugin.Modbus/ModbusSlave/ModbusSlave.cs index 9950307ed..8e72f8394 100644 --- a/src/Plugin/ThingsGateway.Plugin.Modbus/ModbusSlave/ModbusSlave.cs +++ b/src/Plugin/ThingsGateway.Plugin.Modbus/ModbusSlave/ModbusSlave.cs @@ -92,7 +92,8 @@ public class ModbusSlave : BusinessBase ArgumentNullException.ThrowIfNull(channel); var plc = _plc; _plc = new(); - plc?.SafeDispose(); + if (plc != null) + await plc.SafeDisposeAsync().ConfigureAwait(false); //载入配置 _plc.DataFormat = _driverPropertys.DataFormat; _plc.IsStringReverseByteWord = _driverPropertys.IsStringReverseByteWord; @@ -137,13 +138,14 @@ public class ModbusSlave : BusinessBase ); } /// - protected override void Dispose(bool disposing) + protected override async Task DisposeAsync(bool disposing) { ModbusVariables?.Clear(); ModbusVariableQueue?.Clear(); GlobalData.VariableValueChangeEvent -= VariableValueChange; - _plc?.SafeDispose(); - base.Dispose(disposing); + if (_plc != null) + await _plc.SafeDisposeAsync().ConfigureAwait(false); + await base.DisposeAsync(disposing).ConfigureAwait(false); } protected override async Task ProtectedExecuteAsync(object? state, CancellationToken cancellationToken) diff --git a/src/Plugin/ThingsGateway.Plugin.Mqtt/MqttClient/MqttClient.cs b/src/Plugin/ThingsGateway.Plugin.Mqtt/MqttClient/MqttClient.cs index 923a3a872..7405ef010 100644 --- a/src/Plugin/ThingsGateway.Plugin.Mqtt/MqttClient/MqttClient.cs +++ b/src/Plugin/ThingsGateway.Plugin.Mqtt/MqttClient/MqttClient.cs @@ -150,18 +150,17 @@ public partial class MqttClient : BusinessBaseWithCacheIntervalScriptAll } /// - protected override void Dispose(bool disposing) + protected override async Task DisposeAsync(bool disposing) { - base.Dispose(disposing); - _ = Task.Run(async () => + await base.DisposeAsync(disposing).ConfigureAwait(false); + + if (_mqttClient != null) { - if (_mqttClient != null) - { - await _mqttClient.DisconnectAsync().ConfigureAwait(false); - _mqttClient.SafeDispose(); - } - _mqttClient = null; - }); + await _mqttClient.DisconnectAsync().ConfigureAwait(false); + _mqttClient.SafeDispose(); + } + _mqttClient = null; + } protected override async Task ProtectedStartAsync(CancellationToken cancellationToken) diff --git a/src/Plugin/ThingsGateway.Plugin.Mqtt/MqttClient/MqttClient.other.cs b/src/Plugin/ThingsGateway.Plugin.Mqtt/MqttClient/MqttClient.other.cs index c2ef06cbf..2c39d6784 100644 --- a/src/Plugin/ThingsGateway.Plugin.Mqtt/MqttClient/MqttClient.other.cs +++ b/src/Plugin/ThingsGateway.Plugin.Mqtt/MqttClient/MqttClient.other.cs @@ -505,8 +505,8 @@ public partial class MqttClient : BusinessBaseWithCacheIntervalScriptAll private async ValueTask TryMqttClientAsync(CancellationToken cancellationToken) { - if(DisposedValue|| _mqttClient==null) return new OperResult("MqttClient is disposed"); - + if (DisposedValue || _mqttClient == null) return new OperResult("MqttClient is disposed"); + if (_mqttClient?.IsConnected == true) return OperResult.Success; return await Client().ConfigureAwait(false); diff --git a/src/Plugin/ThingsGateway.Plugin.Mqtt/MqttCollect/MqttCollect.cs b/src/Plugin/ThingsGateway.Plugin.Mqtt/MqttCollect/MqttCollect.cs index 2b260fba6..094ed4f0c 100644 --- a/src/Plugin/ThingsGateway.Plugin.Mqtt/MqttCollect/MqttCollect.cs +++ b/src/Plugin/ThingsGateway.Plugin.Mqtt/MqttCollect/MqttCollect.cs @@ -38,11 +38,16 @@ public partial class MqttCollect : CollectBase } /// - protected override void Dispose(bool disposing) + protected override async Task DisposeAsync(bool disposing) { - _mqttClient?.SafeDispose(); + await base.DisposeAsync(disposing).ConfigureAwait(false); + if (_mqttClient != null) + { + await _mqttClient.DisconnectAsync().ConfigureAwait(false); + _mqttClient.SafeDispose(); + } + _mqttClient = null; TopicItemDict?.Clear(); - base.Dispose(disposing); } public override string GetAddressDescription() diff --git a/src/Plugin/ThingsGateway.Plugin.Mqtt/MqttServer/MqttServer.cs b/src/Plugin/ThingsGateway.Plugin.Mqtt/MqttServer/MqttServer.cs index f4ee9e82f..e9556f718 100644 --- a/src/Plugin/ThingsGateway.Plugin.Mqtt/MqttServer/MqttServer.cs +++ b/src/Plugin/ThingsGateway.Plugin.Mqtt/MqttServer/MqttServer.cs @@ -66,9 +66,9 @@ public partial class MqttServer : BusinessBaseWithCacheIntervalScriptAll } /// - protected override void Dispose(bool disposing) + protected override async Task DisposeAsync(bool disposing) { - base.Dispose(disposing); + await base.DisposeAsync(disposing).ConfigureAwait(false); if (_mqttServer != null) { _mqttServer.ClientDisconnectedAsync -= MqttServer_ClientDisconnectedAsync; diff --git a/src/Plugin/ThingsGateway.Plugin.OpcDa/OpcDaMaster/OpcDaMaster.cs b/src/Plugin/ThingsGateway.Plugin.OpcDa/OpcDaMaster/OpcDaMaster.cs index 750a7714b..b6f90b5ae 100644 --- a/src/Plugin/ThingsGateway.Plugin.OpcDa/OpcDaMaster/OpcDaMaster.cs +++ b/src/Plugin/ThingsGateway.Plugin.OpcDa/OpcDaMaster/OpcDaMaster.cs @@ -84,14 +84,14 @@ public class OpcDaMaster : CollectBase /// /// - protected override void Dispose(bool disposing) + protected override Task DisposeAsync(bool disposing) { if (_plc != null) _plc.DataChangedHandler -= DataChangedHandler; _plc?.SafeDispose(); VariableAddresDicts?.Clear(); - base.Dispose(disposing); + return base.DisposeAsync(disposing); } public override string GetAddressDescription() diff --git a/src/Plugin/ThingsGateway.Plugin.OpcUa/OpcUaMaster/OpcUaMaster.cs b/src/Plugin/ThingsGateway.Plugin.OpcUa/OpcUaMaster/OpcUaMaster.cs index d5b606af4..7a617f979 100644 --- a/src/Plugin/ThingsGateway.Plugin.OpcUa/OpcUaMaster/OpcUaMaster.cs +++ b/src/Plugin/ThingsGateway.Plugin.OpcUa/OpcUaMaster/OpcUaMaster.cs @@ -70,7 +70,7 @@ public class OpcUaMaster : CollectBase { plc.DataChangedHandler -= DataChangedHandler; plc.LogEvent -= _plc_LogEvent; - plc.SafeDispose(); + await plc.SafeDisposeAsync().ConfigureAwait(false); } _plc.LogEvent += _plc_LogEvent; @@ -88,19 +88,18 @@ public class OpcUaMaster : CollectBase } /// - protected override void Dispose(bool disposing) + protected override async Task DisposeAsync(bool disposing) { if (_plc != null) { _plc.DataChangedHandler -= DataChangedHandler; _plc.LogEvent -= _plc_LogEvent; - _plc.Disconnect(); - _plc.SafeDispose(); + await _plc.DisposeAsync().ConfigureAwait(false); } VariableAddresDicts?.Clear(); - base.Dispose(disposing); + await base.DisposeAsync(disposing).ConfigureAwait(false); } public override string GetAddressDescription() @@ -301,7 +300,8 @@ public class OpcUaMaster : CollectBase { try { - _plc?.Disconnect(); + if (_plc != null) + await _plc.DisconnectAsync().ConfigureAwait(false); await base.AfterVariablesChangedAsync(cancellationToken).ConfigureAwait(false); } finally diff --git a/src/Plugin/ThingsGateway.Plugin.OpcUa/OpcUaServer/OpcUaServer.cs b/src/Plugin/ThingsGateway.Plugin.OpcUa/OpcUaServer/OpcUaServer.cs index 870d89345..02e8481bf 100644 --- a/src/Plugin/ThingsGateway.Plugin.OpcUa/OpcUaServer/OpcUaServer.cs +++ b/src/Plugin/ThingsGateway.Plugin.OpcUa/OpcUaServer/OpcUaServer.cs @@ -175,13 +175,13 @@ public partial class OpcUaServer : BusinessBase } /// - protected override void Dispose(bool disposing) + protected override Task DisposeAsync(bool disposing) { GlobalData.VariableValueChangeEvent -= VariableValueChange; UaDispose(); CollectVariableRuntimes?.Clear(); IdVariableRuntimes?.Clear(); - base.Dispose(disposing); + return base.DisposeAsync(disposing); } protected override async Task ProtectedStartAsync(CancellationToken cancellationToken) diff --git a/src/Plugin/ThingsGateway.Plugin.OpcUa/Pages/OpcUaMaster.razor.cs b/src/Plugin/ThingsGateway.Plugin.OpcUa/Pages/OpcUaMaster.razor.cs index c7305a0e7..0e1056506 100644 --- a/src/Plugin/ThingsGateway.Plugin.OpcUa/Pages/OpcUaMaster.razor.cs +++ b/src/Plugin/ThingsGateway.Plugin.OpcUa/Pages/OpcUaMaster.razor.cs @@ -119,7 +119,7 @@ public partial class OpcUaMaster : IDisposable { try { - _plc.Disconnect(); + await _plc.DisconnectAsync().ConfigureAwait(false); LogPath = _plc?.GetHashCode().ToLong().GetDebugLogPath(); await GetOpc().ConnectAsync(CancellationToken.None); } diff --git a/src/Plugin/ThingsGateway.Plugin.RabbitMQ/RabbitMQ/RabbitMQProducer.cs b/src/Plugin/ThingsGateway.Plugin.RabbitMQ/RabbitMQ/RabbitMQProducer.cs index 61b509faa..c50cfc45e 100644 --- a/src/Plugin/ThingsGateway.Plugin.RabbitMQ/RabbitMQ/RabbitMQProducer.cs +++ b/src/Plugin/ThingsGateway.Plugin.RabbitMQ/RabbitMQ/RabbitMQProducer.cs @@ -12,8 +12,6 @@ using RabbitMQ.Client; using ThingsGateway.Foundation; -using TouchSocket.Core; - namespace ThingsGateway.Plugin.RabbitMQ; /// @@ -53,11 +51,13 @@ public partial class RabbitMQProducer : BusinessBaseWithCacheIntervalScriptAll } /// - protected override void Dispose(bool disposing) + protected override async Task DisposeAsync(bool disposing) { - _channel?.SafeDispose(); - _connection?.SafeDispose(); - base.Dispose(disposing); + if (_channel != null) + await _channel.SafeDisposeAsync().ConfigureAwait(false); + if (_connection != null) + await _connection.SafeDisposeAsync().ConfigureAwait(false); + await base.DisposeAsync(disposing).ConfigureAwait(false); } protected override async Task ProtectedExecuteAsync(object? state, CancellationToken cancellationToken) diff --git a/src/Plugin/ThingsGateway.Plugin.SiemensS7/SiemensS7Master/SiemensS7Master.cs b/src/Plugin/ThingsGateway.Plugin.SiemensS7/SiemensS7Master/SiemensS7Master.cs index 176fa2bdb..c487527a9 100644 --- a/src/Plugin/ThingsGateway.Plugin.SiemensS7/SiemensS7Master/SiemensS7Master.cs +++ b/src/Plugin/ThingsGateway.Plugin.SiemensS7/SiemensS7Master/SiemensS7Master.cs @@ -60,7 +60,8 @@ public class SiemensS7Master : CollectFoundationBase var plc = _plc; _plc = new(); - plc?.SafeDispose(); + if (plc != null) + await plc.SafeDisposeAsync().ConfigureAwait(false); //载入配置 _plc.DataFormat = _driverPropertys.DataFormat;