.NET 8 Series has started! Join Now for FREE

19 min read

How to Integrate AdminLTE with ASP.NET Core? Detailed

#dotnet

In this article, we will learn about Integrating AdminLTE with ASP.NET Core 3.1 MVC or really any other Bootstrap based UI Frameworks completely from scratch. We will also go through about integrating Identity Authentication to our MVC Applicaiton. Also, you will gain quite a lot of practical knowledge on Views, Layouts, Partial Views, Conditional Rendering, Navigation Indicatior and much more.

You can find the source code of this demonstration at my Github.

Disclaimer : This is a pretty huge article with around 3500+ words. Do bookmark this page and continue :D

What we will learn and build?

Here are the Features included.

  • Integration with a Third Party Bootrstrap Template.
  • Clean usage and seperation of Layouts, Views and Partial Views.
  • Integration of Identity Authentication
  • Scaffolded Identity
  • Conditional Rendering
  • Login / Register / Logout and more

The need to Integrate Third-Party Bootstrap UI

If you are back-end developer like me with just OKayish skills with recreating an entire HTML / CSS / JS Template from scratch, you would probably want to look into other options that make your application look 100x more Professional. Now, there are quite a lot of options, including paid templates as well.

For this article, we will use an Open Sourced Dashboard Template that is quite popular.

Here are the advantages of integrating an already built template.

  • Proffesional UI
  • Already Tested.
  • Responsive.
  • Would have a bunch of reusable components like datatables, forms, and more so that you don’t have to re-invent the wheel.

What’s AdminLTE?

AdminLTE is an open sourced Admin Dashboard Template that is built over Bootsrap. It is packed with quite a lot of responsive and commonly used components that are very easily integrated with your webapplications.

To get a better picture, click here to see a demo of AdminLTE in action.

You may notice how premium it already looks. For now, these pages are not bound to any server side applications. They are just plain old HTML files. In this article we will integrate this UI with our ASP.NET Core MVC Application with some clean practices.

Downloading AdminLTE

AdminLTE is completely FREE to use. Follow this link to start downloading. At the time of writing this article, 3.0.5 is the latest version available. Click on the link to Source Code to download the zipped file on to your machine.

integrating-adminlte-with-aspnet-core

Exploring the Folder Structure

Once downloaded, extract the zipped file. Here you will find a bunch of folders and files. We will not have to touch each and every file, rather just a few. I will give you a brief overview on what each folder contains.

  • dist/ - This is the distribution folder that contains all the css and js files, mostly all the static files of the application. We will need to copy this folder over to wwrootfolder of our MVC Project later on.
  • pages/ - Here you get a list of all pre-made HTML files to refer to. This is quite an important section as it uses all the available components and can be helpful to check out how components are being utilized.
  • plugins/ - 3rd party JS plugins like select2, jquery, datatables, etc are contained here. We will need this folder too.
  • starter.html - Here we get a minimal setup of the HTML file. We will using this page to generate the _Layout.cshml for our ASP.NET Core MVC Application. I have attached a screenshot below.

integrating-adminlte-with-aspnet-core

Setting up ASP.NET Core MVC Project with Authentication

Let’s create a new ASP.NET Core Application with the Model-View-Controller (MVC) Template. Make sure you select the authentication mode to Individual User Accounts. This enables us to use the built in Authenication (using Microsoft Identity). I will be using Visual Studio 2019 Community.

integrating-adminlte-with-aspnet-core

Now that we have our AdminLTE files and ASP.NET Core Application ready, let’s start integrating them. Before getting started, let’s see how the default layout of ASP.NET Core work.

Understanding Layouts and Partial Views

Build and run the Application. This is the default layout that comes out of the box with ASP.NET Core 3.1 Web Applications.

integrating-adminlte-with-aspnet-core

This is how the page is split into.

  • Main Layout Page - This is the master layout defined at /Views/Shared/_Layout.cshtml
  • Navigate Panel - Within the master layout,a partial view reference is defined that calls the _LoginPartial.cshtml page.
  • Content Body - Here is where the actual content goes.

PS, ASP.NET Core uses .cshtml (Razor markup files) extension for it’s pages.

Now why this kind of seperation?

