Revert "build: 10.9.42"

This reverts commit 2cafe745b9.
This commit is contained in:
Diego
2025-07-18 14:41:19 +08:00
parent 2cafe745b9
commit 143b751213
30 changed files with 150 additions and 188 deletions

View File

@@ -1,11 +1,11 @@
<Project>
<PropertyGroup>
<PluginVersion>10.9.42</PluginVersion>
<ProPluginVersion>10.9.42</ProPluginVersion>
<DefaultVersion>10.9.42</DefaultVersion>
<AuthenticationVersion>2.9.19</AuthenticationVersion>
<SourceGeneratorVersion>10.9.19</SourceGeneratorVersion>
<PluginVersion>10.9.41</PluginVersion>
<ProPluginVersion>10.9.41</ProPluginVersion>
<DefaultVersion>10.9.41</DefaultVersion>
<AuthenticationVersion>2.9.18</AuthenticationVersion>
<SourceGeneratorVersion>10.9.18</SourceGeneratorVersion>
<NET8Version>8.0.18</NET8Version>
<NET9Version>9.0.7</NET9Version>
<SatelliteResourceLanguages>zh-Hans;en-US</SatelliteResourceLanguages>

View File

@@ -350,9 +350,6 @@ public abstract class DeviceBase : DisposableObject, IDevice
if (SendDelayTime != 0)
await Task.Delay(SendDelayTime, token).ConfigureAwait(false);
if (token.IsCancellationRequested)
return new OperResult(new OperationCanceledException());
if (channel is IDtuUdpSessionChannel udpSession)
{
await udpSession.SendAsync(endPoint, sendMessage).ConfigureAwait(false);
@@ -560,9 +557,6 @@ public abstract class DeviceBase : DisposableObject, IDevice
if (clientChannel.ReadOnlyDataHandlingAdapter != null)
clientChannel.ReadOnlyDataHandlingAdapter.Logger = Logger;
if (cancellationToken.IsCancellationRequested)
return new MessageBase(new OperationCanceledException());
waitData.SetCancellationToken(cancellationToken);
Channel.ChannelReceivedWaitDict.TryAdd(sign, ChannelReceived);
@@ -572,14 +566,6 @@ public abstract class DeviceBase : DisposableObject, IDevice
await waitData.WaitAsync(timeout).ConfigureAwait(false);
if (cancellationToken.IsCancellationRequested)
{
if (!this.DisposedValue)
{
await Task.Delay(timeout, CancellationToken.None).ConfigureAwait(false);
}
}
var result = waitData.Check();
if (result.IsSuccess)
{

View File

@@ -16,18 +16,17 @@ public class AsyncReadWriteLock
{
private AsyncAutoResetEvent _readerLock = new AsyncAutoResetEvent(false); // 控制读计数
private long _writerCount = 0; // 当前活跃的写线程数
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
/// <summary>
/// 获取读锁,支持多个线程并发读取,但写入时会阻止所有读取。
/// </summary>
public async Task<CancellationToken> ReaderLockAsync(CancellationToken cancellationToken)
public async Task ReaderLockAsync(CancellationToken cancellationToken)
{
if (Interlocked.Read(ref _writerCount) > 0)
{
// 第一个读者需要获取写入锁,防止写操作
await _readerLock.WaitOneAsync(cancellationToken).ConfigureAwait(false);
}
return _cancellationTokenSource.Token;
}
/// <summary>
@@ -35,14 +34,7 @@ public class AsyncReadWriteLock
/// </summary>
public IDisposable WriterLock()
{
if (Interlocked.Increment(ref _writerCount) == 1)
{
var cancellationTokenSource = _cancellationTokenSource;
_cancellationTokenSource = new();
cancellationTokenSource.Cancel();//取消读取
cancellationTokenSource.SafeDispose();
}
Interlocked.Increment(ref _writerCount);
return new Writer(this);
}

View File

@@ -148,9 +148,9 @@ public class ControlController : ControllerBase
/// </summary>
[HttpPost("batchSaveChannel")]
[DisplayName("保存通道")]
public Task<bool> BatchSaveChannelAsync([FromBody] List<ChannelInput> channels, ItemChangedType type)
public Task<bool> BatchSaveChannelAsync([FromBody] List<ChannelInput> channels, ItemChangedType type, bool restart)
{
return GlobalData.ChannelRuntimeService.BatchSaveChannelAsync(channels.AdaptListChannel(), type);
return GlobalData.ChannelRuntimeService.BatchSaveChannelAsync(channels.AdaptListChannel(), type, restart);
}
/// <summary>
@@ -158,9 +158,9 @@ public class ControlController : ControllerBase
/// </summary>
[HttpPost("batchSaveDevice")]
[DisplayName("保存设备")]
public Task<bool> BatchSaveDeviceAsync([FromBody] List<DeviceInput> devices, ItemChangedType type)
public Task<bool> BatchSaveDeviceAsync([FromBody] List<DeviceInput> devices, ItemChangedType type, bool restart)
{
return GlobalData.DeviceRuntimeService.BatchSaveDeviceAsync(devices.AdaptListDevice(), type);
return GlobalData.DeviceRuntimeService.BatchSaveDeviceAsync(devices.AdaptListDevice(), type, restart);
}
/// <summary>
@@ -178,10 +178,10 @@ public class ControlController : ControllerBase
/// </summary>
[HttpPost("deleteChannel")]
[DisplayName("删除通道")]
public Task<bool> DeleteChannelAsync([FromBody] List<long> ids)
public Task<bool> DeleteChannelAsync([FromBody] List<long> ids, bool restart)
{
if (ids == null || ids.Count == 0) ids = GlobalData.IdChannels.Keys.ToList();
return GlobalData.ChannelRuntimeService.DeleteChannelAsync(ids, default);
return GlobalData.ChannelRuntimeService.DeleteChannelAsync(ids, restart, default);
}
@@ -190,10 +190,10 @@ public class ControlController : ControllerBase
/// </summary>
[HttpPost("deleteDevice")]
[DisplayName("删除设备")]
public Task<bool> DeleteDeviceAsync([FromBody] List<long> ids)
public Task<bool> DeleteDeviceAsync([FromBody] List<long> ids, bool restart)
{
if (ids == null || ids.Count == 0) ids = GlobalData.IdDevices.Keys.ToList();
return GlobalData.DeviceRuntimeService.DeleteDeviceAsync(ids, default);
return GlobalData.DeviceRuntimeService.DeleteDeviceAsync(ids, restart, default);
}
/// <summary>

View File

@@ -344,25 +344,18 @@ public abstract class CollectBase : DriverBase, IRpcDriver
{
if (state is not VariableSourceRead variableSourceRead) return;
if (Pause) return;
if (cancellationToken.IsCancellationRequested) return;
if (Pause)
return;
if (cancellationToken.IsCancellationRequested)
return;
var readErrorCount = 0;
var readToken = await ReadWriteLock.ReaderLockAsync(cancellationToken).ConfigureAwait(false);
if (readToken.IsCancellationRequested)
{
await ReadVariableSource(state, cancellationToken).ConfigureAwait(false);
return;
}
using var allTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, readToken);
var allToken = allTokenSource.Token;
await ReadWriteLock.ReaderLockAsync(cancellationToken).ConfigureAwait(false);
//if (LogMessage?.LogLevel <= TouchSocket.Core.LogLevel.Trace)
// LogMessage?.Trace(string.Format("{0} - Collecting [{1} - {2}]", DeviceName, variableSourceRead?.RegisterAddress, variableSourceRead?.Length));
var readResult = await ReadSourceAsync(variableSourceRead, allToken).ConfigureAwait(false);
var readResult = await ReadSourceAsync(variableSourceRead, cancellationToken).ConfigureAwait(false);
// 读取失败时重试一定次数
while (!readResult.IsSuccess && readErrorCount < CollectProperties.RetryCount)
@@ -372,12 +365,6 @@ public abstract class CollectBase : DriverBase, IRpcDriver
if (cancellationToken.IsCancellationRequested)
return;
if (readToken.IsCancellationRequested)
{
await ReadVariableSource(state, cancellationToken).ConfigureAwait(false);
return;
}
readErrorCount++;
if (LogMessage?.LogLevel <= TouchSocket.Core.LogLevel.Trace)
LogMessage?.Trace(string.Format("{0} - Collection [{1} - {2}] failed - {3}", DeviceName, variableSourceRead?.RegisterAddress, variableSourceRead?.Length, readResult.ErrorMessage));
@@ -400,12 +387,6 @@ public abstract class CollectBase : DriverBase, IRpcDriver
if (cancellationToken.IsCancellationRequested)
return;
if (readToken.IsCancellationRequested)
{
await ReadVariableSource(state, cancellationToken).ConfigureAwait(false);
return;
}
// 读取失败时记录日志并增加失败计数器,更新错误信息并清除变量状态
if (variableSourceRead.LastErrorMessage != readResult.ErrorMessage)
{

View File

@@ -25,12 +25,7 @@ public class RpcLog : PrimaryIdEntity
[SugarColumn(ColumnDescription = "日志时间", IsNullable = false)]
[AutoGenerateColumn(Visible = true, DefaultSort = true, Sortable = true, DefaultSortOrder = SortOrder.Desc)]
public DateTime LogTime { get; set; }
/// <summary>
/// 执行时间
/// </summary>
[SugarColumn(ColumnDescription = "执行时间", IsNullable = true)]
[AutoGenerateColumn(Visible = true, DefaultSort = true, Sortable = true, DefaultSortOrder = SortOrder.Desc)]
public int ExecutionTime { get; set; }
/// <summary>
/// 操作源
///</summary>

View File

@@ -404,7 +404,6 @@
"OperateMethod": "RPCMethod",
"OperateObject": "OperationObject",
"OperateSource": "OperationSource",
"ExecutionTime": "ExecutionTime",
"ParamJson": "RequestParameters",
"ResultJson": "ReturnResults"
},

View File

@@ -405,7 +405,6 @@
"OperateMethod": "RPC方法",
"OperateObject": "操作对象",
"OperateSource": "操作源",
"ExecutionTime": "执行时间",
"ParamJson": "请求参数",
"ResultJson": "返回结果"
},

View File

@@ -26,7 +26,7 @@ public class ChannelRuntimeService : IChannelRuntimeService
}
private WaitLock WaitLock { get; set; } = new WaitLock();
public async Task<bool> CopyAsync(List<Channel> models, Dictionary<Device, List<Variable>> devices, CancellationToken cancellationToken)
public async Task<bool> CopyAsync(List<Channel> models, Dictionary<Device, List<Variable>> devices, bool restart, CancellationToken cancellationToken)
{
try
{
@@ -43,7 +43,7 @@ public class ChannelRuntimeService : IChannelRuntimeService
await RuntimeServiceHelper.InitAsync(newChannelRuntimes, newDeviceRuntimes, _logger).ConfigureAwait(false);
//根据条件重启通道线程
//if (restart)
if (restart)
{
await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false);
@@ -59,7 +59,7 @@ public class ChannelRuntimeService : IChannelRuntimeService
}
}
public async Task<bool> InsertAsync(List<Channel> models, List<Device> devices, List<Variable> variables, CancellationToken cancellationToken)
public async Task<bool> InsertAsync(List<Channel> models, List<Device> devices, List<Variable> variables, bool restart, CancellationToken cancellationToken)
{
try
{
@@ -76,7 +76,7 @@ public class ChannelRuntimeService : IChannelRuntimeService
await RuntimeServiceHelper.InitAsync(newChannelRuntimes, newDeviceRuntimes, _logger).ConfigureAwait(false);
//根据条件重启通道线程
//if (restart)
if (restart)
{
await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false);
@@ -92,7 +92,7 @@ public class ChannelRuntimeService : IChannelRuntimeService
}
}
public async Task<bool> UpdateAsync(List<Channel> models, List<Device> devices, List<Variable> variables, CancellationToken cancellationToken)
public async Task<bool> UpdateAsync(List<Channel> models, List<Device> devices, List<Variable> variables, bool restart, CancellationToken cancellationToken)
{
try
{
@@ -109,7 +109,7 @@ public class ChannelRuntimeService : IChannelRuntimeService
await RuntimeServiceHelper.InitAsync(newChannelRuntimes, newDeviceRuntimes, _logger).ConfigureAwait(false);
//根据条件重启通道线程
//if (restart)
if (restart)
{
await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false);
@@ -125,7 +125,7 @@ public class ChannelRuntimeService : IChannelRuntimeService
}
}
public async Task<bool> BatchEditAsync(IEnumerable<Channel> models, Channel oldModel, Channel model)
public async Task<bool> BatchEditAsync(IEnumerable<Channel> models, Channel oldModel, Channel model, bool restart = true)
{
try
{
@@ -138,7 +138,7 @@ public class ChannelRuntimeService : IChannelRuntimeService
RuntimeServiceHelper.Init(newChannelRuntimes);
//根据条件重启通道线程
//if (restart)
if (restart)
{
await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false);
}
@@ -151,7 +151,7 @@ public class ChannelRuntimeService : IChannelRuntimeService
}
}
public async Task<bool> DeleteChannelAsync(IEnumerable<long> ids, CancellationToken cancellationToken)
public async Task<bool> DeleteChannelAsync(IEnumerable<long> ids, bool restart, CancellationToken cancellationToken)
{
try
{
@@ -163,7 +163,7 @@ public class ChannelRuntimeService : IChannelRuntimeService
var changedDriver = RuntimeServiceHelper.DeleteChannelRuntime(array);
//根据条件重启通道线程
//if (restart)
if (restart)
{
await GlobalData.ChannelThreadManage.RemoveChannelAsync(array).ConfigureAwait(false);
@@ -186,7 +186,7 @@ public class ChannelRuntimeService : IChannelRuntimeService
public Task<MemoryStream> ExportMemoryStream(IEnumerable<Channel> data) =>
GlobalData.ChannelService.ExportMemoryStream(data);
public async Task ImportChannelAsync(Dictionary<string, ImportPreviewOutputBase> input)
public async Task ImportChannelAsync(Dictionary<string, ImportPreviewOutputBase> input, bool restart = true)
{
try
{
@@ -199,8 +199,8 @@ public class ChannelRuntimeService : IChannelRuntimeService
RuntimeServiceHelper.Init(newChannelRuntimes);
//根据条件重启通道线程
//if (restart)
await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false);
if (restart)
await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false);
}
@@ -209,7 +209,7 @@ public class ChannelRuntimeService : IChannelRuntimeService
WaitLock.Release();
}
}
public async Task<bool> SaveChannelAsync(Channel input, ItemChangedType type)
public async Task<bool> SaveChannelAsync(Channel input, ItemChangedType type, bool restart = true)
{
try
{
@@ -222,8 +222,8 @@ public class ChannelRuntimeService : IChannelRuntimeService
RuntimeServiceHelper.Init(newChannelRuntimes);
//根据条件重启通道线程
//if (restart)
await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false);
if (restart)
await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false);
return true;
}
@@ -234,7 +234,7 @@ public class ChannelRuntimeService : IChannelRuntimeService
}
public async Task<bool> BatchSaveChannelAsync(List<Channel> input, ItemChangedType type)
public async Task<bool> BatchSaveChannelAsync(List<Channel> input, ItemChangedType type, bool restart)
{
try
{
@@ -247,8 +247,8 @@ public class ChannelRuntimeService : IChannelRuntimeService
RuntimeServiceHelper.Init(newChannelRuntimes);
//根据条件重启通道线程
//if (restart)
await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false);
if (restart)
await GlobalData.ChannelThreadManage.RestartChannelAsync(newChannelRuntimes).ConfigureAwait(false);
return true;
}

