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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 21:13:31