Blazor Code Behinds and Base Classes

Blazor.png

Due to the nature of the Blazor architecture, you can be limited in how you use class inheritance. This is a quick guide to how you can create a common base library.

  1. Why Use A Base Class?

Often, you will find yourself copying a pasting the same boilerplate code in every (or a lot!) of your pages. These may be:

  • References

  • Common routines, such as authentication or initialising functions

  • Common functions and helpers

If you find you are constantly copying and pasting code whenever you create a new page, this is a candidate for a Base Class.

2. What Does A 'Normal' Blazor Page Look Like?

When you create a new Blazor page, you get a single file that blends both Razor syntax, and C# code. Whilst this works really well for simple pages, when things get complex, its nice to have some separation.

@page "/fetchdata"

@using TMA.Data
@inject WeatherForecastService ForecastService

<h1>Weather forecast</h1>

<p>This component demonstrates fetching data from a service.</p>

@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var forecast in forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private WeatherForecast[] forecasts;

    protected override async Task OnInitializedAsync()
    {
        forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
    }
}

3. Separating Concerns

Separating the Razor from the C#

The first thing I'm inclined to do is separate the Razor syntax from the C# code. To do this:

Create a new class with the same name as the Razor page (FetchData), and change the class scope line to 'partial'

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace TMA.Pages
{
    public partial class FetchData
    {
    
    }
}

You can now move code from the Razor page to this new 'code behind page', or even have it in both places:

New Code Behind Partial Class:

using Microsoft.AspNetCore.Components;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TMA.Data;

namespace TMA.Pages
{
    public partial class FetchData
    {
        [Inject]
        WeatherForecastService ForecastService { get; set; }


        private WeatherForecast[] forecasts;

        protected override async Task OnInitializedAsync()
        {
            forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
        }
    }
}

New Razor Page:

<@page "/fetchdata"
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from a service.</p>
@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var forecast in forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

We've now seperated our code into Razor and C#, however we still don't have a base class we can re-use on any page that contains our common elements.

Say (for example), that every page will use the WeatherForecastService. Rather than injecting this every time, you can set up a base class that contains the references and injection code.

4. Creating a Reusable Base Class

Create a new public class. By convention, you should have the word 'Base' in the name. We will call ours WeatherBase.cs. This class needs to inherit from ComponentBase.

You can then copy all code required to inject the WeatherForecastService (and any other references, functions, variables, etc.). This is a very simple example, however you can see how powerful these base classes can be. Especially if any of your common code needs to change!

Note: Rather than using 'private' to scope variables, you will need to use 'protected' as seen below for the int counter variable.

Base Class (Reusable)

using Microsoft.AspNetCore.Components;
using TMA.Data;

namespace TMA.Pages
{
    public class WeatherBase : ComponentBase
    {
        [Inject]
        public WeatherForecastService forecastService { get; set; }

        protected int counter = 1;
    }
}

Implementing (um, or Inheriting) the Base Class In Your Pages

To use this base class in your page, you just need to add the following razor code @inherits WeatherBase

All functions and variables are now available to both your Razor and Partial Class code.

New Razor Page:

@page "/fetchdata"
@inherits WeatherBase

<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from a service. Counter @counter</p>
@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var forecast in forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

New Partial Class Code Behind

using System;
using System.Threading.Tasks;
using TMA.Data;

namespace TMA.Pages
{
    public partial class FetchData
    {
        private WeatherForecast[] forecasts;

        protected override async Task OnInitializedAsync()
        {
            forecasts = await forecastService.GetForecastAsync(DateTime.Now);
            counter += 1;
        }
    }
}

Summary

We first talked about the structure of a standard Blazor Page. We then looked at how you can seperate the code from the Razor syntax by using a partial class, and then how you can strip out common code into a base class that can be inherited by any page.

Thanks to Split HTML And C# Code In Blazor Using Either Partial Class Or ComponentBase Class (learmoreseekmore.com) article for some of the base material for this post.

Previous
Previous

RipteqSQL Introduction