Building a Marvel Hero catalog app using Blazor Server and .NET8
Introduction
At the end of 2022, as part of the Festive Tech Calendar community initiative, I provided a step-by-step instruction blog on how to build a Blazor Web Assembly app from scratch, using .NET7.
About 18 months later, a lot of things have changed in the .NET8 world, which also impacted positively new features around the Blazor Web App Framework, on both Web Assembly (Client/Browser) and Server side.
I decided to rewrite/update the steps, using the same idea for the app, but this time redeveloping it from scratch, using .NET8 and Blazor WebAssembly RenderMode. If you want to see the live coding in action, head over to https://www.scifidevcon.com, a great community initiative to celebrate the month of May, Geekiness, Developing, cloud and everything else that fits in the combination of all those topics in a virtual conference.
This app introduces Blazor .NET8 development, and more specifically how to easily create a Single Page App using HTML, CSS and API calls to an external API Service at https://developer.marvel.com
While I’ve been using Blazor .NET for about 3 years now as a hobby project, I feel like I am still learning development with .NET for the first time at age 48. Having succeeded in getting an actual app up-and-running, I wanted to continue sharing my experience, inspiring other readers (and viewers of the ScifiDevCon session) to learn coding as well. And maybe becoming a passionate Marvel Comics fan as myself.
Prerequisites
If you want to follow along and building this sample app from scratch, you need a few tools to get started:
- Visual Studio 2022 version 17.9.7 or newer, to develop the application (VSCode or other dev tools will work as well, but I’m not that familiar with those…)
- Community Edition can be downloaded for free here (Visual Studio 2022 Community Edition â Download Latest Free Version (microsoft.com))
- GitHub Account to store the application code in source control
- Sign Up for free here (https://github.com/join)
- Azure Subscription to run Azure App Service web application
- Get a Free Azure Subscription here (https://azure.microsoft.com/en-us/free/)
- Marvel Developer Account to get access to the API back-end
- Register for free at https://developer.marvel.com
Deploying your first Blazor Web Assembly app from a template
Visual Studio (and .NET) provide different Blazor templates, both as an âempty templateâ, as well as one with a functional âsample weather appâ, and both options are available for Server and Web Assembly.
With the release of .NET8 last November, the Product Group decided to simplify getting started with Blazor, using the Blazor Web App template. Actually allowing you to decide wether to use WebAssembly, Server or both, in the same project.
- Launch Visual Studio 2022, and select Create New Project
- From the list of templates, select Blazor Web App

-
Provide a name for the project, e.g. BlazorMarvel8, and store it to your local machine’s folder of choice
-
Click Next to continue the project creation wizard
-
Select .NET 8.0 (Long Term Support) as Framework version
-
Select None for authentication type
-
Select WebAssembly for Interactive Render Mode
-
Select Per Page/component for Interactivity location
-
Click Create to complete the project creation wizard and wait for the template to get deployed in the Visual Studio development environment. The Solution Explorer looks like below:

- Run the app by pressing Ctrl-F5 or select Run from the upper menu (the green arrow) and wait for the compile and build phase to complete. The web app should load successfully in a new browser window.

- Wander around the different parts of the web app to get a bit familiar with the features. In the context of .NET 8, Blazor WebAssembly projects typically consist of two separate projects: an app and an app.client. The app project is the server-side part of the Blazor application, which can serve pages or views as a Razor Pages or MVC app. The app.client project contains the client-side Blazor application that runs in the browser on a WebAssembly-based .NET runtime.
The separation of the client and server projects in the Blazor WebAssembly hosting model provides a clear separation of concerns, allowing for server-side functionality, integration with ASP.NET Core features, and flexibility in hosting and deployment options. This architecture aligns well with the server-client model and the capabilities of the ASP.NET Core framework.
For instance, Blazor WebAssembly can be standalone for simple, offline apps, but having a separate server project unlocks improved security, scalability, complex server tasks, and potential offline features, making it ideal for more elaborate and demanding applications. As your application grows or requires server-side functionality, having a separate server project provides a scalable and maintainable architecture.
This design pattern, where decoupling or loosely coupled apps are encouraged, is preferred over tightly coupled applications, especially as the complexity of the project increases.
-
Close the browser, which brings you back into the Visual Studio development environment.
-
This confirms the Blazor Server app is running as expected.
In the next section, you learn how to update the Home.razor page and add your own custom HTML-layout, CSS structure and actual runtime code.
Updating the template with your custom code
Blazor allows you to combine web page layout code (Razor pages), basically HTML and CSS, together with actual application source code (C# DotNet), in the same razor files. I canât compare it with previous development environments, but it seems to be one of the great things about Blazor â and I really like it, since itâs somewhat simplifying the structure of your application source code itself.
Another take is creating the web page layout first, and only adding logic later on. So letâs start with creating a basic web page, adding a search field and a button. All Razor Pages the app uses, are typically stored in the \Components subfolder.
-
You can chose to reuse the Home.razor sample page and continue from there, or create a new Razor Page and update the route path. To show you how Blazor Components are working, let’s define our SearchMarvel page, as a new page under the \Pages section in the Client project. Save it as SearchMarvel.razor
-
In this part, we start with adding a search field and a search button to the web page layout. Insert the following snippet of code, replacing all the current content on the page:
|
|
- This adds the necessary objects on the web page.
- And letâs run this update to see what we have for now.

-
So the layout for the search part of the app is done. Letâs move on with the design of the actual response / result items. The return from the Marvel API can be presented in a table gridview, but thatâs not that nice-looking; I remembered having physical cards as collector items as a kid, so I did some searching for a similar digital experience. Interesting enough, there is a CSS-class object âcardâ, which nicely reflects this experience. So letâs add the next snippet of code for this response layout.
-
Add the following code, below the snippet you copied earlier:
|
|
What this snippet does, is adding a âcontainerâ object, in which we create a small table view having 3 rows and 1 column. The card composition shows the Hero title on top, the Marvel Hero character details in the middle and an image of the character as well.
- Letâs run the code again to test if everything works as expected.

- Now wait, we lose quite some time on stopping the app, updating code, starting it again â so what we can do is use the new VS2022 feature called Hot Reload / if I set this to âHot Reload on Saveâ, it will dynamically update the runtime state of the app based on my edits. Letâs check it out.
- While in debugging mode, check the âflameâ icon in the menu:

- Enable the setting âHot Reload on File Saveâ.
- Edit the card-title âMarvel Hero Nameâ to âMarvel Character Nameâ and check how the app refreshes itself without needing to stop/start.

The search field is not doing anything yet, so we need to make sure â that whenever we type something in that field - it kicks of an API call to the Marvel API back-end.
- First, we need to use the bind-value parameter for this field, linking it to a search task; Update the line with the field box as follows:
|
|
add @bind-value=âwhotofindâ at the end of the line.

Ignore the errors regarding the âwhotofindâ for now. We’ll fix that in a minute.
- Next, we need to update the button code to actually pick up an action when clicking on it; this is done using the @onclick event
Add **@onclick=FindMarvel**

-
The code snippet complains about unknown attributes, which is what we need to add in the actual code section of the app page:
-
Add the following @code section below the HTML/CSS layout
|
|
- Within the curly brackets, we can use regular C# code
- Start with defining a string for the âwhotofindâ
- Followed by defining a method (task) for the FindMarvel onclick action â for now, letâs write something to the console to validate our search field is working as expected
The string âwhotofindâ refers to the search field object, where the Task âFindMarvelâ refers to the button click action. So easy said, whenever we click the button, it will pick up the string content from the search field, and send it to the Marvel API back-end. As we donât have that yet, Iâm just writing the data to the console, which is always a great test to validate the code is working as expected.

- Save the file, which will throw a warning regarding the hot reload. Since we added new actual code snippets, hot reload canât just go and recognize it. So a reload is neededâŚ

-
Select âRebuild and Apply Changesâ
-
Enter the name of a Marvel character, for example âthorâ, and notice nothing happens on the console/terminal. Why not?? Is it an error in our code, did we miss anything,…?
NO and YES :)… our code is fine, but we are missing a new .NET8 feature for Blazor apps… we need to specify the Render Mode
Note > for more details on Blazor app Render Mode, check this article I guest-authored for SitePoint a few weeks ago, explaining the different options and how to use them.
- Remember when we created the Visual Studio project, we defined the WebAssembly Render Mode. Now to make this work, there are a few more changes needed in the source code:
a) Define the InteractiveWebAssembly Render Mode in the App.razor file b) (Optionally), specify the InteractiveWebAssembly Render Mode for Pages and/or Components
So depending a bit on how much control you want, or how frequently you want to use Interactive Render mode, you would specify this in your App.razor, as a Global parameter - turning the full Blazor App into that mode. Or, if not all pages and/or components require that Render Mode, you can add the specific parameter to individual components.
In this example, I’ll show you how to use it on a ‘per page’ level, knowing that either one would be OK for this sample app.
- At the top of your SearchMarvel.razor page, after the @page line, add the following:
|
|
which tells the page/component should use the Interactive Render Mode, which “enables” the button event in our case.
- Save the changes, and run the app; enter a Marvel character name in the search field, click the Find Button and notice the search field string is shown in the console now. This is what InteractiveWebAssembly Render Mode is doing…

