Toast Notifications In Blazor Web Assembly App Using C#

Introduction

Ever wonder how we can show user-friendly notification in blazer when a record is updated/saved like we used to do in JavaScript. In this article, we will create fully functional toast notifications for our Blazor web assembly application. By the end of this article, you'll be able to show different toasts depending on the level of importance (information, success, warning, and error). All the coding would only be done in c#.

Prerequisites

This article assumes you have a basic working knowledge of Blazor web assembly and .NET Core.

If you are new to Blazor read my previous article on creating a fully functional application in Blazor web assembly with Add/Edit/Delete operations.

The link for both the articles is mentioned below,

  1. Blazor Web Assembly 3.2 Add/Edit/Delete Fully Functional Application - Part One
  2. Blazor Web Assembly 3.2 Add/Edit/Delete Fully Functional Application - Part 2

Through this article, we will cover the following topics,

  1. Creating Toast notification service and registering the service.
  2. Creating common components Toast notification.
  3. Integrating the toast component inside our existing Employee Blazor app.

Output

Employee Home Page.

Info notification would be showed when all the employees have been loaded.

Toast Notifications In Blazor Web Assembly App Using C#

Success notification would be displayed when employee information is updated or if any new employee has been added.

Toast Notifications In Blazor Web Assembly App Using C#

Toast Notifications In Blazor Web Assembly App Using C#

Implementation

Solution Structure

Employee.Client project

This is a Blazor Web Assembly Project and all the client-side code will reside in this project.

This will include the below items,

  1. Blazor components
  2. Razor pages
  3. Client-side css libraries and Master Layout 
  4. Services (Services are used to call .NET Core API)

EmployeePortal.Server

This is the ASP.NET Core project. All our APIs and repositories will reside in this project.

It will also contain all the necessary configurations to connect to the SQL server.

EmployeePortal.Shared 

This project will include data models and it will be shared by our client and server projects.

We would first build the required Toast Service.

The first thing is we would create an enum called ToastLevel inside the services folder.

public enum ToastLevel {
    Info,
    Success,
    Warning,
    Error
}

Here we have 4 different types of toast.

As per requirement, we can call the required toast level.

Now we will create a new class called ToastService.

The toast service will bind any component that issues a toast with a toast component that displays the toast.

The ShowToast method takes the message that needs to be displayed along with the level of toast as parameters.

The service has two events, OnShow and OnHide, and a timer, Countdown. Our toast component will subscribe to the events and use them to show and hide. The timer is used internally by the service and is set at 5 seconds. When it elapses it invokes the OnHide event,

public class ToastService: IDisposable {
    public event Action < string, ToastLevel > OnShow;
    public event Action OnHide;
    private Timer Countdown;
    public void ShowToast(string message, ToastLevel level) {
        OnShow?.Invoke(message, level);
        StartCountdown();
    }
    private void StartCountdown() {
        SetCountdown();
        if (Countdown.Enabled) {
            Countdown.Stop();
            Countdown.Start();
        } else {
            Countdown.Start();
        }
    }
    private void SetCountdown() {
        if (Countdown == null) {
            Countdown = new System.Timers.Timer(10000);
            Countdown.Elapsed += HideToast;
            Countdown.AutoReset = false;
        }
    }
    private void HideToast(object source, ElapsedEventArgs args) {
        OnHide?.Invoke();
    }
    public void Dispose() {
        Countdown?.Dispose();
    }
}

Toast Notifications In Blazor Web Assembly App Using C#

Building Toast component 

The toast component will work with the service to display toast on the screen or in UI.

Base class for logic - Toast.razor.cs

We inherit from the ComponentBase class so Blazor knows that this is a component.

