我遇到这个问题已经有一段时间了,为了重现该错误,我创建了一个新的 Blazor 项目来向您显示所有文件。
这是我的index.razor文件:
@using BlazorApp1.Models.TestSuiteModel;
@inject BlazorApp1.Services.TestSuiteService TestSuiteServ;
@page "/"
<b>
@TestSuitesResult.count;
</b>
@code {
protected override async Task OnInitializedAsync()
{
this.GetTestSuites();
}
TestSuiteModel TestSuitesResult;
protected async Task GetTestSuites()
{
TestSuiteServ.url = "https://dev.azure.com/****/_apis/test/Plans/12/suites?api-version=5.0";
TestSuiteServ.PersonalAccessToken = "****";
TestSuitesResult = await TestSuiteServ.GetTestSuites();
await base.OnInitializedAsync();
}
}
Run Code Online (Sandbox Code Playgroud)
问题是@TestSuitesResult.count;始终为空并引发此错误:

下面是我的模型
namespace BlazorApp1.Models.TestSuiteModel
{
public class TestSuiteModel
{
public List<Value> value { get; set; }
public int count { get; set; }
}
// .. mode classes
}
Run Code Online (Sandbox Code Playgroud)
以下是我的服务
using BlazorApp1.Models.TestSuiteModel;
using Newtonsoft.Json;
using System.Net.Http.Headers;
using System.Net.Http.Headers;
namespace BlazorApp1.Services
{
public class TestSuiteService
{
public string url { get; set; }
public string PersonalAccessToken { get; set; }
TestSuiteModel result;
public async Task<TestSuiteModel> GetTestSuites()
{
using (HttpClient client = new HttpClient())
{
// accept response as JSON
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json")
);
// add DevOps token to the HTTP Header request
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
"Basic", Convert.ToBase64String(
System.Text.Encoding.ASCII.GetBytes(
string.Format("{0}:{1}", "", PersonalAccessToken)
)
)
);
HttpResponseMessage response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
string responseData = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<TestSuiteModel>(responseData);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是我在这个项目中唯一拥有的东西。除了在中注册服务之外,我没有修改或删除默认 Blazor 项目中的任何文件program.cs
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
builder.Services.AddSingleton<TestSuiteService>(); <!-- my service -->
var app = builder.Build();
Run Code Online (Sandbox Code Playgroud)
还添加了 Newtonsoft,因此它不可能是缺少的库。
GetTestSuites永远不会被等待
protected override async Task OnInitializedAsync()
{
this.GetTestSuites();
}
Run Code Online (Sandbox Code Playgroud)
它应该是 :
protected override async Task OnInitializedAsync()
{
await this.GetTestSuites();
}
Run Code Online (Sandbox Code Playgroud)
现在已OnInitializedAsync完成,并且页面在GetTestSuites有机会完成之前呈现。
还有其他问题TestSuiteService。HttpClient 旨在重用,而不是在using块中定义。特别是在 Blazor 中,HttpClient 实例是由浏览器提供的。整个GetTestSuites方法可以替换为单个方法await _httpClient.GetFromJsonAsync<TestSuiteModel>(url);,其中_httpClient可以是通过 注册的 HttpClient AddHttpClient。其他一切都是GetFromJsonAsync的默认行为:
public interface ITestSuiteService
{
Task<TestSuiteModel> GetTestSuites(string url);
}
public class TestSuiteService:ITestSuiteService
{
public TestSuiteService(HttpClient client)
{
_httpClient=client;
}
public async Task<TestSuiteModel> GetTestSuites(string url)
{
var model=await _httpClient.GetFromJsonAsync<TestSuiteModel>(url);
return model;
}
}
Run Code Online (Sandbox Code Playgroud)
该服务可以注册为类型化的 HttpClient :
builder.Services.AddHttpClient<ITestSuiteService,TestSuiteService>(client=>{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
"Basic", Convert.ToBase64String(
System.Text.Encoding.ASCII.GetBytes(
$":{PersonalAccessToken}")
)
)
);
});
Run Code Online (Sandbox Code Playgroud)
此时可以从配置中检索令牌。
另一种选择是使用GetAsyn、检查响应并使用HttpContent.ReadFromJsonAsync。这避免了异常的成本,特别是在 API 中,当需要像 429(请求过多)这样的响应时:
public async Task<TestSuiteModel> GetTestSuites(string url)
{
var response=await _httpClient.GetAsync(url);
if(response.IsSuccessStatusCode)
{
var model=await response.Content.ReadFromJsonAsync<TestSuiteModel>();
return model;
}
else
{
...
}
}
Run Code Online (Sandbox Code Playgroud)
对象的初始状态为 null。
您必须在此处进行空检查或提供默认对象。您可以通过三种方法来解决此问题。1:使用 if 检查 null
<b>
@if(TestSuitesResult is not null)
{
@TestSuitesResult.count;
}
</b>
Run Code Online (Sandbox Code Playgroud)
2:使用 Elvis 运算符检查 null
<b>
@TestSuitesResult?.count;
</b>
Run Code Online (Sandbox Code Playgroud)
3:提供默认值
TestSuiteModel TestSuitesResult = new TestSuiteModel();
Run Code Online (Sandbox Code Playgroud)
还要确保等待您的函数,OnInitializedAsync否则您将调用您的函数并忘记它。