基于首个API响应调用第二个API时遇NullReferenceException问题求助
异步逻辑导致的NullReferenceException问题解决思路
问题场景
先调用URL获取测试套件列表,再遍历每个套件调用对应URL获取测试用例,在Blazor组件中渲染时,测试套件能正常显示,但测试用例抛出空引用异常,提示TestCases was null。
组件异步方法代码
TestSuiteModel TestSuites; public async Task GetTestSuites() { string url = "https://dev.azure.com/XXX/_apis/test/Plans/12/suites?api-version=5.0"; TestSuites = await TestSuiteService.GetTestSuites(url); if(TestSuites != null) { foreach (var ts in TestSuites.value) { await this.GetTestCasess(ts.url); } } } TestCasesModel TestCases; private async Task GetTestCasess(string url) { TestCases = await TestCasesService.GetTestCases(url); }
Blazor渲染代码
@if(TestSuites != null) { <ul> @foreach (var ts in TestSuites.value) { <li> @ts.name </li> } </ul> } @if (TestCases.value != null) { <ul> @foreach (var ts in TestCases.value) { <li> @ts.testCase.webUrl </li> } </ul> }
错误信息
System.NullReferenceException: 'Object reference not set to an instance of an object.'
TestCases was null.
组件初始化代码
@page "/" @using BlazorTest.Models.TestSuiteModel; @using BlazorTest.Models.TestCasesModel; @inject BlazorTest.Services.TestSuiteService TestSuiteService; @inject BlazorTest.Services.TestCasesService TestCasesService; protected override async Task OnInitializedAsync() { await this.GetTestSuites(); await base.OnInitializedAsync(); }
核心问题分析
- 单变量无法存储多组数据:
TestCases是单个变量,在GetTestSuites的foreach循环中每次调用GetTestCasess都会覆盖它,最终仅保留最后一个套件的测试用例;若循环中某次接口返回null,或组件渲染时循环未执行完成,就会导致TestCases为null。 - 渲染时缺少空值判断:渲染代码直接访问
TestCases.value,但未先判断TestCases本身是否为null,触发空引用异常。 - 数据关联逻辑缺失:未建立测试套件与对应测试用例的关联关系,无法按套件展示对应的测试用例。
具体修复步骤
1. 修改数据存储结构
使用字典存储每个测试套件对应的测试用例,建立关联关系:
TestSuiteModel TestSuites; Dictionary<string, TestCasesModel> SuiteTestCases = new Dictionary<string, TestCasesModel>(); public async Task GetTestSuites() { string url = "https://dev.azure.com/XXX/_apis/test/Plans/12/suites?api-version=5.0"; TestSuites = await TestSuiteService.GetTestSuites(url); if(TestSuites != null) { foreach (var ts in TestSuites.value) { var testCases = await TestCasesService.GetTestCases(ts.url); SuiteTestCases.Add(ts.url, testCases ?? new TestCasesModel()); } } }
2. 修复渲染逻辑
按套件关联渲染测试用例,同时增加多层空值判断:
@if(TestSuites != null) { <ul> @foreach (var ts in TestSuites.value) { <li> @ts.name @if(SuiteTestCases.ContainsKey(ts.url) && SuiteTestCases[ts.url]?.value != null) { <ul> @foreach (var tc in SuiteTestCases[ts.url].value) { <li> @tc.testCase.webUrl </li> } </ul> } </li> } </ul> }
3. 增加加载状态优化体验
添加加载状态变量,避免异步加载过程中出现异常:
bool isLoading = true; protected override async Task OnInitializedAsync() { await this.GetTestSuites(); isLoading = false; await base.OnInitializedAsync(); }
渲染时先显示加载提示:
@if(isLoading) { <p>加载中...</p> } else { <!-- 上述套件与测试用例渲染代码 --> }
4. 空值防御编程
在服务调用层确保返回非null对象,避免后续空引用:
// 在GetTestCasess方法中(若仍使用单变量场景) private async Task GetTestCasess(string url) { TestCases = await TestCasesService.GetTestCases(url) ?? new TestCasesModel(); }
内容的提问来源于stack exchange,提问作者elektra
相关产品推荐
相关产品推荐