public partial class ToastBase: ComponentBase, IDisposable {
    [Inject] ToastService ToastService {
        get;
        set;
    }
    protected string Heading {
        get;
        set;
    }
    protected string Message {
        get;
        set;
    }
    protected bool IsVisible {
        get;
        set;
    }
    protected string BackgroundCssClass {
        get;
        set;
    }
    protected string IconCssClass {
        get;
        set;
    }
    protected override void OnInitialized() {
        ToastService.OnShow += ShowToast;
        ToastService.OnHide += HideToast;
    }
    private void ShowToast(string message, ToastLevel level) {
        BuildToastSettings(level, message);
        IsVisible = true;
        StateHasChanged();
    }
    private void HideToast() {
        IsVisible = false;
        StateHasChanged();
    }
    private void BuildToastSettings(ToastLevel level, string message) {
        switch (level) {
            case ToastLevel.Info:
                BackgroundCssClass = "bg-info";
                IconCssClass = "info";
                Heading = "Info";
                break;
            case ToastLevel.Success:
                BackgroundCssClass = "bg-success";
                IconCssClass = "check";
                Heading = "Success";
                break;
            case ToastLevel.Warning:
                BackgroundCssClass = "bg-warning";
                IconCssClass = "exclamation";
                Heading = "Warning";
                break;
            case ToastLevel.Error:
                BackgroundCssClass = "bg-danger";
                IconCssClass = "times";
                Heading = "Error";
                break;
        }
        Message = message;
    }
    public void Dispose() {
        ToastService.OnShow -= ShowToast;
    }
}

e are injecting the ToastService into the component.

In the OnInitialized event we're wiring up the events we defined in the ToastService to handlers in the component.

We have the event handlers, ShowToast and HideToastShowToast takes the message and the toast level and passes them to BuildToastSettings. This then sets various CSS class names, the heading, and the message. The IsVisible property is then set on the component and StateHasChanged is called. HideToast just sets IsVisible to false and calls StateHasChanged.

Razor markup - Toast.razor

<div class="toast @(IsVisible ? "toast-visible" : null) @BackgroundCssClass">
    <div class="toast-icon">
        <i class="fa fa-@IconCssClass" aria-hidden="true"></i>
    </div>
    <div class="toast-body">
        <h5>@Heading</h5>
        <p>@Message</p>
    </div>
</div>

Add the following CSS in app.css folder,

.toast {
    display: none;
    padding: 1.5 rem;
    color: #fff;
    z - index: 1;
    position: absolute;
    width: 25 rem;
    top: 2 rem;
    border - radius: 1 rem;
    left: 50 % ;
}.toast - icon {
    display: flex;
    flex - direction: column;
    justify - content: center;
    padding: 0 1 rem;
    font - size: 2.5 rem;
}.toast - body {
    display: flex;
    flex - direction: column;
    flex: 1;
    padding - left: 1 rem;
}.toast - body p {
    margin - bottom: 0;
}.toast - visible {
    display: flex;
    flex - direction: row;
    animation: fadein 1.5 s;
}
@keyframes fadein {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}

Now we need to register our ToastService in Program.cs of EmployeePortal.Client project,

public static async Task Main(string[] args) {
    var builder = WebAssemblyHostBuilder.CreateDefault(args);
    builder.RootComponents.Add < App > ("app");
    //builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
    builder.Services.AddHttpClient < IEmployeeDataService, EmployeeDataService > (client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));
    builder.Services.AddScoped < ToastService > ();
    await builder.Build().RunAsync();
}

Register the ToastService in Startup.cs of EmployeePortal.Server Project,

public void ConfigureServices(IServiceCollection services) {
    services.AddDbContext < AppDbContext > (options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    services.AddControllersWithViews();
    services.AddRazorPages();
    services.AddScoped < IEmployeeRepository, EmployeeRepository > ();
    services.AddScoped < ToastService > ();
    SpreadsheetInfo.SetLicense("FREE-LIMITED-KEY");
}

Add the toast component to the main layout,

@inherits LayoutComponentBase
@using EmployeePortal.Client.Components;

<div class="sidebar">
    <NavMenu />
</div>

<ToastBase></ToastBase>
<div class="main">
    <div class="top-row px-4">
        <a href="http://blazor.net" target="_blank" class="ml-md-auto">About</a>
    </div>

    <div class="content px-4">
        @Body
    </div>
</div>

Link to FontAwesome in the head tag of Index.html in EmployeePortal.Client project,

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>EmployeePortal</title>
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/app.css" rel="stylesheet" />
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" integrity="sha384-gfdkjb5BdAXd+lj+gudLWI+BXq4IuLW5IT+brZEZsLFm++aCMlF1V92rMkPaX4PP" crossorigin="anonymous">
</head>

Run the application and we are good to go.

When the employees are loaded on the home screen we would see the info notification.

When we edit any employee and the save button is clicked success notification would be displayed.

Summary

Through this article, we have learned how to create and use toast notifications for Blazor web assembly projects hosted in .NET Core using C#.

Thanks a lot for reading. I hope you liked this article. Please share your valuable suggestions and feedback. Write in the comment box in case you have any questions. Have a good day!