View File

@@ -21,14 +21,16 @@ public interface IChannelRuntimeService
/// </summary>
/// <param name="input">通道对象</param>
/// <param name="type">保存类型</param>
Task<bool> SaveChannelAsync(Channel input, ItemChangedType type);
/// <param name="restart">重启</param>
Task<bool> SaveChannelAsync(Channel input, ItemChangedType type, bool restart);
/// <summary>
/// 保存通道
/// </summary>
/// <param name="input">通道对象</param>
/// <param name="type">保存类型</param>
Task<bool> BatchSaveChannelAsync(List<Channel> input, ItemChangedType type);
/// <param name="restart">重启</param>
Task<bool> BatchSaveChannelAsync(List<Channel> input, ItemChangedType type, bool restart);
/// <summary>
@@ -37,23 +39,24 @@ public interface IChannelRuntimeService
/// <param name="models">列表</param>
/// <param name="oldModel">旧数据</param>
/// <param name="model">新数据</param>
/// <param name="restart">重启</param>
/// <returns></returns>
Task<bool> BatchEditAsync(IEnumerable<Channel> models, Channel oldModel, Channel model);
Task<bool> BatchEditAsync(IEnumerable<Channel> models, Channel oldModel, Channel model, bool restart);
/// <summary>
/// 删除通道
/// </summary>
Task<bool> DeleteChannelAsync(IEnumerable<long> ids, CancellationToken cancellationToken);
Task<bool> DeleteChannelAsync(IEnumerable<long> ids, bool restart, CancellationToken cancellationToken);
/// <summary>
/// 导入通道数据
/// </summary>
Task ImportChannelAsync(Dictionary<string, ImportPreviewOutputBase> input);
Task ImportChannelAsync(Dictionary<string, ImportPreviewOutputBase> input, bool restart);
Task<Dictionary<string, object>> ExportChannelAsync(ExportFilter exportFilter);
Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IBrowserFile browserFile);
Task<MemoryStream> ExportMemoryStream(IEnumerable<Channel> data);
Task RestartChannelAsync(IEnumerable<ChannelRuntime> oldChannelRuntimes);
Task<bool> CopyAsync(List<Channel> models, Dictionary<Device, List<Variable>> devices, CancellationToken cancellationToken);
Task<bool> UpdateAsync(List<Channel> models, List<Device> devices, List<Variable> variables, CancellationToken cancellationToken);
Task<bool> InsertAsync(List<Channel> models, List<Device> devices, List<Variable> variables, CancellationToken cancellationToken);
Task<bool> CopyAsync(List<Channel> models, Dictionary<Device, List<Variable>> devices, bool restart, CancellationToken cancellationToken);
Task<bool> UpdateAsync(List<Channel> models, List<Device> devices, List<Variable> variables, bool restart, CancellationToken cancellationToken);
Task<bool> InsertAsync(List<Channel> models, List<Device> devices, List<Variable> variables, bool restart, CancellationToken cancellationToken);
}

