This article has been updated to v4 by Mark Munyaka.
Learn how to create a simple but blazing-fast blog app using Blazor WebAssembly, Tailwind CSS, and Strapi. You will use Strapi, the leading open-source headless CMS, to store your posts and Blazor to build your front-end.
Before you can jump into this content, you need to have a basic understanding of the following:
The following software should be installed:
For a full rundown of all the requirements needed to run a Strapi app, check out the Hardware and Software requirements.
Blazor is a web framework from Microsoft which allows you to create a web application using C# and HTML. If you are a developer using C# and want to build a blazing-fast web application, you should check out Blazor.
Blazor is a free, open-source web framework that enables developers to create web apps using C# and HTML.
Blazor lets you build interactive web UIs using C# instead of JavaScript. Blazor apps are composed of reusable web UI components implemented using C#, HTML, and CSS.
Both client and server code are written in C#, allowing you to share code and libraries. Blazor can run your client-side C# code directly in the browser using WebAssembly. Because it's real .NET running on WebAssembly, you can re-use code and libraries from server-side parts of your application.
In this article, you will use Blazor Web Assembly to build the client side of the blog app.
Strapi is the leading open-source headless CMS based on Node.js to develop and manage content using Restful APIs and GraphQL.
With Strapi, we can scaffold our API faster and consume the content via APIs using any HTTP RESTful client or GraphQL-enabled front-end.
Open up your terminal and create an empty project directory to store your project. This folder will serve as the root folder. The front-end and back-end code will be stored in subdirectories. I will name my project directory purplerhino.
$ mkdir purplerhino
Change the directory to the project directory purplerhino.
$ cd purplerhino
Enable source control for your project by initializing a git repository.
/purplerhino $ git init
Create a Strapi app.
/purplerhino $ npx create-strapi-app backend --quickstart
The command above will scaffold a new Strapi project in a directory named backend
. The quickstart
flag sets up your Strapi app with an SQLite database.
After successful installation, the Strapi app starts automatically. Open the Strapi Admin Registration interface from your web browser at localhost:1337/admin. Create the admin user for your Strapi application and click Let's Start.
Next, we will create a content-type that will store the details of each post.
We will create the content-type named posts
containing the following fields: title
, content
, author
, and image
.
We need to fill the Post collection with lots of post data. You can achieve this in two ways: using the Admin UI and using Strapi-generated API.
We will use the Admin UI to create a post.
Text
and fill in title
in the Text field.+ Add another field
, select Rich Text
, and name it content
.+ Add another field
and select Media
field and name it image
.+ Add another field
once again and select Text
field and name it author
.After successfully creating the Posts collection, it's time to allow public access to the collection because access will be denied if we try to access it with our public HTTP client.
We will need to transform the JSON from the API request to work with our Blazor front-end. To do that, we will use Transformer by @ComfortablyCoding.
Ctrl + C
on your keyboard./purplerhino/backend $ npm install strapi-plugin-transformer
plugins.js
file in the config
folder to configure your plugin./purplerhino/backend $ touch config/plugins.js
./config/plugins.js
.1module.exports = ({ env }) => ({
2 'transformer': {
3 enabled: true,
4 config: {
5 prefix: '/api/',
6 responseTransforms: {
7 removeAttributesKey: true,
8 removeDataKey: true,
9 }
10 }
11 },
12});
This configuration will provide an API response that will work with the setup of your Blazor front-end app.
1/purplerhino/backend $ yarn build
2/purplerhino/backend $ yarn develop
Let's set up our Blazor front-end app using the .NET command-line interface (CLI) to execute commands.
Open up your terminal and run the following commands:
1/purplerhino $ dotnet new blazorwasm -o frontend
2/purplerhino $ cd frontend
3/purplerhino/frontend $ dotnet run
Open localhost:5024 in your browser to see the Blazor frontend
app.
Your Blazor project is now set; the next step is to create the blog front-end.
To access the posts, you will have to use the Strapi API URL, which is localhost:1337/api.
In the frontend/wwwroot
folder, create a file called appsettings.json
to store the Strapi API URL.
/purplerhino/frontend $ touch wwwroot/appsettings.json
Add the following code to appsettings.json
:
1{
2 "AppSettings": {
3 "STRAPI_API_URL": "http://localhost:1337"
4 }
5}
Create a folder called Models
and create a file called AppSettings.cs
inside it.
1/purplerhino/frontend $ mkdir Models
2/purplerhino/frontend $ touch Models/AppSettings.cs
Add the following code to Models/AppSettings.cs
:
1// ./Models/AppSettings.cs
2
3namespace frontend.Models
4{
5 public class AppSettings
6 {
7 public string STRAPI_API_URL { get; set; }
8 }
9}
Now open the Program.cs
file and the code below. This is required to read the data from the appsettings.json
file from anywhere in the application.
1// ./Program.cs
2
3using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
4using Microsoft.Extensions.Configuration;
5using Microsoft.Extensions.DependencyInjection;
6using frontend.Models;
7using System;
8using System.Net.Http;
9using System.Threading.Tasks;
10
11namespace frontend
12{
13 public class Program
14 {
15 public static async Task Main(string[] args)
16 {
17 var builder = WebAssemblyHostBuilder.CreateDefault(args);
18 builder.RootComponents.Add<App>("#app");
19
20 builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
21
22 await builder.Build().RunAsync();
23 }
24
25 public static void ConfigureServices(IServiceCollection services)
26 {
27 // Example of loading a configuration as configuration isn't available yet at this stage.
28 services.AddSingleton(provider =>
29 {
30 var config = provider.GetService<IConfiguration>();
31 return config.GetSection("App").Get<AppSettings>();
32 });
33 }
34 }
35}
You have just set up the integration of the Strapi API with the Blazor app. The next step is to create a component for your blog application.
We use Tailwind CSS to style our awesome blog. So open the index.html
file in the wwwroot
folder and add this HTML snippet within the <head></head>
section.
<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
Now open the Pages/Index.razor
file and replace the existing code with the code below to show all the posts fetched from Strapi into your client app:
1@* ./Pages/Index.razor *@
2
3@page "/"
4@inject HttpClient Http
5@using Microsoft.Extensions.Configuration;
6@using Models
7@inject IConfiguration Configuration
8
9@if (allPosts == null)
10{
11 <p><em>Loading...</em></p>
12}
13else
14{
15 <section class="text-gray-600 body-font">
16 <div class="container px-5 py-4 mx-auto">
17 <div class="text-center mb-20">
18 <h1 class="sm:text-3xl text-2xl font-medium title-font text-gray-900 mb-4">Strapi Blazor Blog App</h1>
19 <p class="text-base leading-relaxed xl:w-2/4 lg:w-3/4 mx-auto text-gray-500s">British History - From the Anglo-Saxon era to present day Britain.</p>
20 <div class="flex mt-6 justify-center">
21 <div class="w-16 h-1 rounded-full bg-indigo-500 inline-flex"></div>
22 </div>
23 </div>
24 <div class="flex flex-wrap -m-3">
25 @foreach (var post in allPosts.data)
26 {
27 <div class="xl:w-1/4 md:w-1/2 p-4">
28 <div class="bg-gray-100 p-6 rounded-lg">
29 <img class="h-40 rounded w-full object-cover object-center mb-6" src="@post.Image.Url"
30 alt="content">
31 <h2 class="text-lg text-gray-900 font-medium title-font mb-4">@post.Title</h2>
32 <NavLink href="@($"post/{post.Id.ToString()}")">
33 <a class="text-indigo-500 inline-flex items-center">
34 Read More
35 <svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
36 stroke-width="2" class="w-4 h-4 ml-2" viewBox="0 0 24 24">
37 <path d="M5 12h14M12 5l7 7-7 7"></path>
38 </svg>
39 </a>
40 </NavLink>
41 </div>
42 </div>
43 }
44 </div>
45 </div>
46 </section>
47}
48
49
50@code {
51 private PostList allPosts = null;
52 public string strapi_api_url;
53
54 protected override async Task OnInitializedAsync()
55 {
56 strapi_api_url = Configuration["AppSettings:STRAPI_API_URL"];
57 var url = "{STRAPI_API_URL}/api/posts?populate=*";
58 allPosts = await Http.GetFromJsonAsync<PostList>(url.Replace("{STRAPI_API_URL}", strapi_api_url));
59 if (allPosts.data != null)
60 {
61 foreach (var post in allPosts.data)
62 {
63 post.Image.Url = strapi_api_url + post.Image.Url;
64 }
65 }
66 }
67
68 public class Post
69 {
70 public int Id { get; set; }
71 public string Title { get; set; }
72 public string Content { get; set; }
73 public string Author { get; set; }
74 public Image Image { get; set; }
75 }
76
77 public class Image
78 {
79 public string Url { get; set; }
80 }
81
82 public class PostList
83 {
84 public List<Post> data { get; set; }
85 }
86
87}
Here's a brief explanation of what the code does:
@page
to @inject
is a list of all libraries Index.razor
needs to use to fetch data from the Strapi API.@if (allPosts == null)
down to </section>}
is the HTML required to render the posts from the Strapi API. The @foreach
will loop through all the posts and retrieve the image
, title
, and id
of each post and display each post on its card.@code
section is C# code. Post
, Image
, and PostList
are classes that we will use to map the JSON data from the API response. allPosts
is an instance of PostList
. The JSON data from the url
will be parsed into allPosts
using the Http.GetFromJsonAsync()
function. The @foreach
loop will retrieve the URLs of each post's image.Update the Shared/NavMenu.razor
file to remove the extra menu from the sidebar. Replace the existing code with the following code:
1@* ./Shared/NavMenu.razor *@
2
3<header class="text-gray-600 body-font">
4 <div class="container mx-auto flex flex-wrap p-5 flex-col md:flex-row items-center">
5 <a class="flex order-first lg:order-none lg:w-1/5 title-font font-medium items-center text-gray-900 lg:items-center lg:justify-center mb-4 md:mb-0">
6 <img src="/blazor_strapi_logo.png" alt="logo" style="height:60px" />
7 <span class="ml-3 text-3xl">StrapiBlazorBlog</span>
8 </a>
9 </div>
10</header>
Update Shared/MainLayout.razor
file as below:
1@* ./Shared/MainLayout.razor *@
2
3@inherits LayoutComponentBase
4
5<div>
6<NavMenu />
7
8<div>
9 @Body
10</div>
11</div>
Now run the application and navigate to localhost:5024 in your browser.
Wow 👌 We successfully displayed all our posts on the home page.
We have managed to display all the posts on one page, but each post doesn't have its page, and the Read more button on the home page doesn't work too. Let's fix this.
Create a file called PostDetails.razor
in the Pages
folder.
/purplerhino/frontend $ touch Pages/PostDetails.razor
Add the following code to PostDetails.razor
:
1@* ./Pages/PostDetails.razor *@
2
3@page "/post/{Id}"
4@inject HttpClient Http
5@inject NavigationManager NavigationManager
6@using System.Text.Json.Serialization
7@using Microsoft.Extensions.Configuration;
8@using Models
9@inject IConfiguration Configuration
10
11@if (postDetails == null)
12{
13 <p><em>Loading...</em></p>
14}
15else
16{
17 <section class="text-gray-700 body-font">
18 <div class="container mx-auto flex px-5 pb-24 items-center justify-center flex-col">
19 <h1 class="title-font sm:text-4xl text-3xl mb-4 font-medium text-gray-900">@postDetails.Data.Title</h1>
20 <img class=" mb-10 object-cover object-center rounded" alt="hero" src="@postDetails.Data.Image.Url" style="height:400px;width:900px">
21 <div class=" w-full">
22 <div class="mb-8 leading-relaxed">@((MarkupString)postDetails.Data.Content)</div>
23 </div>
24 <div class="p-2 w-full">
25 <button class="flex mx-auto text-white bg-indigo-500 border-0 py-2 px-8 focus:outline-none hover:bg-indigo-600 rounded text-lg" @onclick="NavigateToIndexComponent">Back</button>
26 </div>
27 </div>
28 </section>
29}
30
31@code {
32 [Parameter] public string Id { get; set; }
33
34 private PostSingle postDetails = null;
35
36 public string strapi_api_url;
37
38 protected override async Task OnInitializedAsync()
39 {
40
41 strapi_api_url = Configuration["AppSettings:STRAPI_API_URL"];
42 var url = "{STRAPI_API_URL}/api/posts/{Id}?populate=*";
43 url = url.Replace("{STRAPI_API_URL}", strapi_api_url);
44 url = url.Replace("{Id}", Id);
45 postDetails = await Http.GetFromJsonAsync<PostSingle>(url);
46
47 if (postDetails.Data != null)
48 {
49 postDetails.Data.Image.Url = strapi_api_url + postDetails.Data.Image.Url;
50 }
51 }
52
53 private void NavigateToIndexComponent()
54 {
55 NavigationManager.NavigateTo("");
56 }
57
58 public class PostSingle
59 {
60 public Data Data { get; set; }
61 }
62 public class Data
63 {
64 public int Id { get; set; }
65 public string Title { get; set; }
66 public string Content { get; set; }
67 public string Author { get; set; }
68 public Image Image { get; set; }
69 }
70
71 public class Image
72 {
73 public string Url { get; set; }
74 }
75
76}
Here's a brief explanation of what the code does.
@page "/post/{Id}"
refers to the URL of the page to be rendered based on the Id of the post@if (postDetaills == null)
to </section>
is the markup for rendering the page and uses the post's title
, image
and content
retrieved from the Strapi API.@code
section contains the classes to populate the data from the Strapi API just like in Index.razor
, except that the API request is for a single post, not all the posts.Now rerun the app and click on the Read More
button for any post. You will see the full blog post on its own page.
Here’s a short video demo of how the blog will look like:
The Strapi backend API and our Blazor frontend app working, and the next step is to deploy your application. Among the options available, you can deploy Strapi API on Heroku. To deploy a Blazor WebAssembly app on Netlify, check out "How to Deploy a Blazor App on Netlify".
This article demonstrated how to build a simple blog application using Blazor as the front-end and Strapi as the back-end. Strapi has lots of integration with other frameworks. Check out the Strapi blog for more interesting tutorials showcasing Strapi's capabilities.
You can download the source code implementation from Github. Let me know if you have any comments, queries, or suggestions. The Strapi Team is always available to assist you.