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

MudBlazor显示图片时OnInitializedAsync与Dispose重复执行问题

问题分析与解决方案

原因

你的问题核心是Blazor Server组件被实例化了两次,进而导致OnInitializedAsync和Dispose各执行两次。仅在显示图片时出现该现象,是因为图片的Base64内容触发了Blazor的渲染边界处理:当组件输出的静态内容过大时,框架会放弃预渲染的实例,重新创建交互式实例;即便关闭预渲染,.NET 9的自动渲染模式逻辑也可能导致组件被二次初始化。

你之前尝试的_isInitialized标记未生效,大概率是标记变量作用域处理不当,或是未在初始化流程开始前做判断。

解决方案

针对你的场景,推荐以下互补方案,彻底解决重复加载与重复释放问题:

1. 明确禁用预渲染+组件内初始化锁

在组件顶部指定禁用预渲染的交互式服务器渲染模式,并在代码中加入初始化锁,确保图片加载逻辑仅执行一次:

修改Razor页面头部:

@page "/"
@using MudBlazor
@implements IDisposable
@inject NavigationManager Navigation
@rendermode InteractiveServerRenderMode(prerender: false)

在@code块中添加初始化标记:

private List<Foo> Foos = new List<Foo>();
private bool _isInitialized = false;

protected override async Task OnInitializedAsync()
{
    if (_isInitialized) return;
    
    Foos = await LoadImages();
    _isInitialized = true;
    Console.WriteLine("OnInitializedAsync executed.");
}

2. 用范围服务缓存图片数据(推荐,适配后续数据库场景)

将图片加载逻辑封装到范围服务中,借助依赖注入的生命周期特性,确保每个用户会话仅加载一次图片,避免重复的磁盘/数据库访问:

首先创建图片服务:

namespace BlazorMinimalExample2;

public interface IFooImageService
{
    Task<List<Foo>> GetImagesAsync();
}

public class FooImageService : IFooImageService
{
    private List<Foo>? _cachedImages;

    public async Task<List<Foo>> GetImagesAsync()
    {
        if (_cachedImages != null) return _cachedImages;
        
        var foos = new List<Foo>();
        var userPicPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Pictures");
        
        foos.Add(new Foo(File.ReadAllBytes(Path.Combine(userPicPath, "20190119_131055 2.jpg"))));
        foos.Add(new Foo(File.ReadAllBytes(Path.Combine(userPicPath, "20210117_010401.jpg"))));
        
        _cachedImages = foos;
        return foos;
    }
}

在Program.cs中注册为范围服务:

builder.Services.AddScoped<IFooImageService, FooImageService>();

最后修改组件逻辑,注入服务并调用:

@inject IFooImageService ImageService

@code {
    private List<Foo> Foos = new List<Foo>();
    private bool _isInitialized = false;

    protected override async Task OnInitializedAsync()
    {
        if (_isInitialized) return;
        
        Foos = await ImageService.GetImagesAsync();
        _isInitialized = true;
        Console.WriteLine("OnInitializedAsync executed.");
    }
}

3. 优化Dispose逻辑,避免重复释放

加入释放标记,确保Dispose仅执行一次:

private bool _isDisposed = false;

public void Dispose()
{
    if (_isDisposed) return;
    
    Console.WriteLine("Dispose executed.");
    foreach (var foo in Foos)
    {
        foo.CleanUp();
    }
    Foos.Clear();
    _isDisposed = true;
}

修改后的完整组件代码

@page "/"
@using MudBlazor
@implements IDisposable
@inject NavigationManager Navigation
@inject IFooImageService ImageService
@rendermode InteractiveServerRenderMode(prerender: false)

<MudLayout>
    @if (Foos.Count > 0)
    {
        <MudGrid Class="mt-4" Spacing="0">
            @foreach (Foo f in Foos)
            {
                @if (f.ImageAsByteArray != null)
                {
                    <MudItem xs="12" sm="6" md="4">
                        <MudCardContent Dense="true">
                            <MudImage Src="@($"data:image;base64,{Convert.ToBase64String(f.ImageAsByteArray)}")" 
                                      Elevation="25" 
                                      Class="rounded-lg ma-2 d-block mx-auto" 
                                      Width="350" 
                                      Height="350" />
                        </MudCardContent>
                    </MudItem>
                }
            }
        </MudGrid>
    }
</MudLayout>

@code {
    private List<Foo> Foos = new List<Foo>();
    private bool _isInitialized = false;
    private bool _isDisposed = false;

    protected override async Task OnInitializedAsync()
    {
        if (_isInitialized) return;
        
        Foos = await ImageService.GetImagesAsync();
        _isInitialized = true;
        Console.WriteLine("OnInitializedAsync executed.");
    }

    public void Dispose()
    {
        if (_isDisposed) return;
        
        Console.WriteLine("Dispose executed.");
        foreach (var foo in Foos)
        {
            foo.CleanUp();
        }
        Foos.Clear();
        _isDisposed = true;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 21:46:11