View File

@@ -30,7 +30,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService
private WaitLock WaitLock { get; set; } = new WaitLock();
public async Task<bool> CopyAsync(Dictionary<Device, List<Variable>> devices, CancellationToken cancellationToken)
public async Task<bool> CopyAsync(Dictionary<Device, List<Variable>> devices, bool restart, CancellationToken cancellationToken)
{
try
{
@@ -45,7 +45,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService
//根据条件重启通道线程
//if (restart)
if (restart)
{
await RuntimeServiceHelper.RestartDeviceAsync(newDeviceRuntimes).ConfigureAwait(false);
await RuntimeServiceHelper.ChangedDriverAsync(_logger, cancellationToken).ConfigureAwait(false);
@@ -60,7 +60,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService
}
}
public async Task<bool> BatchEditAsync(IEnumerable<Device> models, Device oldModel, Device model)
public async Task<bool> BatchEditAsync(IEnumerable<Device> models, Device oldModel, Device model, bool restart = true)
{
try
{
@@ -71,7 +71,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService
var newDeviceRuntimes = await RuntimeServiceHelper.GetNewDeviceRuntimesAsync(deviceids).ConfigureAwait(false);
//if (restart)
if (restart)
{
var newDeciceIds = newDeviceRuntimes.Select(a => a.Id).ToHashSet();
@@ -82,7 +82,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService
//根据条件重启通道线程
//if (restart)
if (restart)
{
await RuntimeServiceHelper.RestartDeviceAsync(newDeviceRuntimes).ConfigureAwait(false);
}
@@ -95,7 +95,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService
}
}
public async Task<bool> DeleteDeviceAsync(IEnumerable<long> ids, CancellationToken cancellationToken)
public async Task<bool> DeleteDeviceAsync(IEnumerable<long> ids, bool restart, CancellationToken cancellationToken)
{
try
{
@@ -111,7 +111,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService
ConcurrentHashSet<IDriver> changedDriver = RuntimeServiceHelper.DeleteDeviceRuntime(deviceRuntimes);
//if (restart)
if (restart)
{
await RuntimeServiceHelper.RemoveDeviceAsync(deviceRuntimes).ConfigureAwait(false);
@@ -136,7 +136,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService
GlobalData.DeviceService.ExportMemoryStream(data, channelName, plugin);
public async Task ImportDeviceAsync(Dictionary<string, ImportPreviewOutputBase> input)
public async Task ImportDeviceAsync(Dictionary<string, ImportPreviewOutputBase> input, bool restart = true)
{
try
{
@@ -146,7 +146,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService
var newDeviceRuntimes = await RuntimeServiceHelper.GetNewDeviceRuntimesAsync(deviceids).ConfigureAwait(false);
//if (restart)
if (restart)
{
var newDeciceIds = newDeviceRuntimes.Select(a => a.Id).ToHashSet();
@@ -158,7 +158,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService
RuntimeServiceHelper.Init(newDeviceRuntimes);
//根据条件重启通道线程
//if (restart)
if (restart)
{
await RuntimeServiceHelper.RestartDeviceAsync(newDeviceRuntimes).ConfigureAwait(false);
@@ -174,7 +174,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService
}
public async Task<bool> SaveDeviceAsync(Device input, ItemChangedType type)
public async Task<bool> SaveDeviceAsync(Device input, ItemChangedType type, bool restart = true)
{
try
{
@@ -190,7 +190,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService
RuntimeServiceHelper.Init(newDeviceRuntimes);
//if (restart)
if (restart)
{
//根据条件重启通道线程
await RuntimeServiceHelper.RestartDeviceAsync(newDeviceRuntimes).ConfigureAwait(false);
@@ -205,7 +205,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService
}
public async Task<bool> BatchSaveDeviceAsync(List<Device> input, ItemChangedType type)
public async Task<bool> BatchSaveDeviceAsync(List<Device> input, ItemChangedType type, bool restart)
{
try
@@ -219,7 +219,7 @@ public class DeviceRuntimeService : IDeviceRuntimeService
RuntimeServiceHelper.Init(newDeviceRuntimes);
//if (restart)
if (restart)
{
//根据条件重启通道线程
await RuntimeServiceHelper.RestartDeviceAsync(newDeviceRuntimes).ConfigureAwait(false);

View File

@@ -16,14 +16,14 @@ namespace ThingsGateway.Gateway.Application
{
public interface IDeviceRuntimeService
{
Task<bool> BatchEditAsync(IEnumerable<Device> models, Device oldModel, Device model);
Task<bool> CopyAsync(Dictionary<Device, List<Variable>> devices, CancellationToken cancellationToken);
Task<bool> DeleteDeviceAsync(IEnumerable<long> ids, CancellationToken cancellationToken);
Task<bool> BatchEditAsync(IEnumerable<Device> models, Device oldModel, Device model, bool restart);
Task<bool> CopyAsync(Dictionary<Device, List<Variable>> devices, bool restart, CancellationToken cancellationToken);
Task<bool> DeleteDeviceAsync(IEnumerable<long> ids, bool restart, CancellationToken cancellationToken);
Task<Dictionary<string, object>> ExportDeviceAsync(ExportFilter exportFilter);
Task<MemoryStream> ExportMemoryStream(List<Device> data, string channelName, string plugin);
Task ImportDeviceAsync(Dictionary<string, ImportPreviewOutputBase> input);
Task ImportDeviceAsync(Dictionary<string, ImportPreviewOutputBase> input, bool restart);
Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IBrowserFile browserFile);
Task<bool> SaveDeviceAsync(Device input, ItemChangedType type);
Task<bool> BatchSaveDeviceAsync(List<Device> input, ItemChangedType type);
Task<bool> SaveDeviceAsync(Device input, ItemChangedType type, bool restart);
Task<bool> BatchSaveDeviceAsync(List<Device> input, ItemChangedType type, bool restart);
}
}

View File

@@ -428,22 +428,22 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
if (DriverTasks.TryRemove(deviceId, out var task))
{
task.Stop();
}
{
task.Stop();
}
// 取消驱动程序的操作
if (CancellationTokenSources.TryRemove(deviceId, out var token))
{
if (token != null)
{
token.Cancel();
token.Dispose();
}
}
// 取消驱动程序的操作
if (CancellationTokenSources.TryRemove(deviceId, out var token))
{
if (token != null)
{
token.Cancel();
token.Dispose();
}
}
});
});
await Task.Delay(100).ConfigureAwait(false);

View File

@@ -146,8 +146,8 @@ internal sealed partial class ReverseCallbackServer : SingletonRpcServer
}
await GlobalData.ChannelRuntimeService.InsertAsync(addChannels, addDevices, addVariables, default).ConfigureAwait(false);
await GlobalData.ChannelRuntimeService.UpdateAsync(upChannels, upDevices, upVariables, default).ConfigureAwait(false);
await GlobalData.ChannelRuntimeService.InsertAsync(addChannels, addDevices, addVariables, true, default).ConfigureAwait(false);
await GlobalData.ChannelRuntimeService.UpdateAsync(upChannels, upDevices, upVariables, true, default).ConfigureAwait(false);
RedundancyTask.LogMessage?.LogTrace($"Sync data success");

View File

@@ -130,10 +130,9 @@ internal sealed class RpcService : IRpcService
{
try
{
var start = DateTime.Now;
// 调用设备的写入方法
var result = await driverData.Key.InVokeWriteAsync(driverData.Value, cancellationToken).ConfigureAwait(false);
var end = DateTime.Now;
// 写入日志
foreach (var resultItem in result)
{
@@ -150,8 +149,7 @@ internal sealed class RpcService : IRpcService
_logQueues.Enqueue(
new RpcLog()
{
LogTime = start,
ExecutionTime = (int)(end - start).TotalMilliseconds,
LogTime = DateTime.Now,
OperateMessage = variableResult.Value.IsSuccess ? null : variableResult.Value.ToString(),
IsSuccess = variableResult.Value.IsSuccess,
OperateMethod = AppResource.WriteVariable,
@@ -192,12 +190,10 @@ internal sealed class RpcService : IRpcService
{
try
{
var start = DateTime.Now;
// 调用设备的写入方法
var result = await driverData.Key.InvokeMethodAsync(driverData.Value, cancellationToken).ConfigureAwait(false);
Dictionary<string, string> operateMethods = driverData.Value.Select(a => a.Key).ToDictionary(a => a.Name, a => a.OtherMethod!);
var end = DateTime.Now;
// 写入日志
foreach (var resultItem in result)
@@ -214,8 +210,7 @@ internal sealed class RpcService : IRpcService
_logQueues.Enqueue(
new RpcLog()
{
LogTime = start,
ExecutionTime = (int)(end - start).TotalMilliseconds,
LogTime = DateTime.Now,
OperateMessage = variableResult.Value.IsSuccess ? null : variableResult.Value.ToString(),
IsSuccess = variableResult.Value.IsSuccess,
OperateMethod = operateMethods[variableResult.Key],

View File

@@ -184,7 +184,7 @@
"Reload": "重载"
},
"ThingsGateway.Gateway.Razor.QuickActions": {
"AutoRestartThread": "变量修改立即生效",
"AutoRestartThread": "自动重启线程",
"HeaderText": "快捷操作",
"ReloadPluginConfirmText": "确定重载插件?",
"ReloadServiceConfirmText": "确定重启运行时?",

View File

@@ -133,7 +133,7 @@ public partial class ChannelTable : IDisposable
{nameof(ChannelCopyComponent.OnSave), async (List<Channel> channels,Dictionary<Device,List<Variable>> devices) =>
{
await Task.Run(() =>GlobalData.ChannelRuntimeService.CopyAsync(channels,devices, default));
await Task.Run(() =>GlobalData.ChannelRuntimeService.CopyAsync(channels,devices,AutoRestartThread, default));
await InvokeAsync(table.QueryAsync);
}},
@@ -174,7 +174,7 @@ public partial class ChannelTable : IDisposable
{
{nameof(ChannelEditComponent.OnValidSubmit), async () =>
{
await Task.Run(() => GlobalData.ChannelRuntimeService.BatchEditAsync(changedModels, oldModel, oneModel));
await Task.Run(() => GlobalData.ChannelRuntimeService.BatchEditAsync(changedModels, oldModel, oneModel,AutoRestartThread));
await InvokeAsync(table.QueryAsync);
@@ -197,7 +197,7 @@ public partial class ChannelTable : IDisposable
{
return await Task.Run(async () =>
{
return await GlobalData.ChannelRuntimeService.DeleteChannelAsync(channels.Select(a => a.Id), default);
return await GlobalData.ChannelRuntimeService.DeleteChannelAsync(channels.Select(a => a.Id), AutoRestartThread, default);
});
}
catch (Exception ex)
@@ -215,7 +215,7 @@ public partial class ChannelTable : IDisposable
try
{
channel = channel.AdaptChannel();
return await Task.Run(() => GlobalData.ChannelRuntimeService.SaveChannelAsync(channel, itemChangedType));
return await Task.Run(() => GlobalData.ChannelRuntimeService.SaveChannelAsync(channel, itemChangedType, AutoRestartThread));
}
catch (Exception ex)
{
@@ -304,7 +304,7 @@ public partial class ChannelTable : IDisposable
await Task.Run(async ()=>
{
var importData=await ChannelServiceHelpers.ImportAsync(data);
await GlobalData.ChannelRuntimeService.ImportChannelAsync(importData);
await GlobalData.ChannelRuntimeService.ImportChannelAsync(importData,AutoRestartThread);
})
;
}
@@ -346,7 +346,7 @@ finally
};
Func<IBrowserFile, Task<Dictionary<string, ImportPreviewOutputBase>>> preview = (a => GlobalData.ChannelRuntimeService.PreviewAsync(a));
Func<Dictionary<string, ImportPreviewOutputBase>, Task> import = (value => GlobalData.ChannelRuntimeService.ImportChannelAsync(value));
Func<Dictionary<string, ImportPreviewOutputBase>, Task> import = (value => GlobalData.ChannelRuntimeService.ImportChannelAsync(value, AutoRestartThread));
op.Component = BootstrapDynamicComponent.CreateComponent<ImportExcel>(new Dictionary<string, object?>
{
{nameof(ImportExcel.Import),import },
@@ -367,7 +367,7 @@ finally
await Task.Run(async () =>
{
await GlobalData.ChannelRuntimeService.DeleteChannelAsync(Items.Select(a => a.Id), default);
await GlobalData.ChannelRuntimeService.DeleteChannelAsync(Items.Select(a => a.Id), AutoRestartThread, default);
await InvokeAsync(async () =>
{
await ToastService.Default();
@@ -386,7 +386,8 @@ finally
}
#endregion
[Parameter]
public bool AutoRestartThread { get; set; }
[Parameter]
public ChannelDeviceTreeItem SelectModel { get; set; }
[Inject]

View File

@@ -83,7 +83,7 @@ namespace ThingsGateway.Gateway.Razor
internal static async Task ShowCopy(Channel oneModel, Dictionary<Device, List<Variable>> deviceDict, string text, Func<Task> onsave, DialogService dialogService)
internal static async Task ShowCopy(Channel oneModel, Dictionary<Device, List<Variable>> deviceDict, string text, bool autoRestart, Func<Task> onsave, DialogService dialogService)
{
var op = new DialogOption()
{
@@ -100,7 +100,7 @@ namespace ThingsGateway.Gateway.Razor
{nameof(ChannelCopyComponent.OnSave), async (List<Channel> channels,Dictionary<Device,List<Variable>> devices) =>
{
await Task.Run(() =>GlobalData.ChannelRuntimeService.CopyAsync(channels,devices, default));
await Task.Run(() =>GlobalData.ChannelRuntimeService.CopyAsync(channels,devices,autoRestart, default));
if(onsave!=null)
await onsave();

View File

@@ -55,6 +55,9 @@ public partial class ChannelDeviceTree
await OnShowTypeChanged(showType);
}
[Parameter]
public bool AutoRestartThread { get; set; }
private static string GetClass(ChannelDeviceTreeItem item)
{
if (item.TryGetChannelRuntime(out var channelRuntime))
@@ -120,7 +123,7 @@ public partial class ChannelDeviceTree
{
{nameof(ChannelEditComponent.OnValidSubmit), async () =>
{
await Task.Run(() =>GlobalData.ChannelRuntimeService.SaveChannelAsync(oneModel,itemChangedType));
await Task.Run(() =>GlobalData.ChannelRuntimeService.SaveChannelAsync(oneModel,itemChangedType,AutoRestartThread));
////await Notify();
}},
{nameof(ChannelEditComponent.Model),oneModel },
@@ -172,7 +175,7 @@ public partial class ChannelDeviceTree
{nameof(ChannelCopyComponent.OnSave), async (List<Channel> channels,Dictionary<Device,List<Variable>> devices) =>
{
await Task.Run(() =>GlobalData.ChannelRuntimeService.CopyAsync(channels,devices, default));
await Task.Run(() =>GlobalData.ChannelRuntimeService.CopyAsync(channels,devices,AutoRestartThread, default));
//await Notify();
}},
@@ -247,7 +250,7 @@ public partial class ChannelDeviceTree
{nameof(ChannelEditComponent.OnValidSubmit), async () =>
{
Spinner.SetRun(true);
await Task.Run(() => GlobalData.ChannelRuntimeService.BatchEditAsync(changedModels, oldModel, oneModel));
await Task.Run(() => GlobalData.ChannelRuntimeService.BatchEditAsync(changedModels, oldModel, oneModel,AutoRestartThread));
//await Notify();
await InvokeAsync(() =>
@@ -298,7 +301,7 @@ public partial class ChannelDeviceTree
await Task.Run(async ()=>
{
var importData=await ChannelServiceHelpers.ImportAsync(data);
await GlobalData.ChannelRuntimeService.ImportChannelAsync(importData);
await GlobalData.ChannelRuntimeService.ImportChannelAsync(importData,AutoRestartThread);
})
;
}
@@ -424,7 +427,7 @@ finally
Spinner.SetRun(true);
await Task.Run(() => GlobalData.ChannelRuntimeService.DeleteChannelAsync(modelIds.Select(a => a.Id), default));
await Task.Run(() => GlobalData.ChannelRuntimeService.DeleteChannelAsync(modelIds.Select(a => a.Id), AutoRestartThread, default));
//await Notify();
await InvokeAsync(() =>
{
@@ -468,7 +471,7 @@ finally
Spinner.SetRun(true);
var key = await GlobalData.GetCurrentUserChannels().ConfigureAwait(false);
await Task.Run(() => GlobalData.ChannelRuntimeService.DeleteChannelAsync(key.Select(a => a.Id), default));
await Task.Run(() => GlobalData.ChannelRuntimeService.DeleteChannelAsync(key.Select(a => a.Id), AutoRestartThread, default));
//await Notify();
await InvokeAsync(() =>
{
@@ -601,7 +604,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e =>
Spinner.SetRun(true);
});
await Task.Run(() => GlobalData.ChannelRuntimeService.ImportChannelAsync(value));
await Task.Run(() => GlobalData.ChannelRuntimeService.ImportChannelAsync(value, AutoRestartThread));
//await Notify();
await InvokeAsync(() =>
{
@@ -656,7 +659,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e =>
{nameof(DeviceCopyComponent.OnSave), async (Dictionary<Device,List<Variable>> devices) =>
{
await Task.Run(() =>GlobalData.DeviceRuntimeService.CopyAsync(devices, default));
await Task.Run(() =>GlobalData.DeviceRuntimeService.CopyAsync(devices,AutoRestartThread, default));
//await Notify();
}},
@@ -709,10 +712,11 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e =>
{
{nameof(DeviceEditComponent.OnValidSubmit), async () =>
{
await Task.Run(() =>GlobalData.DeviceRuntimeService.SaveDeviceAsync(oneModel,itemChangedType));
await Task.Run(() =>GlobalData.DeviceRuntimeService.SaveDeviceAsync(oneModel,itemChangedType, AutoRestartThread));
//await Notify();
}},
{nameof(DeviceEditComponent.Model),oneModel },
{nameof(DeviceEditComponent.AutoRestartThread),AutoRestartThread },
{nameof(DeviceEditComponent.ValidateEnable),true },
{nameof(DeviceEditComponent.BatchEditEnable),false },
});
@@ -794,7 +798,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e =>
Spinner.SetRun(true);
});
await Task.Run(() =>GlobalData.DeviceRuntimeService.BatchEditAsync(changedModels,oldModel,oneModel));
await Task.Run(() =>GlobalData.DeviceRuntimeService.BatchEditAsync(changedModels,oldModel,oneModel,AutoRestartThread));
//await Notify();
await InvokeAsync(() =>
{
@@ -802,6 +806,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e =>
});
}},
{nameof(DeviceEditComponent.Model),oneModel },
{nameof(DeviceEditComponent.AutoRestartThread),AutoRestartThread },
{nameof(DeviceEditComponent.ValidateEnable),true },
{nameof(DeviceEditComponent.BatchEditEnable),true },
});
@@ -837,7 +842,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e =>
await Task.Run(async ()=>
{
var importData=await DeviceServiceHelpers.ImportAsync(data);
await GlobalData.DeviceRuntimeService.ImportDeviceAsync(importData);
await GlobalData.DeviceRuntimeService.ImportDeviceAsync(importData,AutoRestartThread);
})
;
}
@@ -969,7 +974,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e =>
Spinner.SetRun(true);
await Task.Run(() => GlobalData.DeviceRuntimeService.DeleteDeviceAsync(modelIds.Select(a => a.Id), default));
await Task.Run(() => GlobalData.DeviceRuntimeService.DeleteDeviceAsync(modelIds.Select(a => a.Id), AutoRestartThread, default));
//await Notify();
await InvokeAsync(() =>
{
@@ -1016,7 +1021,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e =>
var data = await GlobalData.GetCurrentUserDevices().ConfigureAwait(false);
await Task.Run(() => GlobalData.DeviceRuntimeService.DeleteDeviceAsync(data.Select(a => a.Id), default));
await Task.Run(() => GlobalData.DeviceRuntimeService.DeleteDeviceAsync(data.Select(a => a.Id), AutoRestartThread, default));
//await Notify();
await InvokeAsync(() =>
{
@@ -1150,7 +1155,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e =>
});
await Task.Run(() => GlobalData.DeviceRuntimeService.ImportDeviceAsync(value));
await Task.Run(() => GlobalData.DeviceRuntimeService.ImportDeviceAsync(value, AutoRestartThread));
//await Notify();
await InvokeAsync(() =>
{

View File

@@ -28,6 +28,8 @@ public partial class DeviceEditComponent
[EditorRequired]
public Device Model { get; set; }
[Parameter]
public bool AutoRestartThread { get; set; }
[Parameter]
public Func<Task> OnValidSubmit { get; set; }
@@ -86,7 +88,7 @@ public partial class DeviceEditComponent
{
{nameof(ChannelEditComponent.OnValidSubmit), async () =>
{
await Task.Run(() =>GlobalData.ChannelRuntimeService.SaveChannelAsync(oneModel,ItemChangedType.Add));
await Task.Run(() =>GlobalData.ChannelRuntimeService.SaveChannelAsync(oneModel,ItemChangedType.Add,AutoRestartThread));
OnParametersSet();
}},
{nameof(ChannelEditComponent.Model),oneModel },

View File

@@ -66,7 +66,7 @@
</TableColumns>
<EditTemplate Context="context">
<DeviceEditComponent Model=@(context) ValidateEnable=false BatchEditEnable=false></DeviceEditComponent>
<DeviceEditComponent Model=@(context) ValidateEnable=false BatchEditEnable=false AutoRestartThread=AutoRestartThread></DeviceEditComponent>
</EditTemplate>

View File

@@ -133,7 +133,7 @@ public partial class DeviceTable : IDisposable
{nameof(DeviceCopyComponent.OnSave), async (Dictionary<Device,List<Variable>> devices) =>
{
await Task.Run(() =>GlobalData.DeviceRuntimeService.CopyAsync(devices, default));
await Task.Run(() =>GlobalData.DeviceRuntimeService.CopyAsync(devices,AutoRestartThread, default));
await InvokeAsync(table.QueryAsync);
}},
@@ -173,7 +173,7 @@ public partial class DeviceTable : IDisposable
{
{nameof(DeviceEditComponent.OnValidSubmit), async () =>
{
await Task.Run(() => GlobalData.DeviceRuntimeService.BatchEditAsync(changedModels, oldModel, oneModel));
await Task.Run(() => GlobalData.DeviceRuntimeService.BatchEditAsync(changedModels, oldModel, oneModel,AutoRestartThread));
await InvokeAsync(table.QueryAsync);
@@ -196,7 +196,7 @@ public partial class DeviceTable : IDisposable
{
return await Task.Run(async () =>
{
return await GlobalData.DeviceRuntimeService.DeleteDeviceAsync(devices.Select(a => a.Id), default);
return await GlobalData.DeviceRuntimeService.DeleteDeviceAsync(devices.Select(a => a.Id), AutoRestartThread, default);
});
}
catch (Exception ex)
@@ -215,7 +215,7 @@ public partial class DeviceTable : IDisposable
{
device.DevicePropertys = PluginServiceUtil.SetDict(device.ModelValueValidateForm.Value);
device = device.AdaptDevice();
return await Task.Run(() => GlobalData.DeviceRuntimeService.SaveDeviceAsync(device, itemChangedType));
return await Task.Run(() => GlobalData.DeviceRuntimeService.SaveDeviceAsync(device, itemChangedType, AutoRestartThread));
}
catch (Exception ex)
{
@@ -305,7 +305,7 @@ public partial class DeviceTable : IDisposable
await Task.Run(async ()=>
{
var importData=await DeviceServiceHelpers.ImportAsync(data);
await GlobalData.DeviceRuntimeService.ImportDeviceAsync(importData);
await GlobalData.DeviceRuntimeService.ImportDeviceAsync(importData,AutoRestartThread);
})
;
}
@@ -347,7 +347,7 @@ finally
};
Func<IBrowserFile, Task<Dictionary<string, ImportPreviewOutputBase>>> preview = (a => GlobalData.DeviceRuntimeService.PreviewAsync(a));
Func<Dictionary<string, ImportPreviewOutputBase>, Task> import = (value => GlobalData.DeviceRuntimeService.ImportDeviceAsync(value));
Func<Dictionary<string, ImportPreviewOutputBase>, Task> import = (value => GlobalData.DeviceRuntimeService.ImportDeviceAsync(value, AutoRestartThread));
op.Component = BootstrapDynamicComponent.CreateComponent<ImportExcel>(new Dictionary<string, object?>
{
{nameof(ImportExcel.Import),import },
@@ -368,7 +368,7 @@ finally
await Task.Run(async () =>
{
await GlobalData.DeviceRuntimeService.DeleteDeviceAsync(Items.Select(a => a.Id), default);
await GlobalData.DeviceRuntimeService.DeleteDeviceAsync(Items.Select(a => a.Id), AutoRestartThread, default);
await InvokeAsync(async () =>
{
await ToastService.Default();
@@ -387,7 +387,8 @@ finally
}
#endregion
[Parameter]
public bool AutoRestartThread { get; set; }
[Parameter]
public ChannelDeviceTreeItem SelectModel { get; set; }
[Inject]

View File

@@ -22,10 +22,10 @@ else if (ShowType == ShowTypeEnum.LogInfo)
}
else if (ShowType == ShowTypeEnum.ChannelTable)
{
<ChannelTable SelectModel="SelectModel" Items="ChannelRuntimes"/>
<ChannelTable SelectModel="SelectModel" Items="ChannelRuntimes" AutoRestartThread=AutoRestartThread />
}
else if (ShowType == ShowTypeEnum.DeviceTable)
{
<DeviceTable SelectModel="SelectModel" Items="DeviceRuntimes"/>
<DeviceTable SelectModel="SelectModel" Items="DeviceRuntimes" AutoRestartThread=AutoRestartThread />
}

View File

@@ -15,7 +15,7 @@
<Card IsShadow=true class="h-100 me-1" Color="Color.Primary">
<BodyTemplate>
<ChannelDeviceTree @bind-ShowType=ShowType
<ChannelDeviceTree @bind-ShowType=ShowType AutoRestartThread="AutoRestartThread"
ChannelDeviceChanged="TreeChangedAsync" Value="SelectModel"></ChannelDeviceTree>
</BodyTemplate>
</Card>

View File

@@ -214,10 +214,11 @@ public partial class VariableEditComponent
{
{nameof(DeviceEditComponent.OnValidSubmit), async () =>
{
await Task.Run(() =>GlobalData.DeviceRuntimeService.SaveDeviceAsync(oneModel,ItemChangedType.Add));
await Task.Run(() =>GlobalData.DeviceRuntimeService.SaveDeviceAsync(oneModel,ItemChangedType.Add,AutoRestartThread));
OnParametersSet();
}},
{nameof(DeviceEditComponent.Model),oneModel },
{nameof(DeviceEditComponent.AutoRestartThread),AutoRestartThread },
{nameof(DeviceEditComponent.ValidateEnable),true },
{nameof(DeviceEditComponent.BatchEditEnable),false },
});

View File

@@ -148,16 +148,17 @@ public class OpcDaMaster : CollectBase
}
/// <inheritdoc/>
protected override ValueTask<OperResult<byte[]>> ReadSourceAsync(VariableSourceRead deviceVariableSourceRead, CancellationToken cancellationToken)
protected override async ValueTask<OperResult<byte[]>> ReadSourceAsync(VariableSourceRead deviceVariableSourceRead, CancellationToken cancellationToken)
{
try
{
await ReadWriteLock.ReaderLockAsync(cancellationToken).ConfigureAwait(false);
_plc.ReadItemsWithGroup(deviceVariableSourceRead.RegisterAddress);
return ValueTask.FromResult(OperResult.CreateSuccessResult(Array.Empty<byte>()));
return OperResult.CreateSuccessResult(Array.Empty<byte>());
}
catch (Exception ex)
{
return ValueTask.FromResult(new OperResult<byte[]>($"ReadSourceAsync Error{Environment.NewLine}{ex}"));
return new OperResult<byte[]>($"ReadSourceAsync Error{Environment.NewLine}{ex}");
}
}

View File

@@ -234,8 +234,8 @@ public partial class OpcDaImportVariable
await ToastService.Warning(OpcDaPropertyLocalizer["NoVariablesAvailable"], OpcDaPropertyLocalizer["NoVariablesAvailable"]);
return;
}
await App.RootServices.GetRequiredService<IChannelRuntimeService>().SaveChannelAsync(data.Item1, ItemChangedType.Add);
await App.RootServices.GetRequiredService<IDeviceRuntimeService>().SaveDeviceAsync(data.Item2, ItemChangedType.Add);
await App.RootServices.GetRequiredService<IChannelRuntimeService>().SaveChannelAsync(data.Item1, ItemChangedType.Add, true);
await App.RootServices.GetRequiredService<IDeviceRuntimeService>().SaveDeviceAsync(data.Item2, ItemChangedType.Add, true);
await App.RootServices.GetRequiredService<IVariableRuntimeService>().BatchSaveVariableAsync(data.Item3, ItemChangedType.Add, true, default);
await ToastService.Default();
}

View File

@@ -247,6 +247,7 @@ public class OpcUaMaster : CollectBase
var addresss = deviceVariableSourceRead.VariableRuntimes.Where(a => !a.RegisterAddress.IsNullOrEmpty()).Select(a => a.RegisterAddress!).ToArray();
try
{
await ReadWriteLock.ReaderLockAsync(cancellationToken).ConfigureAwait(false);
var result = await _plc.ReadJTokenValueAsync(addresss, cancellationToken).ConfigureAwait(false);
foreach (var data in result)

View File

@@ -263,8 +263,8 @@ public partial class OpcUaImportVariable
await ToastService.Warning(OpcUaPropertyLocalizer["NoVariablesAvailable"], OpcUaPropertyLocalizer["NoVariablesAvailable"]);
return;
}
await App.RootServices.GetRequiredService<IChannelRuntimeService>().SaveChannelAsync(data.Item1, ItemChangedType.Add);
await App.RootServices.GetRequiredService<IDeviceRuntimeService>().SaveDeviceAsync(data.Item2, ItemChangedType.Add);
await App.RootServices.GetRequiredService<IChannelRuntimeService>().SaveChannelAsync(data.Item1, ItemChangedType.Add, true);
await App.RootServices.GetRequiredService<IDeviceRuntimeService>().SaveDeviceAsync(data.Item2, ItemChangedType.Add, true);
await App.RootServices.GetRequiredService<IVariableRuntimeService>().BatchSaveVariableAsync(data.Item3.ToList(), ItemChangedType.Add, true, default);
await ToastService.Default();
}

View File

@@ -23,7 +23,7 @@
<title>ThingsGateway</title>
@{
#if !NET8_0
#if !NET8_0
}
<link rel="stylesheet" href=@(Assets[$"_content/BootstrapBlazor.FontAwesome/css/font-awesome.min.css"]) />