- I think the bare minimum app layout development is ready, so itâs time to set up the Marvel API-part of the solution in the next section.
Configuring the Marvel Developer API Backend Code interaction
- Head over to the Marvel Developer website https://developer.marvel.com and grab the necessary API information.

-
Select Create Account + Accept Terms & Conditions
-
Grab the API keys (public & private)
Public: 579a41c9eccaf70a3a09c1xxxxxxxxxxx
Private: 6362bd53a4c307c96fb27xxxxxxxxxx
-
To allow requests to come into the Marvel API back-end, you need to specify the source URL domains where the requests are coming from. Add localhost here, which is the URL you use for all testing on your development workstation. Later on, once the app runs in Azure, you need to add the Azure Service URL here as wellâŚ

- Once set up, head over to âinteractive documentationâ, and walk through the different API placeholders and keywords one can use, to show the capabilities. For the app later on, we will use the ânamestartswithâ, as it is the most easy to use â names could work, but it requires knowing the explicit name of the character, and having it correctly spelled.




- Click the âTry it outâ button. The result shows the outcome + the exact URL that was used:

-
Blazor WebAssembly doesn’t come with the HTTPClient package installed by default, which means we need to add the Nuget package for this. (Although if you want, you could also find Nuget packages that provide similar functionality), as well as specifying the necessary Service, in both the server-side and client-side project.
-
From the app.client project, select Manage Nuget Packages, and search for Microsoft.Extension.Http as package name.
.
- Once the package got installed, update the Program.cs file in the client project, by adding the following line below the “var builder = WebAssemblyHostBuilder… line:
|
|

