Welcome to my Blazing Pizza Store! ;)

Here’s how I built my Blazing Pizza Store with the awesome .NET Blazor framework… Oh and let me share a quick recap of the awesome knowledge I gained from it!

So recently I embarked on a journey to learn the latest awesomeness of .NET sphere, the Blazor framework, just so that I would be able to leverage some good old C# into the Web and get rid of having to code in JavaScript! :3 lol

Well I just love learning new stuff and building kickass stuff with .NET so obviously I’m loving it! I set up this repository up in my github just to encourage myself to follow up on every possible tutorial and learn of this Blazor awesomeness top to bottom.

Blazor-Playground repo:
UdaraAlwis/Blazor-Playground

That right there is where I’ll be continuously posting of my little self-learning journey into Blazor Framework.

However I came across this lengthy tutorial article through one of my colleagues, published by the .NET Foundation github, called the blazor-workshop!

BlazingPizza, the Blazor Workshop!

So this tutorial features building a Blazor Web Application from ground up for a Online Pizza Ordering shop, called Blazing Pizza! pretty catchy eh! 😉

Before this I had followed up on a few tutorials and video guides for self-learning Blazor bits, but man I gotta tell you this is the most comprehensive tutorial so far…

.NET Foundation, Blazor-workshop repo:
aka.ms/blazorworkshop

It features a step by step guidance on building a complete Blazor Web Application utilizing all the awesomeness it can offer, and it truly elevated my knowledge to another level! Hence I decided to share some of my learning experience with you guys…

Oh and I have published my finished project solution in github as well…

Udara’s Blazing Pizza Store:
UdaraAlwis/Blazor-Playground/BlazingPizzaApp

Published Web App:
https://blazingpizzaappudara.azurewebsites.net/

And I hosted the finished project in Azure as well! 😉

Feel free to try it out! 😀

Prerequisites?!

As for as some pre-requisites, of course you need some basic practice of HTML and CSS, having an idea of how these Web elements comes in together to form web pages and all, would definitely be helpful.

Its better to have a good overall knowledge of .NET programming with C#, as far as the language goes. Even though we’re going to be developing Blazor, it would some advantage if you had previous experience with ASP.NET, as I’ve seen similar elements.

I would not suggest you use this tutorial as your first ever Blazor try out, hence they provide us a pre-set up solution, with the basic Blazor Client UI and Backend API. So it could get confusing or overwhelming to figure it out at once. So its best if you first try out a few simpler demos from Microsoft docs, or a simple follow along Youtube tutorial, there are plenty out there.

Get started with ASP.NET Core Blazor
Build your first Blazor app

Then once you’re familiar with the project solution structure and all, you’re good to go!

Some Tips…

So I started off by copying their starter solution into my own repository, and from there I started following through the steps in the tutorial.

I would read through a given step, understand the objective of it and type the code all by myself. Sometimes I would even try to memorize the syntax and type it on accordingly to the understand I’ve got in that step.

It’s better not to copy paste the code to your own solution directly, I found typing the code by yourself is more effective in the learning curve, so that you get to familiarize with every little detail specially in the syntax.

Take plenty of intervals, for better productivity. This is a long tutorial, but it could be completed in a day, but its best to take some intervals in between to help clear up the exhaustion.

If a certain step is not clear, then you should complete it anyways, then move to the next step, and come back to it later until you get a clear understanding. Some times reading through a given step several times helped me understand better.

Learning journey!

This project BlazingPizza solution is a Blazor Client Side project hosted with ASP.NET, therefore it will be utilizing awesomeness of Web Assembly during the run time on client browser.

Components, Components everywhere!

Component-izing everything is the key in Blazor! Each page should be comprised of Component blocks, which has their own responsibilities separated, increasing the reusability of our code.

Layouts are also built as Components, where you inherit them component from LayoutComponentBase, such as in MainLayout.razor

@inherits LayoutComponentBase

They have a Body parameter where you will be placing the content in.

Dependency Injection!

@inject directive let’s your inject objects into your page that are registered in the DI container, such as,

@page "/"
@inject HttpClient HttpClient

Also you need to make sure those objects are properly registered in the DI, which is located in Program.cs

builder.Services.AddTransient(...);
...
builder.Services.AddScoped(...);

