Using Blazor, you can build an interactive web application using C#. In this article, I will show you how to create a simple but blazing fast blog using Blazor WebAssembly, Tailwind CSS, and Strapi. We will be using Strapi, the leading open-source headless CMS, to store our posts and Blazor for the frontend.
Prerequisites
Before you can jump into this content, you need to have a basic understanding of the following.
- Installed the latest .NET Core SDK.
- Install Blazor project templates
- Basic knowledge of Blazor
- Basic understanding of Strapi - get started here.
- Download and install Node.js
What is Blazor?
Blazor is a web framework from Microsoft which allows creating a web application using C# and HTML. If you are a developer using C# and want to build a blazing web application, you should check out Blazor.
Accourding to Blazor's docs: “Blazor is a free and open-source web framework that enables developers to create web apps using C# and HTML. Microsoft is developing it.
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 is 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.”
Blazor applications can run directly in the browser, C# code runs in the browser with the help of webassembly or can on the server-side, i.e., client-side code runs on the server-side and communicates with the browser by sending events using SignalR. So in this article, we will use Blazor Web assembly to create a client side-blog app.
What is Strapi - A Headless CMS?
Strapi is a 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 client or GraphQL enabled frontend.
Scaffolding a Strapi project
To scaffold a new Strapi project is very simple and works precisely as installing a new frontend framework.
We are going to start by running the following commands and testing them out in our default browser.
npx create-strapi-app strapi-api --quickstart
# OR
yarn create strapi-app strapi-api --quickstart
The command above will scaffold a new Strapi project in the directory you specified.
Next, run yarn build
to build your app and yarn develop
to run the new project if it doesn't start automatically.
The last command will open a new tab with a page to register your new system admin. Go ahead and fill out the form and click on the submit button to create a new Admin.
Build the Posts collection
Next, we will create a new CollectionType that will store the details of each post.
For instance, we will create a Collection Type called posts
with fields like title
, content
, author
, and image
.
To create our first CollectionType, log into the Admin dashboard and follow these steps.
Click Collection Type Builder
on the left side of the page. Click on Create New Collection Type
still at the left side of the page and fill in Posts
as the display name.
Click on Continue
to create a new Posts
collection. That's the flexibility of Strapi.
We need to fill the Posts
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 (on it soon). Click on Continue
, and it will present you with another modal to select fields for your Collection Type.
Select Text
and fill in Title
in the Text field. Click on Add another field
and select Rich Text
for the content
and again, Click on Add another field
and select Media for the image field and finally select Text
for Author field.
After adding all the required fields, click on Save
to save the collection and click on the Posts
name on the left side.
Next, click on the Add New Posts
button to add a new post. So for this blog application, we will add a couple of posts. You can add any post of your choice and click on the Save and Publish buttons afterward.
Setting up Blazor project
We can create a Blazor project using two ways:
- Using dot CLI commands
- Using Visual Studio Editor
1. Using dot CLI commands
Open a command prompt and go to the location where you want to create your Blazor project and run the below commands:
> dotnet new blazorwasm -o StrapiBlazorBlog
> cd StrapiBlazorBlog
> dotnet run
Now open the http://localhost:5000/ to see the StrapiBlazorBlogblazor
app.
2. Using Visual Studio Editor
Open a visual studio editor, click on Create new project
, and search for Blazor
.
Select Blazor WebAssembly app
and click on the Next
button. After that, provide a project name and click on the Next
button.
After that, click on the Create
button. That's it, and you have successfully created a Blazor project.
Now to run the app, click on the IIS Express
button.
You can see the app running as below:
Building a Blog Application
Now we have created our Blazor project, so the next step is to create a blog application.
Integrating Strapi API with Blazor App
After creating the Cryptos collection successfully, 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.
To allow public access, follow these steps to enable permissions and roles in the Strapi Admin dashboard.
Click on the Settings
item on the sidebar menu, then on the Roles
item on the second sidebar menu that appears. On the right section, click on the Public
item and scroll down.
You will see all the APIs with their handlers. Click on the Select all
checkbox and click on the Save
button at the top. This setting will allow public access to all the Posts APIs in our Strapi project.
So now, to access the posts, we have to use URLs such as http://localhost:1337/posts
. In our Blazor project to store the Strapi API URL, create a new file app settings.json in the wwwroot
folder and add the below code:
{
"AppSettings": {
"STRAPI_API_URL": "http://localhost:1337/" // replace your local strapi url
}
}
Create a folder called Models
and create a class called AppSettings.cs
inside it and add the below code:
namespace StrapiBlazorBlog.Models
{
public class AppSettings
{
public string STRAPI_API_URL { get; set; }
}
}
Now open the Program.cs
file to add below code to which is required to read the data from the appsettings.json
file anywhere in the application.
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using StrapiBlazorBlog.Models;
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace StrapiBlazorBlog
{
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();
}
public static void ConfigureServices(IServiceCollection services)
{
// Example of loading a configuration as configuration isn't available yet at this stage.
services.AddSingleton(provider =>
{
var config = provider.GetService<IConfiguration>();
return config.GetSection("App").Get<AppSettings>();
});
}
}
}
So we have set up the integration with Strapi API with the Blazor app. Now the next step is to create a component for our blog application.
Display all blogs on the home page
We are using Tailwind CSS to style our awesome blog. So open the index.html
file and add below CDN:
<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
Create a class called Post.cs
with the same property in our Strapi posts collection.
namespace StrapiBlazorBlog.Models
{
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public string Author { get; set; }
public Image Image { get; set; }
}
public class Image
{
public string Url { get; set; }
}
}
Now open Pages/inde.razor
file and add below code to show all the posts fetch from Strapi into our client app:
@page "/"
@inject HttpClient Http
@using Microsoft.Extensions.Configuration;
@using Models
@inject IConfiguration Configuration
@if (allPosts == null)
{
<p><em>Loading...</em></p>
}
else
{
<section class="text-gray-600 body-font">
<div class="container px-5 py-4 mx-auto">
<div class="text-center mb-20">
<h1 class="sm:text-3xl text-2xl font-medium title-font text-gray-900 mb-4">Strapi Blazor Blog App</h1>
<p class="text-base leading-relaxed xl:w-2/4 lg:w-3/4 mx-auto text-gray-500s">The perfect blog application starter build using leading open source headless CSM called Strapi and Blazor.</p>
<div class="flex mt-6 justify-center">
<div class="w-16 h-1 rounded-full bg-indigo-500 inline-flex"></div>
</div>
</div>
<div class="flex flex-wrap -m-4">
@foreach (var post in allPosts)
{
<div class="xl:w-1/4 md:w-1/2 p-4">
<div class="bg-gray-100 p-6 rounded-lg">
<img class="h-40 rounded w-full object-cover object-center mb-6" src="@post.Image.Url" alt="content">
<h2 class="text-lg text-gray-900 font-medium title-font mb-4">@post.Title</h2>
<NavLink href="@($"post/{post.Id.ToString()}")">
<a class="text-indigo-500 inline-flex items-center">
Read More
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-4 h-4 ml-2" viewBox="0 0 24 24">
<path d="M5 12h14M12 5l7 7-7 7"></path>
</svg>
</a>
</NavLink>
</div>
</div>
}
</div>
</div>
</section>
}
@code {
private Post[] allPosts = null;
public string strapi_api_url;
protected override async Task OnInitializedAsync()
{
strapi_api_url = Configuration["AppSettings:STRAPI_API_URL"];
var url = "{STRAPI_API_URL}/posts";
allPosts = await Http.GetFromJsonAsync<Post[]>(url.Replace("{STRAPI_API_URL}", strapi_api_url));
if (allPosts != null && allPosts.Length >0)
{
foreach(var post in allPosts)
{
post.Image.Url = strapi_api_url + post.Image.Url;
}
}
}
}
Update the Shared/NavMenu.razor
file to remove extra menu from sidebar.
<header class="text-gray-600 body-font">
<div class="container mx-auto flex flex-wrap p-5 flex-col md:flex-row items-center">
<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">
<img src="/blazor_strapi_logo.png" alt="logo" style="height:60px" />
<span class="ml-3 text-3xl">StrapiBlazorBlog</span>
</a>
</div>
</header>
Update MainLayout.razor
file as below:
@inherits LayoutComponentBase
<div>
<NavMenu />
<div>
@Body
</div>
</div>
Now run the application and see the output as below:
Wow 👌👌 We have now displayed all our posts on the home page successfully.
Display a single blog post
So next part is when we click on the Read more
button from each post, we have to display details of the particular post. So we will create a new page called PostDetails.razor
under the Pages folder and below code:
@page "/post/{Id}"
@inject HttpClient Http
@inject NavigationManager NavigationManager
@using System.Text.Json.Serialization
@using Microsoft.Extensions.Configuration;
@using Models
@inject IConfiguration Configuration
@if (postDetails == null)
{
<p><em>Loading...</em></p>
}
else
{
<section class="text-gray-700 body-font">
<div class="container mx-auto flex px-5 pb-24 items-center justify-center flex-col">
<h1 class="title-font sm:text-4xl text-3xl mb-4 font-medium text-gray-900">@postDetails.Title</h1>
<img class=" mb-10 object-cover object-center rounded" alt="hero" src="@postDetails.Image.Url" style="height:400px;width:900px">
<div class=" w-full">
<div class="mb-8 leading-relaxed">@((MarkupString)postDetails.Content)</div>
</div>
<div class="p-2 w-full">
<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>
</div>
</div>
</section>
}
@code {
[Parameter] public string Id { get; set; }
private Post postDetails = null;
public string strapi_api_url;
protected override async Task OnInitializedAsync()
{
strapi_api_url = Configuration["AppSettings:STRAPI_API_URL"];
var url = "{STRAPI_API_URL}/posts/{Id}";
url = url.Replace("{STRAPI_API_URL}", strapi_api_url);
url = url.Replace("{Id}", Id);
postDetails = await Http.GetFromJsonAsync<Post>(url);
if (postDetails != null)
{
postDetails.Image.Url = strapi_api_url + postDetails.Image.Url;
}
}
private void NavigateToIndexComponent()
{
NavigationManager.NavigateTo("");
}
}
Now rerun the app and click on the Read More
button from any post, and you will see details of that post.
Deployment
Now we have our Strapi backend API and our Blazor frontend app. So we will deploy strapi to Heroku and the Blazor app to Netlify. To deploy Starpi API on Heroku, check out this article.
We can now deploy our Blazor application on any hosting platform. We are deploying our app on Netlify using Github Actions.
- First, create a repo in GitHub and commit your code to that repository.
- Login to Netlify and create a new site.
- We need a Personal Access Token and Site Id to deploy our app to Netlify. So Go to Profile and generate a Personal Access Token.
Go to a new site created in Netlify and navigate to site details and copy the AppId.
Go to repository settings → Click on Secrets → add the above two secrets.
The next step is to create a Github action. So click on Actions and then select New Workflow and select the .NET Core template. After that, add the below code to the yml
file.
name: .NET
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Publish Blazor webassembly using dotnet
#create Blazor WebAssembly dist output folder in the project directory
run: dotnet publish -c Release --no-build -o publishoutput
- name: Publish generated Blazor webassembly to Netlify
uses: netlify/actions/cli@master #uses Netlify Cli actions
env: # These are the environment variables added in GitHub Secrets for this repo
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
with:
args: deploy --dir=publishoutput/wwwroot --prod #push this folder to Netlify
secrets: '["NETLIFY_AUTH_TOKEN", "NETLIFY_SITE_ID"]'
After deployment you can see the site as live.
Conclusion
This article demonstrated how to build a simple blog application using Blazor for frontend and Strapi as the Backend. Strapi has lots of integration with other frameworks, so please check out Strapi blog for more information.
Let me know you have any suggestions and what you will be building with the knowledge.