You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
491 lines
23 KiB
491 lines
23 KiB
using MediatR;
|
|
using Microsoft.Extensions.Logging;
|
|
using CellularManagement.Domain.Common;
|
|
using CellularManagement.Domain.Entities.Device;
|
|
using CellularManagement.Domain.Repositories.Device;
|
|
using CellularManagement.Domain.Repositories.Base;
|
|
using CellularManagement.Domain.Services;
|
|
using CellularManagement.Domain.Repositories.NetworkProfile;
|
|
using X1.Domain.Models;
|
|
using System.Collections.Concurrent;
|
|
using X1.Domain.ThirdPartyDeviceHttpClient.Models;
|
|
using X1.Domain.ThirdPartyDeviceHttpClient;
|
|
|
|
namespace CellularManagement.Application.Features.DeviceRuntimes.Commands.StartDeviceRuntime;
|
|
|
|
/// <summary>
|
|
/// 启动设备运行时状态命令处理器
|
|
/// </summary>
|
|
public class StartDeviceRuntimeCommandHandler : IRequestHandler<StartDeviceRuntimeCommand, OperationResult<StartDeviceRuntimeResponse>>
|
|
{
|
|
private readonly ICellularDeviceRuntimeRepository _deviceRuntimeRepository;
|
|
private readonly ICellularDeviceRepository _deviceRepository;
|
|
private readonly ILogger<StartDeviceRuntimeCommandHandler> _logger;
|
|
private readonly IUnitOfWork _unitOfWork;
|
|
private readonly ICurrentUserService _currentUserService;
|
|
private readonly IInstrumentProtocolClient _protocolClient;
|
|
private readonly INetworkStackConfigRepository _networkStackConfigRepository;
|
|
private readonly ICellularDeviceRuntimeDetailRepository _detailRepository;
|
|
|
|
/// <summary>
|
|
/// 初始化命令处理器
|
|
/// </summary>
|
|
public StartDeviceRuntimeCommandHandler(
|
|
INetworkStackConfigRepository networkStackConfigRepository,
|
|
ICellularDeviceRuntimeRepository deviceRuntimeRepository,
|
|
ICellularDeviceRepository deviceRepository,
|
|
ILogger<StartDeviceRuntimeCommandHandler> logger,
|
|
IUnitOfWork unitOfWork,
|
|
ICurrentUserService currentUserService,
|
|
IInstrumentProtocolClient protocolClient,
|
|
ICellularDeviceRuntimeDetailRepository detailRepository)
|
|
{
|
|
_deviceRuntimeRepository = deviceRuntimeRepository;
|
|
_deviceRepository = deviceRepository;
|
|
_logger = logger;
|
|
_unitOfWork = unitOfWork;
|
|
_currentUserService = currentUserService;
|
|
_protocolClient = protocolClient;
|
|
_networkStackConfigRepository = networkStackConfigRepository;
|
|
_detailRepository = detailRepository;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 处理启动设备运行时状态命令
|
|
/// </summary>
|
|
public async Task<OperationResult<StartDeviceRuntimeResponse>> Handle(StartDeviceRuntimeCommand request, CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
_logger.LogInformation("开始批量启动设备运行时状态,设备数量: {DeviceCount}", request?.DeviceRequests?.Count ?? 0);
|
|
|
|
// 验证命令参数
|
|
if (!request.IsValid())
|
|
{
|
|
_logger.LogWarning("命令参数验证失败");
|
|
return OperationResult<StartDeviceRuntimeResponse>.CreateFailure("命令参数验证失败");
|
|
}
|
|
|
|
// 获取当前用户
|
|
var currentUser = _currentUserService.GetCurrentUserId();
|
|
if (string.IsNullOrEmpty(currentUser))
|
|
{
|
|
_logger.LogWarning("当前用户未登录");
|
|
return OperationResult<StartDeviceRuntimeResponse>.CreateFailure("用户未登录");
|
|
}
|
|
|
|
_logger.LogDebug("开始获取网络堆栈配置,网络堆栈代码: {NetworkStackCodes}",
|
|
string.Join(", ", request.DeviceRequests.Select(r => r.NetworkStackCode)));
|
|
|
|
// 获取网络堆栈配置
|
|
var networkConfigs = await _networkStackConfigRepository.GetNetworkStackConfigsByCodesAsync(
|
|
request.DeviceRequests.Select(s => s.NetworkStackCode).ToArray(), cancellationToken);
|
|
|
|
if (networkConfigs == null || !networkConfigs.Any())
|
|
{
|
|
_logger.LogWarning("未找到指定的网络堆栈配置");
|
|
return OperationResult<StartDeviceRuntimeResponse>.CreateFailure("未找到指定的网络堆栈配置");
|
|
}
|
|
|
|
_logger.LogDebug("成功获取网络堆栈配置,配置数量: {ConfigCount}", networkConfigs.Count());
|
|
|
|
// 生成运行时编码
|
|
var runtimeCode = await GenerateRuntimeCodeAsync(cancellationToken);
|
|
if (string.IsNullOrEmpty(runtimeCode))
|
|
{
|
|
_logger.LogError("生成运行时编码失败");
|
|
return OperationResult<StartDeviceRuntimeResponse>.CreateFailure("生成运行时编码失败");
|
|
}
|
|
_logger.LogInformation("生成运行时编码: {RuntimeCode}", runtimeCode);
|
|
|
|
// 构建网络配置请求
|
|
var networkRequests = BuildNetworkConfigurationRequests(request, networkConfigs, runtimeCode);
|
|
|
|
_logger.LogInformation("成功构建网络配置请求,请求数量: {RequestCount}", networkRequests?.Count ?? 0);
|
|
|
|
// 检查是否有有效的网络配置请求
|
|
if (networkRequests == null || !networkRequests.Any())
|
|
{
|
|
_logger.LogWarning("没有有效的网络配置请求,无法启动设备运行时");
|
|
return OperationResult<StartDeviceRuntimeResponse>.CreateFailure("没有有效的网络配置请求,无法启动设备运行时");
|
|
}
|
|
|
|
// 并行启动网络并收集结果
|
|
var (successfulDevices, failedDevices) = await StartNetworksInParallelAsync(networkRequests, cancellationToken);
|
|
|
|
if (failedDevices.Any())
|
|
{
|
|
_logger.LogWarning("部分设备网络启动失败,失败设备: {FailedDevices}",
|
|
string.Join(", ", failedDevices.Select(f => f.DeviceCode)));
|
|
}
|
|
|
|
// 只为成功启动网络的设备创建运行时详情和更新状态
|
|
var runtimeDetails = new List<CellularDeviceRuntimeDetail>();
|
|
var updatedRuntimes = new List<CellularDeviceRuntime>();
|
|
|
|
foreach (var deviceRequest in request.DeviceRequests)
|
|
{
|
|
// 只处理网络启动成功的设备
|
|
if (!successfulDevices.Contains(deviceRequest.DeviceCode))
|
|
{
|
|
_logger.LogWarning("跳过处理网络启动失败的设备,设备代码: {DeviceCode}", deviceRequest.DeviceCode);
|
|
continue;
|
|
}
|
|
|
|
_logger.LogDebug("处理设备运行时,设备代码: {DeviceCode}", deviceRequest.DeviceCode);
|
|
|
|
// 创建运行时详情
|
|
var detail = CellularDeviceRuntimeDetail.Create(
|
|
deviceRequest.DeviceCode,
|
|
runtimeCode,
|
|
deviceRequest.NetworkStackCode,
|
|
currentUser, true);
|
|
runtimeDetails.Add(detail);
|
|
|
|
// 获取并更新设备运行时状态
|
|
var deviceRuntime = await _deviceRuntimeRepository.GetRuntimeByDeviceCodeAsync(deviceRequest.DeviceCode, cancellationToken);
|
|
if (deviceRuntime == null)
|
|
{
|
|
_logger.LogWarning("设备运行时不存在,设备代码: {DeviceCode}", deviceRequest.DeviceCode);
|
|
continue;
|
|
}
|
|
|
|
deviceRuntime.Start(deviceRequest.NetworkStackCode, runtimeCode);
|
|
_deviceRuntimeRepository.UpdateRuntime(deviceRuntime);
|
|
updatedRuntimes.Add(deviceRuntime);
|
|
|
|
_logger.LogDebug("设备运行时状态已更新,设备代码: {DeviceCode}, 网络堆栈代码: {NetworkStackCode}",
|
|
deviceRequest.DeviceCode, deviceRequest.NetworkStackCode);
|
|
}
|
|
|
|
// 批量保存运行时详情
|
|
if (runtimeDetails.Any())
|
|
{
|
|
_logger.LogDebug("保存运行时详情,详情数量: {DetailCount}", runtimeDetails.Count);
|
|
await _detailRepository.AddRangeAsync(runtimeDetails);
|
|
}
|
|
|
|
// 保存所有更改
|
|
await _unitOfWork.SaveChangesAsync(cancellationToken);
|
|
_logger.LogInformation("批量启动设备运行时状态完成,运行时代码: {RuntimeCode}, 成功设备数: {SuccessCount}, 失败设备数: {FailureCount}",
|
|
runtimeCode, successfulDevices.Count, failedDevices.Count);
|
|
|
|
return OperationResult<StartDeviceRuntimeResponse>.CreateSuccess(new StartDeviceRuntimeResponse
|
|
{
|
|
Summary = new BatchOperationSummary
|
|
{
|
|
TotalCount = request.DeviceRequests.Count,
|
|
SuccessCount = successfulDevices.Count,
|
|
FailureCount = failedDevices.Count
|
|
}
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "批量启动设备运行时状态失败");
|
|
return OperationResult<StartDeviceRuntimeResponse>.CreateFailure($"批量启动设备运行时状态失败: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 生成唯一的运行时编码
|
|
/// </summary>
|
|
/// <param name="cancellationToken">取消令牌</param>
|
|
/// <returns>生成的运行时编码</returns>
|
|
/// <remarks>
|
|
/// 运行时编码格式:RT-{时间戳}-{序号}
|
|
/// - 时间戳:yyyyMMddHHmmssfff 格式,精确到毫秒
|
|
/// - 序号:基于当前运行时总数自动递增,至少3位数字
|
|
///
|
|
/// 使用信号量确保在多线程环境下生成唯一的编码:
|
|
/// 1. 防止并发访问导致的序号重复
|
|
/// 2. 确保时间戳和序号的组合唯一性
|
|
/// 3. 避免数据库查询和插入之间的竞态条件
|
|
/// 4. 支持异步操作,避免死锁风险
|
|
/// 5. 控制并发访问数量,提高性能
|
|
/// </remarks>
|
|
private static readonly SemaphoreSlim _runtimeCodeSemaphore = new SemaphoreSlim(1, 1);
|
|
private async Task<string> GenerateRuntimeCodeAsync(CancellationToken cancellationToken)
|
|
{
|
|
// 使用信号量确保在多线程环境下生成唯一的运行时编码
|
|
await _runtimeCodeSemaphore.WaitAsync(cancellationToken);
|
|
|
|
try
|
|
{
|
|
_logger.LogDebug("开始生成运行时编码,线程ID: {ThreadId}", Thread.CurrentThread.ManagedThreadId);
|
|
|
|
// 获取当前设备运行时总数(异步调用)
|
|
var runtimeCount = await _deviceRuntimeRepository.GetRuntimeCountAsync(cancellationToken);
|
|
_logger.LogDebug("当前运行时总数: {RuntimeCount}", runtimeCount);
|
|
|
|
// 计算下一个序号
|
|
var nextNumber = runtimeCount + 1;
|
|
|
|
// 计算需要的位数,确保至少3位数
|
|
var digitCount = CalculateRequiredDigits(nextNumber);
|
|
|
|
// 格式化序号为指定位数
|
|
var formattedNumber = nextNumber.ToString($"D{digitCount}");
|
|
|
|
// 生成时间戳,精确到毫秒
|
|
string timestamp = DateTime.Now.ToString("yyyyMMddHHmmssfff");
|
|
|
|
// 组装运行时编码
|
|
var runtimeCode = $"RT-{timestamp}-{formattedNumber}";
|
|
|
|
_logger.LogDebug("成功生成运行时编码: {RuntimeCode}, 运行时总数: {RuntimeCount}, 序号: {NextNumber}, 位数: {DigitCount}, 线程ID: {ThreadId}",
|
|
runtimeCode, runtimeCount, nextNumber, digitCount, Thread.CurrentThread.ManagedThreadId);
|
|
|
|
return runtimeCode;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "生成运行时编码失败,线程ID: {ThreadId}", Thread.CurrentThread.ManagedThreadId);
|
|
// 重新抛出异常的原因:
|
|
// 1. 保持异常的原始堆栈跟踪信息,便于调试和问题定位
|
|
// 2. 确保上层调用者能够捕获到原始异常,进行适当的错误处理
|
|
// 3. 避免异常信息丢失,保持异常传播链的完整性
|
|
// 4. 符合异常处理的最佳实践:记录日志后重新抛出
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
// 确保信号量被释放
|
|
_runtimeCodeSemaphore.Release();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 计算需要的位数
|
|
/// </summary>
|
|
private int CalculateRequiredDigits(int number)
|
|
{
|
|
if (number <= 0) return 3; // 从000开始,至少3位数
|
|
|
|
// 计算位数:确保至少3位数,从000开始
|
|
// 1-999用3位,1000-9999用4位,10000-99999用5位,以此类推
|
|
var calculatedDigits = (int)Math.Floor(Math.Log10(number)) + 1;
|
|
return Math.Max(calculatedDigits, 3); // 确保至少3位数
|
|
}
|
|
|
|
/// <summary>
|
|
/// 构建网络配置请求
|
|
/// </summary>
|
|
/// <param name="request">启动设备运行时命令</param>
|
|
/// <param name="networkConfigs">网络堆栈配置</param>
|
|
/// <param name="runtimeCode">运行时编码</param>
|
|
/// <returns>构建好的网络配置请求列表</returns>
|
|
private List<CellularNetworkConfiguration> BuildNetworkConfigurationRequests(
|
|
StartDeviceRuntimeCommand request,
|
|
IEnumerable<NetworkStackConfigBasicDto> networkConfigs,
|
|
string runtimeCode)
|
|
{
|
|
// 按NetworkStackCode分组网络配置,提高查询效率
|
|
var networkConfigsByCode = networkConfigs
|
|
.Where(nc => !string.IsNullOrEmpty(nc.NetworkStackCode))
|
|
.GroupBy(nc => nc.NetworkStackCode!)
|
|
.ToDictionary(g => g.Key, g => g.ToList());
|
|
|
|
// 使用HashSet进行去重,提高性能
|
|
var processedDeviceNetworkPairs = new HashSet<string>();
|
|
|
|
return request.DeviceRequests
|
|
.Where(deviceRequest =>
|
|
{
|
|
// 检查是否已处理过相同的设备-网络堆栈组合
|
|
var deviceNetworkKey = $"{deviceRequest.DeviceCode}_{deviceRequest.NetworkStackCode}";
|
|
if (processedDeviceNetworkPairs.Contains(deviceNetworkKey))
|
|
{
|
|
_logger.LogWarning("设备代码 {DeviceCode} 与网络堆栈 {NetworkStackCode} 的组合已存在,跳过重复处理",
|
|
deviceRequest.DeviceCode, deviceRequest.NetworkStackCode);
|
|
return false;
|
|
}
|
|
|
|
// 检查是否存在对应的网络配置
|
|
if (!networkConfigsByCode.TryGetValue(deviceRequest.NetworkStackCode, out var deviceNetworkConfigs))
|
|
{
|
|
_logger.LogWarning("未找到对应的网络配置,设备代码: {DeviceCode}, 网络堆栈代码: {NetworkStackCode}",
|
|
deviceRequest.DeviceCode, deviceRequest.NetworkStackCode);
|
|
return false;
|
|
}
|
|
|
|
// 验证配置有效性
|
|
var hasValidRanConfig = deviceNetworkConfigs.Any(s => !string.IsNullOrEmpty(s.RanConfigContent));
|
|
var hasValidNetworkConfigs = deviceNetworkConfigs.Any(s =>
|
|
!string.IsNullOrEmpty(s.IMSConfigContent) && !string.IsNullOrEmpty(s.CoreNetworkConfigContent));
|
|
|
|
if (!hasValidRanConfig && !hasValidNetworkConfigs)
|
|
{
|
|
_logger.LogWarning("设备 {DeviceCode} 的网络配置既缺少RAN配置内容,又缺少有效的IMS和核心网配置内容,跳过处理",
|
|
deviceRequest.DeviceCode);
|
|
return false;
|
|
}
|
|
|
|
processedDeviceNetworkPairs.Add(deviceNetworkKey);
|
|
return true;
|
|
})
|
|
.Select(deviceRequest =>
|
|
{
|
|
var deviceNetworkConfigs = networkConfigsByCode[deviceRequest.NetworkStackCode];
|
|
|
|
// 构建CoreNetworkImsConfiguration列表
|
|
var coreNetworkImsConfigurations = deviceNetworkConfigs
|
|
.Where(s => !string.IsNullOrEmpty(s.IMSConfigContent) && !string.IsNullOrEmpty(s.CoreNetworkConfigContent))
|
|
.Select(networkConfig => new CoreNetworkImsConfiguration
|
|
{
|
|
Index = networkConfig.Index ?? 0,
|
|
Plmn = ExtractPlmnFromConfig(networkConfig.CoreNetworkConfigContent),
|
|
CoreNetworkConfiguration = networkConfig.CoreNetworkConfigContent!,
|
|
ImsServiceConfiguration = networkConfig.IMSConfigContent!
|
|
})
|
|
.ToList();
|
|
|
|
// 获取RAN配置
|
|
var validRanConfig = deviceNetworkConfigs
|
|
.Where(s => !string.IsNullOrEmpty(s.RanConfigContent))
|
|
.Select(s => s.RanConfigContent)
|
|
.Distinct()
|
|
.FirstOrDefault() ?? string.Empty;
|
|
|
|
// 创建网络配置
|
|
var configuration = new CellularNetworkConfiguration
|
|
{
|
|
RuntimeCode = runtimeCode,
|
|
DeviceCode = deviceRequest.DeviceCode,
|
|
RadioAccessNetworkConfiguration = validRanConfig,
|
|
CoreNetworkImsConfigurations = coreNetworkImsConfigurations
|
|
};
|
|
|
|
_logger.LogDebug("构建网络配置请求,设备代码: {DeviceCode}, 网络堆栈代码: {NetworkStackCode}, 绑定关系数量: {BindingCount}",
|
|
deviceRequest.DeviceCode, deviceRequest.NetworkStackCode, coreNetworkImsConfigurations.Count);
|
|
|
|
return configuration;
|
|
})
|
|
.ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 并行启动网络并收集结果
|
|
/// </summary>
|
|
/// <param name="networkRequests">网络配置请求列表</param>
|
|
/// <param name="cancellationToken">取消令牌</param>
|
|
/// <returns>成功和失败的设备信息元组</returns>
|
|
/// <remarks>
|
|
/// 该方法使用并行执行来同时启动多个网络,提高性能:
|
|
/// 1. 使用ConcurrentBag确保线程安全的结果收集
|
|
/// 2. 使用SemaphoreSlim控制并发数量,避免资源竞争(可选)
|
|
/// 3. 设置超时机制,防止任务无限等待
|
|
/// 4. 提供详细的错误处理和日志记录
|
|
/// 5. 确保资源正确释放
|
|
/// </remarks>
|
|
private async Task<(HashSet<string> SuccessfulDevices, List<(string DeviceCode, string ErrorMessage)> FailedDevices)>
|
|
StartNetworksInParallelAsync(List<CellularNetworkConfiguration> networkRequests, CancellationToken cancellationToken)
|
|
{
|
|
var networkResults = new ConcurrentBag<(bool Success, string DeviceCode, string ErrorMessage)>();
|
|
_logger.LogInformation("开始并行启动网络,请求数量: {RequestCount}", networkRequests.Count);
|
|
|
|
// 设置超时时间,防止任务无限等待
|
|
using var timeoutCts = new CancellationTokenSource(TimeSpan.FromMinutes(5)); // 5分钟超时
|
|
using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token);
|
|
|
|
// 完全并行执行,不受信号量限制
|
|
var tasks = networkRequests.Select(async networkRequest =>
|
|
{
|
|
try
|
|
{
|
|
_logger.LogDebug("启动网络,设备代码: {DeviceCode}, 运行时代码: {RuntimeCode}",
|
|
networkRequest.DeviceCode, networkRequest.RuntimeCode);
|
|
|
|
// 创建包装请求对象
|
|
var request = new StartCellularNetworkRequest
|
|
{
|
|
CellularNetwork = networkRequest
|
|
};
|
|
|
|
var startResult = await _protocolClient.StartNetworkAsync(request);
|
|
_logger.LogDebug("网络启动结果,设备代码: {DeviceCode}, 启动成功: {StartResult}",
|
|
networkRequest.DeviceCode, startResult);
|
|
|
|
if (startResult)
|
|
{
|
|
_logger.LogDebug("网络启动成功,设备代码: {DeviceCode}", networkRequest.DeviceCode);
|
|
networkResults.Add((true, networkRequest.DeviceCode, string.Empty));
|
|
}
|
|
else
|
|
{
|
|
var errorMessage = "网络启动返回失败状态";
|
|
_logger.LogWarning("网络启动返回失败状态,设备代码: {DeviceCode}", networkRequest.DeviceCode);
|
|
networkResults.Add((false, networkRequest.DeviceCode, errorMessage));
|
|
}
|
|
}
|
|
catch (OperationCanceledException) when (timeoutCts.Token.IsCancellationRequested)
|
|
{
|
|
var errorMessage = "网络启动超时";
|
|
_logger.LogWarning("网络启动超时,设备代码: {DeviceCode}", networkRequest.DeviceCode);
|
|
networkResults.Add((false, networkRequest.DeviceCode, errorMessage));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var errorMessage = $"网络启动失败: {ex.Message}";
|
|
_logger.LogError(ex, "网络启动失败,设备代码: {DeviceCode}", networkRequest.DeviceCode);
|
|
networkResults.Add((false, networkRequest.DeviceCode, errorMessage));
|
|
}
|
|
});
|
|
|
|
try
|
|
{
|
|
// 等待所有任务完成
|
|
await Task.WhenAll(tasks);
|
|
}
|
|
catch (OperationCanceledException) when (timeoutCts.Token.IsCancellationRequested)
|
|
{
|
|
_logger.LogWarning("网络启动操作超时,部分设备可能未完成启动");
|
|
}
|
|
|
|
// 检查网络启动结果
|
|
var successfulDevices = networkResults.Where(r => r.Success).Select(r => r.DeviceCode).ToHashSet();
|
|
var failedDevices = networkResults.Where(r => !r.Success).Select(r => (r.DeviceCode, r.ErrorMessage)).ToList();
|
|
|
|
_logger.LogInformation("网络启动完成,成功设备数: {SuccessCount}, 失败设备数: {FailureCount}",
|
|
successfulDevices.Count, failedDevices.Count);
|
|
|
|
return (successfulDevices, failedDevices);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 从网络配置中提取PLMN值
|
|
/// </summary>
|
|
/// <param name="configContent">网络配置内容</param>
|
|
/// <returns>提取的PLMN值,如果未找到则返回默认值"000000"</returns>
|
|
private string ExtractPlmnFromConfig(string configContent)
|
|
{
|
|
if (string.IsNullOrEmpty(configContent))
|
|
{
|
|
return "000000";
|
|
}
|
|
|
|
try
|
|
{
|
|
// 使用正则表达式匹配PLMN值(支持双引号和单引号)
|
|
var match = System.Text.RegularExpressions.Regex.Match(
|
|
configContent,
|
|
@"""plmn""\s*:\s*[""']([^""']+)[""']",
|
|
System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|
|
|
if (match.Success && match.Groups.Count > 1)
|
|
{
|
|
var plmnValue = match.Groups[1].Value.Trim();
|
|
_logger.LogDebug("从配置中提取到PLMN值: {PlmnValue}", plmnValue);
|
|
return string.IsNullOrEmpty(plmnValue) ? "000000" : plmnValue;
|
|
}
|
|
|
|
_logger.LogDebug("未从配置中找到PLMN值,使用默认值: 000000");
|
|
return "000000";
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "提取PLMN值时发生异常,使用默认值: 000000");
|
|
return "000000";
|
|
}
|
|
}
|
|
}
|