ASP.NET Core 6.0 - Homegrown TagHelpers
This article will describe the implementation of custom tag helpers. I will assume you have downloaded the ASP.NET Core 6.0 - Homegrown Analytics Project.
Homegrown Analytics Project and Article Series
The Homegrown Analytics Project (HAP) is designed and organized to allow easy integration with existing projects. V2 simplifies the process with an Analytics area folder. The analytics schema can be implemented with SQL scripts or EF Core migration. See ASP.NET Core 6.0 - Analytics Schema and Integration. The HAP details page includes the version change log.
ASP.NET Core 6.0
- ASP.NET Core 6.0 - Homegrown Analytics
- ASP.NET Core 6.0 - Analytics Schema and Integration
- ASP.NET Core 6.0 - Data Collection
- ASP.NET Core 6.0 - Data Filters
- ASP.NET Core 6.0 - Data Visualization
- ASP.NET Core 6.0 - World Heat Map
- ASP.NET Core 6.0 - Homegrown TagHelpers
- ASP.NET Core 6.0 - Client End Of Day
ASP.NET Core 5.0
- ASP.NET Core 5.0 - Homegrown Analytics
- ASP.NET Core 5.0 - Analytics Schema and Integration
- ASP.NET Core 5.0 - Cookie Consent and GDPR
- ASP.NET Core 5.0 - Analytic Data Collection
- ASP.NET Core 5.0 - Not Found Errors
- ASP.NET Core 5.0 - Preferred UserAgents
- ASP.NET Core 5.0 - Analytic Dashboard
- ASP.NET Core 5.0 - Online User Count with SignalR
- ASP.NET Core 5.0 - Is Human with Google reCAPTCHA
- ASP.NET Core 5.0 - Log Maintenance with Hangfire
Filtering a boolean property with a checkbox facilitates 2 states: include and only. I developed a group of radio buttons to allow 3 states: include, exclude, and only. The PageHit has a boolean property named CookieConsent indicating non essential cookies are allowed. A Consented checkbox can query all pageHits or pageHits with CookieConsent.
[Display(Name = "Consented")] public bool ConsentedOnly { get; set; }
if (consentedOnly) pageHitsQuery = pageHitsQuery.Where(ph => ph.CookieConsent).AsQueryable();
A 3 button radio button group and a ConsentedFilter int property can query all pageHits, pageHits with CookieConsent, and pageHits without CookieConsent.
[Display(Name = "Consented")] public int ConsentedFilter { get; set; }
if (ConsentedFilter == 1) pageHitsQuery = pageHitsQuery.Where(ph => !ph.CookieConsent).AsQueryable(); if (ConsentedFilter == 2) pageHitsQuery = pageHitsQuery.Where(ph => ph.CookieConsent).AsQueryable();
We use Microsoft. AspNetCore. Mvc. TagHelpers all the time. When a html tag is recognized the tag text is bold. When an attribute is recognized the attribute text is bold. Most of the built in tag helpers target known html elements. I use the radio button boolean filter on many pages for a lot of properties. Creating a custom BoolFilterTagHelper is easier than initial research suggests. After reviewing MS Docs on Tag Helpers and Tag Helper Components, my expectations grew as I followed the example at MS Docs - Author Tag Helpers in ASP.NET Core. The EmailTagHelper example demonstrated you can create a custom tag name and PascalCase property names in C# get translated to kebab-case attributes in html.
using Microsoft.AspNetCore.Razor.TagHelpers; namespace HomegrownAnalyticsNet6.Areas.Analytics.Models.TagHelpers; /// <summary> /// <see cref="ITagHelper" /> implementation of a radio button group with Include, Exclude, and Only radio buttons. /// </summary> public class BoolFilterTagHelper : TagHelper { /// <summary> /// Radio button group name. Suffix of input ids. Must match an int property/parameter name on the page. /// </summary> public string FilterFor { get; set; } = string.Empty; /// <summary> /// Radio button group header text. /// </summary> public string FilterLabel { get; set; } = string.Empty; /// <summary> /// Indicates the checked radio button. 0 = Include, 1 = Exclude, or 2 = Only. /// </summary> public int FilterValue { get; set; } public override void Process(TagHelperContext context, TagHelperOutput output) { if (string.IsNullOrEmpty(FilterFor)) output.Content.SetHtmlContent("<h4>The bool-filter tag requires a filter-for attribute.</h4>"); else { var includeChecked = FilterValue == 0 ? "checked" : ""; var excludeChecked = FilterValue == 1 ? "checked" : ""; var onlyChecked = FilterValue == 2 ? "checked" : ""; string markup = @$"<div class='d-inline-flex flex-wrap p-0 ps-2 alert alert-primary align-top mb-1'> <h6 class='d-inline mt-1 me-2 mb-0'>{FilterLabel}</h6> <div class='form-check form-check-inline mt-1'> <input type='radio' value='0' class='form-check-input' id='Include{FilterFor}' {includeChecked} name='{FilterFor}' onclick='this.form.submit();' /> <label class='form-check-label fw-bold' for='Include{FilterFor}'> Include </label> </div> <div class='form-check form-check-inline mt-1'> <input type='radio' value='1' class='form-check-input' id='Exclude{FilterFor}' {excludeChecked} name='{FilterFor}' onclick='this.form.submit();' /> <label class='form-check-label fw-bold' for='Exclude{FilterFor}'> Exclude </label> </div> <div class='form-check form-check-inline mt-1'> <input type='radio' value='2' class='form-check-input' id='Only{FilterFor}' {onlyChecked} name='{FilterFor}' onclick='this.form.submit();' /> <label class='form-check-label fw-bold' for='Only{FilterFor}'> Only </label> </div> </div>"; output.Content.SetHtmlContent(markup); } } }
The BoolFilterTagHelper reduces the html for the 3 button radio button group to a single html tag. To make all custom TagHelper classes available to all Razor pages, implement the addTagHelper directive with a wildcard and the project name in all _ViewImports.cshtml files.
@using HomegrownAnalyticsNet6.Areas.Analytics.Models; @using HomegrownAnalyticsNet6.Areas.Analytics.Models.Entities; @using HomegrownAnalyticsNet6.Areas.Analytics.Services; @using Microsoft.AspNetCore.Authorization; @namespace HomegrownAnalyticsNet6.Areas.Analytics.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @addTagHelper *, HomegrownAnalyticsNet6
Meaningful xml comments provide BoolFilterTagHelper Intellisense.
I liked the BoolFilterTagHelper so much, I developed TagHelpers for SegmentsFilter, CurrentIpFilter, and DateTime. The DateTimeTagHelper implements a date-time picker.
The images display the AnalyticsSampleData derived from a KenHaggerty.Com db backup.
Width
Live Demonstration
I publish the Users Without Passwords Project (UWPP) on the FIDO subdomain and the Users With Comments Project (UWCP) on the Preview subdomain. I integrated the HAP with the published projects. The subdomains have their own databases. Registered users can request permission to access the Admin - Analytics Dashboard. The permission will be granted automatically. The UWCP implements the Users With Device 2FA Project (UWD2FAP). Preview requires 2FA enabled to access admin pages.
After you register, browse to Manage Account > Visit Log. Click the More link in the HAP banner. Request permission.
Comments(0)