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

Blazor异步字典服务初始空白、重复加载问题的修复咨询

问题解答

1. 解决初始空白值问题

初始表格显示空白是因为Blazor渲染时,GetIntStrDictVal的异步操作尚未完成,渲染使用了未完成任务的默认结果(空字符串),且操作完成后没有触发组件重新渲染。

解决方案:在页面的OnInitializedAsync中预加载所需字典
在页面初始化时提前加载表格用到的字典(Dict1和Dict2),确保缓存填充完成后再渲染表格,这样GetIntStrDictVal能直接从缓存返回值,无需等待异步操作。

页面代码修改示例:

@inject DictService _ds;
<MudTable Items="@List1">
<!-- 原表格内容不变 -->
</MudTable>

@code {
    private List<YourModelType> List1; // 替换为你的实际模型类型

    protected override async Task OnInitializedAsync()
    {
        // 先加载表格依赖的字典
        await _ds.GetAllIntStrDict("Dict1");
        await _ds.GetAllIntStrDict("Dict2");

        // 再加载表格数据
        List1 = await LoadTableData(); // 替换为你的数据加载逻辑
    }

    private async Task<List<YourModelType>> LoadTableData()
    {
        // 模拟数据加载,替换为实际API调用
        await Task.Delay(100);
        return new List<YourModelType>();
    }
}

如果无法提前确定所需字典(比如字典依赖表格数据),可在表格数据加载完成后,收集所需字典并加载,最后调用StateHasChanged()触发重新渲染:

protected override async Task OnInitializedAsync()
{
    List1 = await LoadTableData();
    
    // 收集所有需要的字典名称(示例)
    var requiredDicts = new HashSet<string> { "Dict1", "Dict2" };
    foreach (var dictName in requiredDicts)
    {
        await _ds.GetAllIntStrDict(dictName);
    }
    
    StateHasChanged();
}

2. 修复字典重复加载问题

原代码中静态Dictionary不是线程安全的,并发场景下多个线程会同时判断缓存不存在,导致重复调用FillIntStrDict和API请求。

解决方案:使用ConcurrentDictionary结合Lazy<Task<>>实现线程安全的异步缓存
通过ConcurrentDictionary存储Lazy<Task<List<...>>>,确保同一个字典仅触发一次API请求,即使多个线程并发调用。

修改后的DictService代码:

public class DictService
{
    private readonly IHttpService _ihttp;
    private readonly ILogger<DictService> _logger;
    // 使用ConcurrentDictionary存储Lazy包装的异步任务,确保线程安全
    private static readonly ConcurrentDictionary<string, Lazy<Task<List<KeyValuePair<int, string>>>>> _intStrDictCache = new();

    public DictService(IHttpService ihttp, ILogger<DictService> logger)
    {
        _ihttp = ihttp;
        _logger = logger;
    }

    public async ValueTask<List<KeyValuePair<int, string>>> GetAllIntStrDict(string dictName)
    {
        // GetOrAdd确保每个字典仅创建一次Lazy任务
        var lazyTask = _intStrDictCache.GetOrAdd(dictName, name => new Lazy<Task<List<KeyValuePair<int, string>>>>(() =>
        {
            return _ihttp.Get<List<KeyValuePair<int, string>>>($"api/Dicts/IntStr/all/{name}");
        }));

        // 等待任务完成并返回结果
        return await lazyTask.Value;
    }

    public async ValueTask<string> GetIntStrDictVal(int? key, string dictName)
    {
        if (key == null) return string.Empty;

        var dict = await GetAllIntStrDict(dictName);
        // 使用SingleOrDefault避免键不存在时抛出异常
        var item = dict.SingleOrDefault(x => x.Key == key);
        return item?.Value ?? string.Empty;
    }
}

关键改进点:

  • ConcurrentDictionary:线程安全的字典实现,避免并发读写冲突。
  • Lazy<Task<>>:确保异步任务仅被创建和执行一次,即使多个线程同时访问同一个字典。
  • 移除原FillIntStrDict方法,将API调用逻辑整合到GetOrAdd的工厂函数中。
  • 用SingleOrDefault替代Single,避免键不存在时抛出异常,增强代码健壮性。

内容的提问来源于stack exchange,提问作者Dorian

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 19:01:23