Last active
November 16, 2022 14:00
-
-
Save FWest98/9141b3c2f260bee0e46058897d2017d2 to your computer and use it in GitHub Desktop.
.NET Core 3 Custom Validation Classnames
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This is the default partial generated in the template, if you have another place | |
// where you include the jQuery unobtrusive validation plugin, put this code there | |
@using Foo | |
@inject IOptions<ValidationOptions> validationOptionsHolder | |
@{ var validationOptions = validationOptionsHolder.Value; } | |
// Here is your normal environment stuff | |
<script> | |
(function () { | |
// Set default options for the validation | |
const defaultOptions = { | |
errorClass: "@validationOptions.InvalidInput", // or add custom, extra ones | |
validClass: "@validationOptions.ValidInput" | |
}; | |
$.validator.setDefaults(defaultOptions); | |
$.validator.unobtrusive.options = defaultOptions; | |
})(); | |
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using System.Text.Encodings.Web; | |
using Microsoft.AspNetCore.Antiforgery; | |
using Microsoft.AspNetCore.Mvc; | |
using Microsoft.AspNetCore.Mvc.ModelBinding; | |
using Microsoft.AspNetCore.Mvc.Rendering; | |
using Microsoft.AspNetCore.Mvc.Routing; | |
using Microsoft.AspNetCore.Mvc.ViewFeatures; | |
using Microsoft.Extensions.Options; | |
namespace Foo | |
{ | |
// Custom HTML Generator to override the default behaviour and replace the CSS classes as they emerge | |
public class CustomHtmlGenerator : DefaultHtmlGenerator | |
{ | |
private readonly ValidationOptions _options; | |
public CustomHtmlGenerator(IAntiforgery antiforgery, IOptions<MvcViewOptions> optionsAccessor, | |
IModelMetadataProvider metadataProvider, IUrlHelperFactory urlHelperFactory, HtmlEncoder htmlEncoder, | |
ValidationHtmlAttributeProvider validationAttributeProvider, IOptions<ValidationOptions> options) : | |
base(antiforgery, optionsAccessor, metadataProvider, urlHelperFactory, htmlEncoder, validationAttributeProvider) | |
{ | |
_options = options.Value; | |
} | |
protected override TagBuilder GenerateInput(ViewContext viewContext, InputType inputType, ModelExplorer modelExplorer, string expression, | |
object value, bool useViewData, bool isChecked, bool setId, bool isExplicitValue, string format, | |
IDictionary<string, object> htmlAttributes) | |
{ | |
var tagBuilder = base.GenerateInput(viewContext, inputType, modelExplorer, expression, value, useViewData, isChecked, setId, isExplicitValue, format, htmlAttributes); | |
FixValidationCssClassNames(tagBuilder); | |
return tagBuilder; | |
} | |
public override TagBuilder GenerateTextArea(ViewContext viewContext, ModelExplorer modelExplorer, string expression, int rows, | |
int columns, object htmlAttributes) | |
{ | |
var tagBuilder = base.GenerateTextArea(viewContext, modelExplorer, expression, rows, columns, htmlAttributes); | |
FixValidationCssClassNames(tagBuilder); | |
return tagBuilder; | |
} | |
public override TagBuilder GenerateValidationMessage(ViewContext viewContext, ModelExplorer modelExplorer, string expression, | |
string message, string tag, object htmlAttributes) | |
{ | |
var tagBuilder = base.GenerateValidationMessage(viewContext, modelExplorer, expression, message, tag, htmlAttributes); | |
FixValidationCssClassNames(tagBuilder); | |
return tagBuilder; | |
} | |
public override TagBuilder GenerateValidationSummary(ViewContext viewContext, bool excludePropertyErrors, string message, | |
string headerTag, object htmlAttributes) | |
{ | |
var tagBuilder = base.GenerateValidationSummary(viewContext, excludePropertyErrors, message, headerTag, htmlAttributes); | |
FixValidationCssClassNames(tagBuilder); | |
return tagBuilder; | |
} | |
private void FixValidationCssClassNames(TagBuilder tagBuilder) | |
{ | |
tagBuilder.ReplaceCssClass(HtmlHelper.ValidationInputCssClassName, _options.InvalidInput); | |
tagBuilder.ReplaceCssClass(HtmlHelper.ValidationInputValidCssClassName, _options.ValidInput); | |
tagBuilder.ReplaceCssClass(HtmlHelper.ValidationMessageCssClassName, _options.InvalidMessage); | |
tagBuilder.ReplaceCssClass(HtmlHelper.ValidationMessageValidCssClassName, _options.ValidMessage); | |
tagBuilder.ReplaceCssClass(HtmlHelper.ValidationSummaryCssClassName, _options.InvalidSummary); | |
tagBuilder.ReplaceCssClass(HtmlHelper.ValidationSummaryValidCssClassName, _options.ValidSummary); | |
} | |
} | |
public static class TagBuilderHelpers | |
{ | |
public static void ReplaceCssClass(this TagBuilder tagBuilder, string old, string val) | |
{ | |
if (!tagBuilder.Attributes.TryGetValue("class", out string str)) return; | |
tagBuilder.Attributes["class"] = str.Replace(old, val); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.DirectoryServices.AccountManagement; | |
using System.Linq; | |
using Microsoft.AspNetCore.Authentication.Cookies; | |
using Microsoft.AspNetCore.Authentication.WsFederation; | |
using Microsoft.AspNetCore.Builder; | |
using Microsoft.AspNetCore.Hosting; | |
using Microsoft.AspNetCore.Mvc.DataAnnotations; | |
using Microsoft.AspNetCore.Mvc.ViewFeatures; | |
using Microsoft.EntityFrameworkCore; | |
using Microsoft.Extensions.Configuration; | |
using Microsoft.Extensions.DependencyInjection; | |
using Microsoft.Extensions.Hosting; | |
using Microsoft.Extensions.Options; | |
namespace Foo | |
{ | |
public class Startup | |
{ | |
public Startup(IConfiguration configuration) | |
{ | |
Configuration = configuration; | |
} | |
public IConfiguration Configuration { get; } | |
// This method gets called by the runtime. Use this method to add services to the container. | |
public void ConfigureServices(IServiceCollection services) | |
{ | |
// All your usual stuff | |
// Configure Options | |
services.Configure<ValidationOptions>(Configuration.GetSection("Validation")); // or use a custom source | |
// Configure custom html generator to override css classnames | |
services.AddSingleton<IHtmlGenerator, CustomHtmlGenerator>(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Foo | |
{ | |
// Options class to set the validation classes. Of course, this is not required as you can | |
// also harcode the classnames in the CustomHtmlGenerator file. | |
public class ValidationOptions | |
{ | |
public string ValidInput { get; set; } | |
public string InvalidInput { get; set; } | |
public string InvalidMessage { get; set; } | |
public string ValidMessage { get; set; } | |
public string InvalidSummary { get; set; } | |
public string ValidSummary { get; set; } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I ultimately figured it out... the values are hard-coded in jquery.validate.unobtrusive.js so a direct change is required. I added a couple of getter methods to pull the class name from the options from '$jQval.unobtrusive.options', then replaced all the hard coded values with calls to the getter functions. Fingers crossed MS does something better in .NET 8!
Thanks again!