Using reference objects in Blazor server-side

 May 26, 2019


This post covers a preview-release of Blazor (preview5). I'm not sure if the behvaior described below is expected or a bug.

My example builds on the reference TODO-sample project found here and is part of this tutorial.

After looking at the sample, you might decide to replace the string newTodo with TodoItem todoInstance and bind the todoInstance.Title to the <input>-tag:

@page "/todo"

<h1>Todo (@todos.Count(todo => !todo.IsDone))</h1>

<ul>
    @foreach (var todo in todos)
    {
        <li>
            <input type="checkbox" bind="@todo.IsDone" />
            <input bind="@todo.Title" />
        </li>
    }
</ul>

<input placeholder="Something todo" bind="@todoInstance.Title" />
<button onclick="@AddTodo">Add todo</button>

@functions {
    private IList<TodoItem> todos = new List<TodoItem>();

    // Create an instance of our model to bind to the "new todo form".
    private TodoItem todoInstance = new TodoItem();

    private void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(todoInstance.Title))
        {
            todos.Add(todoInstance);
        }
    }
}

Everthing compiles and you run the app. Your first item gets added no problem. But, adding a second-item or editing an existing TodoItem changes all the todos 😕.

My knowledge of Blazor's internals is miniscule. However, adding a constructor to TodoItem confirms it is only called once during the page's session. Similarly, overriding OnInitAsync confirms this is also only called once. Going to a different page and then coming back or refreshing the page resets everything.

What it looks like

Screenshot showing Blazor behavior of reference objects in a list

My takeaway

Blazor server-side is not as stateless as originally thought (maybe that's the whole idea). Therefore, the same behaviors a dev. would implement for either an API or MVC project won't work here. In my sample, either create a new instance of TodoItem after it's been added to the collection or use a set of properties and create a new TodoItem-instance once adding to the collection. The latter approach would also require "resetting" each property so the form clears. 🤔