An Early Exploration of Blazor
My first exposure to Blazor was prior to it having a name. In late 2017 I watched a recording of Steve Sanderson's NDC Oslo 2017 presentation Web Apps can’t really do that, can they? He discussed four emerging web technologies being supported by the major browser manufacturers. One of those technologies was Web Assembly (WASM). In Steve's WASM demo he explored using ASP.NET Razor technology directly in the browser by compiling C# to Web Assembly using and open-source C# to C++ compiler. It was quite impressive and people's head's exploded, mine included. Shortly afterwards I discovered that Microsoft had initiated the experimental project "Blazor". Since then there's been a dearth of excitement. I finally decided to pull down bits and give Blazor as spin. For me that excitement became infectious.
Getting Started
Blog posts and code snippets are plentiful for installing and setting up Blazor. The official Get Started page covers the basics so I won't duplicate that here. A note to Windows users who routinely make use of both Visual Studio (VS) and the dotnet CLI, be sure to install the latest packages for both. You'd think that the VS install would subsume the dotnet CLI but in my experience that has not been the case.
After you have the Blazor SDK installed you'll find new Blazor templates in both VS (new project Web -> ASP.NET Core Web Application) and the dotnet CLI (dotnet new
). Newly available project types are:
Blazor (hosted in ASP.NET server)
- ASP.NET project which provides a Web API to a dependent Blazor client application.Blazor Library
- .NET Standard library project which aids in interfacing with JavaScript components.Blazor (Server-side in ASP.NET Core)
- ASP.NET project which hosts both service and client applications providing real-time client-side HTML to the browser using SignalR.Blazor (standalone)
- .NET Standard project which produces only the client-side Blazor, i.e. WASM.
In this exploration of Blazor I utilized the Blazor (standalone)
project template to create a browser client which had feature parity with my Vue.js Stupid Todo client project. The result is the Blazor Stupid Todo client project project.
Coding with Blazor
Anyone familiar with ASP.NET Razor syntax will feel relatively at home working with Blazor. I've heard Daniel Roth say "Blazor is Razor in the browser" and that's essentially correct. The syntax used is almost identical but with Blazor page rendering occurs directly in the browser. This eliminates the need for a round-trip to the server for such rendering. With Blazor it's become a possibility that .NET developers will soon be able to build browser applications rivaling those created with JavaScript frameworks such as Angular and React.
At this point development patterns for Blazor are in their infancy and Microsoft's best (only) sample application is Flight Finder. Flight Finder makes use of a singleton instance of the class AppState
to handle various application concerns. To me their use of the AppState
class is reminiscent of a ViewModel in the Model/View/ViewModel (MVVM) pattern. The MVVM pattern has historically been applied to XAML frameworks (WPF, Xamarin, Silverlight) but to me it seems like it may be a reasonable fit with Blazor as well. I decided to explore this idea further.
A partial (and simplified) implementation of the MVVM pattern in Blazor applied to the Stupid Todo application has a Model (Todo.cs), View (Todo.cshtml) and ViewModel (TodoViewModel.cs).
Todo.cs (Model)
public class Todo
{
public string Description { get; set; }
public bool Done { get; set; }
public Guid Id { get; set; }
}
Todo.cshtml (View)
@inject TodoViewModel ViewModel
<div>
<button onclick=@(async () => await ViewModel.CheckDoneAsync())>Complete</i></button>
<input type="text" bind=@ViewModel.Todo.Description />
<button onclick=@(async () => await ViewModel.SaveAsync())>Save</button>
</div>
@functions
{
[Parameter]
private Todo SourceTodo { get; set; }
protected override void OnInit()
{
ViewModel.Load(SourceTodo);
}
}
TodoViewModel.cs (ViewModel)
public class TodoViewModel
{
public TodoViewModel(HttpClient httpClient)
{
HttpClient = httpClient;
}
public async Task CheckDoneAsync()
{
Todo.Done = true;
await SaveAsync();
}
public void Load(Todo todo)
{
Todo = todo;
}
public async Task SaveAsync()
{
var response = await HttpClient.PutAsync($"https://stupidtodo-api.azurewebsites.net/api/{Todo.Id}, Todo);
}
public Todo Todo { get; set; }
private readonly HttpClient HttpClient;
}
In the ConfigureServices
method of Startup.cs we wire up the needed dependencies.
services.AddSingleton<TodoViewModel>()
.AddSingleton<HttpClient>(new HttpClient());
The Todo component can then be leveraged in parent component as a simple element in the .cshtml.
<Todo SourceTodo="@SelectedTodo" />
In this way the parent component can create a rendered Todo (Model) by passing an instance of a Todo to the child component as a Parameter
. The OnInit
of method of the child View component calls the ViewModel's Load
method passing it the View's Parameter
Todo. All bindings in the View reference the ViewModel and everything just works. Excellent!
One caveat, two-way bindings in Blazor work fairly well even now but binding updates for inputs fire on leave of the input, not on its change. Steve Sanderson has said the solution will be to utilize bind-value-oninput
instead of bind
in the .cshtml but as of 0.6.0 that path is non-functional.
Conclusions
As of this post Blazor is roughly a year old and the current latest version of is 0.6.0. Already there are dozens of excellent articles, blog posts and videos on the technology. Enthusiasm in the .NET community is very high and Blazor looks to have the momentum to move towards production. At the moment Blazor is as rough as you might expect a pre-release framework to be. You'll encounter missing features and nagging tooling issues with any significant development effort you undertake. That said, what Blazor has accomplished in its relatively short existence is extremely impressive. Since these explorations I've found myself pondering whether or not I'll ever voluntarily create a JavaScript client again. That's fairly ironic considering my last post Vue.js where I sing that framework's praises.
Future
Several years ago I posted How HTML5 destroyed my CSLA dream. For quite some time I've been contemplating a new post along the lines of "How Microsoft Rescued my CSLA dream". My plan had been to discuss how Xamarin and the future release of XMAL Standard could potentially restore my dream of writing end-to-end, multi-layered and multi-tiered applications using a single set of semantics (language). Until now I've been under the assumption that XAML would serve as the client-side markup in this new landscape. Blazor has me considering a whole new set of possibilities and I'm pretty excited about the potential.
References
- Blazor, Blazor home
- Stupid Todo Blazor, Blazor branch of the StupidTodo exploratory application's source code repository
- Web Apps can’t really do that, can they?, Steve Sanderson, NDC Oslo 2017, video
- CSLA running on Blazor, Rockford Lhotka, blog post
- Blazor: Modern Web development with .NET and WebAssembly, Daniel Roth, .NET Conf 2018, video
- Stupid Todo Client, Blazor, live instance of the Blazor Stupid Todo client
- Stupid Todo Client, Vue.js, live instance of the Vue.js Stupid Todo client