- Next, open the Program.cs on the server-side project, and add the following line to the //Add Services to the container section:
|
|

- Next, using .NET dependency injection, create a reference to the HTTPCLient in your Blazor SearchMarvel.razor page
|
|

- As you could see from the Marvel output, they are using JSON; this means, when calling the HttpClient, we also receive a JSON object back.

-
To ‘recognize’ the data from the JSON response into our Web App, we need to link it to a data model, using a Csharp class. There’s a few different ways to do this, either creating it manual, using the Visual Studio ‘Edit - Paste Special - as JSON”, which will create the necessary Class setup for you. However, in this specific scenario, I don’t need all the details from the JSON Response (although you could definitely update the app yourself to display all the information you want, related to a Marvel Character…)
-
To help transforming a JSON Response into an actual C-Sharp Class, I often rely on a free website, https://www.jSON2CSharp.com, which allows for pasting in a JSON payload, which then gets converted to c# class structure

- In the VStudio app.client project, create a new subfolder âModelsâ, and add a new Item in there, called MarvelResult.cs

- We could copy the content from the JSON deserialize output into this class object, but for this sample, we donât need all the provided data by Marvel â so I made some changes and ended up with the core pieces of data I want, like image, name, description
The code snippet I’m using for this example, looks like follows:
|
|

- With the class in place, letâs update the SearchMarvel.razor, to make sure it recognizes the model class MarvelResult. To do this, we need to add a private MarvelResult, reflecting the data class we just created;
|
|

- As we stored the MarvelResult.cs class model in a different folder within the application source code, we also need to update our Page details, telling it to âuseâ the Models subfolder to find it. This is done using the @using statement on top of the Home.razor page:
|
|

Where now the Class gets nicely recognized

