244 KiB
修改记录
2025-01-02
ProtocolWsClientManager.StartAllClients方法启动和连接状态检查分离
修改时间: 2025年1月2日 修改文件:
CoreAgent.Infrastructure/Services/Network/ProtocolWsClientManager.cs
CoreAgent.ProtocolClient/Interfaces/IProtocolWsClientManager.cs
CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
修改内容:
-
问题描述:
StartAllClients
方法中启动客户端和检查连接状态混在一起- 方法职责不够清晰,同时处理启动和连接状态检查
- 需要将启动和连接状态检查分离,提高代码的可读性和可维护性
GeneralCellularNetworkService.StartAllProtocolClientsAsync
方法需要适配新的接口
-
修复方案:
- 分离启动和连接状态检查:将
StartAllClients
方法中的连接状态检查逻辑分离出来 - 新增连接状态检查方法:创建
CheckAllClientsConnection()
方法专门用于检查连接状态 - 简化启动方法:
StartAllClients
方法只负责启动客户端,不检查连接状态 - 更新接口定义:在
IProtocolWsClientManager
接口中添加新的方法定义 - 优化返回值:
StartAllClients
返回是否所有客户端都成功启动,CheckAllClientsConnection
返回是否所有客户端都已连接 - 修复调用方代码:更新
GeneralCellularNetworkService.StartAllProtocolClientsAsync
方法以适配新的接口
- 分离启动和连接状态检查:将
-
具体修改: StartAllClients方法优化:
// 修改前 - 启动和连接状态检查混在一起 public bool StartAllClients(ProtocolClientConfig[] configs) { // 启动客户端逻辑... // 检查连接状态 if (existingClient.IsConnected) { connectedCount++; } var allConnected = connectedCount == configs.Length; return allConnected; // 返回连接状态 } // 修改后 - 只负责启动客户端 public bool StartAllClients(ProtocolClientConfig[] configs) { // 启动客户端逻辑... var allStarted = startedCount == configs.Length; return allStarted; // 返回启动状态 }
新增CheckAllClientsConnection方法:
/// <summary> /// 检查所有协议客户端连接状态 /// </summary> /// <param name="timeoutSeconds">超时时间(秒),默认10秒</param> /// <returns>是否所有客户端都已连接</returns> public bool CheckAllClientsConnection(int timeoutSeconds = 10) { ThrowIfDisposed(); if (timeoutSeconds <= 0) { _logger.LogWarning("超时时间必须大于0,使用默认值10秒"); timeoutSeconds = 10; } lock (_lock) { if (_clients.Count == 0) { _logger.LogWarning("没有运行中的协议客户端"); return false; } _logger.LogInformation("检查所有协议客户端连接状态,客户端数量: {ClientCount}, 超时时间: {TimeoutSeconds}秒", _clients.Count, timeoutSeconds); var startTime = DateTime.UtcNow; var timeout = TimeSpan.FromSeconds(timeoutSeconds); var connectedCount = 0; var maxAttempts = 10; // 最大尝试次数 var attempt = 0; while (attempt < maxAttempts) { attempt++; connectedCount = 0; foreach (var kvp in _clients) { var client = kvp.Value; if (client.IsConnected) { connectedCount++; } _logger.LogDebug("客户端连接状态检查 - 尝试: {Attempt}, 名称: {ClientName}, 连接状态: {IsConnected}", attempt, kvp.Key, client.IsConnected); } var allConnected = connectedCount == _clients.Count; if (allConnected) { var elapsed = DateTime.UtcNow - startTime; _logger.LogInformation("协议客户端连接状态检查完成 - 已连接: {ConnectedCount}, 总数量: {TotalCount}, 全部连接: {AllConnected}, 耗时: {Elapsed}ms", connectedCount, _clients.Count, allConnected, elapsed.TotalMilliseconds.ToString("F2")); return true; } // 检查是否超时 if (DateTime.UtcNow - startTime > timeout) { var elapsed = DateTime.UtcNow - startTime; _logger.LogWarning("协议客户端连接状态检查超时 - 已连接: {ConnectedCount}, 总数量: {TotalCount}, 耗时: {Elapsed}ms, 超时时间: {TimeoutSeconds}秒", connectedCount, _clients.Count, elapsed.TotalMilliseconds.ToString("F2"), timeoutSeconds); return false; } // 等待一段时间后重试 if (attempt < maxAttempts) { var waitTime = Math.Min(1000, timeoutSeconds * 100); // 等待时间,最大1秒 Thread.Sleep(waitTime); } } var finalElapsed = DateTime.UtcNow - startTime; _logger.LogWarning("协议客户端连接状态检查达到最大尝试次数 - 已连接: {ConnectedCount}, 总数量: {TotalCount}, 耗时: {Elapsed}ms", connectedCount, _clients.Count, finalElapsed.TotalMilliseconds.ToString("F2")); return false; } }
GeneralCellularNetworkService.StartAllProtocolClientsAsync方法修复:
// 修改前 - 只检查启动状态 private async Task<CellularNetworkOperationResult> StartAllProtocolClientsAsync(ProtocolClientConfigFactory protocolConfigFactory) { try { var protocolConfigs = protocolConfigFactory.GetAllConfigs(); var startResult = _protocolWsClientManager.StartAllClients(protocolConfigs); if (!startResult) { _logger.LogWarning("部分协议客户端启动失败"); await RestoreNetworkStateAsync(); return CellularNetworkOperationResult.Failure("部分协议客户端启动失败"); } _logger.LogInformation("所有协议客户端启动完成"); return CellularNetworkOperationResult.Success(NetworkStatus.Connected); } catch (Exception ex) { _logger.LogError(ex, "启动协议客户端失败"); await RestoreNetworkStateAsync(); return CellularNetworkOperationResult.Failure($"启动协议客户端失败: {ex.Message}"); } } // 修改后 - 分别检查启动状态和连接状态 private async Task<CellularNetworkOperationResult> StartAllProtocolClientsAsync(ProtocolClientConfigFactory protocolConfigFactory) { try { _logger.LogInformation("开始启动所有协议客户端"); // 获取协议客户端配置 var protocolConfigs = protocolConfigFactory.GetAllConfigs(); if (protocolConfigs == null || protocolConfigs.Length == 0) { _logger.LogWarning("没有可用的协议客户端配置"); await RestoreNetworkStateAsync(); return CellularNetworkOperationResult.Failure("没有可用的协议客户端配置"); } _logger.LogInformation("获取到 {ConfigCount} 个协议客户端配置", protocolConfigs.Length); // 启动所有协议客户端 var startResult = _protocolWsClientManager.StartAllClients(protocolConfigs); if (!startResult) { _logger.LogWarning("部分协议客户端启动失败"); await RestoreNetworkStateAsync(); return CellularNetworkOperationResult.Failure("部分协议客户端启动失败"); } _logger.LogInformation("所有协议客户端启动完成,开始检查连接状态"); // 检查连接状态(使用默认10秒超时) var connectionResult = _protocolWsClientManager.CheckAllClientsConnection(); if (!connectionResult) { _logger.LogWarning("协议客户端连接状态检查失败,部分客户端可能未连接"); await RestoreNetworkStateAsync(); return CellularNetworkOperationResult.Failure("协议客户端连接状态检查失败,部分客户端可能未连接"); } _logger.LogInformation("所有协议客户端启动并连接成功"); return CellularNetworkOperationResult.Success(NetworkStatus.Connected); } catch (Exception ex) { _logger.LogError(ex, "启动协议客户端失败"); await RestoreNetworkStateAsync(); return CellularNetworkOperationResult.Failure($"启动协议客户端失败: {ex.Message}"); } }
接口定义更新:
public interface IProtocolWsClientManager : IDisposable { /// <summary> /// 启动所有协议客户端 /// </summary> /// <param name="configs">协议客户端配置数组</param> /// <returns>是否所有客户端都成功启动</returns> bool StartAllClients(ProtocolClientConfig[] configs); /// <summary> /// 检查所有协议客户端连接状态 /// </summary> /// <param name="timeoutSeconds">超时时间(秒),默认10秒</param> /// <returns>是否所有客户端都已连接</returns> bool CheckAllClientsConnection(int timeoutSeconds = 10); /// <summary> /// 停止所有协议客户端 /// </summary> /// <returns>是否所有客户端都成功停止并断开连接</returns> bool StopAllClients(); }
-
设计优势:
- 职责分离:启动和连接状态检查分别由不同方法处理,职责更加清晰
- 代码可读性:每个方法的逻辑更加简单,易于理解和维护
- 灵活性:可以独立调用启动和连接状态检查,满足不同的业务需求
- 可测试性:分离后的方法更容易进行单元测试
- 日志清晰:每个方法都有独立的日志记录,便于问题排查
- 接口完整性:接口提供了完整的协议客户端管理功能
- 超时机制:连接状态检查支持超时参数,避免无限等待
- 重试机制:在超时时间内进行多次重试,提高连接检查的成功率
- 性能监控:记录详细的耗时信息,便于性能分析和问题排查
- 错误处理完善:添加了配置验证和详细的错误处理逻辑
-
使用场景:
- 启动场景:先调用
StartAllClients()
启动所有客户端,再调用CheckAllClientsConnection()
检查连接状态 - 监控场景:定期调用
CheckAllClientsConnection()
监控连接状态 - 调试场景:可以独立检查启动状态和连接状态,便于问题定位
- 超时控制:可以根据网络环境调整超时时间,如
CheckAllClientsConnection(30)
设置30秒超时 - 快速检查:使用较短的超时时间进行快速检查,如
CheckAllClientsConnection(5)
设置5秒超时
- 启动场景:先调用
影响范围:
- 协议客户端管理器的职责分离
- 接口定义的完整性
- 调用方代码的使用方式
- 代码可读性和可维护性
- 单元测试的便利性
- 蜂窝网络服务的协议客户端启动流程
2025-01-02
SIPProtocolParser.GeneralParse方法严谨性修复
修改时间: 2025年1月2日 修改文件:
CoreAgent.ProtocolClient/BuildProtocolParser/SIPProtocolParser.cs
修改内容:
-
问题描述:
- 变量名错误:
regisMccLine
实际匹配的是MNC,regisMncLine
实际匹配的是MCC - 空引用风险:使用了
!
操作符但没有进行空值检查 - 重复赋值:对
log.SIP.Plmn
进行了两次赋值,第二次会覆盖第一次 - 正则表达式不够严谨:缺少编译选项
- 返回值检查错误:
StringToId
返回0表示空字符串,不是-1
- 变量名错误:
-
修复方案:
- 修复变量名错误:将变量名与实际匹配内容对应
- 增强空值检查:添加参数验证和空值检查
- 修复重复赋值:分别设置PLMN和IMSI属性
- 优化正则表达式:添加
RegexOptions.Compiled
提高性能 - 修复返回值检查:使用正确的返回值判断逻辑
- 添加参数验证:验证Groups数量和参数有效性
-
具体修复:
// 修复前 - 变量名错误 var regisMccLine = log!.Data.Select(line => _regMnc.Match(line))... // 实际匹配MNC var regisMncLine = log!.Data.Select(line => _regMcc.Match(line))... // 实际匹配MCC // 修复后 - 变量名正确 var mncValue = log.Data?.Select(line => _regMnc.Match(line))... // 匹配MNC var mccValue = log.Data?.Select(line => _regMcc.Match(line))... // 匹配MCC // 修复前 - 重复赋值 log.SIP.Plmn = $"{regisMncLine}{regisMccLine!.Substring(1)}"; log.SIP.Plmn = regisIMSILine; // 覆盖了上面的赋值 // 修复后 - 分别设置不同属性 if (!string.IsNullOrEmpty(mccValue) && !string.IsNullOrEmpty(mncValue)) { log.SIP.Plmn = $"{mccValue}{mncValue}"; } if (!string.IsNullOrEmpty(imsiValue)) { log.SIP.IMSI = imsiValue; // 使用正确的IMSI属性 } // 修复前 - 返回值检查错误 if (info == -1) return; // 修复后 - 正确的返回值检查 if (info == 0) return; // StringToId返回0表示空字符串
-
设计优势:
- 逻辑正确性:修复了变量名错误和重复赋值问题
- 空值安全:添加了完整的空值检查和参数验证
- 性能优化:正则表达式使用编译选项提高性能
- 代码严谨性:添加了Groups数量验证和参数有效性检查
- 错误预防:使用空条件操作符避免空引用异常
- 属性正确性:使用正确的SIP属性设置PLMN和IMSI
-
修复的关键问题:
- 变量命名混乱:MCC和MNC变量名与实际匹配内容不匹配
- 空引用风险:使用
!
操作符但没有验证对象不为空 - 数据覆盖:对同一属性进行两次赋值导致数据丢失
- 返回值误解:对
StringToId
方法返回值理解错误 - 正则表达式性能:缺少编译选项影响性能
- 参数验证缺失:没有验证正则匹配结果的Groups数量
- 日志跟踪缺失:缺少详细的错误日志记录,难以调试问题
-
日志跟踪增强:
- 添加ILogger支持:在构造函数中创建类型安全的Logger实例
- 参数验证日志:记录BuildProtocolLog参数为空的情况
- StringToId失败日志:记录StringToId返回0(空字符串)的情况
- Groups数量验证日志:记录正则匹配Groups数量不足的详细信息
- 性能优化:使用私有Logger字段避免重复创建Logger实例
影响范围:
- SIP协议解析的准确性
- 协议日志数据的完整性
- 代码的稳定性和可靠性
- 性能优化和错误预防
- 代码可读性和维护性
- 调试和问题排查能力显著提升
TimeStampHelper时区初始化异常修复
修改时间: 2025年1月2日 修改文件:
CoreAgent.ProtocolClient/Helpers/TimeStampHelper.cs
修改内容:
-
问题描述:
TimeStampHelper
类在静态初始化时抛出System.TimeZoneNotFoundException
- 错误信息:
The time zone ID 'China Standard Time' was not found on the local computer
- 某些系统上可能不存在"China Standard Time"时区ID
-
修复方案:
- 多时区ID支持:尝试多种可能的时区ID,包括Windows和Linux/macOS格式
- 回退机制:如果系统时区ID都不可用,创建自定义UTC+8时区
- 最终回退:如果自定义时区创建失败,使用UTC时区作为最后回退
- 调试支持:添加时区信息查询和验证方法
-
具体修复:
// 修复前 - 直接使用单一时区ID private static readonly TimeZoneInfo ChinaStandardTime = TimeZoneInfo.FindSystemTimeZoneById("China Standard Time"); // 修复后 - 支持多种时区ID和回退机制 private static readonly TimeZoneInfo ChinaStandardTime = GetChinaStandardTime(); private static TimeZoneInfo GetChinaStandardTime() { // 尝试多种可能的时区ID string[] timeZoneIds = { "China Standard Time", // Windows "Asia/Shanghai", // Linux/macOS "Asia/Chongqing", // 备选 "Asia/Harbin", // 备选 "Asia/Urumqi" // 备选 }; foreach (string timeZoneId in timeZoneIds) { try { return TimeZoneInfo.FindSystemTimeZoneById(timeZoneId); } catch (TimeZoneNotFoundException) { continue; } } // 创建自定义UTC+8时区 try { return TimeZoneInfo.CreateCustomTimeZone( "China Standard Time", TimeSpan.FromHours(8), "China Standard Time", "China Standard Time"); } catch { return TimeZoneInfo.Utc; // 最终回退 } }
-
新增调试方法:
// 获取当前使用的时区信息 public static string GetTimeZoneInfo() // 检查时区是否正确初始化 public static bool IsTimeZoneCorrectlyInitialized()
-
设计优势:
- 跨平台兼容:支持Windows、Linux、macOS等不同操作系统
- 健壮性:多层回退机制确保在任何环境下都能正常工作
- 调试友好:提供时区信息查询方法便于问题排查
- 向后兼容:保持原有API不变,不影响现有代码
- 性能优化:静态初始化,避免重复计算
-
修复的关键问题:
- 时区ID不存在:某些系统上"China Standard Time"时区ID不可用
- 跨平台兼容性:不同操作系统使用不同的时区ID格式
- 初始化失败:静态构造函数异常导致整个类无法使用
- 调试困难:缺少时区状态查询方法
影响范围:
- 时间戳工具类的跨平台兼容性
- 系统启动时的稳定性
- 时间转换功能的可靠性
- 调试和问题排查能力
后续优化:
- 简化时区选择逻辑:优先使用
Asia/Shanghai
时区(Linux标准格式) - 提高性能:减少不必要的时区ID尝试,直接使用最常用的时区
- 代码简洁性:简化回退逻辑,提高代码可读性
- 移除Windows依赖:完全移除
China Standard Time
时区ID,专注于Linux系统优化
2024年修改记录
修复NetworkProtocolLogObserver中的StopChannelManager方法并支持重新创建
修改时间: 2024年12月 修改文件:
CoreAgent.Infrastructure/Services/Network/NetworkProtocolLogObserver.cs
CoreAgent.WebSocketTransport/Interfaces/IMessageChannelManager.cs
CoreAgent.WebSocketTransport/Services/MessageChannelManager.cs
修改内容:
-
问题描述:
StopChannelManager()
方法直接调用_ChannelManager.Dispose()
可能导致资源过早释放IMessageChannelManager
接口已实现IDisposable
,生命周期应由DI容器管理- 直接调用
Dispose()
可能影响其他使用该实例的组件
-
修复方案:
-
修改
MessageChannelManager
设计,不在构造函数中创建通道 -
移除构造函数中的默认参数,要求必须传入容量参数
-
添加容量参数验证,确保参数有效性
-
扩展
WebSocketConfig
配置类,添加分别的通道容量配置 -
更新依赖注入注册,从配置中读取不同的通道容量
-
优化通道管理方法,职责更加清晰:
CreateChannels()
- 安全创建(已存在则跳过)ClearAllChannels()
- 清空通道消息(保持通道可用)CompleteAllChannels()
- 完成通道(标记不再接受新消息,但保持可读)ReleaseChannels()
- 完全释放通道资源
-
将
StopChannelManager()
改为调用ReleaseChannels()
-
将
RecreateChannelManager()
改为调用CreateChannels()
-
优化通道创建逻辑:
- 修改
CreateChannels()
方法,如果通道已存在则先释放再创建 - 移除
ResetChannels()
方法,避免功能重复 - 简化接口设计,减少方法数量
- 修改
-
WebSocketTransport 集成通道管理:
- 重构
ConnectInternalAsync()
方法,提取为多个独立方法:CreateMessageChannels()
- 先创建消息通道(同步方法)EstablishWebSocketConnectionAsync()
- 再建立WebSocket连接(异步方法)StartBackgroundTasks()
- 最后启动后台任务(同步方法)
- 在
CloseAsync()
中调用_channelManager.ReleaseChannels()
释放通道 - 在重连失败时也释放通道,确保资源正确清理
- 通道生命周期与WebSocket连接生命周期完全同步
- 重构
-
添加自动重连配置选项:
- 在
WebSocketConfig
中添加EnableAutoReconnect
配置项 - 在
TriggerReconnect()
方法中添加配置检查 - 支持通过配置文件控制是否启用自动重连功能
- 在
-
修复WebSocket配置文件:
- 更新
websocket.json
和websocket.Development.json
配置文件 - 添加所有新增的配置项:
EnableAutoReconnect
、SendChannelCapacity
、ReceiveChannelCapacity
、PriorityChannelCapacity
、MaxChunkSize
、ChunkDelayMs
- 为开发环境和生产环境提供不同的配置值
- 更新
-
添加重复调用检查,避免二次调用导致异常
-
添加异常处理和日志记录
-
保持方法功能的同时避免资源管理问题
-
-
具体修改: IMessageChannelManager 接口新增方法:
/// <summary> /// 创建所有通道 /// </summary> void CreateChannels(); /// <summary> /// 释放所有通道 /// </summary> void ReleaseChannels();
MessageChannelManager 实现:
// 构造函数要求必须传入容量参数,并验证参数有效性 public MessageChannelManager(ILogger<MessageChannelManager> logger, int sendChannelCapacity, int receiveChannelCapacity, int priorityChannelCapacity) { // 验证容量参数 if (sendChannelCapacity <= 0) throw new ArgumentOutOfRangeException(...); // 保存容量配置,不创建通道 } // 安全创建通道(如果已存在则跳过) public void CreateChannels() { // 检查通道是否已存在,如果存在则跳过创建 } // 清空通道消息(保持通道可用) public void ClearAllChannels() { // 清空所有通道中的消息,但保持通道结构 } // 完成通道(标记不再接受新消息,但保持可读) public void CompleteAllChannels() { // 标记通道完成,不再接受新消息,但可以继续读取 } // 完全释放通道资源 public void ReleaseChannels() { // 完成通道,释放资源,清空引用 }
WebSocketConfig 配置扩展:
public class WebSocketConfig { // 是否启用自动重连功能 public bool EnableAutoReconnect { get; set; } = true; // 最大重连尝试次数 public int MaxReconnectAttempts { get; set; } = 5; // 发送通道容量 public int SendChannelCapacity { get; set; } = 1000; // 接收通道容量 public int ReceiveChannelCapacity { get; set; } = 1000; // 优先级通道容量 public int PriorityChannelCapacity { get; set; } = 100; }
依赖注入注册更新:
services.AddSingleton<IMessageChannelManager>(provider => { var config = provider.GetRequiredService<IOptions<WebSocketConfig>>().Value; return new MessageChannelManager(logger, config.SendChannelCapacity, config.ReceiveChannelCapacity, config.PriorityChannelCapacity); });
NetworkProtocolLogObserver 修改:
public void StopChannelManager() { // 调用 ReleaseChannels() 释放通道 _ChannelManager.ReleaseChannels(); } public void RecreateChannelManager() { // 调用 CreateChannels() 重新创建通道(会自动释放现有通道) _ChannelManager.CreateChannels(); }
WebSocketTransport 重构:
// 连接时先创建通道,再建立连接 private async Task ConnectInternalAsync(CancellationToken cancellationToken) { // 1. 先创建消息通道 await CreateMessageChannelsAsync(); // 2. 再建立 WebSocket 连接 await EstablishWebSocketConnectionAsync(cancellationToken); // 3. 最后启动后台任务 await StartBackgroundTasksAsync(); } // 提取的独立方法 private void CreateMessageChannels() { _channelManager.CreateChannels(); } private async Task EstablishWebSocketConnectionAsync(CancellationToken cancellationToken) { await _connection.ConnectAsync(...); } private void StartBackgroundTasks() { // 启动发送、接收、心跳任务 }
-
修复优势:
- 配置灵活性: 支持通过配置文件分别设置不同通道的容量,更加灵活
- 参数验证: 构造函数中验证容量参数,确保参数有效性
- 方法职责清晰: 每个方法职责明确,避免功能重叠
- 生命周期控制: 通道的创建和释放完全由用户控制,更加灵活
- 资源管理: 避免在构造函数中创建资源,符合延迟初始化原则
- 重复使用: 支持多次创建和释放,满足业务需求
- 重复调用保护: 防止二次调用导致异常,提高系统稳定性
- 异常处理: 添加了完整的异常处理和日志记录,但不影响主程序运行
- 业务连续性: 异常被捕获并记录,但不会中断主程序流程
- 功能保持: 仍然能够正确停止和重新创建通道管理器
- 日志完善: 提供了详细的调试和错误日志信息
创建蜂窝网络配置实体类
创建蜂窝网络配置实体类
修改时间: 2024年 修改文件:
CoreAgent.Domain/Models/Network/CellularNetworkConfiguration.cs
(新建)
修改内容:
-
创建CellularNetworkConfiguration实体类
- 包含设备代码(DeviceCode)字符串属性
- 包含运行时代码(RuntimeCode)字符串属性
- 包含无线接入网配置(RadioAccessNetworkConfiguration)字符串属性
- 包含核心网IMS配置集合(List)属性
-
创建CoreNetworkImsConfiguration实体类
- 包含索引(Index)整数属性
- 包含PLMN标识(Plmn)字符串属性
- 包含核心网配置(CoreNetworkConfiguration)字符串属性
- 包含IMS服务配置(ImsServiceConfiguration)字符串属性
-
具体实现:
/// <summary> /// 蜂窝网络配置实体 /// </summary> public class CellularNetworkConfiguration { /// <summary> /// 设备代码 /// </summary> public string DeviceCode { get; set; } /// <summary> /// 运行时代码 /// </summary> public string RuntimeCode { get; set; } /// <summary> /// 无线接入网配置 /// </summary> public string RadioAccessNetworkConfiguration { get; set; } /// <summary> /// 核心网IMS配置集合 /// </summary> public List<CoreNetworkImsConfiguration> CoreNetworkImsConfigurations { get; set; } = new List<CoreNetworkImsConfiguration>(); } /// <summary> /// 核心网IMS配置对象 /// </summary> public class CoreNetworkImsConfiguration { /// <summary> /// 索引 /// </summary> public int Index { get; set; } /// <summary> /// PLMN标识 /// </summary> public string Plmn { get; set; } /// <summary> /// 核心网配置 /// </summary> public string CoreNetworkConfiguration { get; set; } /// <summary> /// IMS服务配置 /// </summary> public string ImsServiceConfiguration { get; set; } }
-
设计优势:
- 命名规范:遵循C#命名约定,使用PascalCase
- 命名清晰:类名明确表达业务含义,提高代码可读性
- 属性专业:使用完整的专业术语,避免缩写和模糊命名
- 类型安全:使用强类型属性,避免类型错误
- 文档完整:每个属性都有详细的XML文档注释
- 集合初始化:使用集合初始化器确保集合不为null
- 职责清晰:每个类都有明确的职责和用途
- 易于扩展:结构清晰,便于后续添加新属性
- 业务导向:类名直接反映业务领域概念
- 专业术语:使用标准的电信网络术语,提高代码专业性
添加蜂窝网络配置数据校验功能
修改时间: 2024年 修改文件:
CoreAgent.Domain/Models/Network/CellularNetworkConfiguration.cs
修改内容:
-
添加数据校验功能
- 为
DeviceCode
和RuntimeCode
添加[Required]
特性,确保不能为空 - 为
Plmn
添加[Required]
特性,确保不能为空 - 添加
ValidateConfiguration()
方法进行业务逻辑校验
- 为
-
业务规则校验
- 验证
DeviceCode
和RuntimeCode
不能为空 - 验证
RadioAccessNetworkConfiguration
和CoreNetworkImsConfigurations
至少有一个有数据 - 验证
CoreNetworkImsConfiguration
中的CoreNetworkConfiguration
和ImsServiceConfiguration
至少有一个有数据
- 验证
-
创建ValidationResult类
- 提供统一的验证结果返回格式
- 支持成功和失败两种状态
- 提供详细的错误消息
- 支持隐式转换操作符
-
具体实现:
// 必填字段校验 [Required(ErrorMessage = "设备代码不能为空")] public string DeviceCode { get; set; } [Required(ErrorMessage = "运行时代码不能为空")] public string RuntimeCode { get; set; } // 业务逻辑校验 public ValidationResult ValidateConfiguration() { // 验证必填字段 if (string.IsNullOrWhiteSpace(DeviceCode)) { return new ValidationResult("设备代码不能为空"); } // 验证无线接入网配置和核心网IMS配置至少有一个有数据 var hasRadioAccessConfig = !string.IsNullOrWhiteSpace(RadioAccessNetworkConfiguration); var hasCoreNetworkConfigs = CoreNetworkImsConfigurations?.Any() == true; if (!hasRadioAccessConfig && !hasCoreNetworkConfigs) { return new ValidationResult("无线接入网配置和核心网IMS配置至少需要配置其中一项"); } return ValidationResult.Success; }
-
设计优势:
- 数据完整性:确保必填字段不为空
- 业务规则校验:验证业务逻辑的正确性
- 统一验证接口:提供一致的验证方法
- 详细错误信息:提供具体的错误描述
- 分层校验:支持嵌套对象的校验
- 易于扩展:可以轻松添加新的校验规则
影响范围:
- 蜂窝网络配置数据模型定义
- 核心网IMS配置管理
- 数据实体结构标准化
- 领域模型完整性
- 代码可读性和维护性提升
- 数据校验和业务规则验证
- 错误处理和用户反馈
创建MessageTransferProtocolLog模型解决命名冲突
修改时间: 2024年 修改文件:
CoreAgent.WebSocketTransport/Models/MessageTransferProtocolLog.cs
(新建)CoreAgent.Infrastructure/Services/Network/NetworkProtocolLogObserver.cs
修改内容:
-
创建MessageTransferProtocolLog模型
- 在
CoreAgent.WebSocketTransport
项目中创建新的协议日志模型 - 与
CoreAgent.ProtocolClient
中的TransferProtocolLog
区分开 - 保持相同的字段结构,避免命名冲突
- 专门用于WebSocket传输层的协议日志数据传输
- 在
-
修改NetworkProtocolLogObserver转换逻辑
- 在
OnProtocolLogsReceived
方法中添加类型转换 - 将
CoreAgent.ProtocolClient.TransferProtocolLog
转换为CoreAgent.WebSocketTransport.MessageTransferProtocolLog
- 保持所有字段的完整映射
- 添加必要的using语句引用
- 在
-
具体实现:
// 时间跟踪和性能监控 var startTime = DateTime.UtcNow; // 空值检查 if (logDetails == null) { _logger.LogWarning("接收到的协议日志为空"); return; } // 转换为列表以避免多次枚举 var logList = logDetails.ToList(); var logCount = logList.Count; // 空集合检查 if (logCount == 0) { _logger.LogDebug("接收到的协议日志集合为空,跳过处理"); return; } // 类型转换逻辑 var webSocketLogs = logList.Select(log => new MessageTransferProtocolLog { Id = log.Id, LayerType = log.LayerType.ToString(), MessageDetailJson = log.MessageDetailJson, CellID = log.CellID, IMSI = log.IMSI, Direction = log.Direction, UEID = log.UEID, PLMN = log.PLMN, TimeMs = log.TimeMs, Timestamp = log.Timestamp, Info = log.Info, Message = log.Message }); // 通道写入状态监控 var writeSuccess = _ChannelManager.SendChannel.TryWrite(webSocketLogs); var processingTime = DateTime.UtcNow - startTime; if (writeSuccess) { _logger.LogDebug("协议日志处理成功,数量: {LogCount}, 处理时间: {ProcessingTime}ms", logCount, processingTime.TotalMilliseconds); } else { _logger.LogWarning("协议日志写入通道失败,数量: {LogCount}, 处理时间: {ProcessingTime}ms, 通道可能已满或已关闭", logCount, processingTime.TotalMilliseconds); }
-
设计优势:
- 命名清晰:
MessageTransferProtocolLog
明确表示用于消息传输 - 避免冲突:与原始
TransferProtocolLog
有明确区分 - 职责分离:WebSocket传输层有独立的协议日志模型
- 类型安全:通过显式转换确保类型安全
- 易于维护:清晰的命名约定便于理解和维护
- 性能监控:添加时间跟踪和通道写入状态监控
- 错误处理:完善的异常处理和日志记录
- Bug修复:修复空引用检查和多次枚举的性能问题
- 边界处理:添加空集合检查,避免处理空集合
- 代码规范:优化ProtocolMessage模型注释,提高代码可读性
- 命名清晰:
影响范围:
- WebSocket传输层协议日志处理
- 协议日志观察者模式实现
- 跨项目类型转换逻辑
- 协议消息模型注释优化
CellularNetworkService.StartNetworkAsync 方法添加协议客户端配置创建
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs
修改内容:
-
调整执行步骤顺序
- 将原来的第5.5步改为第6步(创建协议客户端配置)
- 将WebSocket传输连接移到第7步(在网络配置启动之前)
- 重新编号后续步骤(8-11步)
- 优化执行顺序:确保WebSocket连接在网络配置启动之前完成
-
添加第7步WebSocket传输连接
- 在
StartNetworkAsync
方法的第6步(创建协议客户端配置)之后添加第7步 - 注入
IWebSocketTransport
依赖 - 创建独立的
StartWebSocketTransportAsync()
方法处理连接逻辑 - 返回
bool
值表示连接是否成功 - 添加连接状态检查和错误处理
- 严格检查:WebSocket连接失败时立即返回失败结果,提示服务端可能未启动
- 在
-
修复Logger类型问题
- 添加
ILoggerFactory
依赖注入到构造函数 - 使用
_loggerFactory.CreateLogger<ProtocolClientConfigFactory>()
创建正确类型的Logger - 确保
ProtocolClientConfigFactory
获得正确的Logger实例
- 添加
-
具体实现:
// 6. 创建协议客户端配置 var protocolConfigFactory = new ProtocolClientConfigFactory(_loggerFactory.CreateLogger<ProtocolClientConfigFactory>(), _context); var configCreated = protocolConfigFactory.CreateFromEntities(); if (configCreated) { _logger.LogInformation("协议客户端配置创建成功,共创建 {ConfigCount} 个配置", protocolConfigFactory.ConfigCount); } else { _logger.LogWarning("协议客户端配置创建失败"); return CellularNetworkOperationResult.Failure("协议客户端配置创建失败"); } // 7. 启动 WebSocket 传输连接 var webSocketConnected = await StartWebSocketTransportAsync(); if (!webSocketConnected) { _logger.LogError("WebSocket 传输连接启动失败,服务端可能未启动"); return CellularNetworkOperationResult.Failure("WebSocket 传输连接启动失败,服务端可能未启动"); } _logger.LogInformation("WebSocket 传输连接启动成功");
-
添加必要的依赖注入
- 添加
ILoggerFactory loggerFactory
参数到构造函数 - 添加
IWebSocketTransport webSocketTransport
参数到构造函数 - 添加
using CoreAgent.Infrastructure.Services.Network;
以支持ProtocolClientConfigFactory
- 添加
using CoreAgent.WebSocketTransport.Interfaces;
以支持IWebSocketTransport
- 添加
-
设计优势:
- 在IP端点信息准备完成后立即创建协议客户端配置
- 不依赖网络启动结果,确保配置创建的独立性
- 在网络配置启动之前启动WebSocket传输连接
- 提供详细的日志记录便于调试
- 保持代码的简洁性和可维护性
- 正确处理Logger类型,避免类型不匹配问题
- 优化执行顺序,提高错误隔离能力
- 完善的错误处理机制,确保配置创建失败时及时停止
- 严格检查机制,WebSocket连接失败时立即停止网络启动流程
- 方法职责单一,WebSocket连接逻辑独立封装
影响范围:
- 蜂窝网络启动流程
- 协议客户端配置管理
- WebSocket传输服务集成
- 网络状态监控
- 依赖注入配置(需要更新服务注册)
CellularNetworkService构造函数添加IProtocolLogObserver依赖
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs
修改内容:
-
添加IProtocolLogObserver依赖注入
- 在构造函数中添加
IProtocolLogObserver protocolLogObserver
参数 - 添加私有字段
_protocolLogObserver
存储依赖 - 添加空值检查和异常抛出
- 在构造函数中添加
-
添加必要的using语句
- 添加
using CoreAgent.ProtocolClient.ProtocolEngineCore;
以支持IProtocolLogObserver
- 添加
-
具体实现:
// 构造函数参数 public CellularNetworkService( // ... 其他参数 IWebSocketTransport webSocketTransport, IProtocolLogObserver protocolLogObserver) // 私有字段 private readonly IProtocolLogObserver _protocolLogObserver; // 构造函数初始化 _protocolLogObserver = protocolLogObserver ?? throw new ArgumentNullException(nameof(protocolLogObserver));
-
设计优势:
- 为后续协议客户端管理提供必要的依赖
- 保持依赖注入的一致性
- 提供空值检查确保服务稳定性
- 为协议日志观察者模式提供支持
影响范围:
- 蜂窝网络服务依赖注入配置
- 协议客户端日志观察者集成
- 服务注册配置更新
StartNetworkAsync方法添加时间跟踪记录
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs
修改内容:
-
添加整体时间跟踪
- 在方法开始时记录开始时间
- 在方法结束时计算总耗时并记录
- 使用UTC时间确保时间一致性
-
为每个步骤添加详细时间跟踪
- 为11个步骤中的每个步骤添加开始和结束时间记录
- 使用
LogDebug
级别记录每个步骤的耗时 - 保持原有的
LogInformation
和LogError
级别日志不变
-
具体实现:
// 方法开始时间跟踪 var startTime = DateTime.UtcNow; _logger.LogInformation("开始启动网络配置 {ConfigKey},开始时间: {StartTime}", key, startTime.ToString("yyyy-MM-dd HH:mm:ss.fff")); // 每个步骤的时间跟踪 var stepXStart = DateTime.UtcNow; _logger.LogDebug("步骤X开始:[步骤描述]"); // 步骤执行逻辑... var stepXDuration = (DateTime.UtcNow - stepXStart).TotalMilliseconds; _logger.LogDebug("步骤X完成:[步骤描述],耗时: {Duration}ms", stepXDuration.ToString("F2")); // 方法结束时间跟踪 var endTime = DateTime.UtcNow; var duration = endTime - startTime; _logger.LogInformation("蜂窝网络配置 {ConfigKey} 启动成功,当前状态: {Status},总耗时: {Duration}ms", key, state.CurrentStatus, duration.TotalMilliseconds.ToString("F2"));
-
设计优势:
- 性能监控:可以识别网络启动过程中的性能瓶颈
- 调试支持:详细的时间信息有助于问题定位和性能优化
- 日志分级:使用Debug级别避免生产环境日志过多
- 时间精度:使用毫秒级精度提供准确的性能数据
- UTC时间:确保时间记录的一致性和准确性
- 非侵入性:不影响原有的业务逻辑和错误处理
-
跟踪的步骤:
- 步骤1:获取并验证网络配置
- 步骤2:执行网络接口初始化命令
- 步骤3:复制配置值到临时目录
- 步骤4:获取并验证 IP 端点信息
- 步骤5:更新 IP 端点管理器
- 步骤6:创建协议客户端配置
- 步骤7:启动 WebSocket 传输连接
- 步骤8:启动网络配置
- 步骤9:更新网络配置类型
- 步骤10:检查网络端点连接状态
- 步骤11:更新网络状态
影响范围:
- 网络启动性能监控
- 调试和问题定位
- 日志记录详细程度
- 性能优化分析
ProtocolWsClientManager方法参数优化
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/ProtocolWsClientManager.cs
修改内容:
-
简化构造函数
- 移除
ProtocolClientConfig[] configs
参数 - 构造函数只保留必要的依赖:
ILogger
、IProtocolLogObserver
、ILoggerFactory
- 移除私有字段
_configs
,不再在构造函数中存储配置
- 移除
-
修改StartAllClients方法签名
- 添加
ProtocolClientConfig[] configs
参数 - 方法接收配置数组作为参数,而不是依赖构造函数中的配置
- 添加参数验证,检查
configs
是否为 null 或空数组
- 添加
-
优化方法逻辑
- 将配置验证移到方法开始处
- 使用传入的
configs
参数替代私有字段 - 保持原有的客户端创建和启动逻辑不变
-
具体实现:
// 构造函数简化 public ProtocolWsClientManager( ILogger<ProtocolWsClientManager> logger, IProtocolLogObserver protocolLogObserver, ILoggerFactory loggerFactory) // 移除 configs 参数 // StartAllClients方法修改 public void StartAllClients(ProtocolClientConfig[] configs) // 添加参数 { if (configs == null || configs.Length == 0) // 参数验证 { _logger.LogWarning("没有可用的协议客户端配置"); return; } // 使用传入的 configs 参数 _logger.LogInformation("开始启动所有协议客户端,配置数量: {ConfigCount}", configs.Length); foreach (var config in configs) // 遍历传入的配置
-
设计优势:
- 更灵活的使用方式:可以在不同时间传入不同的配置
- 减少内存占用:不需要在构造函数中存储配置数组
- 简化构造函数:降低构造函数的复杂度
- 更好的测试性:可以更容易地测试不同的配置组合
- 符合单一职责原则:构造函数只负责初始化,方法负责执行具体操作
影响范围:
- 协议客户端管理器使用方式
- 配置传递方式
- 调用方代码适配
- 测试用例更新
ProtocolWsClientManager采用面向接口编程
修改时间: 2024年 修改文件:
CoreAgent.ProtocolClient/Interfaces/IProtocolWsClientManager.cs
(新建)CoreAgent.Infrastructure/Services/Network/ProtocolWsClientManager.cs
修改内容:
-
创建IProtocolWsClientManager接口
- 在CoreAgent.ProtocolClient项目中定义接口契约
- 继承
IDisposable
接口 - 定义
StartAllClients
和StopAllClients
方法 - 使用
ProtocolClientConfig[]
作为参数类型
-
修改ProtocolWsClientManager实现类
- 实现
IProtocolWsClientManager
接口 - 添加
using CoreAgent.ProtocolClient.Interfaces;
引用 - 保持原有的实现逻辑不变
- 实现
-
具体实现:
// 接口定义 public interface IProtocolWsClientManager : IDisposable { void StartAllClients(ProtocolClientConfig[] configs); void StopAllClients(); } // 实现类 public class ProtocolWsClientManager : IProtocolWsClientManager { // 原有实现保持不变 }
-
设计优势:
- 依赖倒置:高层模块依赖抽象,不依赖具体实现
- 易于测试:可以轻松创建Mock实现进行单元测试
- 松耦合:降低组件间的耦合度
- 可扩展性:可以轻松添加新的实现类
- 符合SOLID原则:遵循依赖倒置原则和开闭原则
- 便于依赖注入:可以注册接口而不是具体实现
-
接口设计原则:
- 单一职责:接口只定义协议客户端管理的核心功能
- 简洁明了:只包含必要的方法定义
- 易于理解:方法名称和参数清晰明确
- 向后兼容:保持与原有API的兼容性
影响范围:
- 依赖注入配置更新
- 服务注册方式调整
- 单元测试Mock创建
- 调用方代码适配(使用接口类型)
- 项目引用关系调整(CoreAgent.ProtocolClient项目包含接口定义)
CellularNetworkService集成IProtocolWsClientManager
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs
修改内容:
-
添加IProtocolWsClientManager依赖注入
- 在构造函数中添加
IProtocolWsClientManager protocolWsClientManager
参数 - 添加私有字段
_protocolWsClientManager
存储依赖 - 添加空值检查和异常抛出
- 在构造函数中添加
-
StartNetworkAsync方法添加第12步
- 在步骤11(更新网络状态)之后添加第12步
- 调用
protocolConfigFactory.GetAllConfigs()
获取配置数组 - 调用
_protocolWsClientManager.StartAllClients(protocolConfigs)
启动所有协议客户端 - 添加时间跟踪和错误处理
- 如果启动失败,立即返回失败结果
-
StopAsync方法集成协议客户端停止
- 在步骤4(禁用网络配置)之后添加步骤5(停止所有协议客户端)
- 调用
_protocolWsClientManager.StopAllClients()
停止所有协议客户端 - 添加错误处理,但不中断停止流程
- 重新编号后续步骤(6-9步)
-
修复StopWebSocketTransportAsync方法
- 修正方法实现,使用
CloseAsync()
而不是DisconnectAsync()
- 修正日志信息和返回值逻辑
- 确保方法名称和实现一致
- 修正方法实现,使用
-
具体实现:
// 构造函数添加依赖 public CellularNetworkService( // ... 其他参数 IProtocolWsClientManager protocolWsClientManager) // StartNetworkAsync第12步 // 12. 启动所有协议客户端 var protocolConfigs = protocolConfigFactory.GetAllConfigs(); _protocolWsClientManager.StartAllClients(protocolConfigs); // StopAsync步骤5 // 5. 停止所有协议客户端 _protocolWsClientManager.StopAllClients();
-
设计优势:
- 完整的生命周期管理:启动和停止时都正确处理协议客户端
- 错误隔离:启动失败时立即停止,停止失败时继续执行
- 时间跟踪:为协议客户端操作添加详细的时间记录
- 依赖注入:使用接口编程,便于测试和扩展
- 日志完整:提供详细的启动和停止日志记录
影响范围:
- 蜂窝网络服务依赖注入配置
- 协议客户端生命周期管理
- 网络启动和停止流程
- 服务注册配置更新
LogLayerHelp类名规范化
修改时间: 2024年 修改文件:
- `
ProtocolWsClientManager方法返回类型优化
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/ProtocolWsClientManager.cs
CoreAgent.ProtocolClient/Interfaces/IProtocolWsClientManager.cs
修改内容:
-
StartAllClients方法返回类型修改
- 将返回类型从
void
改为bool
- 添加连接状态检查逻辑,使用
client.IsConnected
判断连接状态 - 统计已连接的客户端数量
- 返回
bool
值表示是否所有客户端都成功启动并连接 - 添加详细的日志记录,包括连接状态信息
- 将返回类型从
-
StopAllClients方法返回类型修改
- 将返回类型从
void
改为bool
- 添加断开连接状态检查逻辑,使用
client.IsConnected
判断连接状态 - 记录停止前的连接状态和停止后的连接状态
- 统计已断开连接的客户端数量
- 返回
bool
值表示是否所有客户端都成功停止并断开连接 - 添加详细的日志记录,包括连接状态变化信息
- 将返回类型从
-
GetAllClientsStatus方法修复
- 修复语法错误,完善方法实现
- 添加线程安全锁保护
- 遍历所有客户端并记录其状态信息
- 包括客户端名称、连接状态(IsConnected)和客户端状态(State)
- 添加空客户端检查
-
接口定义更新
- 更新
IProtocolWsClientManager
接口中的方法签名 StartAllClients
方法返回bool
类型StopAllClients
方法返回bool
类型- 添加详细的XML文档注释说明返回值含义
- 更新
-
具体实现:
// StartAllClients方法 public bool StartAllClients(ProtocolClientConfig[] configs) { // 检查连接状态 if (existingClient.IsConnected) { connectedCount++; } var allConnected = connectedCount == configs.Length; return allConnected; } // StopAllClients方法 public bool StopAllClients() { var client = kvp.Value; var wasConnected = client.IsConnected; client.Stop(); // 检查连接状态 if (!client.IsConnected) { disconnectedCount++; } var allDisconnected = disconnectedCount == _clients.Count; return allDisconnected; } // GetAllClientsStatus方法 public void GetAllClientsStatus() { foreach (var kvp in _clients) { var client = kvp.Value; _logger.LogInformation("客户端状态 - 名称: {ClientName}, 连接状态: {IsConnected}, 客户端状态: {State}", kvp.Key, client.IsConnected, client.State); } }
-
设计优势:
- 状态可追踪:通过返回值可以明确知道操作是否完全成功
- 连接状态监控:使用
IsConnected
属性准确判断连接状态 - 详细日志记录:提供完整的操作过程和状态变化日志
- 线程安全:使用锁保护共享资源访问
- 错误处理完善:提供详细的错误信息和状态统计
- 接口一致性:接口和实现保持完全一致
- 向后兼容:保持方法签名的一致性,只改变返回类型
-
返回值含义:
StartAllClients
返回true
:所有客户端都成功启动并连接StartAllClients
返回false
:部分或全部客户端启动失败或未连接StopAllClients
返回true
:所有客户端都成功停止并断开连接StopAllClients
返回false
:部分或全部客户端停止失败或仍保持连接
影响范围:
- 协议客户端管理器接口契约
- 调用方代码需要处理返回值
- 网络启动和停止流程的状态判断
- 日志记录详细程度提升
- 错误处理和状态监控能力增强
WebSocket传输服务依赖注入修复
修改时间: 2024年 修改文件:
CoreAgent.WebSocketTransport/Extensions/WebSocketTransportExtensions.cs
CoreAgent.API/Startup.cs
修改内容:
-
修复依赖注入顺序问题
- 将
RegisterDefaultMiddleware
移到RegisterCoreServices
之前调用 - 确保中间件在核心服务注册之前就已经注册到容器中
- 解决
provider.GetServices<IMessageMiddleware>()
无法找到服务的问题
- 将
-
修复CacheMiddleware注册方式
- 将
CacheMiddleware
的注册方式从手动工厂方法改为使用AddWebSocketMiddleware<T>
- 简化注册逻辑,确保依赖注入容器能正确处理构造函数参数
- 移除复杂的工厂方法注册,使用标准的依赖注入模式
- 将
-
添加IMemoryCache服务注册
- 在
Startup.cs
的ConfigureServices
方法中添加services.AddMemoryCache()
- 确保
CacheMiddleware
能够正确获取IMemoryCache
依赖 - 在 WebSocket 传输服务注册之前添加内存缓存服务
- 在
-
具体实现:
// WebSocketTransportExtensions.cs - 调整注册顺序 public static IServiceCollection AddWebSocketTransport(...) { // 注册配置 services.Configure<WebSocketConfig>(...); // 注册默认中间件(在核心服务之前) RegisterDefaultMiddleware(services); // 注册核心服务 RegisterCoreServices(services); return services; } // Startup.cs - 添加内存缓存服务 public void ConfigureServices(IServiceCollection services) { // ... 其他服务注册 ... // 添加内存缓存服务(WebSocket中间件需要) services.AddMemoryCache(); // 添加 WebSocket 传输服务 services.AddWebSocketTransport(Configuration, "WebSocket"); }
-
设计优势:
- 依赖顺序正确:确保中间件在核心服务之前注册
- 简化注册逻辑:使用标准的依赖注入模式
- 完整的服务注册:包含所有必要的依赖服务
- 错误预防:避免运行时依赖注入异常
- 代码清晰:注册逻辑更加直观和易于理解
-
修复的问题:
System.InvalidOperationException: Cannot resolve scoped service 'System.Collections.Generic.IEnumerable
1[CoreAgent.WebSocketTransport.Middleware.IMessageMiddleware]' from root provider`- 依赖注入容器无法找到
IMessageMiddleware
服务 CacheMiddleware
无法获取IMemoryCache
依赖
影响范围:
- WebSocket传输服务的依赖注入配置
- 中间件注册和初始化顺序
- 应用程序启动时的服务注册
- 内存缓存服务的可用性
- 错误处理和异常预防
CacheMiddleware构造函数依赖注入修复
修改时间: 2024年 修改文件:
CoreAgent.WebSocketTransport/Middleware/CacheMiddleware.cs
修改内容:
-
修复构造函数参数类型
- 将构造函数参数从
WebSocketConfig config
改为IOptions<WebSocketConfig> config
- 添加
using Microsoft.Extensions.Options;
引用 - 在构造函数中通过
config?.Value
获取配置值
- 将构造函数参数从
-
增强空值检查
- 为所有构造函数参数添加空值检查和异常抛出
- 使用
ArgumentNullException
确保参数有效性 - 提供更明确的错误信息
-
具体实现:
// 修复前 public CacheMiddleware(IMemoryCache cache, ILogger<CacheMiddleware> logger, WebSocketConfig config) { _cache = cache; _logger = logger; _config = config; } // 修复后 public CacheMiddleware(IMemoryCache cache, ILogger<CacheMiddleware> logger, IOptions<WebSocketConfig> config) { _cache = cache ?? throw new ArgumentNullException(nameof(cache)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _config = config?.Value ?? throw new ArgumentNullException(nameof(config)); }
-
设计优势:
- 正确的依赖注入模式:使用
IOptions<T>
模式获取配置 - 强化的错误处理:提供详细的空值检查和异常信息
- 类型安全:确保配置对象正确获取
- 符合最佳实践:遵循 .NET 依赖注入的标准模式
- 正确的依赖注入模式:使用
-
修复的问题:
Unable to resolve service for type 'CoreAgent.WebSocketTransport.Models.WebSocketConfig'
- 依赖注入容器无法直接解析
WebSocketConfig
类型 - 中间件构造函数参数类型不匹配
影响范围:
- CacheMiddleware的依赖注入配置
- WebSocket传输服务的启动
- 配置对象的正确获取
- 错误处理和异常预防
WebSocket中间件生命周期修复
修改时间: 2024年 修改文件:
CoreAgent.WebSocketTransport/Extensions/WebSocketTransportExtensions.cs
修改内容:
-
修复生命周期不匹配问题
- 将中间件注册从
AddScoped
改为AddTransient
- 解决单例服务无法解析作用域服务的问题
- 确保中间件每次使用都创建新实例
- 将中间件注册从
-
生命周期分析
IWebSocketTransport
注册为Singleton
(单例)- 中间件注册为
Transient
(瞬时) - 单例服务可以安全地解析瞬时服务
- 每次获取中间件都会创建新实例
-
具体实现:
// 修复前 services.AddScoped<IMessageMiddleware, T>(); // 修复后 services.AddTransient<IMessageMiddleware, T>();
-
设计优势:
- 生命周期兼容:瞬时服务可以被单例服务安全解析
- 性能优化:中间件每次使用都是新实例,避免状态污染
- 线程安全:瞬时服务天然线程安全
- 内存管理:中间件使用完毕后自动释放
-
修复的问题:
Cannot resolve scoped service 'System.Collections.Generic.IEnumerable
1[CoreAgent.WebSocketTransport.Middleware.IMessageMiddleware]' from root provider`- 单例服务无法解析作用域服务的依赖注入异常
- 生命周期不匹配导致的运行时错误
-
生命周期说明:
- Singleton: 整个应用程序生命周期内只有一个实例
- Scoped: 每个请求作用域内有一个实例
- Transient: 每次请求都创建新实例
- 单例服务只能解析瞬时服务,不能解析作用域服务
影响范围:
- WebSocket中间件的生命周期管理
- 依赖注入容器的服务解析
- 应用程序启动时的服务注册
- 中间件的实例化策略
- 性能和内存使用优化
NetworkConfigCopier方法Bug修复和日志增强
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs
CoreAgent.Domain/Models/Network/NetworkConfigCopyResult.cs
CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs
修改内容:
-
返回类型统一化
- 统一返回类型:所有方法都返回
NetworkConfigCopyResult
类型,不再抛出异常 - 泛型结果类型:创建
NetworkConfigCopyResult<T>
泛型类,支持返回数据 - 接口更新:更新
INetworkConfigCopier
接口以匹配新的返回类型 - 错误处理改进:使用结果对象而不是异常来处理错误情况
- 统一返回类型:所有方法都返回
-
CreateCellularNetworkConfigurationFile方法修复
- 返回类型修改:从
Task<NetworkConfiguration>
改为Task<NetworkConfigCopyResult>
- 路径构建Bug修复:修复
Path.Combine
使用不当的问题,正确构建文件路径 - 参数验证增强:添加完整的参数空值检查,返回失败结果而不是抛出异常
- 目录创建:确保目标目录存在,避免文件写入失败
- 详细日志:添加每个步骤的详细日志记录,包括开始、成功、警告和错误信息
- 返回类型修改:从
-
CreateRadioAccessNetworkConfigurationFile方法修复
- 返回类型修改:从
Task<bool>
改为Task<NetworkConfigCopyResult>
- 参数命名规范化:使用小写开头的参数名,符合C#命名约定
- 目录创建逻辑:添加目录存在性检查和自动创建
- 错误处理增强:返回失败结果而不是抛出异常
- 参数验证:验证文件路径和配置内容不为空
- 返回类型修改:从
-
CreateCoreNetworkImsConfigurationFiles方法重构
- 返回类型修改:从
Task<List<CoreImsConfig>>
改为Task<NetworkConfigCopyResult<List<CoreImsConfig>>>
- 方法重命名:避免与RAN配置文件创建方法名冲突
- 参数验证完善:验证RuntimeCode、配置列表和AppSettings
- 配置项验证:验证每个配置项的PLMN和配置内容
- 目录创建:为CN和IMS配置文件分别创建目录
- 错误隔离:单个配置项失败不影响其他配置项处理
- 详细日志:记录每个配置项的处理过程和结果
- 返回类型修改:从
-
DeleteCellularNetworkConfigurationFile方法增强
- 返回类型修改:从
bool
改为NetworkConfigCopyResult
- 文件存在性检查:删除前检查文件是否存在,避免异常
- 错误隔离:单个文件删除失败不影响其他文件删除
- 删除统计:统计成功删除的文件数量
- 详细日志:记录每个文件的删除状态和结果
- 参数验证:验证NetworkConfiguration参数不为空
- 返回类型修改:从
-
NetworkConfigCopyResult类扩展
- 泛型支持:添加
NetworkConfigCopyResult<T>
泛型类 - 数据返回:支持返回操作结果的同时返回数据
- 继承关系:泛型类继承自基础类,保持类型安全
- 静态工厂方法:提供
Success(T data)
和Failure(string errorMessage)
方法
- 泛型支持:添加
-
具体修复的Bug:
// 修复前 - 路径构建错误 string RanConfigPath = $"{appSettings.RanConfigDirectory}{Path.Combine("RAN", $"{cellular.RuntimeCode}.cfg")}"; // 修复后 - 正确的路径构建 string ranConfigPath = Path.Combine(appSettings.RanConfigDirectory, "RAN", $"{cellular.RuntimeCode}.cfg"); // 修复前 - 抛出异常 throw new ArgumentNullException(nameof(cellular)); // 修复后 - 返回失败结果 return NetworkConfigCopyResult.Failure("CellularNetworkConfiguration 参数为空"); // 修复前 - 返回原始类型 public async Task<NetworkConfiguration> CreateCellularNetworkConfigurationFile(...) // 修复后 - 返回结果类型 public async Task<NetworkConfigCopyResult> CreateCellularNetworkConfigurationFile(...)
-
设计优势:
- 统一错误处理:所有方法都使用结果对象,避免异常传播
- 类型安全:泛型结果类型确保类型安全
- Bug修复:修复路径构建、方法名冲突、文件删除等关键Bug
- 错误处理完善:添加完整的错误处理和错误隔离机制
- 日志详细:提供完整的操作跟踪和调试信息
- 参数验证:确保所有输入参数的有效性
- 目录管理:自动创建必要的目录结构
- 错误隔离:单个操作失败不影响整体流程
- 命名规范:遵循C#命名约定,提高代码可读性
- 方法职责清晰:每个方法都有明确的职责和边界
-
修复的关键问题:
- 异常处理不一致:统一使用结果对象而不是异常
- 路径构建错误:
Path.Combine
使用不当导致路径错误 - 方法名冲突:两个不同功能的方法使用相同名称
- 文件删除异常:删除不存在的文件导致异常
- 目录不存在:目标目录不存在导致文件写入失败
- 错误传播:单个错误导致整个操作失败
- 日志缺失:缺少关键操作的日志记录
影响范围:
- 网络配置文件创建和删除的稳定性
- 错误处理和异常预防
- 日志记录和调试能力
- 代码可读性和维护性
- 文件系统操作的可靠性
- 配置管理的完整性
- 接口契约的一致性
- 调用方代码的错误处理方式
NetworkConfigCopier返回类型优化和GeneralCellularNetworkService适配
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs
CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs
CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
修改内容:
-
CreateCellularNetworkConfigurationFile返回类型优化
- 返回类型修改:从
Task<NetworkConfigCopyResult>
改为Task<NetworkConfigCopyResult<NetworkConfiguration>>
- 数据返回:成功时返回包含
NetworkConfiguration
对象的结果 - 接口更新:更新接口定义以匹配新的返回类型
- 调用方适配:修改调用方代码以正确使用返回的数据
- 返回类型修改:从
-
GeneralCellularNetworkService调用修复
- 返回类型适配:修改调用方式以适配新的泛型返回类型
- 数据获取:直接从结果对象的
Data
属性获取NetworkConfiguration
- 错误处理改进:使用
IsSuccess
属性检查操作是否成功 - 代码简化:移除手动创建
NetworkConfiguration
的代码
-
接口定义更新
- 泛型支持:接口方法返回
Task<NetworkConfigCopyResult<NetworkConfiguration>>
- 文档更新:更新XML文档注释说明返回的数据类型
- 泛型支持:接口方法返回
-
具体修改:
// NetworkConfigCopier.cs - 返回类型修改 // 修复前 public async Task<NetworkConfigCopyResult> CreateCellularNetworkConfigurationFile(...) { // ... 创建NetworkConfiguration对象 return NetworkConfigCopyResult.Success(); // 没有返回数据 } // 修复后 public async Task<NetworkConfigCopyResult<NetworkConfiguration>> CreateCellularNetworkConfigurationFile(...) { // ... 创建NetworkConfiguration对象 return NetworkConfigCopyResult<NetworkConfiguration>.Success(network); // 返回数据 } // GeneralCellularNetworkService.cs - 调用修复 // 修复前 - 手动创建配置对象 var createResult = await _configCopier.CreateCellularNetworkConfigurationFile(cellular, _context.GetAppSettings()); if (!createResult.IsSuccess) { return CellularNetworkOperationResult.Failure($"创建网络配置文件失败: {createResult.ErrorMessage}"); } var config = NetworkConfiguration.Create(cellular.RuntimeCode, Path.Combine(_context.GetAppSettings().RanConfigDirectory, "RAN", $"{cellular.RuntimeCode}.cfg"), new List<CoreImsConfig>()); // 修复后 - 直接使用返回的数据 var createResult = await _configCopier.CreateCellularNetworkConfigurationFile(cellular, _context.GetAppSettings()); if (!createResult.IsSuccess) { return CellularNetworkOperationResult.Failure($"创建网络配置文件失败: {createResult.ErrorMessage}"); } var config = createResult.Data; // 直接获取返回的NetworkConfiguration对象
-
设计优势:
- 数据完整性:返回完整的
NetworkConfiguration
对象,包含所有配置信息 - 类型安全:泛型结果类型确保类型安全
- 代码简化:调用方无需手动创建配置对象
- 错误处理统一:保持统一的错误处理模式
- 接口一致性:接口和实现保持完全一致
- 数据完整性:返回完整的
-
修复的关键问题:
- 数据丢失:原方法创建了
NetworkConfiguration
但没有返回 - 代码重复:调用方需要手动创建配置对象
- 类型不匹配:返回类型与实际需求不匹配
- 接口不一致:接口定义与实际实现不一致
- 数据丢失:原方法创建了
影响范围:
- 网络配置创建流程的数据完整性
- 调用方代码的简化
- 接口契约的一致性
- 类型安全和错误处理
修改CreateCellularNetworkConfigurationFile为元组返回
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs
CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs
CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
修改内容:
-
修改CreateCellularNetworkConfigurationFile返回类型
- 将返回类型从
Task<NetworkConfigCopyResult<NetworkConfiguration>>
改为元组Task<(bool IsSuccess, string ErrorMessage, NetworkConfiguration NetworkConfiguration)>
- 简化返回结构,直接返回三个值:是否成功、错误信息、网络配置对象
- 将返回类型从
-
更新接口定义
- 更新
INetworkConfigCopier
接口中的方法签名 - 更新XML文档注释说明新的返回类型
- 更新
-
更新调用代码
- 修改
GeneralCellularNetworkService.cs
中的调用逻辑 - 使用元组解构语法
var (isSuccess, errorMessage, config) = await ...
- 直接使用解构后的变量
- 修改
-
具体实现:
// 修改前 public async Task<NetworkConfigCopyResult<NetworkConfiguration>> CreateCellularNetworkConfigurationFile(...) { return NetworkConfigCopyResult<NetworkConfiguration>.Failure("错误信息"); return NetworkConfigCopyResult<NetworkConfiguration>.Success(network); } // 修改后 public async Task<(bool IsSuccess, string ErrorMessage, NetworkConfiguration NetworkConfiguration)> CreateCellularNetworkConfigurationFile(...) { return (false, "错误信息", null); return (true, null, network); }
-
调用代码修改:
// 修改前 var createResult = await _configCopier.CreateCellularNetworkConfigurationFile(cellular, _context.GetAppSettings()); if (!createResult.IsSuccess) { return CellularNetworkOperationResult.Failure($"创建网络配置文件失败: {createResult.ErrorMessage}"); } var config = createResult.Data; // 修改后 var (isSuccess, errorMessage, config) = await _configCopier.CreateCellularNetworkConfigurationFile(cellular, _context.GetAppSettings()); if (!isSuccess) { return CellularNetworkOperationResult.Failure($"创建网络配置文件失败: {errorMessage}"); }
-
设计优势:
- 简洁性:元组返回比包装类更简洁
- 直观性:直接返回三个值,语义更清晰
- 性能:避免创建额外的包装对象
- 易用性:使用元组解构语法,代码更简洁
- 类型安全:保持强类型,编译时检查
影响范围:
- 网络配置创建方法的返回类型简化
- 调用代码的简化
- 接口定义的更新
- 代码可读性的提升
修改CreateCoreNetworkImsConfigurationFiles为元组返回
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs
修改内容:
-
修改CreateCoreNetworkImsConfigurationFiles返回类型
- 将返回类型从
Task<NetworkConfigCopyResult<List<CoreImsConfig>>>
改为元组Task<(bool IsSuccess, string ErrorMessage, List<CoreImsConfig> CoreImsConfigs)>
- 简化返回结构,直接返回三个值:是否成功、错误信息、核心IMS配置列表
- 将返回类型从
-
更新调用代码
- 修改
CreateCellularNetworkConfigurationFile
方法中对CreateCoreNetworkImsConfigurationFiles
的调用 - 使用元组解构语法
var (coreImsSuccess, coreImsError, coreImsConfigs) = await ...
- 直接使用解构后的变量
- 修改
-
具体实现:
// 修改前 public async Task<NetworkConfigCopyResult<List<CoreImsConfig>>> CreateCoreNetworkImsConfigurationFiles(...) { return NetworkConfigCopyResult<List<CoreImsConfig>>.Failure("错误信息"); return NetworkConfigCopyResult<List<CoreImsConfig>>.Success(list); } // 修改后 public async Task<(bool IsSuccess, string ErrorMessage, List<CoreImsConfig> CoreImsConfigs)> CreateCoreNetworkImsConfigurationFiles(...) { return (false, "错误信息", null); return (true, null, list); }
-
调用代码修改:
// 修改前 var coreImsResult = await CreateCoreNetworkImsConfigurationFiles(cellular.RuntimeCode, cellular.CoreNetworkImsConfigurations, appSettings); if (!coreImsResult.IsSuccess) { return (false, $"创建核心网络和IMS配置文件失败: {coreImsResult.ErrorMessage}", null); } list = coreImsResult.Data; // 修改后 var (coreImsSuccess, coreImsError, coreImsConfigs) = await CreateCoreNetworkImsConfigurationFiles(cellular.RuntimeCode, cellular.CoreNetworkImsConfigurations, appSettings); if (!coreImsSuccess) { return (false, $"创建核心网络和IMS配置文件失败: {coreImsError}", null); } list = coreImsConfigs;
-
设计优势:
- 一致性:与
CreateCellularNetworkConfigurationFile
方法保持相同的返回模式 - 简洁性:元组返回比包装类更简洁
- 直观性:直接返回三个值,语义更清晰
- 性能:避免创建额外的包装对象
- 易用性:使用元组解构语法,代码更简洁
- 一致性:与
-
接口说明:
CreateCoreNetworkImsConfigurationFiles
是内部方法,不在接口中定义- 只在
NetworkConfigCopier
实现类中使用 - 保持接口的简洁性
影响范围:
- 核心网络和IMS配置文件创建方法的返回类型简化
- 内部方法调用代码的简化
- 代码一致性的提升
- 性能的优化
ProtocolLogProcessor.ProcessLogDetails方法Info字段过滤修复
修改时间: 2024年12月 修改文件:
CoreAgent.ProtocolClient/ProtocolEngineCore/ProtocolLogProcessor.cs
修改内容:
-
修复foreach循环中的Info字段检查
- 在
ProcessLogDetails
方法的foreach
循环中移除Info
字段不为空的检查 - 允许处理所有日志记录,包括
Info
为空的记录 - 保持完整的日志处理和输出功能
- 在
-
修复_protocolLogObserver.OnProtocolLogsReceived调用
- 在调用
_protocolLogObserver.OnProtocolLogsReceived(logDetails)
之前过滤掉Info
为空或无效的记录 - 使用
!string.IsNullOrWhiteSpace(detail.Info)
进行过滤,确保Info字段不为null、空字符串或只包含空白字符 - 确保传递给观察者的数据中只包含有效的
Info
字段 - 添加空集合检查,避免传递空集合给观察者
- 在调用
-
具体实现:
// 修复前 foreach (var detail in logDetails) { try { // 检查Info字段不为空 if (!string.IsNullOrEmpty(detail.Info)) { Console.WriteLine($"处理日志详情:Time={detail.Time} Layer={detail.LayerType}, UEID={detail.UEID}, IMSI={detail.IMSI},PLMN={detail.PLMN},INFO={detail.Info},Messsage={detail.Message}"); // 这里可以添加具体的业务处理逻辑 // 例如:保存到数据库、发送到其他服务等 _logger.LogDebug($"处理日志详情: Layer={detail.LayerType}, UEID={detail.UEID}, IMSI={detail.IMSI}"); } } catch (Exception ex) { _logger.LogError(ex, $"处理日志详情失败: Layer={detail.LayerType}, UEID={detail.UEID}"); } } // 通知协议日志观察者处理转换后的数据 try { // 过滤掉Info为空的记录 var filteredLogDetails = logDetails.Where(detail => !string.IsNullOrEmpty(detail.Info)).ToList(); _protocolLogObserver.OnProtocolLogsReceived(filteredLogDetails); } catch (Exception ex) { _logger.LogError(ex, "通知协议日志观察者失败"); } // 修复后 foreach (var detail in logDetails) { try { Console.WriteLine($"处理日志详情:Time={detail.Time} Layer={detail.LayerType}, UEID={detail.UEID}, IMSI={detail.IMSI},PLMN={detail.PLMN},INFO={detail.Info},Messsage={detail.Message}"); // 这里可以添加具体的业务处理逻辑 // 例如:保存到数据库、发送到其他服务等 _logger.LogDebug($"处理日志详情: Layer={detail.LayerType}, UEID={detail.UEID}, IMSI={detail.IMSI}"); } catch (Exception ex) { _logger.LogError(ex, $"处理日志详情失败: Layer={detail.LayerType}, UEID={detail.UEID}"); } } // 通知协议日志观察者处理转换后的数据 try { // 过滤掉Info为空或无效的记录 var filteredLogDetails = logDetails.Where(detail => !string.IsNullOrWhiteSpace(detail.Info) ).ToList(); if (filteredLogDetails.Any()) { _protocolLogObserver.OnProtocolLogsReceived(filteredLogDetails); } else { _logger.LogDebug("过滤后没有有效的日志记录,跳过观察者通知"); } } catch (Exception ex) { _logger.LogError(ex, "通知协议日志观察者失败"); }
-
设计优势:
- 完整日志处理:处理所有日志记录,包括Info为空的记录
- 数据质量保证:确保传递给观察者的数据中只包含有效的Info字段
- 调试友好:可以看到所有日志记录的详细信息,便于调试
- 观察者模式优化:传递给观察者的数据更加纯净
- 错误预防:避免因空Info字段导致的潜在问题
-
修复的问题:
- 日志信息缺失:原代码会跳过Info为空的记录,导致日志信息不完整
- 调试困难:无法看到所有日志记录的详细信息
- 数据传递问题:将无效数据传递给协议日志观察者
- 信息不完整:处理过程中丢失了部分日志信息
影响范围:
- 协议日志处理的完整性
- 日志输出的完整性
- 协议日志观察者接收的数据质量
- 调试和问题排查能力
GeneralCellularNetworkService.StartNetworkAsync方法步骤注释优化
修改时间: 2024年12月 修改文件:
CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
修改内容:
-
重新注释StartNetworkAsync方法中的步骤
- 为每个步骤添加更详细和清晰的注释说明
- 统一注释格式,使用"步骤X: 功能描述"的格式
- 为每个步骤添加功能说明,解释该步骤的具体作用
- 保持原有的时间跟踪和日志记录功能
-
具体修改的步骤注释:
- 步骤1: 创建蜂窝网络配置文件 - 根据传入的蜂窝网络配置和应用程序设置,创建临时配置文件
- 步骤2: 执行网络接口初始化命令 - 初始化网络接口,确保网络环境准备就绪
- 步骤3: 复制配置值到临时目录 - 将网络配置的关键参数复制到系统临时目录,供后续步骤使用
- 步骤4: 获取并验证IP端点信息 - 从配置中提取通信地址信息,验证端点的有效性
- 步骤5: 更新IP端点管理器 - 将获取到的端点信息更新到网络上下文中的端点管理器
- 步骤6: 创建协议客户端配置 - 基于网络实体信息创建协议客户端配置,为后续的协议通信做准备
- 步骤7: 启动WebSocket传输连接 - 建立与协议服务器的WebSocket连接,为数据传输做准备
- 步骤8: 启动网络配置 - 启用网络接口配置,激活蜂窝网络连接
- 步骤9: 更新网络配置类型 - 根据启动结果更新网络配置类型,记录当前使用的配置类型
- 步骤10: 检查网络端点连接状态 - 验证所有网络端点的连接状态,确保网络连接正常
- 步骤11: 更新网络状态 - 将网络状态标记为已启动,更新内部状态管理
- 步骤12: 启动所有协议客户端 - 启动所有协议客户端,开始协议数据采集和传输
-
设计优势:
- 注释清晰:每个步骤都有明确的功能描述
- 格式统一:使用一致的注释格式,提高可读性
- 功能说明:详细解释每个步骤的作用和目的
- 易于理解:帮助开发者快速理解网络启动流程
- 维护友好:清晰的注释便于后续维护和修改
-
注释示例:
// 步骤1: 创建蜂窝网络配置文件 // 根据传入的蜂窝网络配置和应用程序设置,创建临时配置文件 var step1Start = DateTime.UtcNow; _logger.LogDebug("步骤1开始:创建蜂窝网络配置文件"); // 步骤2: 执行网络接口初始化命令 // 初始化网络接口,确保网络环境准备就绪 var step2Start = DateTime.UtcNow; _logger.LogDebug("步骤2开始:执行网络接口初始化命令");
影响范围:
- 网络启动流程的代码可读性
- 开发者对网络启动过程的理解
- 代码维护和调试的便利性
- 新团队成员的学习成本
GeneralCellularNetworkService网络状态恢复机制优化
修改时间: 2024年12月 修改文件:
CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
修改内容:
-
重新命名和优化恢复方法
- 将
StartRestore
方法重命名为RestoreNetworkStateAsync
- 添加完整的XML文档注释说明方法用途
- 返回
bool
类型表示恢复操作是否成功 - 移除直接抛出异常的代码,改为记录日志并返回失败状态
- 将
-
完善恢复流程
- 步骤1: 停止所有协议客户端
- 步骤2: 关闭WebSocket传输连接
- 步骤3: 执行网络接口初始化命令,重置网络状态
- 步骤4: 重置网络上下文状态
- 每个步骤都有独立的异常处理,确保单个步骤失败不影响其他步骤
-
在步骤10之后的所有步骤中添加恢复机制
- 步骤10: 网络端点状态检查失败时调用恢复
- 步骤11: 更新网络状态失败时调用恢复
- 步骤12: 启动协议客户端失败时调用恢复
- 确保在任何步骤失败时都能正确清理资源
-
具体实现:
// 恢复方法优化 private async Task<bool> RestoreNetworkStateAsync() { try { _logger.LogInformation("开始恢复网络状态"); // 1. 停止所有协议客户端 try { _protocolWsClientManager.StopAllClients(); _logger.LogDebug("协议客户端停止完成"); } catch (Exception ex) { _logger.LogWarning(ex, "停止协议客户端时出现异常,继续执行恢复流程"); } // 2. 关闭WebSocket传输连接 try { if (_webSocketTransport.IsConnected) { await _webSocketTransport.CloseAsync(); _logger.LogDebug("WebSocket传输连接关闭完成"); } } catch (Exception ex) { _logger.LogWarning(ex, "关闭WebSocket传输连接时出现异常,继续执行恢复流程"); } // 3. 执行网络接口初始化命令,重置网络状态 try { var initResult = await _interfaceManager.ExecuteInitializeCommandsAsync(true); if (!initResult.IsSuccess) { _logger.LogWarning("执行网络接口初始化命令失败: {ErrorMessage}", initResult.ErrorMessage); } else { _logger.LogDebug("网络接口初始化命令执行成功"); } } catch (Exception ex) { _logger.LogWarning(ex, "执行网络接口初始化命令时出现异常"); } // 4. 重置网络上下文状态 _context.Reset(); _logger.LogDebug("网络上下文状态重置完成"); _logger.LogInformation("网络状态恢复完成"); return true; } catch (Exception ex) { _logger.LogError(ex, "恢复网络状态过程中出现未预期的异常"); return false; } }
-
步骤10-12的恢复调用:
// 步骤10: 网络端点状态检查失败 if (!statusCheckResult.IsSuccess) { var errorMessage = string.Join("; ", statusCheckResult.ErrorMessage); _logger.LogWarning("网络端点状态检查未通过: {ErrorMessage}", errorMessage); await RestoreNetworkStateAsync(); return CellularNetworkOperationResult.Failure($"网络端点状态检查失败: {errorMessage}"); } // 步骤11: 更新网络状态 var state = _context.GetNetworkState(); state.MarkAsStarted(); // 步骤12: 启动协议客户端失败 try { var protocolConfigs = protocolConfigFactory.GetAllConfigs(); var startResult = _protocolWsClientManager.StartAllClients(protocolConfigs); if (!startResult) { _logger.LogWarning("部分协议客户端启动失败"); await RestoreNetworkStateAsync(); return CellularNetworkOperationResult.Failure("部分协议客户端启动失败"); } _logger.LogInformation("所有协议客户端启动完成"); } catch (Exception ex) { _logger.LogError(ex, "启动协议客户端失败"); await RestoreNetworkStateAsync(); return CellularNetworkOperationResult.Failure($"启动协议客户端失败: {ex.Message}"); }
-
设计优势:
- 完整的资源清理:确保所有已创建的资源都被正确清理
- 错误隔离:每个恢复步骤都有独立的异常处理,避免单个失败影响整体恢复
- 详细日志记录:提供完整的恢复过程日志,便于问题排查
- 状态一致性:确保网络状态在失败时能够恢复到初始状态
- 方法命名清晰:
RestoreNetworkStateAsync
明确表达方法功能 - 返回值有意义:返回bool值表示恢复操作是否成功
- 异常处理完善:不直接抛出异常,而是记录日志并返回失败状态
影响范围:
- 网络启动失败时的资源清理机制
- 网络状态恢复的可靠性
- 错误处理和日志记录的完整性
- 系统稳定性和资源管理
- 调试和问题排查能力
优化GeneralCellularNetworkService中的RestoreNetworkStateAsync方法和启动流程
修改时间: 2024年12月 修改文件:
CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
修改内容:
-
问题描述:
RestoreNetworkStateAsync
方法返回布尔值但调用方不做判断,返回值无意义- 步骤12(启动所有协议客户端)代码较长,需要提取为单独方法以提高可读性
- 需要确保只有步骤1成功时才继续执行后续步骤
- 删除临时配置文件这一步无论成功还是失败都需要执行
-
修复方案:
- 将
RestoreNetworkStateAsync
方法改为void
返回类型,移除不必要的返回值 - 提取步骤12的协议客户端启动逻辑到单独的私有方法
StartAllProtocolClientsAsync
- 重构
StartNetworkAsync
方法,将步骤1和删除临时配置文件分离 - 提取步骤2-12到新的私有方法
ExecuteRemainingStepsAsync
- 确保删除临时配置文件无论成功还是失败都会执行
- 将
-
具体修改: RestoreNetworkStateAsync 方法优化:
// 修改前 private async Task<bool> RestoreNetworkStateAsync() // 修改后 private async Task RestoreNetworkStateAsync()
新增 StartAllProtocolClientsAsync 方法:
/// <summary> /// 启动所有协议客户端 /// </summary> /// <param name="protocolConfigFactory">协议配置工厂</param> /// <returns>启动结果</returns> private async Task<CellularNetworkOperationResult> StartAllProtocolClientsAsync(ProtocolClientConfigFactory protocolConfigFactory)
新增 ExecuteRemainingStepsAsync 方法:
/// <summary> /// 执行剩余的启动步骤(步骤2-12) /// </summary> /// <param name="config">网络配置</param> /// <param name="key">配置键</param> /// <param name="startTime">开始时间</param> /// <returns>执行结果</returns> private async Task<CellularNetworkOperationResult> ExecuteRemainingStepsAsync(object config, string key, DateTime startTime)
StartNetworkAsync 方法重构:
// 步骤1成功后,调用ExecuteRemainingStepsAsync执行后续步骤 var result = await ExecuteRemainingStepsAsync(config, key, startTime); // 删除临时配置文件 - 无论成功还是失败都需要执行 var deleteResult = _configCopier.DeleteCellularNetworkConfigurationFile(config); // 记录结果但不影响返回值
-
影响范围:
- 简化了方法调用,移除了不必要的返回值判断
- 提高了代码可读性和维护性
- 确保了步骤1的成功验证逻辑
- 保证了临时配置文件的清理操作总是执行
- 保持了原有的错误处理逻辑
代码提交 - 完善网络配置和协议客户端功能
修改时间: 2024年12月
提交信息: 更新代码:完善网络配置和协议客户端功能
提交哈希: d011b25
修改内容:
-
GeneralCellularNetworkService网络状态恢复机制优化
- 重新命名和优化恢复方法:将
StartRestore
重命名为RestoreNetworkStateAsync
- 完善恢复流程:停止协议客户端、关闭WebSocket连接、重置网络状态
- 在步骤10-12中添加恢复机制,确保失败时能正确清理资源
- 添加完整的异常处理和日志记录
- 重新命名和优化恢复方法:将
-
ProtocolLogProcessor.ProcessLogDetails方法Info字段过滤修复
- 修复foreach循环中的Info字段检查,允许处理所有日志记录
- 在调用观察者之前过滤掉Info为空或无效的记录
- 确保传递给观察者的数据质量,添加空集合检查
-
GeneralCellularNetworkService.StartNetworkAsync方法步骤注释优化
- 为每个步骤添加详细和清晰的功能说明注释
- 统一注释格式,使用"步骤X: 功能描述"的格式
- 提高代码可读性和维护性
-
NetworkConfigCopier方法Bug修复和日志增强
- 统一返回类型为
NetworkConfigCopyResult
,不再抛出异常 - 修复路径构建Bug,正确使用
Path.Combine
- 添加完整的参数验证和目录创建逻辑
- 增强错误处理和详细日志记录
- 统一返回类型为
-
WebSocket传输服务依赖注入修复
- 修复依赖注入顺序问题,确保中间件在核心服务之前注册
- 修复CacheMiddleware注册方式,使用标准的依赖注入模式
- 添加IMemoryCache服务注册,确保中间件依赖完整
-
ProtocolWsClientManager方法参数优化
- 简化构造函数,移除配置参数
- 修改StartAllClients方法签名,添加配置参数
- 采用面向接口编程,创建IProtocolWsClientManager接口
-
CellularNetworkService集成协议客户端管理
- 添加IProtocolWsClientManager依赖注入
- 在StartNetworkAsync方法中添加协议客户端启动步骤
- 在StopAsync方法中集成协议客户端停止逻辑
- 添加时间跟踪记录,提供详细的性能监控
-
MessageTransferProtocolLog模型创建
- 创建新的协议日志模型,解决命名冲突
- 修改NetworkProtocolLogObserver转换逻辑
- 添加类型转换和字段映射
-
蜂窝网络配置实体类创建
- 创建CellularNetworkConfiguration实体类
- 创建CoreNetworkImsConfiguration实体类
- 添加数据校验功能和ValidationResult类
-
NetworkProtocolLogObserver中的StopChannelManager方法修复
- 修复资源管理问题,避免过早释放
- 优化通道管理方法,职责更加清晰
- 添加自动重连配置选项
- 修复WebSocket配置文件
影响范围:
- 网络配置和协议客户端功能的完整性
- 错误处理和资源管理的可靠性
- 代码可读性和维护性的提升
- 依赖注入配置的完善
- 日志记录和调试能力的增强
- 系统稳定性和性能监控的改进
2024年修改记录
修复NetworkProtocolLogObserver中的StopChannelManager方法并支持重新创建
修改时间: 2024年12月 修改文件:
CoreAgent.Infrastructure/Services/Network/NetworkProtocolLogObserver.cs
CoreAgent.WebSocketTransport/Interfaces/IMessageChannelManager.cs
CoreAgent.WebSocketTransport/Services/MessageChannelManager.cs
修改内容:
-
问题描述:
StopChannelManager()
方法直接调用_ChannelManager.Dispose()
可能导致资源过早释放IMessageChannelManager
接口已实现IDisposable
,生命周期应由DI容器管理- 直接调用
Dispose()
可能影响其他使用该实例的组件
-
修复方案:
-
修改
MessageChannelManager
设计,不在构造函数中创建通道 -
移除构造函数中的默认参数,要求必须传入容量参数
-
添加容量参数验证,确保参数有效性
-
扩展
WebSocketConfig
配置类,添加分别的通道容量配置 -
更新依赖注入注册,从配置中读取不同的通道容量
-
优化通道管理方法,职责更加清晰:
CreateChannels()
- 安全创建(已存在则跳过)ClearAllChannels()
- 清空通道消息(保持通道可用)CompleteAllChannels()
- 完成通道(标记不再接受新消息,但保持可读)ReleaseChannels()
- 完全释放通道资源
-
将
StopChannelManager()
改为调用ReleaseChannels()
-
将
RecreateChannelManager()
改为调用CreateChannels()
-
优化通道创建逻辑:
- 修改
CreateChannels()
方法,如果通道已存在则先释放再创建 - 移除
ResetChannels()
方法,避免功能重复 - 简化接口设计,减少方法数量
- 修改
-
WebSocketTransport 集成通道管理:
- 重构
ConnectInternalAsync()
方法,提取为多个独立方法:CreateMessageChannels()
- 先创建消息通道(同步方法)EstablishWebSocketConnectionAsync()
- 再建立WebSocket连接(异步方法)StartBackgroundTasks()
- 最后启动后台任务(同步方法)
- 在
CloseAsync()
中调用_channelManager.ReleaseChannels()
释放通道 - 在重连失败时也释放通道,确保资源正确清理
- 通道生命周期与WebSocket连接生命周期完全同步
- 重构
-
添加自动重连配置选项:
- 在
WebSocketConfig
中添加EnableAutoReconnect
配置项 - 在
TriggerReconnect()
方法中添加配置检查 - 支持通过配置文件控制是否启用自动重连功能
- 在
-
修复WebSocket配置文件:
- 更新
websocket.json
和websocket.Development.json
配置文件 - 添加所有新增的配置项:
EnableAutoReconnect
、SendChannelCapacity
、ReceiveChannelCapacity
、PriorityChannelCapacity
、MaxChunkSize
、ChunkDelayMs
- 为开发环境和生产环境提供不同的配置值
- 更新
-
添加重复调用检查,避免二次调用导致异常
-
添加异常处理和日志记录
-
保持方法功能的同时避免资源管理问题
-
-
具体修改: IMessageChannelManager 接口新增方法:
/// <summary> /// 创建所有通道 /// </summary> void CreateChannels(); /// <summary> /// 释放所有通道 /// </summary> void ReleaseChannels();
MessageChannelManager 实现:
// 构造函数要求必须传入容量参数,并验证参数有效性 public MessageChannelManager(ILogger<MessageChannelManager> logger, int sendChannelCapacity, int receiveChannelCapacity, int priorityChannelCapacity) { // 验证容量参数 if (sendChannelCapacity <= 0) throw new ArgumentOutOfRangeException(...); // 保存容量配置,不创建通道 } // 安全创建通道(如果已存在则跳过) public void CreateChannels() { // 检查通道是否已存在,如果存在则跳过创建 } // 清空通道消息(保持通道可用) public void ClearAllChannels() { // 清空所有通道中的消息,但保持通道结构 } // 完成通道(标记不再接受新消息,但保持可读) public void CompleteAllChannels() { // 标记通道完成,不再接受新消息,但可以继续读取 } // 完全释放通道资源 public void ReleaseChannels() { // 完成通道,释放资源,清空引用 }
WebSocketConfig 配置扩展:
public class WebSocketConfig { // 是否启用自动重连功能 public bool EnableAutoReconnect { get; set; } = true; // 最大重连尝试次数 public int MaxReconnectAttempts { get; set; } = 5; // 发送通道容量 public int SendChannelCapacity { get; set; } = 1000; // 接收通道容量 public int ReceiveChannelCapacity { get; set; } = 1000; // 优先级通道容量 public int PriorityChannelCapacity { get; set; } = 100; }
依赖注入注册更新:
services.AddSingleton<IMessageChannelManager>(provider => { var config = provider.GetRequiredService<IOptions<WebSocketConfig>>().Value; return new MessageChannelManager(logger, config.SendChannelCapacity, config.ReceiveChannelCapacity, config.PriorityChannelCapacity); });
NetworkProtocolLogObserver 修改:
public void StopChannelManager() { // 调用 ReleaseChannels() 释放通道 _ChannelManager.ReleaseChannels(); } public void RecreateChannelManager() { // 调用 CreateChannels() 重新创建通道(会自动释放现有通道) _ChannelManager.CreateChannels(); }
WebSocketTransport 重构:
// 连接时先创建通道,再建立连接 private async Task ConnectInternalAsync(CancellationToken cancellationToken) { // 1. 先创建消息通道 await CreateMessageChannelsAsync(); // 2. 再建立 WebSocket 连接 await EstablishWebSocketConnectionAsync(cancellationToken); // 3. 最后启动后台任务 await StartBackgroundTasksAsync(); } // 提取的独立方法 private void CreateMessageChannels() { _channelManager.CreateChannels(); } private async Task EstablishWebSocketConnectionAsync(CancellationToken cancellationToken) { await _connection.ConnectAsync(...); } private void StartBackgroundTasks() { // 启动发送、接收、心跳任务 }
-
修复优势:
- 配置灵活性: 支持通过配置文件分别设置不同通道的容量,更加灵活
- 参数验证: 构造函数中验证容量参数,确保参数有效性
- 方法职责清晰: 每个方法职责明确,避免功能重叠
- 生命周期控制: 通道的创建和释放完全由用户控制,更加灵活
- 资源管理: 避免在构造函数中创建资源,符合延迟初始化原则
- 重复使用: 支持多次创建和释放,满足业务需求
- 重复调用保护: 防止二次调用导致异常,提高系统稳定性
- 异常处理: 添加了完整的异常处理和日志记录,但不影响主程序运行
- 业务连续性: 异常被捕获并记录,但不会中断主程序流程
- 功能保持: 仍然能够正确停止和重新创建通道管理器
- 日志完善: 提供了详细的调试和错误日志信息
创建蜂窝网络配置实体类
创建蜂窝网络配置实体类
修改时间: 2024年 修改文件:
CoreAgent.Domain/Models/Network/CellularNetworkConfiguration.cs
(新建)
修改内容:
-
创建CellularNetworkConfiguration实体类
- 包含设备代码(DeviceCode)字符串属性
- 包含运行时代码(RuntimeCode)字符串属性
- 包含无线接入网配置(RadioAccessNetworkConfiguration)字符串属性
- 包含核心网IMS配置集合(List)属性
-
创建CoreNetworkImsConfiguration实体类
- 包含索引(Index)整数属性
- 包含PLMN标识(Plmn)字符串属性
- 包含核心网配置(CoreNetworkConfiguration)字符串属性
- 包含IMS服务配置(ImsServiceConfiguration)字符串属性
-
具体实现:
/// <summary> /// 蜂窝网络配置实体 /// </summary> public class CellularNetworkConfiguration { /// <summary> /// 设备代码 /// </summary> public string DeviceCode { get; set; } /// <summary> /// 运行时代码 /// </summary> public string RuntimeCode { get; set; } /// <summary> /// 无线接入网配置 /// </summary> public string RadioAccessNetworkConfiguration { get; set; } /// <summary> /// 核心网IMS配置集合 /// </summary> public List<CoreNetworkImsConfiguration> CoreNetworkImsConfigurations { get; set; } = new List<CoreNetworkImsConfiguration>(); } /// <summary> /// 核心网IMS配置对象 /// </summary> public class CoreNetworkImsConfiguration { /// <summary> /// 索引 /// </summary> public int Index { get; set; } /// <summary> /// PLMN标识 /// </summary> public string Plmn { get; set; } /// <summary> /// 核心网配置 /// </summary> public string CoreNetworkConfiguration { get; set; } /// <summary> /// IMS服务配置 /// </summary> public string ImsServiceConfiguration { get; set; } }
-
设计优势:
- 命名规范:遵循C#命名约定,使用PascalCase
- 命名清晰:类名明确表达业务含义,提高代码可读性
- 属性专业:使用完整的专业术语,避免缩写和模糊命名
- 类型安全:使用强类型属性,避免类型错误
- 文档完整:每个属性都有详细的XML文档注释
- 集合初始化:使用集合初始化器确保集合不为null
- 职责清晰:每个类都有明确的职责和用途
- 易于扩展:结构清晰,便于后续添加新属性
- 业务导向:类名直接反映业务领域概念
- 专业术语:使用标准的电信网络术语,提高代码专业性
添加蜂窝网络配置数据校验功能
修改时间: 2024年 修改文件:
CoreAgent.Domain/Models/Network/CellularNetworkConfiguration.cs
修改内容:
-
添加数据校验功能
- 为
DeviceCode
和RuntimeCode
添加[Required]
特性,确保不能为空 - 为
Plmn
添加[Required]
特性,确保不能为空 - 添加
ValidateConfiguration()
方法进行业务逻辑校验
- 为
-
业务规则校验
- 验证
DeviceCode
和RuntimeCode
不能为空 - 验证
RadioAccessNetworkConfiguration
和CoreNetworkImsConfigurations
至少有一个有数据 - 验证
CoreNetworkImsConfiguration
中的CoreNetworkConfiguration
和ImsServiceConfiguration
至少有一个有数据
- 验证
-
创建ValidationResult类
- 提供统一的验证结果返回格式
- 支持成功和失败两种状态
- 提供详细的错误消息
- 支持隐式转换操作符
-
具体实现:
// 必填字段校验 [Required(ErrorMessage = "设备代码不能为空")] public string DeviceCode { get; set; } [Required(ErrorMessage = "运行时代码不能为空")] public string RuntimeCode { get; set; } // 业务逻辑校验 public ValidationResult ValidateConfiguration() { // 验证必填字段 if (string.IsNullOrWhiteSpace(DeviceCode)) { return new ValidationResult("设备代码不能为空"); } // 验证无线接入网配置和核心网IMS配置至少有一个有数据 var hasRadioAccessConfig = !string.IsNullOrWhiteSpace(RadioAccessNetworkConfiguration); var hasCoreNetworkConfigs = CoreNetworkImsConfigurations?.Any() == true; if (!hasRadioAccessConfig && !hasCoreNetworkConfigs) { return new ValidationResult("无线接入网配置和核心网IMS配置至少需要配置其中一项"); } return ValidationResult.Success; }
-
设计优势:
- 数据完整性:确保必填字段不为空
- 业务规则校验:验证业务逻辑的正确性
- 统一验证接口:提供一致的验证方法
- 详细错误信息:提供具体的错误描述
- 分层校验:支持嵌套对象的校验
- 易于扩展:可以轻松添加新的校验规则
影响范围:
- 蜂窝网络配置数据模型定义
- 核心网IMS配置管理
- 数据实体结构标准化
- 领域模型完整性
- 代码可读性和维护性提升
- 数据校验和业务规则验证
- 错误处理和用户反馈
创建MessageTransferProtocolLog模型解决命名冲突
修改时间: 2024年 修改文件:
CoreAgent.WebSocketTransport/Models/MessageTransferProtocolLog.cs
(新建)CoreAgent.Infrastructure/Services/Network/NetworkProtocolLogObserver.cs
修改内容:
-
创建MessageTransferProtocolLog模型
- 在
CoreAgent.WebSocketTransport
项目中创建新的协议日志模型 - 与
CoreAgent.ProtocolClient
中的TransferProtocolLog
区分开 - 保持相同的字段结构,避免命名冲突
- 专门用于WebSocket传输层的协议日志数据传输
- 在
-
修改NetworkProtocolLogObserver转换逻辑
- 在
OnProtocolLogsReceived
方法中添加类型转换 - 将
CoreAgent.ProtocolClient.TransferProtocolLog
转换为CoreAgent.WebSocketTransport.MessageTransferProtocolLog
- 保持所有字段的完整映射
- 添加必要的using语句引用
- 在
-
具体实现:
// 时间跟踪和性能监控 var startTime = DateTime.UtcNow; // 空值检查 if (logDetails == null) { _logger.LogWarning("接收到的协议日志为空"); return; } // 转换为列表以避免多次枚举 var logList = logDetails.ToList(); var logCount = logList.Count; // 空集合检查 if (logCount == 0) { _logger.LogDebug("接收到的协议日志集合为空,跳过处理"); return; } // 类型转换逻辑 var webSocketLogs = logList.Select(log => new MessageTransferProtocolLog { Id = log.Id, LayerType = log.LayerType.ToString(), MessageDetailJson = log.MessageDetailJson, CellID = log.CellID, IMSI = log.IMSI, Direction = log.Direction, UEID = log.UEID, PLMN = log.PLMN, TimeMs = log.TimeMs, Timestamp = log.Timestamp, Info = log.Info, Message = log.Message }); // 通道写入状态监控 var writeSuccess = _ChannelManager.SendChannel.TryWrite(webSocketLogs); var processingTime = DateTime.UtcNow - startTime; if (writeSuccess) { _logger.LogDebug("协议日志处理成功,数量: {LogCount}, 处理时间: {ProcessingTime}ms", logCount, processingTime.TotalMilliseconds); } else { _logger.LogWarning("协议日志写入通道失败,数量: {LogCount}, 处理时间: {ProcessingTime}ms, 通道可能已满或已关闭", logCount, processingTime.TotalMilliseconds); }
-
设计优势:
- 命名清晰:
MessageTransferProtocolLog
明确表示用于消息传输 - 避免冲突:与原始
TransferProtocolLog
有明确区分 - 职责分离:WebSocket传输层有独立的协议日志模型
- 类型安全:通过显式转换确保类型安全
- 易于维护:清晰的命名约定便于理解和维护
- 性能监控:添加时间跟踪和通道写入状态监控
- 错误处理:完善的异常处理和日志记录
- Bug修复:修复空引用检查和多次枚举的性能问题
- 边界处理:添加空集合检查,避免处理空集合
- 代码规范:优化ProtocolMessage模型注释,提高代码可读性
- 命名清晰:
影响范围:
- WebSocket传输层协议日志处理
- 协议日志观察者模式实现
- 跨项目类型转换逻辑
- 协议消息模型注释优化
CellularNetworkService.StartNetworkAsync 方法添加协议客户端配置创建
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs
修改内容:
-
调整执行步骤顺序
- 将原来的第5.5步改为第6步(创建协议客户端配置)
- 将WebSocket传输连接移到第7步(在网络配置启动之前)
- 重新编号后续步骤(8-11步)
- 优化执行顺序:确保WebSocket连接在网络配置启动之前完成
-
添加第7步WebSocket传输连接
- 在
StartNetworkAsync
方法的第6步(创建协议客户端配置)之后添加第7步 - 注入
IWebSocketTransport
依赖 - 创建独立的
StartWebSocketTransportAsync()
方法处理连接逻辑 - 返回
bool
值表示连接是否成功 - 添加连接状态检查和错误处理
- 严格检查:WebSocket连接失败时立即返回失败结果,提示服务端可能未启动
- 在
-
修复Logger类型问题
- 添加
ILoggerFactory
依赖注入到构造函数 - 使用
_loggerFactory.CreateLogger<ProtocolClientConfigFactory>()
创建正确类型的Logger - 确保
ProtocolClientConfigFactory
获得正确的Logger实例
- 添加
-
具体实现:
// 6. 创建协议客户端配置 var protocolConfigFactory = new ProtocolClientConfigFactory(_loggerFactory.CreateLogger<ProtocolClientConfigFactory>(), _context); var configCreated = protocolConfigFactory.CreateFromEntities(); if (configCreated) { _logger.LogInformation("协议客户端配置创建成功,共创建 {ConfigCount} 个配置", protocolConfigFactory.ConfigCount); } else { _logger.LogWarning("协议客户端配置创建失败"); return CellularNetworkOperationResult.Failure("协议客户端配置创建失败"); } // 7. 启动 WebSocket 传输连接 var webSocketConnected = await StartWebSocketTransportAsync(); if (!webSocketConnected) { _logger.LogError("WebSocket 传输连接启动失败,服务端可能未启动"); return CellularNetworkOperationResult.Failure("WebSocket 传输连接启动失败,服务端可能未启动"); } _logger.LogInformation("WebSocket 传输连接启动成功");
-
添加必要的依赖注入
- 添加
ILoggerFactory loggerFactory
参数到构造函数 - 添加
IWebSocketTransport webSocketTransport
参数到构造函数 - 添加
using CoreAgent.Infrastructure.Services.Network;
以支持ProtocolClientConfigFactory
- 添加
using CoreAgent.WebSocketTransport.Interfaces;
以支持IWebSocketTransport
- 添加
-
设计优势:
- 在IP端点信息准备完成后立即创建协议客户端配置
- 不依赖网络启动结果,确保配置创建的独立性
- 在网络配置启动之前启动WebSocket传输连接
- 提供详细的日志记录便于调试
- 保持代码的简洁性和可维护性
- 正确处理Logger类型,避免类型不匹配问题
- 优化执行顺序,提高错误隔离能力
- 完善的错误处理机制,确保配置创建失败时及时停止
- 严格检查机制,WebSocket连接失败时立即停止网络启动流程
- 方法职责单一,WebSocket连接逻辑独立封装
影响范围:
- 蜂窝网络启动流程
- 协议客户端配置管理
- WebSocket传输服务集成
- 网络状态监控
- 依赖注入配置(需要更新服务注册)
CellularNetworkService构造函数添加IProtocolLogObserver依赖
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs
修改内容:
-
添加IProtocolLogObserver依赖注入
- 在构造函数中添加
IProtocolLogObserver protocolLogObserver
参数 - 添加私有字段
_protocolLogObserver
存储依赖 - 添加空值检查和异常抛出
- 在构造函数中添加
-
添加必要的using语句
- 添加
using CoreAgent.ProtocolClient.ProtocolEngineCore;
以支持IProtocolLogObserver
- 添加
-
具体实现:
// 构造函数参数 public CellularNetworkService( // ... 其他参数 IWebSocketTransport webSocketTransport, IProtocolLogObserver protocolLogObserver) // 私有字段 private readonly IProtocolLogObserver _protocolLogObserver; // 构造函数初始化 _protocolLogObserver = protocolLogObserver ?? throw new ArgumentNullException(nameof(protocolLogObserver));
-
设计优势:
- 为后续协议客户端管理提供必要的依赖
- 保持依赖注入的一致性
- 提供空值检查确保服务稳定性
- 为协议日志观察者模式提供支持
影响范围:
- 蜂窝网络服务依赖注入配置
- 协议客户端日志观察者集成
- 服务注册配置更新
StartNetworkAsync方法添加时间跟踪记录
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs
修改内容:
-
添加整体时间跟踪
- 在方法开始时记录开始时间
- 在方法结束时计算总耗时并记录
- 使用UTC时间确保时间一致性
-
为每个步骤添加详细时间跟踪
- 为11个步骤中的每个步骤添加开始和结束时间记录
- 使用
LogDebug
级别记录每个步骤的耗时 - 保持原有的
LogInformation
和LogError
级别日志不变
-
具体实现:
// 方法开始时间跟踪 var startTime = DateTime.UtcNow; _logger.LogInformation("开始启动网络配置 {ConfigKey},开始时间: {StartTime}", key, startTime.ToString("yyyy-MM-dd HH:mm:ss.fff")); // 每个步骤的时间跟踪 var stepXStart = DateTime.UtcNow; _logger.LogDebug("步骤X开始:[步骤描述]"); // 步骤执行逻辑... var stepXDuration = (DateTime.UtcNow - stepXStart).TotalMilliseconds; _logger.LogDebug("步骤X完成:[步骤描述],耗时: {Duration}ms", stepXDuration.ToString("F2")); // 方法结束时间跟踪 var endTime = DateTime.UtcNow; var duration = endTime - startTime; _logger.LogInformation("蜂窝网络配置 {ConfigKey} 启动成功,当前状态: {Status},总耗时: {Duration}ms", key, state.CurrentStatus, duration.TotalMilliseconds.ToString("F2"));
-
设计优势:
- 性能监控:可以识别网络启动过程中的性能瓶颈
- 调试支持:详细的时间信息有助于问题定位和性能优化
- 日志分级:使用Debug级别避免生产环境日志过多
- 时间精度:使用毫秒级精度提供准确的性能数据
- UTC时间:确保时间记录的一致性和准确性
- 非侵入性:不影响原有的业务逻辑和错误处理
-
跟踪的步骤:
- 步骤1:获取并验证网络配置
- 步骤2:执行网络接口初始化命令
- 步骤3:复制配置值到临时目录
- 步骤4:获取并验证 IP 端点信息
- 步骤5:更新 IP 端点管理器
- 步骤6:创建协议客户端配置
- 步骤7:启动 WebSocket 传输连接
- 步骤8:启动网络配置
- 步骤9:更新网络配置类型
- 步骤10:检查网络端点连接状态
- 步骤11:更新网络状态
影响范围:
- 网络启动性能监控
- 调试和问题定位
- 日志记录详细程度
- 性能优化分析
ProtocolWsClientManager方法参数优化
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/ProtocolWsClientManager.cs
修改内容:
-
简化构造函数
- 移除
ProtocolClientConfig[] configs
参数 - 构造函数只保留必要的依赖:
ILogger
、IProtocolLogObserver
、ILoggerFactory
- 移除私有字段
_configs
,不再在构造函数中存储配置
- 移除
-
修改StartAllClients方法签名
- 添加
ProtocolClientConfig[] configs
参数 - 方法接收配置数组作为参数,而不是依赖构造函数中的配置
- 添加参数验证,检查
configs
是否为 null 或空数组
- 添加
-
优化方法逻辑
- 将配置验证移到方法开始处
- 使用传入的
configs
参数替代私有字段 - 保持原有的客户端创建和启动逻辑不变
-
具体实现:
// 构造函数简化 public ProtocolWsClientManager( ILogger<ProtocolWsClientManager> logger, IProtocolLogObserver protocolLogObserver, ILoggerFactory loggerFactory) // 移除 configs 参数 // StartAllClients方法修改 public void StartAllClients(ProtocolClientConfig[] configs) // 添加参数 { if (configs == null || configs.Length == 0) // 参数验证 { _logger.LogWarning("没有可用的协议客户端配置"); return; } // 使用传入的 configs 参数 _logger.LogInformation("开始启动所有协议客户端,配置数量: {ConfigCount}", configs.Length); foreach (var config in configs) // 遍历传入的配置
-
设计优势:
- 更灵活的使用方式:可以在不同时间传入不同的配置
- 减少内存占用:不需要在构造函数中存储配置数组
- 简化构造函数:降低构造函数的复杂度
- 更好的测试性:可以更容易地测试不同的配置组合
- 符合单一职责原则:构造函数只负责初始化,方法负责执行具体操作
影响范围:
- 协议客户端管理器使用方式
- 配置传递方式
- 调用方代码适配
- 测试用例更新
ProtocolWsClientManager采用面向接口编程
修改时间: 2024年 修改文件:
CoreAgent.ProtocolClient/Interfaces/IProtocolWsClientManager.cs
(新建)CoreAgent.Infrastructure/Services/Network/ProtocolWsClientManager.cs
修改内容:
-
创建IProtocolWsClientManager接口
- 在CoreAgent.ProtocolClient项目中定义接口契约
- 继承
IDisposable
接口 - 定义
StartAllClients
和StopAllClients
方法 - 使用
ProtocolClientConfig[]
作为参数类型
-
修改ProtocolWsClientManager实现类
- 实现
IProtocolWsClientManager
接口 - 添加
using CoreAgent.ProtocolClient.Interfaces;
引用 - 保持原有的实现逻辑不变
- 实现
-
具体实现:
// 接口定义 public interface IProtocolWsClientManager : IDisposable { void StartAllClients(ProtocolClientConfig[] configs); void StopAllClients(); } // 实现类 public class ProtocolWsClientManager : IProtocolWsClientManager { // 原有实现保持不变 }
-
设计优势:
- 依赖倒置:高层模块依赖抽象,不依赖具体实现
- 易于测试:可以轻松创建Mock实现进行单元测试
- 松耦合:降低组件间的耦合度
- 可扩展性:可以轻松添加新的实现类
- 符合SOLID原则:遵循依赖倒置原则和开闭原则
- 便于依赖注入:可以注册接口而不是具体实现
-
接口设计原则:
- 单一职责:接口只定义协议客户端管理的核心功能
- 简洁明了:只包含必要的方法定义
- 易于理解:方法名称和参数清晰明确
- 向后兼容:保持与原有API的兼容性
影响范围:
- 依赖注入配置更新
- 服务注册方式调整
- 单元测试Mock创建
- 调用方代码适配(使用接口类型)
- 项目引用关系调整(CoreAgent.ProtocolClient项目包含接口定义)
CellularNetworkService集成IProtocolWsClientManager
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs
修改内容:
-
添加IProtocolWsClientManager依赖注入
- 在构造函数中添加
IProtocolWsClientManager protocolWsClientManager
参数 - 添加私有字段
_protocolWsClientManager
存储依赖 - 添加空值检查和异常抛出
- 在构造函数中添加
-
StartNetworkAsync方法添加第12步
- 在步骤11(更新网络状态)之后添加第12步
- 调用
protocolConfigFactory.GetAllConfigs()
获取配置数组 - 调用
_protocolWsClientManager.StartAllClients(protocolConfigs)
启动所有协议客户端 - 添加时间跟踪和错误处理
- 如果启动失败,立即返回失败结果
-
StopAsync方法集成协议客户端停止
- 在步骤4(禁用网络配置)之后添加步骤5(停止所有协议客户端)
- 调用
_protocolWsClientManager.StopAllClients()
停止所有协议客户端 - 添加错误处理,但不中断停止流程
- 重新编号后续步骤(6-9步)
-
修复StopWebSocketTransportAsync方法
- 修正方法实现,使用
CloseAsync()
而不是DisconnectAsync()
- 修正日志信息和返回值逻辑
- 确保方法名称和实现一致
- 修正方法实现,使用
-
具体实现:
// 构造函数添加依赖 public CellularNetworkService( // ... 其他参数 IProtocolWsClientManager protocolWsClientManager) // StartNetworkAsync第12步 // 12. 启动所有协议客户端 var protocolConfigs = protocolConfigFactory.GetAllConfigs(); _protocolWsClientManager.StartAllClients(protocolConfigs); // StopAsync步骤5 // 5. 停止所有协议客户端 _protocolWsClientManager.StopAllClients();
-
设计优势:
- 完整的生命周期管理:启动和停止时都正确处理协议客户端
- 错误隔离:启动失败时立即停止,停止失败时继续执行
- 时间跟踪:为协议客户端操作添加详细的时间记录
- 依赖注入:使用接口编程,便于测试和扩展
- 日志完整:提供详细的启动和停止日志记录
影响范围:
- 蜂窝网络服务依赖注入配置
- 协议客户端生命周期管理
- 网络启动和停止流程
- 服务注册配置更新
LogLayerHelp类名规范化
修改时间: 2024年 修改文件:
- `
ProtocolWsClientManager方法返回类型优化
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/ProtocolWsClientManager.cs
CoreAgent.ProtocolClient/Interfaces/IProtocolWsClientManager.cs
修改内容:
-
StartAllClients方法返回类型修改
- 将返回类型从
void
改为bool
- 添加连接状态检查逻辑,使用
client.IsConnected
判断连接状态 - 统计已连接的客户端数量
- 返回
bool
值表示是否所有客户端都成功启动并连接 - 添加详细的日志记录,包括连接状态信息
- 将返回类型从
-
StopAllClients方法返回类型修改
- 将返回类型从
void
改为bool
- 添加断开连接状态检查逻辑,使用
client.IsConnected
判断连接状态 - 记录停止前的连接状态和停止后的连接状态
- 统计已断开连接的客户端数量
- 返回
bool
值表示是否所有客户端都成功停止并断开连接 - 添加详细的日志记录,包括连接状态变化信息
- 将返回类型从
-
GetAllClientsStatus方法修复
- 修复语法错误,完善方法实现
- 添加线程安全锁保护
- 遍历所有客户端并记录其状态信息
- 包括客户端名称、连接状态(IsConnected)和客户端状态(State)
- 添加空客户端检查
-
接口定义更新
- 更新
IProtocolWsClientManager
接口中的方法签名 StartAllClients
方法返回bool
类型StopAllClients
方法返回bool
类型- 添加详细的XML文档注释说明返回值含义
- 更新
-
具体实现:
// StartAllClients方法 public bool StartAllClients(ProtocolClientConfig[] configs) { // 检查连接状态 if (existingClient.IsConnected) { connectedCount++; } var allConnected = connectedCount == configs.Length; return allConnected; } // StopAllClients方法 public bool StopAllClients() { var client = kvp.Value; var wasConnected = client.IsConnected; client.Stop(); // 检查连接状态 if (!client.IsConnected) { disconnectedCount++; } var allDisconnected = disconnectedCount == _clients.Count; return allDisconnected; } // GetAllClientsStatus方法 public void GetAllClientsStatus() { foreach (var kvp in _clients) { var client = kvp.Value; _logger.LogInformation("客户端状态 - 名称: {ClientName}, 连接状态: {IsConnected}, 客户端状态: {State}", kvp.Key, client.IsConnected, client.State); } }
-
设计优势:
- 状态可追踪:通过返回值可以明确知道操作是否完全成功
- 连接状态监控:使用
IsConnected
属性准确判断连接状态 - 详细日志记录:提供完整的操作过程和状态变化日志
- 线程安全:使用锁保护共享资源访问
- 错误处理完善:提供详细的错误信息和状态统计
- 接口一致性:接口和实现保持完全一致
- 向后兼容:保持方法签名的一致性,只改变返回类型
-
返回值含义:
StartAllClients
返回true
:所有客户端都成功启动并连接StartAllClients
返回false
:部分或全部客户端启动失败或未连接StopAllClients
返回true
:所有客户端都成功停止并断开连接StopAllClients
返回false
:部分或全部客户端停止失败或仍保持连接
影响范围:
- 协议客户端管理器接口契约
- 调用方代码需要处理返回值
- 网络启动和停止流程的状态判断
- 日志记录详细程度提升
- 错误处理和状态监控能力增强
WebSocket传输服务依赖注入修复
修改时间: 2024年 修改文件:
CoreAgent.WebSocketTransport/Extensions/WebSocketTransportExtensions.cs
CoreAgent.API/Startup.cs
修改内容:
-
修复依赖注入顺序问题
- 将
RegisterDefaultMiddleware
移到RegisterCoreServices
之前调用 - 确保中间件在核心服务注册之前就已经注册到容器中
- 解决
provider.GetServices<IMessageMiddleware>()
无法找到服务的问题
- 将
-
修复CacheMiddleware注册方式
- 将
CacheMiddleware
的注册方式从手动工厂方法改为使用AddWebSocketMiddleware<T>
- 简化注册逻辑,确保依赖注入容器能正确处理构造函数参数
- 移除复杂的工厂方法注册,使用标准的依赖注入模式
- 将
-
添加IMemoryCache服务注册
- 在
Startup.cs
的ConfigureServices
方法中添加services.AddMemoryCache()
- 确保
CacheMiddleware
能够正确获取IMemoryCache
依赖 - 在 WebSocket 传输服务注册之前添加内存缓存服务
- 在
-
具体实现:
// WebSocketTransportExtensions.cs - 调整注册顺序 public static IServiceCollection AddWebSocketTransport(...) { // 注册配置 services.Configure<WebSocketConfig>(...); // 注册默认中间件(在核心服务之前) RegisterDefaultMiddleware(services); // 注册核心服务 RegisterCoreServices(services); return services; } // Startup.cs - 添加内存缓存服务 public void ConfigureServices(IServiceCollection services) { // ... 其他服务注册 ... // 添加内存缓存服务(WebSocket中间件需要) services.AddMemoryCache(); // 添加 WebSocket 传输服务 services.AddWebSocketTransport(Configuration, "WebSocket"); }
-
设计优势:
- 依赖顺序正确:确保中间件在核心服务之前注册
- 简化注册逻辑:使用标准的依赖注入模式
- 完整的服务注册:包含所有必要的依赖服务
- 错误预防:避免运行时依赖注入异常
- 代码清晰:注册逻辑更加直观和易于理解
-
修复的问题:
System.InvalidOperationException: Cannot resolve scoped service 'System.Collections.Generic.IEnumerable
1[CoreAgent.WebSocketTransport.Middleware.IMessageMiddleware]' from root provider`- 依赖注入容器无法找到
IMessageMiddleware
服务 CacheMiddleware
无法获取IMemoryCache
依赖
影响范围:
- WebSocket传输服务的依赖注入配置
- 中间件注册和初始化顺序
- 应用程序启动时的服务注册
- 内存缓存服务的可用性
- 错误处理和异常预防
CacheMiddleware构造函数依赖注入修复
修改时间: 2024年 修改文件:
CoreAgent.WebSocketTransport/Middleware/CacheMiddleware.cs
修改内容:
-
修复构造函数参数类型
- 将构造函数参数从
WebSocketConfig config
改为IOptions<WebSocketConfig> config
- 添加
using Microsoft.Extensions.Options;
引用 - 在构造函数中通过
config?.Value
获取配置值
- 将构造函数参数从
-
增强空值检查
- 为所有构造函数参数添加空值检查和异常抛出
- 使用
ArgumentNullException
确保参数有效性 - 提供更明确的错误信息
-
具体实现:
// 修复前 public CacheMiddleware(IMemoryCache cache, ILogger<CacheMiddleware> logger, WebSocketConfig config) { _cache = cache; _logger = logger; _config = config; } // 修复后 public CacheMiddleware(IMemoryCache cache, ILogger<CacheMiddleware> logger, IOptions<WebSocketConfig> config) { _cache = cache ?? throw new ArgumentNullException(nameof(cache)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _config = config?.Value ?? throw new ArgumentNullException(nameof(config)); }
-
设计优势:
- 正确的依赖注入模式:使用
IOptions<T>
模式获取配置 - 强化的错误处理:提供详细的空值检查和异常信息
- 类型安全:确保配置对象正确获取
- 符合最佳实践:遵循 .NET 依赖注入的标准模式
- 正确的依赖注入模式:使用
-
修复的问题:
Unable to resolve service for type 'CoreAgent.WebSocketTransport.Models.WebSocketConfig'
- 依赖注入容器无法直接解析
WebSocketConfig
类型 - 中间件构造函数参数类型不匹配
影响范围:
- CacheMiddleware的依赖注入配置
- WebSocket传输服务的启动
- 配置对象的正确获取
- 错误处理和异常预防
WebSocket中间件生命周期修复
修改时间: 2024年 修改文件:
CoreAgent.WebSocketTransport/Extensions/WebSocketTransportExtensions.cs
修改内容:
-
修复生命周期不匹配问题
- 将中间件注册从
AddScoped
改为AddTransient
- 解决单例服务无法解析作用域服务的问题
- 确保中间件每次使用都创建新实例
- 将中间件注册从
-
生命周期分析
IWebSocketTransport
注册为Singleton
(单例)- 中间件注册为
Transient
(瞬时) - 单例服务可以安全地解析瞬时服务
- 每次获取中间件都会创建新实例
-
具体实现:
// 修复前 services.AddScoped<IMessageMiddleware, T>(); // 修复后 services.AddTransient<IMessageMiddleware, T>();
-
设计优势:
- 生命周期兼容:瞬时服务可以被单例服务安全解析
- 性能优化:中间件每次使用都是新实例,避免状态污染
- 线程安全:瞬时服务天然线程安全
- 内存管理:中间件使用完毕后自动释放
-
修复的问题:
Cannot resolve scoped service 'System.Collections.Generic.IEnumerable
1[CoreAgent.WebSocketTransport.Middleware.IMessageMiddleware]' from root provider`- 单例服务无法解析作用域服务的依赖注入异常
- 生命周期不匹配导致的运行时错误
-
生命周期说明:
- Singleton: 整个应用程序生命周期内只有一个实例
- Scoped: 每个请求作用域内有一个实例
- Transient: 每次请求都创建新实例
- 单例服务只能解析瞬时服务,不能解析作用域服务
影响范围:
- WebSocket中间件的生命周期管理
- 依赖注入容器的服务解析
- 应用程序启动时的服务注册
- 中间件的实例化策略
- 性能和内存使用优化
NetworkConfigCopier方法Bug修复和日志增强
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs
CoreAgent.Domain/Models/Network/NetworkConfigCopyResult.cs
CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs
修改内容:
-
返回类型统一化
- 统一返回类型:所有方法都返回
NetworkConfigCopyResult
类型,不再抛出异常 - 泛型结果类型:创建
NetworkConfigCopyResult<T>
泛型类,支持返回数据 - 接口更新:更新
INetworkConfigCopier
接口以匹配新的返回类型 - 错误处理改进:使用结果对象而不是异常来处理错误情况
- 统一返回类型:所有方法都返回
-
CreateCellularNetworkConfigurationFile方法修复
- 返回类型修改:从
Task<NetworkConfiguration>
改为Task<NetworkConfigCopyResult>
- 路径构建Bug修复:修复
Path.Combine
使用不当的问题,正确构建文件路径 - 参数验证增强:添加完整的参数空值检查,返回失败结果而不是抛出异常
- 目录创建:确保目标目录存在,避免文件写入失败
- 详细日志:添加每个步骤的详细日志记录,包括开始、成功、警告和错误信息
- 返回类型修改:从
-
CreateRadioAccessNetworkConfigurationFile方法修复
- 返回类型修改:从
Task<bool>
改为Task<NetworkConfigCopyResult>
- 参数命名规范化:使用小写开头的参数名,符合C#命名约定
- 目录创建逻辑:添加目录存在性检查和自动创建
- 错误处理增强:返回失败结果而不是抛出异常
- 参数验证:验证文件路径和配置内容不为空
- 返回类型修改:从
-
CreateCoreNetworkImsConfigurationFiles方法重构
- 返回类型修改:从
Task<List<CoreImsConfig>>
改为Task<NetworkConfigCopyResult<List<CoreImsConfig>>>
- 方法重命名:避免与RAN配置文件创建方法名冲突
- 参数验证完善:验证RuntimeCode、配置列表和AppSettings
- 配置项验证:验证每个配置项的PLMN和配置内容
- 目录创建:为CN和IMS配置文件分别创建目录
- 错误隔离:单个配置项失败不影响其他配置项处理
- 详细日志:记录每个配置项的处理过程和结果
- 返回类型修改:从
-
DeleteCellularNetworkConfigurationFile方法增强
- 返回类型修改:从
bool
改为NetworkConfigCopyResult
- 文件存在性检查:删除前检查文件是否存在,避免异常
- 错误隔离:单个文件删除失败不影响其他文件删除
- 删除统计:统计成功删除的文件数量
- 详细日志:记录每个文件的删除状态和结果
- 参数验证:验证NetworkConfiguration参数不为空
- 返回类型修改:从
-
NetworkConfigCopyResult类扩展
- 泛型支持:添加
NetworkConfigCopyResult<T>
泛型类 - 数据返回:支持返回操作结果的同时返回数据
- 继承关系:泛型类继承自基础类,保持类型安全
- 静态工厂方法:提供
Success(T data)
和Failure(string errorMessage)
方法
- 泛型支持:添加
-
具体修复的Bug:
// 修复前 - 路径构建错误 string RanConfigPath = $"{appSettings.RanConfigDirectory}{Path.Combine("RAN", $"{cellular.RuntimeCode}.cfg")}"; // 修复后 - 正确的路径构建 string ranConfigPath = Path.Combine(appSettings.RanConfigDirectory, "RAN", $"{cellular.RuntimeCode}.cfg"); // 修复前 - 抛出异常 throw new ArgumentNullException(nameof(cellular)); // 修复后 - 返回失败结果 return NetworkConfigCopyResult.Failure("CellularNetworkConfiguration 参数为空"); // 修复前 - 返回原始类型 public async Task<NetworkConfiguration> CreateCellularNetworkConfigurationFile(...) // 修复后 - 返回结果类型 public async Task<NetworkConfigCopyResult> CreateCellularNetworkConfigurationFile(...)
-
设计优势:
- 统一错误处理:所有方法都使用结果对象,避免异常传播
- 类型安全:泛型结果类型确保类型安全
- Bug修复:修复路径构建、方法名冲突、文件删除等关键Bug
- 错误处理完善:添加完整的错误处理和错误隔离机制
- 日志详细:提供完整的操作跟踪和调试信息
- 参数验证:确保所有输入参数的有效性
- 目录管理:自动创建必要的目录结构
- 错误隔离:单个操作失败不影响整体流程
- 命名规范:遵循C#命名约定,提高代码可读性
- 方法职责清晰:每个方法都有明确的职责和边界
-
修复的关键问题:
- 异常处理不一致:统一使用结果对象而不是异常
- 路径构建错误:
Path.Combine
使用不当导致路径错误 - 方法名冲突:两个不同功能的方法使用相同名称
- 文件删除异常:删除不存在的文件导致异常
- 目录不存在:目标目录不存在导致文件写入失败
- 错误传播:单个错误导致整个操作失败
- 日志缺失:缺少关键操作的日志记录
影响范围:
- 网络配置文件创建和删除的稳定性
- 错误处理和异常预防
- 日志记录和调试能力
- 代码可读性和维护性
- 文件系统操作的可靠性
- 配置管理的完整性
- 接口契约的一致性
- 调用方代码的错误处理方式
NetworkConfigCopier返回类型优化和GeneralCellularNetworkService适配
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs
CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs
CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
修改内容:
-
CreateCellularNetworkConfigurationFile返回类型优化
- 返回类型修改:从
Task<NetworkConfigCopyResult>
改为Task<NetworkConfigCopyResult<NetworkConfiguration>>
- 数据返回:成功时返回包含
NetworkConfiguration
对象的结果 - 接口更新:更新接口定义以匹配新的返回类型
- 调用方适配:修改调用方代码以正确使用返回的数据
- 返回类型修改:从
-
GeneralCellularNetworkService调用修复
- 返回类型适配:修改调用方式以适配新的泛型返回类型
- 数据获取:直接从结果对象的
Data
属性获取NetworkConfiguration
- 错误处理改进:使用
IsSuccess
属性检查操作是否成功 - 代码简化:移除手动创建
NetworkConfiguration
的代码
-
接口定义更新
- 泛型支持:接口方法返回
Task<NetworkConfigCopyResult<NetworkConfiguration>>
- 文档更新:更新XML文档注释说明返回的数据类型
- 泛型支持:接口方法返回
-
具体修改:
// NetworkConfigCopier.cs - 返回类型修改 // 修复前 public async Task<NetworkConfigCopyResult> CreateCellularNetworkConfigurationFile(...) { // ... 创建NetworkConfiguration对象 return NetworkConfigCopyResult.Success(); // 没有返回数据 } // 修复后 public async Task<NetworkConfigCopyResult<NetworkConfiguration>> CreateCellularNetworkConfigurationFile(...) { // ... 创建NetworkConfiguration对象 return NetworkConfigCopyResult<NetworkConfiguration>.Success(network); // 返回数据 } // GeneralCellularNetworkService.cs - 调用修复 // 修复前 - 手动创建配置对象 var createResult = await _configCopier.CreateCellularNetworkConfigurationFile(cellular, _context.GetAppSettings()); if (!createResult.IsSuccess) { return CellularNetworkOperationResult.Failure($"创建网络配置文件失败: {createResult.ErrorMessage}"); } var config = NetworkConfiguration.Create(cellular.RuntimeCode, Path.Combine(_context.GetAppSettings().RanConfigDirectory, "RAN", $"{cellular.RuntimeCode}.cfg"), new List<CoreImsConfig>()); // 修复后 - 直接使用返回的数据 var createResult = await _configCopier.CreateCellularNetworkConfigurationFile(cellular, _context.GetAppSettings()); if (!createResult.IsSuccess) { return CellularNetworkOperationResult.Failure($"创建网络配置文件失败: {createResult.ErrorMessage}"); } var config = createResult.Data; // 直接获取返回的NetworkConfiguration对象
-
设计优势:
- 数据完整性:返回完整的
NetworkConfiguration
对象,包含所有配置信息 - 类型安全:泛型结果类型确保类型安全
- 代码简化:调用方无需手动创建配置对象
- 错误处理统一:保持统一的错误处理模式
- 接口一致性:接口和实现保持完全一致
- 数据完整性:返回完整的
-
修复的关键问题:
- 数据丢失:原方法创建了
NetworkConfiguration
但没有返回 - 代码重复:调用方需要手动创建配置对象
- 类型不匹配:返回类型与实际需求不匹配
- 接口不一致:接口定义与实际实现不一致
- 数据丢失:原方法创建了
影响范围:
- 网络配置创建流程的数据完整性
- 调用方代码的简化
- 接口契约的一致性
- 类型安全和错误处理
修改CreateCellularNetworkConfigurationFile为元组返回
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs
CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs
CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
修改内容:
-
修改CreateCellularNetworkConfigurationFile返回类型
- 将返回类型从
Task<NetworkConfigCopyResult<NetworkConfiguration>>
改为元组Task<(bool IsSuccess, string ErrorMessage, NetworkConfiguration NetworkConfiguration)>
- 简化返回结构,直接返回三个值:是否成功、错误信息、网络配置对象
- 将返回类型从
-
更新接口定义
- 更新
INetworkConfigCopier
接口中的方法签名 - 更新XML文档注释说明新的返回类型
- 更新
-
更新调用代码
- 修改
GeneralCellularNetworkService.cs
中的调用逻辑 - 使用元组解构语法
var (isSuccess, errorMessage, config) = await ...
- 直接使用解构后的变量
- 修改
-
具体实现:
// 修改前 public async Task<NetworkConfigCopyResult<NetworkConfiguration>> CreateCellularNetworkConfigurationFile(...) { return NetworkConfigCopyResult<NetworkConfiguration>.Failure("错误信息"); return NetworkConfigCopyResult<NetworkConfiguration>.Success(network); } // 修改后 public async Task<(bool IsSuccess, string ErrorMessage, NetworkConfiguration NetworkConfiguration)> CreateCellularNetworkConfigurationFile(...) { return (false, "错误信息", null); return (true, null, network); }
-
调用代码修改:
// 修改前 var createResult = await _configCopier.CreateCellularNetworkConfigurationFile(cellular, _context.GetAppSettings()); if (!createResult.IsSuccess) { return CellularNetworkOperationResult.Failure($"创建网络配置文件失败: {createResult.ErrorMessage}"); } var config = createResult.Data; // 修改后 var (isSuccess, errorMessage, config) = await _configCopier.CreateCellularNetworkConfigurationFile(cellular, _context.GetAppSettings()); if (!isSuccess) { return CellularNetworkOperationResult.Failure($"创建网络配置文件失败: {errorMessage}"); }
-
设计优势:
- 简洁性:元组返回比包装类更简洁
- 直观性:直接返回三个值,语义更清晰
- 性能:避免创建额外的包装对象
- 易用性:使用元组解构语法,代码更简洁
- 类型安全:保持强类型,编译时检查
影响范围:
- 网络配置创建方法的返回类型简化
- 调用代码的简化
- 接口定义的更新
- 代码可读性的提升
修改CreateCoreNetworkImsConfigurationFiles为元组返回
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs
修改内容:
-
修改CreateCoreNetworkImsConfigurationFiles返回类型
- 将返回类型从
Task<NetworkConfigCopyResult<List<CoreImsConfig>>>
改为元组Task<(bool IsSuccess, string ErrorMessage, List<CoreImsConfig> CoreImsConfigs)>
- 简化返回结构,直接返回三个值:是否成功、错误信息、核心IMS配置列表
- 将返回类型从
-
更新调用代码
- 修改
CreateCellularNetworkConfigurationFile
方法中对CreateCoreNetworkImsConfigurationFiles
的调用 - 使用元组解构语法
var (coreImsSuccess, coreImsError, coreImsConfigs) = await ...
- 直接使用解构后的变量
- 修改
-
具体实现:
// 修改前 public async Task<NetworkConfigCopyResult<List<CoreImsConfig>>> CreateCoreNetworkImsConfigurationFiles(...) { return NetworkConfigCopyResult<List<CoreImsConfig>>.Failure("错误信息"); return NetworkConfigCopyResult<List<CoreImsConfig>>.Success(list); } // 修改后 public async Task<(bool IsSuccess, string ErrorMessage, List<CoreImsConfig> CoreImsConfigs)> CreateCoreNetworkImsConfigurationFiles(...) { return (false, "错误信息", null); return (true, null, list); }
-
调用代码修改:
// 修改前 var coreImsResult = await CreateCoreNetworkImsConfigurationFiles(cellular.RuntimeCode, cellular.CoreNetworkImsConfigurations, appSettings); if (!coreImsResult.IsSuccess) { return (false, $"创建核心网络和IMS配置文件失败: {coreImsResult.ErrorMessage}", null); } list = coreImsResult.Data; // 修改后 var (coreImsSuccess, coreImsError, coreImsConfigs) = await CreateCoreNetworkImsConfigurationFiles(cellular.RuntimeCode, cellular.CoreNetworkImsConfigurations, appSettings); if (!coreImsSuccess) { return (false, $"创建核心网络和IMS配置文件失败: {coreImsError}", null); } list = coreImsConfigs;
-
设计优势:
- 一致性:与
CreateCellularNetworkConfigurationFile
方法保持相同的返回模式 - 简洁性:元组返回比包装类更简洁
- 直观性:直接返回三个值,语义更清晰
- 性能:避免创建额外的包装对象
- 易用性:使用元组解构语法,代码更简洁
- 一致性:与
-
接口说明:
CreateCoreNetworkImsConfigurationFiles
是内部方法,不在接口中定义- 只在
NetworkConfigCopier
实现类中使用 - 保持接口的简洁性
影响范围:
- 核心网络和IMS配置文件创建方法的返回类型简化
- 内部方法调用代码的简化
- 代码一致性的提升
- 性能的优化
ProtocolLogProcessor.ProcessLogDetails方法Info字段过滤修复
修改时间: 2024年12月 修改文件:
CoreAgent.ProtocolClient/ProtocolEngineCore/ProtocolLogProcessor.cs
修改内容:
-
修复foreach循环中的Info字段检查
- 在
ProcessLogDetails
方法的foreach
循环中移除Info
字段不为空的检查 - 允许处理所有日志记录,包括
Info
为空的记录 - 保持完整的日志处理和输出功能
- 在
-
修复_protocolLogObserver.OnProtocolLogsReceived调用
- 在调用
_protocolLogObserver.OnProtocolLogsReceived(logDetails)
之前过滤掉Info
为空或无效的记录 - 使用
!string.IsNullOrWhiteSpace(detail.Info)
进行过滤,确保Info字段不为null、空字符串或只包含空白字符 - 确保传递给观察者的数据中只包含有效的
Info
字段 - 添加空集合检查,避免传递空集合给观察者
- 在调用
-
具体实现:
// 修复前 foreach (var detail in logDetails) { try { // 检查Info字段不为空 if (!string.IsNullOrEmpty(detail.Info)) { Console.WriteLine($"处理日志详情:Time={detail.Time} Layer={detail.LayerType}, UEID={detail.UEID}, IMSI={detail.IMSI},PLMN={detail.PLMN},INFO={detail.Info},Messsage={detail.Message}"); // 这里可以添加具体的业务处理逻辑 // 例如:保存到数据库、发送到其他服务等 _logger.LogDebug($"处理日志详情: Layer={detail.LayerType}, UEID={detail.UEID}, IMSI={detail.IMSI}"); } } catch (Exception ex) { _logger.LogError(ex, $"处理日志详情失败: Layer={detail.LayerType}, UEID={detail.UEID}"); } } // 通知协议日志观察者处理转换后的数据 try { // 过滤掉Info为空的记录 var filteredLogDetails = logDetails.Where(detail => !string.IsNullOrEmpty(detail.Info)).ToList(); _protocolLogObserver.OnProtocolLogsReceived(filteredLogDetails); } catch (Exception ex) { _logger.LogError(ex, "通知协议日志观察者失败"); } // 修复后 foreach (var detail in logDetails) { try { Console.WriteLine($"处理日志详情:Time={detail.Time} Layer={detail.LayerType}, UEID={detail.UEID}, IMSI={detail.IMSI},PLMN={detail.PLMN},INFO={detail.Info},Messsage={detail.Message}"); // 这里可以添加具体的业务处理逻辑 // 例如:保存到数据库、发送到其他服务等 _logger.LogDebug($"处理日志详情: Layer={detail.LayerType}, UEID={detail.UEID}, IMSI={detail.IMSI}"); } catch (Exception ex) { _logger.LogError(ex, $"处理日志详情失败: Layer={detail.LayerType}, UEID={detail.UEID}"); } } // 通知协议日志观察者处理转换后的数据 try { // 过滤掉Info为空或无效的记录 var filteredLogDetails = logDetails.Where(detail => !string.IsNullOrWhiteSpace(detail.Info) ).ToList(); if (filteredLogDetails.Any()) { _protocolLogObserver.OnProtocolLogsReceived(filteredLogDetails); } else { _logger.LogDebug("过滤后没有有效的日志记录,跳过观察者通知"); } } catch (Exception ex) { _logger.LogError(ex, "通知协议日志观察者失败"); }
-
设计优势:
- 完整日志处理:处理所有日志记录,包括Info为空的记录
- 数据质量保证:确保传递给观察者的数据中只包含有效的Info字段
- 调试友好:可以看到所有日志记录的详细信息,便于调试
- 观察者模式优化:传递给观察者的数据更加纯净
- 错误预防:避免因空Info字段导致的潜在问题
-
修复的问题:
- 日志信息缺失:原代码会跳过Info为空的记录,导致日志信息不完整
- 调试困难:无法看到所有日志记录的详细信息
- 数据传递问题:将无效数据传递给协议日志观察者
- 信息不完整:处理过程中丢失了部分日志信息
影响范围:
- 协议日志处理的完整性
- 日志输出的完整性
- 协议日志观察者接收的数据质量
- 调试和问题排查能力
GeneralCellularNetworkService.StartNetworkAsync方法步骤注释优化
修改时间: 2024年12月 修改文件:
CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
修改内容:
-
重新注释StartNetworkAsync方法中的步骤
- 为每个步骤添加更详细和清晰的注释说明
- 统一注释格式,使用"步骤X: 功能描述"的格式
- 为每个步骤添加功能说明,解释该步骤的具体作用
- 保持原有的时间跟踪和日志记录功能
-
具体修改的步骤注释:
- 步骤1: 创建蜂窝网络配置文件 - 根据传入的蜂窝网络配置和应用程序设置,创建临时配置文件
- 步骤2: 执行网络接口初始化命令 - 初始化网络接口,确保网络环境准备就绪
- 步骤3: 复制配置值到临时目录 - 将网络配置的关键参数复制到系统临时目录,供后续步骤使用
- 步骤4: 获取并验证IP端点信息 - 从配置中提取通信地址信息,验证端点的有效性
- 步骤5: 更新IP端点管理器 - 将获取到的端点信息更新到网络上下文中的端点管理器
- 步骤6: 创建协议客户端配置 - 基于网络实体信息创建协议客户端配置,为后续的协议通信做准备
- 步骤7: 启动WebSocket传输连接 - 建立与协议服务器的WebSocket连接,为数据传输做准备
- 步骤8: 启动网络配置 - 启用网络接口配置,激活蜂窝网络连接
- 步骤9: 更新网络配置类型 - 根据启动结果更新网络配置类型,记录当前使用的配置类型
- 步骤10: 检查网络端点连接状态 - 验证所有网络端点的连接状态,确保网络连接正常
- 步骤11: 更新网络状态 - 将网络状态标记为已启动,更新内部状态管理
- 步骤12: 启动所有协议客户端 - 启动所有协议客户端,开始协议数据采集和传输
-
设计优势:
- 注释清晰:每个步骤都有明确的功能描述
- 格式统一:使用一致的注释格式,提高可读性
- 功能说明:详细解释每个步骤的作用和目的
- 易于理解:帮助开发者快速理解网络启动流程
- 维护友好:清晰的注释便于后续维护和修改
-
注释示例:
// 步骤1: 创建蜂窝网络配置文件 // 根据传入的蜂窝网络配置和应用程序设置,创建临时配置文件 var step1Start = DateTime.UtcNow; _logger.LogDebug("步骤1开始:创建蜂窝网络配置文件"); // 步骤2: 执行网络接口初始化命令 // 初始化网络接口,确保网络环境准备就绪 var step2Start = DateTime.UtcNow; _logger.LogDebug("步骤2开始:执行网络接口初始化命令");
影响范围:
- 网络启动流程的代码可读性
- 开发者对网络启动过程的理解
- 代码维护和调试的便利性
- 新团队成员的学习成本
GeneralCellularNetworkService网络状态恢复机制优化
修改时间: 2024年12月 修改文件:
CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
修改内容:
-
重新命名和优化恢复方法
- 将
StartRestore
方法重命名为RestoreNetworkStateAsync
- 添加完整的XML文档注释说明方法用途
- 返回
bool
类型表示恢复操作是否成功 - 移除直接抛出异常的代码,改为记录日志并返回失败状态
- 将
-
完善恢复流程
- 步骤1: 停止所有协议客户端
- 步骤2: 关闭WebSocket传输连接
- 步骤3: 执行网络接口初始化命令,重置网络状态
- 步骤4: 重置网络上下文状态
- 每个步骤都有独立的异常处理,确保单个步骤失败不影响其他步骤
-
在步骤10之后的所有步骤中添加恢复机制
- 步骤10: 网络端点状态检查失败时调用恢复
- 步骤11: 更新网络状态失败时调用恢复
- 步骤12: 启动协议客户端失败时调用恢复
- 确保在任何步骤失败时都能正确清理资源
-
具体实现:
// 恢复方法优化 private async Task<bool> RestoreNetworkStateAsync() { try { _logger.LogInformation("开始恢复网络状态"); // 1. 停止所有协议客户端 try { _protocolWsClientManager.StopAllClients(); _logger.LogDebug("协议客户端停止完成"); } catch (Exception ex) { _logger.LogWarning(ex, "停止协议客户端时出现异常,继续执行恢复流程"); } // 2. 关闭WebSocket传输连接 try { if (_webSocketTransport.IsConnected) { await _webSocketTransport.CloseAsync(); _logger.LogDebug("WebSocket传输连接关闭完成"); } } catch (Exception ex) { _logger.LogWarning(ex, "关闭WebSocket传输连接时出现异常,继续执行恢复流程"); } // 3. 执行网络接口初始化命令,重置网络状态 try { var initResult = await _interfaceManager.ExecuteInitializeCommandsAsync(true); if (!initResult.IsSuccess) { _logger.LogWarning("执行网络接口初始化命令失败: {ErrorMessage}", initResult.ErrorMessage); } else { _logger.LogDebug("网络接口初始化命令执行成功"); } } catch (Exception ex) { _logger.LogWarning(ex, "执行网络接口初始化命令时出现异常"); } // 4. 重置网络上下文状态 _context.Reset(); _logger.LogDebug("网络上下文状态重置完成"); _logger.LogInformation("网络状态恢复完成"); return true; } catch (Exception ex) { _logger.LogError(ex, "恢复网络状态过程中出现未预期的异常"); return false; } }
-
步骤10-12的恢复调用:
// 步骤10: 网络端点状态检查失败 if (!statusCheckResult.IsSuccess) { var errorMessage = string.Join("; ", statusCheckResult.ErrorMessage); _logger.LogWarning("网络端点状态检查未通过: {ErrorMessage}", errorMessage); await RestoreNetworkStateAsync(); return CellularNetworkOperationResult.Failure($"网络端点状态检查失败: {errorMessage}"); } // 步骤11: 更新网络状态 var state = _context.GetNetworkState(); state.MarkAsStarted(); // 步骤12: 启动协议客户端失败 try { var protocolConfigs = protocolConfigFactory.GetAllConfigs(); var startResult = _protocolWsClientManager.StartAllClients(protocolConfigs); if (!startResult) { _logger.LogWarning("部分协议客户端启动失败"); await RestoreNetworkStateAsync(); return CellularNetworkOperationResult.Failure("部分协议客户端启动失败"); } _logger.LogInformation("所有协议客户端启动完成"); } catch (Exception ex) { _logger.LogError(ex, "启动协议客户端失败"); await RestoreNetworkStateAsync(); return CellularNetworkOperationResult.Failure($"启动协议客户端失败: {ex.Message}"); }
-
设计优势:
- 完整的资源清理:确保所有已创建的资源都被正确清理
- 错误隔离:每个恢复步骤都有独立的异常处理,避免单个失败影响整体恢复
- 详细日志记录:提供完整的恢复过程日志,便于问题排查
- 状态一致性:确保网络状态在失败时能够恢复到初始状态
- 方法命名清晰:
RestoreNetworkStateAsync
明确表达方法功能 - 返回值有意义:返回bool值表示恢复操作是否成功
- 异常处理完善:不直接抛出异常,而是记录日志并返回失败状态
影响范围:
- 网络启动失败时的资源清理机制
- 网络状态恢复的可靠性
- 错误处理和日志记录的完整性
- 系统稳定性和资源管理
- 调试和问题排查能力
优化GeneralCellularNetworkService中的RestoreNetworkStateAsync方法和启动流程
修改时间: 2024年12月 修改文件:
CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
修改内容:
-
问题描述:
RestoreNetworkStateAsync
方法返回布尔值但调用方不做判断,返回值无意义- 步骤12(启动所有协议客户端)代码较长,需要提取为单独方法以提高可读性
- 需要确保只有步骤1成功时才继续执行后续步骤
- 删除临时配置文件这一步无论成功还是失败都需要执行
-
修复方案:
- 将
RestoreNetworkStateAsync
方法改为void
返回类型,移除不必要的返回值 - 提取步骤12的协议客户端启动逻辑到单独的私有方法
StartAllProtocolClientsAsync
- 重构
StartNetworkAsync
方法,将步骤1和删除临时配置文件分离 - 提取步骤2-12到新的私有方法
ExecuteRemainingStepsAsync
- 确保删除临时配置文件无论成功还是失败都会执行
- 将
-
具体修改: RestoreNetworkStateAsync 方法优化:
// 修改前 private async Task<bool> RestoreNetworkStateAsync() // 修改后 private async Task RestoreNetworkStateAsync()
新增 StartAllProtocolClientsAsync 方法:
/// <summary> /// 启动所有协议客户端 /// </summary> /// <param name="protocolConfigFactory">协议配置工厂</param> /// <returns>启动结果</returns> private async Task<CellularNetworkOperationResult> StartAllProtocolClientsAsync(ProtocolClientConfigFactory protocolConfigFactory)
新增 ExecuteRemainingStepsAsync 方法:
/// <summary> /// 执行剩余的启动步骤(步骤2-12) /// </summary> /// <param name="config">网络配置</param> /// <param name="key">配置键</param> /// <param name="startTime">开始时间</param> /// <returns>执行结果</returns> private async Task<CellularNetworkOperationResult> ExecuteRemainingStepsAsync(object config, string key, DateTime startTime)
StartNetworkAsync 方法重构:
// 步骤1成功后,调用ExecuteRemainingStepsAsync执行后续步骤 var result = await ExecuteRemainingStepsAsync(config, key, startTime); // 删除临时配置文件 - 无论成功还是失败都需要执行 var deleteResult = _configCopier.DeleteCellularNetworkConfigurationFile(config); // 记录结果但不影响返回值
-
影响范围:
- 简化了方法调用,移除了不必要的返回值判断
- 提高了代码可读性和维护性
- 确保了步骤1的成功验证逻辑
- 保证了临时配置文件的清理操作总是执行
- 保持了原有的错误处理逻辑
代码提交 - 完善网络配置和协议客户端功能
修改时间: 2024年12月
提交信息: 更新代码:完善网络配置和协议客户端功能
提交哈希: d011b25
修改内容:
-
GeneralCellularNetworkService网络状态恢复机制优化
- 重新命名和优化恢复方法:将
StartRestore
重命名为RestoreNetworkStateAsync
- 完善恢复流程:停止协议客户端、关闭WebSocket连接、重置网络状态
- 在步骤10-12中添加恢复机制,确保失败时能正确清理资源
- 添加完整的异常处理和日志记录
- 重新命名和优化恢复方法:将
-
ProtocolLogProcessor.ProcessLogDetails方法Info字段过滤修复
- 修复foreach循环中的Info字段检查,允许处理所有日志记录
- 在调用观察者之前过滤掉Info为空或无效的记录
- 确保传递给观察者的数据质量,添加空集合检查
-
GeneralCellularNetworkService.StartNetworkAsync方法步骤注释优化
- 为每个步骤添加详细和清晰的功能说明注释
- 统一注释格式,使用"步骤X: 功能描述"的格式
- 提高代码可读性和维护性
-
NetworkConfigCopier方法Bug修复和日志增强
- 统一返回类型为
NetworkConfigCopyResult
,不再抛出异常 - 修复路径构建Bug,正确使用
Path.Combine
- 添加完整的参数验证和目录创建逻辑
- 增强错误处理和详细日志记录
- 统一返回类型为
-
WebSocket传输服务依赖注入修复
- 修复依赖注入顺序问题,确保中间件在核心服务之前注册
- 修复CacheMiddleware注册方式,使用标准的依赖注入模式
- 添加IMemoryCache服务注册,确保中间件依赖完整
-
ProtocolWsClientManager方法参数优化
- 简化构造函数,移除配置参数
- 修改StartAllClients方法签名,添加配置参数
- 采用面向接口编程,创建IProtocolWsClientManager接口
-
CellularNetworkService集成协议客户端管理
- 添加IProtocolWsClientManager依赖注入
- 在StartNetworkAsync方法中添加协议客户端启动步骤
- 在StopAsync方法中集成协议客户端停止逻辑
- 添加时间跟踪记录,提供详细的性能监控
-
MessageTransferProtocolLog模型创建
- 创建新的协议日志模型,解决命名冲突
- 修改NetworkProtocolLogObserver转换逻辑
- 添加类型转换和字段映射
-
蜂窝网络配置实体类创建
- 创建CellularNetworkConfiguration实体类
- 创建CoreNetworkImsConfiguration实体类
- 添加数据校验功能和ValidationResult类
-
NetworkProtocolLogObserver中的StopChannelManager方法修复
- 修复资源管理问题,避免过早释放
- 优化通道管理方法,职责更加清晰
- 添加自动重连配置选项
- 修复WebSocket配置文件
影响范围:
- 网络配置和协议客户端功能的完整性
- 错误处理和资源管理的可靠性
- 代码可读性和维护性的提升
- 依赖注入配置的完善
- 日志记录和调试能力的增强
- 系统稳定性和性能监控的改进
2024年修改记录
修复NetworkProtocolLogObserver中的StopChannelManager方法并支持重新创建
修改时间: 2024年12月 修改文件:
CoreAgent.Infrastructure/Services/Network/NetworkProtocolLogObserver.cs
CoreAgent.WebSocketTransport/Interfaces/IMessageChannelManager.cs
CoreAgent.WebSocketTransport/Services/MessageChannelManager.cs
修改内容:
-
问题描述:
StopChannelManager()
方法直接调用_ChannelManager.Dispose()
可能导致资源过早释放IMessageChannelManager
接口已实现IDisposable
,生命周期应由DI容器管理- 直接调用
Dispose()
可能影响其他使用该实例的组件
-
修复方案:
-
修改
MessageChannelManager
设计,不在构造函数中创建通道 -
移除构造函数中的默认参数,要求必须传入容量参数
-
添加容量参数验证,确保参数有效性
-
扩展
WebSocketConfig
配置类,添加分别的通道容量配置 -
更新依赖注入注册,从配置中读取不同的通道容量
-
优化通道管理方法,职责更加清晰:
CreateChannels()
- 安全创建(已存在则跳过)ClearAllChannels()
- 清空通道消息(保持通道可用)CompleteAllChannels()
- 完成通道(标记不再接受新消息,但保持可读)ReleaseChannels()
- 完全释放通道资源
-
将
StopChannelManager()
改为调用ReleaseChannels()
-
将
RecreateChannelManager()
改为调用CreateChannels()
-
优化通道创建逻辑:
- 修改
CreateChannels()
方法,如果通道已存在则先释放再创建 - 移除
ResetChannels()
方法,避免功能重复 - 简化接口设计,减少方法数量
- 修改
-
WebSocketTransport 集成通道管理:
- 重构
ConnectInternalAsync()
方法,提取为多个独立方法:CreateMessageChannels()
- 先创建消息通道(同步方法)EstablishWebSocketConnectionAsync()
- 再建立WebSocket连接(异步方法)StartBackgroundTasks()
- 最后启动后台任务(同步方法)
- 在
CloseAsync()
中调用_channelManager.ReleaseChannels()
释放通道 - 在重连失败时也释放通道,确保资源正确清理
- 通道生命周期与WebSocket连接生命周期完全同步
- 重构
-
添加自动重连配置选项:
- 在
WebSocketConfig
中添加EnableAutoReconnect
配置项 - 在
TriggerReconnect()
方法中添加配置检查 - 支持通过配置文件控制是否启用自动重连功能
- 在
-
修复WebSocket配置文件:
- 更新
websocket.json
和websocket.Development.json
配置文件 - 添加所有新增的配置项:
EnableAutoReconnect
、SendChannelCapacity
、ReceiveChannelCapacity
、PriorityChannelCapacity
、MaxChunkSize
、ChunkDelayMs
- 为开发环境和生产环境提供不同的配置值
- 更新
-
添加重复调用检查,避免二次调用导致异常
-
添加异常处理和日志记录
-
保持方法功能的同时避免资源管理问题
-
-
具体修改: IMessageChannelManager 接口新增方法:
/// <summary> /// 创建所有通道 /// </summary> void CreateChannels(); /// <summary> /// 释放所有通道 /// </summary> void ReleaseChannels();
MessageChannelManager 实现:
// 构造函数要求必须传入容量参数,并验证参数有效性 public MessageChannelManager(ILogger<MessageChannelManager> logger, int sendChannelCapacity, int receiveChannelCapacity, int priorityChannelCapacity) { // 验证容量参数 if (sendChannelCapacity <= 0) throw new ArgumentOutOfRangeException(...); // 保存容量配置,不创建通道 } // 安全创建通道(如果已存在则跳过) public void CreateChannels() { // 检查通道是否已存在,如果存在则跳过创建 } // 清空通道消息(保持通道可用) public void ClearAllChannels() { // 清空所有通道中的消息,但保持通道结构 } // 完成通道(标记不再接受新消息,但保持可读) public void CompleteAllChannels() { // 标记通道完成,不再接受新消息,但可以继续读取 } // 完全释放通道资源 public void ReleaseChannels() { // 完成通道,释放资源,清空引用 }
WebSocketConfig 配置扩展:
public class WebSocketConfig { // 是否启用自动重连功能 public bool EnableAutoReconnect { get; set; } = true; // 最大重连尝试次数 public int MaxReconnectAttempts { get; set; } = 5; // 发送通道容量 public int SendChannelCapacity { get; set; } = 1000; // 接收通道容量 public int ReceiveChannelCapacity { get; set; } = 1000; // 优先级通道容量 public int PriorityChannelCapacity { get; set; } = 100; }
依赖注入注册更新:
services.AddSingleton<IMessageChannelManager>(provider => { var config = provider.GetRequiredService<IOptions<WebSocketConfig>>().Value; return new MessageChannelManager(logger, config.SendChannelCapacity, config.ReceiveChannelCapacity, config.PriorityChannelCapacity); });
NetworkProtocolLogObserver 修改:
public void StopChannelManager() { // 调用 ReleaseChannels() 释放通道 _ChannelManager.ReleaseChannels(); } public void RecreateChannelManager() { // 调用 CreateChannels() 重新创建通道(会自动释放现有通道) _ChannelManager.CreateChannels(); }
WebSocketTransport 重构:
// 连接时先创建通道,再建立连接 private async Task ConnectInternalAsync(CancellationToken cancellationToken) { // 1. 先创建消息通道 await CreateMessageChannelsAsync(); // 2. 再建立 WebSocket 连接 await EstablishWebSocketConnectionAsync(cancellationToken); // 3. 最后启动后台任务 await StartBackgroundTasksAsync(); } // 提取的独立方法 private void CreateMessageChannels() { _channelManager.CreateChannels(); } private async Task EstablishWebSocketConnectionAsync(CancellationToken cancellationToken) { await _connection.ConnectAsync(...); } private void StartBackgroundTasks() { // 启动发送、接收、心跳任务 }
-
修复优势:
- 配置灵活性: 支持通过配置文件分别设置不同通道的容量,更加灵活
- 参数验证: 构造函数中验证容量参数,确保参数有效性
- 方法职责清晰: 每个方法职责明确,避免功能重叠
- 生命周期控制: 通道的创建和释放完全由用户控制,更加灵活
- 资源管理: 避免在构造函数中创建资源,符合延迟初始化原则
- 重复使用: 支持多次创建和释放,满足业务需求
- 重复调用保护: 防止二次调用导致异常,提高系统稳定性
- 异常处理: 添加了完整的异常处理和日志记录,但不影响主程序运行
- 业务连续性: 异常被捕获并记录,但不会中断主程序流程
- 功能保持: 仍然能够正确停止和重新创建通道管理器
- 日志完善: 提供了详细的调试和错误日志信息
创建蜂窝网络配置实体类
创建蜂窝网络配置实体类
修改时间: 2024年 修改文件:
CoreAgent.Domain/Models/Network/CellularNetworkConfiguration.cs
(新建)
修改内容:
-
创建CellularNetworkConfiguration实体类
- 包含设备代码(DeviceCode)字符串属性
- 包含运行时代码(RuntimeCode)字符串属性
- 包含无线接入网配置(RadioAccessNetworkConfiguration)字符串属性
- 包含核心网IMS配置集合(List)属性
-
创建CoreNetworkImsConfiguration实体类
- 包含索引(Index)整数属性
- 包含PLMN标识(Plmn)字符串属性
- 包含核心网配置(CoreNetworkConfiguration)字符串属性
- 包含IMS服务配置(ImsServiceConfiguration)字符串属性
-
具体实现:
/// <summary> /// 蜂窝网络配置实体 /// </summary> public class CellularNetworkConfiguration { /// <summary> /// 设备代码 /// </summary> public string DeviceCode { get; set; } /// <summary> /// 运行时代码 /// </summary> public string RuntimeCode { get; set; } /// <summary> /// 无线接入网配置 /// </summary> public string RadioAccessNetworkConfiguration { get; set; } /// <summary> /// 核心网IMS配置集合 /// </summary> public List<CoreNetworkImsConfiguration> CoreNetworkImsConfigurations { get; set; } = new List<CoreNetworkImsConfiguration>(); } /// <summary> /// 核心网IMS配置对象 /// </summary> public class CoreNetworkImsConfiguration { /// <summary> /// 索引 /// </summary> public int Index { get; set; } /// <summary> /// PLMN标识 /// </summary> public string Plmn { get; set; } /// <summary> /// 核心网配置 /// </summary> public string CoreNetworkConfiguration { get; set; } /// <summary> /// IMS服务配置 /// </summary> public string ImsServiceConfiguration { get; set; } }
-
设计优势:
- 命名规范:遵循C#命名约定,使用PascalCase
- 命名清晰:类名明确表达业务含义,提高代码可读性
- 属性专业:使用完整的专业术语,避免缩写和模糊命名
- 类型安全:使用强类型属性,避免类型错误
- 文档完整:每个属性都有详细的XML文档注释
- 集合初始化:使用集合初始化器确保集合不为null
- 职责清晰:每个类都有明确的职责和用途
- 易于扩展:结构清晰,便于后续添加新属性
- 业务导向:类名直接反映业务领域概念
- 专业术语:使用标准的电信网络术语,提高代码专业性
添加蜂窝网络配置数据校验功能
修改时间: 2024年 修改文件:
CoreAgent.Domain/Models/Network/CellularNetworkConfiguration.cs
修改内容:
-
添加数据校验功能
- 为
DeviceCode
和RuntimeCode
添加[Required]
特性,确保不能为空 - 为
Plmn
添加[Required]
特性,确保不能为空 - 添加
ValidateConfiguration()
方法进行业务逻辑校验
- 为
-
业务规则校验
- 验证
DeviceCode
和RuntimeCode
不能为空 - 验证
RadioAccessNetworkConfiguration
和CoreNetworkImsConfigurations
至少有一个有数据 - 验证
CoreNetworkImsConfiguration
中的CoreNetworkConfiguration
和ImsServiceConfiguration
至少有一个有数据
- 验证
-
创建ValidationResult类
- 提供统一的验证结果返回格式
- 支持成功和失败两种状态
- 提供详细的错误消息
- 支持隐式转换操作符
-
具体实现:
// 必填字段校验 [Required(ErrorMessage = "设备代码不能为空")] public string DeviceCode { get; set; } [Required(ErrorMessage = "运行时代码不能为空")] public string RuntimeCode { get; set; } // 业务逻辑校验 public ValidationResult ValidateConfiguration() { // 验证必填字段 if (string.IsNullOrWhiteSpace(DeviceCode)) { return new ValidationResult("设备代码不能为空"); } // 验证无线接入网配置和核心网IMS配置至少有一个有数据 var hasRadioAccessConfig = !string.IsNullOrWhiteSpace(RadioAccessNetworkConfiguration); var hasCoreNetworkConfigs = CoreNetworkImsConfigurations?.Any() == true; if (!hasRadioAccessConfig && !hasCoreNetworkConfigs) { return new ValidationResult("无线接入网配置和核心网IMS配置至少需要配置其中一项"); } return ValidationResult.Success; }
-
设计优势:
- 数据完整性:确保必填字段不为空
- 业务规则校验:验证业务逻辑的正确性
- 统一验证接口:提供一致的验证方法
- 详细错误信息:提供具体的错误描述
- 分层校验:支持嵌套对象的校验
- 易于扩展:可以轻松添加新的校验规则
影响范围:
- 蜂窝网络配置数据模型定义
- 核心网IMS配置管理
- 数据实体结构标准化
- 领域模型完整性
- 代码可读性和维护性提升
- 数据校验和业务规则验证
- 错误处理和用户反馈
创建MessageTransferProtocolLog模型解决命名冲突
修改时间: 2024年 修改文件:
CoreAgent.WebSocketTransport/Models/MessageTransferProtocolLog.cs
(新建)CoreAgent.Infrastructure/Services/Network/NetworkProtocolLogObserver.cs
修改内容:
-
创建MessageTransferProtocolLog模型
- 在
CoreAgent.WebSocketTransport
项目中创建新的协议日志模型 - 与
CoreAgent.ProtocolClient
中的TransferProtocolLog
区分开 - 保持相同的字段结构,避免命名冲突
- 专门用于WebSocket传输层的协议日志数据传输
- 在
-
修改NetworkProtocolLogObserver转换逻辑
- 在
OnProtocolLogsReceived
方法中添加类型转换 - 将
CoreAgent.ProtocolClient.TransferProtocolLog
转换为CoreAgent.WebSocketTransport.MessageTransferProtocolLog
- 保持所有字段的完整映射
- 添加必要的using语句引用
- 在
-
具体实现:
// 时间跟踪和性能监控 var startTime = DateTime.UtcNow; // 空值检查 if (logDetails == null) { _logger.LogWarning("接收到的协议日志为空"); return; } // 转换为列表以避免多次枚举 var logList = logDetails.ToList(); var logCount = logList.Count; // 空集合检查 if (logCount == 0) { _logger.LogDebug("接收到的协议日志集合为空,跳过处理"); return; } // 类型转换逻辑 var webSocketLogs = logList.Select(log => new MessageTransferProtocolLog { Id = log.Id, LayerType = log.LayerType.ToString(), MessageDetailJson = log.MessageDetailJson, CellID = log.CellID, IMSI = log.IMSI, Direction = log.Direction, UEID = log.UEID, PLMN = log.PLMN, TimeMs = log.TimeMs, Timestamp = log.Timestamp, Info = log.Info, Message = log.Message }); // 通道写入状态监控 var writeSuccess = _ChannelManager.SendChannel.TryWrite(webSocketLogs); var processingTime = DateTime.UtcNow - startTime; if (writeSuccess) { _logger.LogDebug("协议日志处理成功,数量: {LogCount}, 处理时间: {ProcessingTime}ms", logCount, processingTime.TotalMilliseconds); } else { _logger.LogWarning("协议日志写入通道失败,数量: {LogCount}, 处理时间: {ProcessingTime}ms, 通道可能已满或已关闭", logCount, processingTime.TotalMilliseconds); }
-
设计优势:
- 命名清晰:
MessageTransferProtocolLog
明确表示用于消息传输 - 避免冲突:与原始
TransferProtocolLog
有明确区分 - 职责分离:WebSocket传输层有独立的协议日志模型
- 类型安全:通过显式转换确保类型安全
- 易于维护:清晰的命名约定便于理解和维护
- 性能监控:添加时间跟踪和通道写入状态监控
- 错误处理:完善的异常处理和日志记录
- Bug修复:修复空引用检查和多次枚举的性能问题
- 边界处理:添加空集合检查,避免处理空集合
- 代码规范:优化ProtocolMessage模型注释,提高代码可读性
- 命名清晰:
影响范围:
- WebSocket传输层协议日志处理
- 协议日志观察者模式实现
- 跨项目类型转换逻辑
- 协议消息模型注释优化
CellularNetworkService.StartNetworkAsync 方法添加协议客户端配置创建
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs
修改内容:
-
调整执行步骤顺序
- 将原来的第5.5步改为第6步(创建协议客户端配置)
- 将WebSocket传输连接移到第7步(在网络配置启动之前)
- 重新编号后续步骤(8-11步)
- 优化执行顺序:确保WebSocket连接在网络配置启动之前完成
-
添加第7步WebSocket传输连接
- 在
StartNetworkAsync
方法的第6步(创建协议客户端配置)之后添加第7步 - 注入
IWebSocketTransport
依赖 - 创建独立的
StartWebSocketTransportAsync()
方法处理连接逻辑 - 返回
bool
值表示连接是否成功 - 添加连接状态检查和错误处理
- 严格检查:WebSocket连接失败时立即返回失败结果,提示服务端可能未启动
- 在
-
修复Logger类型问题
- 添加
ILoggerFactory
依赖注入到构造函数 - 使用
_loggerFactory.CreateLogger<ProtocolClientConfigFactory>()
创建正确类型的Logger - 确保
ProtocolClientConfigFactory
获得正确的Logger实例
- 添加
-
具体实现:
// 6. 创建协议客户端配置 var protocolConfigFactory = new ProtocolClientConfigFactory(_loggerFactory.CreateLogger<ProtocolClientConfigFactory>(), _context); var configCreated = protocolConfigFactory.CreateFromEntities(); if (configCreated) { _logger.LogInformation("协议客户端配置创建成功,共创建 {ConfigCount} 个配置", protocolConfigFactory.ConfigCount); } else { _logger.LogWarning("协议客户端配置创建失败"); return CellularNetworkOperationResult.Failure("协议客户端配置创建失败"); } // 7. 启动 WebSocket 传输连接 var webSocketConnected = await StartWebSocketTransportAsync(); if (!webSocketConnected) { _logger.LogError("WebSocket 传输连接启动失败,服务端可能未启动"); return CellularNetworkOperationResult.Failure("WebSocket 传输连接启动失败,服务端可能未启动"); } _logger.LogInformation("WebSocket 传输连接启动成功");
-
添加必要的依赖注入
- 添加
ILoggerFactory loggerFactory
参数到构造函数 - 添加
IWebSocketTransport webSocketTransport
参数到构造函数 - 添加
using CoreAgent.Infrastructure.Services.Network;
以支持ProtocolClientConfigFactory
- 添加
using CoreAgent.WebSocketTransport.Interfaces;
以支持IWebSocketTransport
- 添加
-
设计优势:
- 在IP端点信息准备完成后立即创建协议客户端配置
- 不依赖网络启动结果,确保配置创建的独立性
- 在网络配置启动之前启动WebSocket传输连接
- 提供详细的日志记录便于调试
- 保持代码的简洁性和可维护性
- 正确处理Logger类型,避免类型不匹配问题
- 优化执行顺序,提高错误隔离能力
- 完善的错误处理机制,确保配置创建失败时及时停止
- 严格检查机制,WebSocket连接失败时立即停止网络启动流程
- 方法职责单一,WebSocket连接逻辑独立封装
影响范围:
- 蜂窝网络启动流程
- 协议客户端配置管理
- WebSocket传输服务集成
- 网络状态监控
- 依赖注入配置(需要更新服务注册)
CellularNetworkService构造函数添加IProtocolLogObserver依赖
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs
修改内容:
-
添加IProtocolLogObserver依赖注入
- 在构造函数中添加
IProtocolLogObserver protocolLogObserver
参数 - 添加私有字段
_protocolLogObserver
存储依赖 - 添加空值检查和异常抛出
- 在构造函数中添加
-
添加必要的using语句
- 添加
using CoreAgent.ProtocolClient.ProtocolEngineCore;
以支持IProtocolLogObserver
- 添加
-
具体实现:
// 构造函数参数 public CellularNetworkService( // ... 其他参数 IWebSocketTransport webSocketTransport, IProtocolLogObserver protocolLogObserver) // 私有字段 private readonly IProtocolLogObserver _protocolLogObserver; // 构造函数初始化 _protocolLogObserver = protocolLogObserver ?? throw new ArgumentNullException(nameof(protocolLogObserver));
-
设计优势:
- 为后续协议客户端管理提供必要的依赖
- 保持依赖注入的一致性
- 提供空值检查确保服务稳定性
- 为协议日志观察者模式提供支持
影响范围:
- 蜂窝网络服务依赖注入配置
- 协议客户端日志观察者集成
- 服务注册配置更新
StartNetworkAsync方法添加时间跟踪记录
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs
修改内容:
-
添加整体时间跟踪
- 在方法开始时记录开始时间
- 在方法结束时计算总耗时并记录
- 使用UTC时间确保时间一致性
-
为每个步骤添加详细时间跟踪
- 为11个步骤中的每个步骤添加开始和结束时间记录
- 使用
LogDebug
级别记录每个步骤的耗时 - 保持原有的
LogInformation
和LogError
级别日志不变
-
具体实现:
// 方法开始时间跟踪 var startTime = DateTime.UtcNow; _logger.LogInformation("开始启动网络配置 {ConfigKey},开始时间: {StartTime}", key, startTime.ToString("yyyy-MM-dd HH:mm:ss.fff")); // 每个步骤的时间跟踪 var stepXStart = DateTime.UtcNow; _logger.LogDebug("步骤X开始:[步骤描述]"); // 步骤执行逻辑... var stepXDuration = (DateTime.UtcNow - stepXStart).TotalMilliseconds; _logger.LogDebug("步骤X完成:[步骤描述],耗时: {Duration}ms", stepXDuration.ToString("F2")); // 方法结束时间跟踪 var endTime = DateTime.UtcNow; var duration = endTime - startTime; _logger.LogInformation("蜂窝网络配置 {ConfigKey} 启动成功,当前状态: {Status},总耗时: {Duration}ms", key, state.CurrentStatus, duration.TotalMilliseconds.ToString("F2"));
-
设计优势:
- 性能监控:可以识别网络启动过程中的性能瓶颈
- 调试支持:详细的时间信息有助于问题定位和性能优化
- 日志分级:使用Debug级别避免生产环境日志过多
- 时间精度:使用毫秒级精度提供准确的性能数据
- UTC时间:确保时间记录的一致性和准确性
- 非侵入性:不影响原有的业务逻辑和错误处理
-
跟踪的步骤:
- 步骤1:获取并验证网络配置
- 步骤2:执行网络接口初始化命令
- 步骤3:复制配置值到临时目录
- 步骤4:获取并验证 IP 端点信息
- 步骤5:更新 IP 端点管理器
- 步骤6:创建协议客户端配置
- 步骤7:启动 WebSocket 传输连接
- 步骤8:启动网络配置
- 步骤9:更新网络配置类型
- 步骤10:检查网络端点连接状态
- 步骤11:更新网络状态
影响范围:
- 网络启动性能监控
- 调试和问题定位
- 日志记录详细程度
- 性能优化分析
ProtocolWsClientManager方法参数优化
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/ProtocolWsClientManager.cs
修改内容:
-
简化构造函数
- 移除
ProtocolClientConfig[] configs
参数 - 构造函数只保留必要的依赖:
ILogger
、IProtocolLogObserver
、ILoggerFactory
- 移除私有字段
_configs
,不再在构造函数中存储配置
- 移除
-
修改StartAllClients方法签名
- 添加
ProtocolClientConfig[] configs
参数 - 方法接收配置数组作为参数,而不是依赖构造函数中的配置
- 添加参数验证,检查
configs
是否为 null 或空数组
- 添加
-
优化方法逻辑
- 将配置验证移到方法开始处
- 使用传入的
configs
参数替代私有字段 - 保持原有的客户端创建和启动逻辑不变
-
具体实现:
// 构造函数简化 public ProtocolWsClientManager( ILogger<ProtocolWsClientManager> logger, IProtocolLogObserver protocolLogObserver, ILoggerFactory loggerFactory) // 移除 configs 参数 // StartAllClients方法修改 public void StartAllClients(ProtocolClientConfig[] configs) // 添加参数 { if (configs == null || configs.Length == 0) // 参数验证 { _logger.LogWarning("没有可用的协议客户端配置"); return; } // 使用传入的 configs 参数 _logger.LogInformation("开始启动所有协议客户端,配置数量: {ConfigCount}", configs.Length); foreach (var config in configs) // 遍历传入的配置
-
设计优势:
- 更灵活的使用方式:可以在不同时间传入不同的配置
- 减少内存占用:不需要在构造函数中存储配置数组
- 简化构造函数:降低构造函数的复杂度
- 更好的测试性:可以更容易地测试不同的配置组合
- 符合单一职责原则:构造函数只负责初始化,方法负责执行具体操作
影响范围:
- 协议客户端管理器使用方式
- 配置传递方式
- 调用方代码适配
- 测试用例更新
ProtocolWsClientManager采用面向接口编程
修改时间: 2024年 修改文件:
CoreAgent.ProtocolClient/Interfaces/IProtocolWsClientManager.cs
(新建)CoreAgent.Infrastructure/Services/Network/ProtocolWsClientManager.cs
修改内容:
-
创建IProtocolWsClientManager接口
- 在CoreAgent.ProtocolClient项目中定义接口契约
- 继承
IDisposable
接口 - 定义
StartAllClients
和StopAllClients
方法 - 使用
ProtocolClientConfig[]
作为参数类型
-
修改ProtocolWsClientManager实现类
- 实现
IProtocolWsClientManager
接口 - 添加
using CoreAgent.ProtocolClient.Interfaces;
引用 - 保持原有的实现逻辑不变
- 实现
-
具体实现:
// 接口定义 public interface IProtocolWsClientManager : IDisposable { void StartAllClients(ProtocolClientConfig[] configs); void StopAllClients(); } // 实现类 public class ProtocolWsClientManager : IProtocolWsClientManager { // 原有实现保持不变 }
-
设计优势:
- 依赖倒置:高层模块依赖抽象,不依赖具体实现
- 易于测试:可以轻松创建Mock实现进行单元测试
- 松耦合:降低组件间的耦合度
- 可扩展性:可以轻松添加新的实现类
- 符合SOLID原则:遵循依赖倒置原则和开闭原则
- 便于依赖注入:可以注册接口而不是具体实现
-
接口设计原则:
- 单一职责:接口只定义协议客户端管理的核心功能
- 简洁明了:只包含必要的方法定义
- 易于理解:方法名称和参数清晰明确
- 向后兼容:保持与原有API的兼容性
影响范围:
- 依赖注入配置更新
- 服务注册方式调整
- 单元测试Mock创建
- 调用方代码适配(使用接口类型)
- 项目引用关系调整(CoreAgent.ProtocolClient项目包含接口定义)
CellularNetworkService集成IProtocolWsClientManager
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/CellularNetworkService.cs
修改内容:
-
添加IProtocolWsClientManager依赖注入
- 在构造函数中添加
IProtocolWsClientManager protocolWsClientManager
参数 - 添加私有字段
_protocolWsClientManager
存储依赖 - 添加空值检查和异常抛出
- 在构造函数中添加
-
StartNetworkAsync方法添加第12步
- 在步骤11(更新网络状态)之后添加第12步
- 调用
protocolConfigFactory.GetAllConfigs()
获取配置数组 - 调用
_protocolWsClientManager.StartAllClients(protocolConfigs)
启动所有协议客户端 - 添加时间跟踪和错误处理
- 如果启动失败,立即返回失败结果
-
StopAsync方法集成协议客户端停止
- 在步骤4(禁用网络配置)之后添加步骤5(停止所有协议客户端)
- 调用
_protocolWsClientManager.StopAllClients()
停止所有协议客户端 - 添加错误处理,但不中断停止流程
- 重新编号后续步骤(6-9步)
-
修复StopWebSocketTransportAsync方法
- 修正方法实现,使用
CloseAsync()
而不是DisconnectAsync()
- 修正日志信息和返回值逻辑
- 确保方法名称和实现一致
- 修正方法实现,使用
-
具体实现:
// 构造函数添加依赖 public CellularNetworkService( // ... 其他参数 IProtocolWsClientManager protocolWsClientManager) // StartNetworkAsync第12步 // 12. 启动所有协议客户端 var protocolConfigs = protocolConfigFactory.GetAllConfigs(); _protocolWsClientManager.StartAllClients(protocolConfigs); // StopAsync步骤5 // 5. 停止所有协议客户端 _protocolWsClientManager.StopAllClients();
-
设计优势:
- 完整的生命周期管理:启动和停止时都正确处理协议客户端
- 错误隔离:启动失败时立即停止,停止失败时继续执行
- 时间跟踪:为协议客户端操作添加详细的时间记录
- 依赖注入:使用接口编程,便于测试和扩展
- 日志完整:提供详细的启动和停止日志记录
影响范围:
- 蜂窝网络服务依赖注入配置
- 协议客户端生命周期管理
- 网络启动和停止流程
- 服务注册配置更新
LogLayerHelp类名规范化
修改时间: 2024年 修改文件:
- `
ProtocolWsClientManager方法返回类型优化
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/ProtocolWsClientManager.cs
CoreAgent.ProtocolClient/Interfaces/IProtocolWsClientManager.cs
修改内容:
-
StartAllClients方法返回类型修改
- 将返回类型从
void
改为bool
- 添加连接状态检查逻辑,使用
client.IsConnected
判断连接状态 - 统计已连接的客户端数量
- 返回
bool
值表示是否所有客户端都成功启动并连接 - 添加详细的日志记录,包括连接状态信息
- 将返回类型从
-
StopAllClients方法返回类型修改
- 将返回类型从
void
改为bool
- 添加断开连接状态检查逻辑,使用
client.IsConnected
判断连接状态 - 记录停止前的连接状态和停止后的连接状态
- 统计已断开连接的客户端数量
- 返回
bool
值表示是否所有客户端都成功停止并断开连接 - 添加详细的日志记录,包括连接状态变化信息
- 将返回类型从
-
GetAllClientsStatus方法修复
- 修复语法错误,完善方法实现
- 添加线程安全锁保护
- 遍历所有客户端并记录其状态信息
- 包括客户端名称、连接状态(IsConnected)和客户端状态(State)
- 添加空客户端检查
-
接口定义更新
- 更新
IProtocolWsClientManager
接口中的方法签名 StartAllClients
方法返回bool
类型StopAllClients
方法返回bool
类型- 添加详细的XML文档注释说明返回值含义
- 更新
-
具体实现:
// StartAllClients方法 public bool StartAllClients(ProtocolClientConfig[] configs) { // 检查连接状态 if (existingClient.IsConnected) { connectedCount++; } var allConnected = connectedCount == configs.Length; return allConnected; } // StopAllClients方法 public bool StopAllClients() { var client = kvp.Value; var wasConnected = client.IsConnected; client.Stop(); // 检查连接状态 if (!client.IsConnected) { disconnectedCount++; } var allDisconnected = disconnectedCount == _clients.Count; return allDisconnected; } // GetAllClientsStatus方法 public void GetAllClientsStatus() { foreach (var kvp in _clients) { var client = kvp.Value; _logger.LogInformation("客户端状态 - 名称: {ClientName}, 连接状态: {IsConnected}, 客户端状态: {State}", kvp.Key, client.IsConnected, client.State); } }
-
设计优势:
- 状态可追踪:通过返回值可以明确知道操作是否完全成功
- 连接状态监控:使用
IsConnected
属性准确判断连接状态 - 详细日志记录:提供完整的操作过程和状态变化日志
- 线程安全:使用锁保护共享资源访问
- 错误处理完善:提供详细的错误信息和状态统计
- 接口一致性:接口和实现保持完全一致
- 向后兼容:保持方法签名的一致性,只改变返回类型
-
返回值含义:
StartAllClients
返回true
:所有客户端都成功启动并连接StartAllClients
返回false
:部分或全部客户端启动失败或未连接StopAllClients
返回true
:所有客户端都成功停止并断开连接StopAllClients
返回false
:部分或全部客户端停止失败或仍保持连接
影响范围:
- 协议客户端管理器接口契约
- 调用方代码需要处理返回值
- 网络启动和停止流程的状态判断
- 日志记录详细程度提升
- 错误处理和状态监控能力增强
WebSocket传输服务依赖注入修复
修改时间: 2024年 修改文件:
CoreAgent.WebSocketTransport/Extensions/WebSocketTransportExtensions.cs
CoreAgent.API/Startup.cs
修改内容:
-
修复依赖注入顺序问题
- 将
RegisterDefaultMiddleware
移到RegisterCoreServices
之前调用 - 确保中间件在核心服务注册之前就已经注册到容器中
- 解决
provider.GetServices<IMessageMiddleware>()
无法找到服务的问题
- 将
-
修复CacheMiddleware注册方式
- 将
CacheMiddleware
的注册方式从手动工厂方法改为使用AddWebSocketMiddleware<T>
- 简化注册逻辑,确保依赖注入容器能正确处理构造函数参数
- 移除复杂的工厂方法注册,使用标准的依赖注入模式
- 将
-
添加IMemoryCache服务注册
- 在
Startup.cs
的ConfigureServices
方法中添加services.AddMemoryCache()
- 确保
CacheMiddleware
能够正确获取IMemoryCache
依赖 - 在 WebSocket 传输服务注册之前添加内存缓存服务
- 在
-
具体实现:
// WebSocketTransportExtensions.cs - 调整注册顺序 public static IServiceCollection AddWebSocketTransport(...) { // 注册配置 services.Configure<WebSocketConfig>(...); // 注册默认中间件(在核心服务之前) RegisterDefaultMiddleware(services); // 注册核心服务 RegisterCoreServices(services); return services; } // Startup.cs - 添加内存缓存服务 public void ConfigureServices(IServiceCollection services) { // ... 其他服务注册 ... // 添加内存缓存服务(WebSocket中间件需要) services.AddMemoryCache(); // 添加 WebSocket 传输服务 services.AddWebSocketTransport(Configuration, "WebSocket"); }
-
设计优势:
- 依赖顺序正确:确保中间件在核心服务之前注册
- 简化注册逻辑:使用标准的依赖注入模式
- 完整的服务注册:包含所有必要的依赖服务
- 错误预防:避免运行时依赖注入异常
- 代码清晰:注册逻辑更加直观和易于理解
-
修复的问题:
System.InvalidOperationException: Cannot resolve scoped service 'System.Collections.Generic.IEnumerable
1[CoreAgent.WebSocketTransport.Middleware.IMessageMiddleware]' from root provider`- 依赖注入容器无法找到
IMessageMiddleware
服务 CacheMiddleware
无法获取IMemoryCache
依赖
影响范围:
- WebSocket传输服务的依赖注入配置
- 中间件注册和初始化顺序
- 应用程序启动时的服务注册
- 内存缓存服务的可用性
- 错误处理和异常预防
CacheMiddleware构造函数依赖注入修复
修改时间: 2024年 修改文件:
CoreAgent.WebSocketTransport/Middleware/CacheMiddleware.cs
修改内容:
-
修复构造函数参数类型
- 将构造函数参数从
WebSocketConfig config
改为IOptions<WebSocketConfig> config
- 添加
using Microsoft.Extensions.Options;
引用 - 在构造函数中通过
config?.Value
获取配置值
- 将构造函数参数从
-
增强空值检查
- 为所有构造函数参数添加空值检查和异常抛出
- 使用
ArgumentNullException
确保参数有效性 - 提供更明确的错误信息
-
具体实现:
// 修复前 public CacheMiddleware(IMemoryCache cache, ILogger<CacheMiddleware> logger, WebSocketConfig config) { _cache = cache; _logger = logger; _config = config; } // 修复后 public CacheMiddleware(IMemoryCache cache, ILogger<CacheMiddleware> logger, IOptions<WebSocketConfig> config) { _cache = cache ?? throw new ArgumentNullException(nameof(cache)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _config = config?.Value ?? throw new ArgumentNullException(nameof(config)); }
-
设计优势:
- 正确的依赖注入模式:使用
IOptions<T>
模式获取配置 - 强化的错误处理:提供详细的空值检查和异常信息
- 类型安全:确保配置对象正确获取
- 符合最佳实践:遵循 .NET 依赖注入的标准模式
- 正确的依赖注入模式:使用
-
修复的问题:
Unable to resolve service for type 'CoreAgent.WebSocketTransport.Models.WebSocketConfig'
- 依赖注入容器无法直接解析
WebSocketConfig
类型 - 中间件构造函数参数类型不匹配
影响范围:
- CacheMiddleware的依赖注入配置
- WebSocket传输服务的启动
- 配置对象的正确获取
- 错误处理和异常预防
WebSocket中间件生命周期修复
修改时间: 2024年 修改文件:
CoreAgent.WebSocketTransport/Extensions/WebSocketTransportExtensions.cs
修改内容:
-
修复生命周期不匹配问题
- 将中间件注册从
AddScoped
改为AddTransient
- 解决单例服务无法解析作用域服务的问题
- 确保中间件每次使用都创建新实例
- 将中间件注册从
-
生命周期分析
IWebSocketTransport
注册为Singleton
(单例)- 中间件注册为
Transient
(瞬时) - 单例服务可以安全地解析瞬时服务
- 每次获取中间件都会创建新实例
-
具体实现:
// 修复前 services.AddScoped<IMessageMiddleware, T>(); // 修复后 services.AddTransient<IMessageMiddleware, T>();
-
设计优势:
- 生命周期兼容:瞬时服务可以被单例服务安全解析
- 性能优化:中间件每次使用都是新实例,避免状态污染
- 线程安全:瞬时服务天然线程安全
- 内存管理:中间件使用完毕后自动释放
-
修复的问题:
Cannot resolve scoped service 'System.Collections.Generic.IEnumerable
1[CoreAgent.WebSocketTransport.Middleware.IMessageMiddleware]' from root provider`- 单例服务无法解析作用域服务的依赖注入异常
- 生命周期不匹配导致的运行时错误
-
生命周期说明:
- Singleton: 整个应用程序生命周期内只有一个实例
- Scoped: 每个请求作用域内有一个实例
- Transient: 每次请求都创建新实例
- 单例服务只能解析瞬时服务,不能解析作用域服务
影响范围:
- WebSocket中间件的生命周期管理
- 依赖注入容器的服务解析
- 应用程序启动时的服务注册
- 中间件的实例化策略
- 性能和内存使用优化
NetworkConfigCopier方法Bug修复和日志增强
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs
CoreAgent.Domain/Models/Network/NetworkConfigCopyResult.cs
CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs
修改内容:
-
返回类型统一化
- 统一返回类型:所有方法都返回
NetworkConfigCopyResult
类型,不再抛出异常 - 泛型结果类型:创建
NetworkConfigCopyResult<T>
泛型类,支持返回数据 - 接口更新:更新
INetworkConfigCopier
接口以匹配新的返回类型 - 错误处理改进:使用结果对象而不是异常来处理错误情况
- 统一返回类型:所有方法都返回
-
CreateCellularNetworkConfigurationFile方法修复
- 返回类型修改:从
Task<NetworkConfiguration>
改为Task<NetworkConfigCopyResult>
- 路径构建Bug修复:修复
Path.Combine
使用不当的问题,正确构建文件路径 - 参数验证增强:添加完整的参数空值检查,返回失败结果而不是抛出异常
- 目录创建:确保目标目录存在,避免文件写入失败
- 详细日志:添加每个步骤的详细日志记录,包括开始、成功、警告和错误信息
- 返回类型修改:从
-
CreateRadioAccessNetworkConfigurationFile方法修复
- 返回类型修改:从
Task<bool>
改为Task<NetworkConfigCopyResult>
- 参数命名规范化:使用小写开头的参数名,符合C#命名约定
- 目录创建逻辑:添加目录存在性检查和自动创建
- 错误处理增强:返回失败结果而不是抛出异常
- 参数验证:验证文件路径和配置内容不为空
- 返回类型修改:从
-
CreateCoreNetworkImsConfigurationFiles方法重构
- 返回类型修改:从
Task<List<CoreImsConfig>>
改为Task<NetworkConfigCopyResult<List<CoreImsConfig>>>
- 方法重命名:避免与RAN配置文件创建方法名冲突
- 参数验证完善:验证RuntimeCode、配置列表和AppSettings
- 配置项验证:验证每个配置项的PLMN和配置内容
- 目录创建:为CN和IMS配置文件分别创建目录
- 错误隔离:单个配置项失败不影响其他配置项处理
- 详细日志:记录每个配置项的处理过程和结果
- 返回类型修改:从
-
DeleteCellularNetworkConfigurationFile方法增强
- 返回类型修改:从
bool
改为NetworkConfigCopyResult
- 文件存在性检查:删除前检查文件是否存在,避免异常
- 错误隔离:单个文件删除失败不影响其他文件删除
- 删除统计:统计成功删除的文件数量
- 详细日志:记录每个文件的删除状态和结果
- 参数验证:验证NetworkConfiguration参数不为空
- 返回类型修改:从
-
NetworkConfigCopyResult类扩展
- 泛型支持:添加
NetworkConfigCopyResult<T>
泛型类 - 数据返回:支持返回操作结果的同时返回数据
- 继承关系:泛型类继承自基础类,保持类型安全
- 静态工厂方法:提供
Success(T data)
和Failure(string errorMessage)
方法
- 泛型支持:添加
-
具体修复的Bug:
// 修复前 - 路径构建错误 string RanConfigPath = $"{appSettings.RanConfigDirectory}{Path.Combine("RAN", $"{cellular.RuntimeCode}.cfg")}"; // 修复后 - 正确的路径构建 string ranConfigPath = Path.Combine(appSettings.RanConfigDirectory, "RAN", $"{cellular.RuntimeCode}.cfg"); // 修复前 - 抛出异常 throw new ArgumentNullException(nameof(cellular)); // 修复后 - 返回失败结果 return NetworkConfigCopyResult.Failure("CellularNetworkConfiguration 参数为空"); // 修复前 - 返回原始类型 public async Task<NetworkConfiguration> CreateCellularNetworkConfigurationFile(...) // 修复后 - 返回结果类型 public async Task<NetworkConfigCopyResult> CreateCellularNetworkConfigurationFile(...)
-
设计优势:
- 统一错误处理:所有方法都使用结果对象,避免异常传播
- 类型安全:泛型结果类型确保类型安全
- Bug修复:修复路径构建、方法名冲突、文件删除等关键Bug
- 错误处理完善:添加完整的错误处理和错误隔离机制
- 日志详细:提供完整的操作跟踪和调试信息
- 参数验证:确保所有输入参数的有效性
- 目录管理:自动创建必要的目录结构
- 错误隔离:单个操作失败不影响整体流程
- 命名规范:遵循C#命名约定,提高代码可读性
- 方法职责清晰:每个方法都有明确的职责和边界
-
修复的关键问题:
- 异常处理不一致:统一使用结果对象而不是异常
- 路径构建错误:
Path.Combine
使用不当导致路径错误 - 方法名冲突:两个不同功能的方法使用相同名称
- 文件删除异常:删除不存在的文件导致异常
- 目录不存在:目标目录不存在导致文件写入失败
- 错误传播:单个错误导致整个操作失败
- 日志缺失:缺少关键操作的日志记录
影响范围:
- 网络配置文件创建和删除的稳定性
- 错误处理和异常预防
- 日志记录和调试能力
- 代码可读性和维护性
- 文件系统操作的可靠性
- 配置管理的完整性
- 接口契约的一致性
- 调用方代码的错误处理方式
NetworkConfigCopier返回类型优化和GeneralCellularNetworkService适配
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs
CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs
CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
修改内容:
-
CreateCellularNetworkConfigurationFile返回类型优化
- 返回类型修改:从
Task<NetworkConfigCopyResult>
改为Task<NetworkConfigCopyResult<NetworkConfiguration>>
- 数据返回:成功时返回包含
NetworkConfiguration
对象的结果 - 接口更新:更新接口定义以匹配新的返回类型
- 调用方适配:修改调用方代码以正确使用返回的数据
- 返回类型修改:从
-
GeneralCellularNetworkService调用修复
- 返回类型适配:修改调用方式以适配新的泛型返回类型
- 数据获取:直接从结果对象的
Data
属性获取NetworkConfiguration
- 错误处理改进:使用
IsSuccess
属性检查操作是否成功 - 代码简化:移除手动创建
NetworkConfiguration
的代码
-
接口定义更新
- 泛型支持:接口方法返回
Task<NetworkConfigCopyResult<NetworkConfiguration>>
- 文档更新:更新XML文档注释说明返回的数据类型
- 泛型支持:接口方法返回
-
具体修改:
// NetworkConfigCopier.cs - 返回类型修改 // 修复前 public async Task<NetworkConfigCopyResult> CreateCellularNetworkConfigurationFile(...) { // ... 创建NetworkConfiguration对象 return NetworkConfigCopyResult.Success(); // 没有返回数据 } // 修复后 public async Task<NetworkConfigCopyResult<NetworkConfiguration>> CreateCellularNetworkConfigurationFile(...) { // ... 创建NetworkConfiguration对象 return NetworkConfigCopyResult<NetworkConfiguration>.Success(network); // 返回数据 } // GeneralCellularNetworkService.cs - 调用修复 // 修复前 - 手动创建配置对象 var createResult = await _configCopier.CreateCellularNetworkConfigurationFile(cellular, _context.GetAppSettings()); if (!createResult.IsSuccess) { return CellularNetworkOperationResult.Failure($"创建网络配置文件失败: {createResult.ErrorMessage}"); } var config = NetworkConfiguration.Create(cellular.RuntimeCode, Path.Combine(_context.GetAppSettings().RanConfigDirectory, "RAN", $"{cellular.RuntimeCode}.cfg"), new List<CoreImsConfig>()); // 修复后 - 直接使用返回的数据 var createResult = await _configCopier.CreateCellularNetworkConfigurationFile(cellular, _context.GetAppSettings()); if (!createResult.IsSuccess) { return CellularNetworkOperationResult.Failure($"创建网络配置文件失败: {createResult.ErrorMessage}"); } var config = createResult.Data; // 直接获取返回的NetworkConfiguration对象
-
设计优势:
- 数据完整性:返回完整的
NetworkConfiguration
对象,包含所有配置信息 - 类型安全:泛型结果类型确保类型安全
- 代码简化:调用方无需手动创建配置对象
- 错误处理统一:保持统一的错误处理模式
- 接口一致性:接口和实现保持完全一致
- 数据完整性:返回完整的
-
修复的关键问题:
- 数据丢失:原方法创建了
NetworkConfiguration
但没有返回 - 代码重复:调用方需要手动创建配置对象
- 类型不匹配:返回类型与实际需求不匹配
- 接口不一致:接口定义与实际实现不一致
- 数据丢失:原方法创建了
影响范围:
- 网络配置创建流程的数据完整性
- 调用方代码的简化
- 接口契约的一致性
- 类型安全和错误处理
修改CreateCellularNetworkConfigurationFile为元组返回
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs
CoreAgent.Domain/Interfaces/Network/INetworkConfigCopier.cs
CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
修改内容:
-
修改CreateCellularNetworkConfigurationFile返回类型
- 将返回类型从
Task<NetworkConfigCopyResult<NetworkConfiguration>>
改为元组Task<(bool IsSuccess, string ErrorMessage, NetworkConfiguration NetworkConfiguration)>
- 简化返回结构,直接返回三个值:是否成功、错误信息、网络配置对象
- 将返回类型从
-
更新接口定义
- 更新
INetworkConfigCopier
接口中的方法签名 - 更新XML文档注释说明新的返回类型
- 更新
-
更新调用代码
- 修改
GeneralCellularNetworkService.cs
中的调用逻辑 - 使用元组解构语法
var (isSuccess, errorMessage, config) = await ...
- 直接使用解构后的变量
- 修改
-
具体实现:
// 修改前 public async Task<NetworkConfigCopyResult<NetworkConfiguration>> CreateCellularNetworkConfigurationFile(...) { return NetworkConfigCopyResult<NetworkConfiguration>.Failure("错误信息"); return NetworkConfigCopyResult<NetworkConfiguration>.Success(network); } // 修改后 public async Task<(bool IsSuccess, string ErrorMessage, NetworkConfiguration NetworkConfiguration)> CreateCellularNetworkConfigurationFile(...) { return (false, "错误信息", null); return (true, null, network); }
-
调用代码修改:
// 修改前 var createResult = await _configCopier.CreateCellularNetworkConfigurationFile(cellular, _context.GetAppSettings()); if (!createResult.IsSuccess) { return CellularNetworkOperationResult.Failure($"创建网络配置文件失败: {createResult.ErrorMessage}"); } var config = createResult.Data; // 修改后 var (isSuccess, errorMessage, config) = await _configCopier.CreateCellularNetworkConfigurationFile(cellular, _context.GetAppSettings()); if (!isSuccess) { return CellularNetworkOperationResult.Failure($"创建网络配置文件失败: {errorMessage}"); }
-
设计优势:
- 简洁性:元组返回比包装类更简洁
- 直观性:直接返回三个值,语义更清晰
- 性能:避免创建额外的包装对象
- 易用性:使用元组解构语法,代码更简洁
- 类型安全:保持强类型,编译时检查
影响范围:
- 网络配置创建方法的返回类型简化
- 调用代码的简化
- 接口定义的更新
- 代码可读性的提升
修改CreateCoreNetworkImsConfigurationFiles为元组返回
修改时间: 2024年 修改文件:
CoreAgent.Infrastructure/Services/Network/NetworkConfigCopier.cs
修改内容:
-
修改CreateCoreNetworkImsConfigurationFiles返回类型
- 将返回类型从
Task<NetworkConfigCopyResult<List<CoreImsConfig>>>
改为元组Task<(bool IsSuccess, string ErrorMessage, List<CoreImsConfig> CoreImsConfigs)>
- 简化返回结构,直接返回三个值:是否成功、错误信息、核心IMS配置列表
- 将返回类型从
-
更新调用代码
- 修改
CreateCellularNetworkConfigurationFile
方法中对CreateCoreNetworkImsConfigurationFiles
的调用 - 使用元组解构语法
var (coreImsSuccess, coreImsError, coreImsConfigs) = await ...
- 直接使用解构后的变量
- 修改
-
具体实现:
// 修改前 public async Task<NetworkConfigCopyResult<List<CoreImsConfig>>> CreateCoreNetworkImsConfigurationFiles(...) { return NetworkConfigCopyResult<List<CoreImsConfig>>.Failure("错误信息"); return NetworkConfigCopyResult<List<CoreImsConfig>>.Success(list); } // 修改后 public async Task<(bool IsSuccess, string ErrorMessage, List<CoreImsConfig> CoreImsConfigs)> CreateCoreNetworkImsConfigurationFiles(...) { return (false, "错误信息", null); return (true, null, list); }
-
调用代码修改:
// 修改前 var coreImsResult = await CreateCoreNetworkImsConfigurationFiles(cellular.RuntimeCode, cellular.CoreNetworkImsConfigurations, appSettings); if (!coreImsResult.IsSuccess) { return (false, $"创建核心网络和IMS配置文件失败: {coreImsResult.ErrorMessage}", null); } list = coreImsResult.Data; // 修改后 var (coreImsSuccess, coreImsError, coreImsConfigs) = await CreateCoreNetworkImsConfigurationFiles(cellular.RuntimeCode, cellular.CoreNetworkImsConfigurations, appSettings); if (!coreImsSuccess) { return (false, $"创建核心网络和IMS配置文件失败: {coreImsError}", null); } list = coreImsConfigs;
-
设计优势:
- 一致性:与
CreateCellularNetworkConfigurationFile
方法保持相同的返回模式 - 简洁性:元组返回比包装类更简洁
- 直观性:直接返回三个值,语义更清晰
- 性能:避免创建额外的包装对象
- 易用性:使用元组解构语法,代码更简洁
- 一致性:与
-
接口说明:
CreateCoreNetworkImsConfigurationFiles
是内部方法,不在接口中定义- 只在
NetworkConfigCopier
实现类中使用 - 保持接口的简洁性
影响范围:
- 核心网络和IMS配置文件创建方法的返回类型简化
- 内部方法调用代码的简化
- 代码一致性的提升
- 性能的优化
ProtocolLogProcessor.ProcessLogDetails方法Info字段过滤修复
修改时间: 2024年12月 修改文件:
CoreAgent.ProtocolClient/ProtocolEngineCore/ProtocolLogProcessor.cs
修改内容:
-
修复foreach循环中的Info字段检查
- 在
ProcessLogDetails
方法的foreach
循环中移除Info
字段不为空的检查 - 允许处理所有日志记录,包括
Info
为空的记录 - 保持完整的日志处理和输出功能
- 在
-
修复_protocolLogObserver.OnProtocolLogsReceived调用
- 在调用
_protocolLogObserver.OnProtocolLogsReceived(logDetails)
之前过滤掉Info
为空或无效的记录 - 使用
!string.IsNullOrWhiteSpace(detail.Info)
进行过滤,确保Info字段不为null、空字符串或只包含空白字符 - 确保传递给观察者的数据中只包含有效的
Info
字段 - 添加空集合检查,避免传递空集合给观察者
- 在调用
-
具体实现:
// 修复前 foreach (var detail in logDetails) { try { // 检查Info字段不为空 if (!string.IsNullOrEmpty(detail.Info)) { Console.WriteLine($"处理日志详情:Time={detail.Time} Layer={detail.LayerType}, UEID={detail.UEID}, IMSI={detail.IMSI},PLMN={detail.PLMN},INFO={detail.Info},Messsage={detail.Message}"); // 这里可以添加具体的业务处理逻辑 // 例如:保存到数据库、发送到其他服务等 _logger.LogDebug($"处理日志详情: Layer={detail.LayerType}, UEID={detail.UEID}, IMSI={detail.IMSI}"); } } catch (Exception ex) { _logger.LogError(ex, $"处理日志详情失败: Layer={detail.LayerType}, UEID={detail.UEID}"); } } // 通知协议日志观察者处理转换后的数据 try { // 过滤掉Info为空的记录 var filteredLogDetails = logDetails.Where(detail => !string.IsNullOrEmpty(detail.Info)).ToList(); _protocolLogObserver.OnProtocolLogsReceived(filteredLogDetails); } catch (Exception ex) { _logger.LogError(ex, "通知协议日志观察者失败"); } // 修复后 foreach (var detail in logDetails) { try { Console.WriteLine($"处理日志详情:Time={detail.Time} Layer={detail.LayerType}, UEID={detail.UEID}, IMSI={detail.IMSI},PLMN={detail.PLMN},INFO={detail.Info},Messsage={detail.Message}"); // 这里可以添加具体的业务处理逻辑 // 例如:保存到数据库、发送到其他服务等 _logger.LogDebug($"处理日志详情: Layer={detail.LayerType}, UEID={detail.UEID}, IMSI={detail.IMSI}"); } catch (Exception ex) { _logger.LogError(ex, $"处理日志详情失败: Layer={detail.LayerType}, UEID={detail.UEID}"); } } // 通知协议日志观察者处理转换后的数据 try { // 过滤掉Info为空或无效的记录 var filteredLogDetails = logDetails.Where(detail => !string.IsNullOrWhiteSpace(detail.Info) ).ToList(); if (filteredLogDetails.Any()) { _protocolLogObserver.OnProtocolLogsReceived(filteredLogDetails); } else { _logger.LogDebug("过滤后没有有效的日志记录,跳过观察者通知"); } } catch (Exception ex) { _logger.LogError(ex, "通知协议日志观察者失败"); }
-
设计优势:
- 完整日志处理:处理所有日志记录,包括Info为空的记录
- 数据质量保证:确保传递给观察者的数据中只包含有效的Info字段
- 调试友好:可以看到所有日志记录的详细信息,便于调试
- 观察者模式优化:传递给观察者的数据更加纯净
- 错误预防:避免因空Info字段导致的潜在问题
-
修复的问题:
- 日志信息缺失:原代码会跳过Info为空的记录,导致日志信息不完整
- 调试困难:无法看到所有日志记录的详细信息
- 数据传递问题:将无效数据传递给协议日志观察者
- 信息不完整:处理过程中丢失了部分日志信息
影响范围:
- 协议日志处理的完整性
- 日志输出的完整性
- 协议日志观察者接收的数据质量
- 调试和问题排查能力
GeneralCellularNetworkService.StartNetworkAsync方法步骤注释优化
修改时间: 2024年12月 修改文件:
CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
修改内容:
-
重新注释StartNetworkAsync方法中的步骤
- 为每个步骤添加更详细和清晰的注释说明
- 统一注释格式,使用"步骤X: 功能描述"的格式
- 为每个步骤添加功能说明,解释该步骤的具体作用
- 保持原有的时间跟踪和日志记录功能
-
具体修改的步骤注释:
- 步骤1: 创建蜂窝网络配置文件 - 根据传入的蜂窝网络配置和应用程序设置,创建临时配置文件
- 步骤2: 执行网络接口初始化命令 - 初始化网络接口,确保网络环境准备就绪
- 步骤3: 复制配置值到临时目录 - 将网络配置的关键参数复制到系统临时目录,供后续步骤使用
- 步骤4: 获取并验证IP端点信息 - 从配置中提取通信地址信息,验证端点的有效性
- 步骤5: 更新IP端点管理器 - 将获取到的端点信息更新到网络上下文中的端点管理器
- 步骤6: 创建协议客户端配置 - 基于网络实体信息创建协议客户端配置,为后续的协议通信做准备
- 步骤7: 启动WebSocket传输连接 - 建立与协议服务器的WebSocket连接,为数据传输做准备
- 步骤8: 启动网络配置 - 启用网络接口配置,激活蜂窝网络连接
- 步骤9: 更新网络配置类型 - 根据启动结果更新网络配置类型,记录当前使用的配置类型
- 步骤10: 检查网络端点连接状态 - 验证所有网络端点的连接状态,确保网络连接正常
- 步骤11: 更新网络状态 - 将网络状态标记为已启动,更新内部状态管理
- 步骤12: 启动所有协议客户端 - 启动所有协议客户端,开始协议数据采集和传输
-
设计优势:
- 注释清晰:每个步骤都有明确的功能描述
- 格式统一:使用一致的注释格式,提高可读性
- 功能说明:详细解释每个步骤的作用和目的
- 易于理解:帮助开发者快速理解网络启动流程
- 维护友好:清晰的注释便于后续维护和修改
-
注释示例:
// 步骤1: 创建蜂窝网络配置文件 // 根据传入的蜂窝网络配置和应用程序设置,创建临时配置文件 var step1Start = DateTime.UtcNow; _logger.LogDebug("步骤1开始:创建蜂窝网络配置文件"); // 步骤2: 执行网络接口初始化命令 // 初始化网络接口,确保网络环境准备就绪 var step2Start = DateTime.UtcNow; _logger.LogDebug("步骤2开始:执行网络接口初始化命令");
影响范围:
- 网络启动流程的代码可读性
- 开发者对网络启动过程的理解
- 代码维护和调试的便利性
- 新团队成员的学习成本
GeneralCellularNetworkService网络状态恢复机制优化
修改时间: 2024年12月 修改文件:
CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
修改内容:
-
重新命名和优化恢复方法
- 将
StartRestore
方法重命名为RestoreNetworkStateAsync
- 添加完整的XML文档注释说明方法用途
- 返回
bool
类型表示恢复操作是否成功 - 移除直接抛出异常的代码,改为记录日志并返回失败状态
- 将
-
完善恢复流程
- 步骤1: 停止所有协议客户端
- 步骤2: 关闭WebSocket传输连接
- 步骤3: 执行网络接口初始化命令,重置网络状态
- 步骤4: 重置网络上下文状态
- 每个步骤都有独立的异常处理,确保单个步骤失败不影响其他步骤
-
在步骤10之后的所有步骤中添加恢复机制
- 步骤10: 网络端点状态检查失败时调用恢复
- 步骤11: 更新网络状态失败时调用恢复
- 步骤12: 启动协议客户端失败时调用恢复
- 确保在任何步骤失败时都能正确清理资源
-
具体实现:
// 恢复方法优化 private async Task<bool> RestoreNetworkStateAsync() { try { _logger.LogInformation("开始恢复网络状态"); // 1. 停止所有协议客户端 try { _protocolWsClientManager.StopAllClients(); _logger.LogDebug("协议客户端停止完成"); } catch (Exception ex) { _logger.LogWarning(ex, "停止协议客户端时出现异常,继续执行恢复流程"); } // 2. 关闭WebSocket传输连接 try { if (_webSocketTransport.IsConnected) { await _webSocketTransport.CloseAsync(); _logger.LogDebug("WebSocket传输连接关闭完成"); } } catch (Exception ex) { _logger.LogWarning(ex, "关闭WebSocket传输连接时出现异常,继续执行恢复流程"); } // 3. 执行网络接口初始化命令,重置网络状态 try { var initResult = await _interfaceManager.ExecuteInitializeCommandsAsync(true); if (!initResult.IsSuccess) { _logger.LogWarning("执行网络接口初始化命令失败: {ErrorMessage}", initResult.ErrorMessage); } else { _logger.LogDebug("网络接口初始化命令执行成功"); } } catch (Exception ex) { _logger.LogWarning(ex, "执行网络接口初始化命令时出现异常"); } // 4. 重置网络上下文状态 _context.Reset(); _logger.LogDebug("网络上下文状态重置完成"); _logger.LogInformation("网络状态恢复完成"); return true; } catch (Exception ex) { _logger.LogError(ex, "恢复网络状态过程中出现未预期的异常"); return false; } }
-
步骤10-12的恢复调用:
// 步骤10: 网络端点状态检查失败 if (!statusCheckResult.IsSuccess) { var errorMessage = string.Join("; ", statusCheckResult.ErrorMessage); _logger.LogWarning("网络端点状态检查未通过: {ErrorMessage}", errorMessage); await RestoreNetworkStateAsync(); return CellularNetworkOperationResult.Failure($"网络端点状态检查失败: {errorMessage}"); } // 步骤11: 更新网络状态 var state = _context.GetNetworkState(); state.MarkAsStarted(); // 步骤12: 启动协议客户端失败 try { var protocolConfigs = protocolConfigFactory.GetAllConfigs(); var startResult = _protocolWsClientManager.StartAllClients(protocolConfigs); if (!startResult) { _logger.LogWarning("部分协议客户端启动失败"); await RestoreNetworkStateAsync(); return CellularNetworkOperationResult.Failure("部分协议客户端启动失败"); } _logger.LogInformation("所有协议客户端启动完成"); } catch (Exception ex) { _logger.LogError(ex, "启动协议客户端失败"); await RestoreNetworkStateAsync(); return CellularNetworkOperationResult.Failure($"启动协议客户端失败: {ex.Message}"); }
-
设计优势:
- 完整的资源清理:确保所有已创建的资源都被正确清理
- 错误隔离:每个恢复步骤都有独立的异常处理,避免单个失败影响整体恢复
- 详细日志记录:提供完整的恢复过程日志,便于问题排查
- 状态一致性:确保网络状态在失败时能够恢复到初始状态
- 方法命名清晰:
RestoreNetworkStateAsync
明确表达方法功能 - 返回值有意义:返回bool值表示恢复操作是否成功
- 异常处理完善:不直接抛出异常,而是记录日志并返回失败状态
影响范围:
- 网络启动失败时的资源清理机制
- 网络状态恢复的可靠性
- 错误处理和日志记录的完整性
- 系统稳定性和资源管理
- 调试和问题排查能力
优化GeneralCellularNetworkService中的RestoreNetworkStateAsync方法和启动流程
修改时间: 2024年12月 修改文件:
CoreAgent.Infrastructure/Services/Network/GeneralCellularNetworkService.cs
修改内容:
-
问题描述:
RestoreNetworkStateAsync
方法返回布尔值但调用方不做判断,返回值无意义- 步骤12(启动所有协议客户端)代码较长,需要提取为单独方法以提高可读性
- 需要确保只有步骤1成功时才继续执行后续步骤
- 删除临时配置文件这一步无论成功还是失败都需要执行
-
修复方案:
- 将
RestoreNetworkStateAsync
方法改为void
返回类型,移除不必要的返回值 - 提取步骤12的协议客户端启动逻辑到单独的私有方法
StartAllProtocolClientsAsync
- 重构
StartNetworkAsync
方法,将步骤1和删除临时配置文件分离 - 提取步骤2-12到新的私有方法
ExecuteRemainingStepsAsync
- 确保删除临时配置文件无论成功还是失败都会执行
- 将
-
具体修改: RestoreNetworkStateAsync 方法优化:
// 修改前 private async Task<bool> RestoreNetworkStateAsync() // 修改后 private async Task RestoreNetworkStateAsync()
新增 StartAllProtocolClientsAsync 方法:
/// <summary> /// 启动所有协议客户端 /// </summary> /// <param name="protocolConfigFactory">协议配置工厂</param> /// <returns>启动结果</returns> private async Task<CellularNetworkOperationResult> StartAllProtocolClientsAsync(ProtocolClientConfigFactory protocolConfigFactory)
新增 ExecuteRemainingStepsAsync 方法:
/// <summary> /// 执行剩余的启动步骤(步骤2-12) /// </summary> /// <param name="config">网络配置</param> /// <param name="key">配置键</param> /// <param name="startTime">开始时间</param> /// <returns>执行结果</returns> private async Task<CellularNetworkOperationResult> ExecuteRemainingStepsAsync(object config, string key, DateTime startTime)
StartNetworkAsync 方法重构:
// 步骤1成功后,调用ExecuteRemainingStepsAsync执行后续步骤 var result = await ExecuteRemainingStepsAsync(config, key, startTime); // 删除临时配置文件 - 无论成功还是失败都需要执行 var deleteResult = _configCopier.DeleteCellularNetworkConfigurationFile(config); // 记录结果但不影响返回值
-
影响范围:
- 简化了方法调用,移除了不必要的返回值判断
- 提高了代码可读性和维护性
- 确保了步骤1的成功验证逻辑
- 保证了临时配置文件的清理操作总是执行
- 保持了原有的错误处理逻辑
代码提交 - 完善网络配置和协议客户端功能
修改时间: 2024年12月
提交信息: 更新代码:完善网络配置和协议客户端功能
提交哈希: d011b25
修改内容:
-
GeneralCellularNetworkService网络状态恢复机制优化
- 重新命名和优化恢复方法:将
StartRestore
重命名为RestoreNetworkStateAsync
- 完善恢复流程:停止协议客户端、关闭WebSocket连接、重置网络状态
- 在步骤10-12中添加恢复机制,确保失败时能正确清理资源
- 添加完整的异常处理和日志记录
- 重新命名和优化恢复方法:将
-
ProtocolLogProcessor.ProcessLogDetails方法Info字段过滤修复
- 修复foreach循环中的Info字段检查,允许处理所有日志记录
- 在调用观察者之前过滤掉Info为空或无效的记录
- 确保传递给观察者的数据质量,添加空集合检查
-
GeneralCellularNetworkService.StartNetworkAsync方法步骤注释优化
- 为每个步骤添加详细和清晰的功能说明注释
- 统一注释格式,使用"步骤X: 功能描述"的格式
- 提高代码可读性和维护性
-
NetworkConfigCopier方法Bug修复和日志增强
- 统一返回类型为
NetworkConfigCopyResult
,不再抛出异常 - 修复路径构建Bug,正确使用
Path.Combine
- 添加完整的参数验证和目录创建逻辑
- 增强错误处理和详细日志记录
- 统一返回类型为
-
WebSocket传输服务依赖注入修复
- 修复依赖注入顺序问题,确保中间件在核心服务之前注册
- 修复CacheMiddleware注册方式,使用标准的依赖注入模式
- 添加IMemoryCache服务注册,确保中间件依赖完整
-
ProtocolWsClientManager方法参数优化
- 简化构造函数,移除配置参数
- 修改StartAllClients方法签名,添加配置参数
- 采用面向接口编程,创建IProtocolWsClientManager接口
-
CellularNetworkService集成协议客户端管理
- 添加IProtocolWsClientManager依赖注入
- 在StartNetworkAsync方法中添加协议客户端启动步骤
- 在StopAsync方法中集成协议客户端停止逻辑
- 添加时间跟踪记录,提供详细的性能监控
-
MessageTransferProtocolLog模型创建
- 创建新的协议日志模型,解决命名冲突
- 修改NetworkProtocolLogObserver转换逻辑
- 添加类型转换和字段映射
-
蜂窝网络配置实体类创建
- 创建CellularNetworkConfiguration实体类
- 创建CoreNetworkImsConfiguration实体类
- 添加数据校验功能和ValidationResult类
-
NetworkProtocolLogObserver中的StopChannelManager方法修复
- 修复资源管理问题,避免过早释放
- 优化通道管理方法,职责更加清晰
- 添加自动重连配置选项
- 修复WebSocket配置文件
影响范围:
- 网络配置和协议客户端功能的完整性
- 错误处理和资源管理的可靠性
- 代码可读性和维护性的提升
- 依赖注入配置的完善
- 日志记录和调试能力的增强
- 系统稳定性和性能监控的改进
2025-01-02
CoreAgent.ProtocolClient/Models/TransferProtocolLog.cs
-
修正了时间戳转换方法中的时区问题:
ConvertToFullTimestamp()
: 修正了时区转换逻辑,确保正确转换为UTC时间戳GetFullTimestamp()
: 正确返回上海本地时间- 新增
GetUtcTimestamp()
: 获取UTC时间用于调试和对比 - 新增
GetFullTimestampString()
: 获取格式化的上海时间字符串 - 新增
GetUtcTimestampString()
: 获取格式化的UTC时间字符串
-
解决了时间转换差异问题:
- 原始数据
73365316
转换为1754137365316
后 - 程序计算:
2025-08-02 12:22:45.316
(上海时间) - 工具显示:
2025-08-02 20:22:45
(可能是UTC时间) - 差异8小时是由于时区转换造成的,现在已修正
- 原始数据
CoreAgent.ProtocolClient/Helpers/TimeStampHelper.cs(新增)
-
创建了独立的时间戳工具类,统一使用北京时间(中国标准时间UTC+8):
ConvertToFullTimestamp()
: 将时分秒毫秒时间戳转换为完整时间戳ConvertToBeijingTime()
: 转换为北京时间ConvertToUtcTime()
: 转换为UTC时间GetBeijingTimeString()
: 获取北京时间字符串GetUtcTimeString()
: 获取UTC时间字符串IsMillisecondsTimestamp()
: 判断时间戳类型SmartConvertToBeijingTime()
: 智能转换(自动判断类型)SmartConvertToUtcTime()
: 智能转换(自动判断类型)GetCurrentBeijingTimestamp()
: 获取当前北京时间戳GetCurrentUtcTimestamp()
: 获取当前UTC时间戳ParseDateTimeString()
: 解析时间字符串GetTimeStampInfo()
: 获取时间戳详细信息
-
新增
TimeStampInfo
类:包含时间戳的完整信息 -
统一时区标准:
- 根据中国政府在1949年后统一采用北京时间作为全国标准时间的政策
- 所有时间相关方法统一使用北京时间(UTC+8)
- 变量命名和注释统一使用"北京时间"而非"上海时间"
这些修正确保了时间戳转换的准确性,并提供了UTC和北京时间的对比功能。独立的时间工具类便于在其他地方复用,符合中国统一时区标准。
SIPProtocolParser.GeneralParse方法严谨性修复
修改时间: 2025年1月2日 修改文件:
CoreAgent.ProtocolClient/BuildProtocolParser/SIPProtocolParser.cs
修改内容:
-
问题描述:
- 变量名错误:
regisMccLine
实际匹配的是MNC,regisMncLine
实际匹配的是MCC - 空引用风险:使用了
!
操作符但没有进行空值检查 - 重复赋值:对
log.SIP.Plmn
进行了两次赋值,第二次会覆盖第一次 - 正则表达式不够严谨:缺少编译选项
- 返回值检查错误:
StringToId
返回0表示空字符串,不是-1
- 变量名错误:
-
修复方案:
- 修复变量名错误:将变量名与实际匹配内容对应
- 增强空值检查:添加参数验证和空值检查
- 修复重复赋值:分别设置PLMN和IMSI属性
- 优化正则表达式:添加
RegexOptions.Compiled
提高性能 - 修复返回值检查:使用正确的返回值判断逻辑
- 添加参数验证:验证Groups数量和参数有效性
-
具体修复:
// 修复前 - 变量名错误 var regisMccLine = log!.Data.Select(line => _regMnc.Match(line))... // 实际匹配MNC var regisMncLine = log!.Data.Select(line => _regMcc.Match(line))... // 实际匹配MCC // 修复后 - 变量名正确 var mncValue = log.Data?.Select(line => _regMnc.Match(line))... // 匹配MNC var mccValue = log.Data?.Select(line => _regMcc.Match(line))... // 匹配MCC // 修复前 - 重复赋值 log.SIP.Plmn = $"{regisMncLine}{regisMccLine!.Substring(1)}"; log.SIP.Plmn = regisIMSILine; // 覆盖了上面的赋值 // 修复后 - 分别设置不同属性 if (!string.IsNullOrEmpty(mccValue) && !string.IsNullOrEmpty(mncValue)) { log.SIP.Plmn = $"{mccValue}{mncValue}"; } if (!string.IsNullOrEmpty(imsiValue)) { log.SIP.IMSI = imsiValue; // 使用正确的IMSI属性 } // 修复前 - 返回值检查错误 if (info == -1) return; // 修复后 - 正确的返回值检查 if (info == 0) return; // StringToId返回0表示空字符串
-
设计优势:
- 逻辑正确性:修复了变量名错误和重复赋值问题
- 空值安全:添加了完整的空值检查和参数验证
- 性能优化:正则表达式使用编译选项提高性能
- 代码严谨性:添加了Groups数量验证和参数有效性检查
- 错误预防:使用空条件操作符避免空引用异常
- 属性正确性:使用正确的SIP属性设置PLMN和IMSI
-
修复的关键问题:
- 变量命名混乱:MCC和MNC变量名与实际匹配内容不匹配
- 空引用风险:使用
!
操作符但没有验证对象不为空 - 数据覆盖:对同一属性进行两次赋值导致数据丢失
- 返回值误解:对
StringToId
方法返回值理解错误 - 正则表达式性能:缺少编译选项影响性能
- 参数验证缺失:没有验证正则匹配结果的Groups数量
影响范围:
- SIP协议解析的准确性
- 协议日志数据的完整性
- 代码的稳定性和可靠性
- 性能优化和错误预防
- 代码可读性和维护性