In ASP.NET Core MVC, you can generate Views (CHTML) via controllers. Imagine a real life application having multiple controllers and views. You really don’t want to define the entire HTML for each view do you? Because we already know that we will be having a site-wide common template. So what this Layout concept does is that, you define the layout cshtml just once, and add the content of each other pages dynamically within the layout page.

So, you define the entire HTML Part that essentilaty would be common throughout the application, and you seperate the dynamic content in another cshtml page. This way, we can make the application much more maintainable and reduce the size of the entire application. Get the point?

Let’s examine the file where the default layout is defined. Since we created a MVC templated application, we can find this file at ../Views/Shared/_Layout.cshtml in the solution structure. You can see that this page starts with a HTML tag. This suggests that this is an entire HTML page with all the body and head tags.

Now somewhere at line 33 or so, you would see the following.

<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>

@RenderBody is used to render the content of the child page. When you run the ASP.NET Core application, it navigates to the root of the application, that is , localhost:XXXX/Home and invokes the Index Method in the HomeController (as it is set as the default route). Let’s see what this method contains.

public IActionResult Index()
{
return View();
}

It just returns a view (.cshtml). Rightclick on the View and click Go To View. This will take us to associated CSHTML File.

integrating-adminlte-with-aspnet-core

You will be navigated to Views/Home/Index.cshtml. Here is the content of the page. This is exactly what we saw on the page when we ran the application. Makes sense?

@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

