You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
    }
}

解决方案

关键改动点

  1. 提前空值校验:反序列化后先检查list.Branches是否为null,避免后续Linq查询触发空引用异常
  2. 循环内添加异常捕获:在foreach循环内部嵌套try-catch块,捕获当前单条记录处理时的异常,记录日志后跳过该记录
  3. 过滤无效数据:在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 02:05:19