Building a Marvel Hero catalog app using Blazor Web Assembly
Introduction
This article describes all the steps on how to develop a Marvel Hero catalog app, using Blazor Web Assembly, and is a companion guide to the Festive Tech Calendar 2022 session I presented. This app introduces Blazor .NET 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
As I am learning development with .NET for the first time in 47 years, and succeeding in having an actual app up-and-running, I wanted to share my experience, inspiring other readers (and viewers of the session) to learn coding as well. And maybe becoming a passionate Marvel Comics fan as myself.
I hope you enjoy the steps, feel free to contribute to this project at petender/FestiveBlazor2022live (github.com) if you want to co-learn more Blazor stuff together with me.

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 to develop the application (VSCode or other dev tools will work as well)
- 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 Static Web Apps 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 provides Blazor Web Assembly templates, both as an âempty templateâ, as well as one with a functional âsample weather appâ. Although I wonât use a lot from the template, I like to start with the weather app sample application, as it comes with all necessary building blocks to get started.
- Launch Visual Studio 2022, and select Create New Project
- From the list of templates, select Blazor Web Assembly App

- Click Next to continue the project creation wizard
- Select .NET 7 (Standard Term Support) as Framework version
- Keep all other default settings as is

- 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. The Home button brings up the index.razor page, and can be seen as the Homepage of the app. The + Counter Page demonstrates how you can build out interaction using buttons and running a count function. The Fetch data section shows a basic outcome of an API-call to a JSON-data-structure, to publish data in a gridview.
- Close the browser, which brings you back into the Visual Studio development environment.
- This confirms the Blazor Web Assembly app is running as expected
In the next section, you learn how to update the index.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, basically HTML and CSS, together with actual application source code, 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
- You can chose to reuse the index.razor sample page and continue from there, or create a new Razor Page and update the route path. For simplicity and ease of this scenario, Iâm reusing the existing index.razor page.
- 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:
|
|
- 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:
|
|
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.
-
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:

- Those were the 2 placeholders for the Blazor code section, which can be defined within the same Razor page, a rather unique approach to Blazor code.
- Save the updates again; notice how Hot Reload is not able to refresh the changes just like that, since it is more than just a cosmetic change in HTML.

- Click Edit for now, since we will add more code to the 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 code syntax looks like this:
|
|
- 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â, which will move that to the Output console. This confirms both the bind-value property as well as the search button and corresponding action behind it is working as it should be.

-
I think the app is ready from our perspective, so itâs time to set up the Marvel API-part of the solution in the next section.
Configuring the Marvel Developer API Backend
- 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 Web Assembly already has an HTTP Client built-in, although if you want, you could also find Nuget packages that provide similar functionality â but for now, letâs stick with the built-in one. The details of this service are part of the program.cs file

- The hostenvironment points to our local development workstation, so the only thing we need to do hear is changing this Uri to the Marvel API Gateway Uri, as follows:
https://gateway.marvel.com:443/v1/public/"
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(“https://gateway.marvel.com:443/v1/public/") });

- next, relying on Blazor dependency injection, create a reference to the HTTPCLient in your Blazor index.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, which is not useful for presenting the data as such. What we need to do is deserialize the result, for which we create a class

- A useful website for helping with this, is jSON2CSharp.com, allowing you to paste in a JSON payload, which gets converted to c# class structure

- In the VStudio project, create a new folder â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 looks like follows:
|
|


- With the class in place, letâs update the code to compile the dynamic URL, instead of the fixed gateway.marvel.com one. First, we need to add a private MarvelResult, reflecting the data class we just created;
|
|


- as we stored this 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 index.razor

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 need to integrate the api Private key into our URL search string, so we have to define the string for this
|
|
- After which we can update the Task FindMarvel as follows:
|
|

- Where the url is coming from the gateway.marvel.com part in the HttpClient service definition + the dynamic url part where we specify the characters search option, the nameStartsWith, pointing at the bind-value object whotofind, and adding the MarvelapiKey string.
- While all the code pieces are done, note that .NET6 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

- 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
1 2 3 4 5@if (_marvelResult != null) { <div class="container">
- Next, define the @foreach loop for the actual card item, and update the image placeholder URL with the content from the MarvelResult JSON string (thumbnail path and extension:
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@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> }- 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 Festive Tech Calendar 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 index.razor and copy/paste it to flip.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 flip.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 Shared 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
















