Browse Source

优化 ProtocolMessageHandler:重构方法命名和代码结构,改进错误处理和日志输出格式

feature/x1-web-request
root 1 week ago
parent
commit
4854f1460f
  1. 124
      src/X1.WebSocket/Handlers/ProtocolMessageHandler.cs
  2. 67
      src/X1.WebSocket/Models/ProtocolLayer.cs
  3. 59
      src/X1.WebSocket/Models/ProtocolMessage.cs
  4. 103
      src/X1.WebSocket/Models/TransferProtocolLog.cs
  5. 55
      src/modify.md

124
src/X1.WebSocket/Handlers/ProtocolMessageHandler.cs

@ -6,31 +6,151 @@ using System.Text.Json;
using System.Threading.Tasks;
using CellularManagement.WebSocket.Models;
using Microsoft.Extensions.Logging;
using X1.WebSocket.Models;
namespace CellularManagement.WebSocket.Handlers
{
public class ProtocolMessageHandler : IWebSocketMessageHandler
{
private readonly ILogger<ChatMessageHandler> _logger;
private readonly JsonSerializerOptions _jsonOptions;
public ProtocolMessageHandler(ILogger<ChatMessageHandler> logger)
{
_logger = logger;
_jsonOptions = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
}
public string MessageType => "Protocol";
public async Task<WebSocketMessage> HandleAsync(WebSocketMessage message)
{
_logger.LogDebug("收到仪表发送[Protocol]:{Data}", System.Text.Encoding.UTF8.GetString(message.Data));
var messageData = Encoding.UTF8.GetString(message.Data);
_logger.LogDebug("收到协议消息,连接ID:{ConnectionId},数据长度:{DataLength}字节",
message.ConnectionId, message.Data.Length);
ProcessProtocolMessage(messageData);
var response = new WebSocketMessage
{
ConnectionId = message.ConnectionId,
MessageType = System.Net.WebSockets.WebSocketMessageType.Text,
NeedQueue = false
};
await Task.CompletedTask.ConfigureAwait(false);
_logger.LogDebug("协议消息处理完成,连接ID:{ConnectionId}", message.ConnectionId);
return response;
}
/// <summary>
/// 处理协议消息
/// </summary>
/// <param name="messageData">消息数据</param>
private void ProcessProtocolMessage(string messageData)
{
if (string.IsNullOrWhiteSpace(messageData))
{
_logger.LogWarning("协议消息数据为空");
return;
}
try
{
var protocolMessage = JsonSerializer.Deserialize<ProtocolMessage>(messageData, _jsonOptions);
if (protocolMessage?.Payload?.Message == null)
{
_logger.LogWarning("协议消息载荷为空或格式无效");
return;
}
var messageCount = protocolMessage.Payload.Message.Length;
_logger.LogInformation("开始处理协议消息,消息数量:{MessageCount}", messageCount);
if (messageCount == 0)
{
_logger.LogWarning("协议消息数组为空");
return;
}
ProcessProtocolLogs(protocolMessage.Payload.Message);
_logger.LogInformation("协议消息处理完成,成功处理 {MessageCount} 条消息", messageCount);
}
catch (JsonException jsonEx)
{
_logger.LogError(jsonEx, "协议消息JSON反序列化失败:{MessageData}", messageData);
throw new InvalidOperationException("协议消息格式无效", jsonEx);
}
catch (Exception ex)
{
_logger.LogError(ex, "处理协议消息时发生未预期的错误");
}
}
/// <summary>
/// 处理协议日志数组
/// </summary>
/// <param name="protocolLogs">协议日志数组</param>
private void ProcessProtocolLogs(TransferProtocolLog[] protocolLogs)
{
var processedCount = 0;
var errorCount = 0;
foreach (var log in protocolLogs)
{
try
{
ProcessSingleProtocolLog(log);
processedCount++;
}
catch (Exception ex)
{
errorCount++;
_logger.LogError(ex, "处理单个协议日志时发生错误,日志ID:{LogId}", log.Id);
}
}
if (errorCount > 0)
{
_logger.LogWarning("协议日志处理完成,成功:{SuccessCount},失败:{ErrorCount}",
processedCount, errorCount);
}
else
{
_logger.LogDebug("协议日志处理完成,成功处理 {ProcessedCount} 条日志", processedCount);
}
}
/// <summary>
/// 处理单个协议日志
/// </summary>
/// <param name="log">协议日志</param>
private void ProcessSingleProtocolLog(TransferProtocolLog log)
{
var logInfo = new
{
Id = log.Id,
Time = log.Time.ToString(@"hh\:mm\:ss\.fff"),
Layer = log.LayerType,
UEID = log.UEID?.ToString() ?? "N/A",
IMSI = log.IMSI ?? "N/A",
PLMN = log.PLMN ?? "N/A",
CellID = log.CellID?.ToString() ?? "N/A",
Direction = log.Direction,
Info = log.Info ?? "N/A",
Message = !string.IsNullOrEmpty(log.Message) ? log.Message : "N/A"
};
_logger.LogDebug("处理协议日志 - 【ID】{Id} 【时间】{Time} 【层】{Layer} 【UEID】{UEID} 【IMSI】{IMSI} 【PLMN】{PLMN} 【小区】{CellID} 【方向】{Direction} 【信息】{Info} 【消息】{Message}",
logInfo.Id, logInfo.Time, logInfo.Layer, logInfo.UEID, logInfo.IMSI, logInfo.PLMN, logInfo.CellID, logInfo.Direction, logInfo.Info, logInfo.Message);
// 这里可以添加具体的业务逻辑处理
// 例如:数据验证、业务规则检查、数据持久化等
}
}
}

