0

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:

Template in Visual Studio

Settings while creating project

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;
            }
        }
    }
}

1 Answer 1

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.com/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>
Sign up to request clarification or add additional context in comments.

3 Comments

Hello MrC, thanks for your response. With your solution, I achieve that on other two pages (B, C (not shown here)), the data is no longer fetched twice. One of them also displays images. However, the page in question here (A), which is mentioned in the code above, still loads the data and images twice (OnInitializedAsync is called twice). But yes, it's already better than before.
However, this only happens on the very first call of the page in question.
[Polite] ??? I can't see how it can. I've built a project based on your code (without loading the images), and it loaded once. There must be something you aren't showing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.