Parameterizing Components…

@code {
    [Parameter] public Pizza Pizza { get; set; }
}

[Parameter] attribute defines a parameters of a Component

Handle HTML Events..

You can specify which HTML event you want to handle using the corresponding HTML attribute in that and then specify the C# delegate you want called..

<li 
    @onclick="@(() => Console.WriteLine(special.Name))" .... >
</li>

Two way binding…

@bind directive lets you two-way bind a value between C# and HTML elements, also with @bind:event you can specify which element triggers the value change as follows…

<input type="range" min="@Pizza.MinimumSize" 
max="@Pizza.MaximumSize" step="1" 
@bind="Pizza.Size" @bind:event="oninput" />

Here we bind the value of <input> element to Pizza.Size, but it will change the value on the oninput event.

Component Event Handling!

You can define Events in a Component by creating EventCallback properties. Then Parent Component can subscribe to those events of a Child Component.

[Parameter] 
public EventCallback OnCancel { get; set; }

Then this Child Component’s elements can trigger it,

<button class="btn btn-secondary mr-auto" 
@onclick="OnCancel">Cancel</button>

And parents who are subscribed can get notified on up on it.

<ConfigurePizzaDialog Pizza="configuringPizza" 
OnCancel="CancelConfigurePizzaDialog" />

CancelConfigurePizzaDialog will be pointing to a method in C#.

Url Parameters into Components!

You can pass parameters into Components from the routing Url, as you see here in the @page directive we define the route along with the [Parameter] with the same name.

@page "/myorders/{orderId:int}"

@code {
    [Parameter] public int OrderId { get; set; }
}

Other parameter types such as string, bool, datetime and guid are supported.

Force Update UI!

Forcefully re-render a component by calling StateHasChanged() method which is built in function in Blazor.

This is handy when you don’t know exactly if the data has changed but wants to make sure its reflected in the UI.

Programmatic Navigation..

NavigationManager allows you to programmatically Navigate in your Blazor app.

@inject NavigationManager NavigationManager
...
...
NavigationManager.NavigateTo($"myorders/{newOrderId}");

AppState pattern…

Save the state of an object in the DI container,

builder.Services.AddScoped<OrderState>();

Saving the state will help you retain data during page navigation across components.

Data Validation!

Using Annotations on the data model you can easily implement Server side data validation. You can start by adding DataAnnotations validation rules onto the model classes.

public class Address
{
	public int Id { get; set; }

	[Required, MaxLength(100)]
	public string Name { get; set; }
	
	[Required(ErrorMessage = "Yo we need for sure!"), MaxLength(50)]
	public string City { get; set; }

	...	
}

This will be picked up by [ApiController] endpoints for validation in Server side.

Then for Client side validation, using EditForm component you can easily implement form validation in Blazor.

<div class="main">
    <EditForm Model="OrderState.Order.DeliveryAddress"  OnValidSubmit="PlaceOrder">
        
		... 

        <button class="checkout-button btn btn-warning" @onclick="PlaceOrder">
            Place order
        </button>
		
		<DataAnnotationsValidator />
		<ValidationSummary />
    </EditForm>
</div>

The above ValidationSummary, displays a basic list of errors, if you need something nicer then its better to decorate those <input> data fields with ValidationMessage instead.

<div class="form-field">
    <label>Name:</label>
    <div>
        <input @bind="Address.Name" />
        <ValidationMessage For="@(() => Address.Name)" />
    </div>
</div>

For better UX use Blazor built in components, such as InputText, InputCheckbox, InputDate, InputSelect, etc…

<div class="form-field">
    <label>Name:</label>
    <div>
        <InputText @bind-Value="Address.Name" />
        <ValidationMessage For="@(() => Address.Name)" />
    </div>
</div>

Authorization!

For enforcing Authorization in Server side, add the [Authorize] attribute on the API Controllers, which is provided by Microsoft.AspNetCore.Authorization namespace.

[Route("orders")]
[ApiController]
[Authorize]
public class OrdersController : Controller
{
    ...
}

This will make sure all incoming calls should be Authorized.

For the Client side we use AuthenticationStateProvider, which is provided by Microsoft.AspNetCore.Components.WebAssembly.Authentication package. Then to enable the authentication services for your Blazor Client, add a call to AddApiAuthorization in Program.cs

