Lets start with a sample Razor component that renders the UI:

Component.razor

				
					<div class="table"
    <table cellpadding="0" cellspacing="0">
    <tr>
        <th>Forename</th>
        <th>Surname</th>
        <th>Username</th>
    </tr>
    @foreach (var user in Users)
    {
            <tr>
                <td>@user.Forename</td>
                <td>@user.Surname</td>
                <td>@user.Username</td>
            </tr>
    }
    </table>
</div>
				
			

Lets look at the ‘code behind’ (ooof I’m old) AKA a partial class that represents the logic of the component (view)

Component.razor.cs

				
					public partial class Component
{

    private string _url = String.Empty;
    
    IEnumerable<UserModel> Users { get; set; }
    
    //The Configuration object needs to be injected via dependency injection
    protected async override void OnInitializedAsync()
    {
        _url = Configuration.AllClientSettings().BaseServiceURI;
    
        Users = (await http.CreateClient("ClientSettings").GetFromJsonAsync<List<UserModel>>($"{_URL}/api/lookup/User"))
            .OrderBy(t => t.Username)
            .ToList();

}
				
			

Looks pretty normal right?

The main issue is the way the method OnInitializedAsync() executes in Blazor. It actually executes TWICE, sort of confusing but there is a good reason!

A few things are going on here:

  • Component.razor is initially rendered statically as part of the page, whilst async methods execute in the background.
  • Now we’re awaiting the Users IEnumerable<UserModel>, this data may not be accessible on the initial page render since it’s a task that needs to be awaited.
  • Once the browser has rendered the component the OnInitializedAsync() method is executed again.

Guess what happens when you try to enumerate an IEnumerable on the first render? It’s null (possibly) due to the nature of asynchronous programming, hence the error!

How to fix this behavior?

The solution is pretty simple, wait for the IEnumerable to be available.

				
					@if(Users is not null)
{
    foreach (var user in Users)
    {
        <tr>
            <td>@user.Forename</td>
            <td>@user.Surname</td>
            <td>@user.Username</td>
        </tr>
    }
}
else
{
    <b>Hold tight... loading.</b>
}
				
			

What's the good reason for this?

The reason for the OnInitalizedAsync() method executing twice is to allow developers to insert a loading message or load certain static assets before all the razor components are rendered, especially if they’re populated via asynchronous methods. This way the user knows something is happening and they’re waiting for the data/page to load.

Read more here

Hope this helps, I've fallen victim to this myself!

Leave a Reply

Your email address will not be published. Required fields are marked *

Post comment

Want to learn more?