Why Use Blazor?
The biggest question with any new technology is if it is worthwhile to use in your project, especially in a fast-moving environment like web development where tried and true frameworks already exist. As mentioned previously, using C# for your client application means that your libraries can be shared between your server and client-side projects. No more maintaining duplicate models or rewriting the same logic across two different languages. If you have an API written in C#, then it is likely you already have some parts of your code base that will be useful in getting a web application off the ground. Additionally, if you have worked with Angular apps in the past, some of the concepts and interfaces within Blazor apps will be familiar.
Depending on your situation, Blazor offers two models: WebAssembly and Server. In the server model, the server is responsible for rendering the components. When visiting the page, the client browser is sent a small file that uses SignalR to communicate with the server. The browser will send the server any events that occur, and the server will send back changes to the page. In this case, the browser has much less work it needs to do and will be less performance intensive on the user’s computer. However, since all the interaction is network based, a poor connection or an overwhelmed server can cause visible delays to the clients.
In the WebAssembly version, everything runs directly in the browser. Code is compiled like any other .NET application. The difference is that those files are then sent to the browser along with a WebAssembly version of the .NET runtime – there is no required server infrastructure. When a Blazor WebAssembly project is compiled, the result is a folder of files that make up a static website. The collection of files can be hosted anywhere that can serve static websites, such as an Amazon S3 bucket. There is no need to stand up a server or spin up an instance in Azure for the purpose of serving the application. While this does require more work from the client’s machine, it offers additional flexibility in how the application is hosted and utilized. In fact, Blazor WebAssembly applications can be set up as a progressive web app, allowing them to behave like a desktop application and enabling features like offline use, push notifications, and automatic background updates. This blog post will walk through an example of a Blazor WebAssembly project.
What is WebAssembly?
Recent versions of Visual Studio 2019 come with templates for both WebAssembly and server-side Blazor applications. When you create a new solution with the WebAssembly template, the base project will contain a sample application to show off some of the basic concepts of Blazor.
Like other .NET web apps, Program.cs is the entry point to the application. Components that your application will route to, or have a URL for, go in the Pages folder. Reusable components that will be on multiple pages, rather than a page itself, will go inside the Shared folder. The wwwroot folder holds your CSS files, images, and index.html file. For each request to the app, the index.html file is rendered. This specifies the root element “App” where the application will be inserted into the page. The root element can be defined in Program.cs.
Interacting with the Page
Let’s look at one of the pages included within the default app, the counter page. This page is an example of using C# for basic client-side logic to handle an event and updating the HTML accordingly. When first loaded, the current count will read 0. Each time the button is clicked, the number will increase by 1.
- Keep a variable to store the number of times the button has been clicked
- Get a reference to the button element and the paragraph element used to display the current count
- Add an event handler to the button with a callback function to increase the counter variable
- Update the text within the paragraph element with the current value of the counter
What does this look like within a Blazor component?
Blazor takes this one step further and lets you create dynamic web pages running either in the browser (through WebAssembly) or running on the server and sending updates to the client (through SignalR).
A minor detail on the component is the first line: @page “/counter.” This is found on full page components (not on the components that are designed to be nested in a page) and declares the route that will bring this component up. In this case, adding “/counter” to the root of the website address pulls up the counter page.
Injecting Services and Calling an API
The Counter page shows us how to interact with the user interface, respond to events, and perform some simple logic all in the client’s browser. In a real application, however, it is rare for a page not to require some sort of outside information. Since we are working with a WebAssembly project, this data will likely be retrieved through a call to an API. To use a service such as an HTTP client from within a component, the service needs to be registered at startup and then injected into the components that wish to use it. The weather forecast page in the demo app uses an injected service to retrieve weather information as JSON data and creates a table with that information.
First off, let’s look at the HTML for this page:
If the list “forecasts” is null, the text “Loading” will appear (as seen in the first image). Otherwise, a table will be created with a row for each individual forecast in the list. At the top, we again have the @page directive to specify the route for this page. The line below that is the directive used for injecting a service into a component so it can be referenced from within the component’s code block. In this case, we are injecting an instance of the HttpClient class and naming it HTTP.
The C# section of the weather forecasts page defines the WeatherForecast class and creates a variable to hold an array of WeatherForecasts. This component overrides a function called OnInitializedAsync to make the request for weather data using the HttpClient object we injected earlier. OnInitializedAsync is called when the component is ready to start. By overriding it, we can add additional logic that, once completed, will cause the component to refresh. This is how the page originally shows “Loading” but switches to showing a table once the call to GetJsonAsync is completed and returns data.
To inject a service, register it as a dependency in Program.cs. The HttpClient class has its own method for registering it, but generic functions exist to allow you to add your own classes to the collection of injectable services.
Next, inject the JSRuntime into your component. We will be modifying the counter page, so we will add this to the top of counter.razor.
Then, update the IncrementCount function in the component:
Blazor is a new technology that has quickly grown in popularity. It is something that feels familiar to web developers who have worked in the .NET ecosystem or have used frameworks like Angular. Being able to use all your existing C# code from within the browser and leverage the strengths of WebAssembly is an exciting prospect that will lead to new and interesting solutions for web-based applications.
Tallan is well versed in several aspects of web development. To get started with a project or learn more about our solutions, click here.