This will be a multipart series on using Blazor in different ways. I'm going to show you how you can create a Blazor WebAssembly (WASM) project and share that code across a static web app, WPF and MAUI. I'm also going to show you how you can build and deploy the static app to Azure using a yaml Azure DevOps pipeline. Additionally, I will demonstrate how you can use Azure B2C to authenticate a static web app, WPF and MAUI project to the same tenant.
In Part 1 (you are here), I'm going to outline the project and introduce Blazor.
You can find the complete code on my Blog Examples repo on GitHub .
Introductions
Most of the browsers in use these days support a high level of compatibility with new specs, so that isn’t much of a concern anymore. If you do any web development, you probably keep up with one or more JavaScript development frameworks. Even before the rise of popular frameworks, depending on how old you are, you most likely used tools like jQuery, knockout, and so on. The biggest problem with web development these days centers around JavaScript. Following the ebbs and flows of the framework of the week gets tiring. I, personally, wish that we could start over with a TypeScript and SASS like languages and not try to hack and graft things that we should have years ago.
Take a look at this chart from The State of JavaScript. Like with many things, I think the usage of some of these frameworks is probably inflated based on who backs them. Facebook and Microsoft make use of React. Svelte is picking up usage where Angular has been on a steady decline for the past several years despite version 15 being released a few months ago.
What is Blazor?
Blazor was initial released back in 2018 as an experiment from within Microsoft. When it was first introduced, I said, “This is the future of SPA in for dotnet shops”. Look what it offers, a mostly C# experience for web developers. Of course, we have to learn the nuances of Blazor and how it works, but we benefit greatly from the experiences we already have creating C# backends. An HTML button clicks can call a C# function in a Razor component, we can use (most) standard Razor syntax just like an MVC application of yore. Blazor is now a first class citizen in dotnet land and is baked in to the framework.
If you create a new project in Rider or Visual Studio, you’ll be present with the choice between Blazor Server or Blazor WebAssembly (or WASM). We’re going to focus on the WebAssembly version today, but the main difference is that the server app will do server side rending and communicate with the client by using SignalR vs. WebAssembly that downloads the client and runs a dotnet runtime directly in the browser.
That’s both exciting and sort of terrifying at the same time. We won’t get into much of that today because I think that’s a full post on its own.
The basic web project is just Razor, CSS and an index HTML file. Any calls to a controller, API or state changes happen using JS interop where Blazor handles the communication between the front-end DOM and our C# code.
With a Blazor project in hand, we can publish the project and the output is a static website. This is basically what we’d have if we decided to use React or Angular; the main difference is that our output also contains DLLs.
We can also publish this Blazor project (or any static content) to Azure Static Web Apps, which was released for GA in 2021. This isn’t your dad’s static web apps using specially configured Azure Blob storage, this is an actual Azure service you can stand up and deploy to. I should note that the Azure DevOps task is still in preview and the CI/CD process is a bit clunky at the moment.
Sample Project
For this example, I copied a Bootstrap chat app template and did some tweaking to make it work for this demo. It’s not fully functional, but does allow us to log in with a user and then chat as if we were in a direct message style conversation.
Here's what our solution structure looks like.
Let's break this project structure down a bit, just so you know where the pieces are.
API
From the top, we have an API project. For the demo, I have a single SignalR hub for the chat. It does include an authentication mechanism for Azure B2C. I will also show how to use authorization and policies on a minimal API and compare that to a standard API controller. In the web project, I'll show how to make API calls from Blazor to these endpoints.
MSAL
The B2C process for native apps is significantly different compared to the web project. I've collected and created some common components that both WPF and MAUI can share to log in a user using B2C. I've also created a token provider interface that allows the web and native projects to provide a token for the downstream API (the API project in this case). One of the interesting discoveries I found while building this out is how to "inject" (and I use "inject" loosely) a different Blazor view depending on what project is rendering the view.
Maui and WPF
Both of these projects use a hybrid approach. For Windows, they have a nearly identical process. Both reference the Shared and MSAL projects and mostly just hoist the Blazor frontend. I won't be covering the other native apps that Maui supports other than Windows.
Shared
This project is the star of the show. All three of the hosting projects (Web, Maui, WPF) reference this project and the bulk of the Blazor code lives here. I'll show you how you can set up this shared approach and how to deal with different requirements each project type might have.
Web
This is a standalone WASM (WebAssembly) Blazor project. There are a few web-specific items to take care of, like authentication and how to get a token for our API calls. Much like the Maui and WPF, it references the Shared project for most of the Blazor work.
Get ready!
I'm really looking forward to diving in to this project and showing you the things I've learned. You can be on the lookout for the rest of the series. Each part of the series will focus on one of the projects and how they fit together.
As we go along, if you have any questions, please leave a comment and I will do my best to answer!
Comments
You can also comment directly on GitHub.