67
src/X1.WebSocket/Models/ProtocolLayer.cs

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace X1.WebSocket.Models
{
/// <summary>
/// 协议层类型枚举
/// 定义了各种协议层的类型标识
/// </summary>
public enum ProtocolLayer
{
NONE,
GTPU,
LPPa,
M2AP,
MAC,
NAS,
NGAP,
NRPPa,
PDCP,
PROD,
PHY,
RLC,
RRC,
S1AP,
TRX,
X2AP,
XnAP,
//NAS,
IP,
//S1AP,
//NGAP,
//GTPU,
IMS,
CX,
RX,
S6,
S13,
SGsAP,
SBcAP,
LCSAP,
//LPPa,
N12,
N8,
N17,
N50,
N13,
NL1,
HTTP2,
EPDG,
IKEV2,
IPSEC,
//PROD,
//CX,
//IMS,
//IPSEC,
MEDIA,
MMS,
//RX,
SIP,
}
}

59
src/X1.WebSocket/Models/ProtocolMessage.cs

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using X1.WebSocket.Models;
namespace CellularManagement.WebSocket.Models
{
/// <summary>
/// 协议消息模型
/// 用于封装和传输协议相关的消息数据
/// </summary>
public class ProtocolMessage
{
/// <summary>
/// 消息类型标识
/// 默认为 "Protocol",表示协议类型消息
/// </summary>
public string Type { get; set; } = "Protocol";
/// <summary>
/// 消息载荷数据
/// 包含具体的协议日志数据
/// </summary>
public ProtocolPayload Payload { get; set; }
/// <summary>
/// 初始化协议消息的新实例
/// </summary>
/// <param name="messages">协议日志消息数组</param>
public ProtocolMessage(TransferProtocolLog[] messages)
{
Payload = new ProtocolPayload(messages);
}
}
/// <summary>
/// 协议消息载荷
/// 包含具体的协议日志数据内容
/// </summary>
public class ProtocolPayload
{
/// <summary>
/// 协议日志消息数组
/// 存储要传输的协议日志数据
/// </summary>
public TransferProtocolLog[] Message { get; set; } = Array.Empty<TransferProtocolLog>();
/// <summary>
/// 初始化协议载荷的新实例
/// </summary>
/// <param name="messages">协议日志消息数组</param>
public ProtocolPayload(TransferProtocolLog[] messages)
{
Message = messages;
}
}
}

103
src/X1.WebSocket/Models/TransferProtocolLog.cs