This content is loaded by the @RenderBody tag, so that on runtime you get the complete web page (including the static HTML content and the dynamic code generated by C#).

Now, let’s talk a bit on partial views. In your _Layout.cshtml page, you may find this somewhere in 20th line or so.

<partial name="_LoginPartial" />

Unlike Views, Partial Views in ASP.NET Core renders the HTML output within another View’s rendered output. There can be cases where your applications has components that can be reused anywhere within the application. In our case we have the top Navigation bar that is quite common through the application. You can find the _LoginPartial.cshtml in the shared folder as well.

Integrating AdminLTE with ASP.NET Core

With the basic concepts of Layouts, View and partial Views clear, it will be easier to integrate any 3rd Party HTML Layout to our ASP.NET Core Applications. Let’s proceed.

Copying the Required Resources

As mentioned earlier, AdminLTE is built over Bootstrap. Hence it contains quite a lot of jquery and js integrations as well. We would not be just copying the HTML content, but also the related resources, like css, images, libraries, js files , etc.

In our AdminLTE Folder, Navigate to distcss and copy the content over to the wwwrootcss folder in our Visual Studio. Do the same for the js folder as well.

PS, to copy th contents over, just copy the selected folder/file and go the Visual Studio. Here you may find a wwwroot folder. This is the folder meant to hold the static files of ASP.NET Core applications. Just paste the copied file here with a simple CTRL+V command.

Next copy the entire img folder to the wwwroot folder. Navigate back to the root of the AdminLTE folder and copy thr plugins folder to the wwwroot folder as well.

Note that we will not be using all the plugins in the plugins folder for now. You may need to removed the unused files once you are done with the application to save small space. For now, let’s keep them.

This is how your wwwroot folder would look like after we are done copying the content.

integrating-adminlte-with-aspnet-core

Now that we have all the required resources moved to our application. Let’s wire up the Layout Page.

Adding Layout pages & Partial Views

An Application can have multiple Layout pages. For this tutorial, let’s not disturb the existing _Layout.cshtml page. Rather, let’s build one specifically for AdminLTE.

In the Shared Folder, create a new folder named AdminLTE. Here is where you would want to put all the .cshtml related to AdminLTE.

Before building the layout pages and partial views, let’s decide on how we will seperate the HTML content. Note that we will be using the starter.html page to build the Layout. Open up the starter.html page on your browser.

integrating-adminlte-with-aspnet-core

Here is how we could split up the page into.

  • Side Navigation
  • Top Navigation
  • Body
  • Footer

Additionaly we will want to add 2 more partial views that will hold the references to the css and js files respectively. This makes it easier to sort and manage your resource references.

Under the AdminLTE Folder create a new View and name it _Layout.cshtml. Make sure to uncheck the partial view and layout page options.

integrating-adminlte-with-aspnet-core

Next, let’s start adding the partial view files. In the same AdminLTE folder, add a new view and name it _MainNavigation.cshtml. This time, check the “create as a partial view” option.

integrating-adminlte-with-aspnet-core

Similary, add other partial views with the following file names.

  • _TopNavigation
  • _Footer
  • _Scripts
  • _Styles

This way, you can neatly structure you Layouts.

integrating-adminlte-with-aspnet-core

Let’s start adding content to each file. So, now we have the idea of how we will split the HTML. Open up starter.html in a code editor. I use VS Code. The starter.html has over 330 lines of HTML. Let’s move the code one by one.

Scripts. Go to the end of the file. Above the body tag, you can find few of the script reference there. Cut it and Paste it over to _Scripts.cshml. Replace in the starter.html with the following.

<partial name="AdminLTE/_Scripts" />

Footer. Just above where the scripts were defined, you can find the footer container. Cut this and move to _Footer.cshtml. Add the following instead in the starter.html. We will move the codes from here to the _Layout.cshtml once we are done with the partial views.

<partial name="AdminLTE/_Footer" />

Body. You can find a div class “content”. Delete the entire child div which has a class named “row” This is where we wuold want to put our @RenderBody tag.

Main Navigation - Search for a class “main-sidebar”. Cut it and move it to _MainNavigation.cshtml. Here you have all the sidebar items at once place for you to extend.

<partial name="AdminLTE/_MainNavigation" />

Top Navigation - Search for the class “main-header” and move the content over to _TopNavigation.cshtml.

<partial name="AdminLTE/_TopNavigation" />

Styles. Below the title tag, you can see a bunch of stylesheet references. Cut and paste to _Scripts.cshtml and Replace with the following instead.

<partial name="AdminLTE/_Styles" />

Now, we have moved all the possible componets to partial views. What remains in our code editor would look something like this. Move this to the _Layout.cshtml

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<title>AdminLTE 3 | Starter</title>
<partial name="AdminLTE/_Styles" />
</head>
<body class="hold-transition sidebar-mini">
<div class="wrapper">
<partial name="AdminLTE/_TopNavigation" />
<partial name="AdminLTE/_MainNavigation" />
<div class="content-wrapper">
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0 text-dark">Starter Page</h1>
</div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item"><a href="#">Home</a></li>
<li class="breadcrumb-item active">Starter Page</li>
</ol>
</div>
</div>
</div>
</div>
<div class="content">
<div class="container-fluid">
@RenderBody()
</div>
</div>
</div>
<aside class="control-sidebar control-sidebar-dark">
<div class="p-3">
<h5>Title</h5>
<p>Sidebar content</p>
</div>
</aside>
<partial name="AdminLTE/_Footer" />
</div>
<partial name="AdminLTE/_Scripts" />
</body>
</html>

Congrats, we have seperated the htmls to layouts and partial views. Now build and run the application. You would see absolutely no change. Why? Because we have not mentioned anywhere to use our new layout, have we?

For this, Navigate to Views/Home/Index.cshtml and mention the layout manually.

@{
ViewData["Title"] = "Home Page";
Layout = "~/Views/Shared/AdminLTE/_Layout.cshtml";
}

After this, run the application again. You would see quite of lot of changes. (which you are probably not happy with :p ). The entire page would be broken. However, you can see that we are able to display the content we passed from the View. Now let’s the fix the page.

integrating-adminlte-with-aspnet-core

Any guesses on why this page is broken? It’s quite simple if you already have experiences with HTML pages. This is commonly because the page cannot find the stylesheets that contains the styles defined. We copied the styles and scripts to the Partial Views, but we did not changes the references. Let’s change the paths to point to the specifc files in the wwwroot folder.

Open up _Styles.cshtml and modify as below

<link rel="stylesheet" href="~/plugins/fontawesome-free/css/all.min.css">
<link rel="stylesheet" href="~/css/adminlte.min.css">
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700" rel="stylesheet">

Open up _Scripts.cshtml and modify as below

<script src="~/plugins/jquery/jquery.min.js"></script>
<script src="~/plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
<script src="~/js/adminlte.min.js"></script>

That’s it. Run the application again.

integrating-adminlte-with-aspnet-core

There you go! You can see that the page starts looking great. The only issue is a broken image reference. You can fix it similarly by going to _MainNavigation.cshtml and fixing the reference issue like we did earlier.

Now, let’s add this layout to the Privacy Page too! Go to Views/Home/Privacy.cshtml add in the following line.

@{
ViewData["Title"] = "Privacy Policy";
Layout = "~/Views/Shared/AdminLTE/_Layout.cshtml";
}

Run the application and navigate to loclhost:xxx/home/privacy. This is what we get.We are all setup now.

integrating-adminlte-with-aspnet-core

Adding Navigation

Let’s add some navigation menu to our _MainNavigation.cshtml. What we need to do is simple. Remove the static paths and add add links to our controller methods. For now, we will add 2 Navigation Items. Home and Privacy.

  • Home will be linked to Home/Index
  • Privacy page will be linked to Home/Privacy
<aside class="main-sidebar sidebar-dark-primary elevation-4">
<a href="~/Home" class="brand-link">
<img src="~/img/AdminLTELogo.png" alt="AdminLTE Logo" class="brand-image img-circle elevation-3"
style="opacity: .8">
<span class="brand-text font-weight-light">AdminLTE 3</span>
</a>
<div class="sidebar">
<div class="user-panel mt-3 pb-3 mb-3 d-flex">
<div class="image">
<img src="~/img/user2-160x160.jpg" class="img-circle elevation-2" alt="User Image">
</div>
<div class="info">
<a href="#" class="d-block">Alexander Pierce</a>
</div>
</div>
<nav class="mt-2">
<ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false">
<li class="nav-item ">
<a asp-controller="Home" asp-action="Index" class="nav-link">
<i class="nav-icon fas fa-home"></i>
<p>
Home
</p>
</a>
</li>
<li class="nav-item ">
<a asp-controller="Home" asp-action="Privacy" class="nav-link">
<i class="nav-icon fas fa-lock"></i>
<p>
Privacy
</p>
</a>
</li>
</ul>
</nav>
</div>
</aside>

Line 3 and 10 - image reference fix.
Line 19 - You can see for the navigation Item named “Home” , we are linking to the controller “Home” and Index actions.
Line 27 - For the Privacy page, we like to the Home Controller and Privvacy method.

Run the application and check.

integrating-adminlte-with-aspnet-core

So that’s working too. But there is one detail that we are missing. Navigation Indicator. There is no indication in our sidebar about the currently viewed page. For now, since we have just 2 naviagation item, it’s quite fine to check the URL and understand which page we are at right now. But this is not ideal. Let’s fix it first.

For this to work, we need data from our ASP.NET Core regarding the current controller and action method. And based on this we need to change the class of the corresponsing navigation item to active. Active means the current page.

Add a new folder in the root of the project. Name it Helpers. Under it, add a new NavigationIndicatorHelper class.

public static class NavigationIndicatorHelper
{
public static string MakeActiveClass(this IUrlHelper urlHelper, string controller,string action)
{
try
{
string result = "active";
string controllerName = urlHelper.ActionContext.RouteData.Values["controller"].ToString();
string methodName = urlHelper.ActionContext.RouteData.Values["action"].ToString();
if (string.IsNullOrEmpty(controllerName)) return null;
if (controllerName.Equals(controller, StringComparison.OrdinalIgnoreCase))
{
if (methodName.Equals(action, StringComparison.OrdinalIgnoreCase))
{
return result;
}
}
return null;
}
catch (Exception)
{
return null;
}
}
}

Here is what this helper class does. It has an extension method with the URLHelper. By this way, you can invoke it in the cshtml page too. It takes in the controller and the action method name and checks it with the current route data. If they match, we retun a string “active”, else null.

Go to _MainNavigation.cshtml. Modify / Add these lines

@using static AdminLTE.MVC.Helpers.NavigationIndicatorHelper;
.
.
<a asp-controller="Home" asp-action="Index" class="nav-link @Url.MakeActiveClass("home","index")">
.
.
<a asp-controller="Home" asp-action="Privacy" class="nav-link @Url.MakeActiveClass("home","privacy")">

Run the application. Now, we have got a working navigation indicator. Sweet, yeah?

integrating-adminlte-with-aspnet-core

With that out of the way, as promised, let’s check out how to integrate authentication using the exisitng Identity Authentication.

Integrating the UI with existing Authentication

Let me draw you a scenario. The requirement is that we need to secure a particular view. In our case, we have Index and Privacy pages. Let’s say we keep the Index Page available for everyone. But limit the access to the Privacy page and allow access only if the user is authenticated. We will also want to hide the item from the navigation menu if not authenticated.

If the visitors tries to access the resource (without auth) by navigating directly to ../Home/Privacy, we redirect him to a login page. So this is what we will be doing here. This is quite a practical scenario right?

AdminLTE comes with a default Login and Register page too! It’s located under ../pages/examples folder as login.html and register.html.

By now you would be quite clear on how to integrate the UI. But there is a catch here. If you examine our ASP.NET Core MVC application, you would no where find a Login or Register page. But we added authentication to the application while creating it, Remember? So how does that work.

Sometime, during the announcment of ASP.NET Core 2.1. Microsoft revealed that the Identity UI (all the pages related to Microsoft Identity) would be moved to a Razor Library. Thus, it works out of the box even though it’s not visible to us.

But, what if we had to do some modification to it? That’s where Identity Scaffold comes to play. Follow these steps to bring back the Login and Register Razor Pages for us to modify.

Right click on the Project -> Add New -> New Scaffolded Item.

integrating-adminlte-with-aspnet-core

In this next dialog, select Identity and click Add.

integrating-adminlte-with-aspnet-core

Now, we get to select the required Identity pages. To keep things simple, let’s add only the Login and Registration page. Make sure you select the data class as well. Click Add. Now, Visual Studio does its magic and generate the selected files.

In the background, Visual Studio also makes a DataContext class for you and registers it in the starup services with a default local db.

integrating-adminlte-with-aspnet-core

Once it’s done, you see the following folder with our selected Identity Pages.

integrating-adminlte-with-aspnet-core

Now we will integrate these Views with the login.html and the register.html. It would help you if you do this integration on your own, to help understand the scenarios better. To keep the article compact, i will just the just add the links to the changed files.

These are the resulting page. Pretty neat, yeah?

integrating-adminlte-with-aspnet-core

integrating-adminlte-with-aspnet-core

Enabling Authentication

Now that we have our Identity Pages ready, let us setup our ASP.NET Core Application to enable Authentication.

We will secure all the Controller methods by default. As per as our requirement, we need to allow any random visitor to use the Home/Index method.

Navigate to Startup.cs/ConfigureServices method add these lines.

services.AddMvc(o =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
o.Filters.Add(new AuthorizeFilter(policy));
});

