Most applications would need an Error Summary in their forms. The main challenge would be how are errors populated to this... and how is the translation handled.
One option that I'm using is a TagHelper
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Razor.TagHelpers;
using System.Text.Json;
using System.Text.RegularExpressions;
namespace CESG_SCEE.WebUI.Helpers
{
[HtmlTargetElement("gcds-error-summary", Attributes = "model-state,model-type")]
public class GcdsErrorSummaryTagHelper : TagHelper
{
[HtmlAttributeName("model-state")]
public required ModelStateDictionary ModelState { get; set; }
[HtmlAttributeName("model-type")]
public required Type ModelType { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (ModelState == null || ModelState.IsValid || ModelType == null)
return;
var errorSummary = new Dictionary<string, string>();
var genErrCount = 0;
foreach (var entry in ModelState)
{
var errorMessages = entry.Value.Errors
.Select(error => error.ErrorMessage)
.ToList();
foreach (var errorMessage in errorMessages)
{
if (string.IsNullOrEmpty(entry.Key))
{
errorSummary[$"GenError:{++genErrCount}"] = errorMessage;
}
else
{
//TODO error links need to be fixed
errorSummary[$"#{SanitizeForHtmlId(entry.Key)}"] = $"{ViewModelHelper.GetDisplayName(entry.Key, ModelType)} - {errorMessage}";
}
}
}
if (errorSummary.Count > 0)
{
var json = JsonSerializer.Serialize(errorSummary);
output.Attributes.SetAttribute("error-links", json);
}
}
private static readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(100);
private static readonly Regex HtmlIdSanitizer = new(@"[^a-zA-Z0-9\-_:.]", RegexOptions.Compiled, RegexTimeout);
private static string SanitizeForHtmlId(string input)
=> HtmlIdSanitizer.Replace(input ?? string.Empty, "_");
}
}
Most applications would need an Error Summary in their forms. The main challenge would be how are errors populated to this... and how is the translation handled.
One option that I'm using is a TagHelper