c# - Double execution of OnInitializedAsync and Dispose in MudBlazor when displaying images - Stack Overflow

admin2025-04-17  1

I want to build a website using MudBlazor and C# on .NET 9. On one of the pages, I want to display images, which are loaded in the OnInitializedAsync event handler. To handle the case when the user leaves the page, I have implemented a Dispose method.

However, I noticed that both OnInitializedAsync and Dispose are executed twice.

Log output:

OnInitializedAsync executed.
Dispose executed.
OnInitializedAsync executed.
Dispose executed.

This behavior only occurs when images are displayed.

I am wondering why this happens and how I can prevent unnecessary disk (or later database) access.

I have already tried using a _isInitialized flag set to true to prevent a second disposal, but Dispose is still called twice.

I also attempted using OnAfterRenderAsync with _isRendered flag, but since OnAfterRenderAsync gets triggered multiple times, it is not suitable because the images are reloaded too often.

I came across this thread. I wanted to implement the answers contained there, but the thread is about Blazor in general, and it's from 2019. I don't have the _Host.cshtml in the project (so, my question is not a duplicate).

I then tried the other answer, using

@rendermode @(new InteractiveServerRenderMode(prerender:false))

This has the effect that the second dispose is no longer called when rendering, otherwise only when you leave the page. Nevertheless, the data is fetched twice.

I use a server-side application. The template when creating the project is this one:

MudBlazor was installed as a Nuget package from the beginning.

I have provided a minimal, runnable example for you to check.

@page "/"
@using MudBlazor
@implements IDisposable
@inject NavigationManager Navigation
<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>();
    protected override async Task OnInitializedAsync()
    {
        Foos = await LoadImages();
        Console.WriteLine("OnInitializedAsync executed.");
    }

    public void Dispose()
    {
        Console.WriteLine("Dispose executed.");

        foreach (Foo foo in Foos)
        {
            foo.CleanUp();
        }
    }

    private Task<List<Foo>> LoadImages()
    {
        List<Foo> foos = new List<Foo>();

        Foo foo1 = new Foo(System.IO.File.ReadAllBytes(@$"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}\Pictures\20190119_131055 2.jpg"));
        foos.Add(foo1);

        Foo foo2 = new Foo(System.IO.File.ReadAllBytes(@$"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}\Pictures\20210117_010401.jpg"));
        foos.Add(foo2);

        return Task.FromResult(foos);
    }
}
namespace BlazorMinimalExample2
{
    public class Foo
    {
        public byte[]? ImageAsByteArray { get; set; }

        public Foo(byte[] stuff)
        {
            this.ImageAsByteArray = stuff;
        }

        public void CleanUp()
        {
            if (this.ImageAsByteArray != null)
            {
                this.ImageAsByteArray = null;
            }
        }
    }
}

I want to build a website using MudBlazor and C# on .NET 9. On one of the pages, I want to display images, which are loaded in the OnInitializedAsync event handler. To handle the case when the user leaves the page, I have implemented a Dispose method.

However, I noticed that both OnInitializedAsync and Dispose are executed twice.

Log output:

OnInitializedAsync executed.
Dispose executed.
OnInitializedAsync executed.
Dispose executed.

This behavior only occurs when images are displayed.

I am wondering why this happens and how I can prevent unnecessary disk (or later database) access.

I have already tried using a _isInitialized flag set to true to prevent a second disposal, but Dispose is still called twice.

I also attempted using OnAfterRenderAsync with _isRendered flag, but since OnAfterRenderAsync gets triggered multiple times, it is not suitable because the images are reloaded too often.

I came across this thread. I wanted to implement the answers contained there, but the thread is about Blazor in general, and it's from 2019. I don't have the _Host.cshtml in the project (so, my question is not a duplicate).

I then tried the other answer, using

@rendermode @(new InteractiveServerRenderMode(prerender:false))

This has the effect that the second dispose is no longer called when rendering, otherwise only when you leave the page. Nevertheless, the data is fetched twice.

I use a server-side application. The template when creating the project is this one:

MudBlazor was installed as a Nuget package from the beginning.

I have provided a minimal, runnable example for you to check.

@page "/"
@using MudBlazor
@implements IDisposable
@inject NavigationManager Navigation
<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>();
    protected override async Task OnInitializedAsync()
    {
        Foos = await LoadImages();
        Console.WriteLine("OnInitializedAsync executed.");
    }

    public void Dispose()
    {
        Console.WriteLine("Dispose executed.");

        foreach (Foo foo in Foos)
        {
            foo.CleanUp();
        }
    }

    private Task<List<Foo>> LoadImages()
    {
        List<Foo> foos = new List<Foo>();

        Foo foo1 = new Foo(System.IO.File.ReadAllBytes(@$"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}\Pictures\20190119_131055 2.jpg"));
        foos.Add(foo1);

        Foo foo2 = new Foo(System.IO.File.ReadAllBytes(@$"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}\Pictures\20210117_010401.jpg"));
        foos.Add(foo2);

        return Task.FromResult(foos);
    }
}
namespace BlazorMinimalExample2
{
    public class Foo
    {
        public byte[]? ImageAsByteArray { get; set; }

        public Foo(byte[] stuff)
        {
            this.ImageAsByteArray = stuff;
        }

        public void CleanUp()
        {
            if (this.ImageAsByteArray != null)
            {
                this.ImageAsByteArray = null;
            }
        }
    }
}
Share edited Mar 18 at 1:21 Zhi Lv 22k1 gold badge27 silver badges37 bronze badges asked Mar 10 at 8:13 DanielDaniel 5522 silver badges16 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 2

This is normal behaviour. You are pre-rendering so you everything loads twice.

I'm assuming you are adding @rendermode @(new InteractiveServerRenderMode(prerender:false)) to the page. It won't work as you've already set pre-rendering as true in App.razor.

If you want to disable pre-rendering globally change it in App.razor:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />  
    <link href="https://fonts.googleapis/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
    <link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />  
    <link rel="icon" type="image/ico" href="favicon.ico" />
    <HeadOutlet @rendermode="new InteractiveServerRenderMode(prerender:false)" />
</head>

<body>
    <Routes @rendermode="new InteractiveServerRenderMode(prerender:false)" />
    <script src="_framework/blazor.web.js"></script>
    <script src="_content/MudBlazor/MudBlazor.min.js"></script>
</body>

</html>
转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1744857118a270894.html

最新回复(0)