This will add a new policy to the ASP.NET Core MVC Application that every method needs an authenticated user, unless we define it as [AllowAnonymous]

Now, go to the Home Controller and add [AllowAnonymous] above the Index method. This means that the method can be accessed by anyone.

[AllowAnonymous]
public IActionResult Index()
{
return View();
}

That’s it.Just run the application and check. You would be able to navigate to the Home page without any issues. But when you go to the Privacy page, you will be redirected to the login page. How simple was that.

Authenticated Status Based Menu

We do not want the anonymous user to see the Privacy link in the navigation. To hide the item. go to _MainNavigation.cshtml

Here is the simple logic. We will need to add a condition (if) to check if the current user is authenicated, if yes, display the privacy link. Else, no. Here is how you code it.

@if (User.Identity.IsAuthenticated)
{
<li class="nav-item ">
<a asp-controller="Home" asp-action="Privacy" class="nav-link @Url.MakeActiveClass("home","privacy")">
<i class="nav-icon fas fa-lock"></i>
<p>
Privacy
</p>
</a>
</li>
}

Now, there is one more thing that we can add here using the conditional check of authentication. In the side do you see a random image with a random name? Does it make sense to add a similar condition there? Yeah, right? So what we will do is, show the name of the authenticated user . If not authenticated let’s show a “Hi, Visitor”.