public static async Task Main(string[] args)
{
    ....
    // Add auth services
    builder.Services.AddApiAuthorization();
    ...
}

RemoteAuthenticatorView component orchestrates the authentication flow in the Blazor Client app. So to enable this make sure to add the Authentication.razor component.

@page "/authentication/{action}"

<RemoteAuthenticatorView Action="@Action" />

@code{
    [Parameter]
    public string Action { get; set; }
}

It handles all authentication actions such as register, login, profile, and logout.

We need to maintain the Auth state across the client app and inherit into child components, so let’s use CascadingAuthenticationState that wraps the Router of app.razor

<CascadingAuthenticationState>
    <Router AppAssembly="typeof(Program).Assembly" Context="routeData">
        ...
    </Router>
</CascadingAuthenticationState>

AuthorizeView will let you control displaying of elements based on the Auth state.

<AuthorizeView>
	<Authorizing>
		...
	</Authorizing>
	<Authorized>
		...
	</Authorized>
	<NotAuthorized>
		...
	</NotAuthorized>
</AuthorizeView>

Use the IAccessTokenProvider injected to the pages for acquiring an AccessTokens whenever you need to call the API.

var tokenResult = await TokenProvider.RequestAccessToken();
if (tokenResult.TryGetToken(out var accessToken))
{
	...
}
else
{
	NavigationManager.NavigateTo(tokenResult.RedirectUrl);
}

AuthenticationStateTask lets you check programmatically if the user is logged in or not. You can use it as a [CascadingParameter] in any page, thanks to the CascadingAuthenticationState that we added earlier.

[CascadingParameter] 
public Task<AuthenticationState> AuthenticationStateTask { get; set; }

Use it to access User.Identity.IsAuthenticated for checking the User’s Auth state.

protected override async Task OnInitializedAsync()
{
	var authState = await AuthenticationStateTask;
	if (!authState.User.Identity.IsAuthenticated)
	{
		NavigationManager.NavigateTo("authentication/login?redirectUri=/checkout", true);
	}
}

AuthorizeRouteView controls the direct access to routes based on Auth state

<CascadingAuthenticationState>
    <Router AppAssembly="typeof(Program).Assembly" Context="routeData">
        <Found>
            <AuthorizeRouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)">
                <NotAuthorized>
                    ...
                </NotAuthorized>
                <Authorizing>
                    ...
                </Authorizing>
            </AuthorizeRouteView>
        </Found>
        <NotFound>
            ...
        </NotFound>
    </Router>
</CascadingAuthenticationState>

You will lose state during redirection, specially in authentication flow, but you can preserve it by implementing RemoteAuthenticationState.

public class PizzaAuthenticationState : RemoteAuthenticationState
{
    public Order Order { get; set; }
}

You need to register it in the DI Services with AddApiAuthorization<PizzaAuthenticationState>() and update the Authentication.razor accordingly by replace the RemoteAuthenticatorView with RemoteAuthenticatorViewCore set up.

@page "/authentication/{action}"

<RemoteAuthenticatorViewCore TAuthenticationState="PizzaAuthenticationState"
    AuthenticationState="RemoteAuthenticationState"
    OnLogInSucceeded="RestorePizza"
    Action="@Action" />

@code{
    ...

    public PizzaAuthenticationState RemoteAuthenticationState { get; set; } = new PizzaAuthenticationState();

    ...
}

You can use the LogOutSucceeded in Authentication component to set the page to redirect to once the user logs out.

builder.Services.AddApiAuthorization<PizzaAuthenticationState>(options =>
{
    options.AuthenticationPaths.LogOutSucceededPath = "";
});

Javascript Interop!

Use IJSRuntime to invoke JavaScript functions from C# code.

await JSRuntime.InvokeVoidAsync
("javascript.functionname", param1, param2);

var result = await JSRuntime.InvokeAsync<bool>
("javascript.functionname", param1);

You can call void methods and even await for results as shown above.

Templated Components…

Using Razor Class Library you can create your own components library for your project solution.

Templated Components can be defined as those components that accepts body content as a parameter. You can create these to increase the reusability and build truly decoupled components.