- Letâs update the Task FindMarvel, with the required code snippet to recognize the dynamic URL to connect to, as well as calling the HttpClient function. As per the Marvel API docs, we also need to integrate the api Public key into our URL search string, so we have to define the string for this first.
Btw, the full Request URL to use is visible from the Interactive Documentation page where we ran the ’try it now’ search task (https://gateway.marvel.com:443/v1/public/characters?nameStartsWith=spider&apikey=579a41c9eccaf70a3a09c1722ef6c2fc)
The updated code snippet looks like this now:
|
|
- After which we can update the Task FindMarvel as follows:
|
|

- While all the code pieces are done, note that as of .NET6, it started checking for Nullable values. This is what the green squickly lines are identifying. What this means is that the value could be equal to null, which could potentially break your application, since it expects to have a real value in there.
- I wouldnât recommend it to change, but for this little sample app, it would be totally OK to disable the nullable check. This can be done from the Properties of the Project

Render JSON Response data into HTML Layout
- Thatâs all from a code snippet perspective, where now the last piece of updates is back into the HTML Layout of the web page itself, updating the content of the card object:
- Since we most probably get an array of results back, meaning more than one, we need to go through a âfor eachâ loop; also, there might be scenarios where we are not getting back any results (like the character doesnât exist, a typo in the characterâs name,âŚ), so we will add a little validation check on that too, using an if = !null
Letâs go ahead!
- At the top of the card object (class=container), or right below the section where we defined the search button, insert the @if statement, and move the whole div section between the curly brackets, updating the fixed fields we defined earlier, with the MarvelResult class objects:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25@if (_marvelResult != null) { <div class="container"> <div class="row row-cols-1 row-cols-md-2 row-cols-lg-3"> @foreach (var result in _marvelResult.Data.Results) { <div class="col mb-4"> <div class="card"> <img src="@($"{result.Thumbnail.Path}.{result.Thumbnail.Extension}")" class="card-img-top"> <div class="card-body"> <h5 class="card-title">@result.Name</h5> <p class="card-text"> @result.Description </p> </div> </div> </div> } </div> </div> }- Run the app and see the result in action

- Thatâs it for now. Great job!
Making the cards âflipâ
Note: this part is left out of the ScifiDevCon presentation to keep the video within the expected time â what weâre doing here is integrating more CSS layout components on to a new Page in the web app, which provides a more dynamic look-and-feel to the Marvel cards we have.
While CSS can be difficult â and trust me it is â I literally googled for âflipping cards CSSâ and found a snippet of code on https://w3schools.com, and it worked almost straight awayâŚ
Here we go:
-
Letâs copy the current state of the page we have, and store it in a different page; so we grab SearchMarvel.razor and copy/paste it to FlipMarvel.razor this will allow me to also demonstrate some other Blazor features around Menu Navigation and how to use object-specific css; meaning, CSS that will only be picked up by the specific page, and not interfere with the rest of the application CSS we already have.
-
Open FlipMarvel.razor page; First thing we need to change, is the Page Routing, pointing to the â/flipâ routing directory instead of the â/â, as that one is linked to the index.razor page.

-
Go to this link: https://www.w3schools.com/howto/tryit.asp?filename=tryhow_css_flip_card
-
Select the code between the tags
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77<style> body { font-family: Arial, Helvetica, sans-serif; } .flip-card { background-color: transparent; width: 300px; height: 300px; perspective: 1000px; } .flip-card-inner { position: relative; width: 300px; height: 300px; text-align: center; transition: transform 0.6s; transform-style: preserve-3d; box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); } .flip-card:hover .flip-card-inner { transform: rotateY(180deg); } .flip-card-front, .flip-card-back { position: absolute; width: 300px; height: 300px; -webkit-backface-visibility: hidden; backface-visibility: hidden; } .flip-card-front { background-color: #bbb; color: black; } .flip-card-back { background-color: #2980b9; color: white; transform: rotateY(180deg); } </style>- and paste this under the @using section and the
section of the code you already have (Note: ignore the @using marveltake2.models in the screenshot, itâs the name of my test project)

- Next, we need to update the layout of the card item itself, in the section within the âforeachâ loop, as thatâs where the data is coming in, and getting displayed
@foreach(var result in _marvelResult.Data.Results)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33{ <div class="col mb-4"> <div class="flip-card"> <div class="flip-card-inner"> <div class="flip-card-front"> <img class="thumbnail" src="@($"{result.Thumbnail.Path}.{result.Thumbnail.Extension}")" style="width:300px;height:300px;"> </div> <div class="flip-card-back"> <h5>@result.Name</h5> <p> @result.Description </p> </div> </div> </div> </div> }What we do here is basically pointing to the different CSS-snippets for each style we want to get applied; we have the flip-card div class, next the flip-card-inner and flip-card-front. For the front, we want to use the image, so we keep the img class details as is, but change the width and height to 300px, to make sure it looks like a nice rectangular on screen.
-
Next, we add a class for the flip-card-back, where we will show the Marvel character name and description.

Thatâs all we need to have for now; so letâs have a look, by launching the app
- Since the previous page was index.razor, itâs getting loaded by design (from the index.html). so we need to update the URL to pick up the /flip page, by adding it to the end of the URL, such as https://localhost:7110?flip (note, the port number will be different on your end)

- Search for a character, and see the outcome cards:

- About the same as before, but letâs hoover over a card:
- It flips and shows the character name and description (if provided by Marvel) to the back of the card

Cool!!
- Letâs switch back to the code and add a menu item for the âflipâ page to our left-side navigation menu.
- Open the file NavMenu.razor within the Server-Side Layout folder.
- Add a new section for this menu item, by copying one from above + make minor changes to the href reference (flip) and change the Menu item word to Flip
- The icons are coming from the open iconic library, which is also referenced as part of Blazor bootstrap. Know you can change to MudBlazor, Telerik Progress or several other bootstrap frameworks to have layout-rich styles.
- Open https:://useiconic.com and find a suitable icon, for example loop-circular

1 2 3 4 5 6 7 8 9 10<div class="nav-item px-3"> <**NavLink** class="nav-link" href="flip"> <span class="oi oi-loop-circular" aria-hidden="true"></span> Flip </**NavLink**> </div>- When you run the app again, the new Menu item will appear. Given the href=âflipâ, it will redirect to the base URL (https://localhost:7110) /flip route

Since we are changing the layout a bit here, why not modify the default purple color from the Blazor template, to the well-known Marvel dark-red?
- Open MainLayout.razor
- Notice the
