Modify the _MainNavigation.cshtml like below.

@if (User.Identity.IsAuthenticated)
{
<div class="user-panel mt-3 pb-3 mb-3 d-flex">
<div class="image">
<img src="~/img/user2-160x160.jpg" class="img-circle elevation-2" alt="User Image">
</div>
<div class="info">
<a href="#" class="d-block">Hi, @User.Identity.Name</a>
</div>
</div>
}
else
{
<div class="user-panel mt-3 pb-3 mb-3 d-flex">
<div class="info">
<a href="#" class="d-block">Hi, Visitor</a>
</div>
</div>
}

Build and run the application.

integrating-adminlte-with-aspnet-core

Quite self explanatory, yeah? Finally let’s add the login/register links to the Top Navigation Menu.

Go to _TopNavigation.cshtml and modify the code.

@if (User.Identity.IsAuthenticated)
{
<li class="nav-item d-none d-sm-inline-block">
<form class="form-inline" asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="@Url.Action("Index", "Home", new { area = "" })">
<button type="submit" class="nav-link btn btn-link text-dark">Logout</button>
</form>
</li>
}
else
{
<li class="nav-item d-none d-sm-inline-block">
<a asp-area="Identity" asp-page="/Account/Login" class="nav-link">Login</a>
</li>
<li class="nav-item d-none d-sm-inline-block">
<a asp-area="Identity" asp-page="/Account/Register" class="nav-link">Register</a>
</li>
}