@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace X1.WebSocket.Models
{
public class TransferProtocolLog
{
/// <summary>
/// 主键ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 协议层类型
/// </summary>
public ProtocolLayer LayerType { get; set; }
/// <summary>
/// 消息详情集合(JSON格式存储)
/// </summary>
public string? MessageDetailJson { get; set; }
/// <summary>
/// 小区ID
/// </summary>
public int? CellID { get; set; }
/// <summary>
/// 国际移动用户识别码
/// </summary>
public string? IMSI { get; set; }
/// <summary>
/// 日志方向类型
/// </summary>
public int Direction { get; set; }
/// <summary>
/// 用户设备ID
/// </summary>
public int? UEID { get; set; }
/// <summary>
/// 公共陆地移动网络标识
/// </summary>
public string? PLMN { get; set; }
/// <summary>
/// 时间间隔(毫秒)
/// </summary>
public long TimeMs { get; set; }
/// <summary>
/// 时间戳
/// </summary>
public long Timestamp { get; set; }
/// <summary>
/// 信息字段
/// </summary>
public string? Info { get; set; }
/// <summary>
/// 消息字段
/// </summary>
public string? Message { get; set; }
/// <summary>
/// 消息详情集合(用于业务逻辑)
/// </summary>
public IEnumerable<string>? MessageDetail
{
get => !string.IsNullOrEmpty(MessageDetailJson)
? JsonSerializer.Deserialize<IEnumerable<string>>(MessageDetailJson, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
})
: null;
set => MessageDetailJson = value != null
? JsonSerializer.Serialize(value, new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
WriteIndented = true
})
: null;
}
/// <summary>
/// 时间间隔(用于业务逻辑)
/// </summary>
public TimeSpan Time
{
get => TimeSpan.FromMilliseconds(TimeMs);
set => TimeMs = (long)value.TotalMilliseconds;
}
}
}

55
src/modify.md

@ -0,0 +1,55 @@
# 修改记录
## 2024-12-19 ProtocolMessageHandler 优化
### 修改文件
- `X1.WebSocket/Handlers/ProtocolMessageHandler.cs`
### 主要改进
#### 1. 方法重命名
- `ProtocolMessageOutput``ProcessProtocolMessageAsync`
- 更符合方法命名规范,清晰表达方法功能
#### 2. 代码结构优化
- 将原来的单一方法拆分为多个职责明确的方法:
- `ProcessProtocolMessageAsync`: 处理协议消息的主要逻辑
- `ProcessProtocolLogs`: 处理协议日志数组
- `ProcessSingleProtocolLog`: 处理单个协议日志
#### 3. 错误处理改进
- 在 `ProcessProtocolMessageAsync` 方法中添加了完整的异常处理机制
- 区分 JSON 反序列化错误和其他异常
- 提供更详细的错误日志信息
- 移除了 `HandleAsync` 方法中不必要的 try-catch,让异常向上传播
- 优化异常处理策略:记录错误日志后不再抛出异常,避免异常传播
#### 4. 日志记录优化
- 使用结构化日志记录,提高日志可读性
- 添加处理进度和统计信息的日志
- 改进日志级别使用,Debug/Info/Warning/Error 合理分配
- 美化协议日志输出格式,使用【】括号突出字段名称,提高可读性
- 添加空值处理,使用 "N/A" 标识空值
- 时间格式化为易读的时分秒毫秒格式
#### 5. 性能优化
- 添加 JsonSerializerOptions 配置,提高序列化性能
- 移除不必要的异步操作(ProcessProtocolMessage、ProcessProtocolLogs 和 ProcessSingleProtocolLog)
- 避免为了异步而异步的代码模式,只在实际需要异步的地方使用 async/await
#### 6. 代码质量提升
- 添加详细的 XML 文档注释
- 改进变量命名(MsgData → messageData)
- 使用 null 检查和空值验证
- 添加输入参数验证
#### 7. 可维护性改进
- 方法职责单一,便于测试和维护
- 代码结构清晰,易于理解和扩展
- 为未来业务逻辑扩展预留了接口
### 技术细节
- 使用 JsonSerializerOptions 配置大小写不敏感和驼峰命名
- 添加了消息数量统计和错误计数
- 改进了异常处理的分层结构
- 优化了日志输出的格式和内容
Loading…
Cancel
Save