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

.NET 6 Blazor Server中SfGrid筛选后ImageViewer图片加载异常求助

问题原因分析
  • Blazor组件的OnInitializedAsync仅在首次初始化时执行,SfGrid筛选后组件可能被复用,此时DocumentID参数更新但不会触发OnInitializedAsync,导致图片未重新加载。
  • 参数setter中用Task.Run调用异步方法存在错误:既未等待任务完成,也未触发组件状态更新,还可能引发线程安全问题。
  • HttpClient头部处理不当,每次调用都清空默认头会影响其他请求,且重复实例化DocumentService属于冗余操作。
最优实现方案

1. 用OnParametersSetAsync处理初始化与参数更新

替换OnInitializedAsync,改用OnParametersSetAsync——该方法会在组件初始化以及参数变更时执行,完美适配网格筛选后的场景:

@inject HttpClient httpClient

@if (isLoading)
{
    <div>加载中...</div>
}
else if (DocumentFileData != null)
{
    <img src="data:image;base64,@(Convert.ToBase64String(DocumentFileData))" />
}
else
{
    <div>无可用图片</div>
}

@code {
    private int _currentDocumentId;
    private byte[] DocumentFileData { get; set; }
    private bool isLoading;

    [Parameter] public string AuthCookieValue { get; set; }
    [Parameter] public int DocumentID { get; set; }

    protected override async Task OnParametersSetAsync()
    {
        // 仅当DocumentID变化时重新加载,避免重复请求
        if (DocumentID != 0 && DocumentID != _currentDocumentId)
        {
            _currentDocumentId = DocumentID;
            isLoading = true;
            StateHasChanged(); // 触发UI更新显示加载状态
            
            try
            {
                DocumentFileData = await GetDocumentAsync(DocumentID);
            }
            finally
            {
                isLoading = false;
            }
        }
    }

    private async Task<byte[]> GetDocumentAsync(int documentId)
    {
        // 单独创建请求消息设置头部,避免修改HttpClient全局默认头
        using var request = new HttpRequestMessage(HttpMethod.Get, $"api/documents/{documentId}");
        request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", AuthCookieValue);

        var response = await httpClient.SendAsync(request);
        response.EnsureSuccessStatusCode();
        
        return await response.Content.ReadAsByteArrayAsync();
    }
}

2. 优化服务与依赖注入

  • 将DocumentService注册为Scoped服务(在Program.cs中添加builder.Services.AddScoped<DocumentService>()),直接注入组件而非每次实例化:
@inject DocumentService documentService
  • 调整GetDocumentAsync逻辑:
private async Task<byte[]> GetDocumentAsync(int documentId)
{
    var doc = await documentService.GetDocumentAsync(documentId);
    return doc.FileData;
}
  • 在DocumentService内部处理请求头,避免在组件中操作HttpClient全局配置。

3. 配合SfGrid的组件实例管理

给MyImageViewer添加@key,让Blazor根据DocumentID准确识别组件实例,避免复用导致的状态混乱:

<SfGrid Data="@GridData">
    <GridColumns>
        <GridColumn>
            <Template>
                @{
                    var data = (YourDataType)context;
                }
                <MyImageViewer AuthCookieValue="@AuthCookieValue" DocumentID="@data.DocumentID" @key="@data.DocumentID" />
            </Template>
        </GridColumn>
    </GridColumns>
</SfGrid>
关键要点总结
  • 用OnParametersSetAsync替代OnInitializedAsync,覆盖初始化与参数变更两种场景。
  • 通过@key帮助Blazor正确管理组件实例,避免复用引发的状态异常。
  • 异步逻辑必须在生命周期方法中处理,禁止在参数setter中调用无等待的异步方法。
  • 避免修改HttpClient全局请求头,改用独立请求消息配置头部,防止影响其他组件请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 18:55:20