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
相关产品推荐
相关产品推荐

