Blazor .NET 8:客户端依赖注入配置异常排查(调用外部API)
基于标准Blazor模板扩展客户列表页面,需在WebAssembly客户端调用自定义基地址的外部API:页面加载时显示“Loading..”,获取数据后填充表格。
已创建类型化HttpClient CustomerServiceApiClient,在客户列表页面CustomerSummaryPage通过依赖注入调用,并在客户端项目Program.cs中注册服务和HttpClient:
public class CustomerServiceApiClient(HttpClient client) { public async Task<PaginatedResponse<CustomerDto>> GetPaginatedCustomersAsync() { var result = await client.GetFromJsonAsync<PaginatedResponse<CustomerDto>>("customers"); return result ?? new PaginatedResponse<CustomerDto> { Data = [] }; } }
public partial class CustomerSummaryPage : ComponentBase { public PaginatedResponse<CustomerDto> PaginatedCustomers { get; set; } = new(); [Inject] private CustomerServiceApiClient? CustomerServiceApiClient { get; set; } protected override async Task OnInitializedAsync() { await GetCustomersAsync(); } public async Task GetCustomersAsync() { PaginatedCustomers = await CustomerServiceApiClient.GetPaginatedCustomersAsync(); } }
// Dependency Injection of the typed HttpClients builder.Services.AddScoped<CustomerServiceApiClient>(); // Add typed HttpClient for all internal API calls builder.Services.AddHttpClient<CustomerServiceApiClient>(client => client.BaseAddress = new Uri(builder.Configuration["WebApi:CustomerServiceApi"])) .AddHttpMessageHandler<AuthorizedHttpClientHandler>();
出现以下错误:
System.InvalidOperationException: Cannot provide a value for property 'CustomerServiceApiClient' on type 'Maliev.Intranet.Client.Pages.Customers.CustomerSummaryPage'. There is no registered service of type 'Maliev.Intranet.Client.Services.CustomerServiceApiClient'.
若将依赖注入代码复制到服务端项目,错误消失,但BaseAddress始终为空(服务端和客户端的appsettings.json均已配置对应值):
{ "WebApi": { "BaseAddress": "https://xxx.xxx.xxx/xxx", "CustomerServiceApi": "https://xxx.xxx.xxx/xxx/xxx/xxx", "CurrenciesServiceApi": "https://xxx.xxx.xxx/xxx/xxx/xxx" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } } }
页面和类型化HttpClient都在客户端项目,请问正确的配置方式是什么?
1. 修正客户端DI注册逻辑
AddHttpClient<T>方法会自动注册T为Scoped服务,不需要额外调用AddScoped<CustomerServiceApiClient>(),重复注册会导致冲突。修改客户端Program.cs代码:
// 移除单独的AddScoped注册,保留AddHttpClient即可 builder.Services.AddHttpClient<CustomerServiceApiClient>(client => { var apiUrl = builder.Configuration["WebApi:CustomerServiceApi"]; // 添加空值检查,避免Uri初始化失败 if (string.IsNullOrEmpty(apiUrl)) { throw new InvalidOperationException("CustomerServiceApi配置项未设置"); } client.BaseAddress = new Uri(apiUrl); }) .AddHttpMessageHandler<AuthorizedHttpClientHandler>();
2. 确保客户端配置正确加载
Blazor WebAssembly项目中,appsettings.json必须放在客户端项目的wwwroot目录下,否则无法被加载。确认文件路径为ClientProject/wwwroot/appsettings.json,且配置项名称完全匹配(注意大小写敏感)。
3. 修正页面注入的可空性问题
页面中注入的CustomerServiceApiClient标记为可空,但调用时未做空值判断,容易引发空引用异常。修改注入代码:
[Inject] private CustomerServiceApiClient CustomerServiceApiClient { get; set; } = null!;
4. 确保AuthorizedHttpClientHandler在客户端注册
如果AuthorizedHttpClientHandler是自定义的消息处理器,需要确保它在客户端Program.cs中注册为Scoped服务:
builder.Services.AddScoped<AuthorizedHttpClientHandler>();
5. 验证BaseAddress是否正确加载
可以在CustomerServiceApiClient中添加日志输出,确认BaseAddress是否正确:
public class CustomerServiceApiClient(HttpClient client, ILogger<CustomerServiceApiClient> logger) { public async Task<PaginatedResponse<CustomerDto>> GetPaginatedCustomersAsync() { logger.LogInformation("BaseAddress: {BaseAddress}", client.BaseAddress); var result = await client.GetFromJsonAsync<PaginatedResponse<CustomerDto>>("customers"); return result ?? new PaginatedResponse<CustomerDto> { Data = [] }; } }
6. 页面添加Loading状态处理
在页面中实现加载时显示“Loading..”的需求:
public partial class CustomerSummaryPage : ComponentBase { public PaginatedResponse<CustomerDto> PaginatedCustomers { get; set; } = new(); public bool IsLoading { get; set; } = true; [Inject] private CustomerServiceApiClient CustomerServiceApiClient { get; set; } = null!; protected override async Task OnInitializedAsync() { await GetCustomersAsync(); } public async Task GetCustomersAsync() { IsLoading = true; try { PaginatedCustomers = await CustomerServiceApiClient.GetPaginatedCustomersAsync(); } finally { IsLoading = false; } } }
对应的Razor部分:
@if (IsLoading) { <p>Loading..</p> } else { <table> <!-- 表格内容 --> </table> }
内容的提问来源于stack exchange,提问作者Natthapol Vanasrivilai

