The Nightmare Before Blazor
Boys and girls of every age
Wouldn’t you like to see something strange?
Come with me and you will see
This, C# in WebAssembly
This is Blazor, this is Blazor
C# in my browser, what a sight
This is Blazor, C# devs in WebAssembly
C# in my browser, what a sight
This post is part of the 2019 C# Advent. Check out all the amazing posts here.
What better way to celebrate this C# Advent on a Friday, the 13th, than to talk about the nightmare that is web development. Devs have more ways than ever to write applications for the web. And now, into the vast wasteland of web development, rides Blazor.
Over the last few years, WebAssembly has arisen as a new means of writing websites. First introduced in 2015, WebAssembly is a set of low-level binary instructions in partnership between Google, Microsoft, Mozilla and others that now run in all modern web browsers. Just as most programming languages use various means to convert their code into binary instructions that a local operating system can understand and execute, these languages can now be converted into the WebAssembly instruction set that all modern browsers can understand and execute. This code can be written in any number of languages, including Rust, C++, Java, and a dozen others. And now, entering into this foray of binary in the browser, comes the C# implementation, known as Blazor.
The biggest question most people have about WebAssembly is what does it mean for JavaScript. The short answer is: absolutely nothing. Most implementations include some form of JavaScript interop process that allows developers to call JavaScript functions from their other code and call their other code from JavaScript as if they were running together, which they basically are.
There are two big benefits to WebAssembly, at least initially. The first is being able to reuse code that you may have already developed, such as business layer logic, calculation functions and so forth, and that files are in binary format. And the second is that the files are pre-compiled transferred in binary format. This minimizes the network bandwidth that is used to transfer the files to the browser for execution.
Overview of Blazor
Blazor itself comes in two different flavors. The first flavor is server-side Blazor, now called Blazor Server. The other is client-side Blazor, now called Blazor WebAssembly. Both versions are being released along with the releases of .NET Core 3.x. Blazor Server is in full release and fully supported for production applications. Blazor WebAssembly is still in preview and should be released some time in 2020.
So what’s the difference between the two versions? Well, they are exactly as their names imply. Blazor Server keeps all of your .NET code on the web server. All that gets downloaded with the web page is a fairly small piece of JavaScript that sets up the connections between client and server. When the client browser calls a function in the server side .NET code, a call is made to the server, the code runs and the result is downloaded to the browser. The biggest benefits of Blazor Server include extremely quick app startup times, minimal client footprint, and the ability to implement all of the server capabilities that .NET can provide any other application. Blazor Server is the version you should choose if you want fast startup times, the smallest client footprint, you need access to some of the server APIs or you need to keep your .NET code hidden or protected. On the downside, it requires a lot more communication between client and server, basically maintaining a constant connection to the server and passing a call to the server for every client interaction. As a result, it has the potential for higher latency for user interactions, and cannot run in an offline mode.
It should be noted that Blazor Server is not an actual WebAssembly implementation, as the code is running on the server and not running the WebAssembly instructions in the browser. However, the C# code and Razor components are written in the same manner as Blazor WebAssembly, so the two versions are generally always discussed together.
Blazor WebAssembly, on the other hand, downloads all of your .NET code to the browser, along with the .NET WebAssembly runtime that allows it to run in WebAssembly. As such, the initial download and app launch can be slow and the browser memory footprint is much larger. Also, this version is a subset of instructions and doesn’t have access to any of the server-side API functionality that a full .NET Core implementation would be able to use without calling a server-side API of some kind. On the plus side, Blazor WebAssembly can run entirely on the browser, can run in offline mode, and minimizes your network traffic (after the initial download).
At present, the other big difference is that Blazor Server can be debugged in the same manner as any other .NET application in Visual Studio. The tools for debugging Blazor WebAssembly, on the other hand, are not in place yet. Debugging Blazor WebAssembly is currently an extremely difficult and frustrating experience. The tools just don’t exist yet to do this well. This is one of the reasons Blazor WebAssembly is still in preview. The other is that they are continuing to work on minimizing the download footprint of the code, trying to reduce that initial delay that comes from downloading the application for the first time.
Getting Started
To get started, you need need to be running the latest version of Visual Studio 2019 Preview and have installed the latest version of .NET Core 3.x SDK Preview. While the Preview versions aren’t required for Blazor Server, they are required for Blazor WebAssembly since it’s still in preview. You should also install the Blazor WebAssembly templates for Visual Studio. This will also gives you access to the new tooling for WebAssembly debugging as it becomes available. Further instructions on getting set up are available on the Microsoft Docs website, so I won’t go over them again.
You also need to have an understanding of Razor pages and components. This is the method used to implement web pages that implement Blazor code. If you’re like me and that’s something you haven’t played around with much prior to delving into Blazor, you can get a fantastic overview and knowledge pump on the Microsoft Docs site as well. It’s a good place to get a grasp on some of the basic concepts around Razor pages, components, imports, and so forth. I actually found that having a background in both C# and JavaScript SPA apps such as Angular, React and Vue made it fairly easy to get up to speed on the Razor pages concepts, but YMMV.
Razor Components
Much like most JavaScript SPA implementations, the core of Blazor apps are built around components. A component is built of a combination of HTML and C# in a Razor component file. It’s a lot like writing a C# class file, but with the UI/UX thrown in as well. Once you’ve defined your component, then you can drop it into any other Razor component or page by just using the component’s name like an HTML tag.
Sample Component Welcome.cshtml file in the Components folder to define the component
<div>
<span>@welcomeText</span>
</div>
@code{
private string welcomeText = "Hello there, visitor!";
}
Note that Razor pages/components files contain a mix of HTML and C# code. The bits and pieces of C# are generally set off using the @ symbol. Small bits, such as the variable @welcomeText in the tag are just prefixed by the @. Larger sections are set off in @code {} or @function {} blocks, which are use to mark larger sections of C# code.
Sample Razor Page index.cshtml implementing the Welcome component
//As with C# classes, we need to import our namespace
@using Components
<h1>This is my page</h1>
<Welcome />
That’s an overly simple example, but it demonstrates the concept of Razor components. Define your component in a Razor file, then drop it in somewhere to use it. Simple. But generally not all that useful by itself. Most components will need some data in order to actually be useful. So next let’s look at getting some data into our component.
Working With Data
We’ll get to how data gets passed into the component in a minute. First, a quick demo on how the data can get used by the component. Variables can be dropped into the HTML block anywhere by just prefixing the variable name with the @ symbol, like so:
<div class="someclass">@Title</div>
@code{
public string Title {get;set;}
}
Here, we’ve got a string variable called Title and we’re dropping it’s value into our
<div class="someclass">@Title</div>
@code{
[Parameter]
public string Title {get;set;}
}
So, first we’ve added the Parameter attribute to our variable. This now lets us pass in the starting value to the variable when we intialize the component in the parent page or component, like so:
<h1>Hello, there</h1>
<MyComponent Title="This is my page" />
So, first we’ve added the Parameter attribute to our variable. This now lets us pass in the starting value to the variable when we intialize the component in the parent page or component, like so:
<h1>Hello, there</h1>
<MyComponent Title="This is my page" />
This will render our <h1>
header, followed by a with our text “This is my page” in it. Again, for those familiar with JavaScript SPA frameworks, this should be familiar space. But this only gives us a static display of our value in the HTML. Let’s look next at data binding and how to tie variable values to our HTML controls.
<input value="@CurrentValue" />
@code{
public string CurrentValue {get;set;} = "Hello";
}
So we’ve tied our <input>
to our variable CurrentValue and set it’s initial value to “Hello”. Right? Well, sort of. While this will correctly set our initial value, if we were to then change what’s in the box, our variable value would not be changed. This is what’s known as one-way binding. What we need is a two-way binding to our variable. For that we use the @bind syntax.
<input @bind="CurrentValue" />
@code{
public string CurrentValue {get;set;} = "Hello";
}
Because we’ve used the @bind syntax instead of just referencing our variable, we have now introduced two-way binding between our HTML control and our variable. Changing the <input>
box now updates the value of our variable CurrentValue.
What’s more, this process also allows us to perform some basic validation just by changing the variable type. Let’s say instead of a string, our CurrentValue variable is now an int and set our default value to 42.
<input @bind="CurrentValue" />
@code{
public int CurrentValue {get;set;} = 42;
}
If we now try to enter a value of 55.234 or “Frank”, the value will not be changed. It will remain at the value of 42 because those other values can’t be put into an int variable type.
One of the benefits of @bind is that it works across components. If you want to have the value change in a child component when it changes in the parent, you can use the following syntax to create that relationship by using @bind-parametername.
<ChildComponent @bind-Title @bind-FirstName />
This will enable the child component to reflect changes to values of variables in the parent component.
Calling Functions
We’ve got some variable and binding basics, so let’s turn our attention to calling functions. Let’s look at a simple example of a function in a component.
What's your name? <input @bind="InputText" />
<button >Say Hello</button>
<span>@OutputText</span>
@code{
public string InputText {get;set;}
public string OutputText {get;set;}
public void HelloText(){
OutputText = "Hello, " + InputText;
}
}
So how do we tie our to our HelloText function? Similar to our @bind syntax, we have a syntax for the onclick function that will wire it to our C# function. And it is……. @onclick!
<button @onclick="HelloText">Say Hello</button>
Simple and easy to use. And the list of supported functions is quite extensive. Just about all of the DOM on{EVENT} calls are supported: onclick, onsubmit, onchange, onmouseover, oncut, ondrag, and on and on and on. :)
One of the other scenarios that are supported is the ability to call a function or EventCallback in the parent from a child component. You just pass the function name into the child the same as you would any other parameter.
<h1>Parent component</h1>
<ChildComponent Title="Child Panel TItle" OnClick="@ShowMessage" />
@code{
public void ShowMessage(MouseEventArgs args){
//Do something
}
}
Component Class Libraries
One other great thing about Razor components is that you can group them into class libraries, much like you would with other C# classes. This will let you reuse components across projects, such as if you want to start with a Razor Server project and later change to a Razor WebAssembly application.
Using them in a Razor page is simple. Just import the library with a @using directive on your Razor page or component, just as you would with any class library.
Fin
There is so much more that you can do with Blazor. I’ve only just touched on the very surface of what’s included. For more information be sure to check out the Blazor website and the Microsoft Docs site.