ASP.NET Core Web API遇空引用异常时跳过记录插入的方法
问题:ASP.NET Core 6 Web API处理第三方API数据时跳过异常记录继续执行
我正在使用ASP.NET Core 6 Web API将第三方API的数据插入数据库。第三方API地址为https://api.thirdpartycompany.com:2233/api/BranchDetail,该地址配置在appsettings.json的Endpoints节点中。API返回的JSON数据包含多个分支信息,我已定义对应的Entity(Branch类)、DTO(BranchCreateUpdateDto、BranchResponse)、BaseResponse类,以及服务层的IAdminBranchService接口和AdminBranchService实现类,用于实现新增分支记录或更新已有记录的逻辑。
但在执行InsertAsync(res)方法时,部分记录出现如下异常:
System.NullReferenceException HResult=0x80004003 Message=Object reference not set to an instance of an object.
请问如何修改代码,让程序遇到该异常时跳过当前记录,继续处理下一条分支数据?
相关核心代码
Entity
public class Branch { public int Id { get; set; } public string BranchName { get; set; } public string BranchType { get; set; } public int BranchNumber { get; set; } }
DTO
public class BranchCreateUpdateDto { public string BranchName { get; set; } public string BranchType { get; set; } public int BranchNumber { get; set; } } public class BranchResponse { public List<BranchCreateUpdateDto> Branches { get; set; } }
BaseResponse
public class BaseResponse { public bool Success { get; set; } = true; public string Message { get; set; } }
Service实现
public class AdminBranchService : IAdminBranchService { private readonly ApplicationDbContext _dbContext; private readonly IMapper _mapper; private readonly IUnitOfWork _unitOfWork; private readonly ILogger _logger; private readonly IConfiguration _config; private readonly HttpClient _myClient; public AdminBranchService( ApplicationDbContext dbContext, IUnitOfWork unitOfWork, ILogger logger, IMapper mapper, IConfiguration config, HttpClient myClient ) { _dbContext = dbContext; _mapper = mapper; _unitOfWork = unitOfWork; _logger = logger; _config = config; _myClient = myClient; } public async Task<BaseResponse> CreateBranchAsync() { var branchResponse = new BaseResponse(); var branches = new List<Branch>(); try { string branchUrl = _config.GetSection("Endpoints").GetValue<string>("branchUrl"); _myClient.DefaultRequestHeaders.Accept.Clear(); _myClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = _myClient.GetAsync(branchUrl).Result; var stringResult = response.Content.ReadAsStringAsync().Result; BranchResponse list = JsonConvert.DeserializeObject<BranchResponse>(stringResult); // filter branches based on BranchType var filteredBranches = list.Branches .Where(x => x.BranchType.StartsWith("Human Resource") || x.BranchType.StartsWith("Production")); foreach (var singleBranch in filteredBranches) { Branch res = new Branch(); if (_dbContext.Branches.Any(x => x.BranchName == singleBranch.BranchName)) { res.BranchNumber = singleBranch.BranchNumber; _unitOfWork.Branches.Update(res); } else { //set all fields here res.BranchName = singleBranch.BranchName; res.BranchNumber = singleBranch.BranchNumber; await _unitOfWork.Branches.InsertAsync(res); } await _unitOfWork.Save(); } } catch (Exception ex) { _logger.Error("An Error occured " + ex.ToString()); } return branchResponse; } }
解决方案
关键改动点
- 提前空值校验:反序列化后先检查
list.Branches是否为null,避免后续Linq查询触发空引用异常 - 循环内添加异常捕获:在foreach循环内部嵌套try-catch块,捕获当前单条记录处理时的异常,记录日志后跳过该记录
- 过滤无效数据:在Linq查询中增加对
singleBranch及其属性的空值校验,提前排除无效数据
修改后的Service实现代码
public class AdminBranchService : IAdminBranchService { private readonly ApplicationDbContext _dbContext; private readonly IMapper _mapper; private readonly IUnitOfWork _unitOfWork; private readonly ILogger _logger; private readonly IConfiguration _config; private readonly HttpClient _myClient; public AdminBranchService( ApplicationDbContext dbContext, IUnitOfWork unitOfWork, ILogger logger, IMapper mapper, IConfiguration config, HttpClient myClient ) { _dbContext = dbContext; _mapper = mapper; _unitOfWork = unitOfWork; _logger = logger; _config = config; _myClient = myClient; } public async Task<BaseResponse> CreateBranchAsync() { var branchResponse = new BaseResponse(); var processedCount = 0; var skippedCount = 0; try { string branchUrl = _config.GetSection("Endpoints").GetValue<string>("branchUrl"); _myClient.DefaultRequestHeaders.Accept.Clear(); _myClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); // 替换为异步调用,避免阻塞线程 HttpResponseMessage response = await _myClient.GetAsync(branchUrl); response.EnsureSuccessStatusCode(); // 确保API请求成功 var stringResult = await response.Content.ReadAsStringAsync(); BranchResponse list = JsonConvert.DeserializeObject<BranchResponse>(stringResult); // 先校验Branches是否为null,避免空引用 if (list?.Branches == null) { _logger.Warn("第三方API返回的分支数据为空"); branchResponse.Message = "未获取到有效分支数据"; return branchResponse; } // 过滤分支:排除null记录,同时校验BranchType和BranchName不为null var filteredBranches = list.Branches .Where(x => x != null && !string.IsNullOrEmpty(x.BranchType) && !string.IsNullOrEmpty(x.BranchName) && (x.BranchType.StartsWith("Human Resource") || x.BranchType.StartsWith("Production"))); foreach (var singleBranch in filteredBranches) { try { Branch res = new Branch(); var existingBranch = await _dbContext.Branches.FirstOrDefaultAsync(x => x.BranchName == singleBranch.BranchName); if (existingBranch != null) { // 更新已有分支:使用查询到的实体,而非新建的空实体 existingBranch.BranchNumber = singleBranch.BranchNumber; _unitOfWork.Branches.Update(existingBranch); } else { res.BranchName = singleBranch.BranchName; res.BranchType = singleBranch.BranchType; // 补充设置BranchType字段 res.BranchNumber = singleBranch.BranchNumber; await _unitOfWork.Branches.InsertAsync(res); } await _unitOfWork.Save(); processedCount++; } catch (Exception ex) { skippedCount++; _logger.Error($"处理分支[{singleBranch?.BranchName}]时出错:{ex.ToString()}"); // 跳过当前记录,继续处理下一条 continue; } } branchResponse.Message = $"处理完成:成功{processedCount}条,跳过{skippedCount}条"; } catch (Exception ex) { _logger.Error($"获取第三方API数据时出错:{ex.ToString()}"); branchResponse.Success = false; branchResponse.Message = "数据获取失败,请稍后重试"; } return branchResponse; } }
额外优化说明
- 将同步的
.Result调用替换为await,避免线程阻塞 - 更新逻辑中使用查询到的
existingBranch实体而非新建空实体,原代码中更新空实体不会生效 - 补充设置Branch实体的
BranchType字段,原代码中遗漏该字段赋值 - 增加处理统计,在返回结果中展示成功和跳过的记录数
内容的提问来源于stack exchange,提问作者Ayobamilaye
相关产品推荐
相关产品推荐