Use a parameter of type RenderFragment which is a delegate type that the runtime has special handling for, to place content inside a Templated Component.

[Parameter] 
public RenderFragment ChildContent { get; set; }

You can also add multiple RederFragment parameters in a component. We can create a generic-typed component using the @typeparam directive, to support any type of data as follows, @typeparam TItem

[Parameter] 
public RenderFragment Loading { get; set; }
[Parameter] 
public RenderFragment<TItem> Item { get; set; }

and you can set the type and pass parameter content to the generic template by,

<div class="main">
    <TemplatedList TItem="OrderWithStatus" Loader="@LoadOrders">
        <Loading>Loading...</Loading>
        <Item Context="item">
            Status: @item.StatusText
        </Item>
    </TemplatedList>
</div>

PWA bits!

Easily set up PWA features (installable, offline, push notifications) for Blazor, with service-worker.js configuration.

Simply create a service-worker.js file in your Blazor Client’s wwwroot directory, and add the ‘install’ and ‘fetch’ event listeners inside. Then to enable it add a reference of it to the index.html file, beneath the other script elements..

<script>navigator.serviceWorker.register('service-worker.js');</script>

To make your Web app installable, add the manifest.json file in wwwroot directory, which will include app set up details. Then add the reference of it inside the <head> element in index.html

<link rel="manifest" href="manifest.json" />

Setting up Push Notification, first execute the Push Notification permission request from the user through JS script and acquire the NotificationSubscription object, which will provide you the following object filled with Url, P256dh and Auth properties.

You will be passing it over to the API endpoint to save it in the DB with the UserId attached in it. Then when you need to send push notification to your User from your API backend, retrieve the NotificationSubscription object from the DB and use WebPush to execute the broadcast.

var payload = JsonSerializer.Serialize(new
{
	message,
	url = $"myorders/{order.OrderId}",
});
await webPushClient.SendNotificationAsync(pushSubscription, payload, vapidDetails);

Then to display that push notification you need to set up ‘push’ event listener in your service-worker.js and additionally to handle the user click on notification, you can set up ‘notificationclick’ event listener in there as well.

self.addEventListener('push', event => {
...

self.addEventListener('notificationclick', event => {
...

You can generate your cryptographic keys for the push notification set up at https://tools.reactpwa.com/vapid and make sure to update the publicKey in both client and server, then privateKey in server along with the subject, mailto:bingo@bingomail.bingo

Publish to Azure!

To Publish to Azure, you need to create an App Service and a Hosting Plan of Basic tier or higher. Right click on Blazor Server project node -> Publish and follow through the wizard to create your Publish profile.

Before deploying you need to set up a signing key with Azure Key Vault for the IdentityServer. So create a new Key Vault -> create new Certificate (copy the Subject value for later use) -> go to your App Service -> TLS/SSL Settings -> Private Key Certificates (.pfx) -> Import Key Vault Certificate -> Select the imported certificate and copy its thumbprint -> go to Configuration in same App Service -> Add the new key WEBSITE_LOAD_CERTIFICATES and use the thumbprint as the value -> Ok

Then update the BlazingPizza.Server appsettings.json with the Certificate Subject name you configured, “Name”: “CN=BlazingPizzaCertificateUdara”

Publish the App! you’re all done! 😉

It’s go time!

So at the end of all that awesome learning experience, I had built myself a beautiful Blazing Pizza Store web app! 😀

Woot! woot!

Update to the Tutorial…

By the time I almost finished writing this post, they seemed to have updated the tutorial a little bit for the better, such as using the BaseAddressAuthorizationMessageHandler for acquiring access tokens and moving the whole logic to a separate OrdersClient, which will increase the reusability of the code for sure! 😀

Conclusion!

This BlazingPizza workshop tutorial was one of the most comprehensive step by step guide I ever followed for learning Blazor given my last few weeks into this awesome journey. I’m not much of a Web dev fella given my extensive Mobile dev background, but I gotta say I picked up a lot about .NET Web development bits in this tutorial, not only that a complete picture of the awesomeness of Blazor framework.

I hope my humble effort of sharing the new knowledge I gained in Blazor development helps out any fellow devs out there striving to learn new stuff!

Share the love! 😀 Cheers yol!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.