That’s all for this guide. Let’s now check if everything works fine. Let’s register a new account.

integrating-adminlte-with-aspnet-core

Ps. we have to apply the migrations yet. While registering for the first time, Visual studio let’s you know about this.

integrating-adminlte-with-aspnet-core

Click on Apply Migrations. Once it is done, You will get a message saying, “Try refreshing the page.” . Refresh the page.

integrating-adminlte-with-aspnet-core

In this page, click on confirm your account. Then Navigate to localhost:xxx/Home

integrating-adminlte-with-aspnet-core

Let’ s login! with the created credentials.

integrating-adminlte-with-aspnet-core

integrating-adminlte-with-aspnet-core

Great, everything works as we intended. Let’s me wind up this really long article :D

Update - Issue with filterizr Plugin for AdminLTE 3.0.5

Recently one of the readers posted an issue in the comments section that he faced while working with AdminLTE 3.0.5. The exception goes something like this.

Build: The module ‘”./FilterizrOptions/defaultOptions”‘ has no exported member ‘RawOptionsCallbacks’. Did you mean ‘import RawOptionsCallbacks from “./FilterizrOptions/defaultOptions”‘ instead.

With AdminLTE 3.0.5, the filterizr plugin for some reason still has it’s own source code files, which can cause TypeScript errors in Visual Studio if you try to run the project (I didn’t face such an issue). If you face the similar issue, kindly remove the plugin from your solution. Delete everything in filterizr folder except for the following files:

  • filterizr.min.js
  • jquery.filterizr.min.js
  • vanilla.filterizr.min.js

AdminLTE Starter Kit for ASP.NET Core 3.1 - Open Source Project

If you are interested in having a starter kit / boilerplate template for AdminLTE ASP.NET Core, take a look at this open-source project.

Summary

In this detailed beginner-friendly guide, We have learnt Integrating AdminLTE with ASP.NET Core 3.1 MVC. We covered several topics inclusing Layouts, Views, PartialViews, Authentication, Identity, Navigation Indicator, and much more. You can check out the complete source code for this demonstration over at my Github. Do not forget to share this article and leave your comments below. Happy Coding :)

Shall we extend this Application by adding more features to it in another articlle? Like jquery datatable, CRUD, Role based Authorization, and more? Leave your opinions about it.

Source Code ✌
Grab the source code of the entire implementation by clicking here. Do Follow me on GitHub .
Support ❀
If you have enjoyed my content and code, do support me by buying a couple of coffees. This will enable me to dedicate more time to research and create new content. Cheers!
Share this Article
Share this article with your network to help others!
What's your Feedback?
Do let me know your thoughts around this article.

Boost your .NET Skills

I am starting a .NET 8 Zero to Hero Series soon! Join the waitlist.

Join Now

No spam ever, we are care about the protection of your data. Read our Privacy Policy