Reputation: 124
I am working on a new project in .net Core having previously been working with .net Framework.
I wish to produce html select elements for boolean properties but using custom values instead of True and False (mainly "Yes" and "No"). In previous projects I have used the following method:
Create a custom attribute for boolean values:
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public class BooleanCustomValuesAttribute : Attribute, IMetadataAware
{
public string TrueValue { get; set; }
public string FalseValue { get; set; }
public void OnMetadataCreated(ModelMetadata metadata)
{
metadata.AdditionalValues["TrueValue"] = TrueValue;
metadata.AdditionalValues["FalseValue"] = FalseValue;
}
}
Use this in my model:
[BooleanCustomValues(TrueValue = "Yes", FalseValue = "No")]
public bool ThisWorks { get; set; }
Then in an editor template I can access these values for adding to a select:
object trueTitle;
ViewData.ModelMetadata.AdditionalValues.TryGetValue("TrueValue", out trueTitle);
trueTitle = trueTitle ?? "True";
object falseTitle;
ViewData.ModelMetadata.AdditionalValues.TryGetValue("FalseValue", out falseTitle);
falseTitle = falseTitle ?? "False";
I am now trying to do something similar in .net core, this time using a tag-helper instead of an editor template.
I understand that setting the AdditionalValues as above is not supported in core?
The closest I have found is this answer: Getting property attributes in TagHelpers
My tag helper code looks like this currenty (outputting p just for testing):
public class BooleanSelectTagHelper: TagHelper
{
[HtmlAttributeName("asp-for")]
public ModelExpression Source { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "p";
output.TagMode = TagMode.StartTagAndEndTag;
var booleanAttribute = Source.Metadata.ContainerType.GetProperty(Source.Name).GetCustomAttribute(typeof(BooleanCustomValuesAttribute));
var contents = $@"{booleanAttribute.TrueValue} or {booleanAttribute.FalseValue}";
output.Content.SetHtmlContent(new HtmlString(contents));
}
}
However I can't get it to work as Source.Metadata.ContainerType.GetProperty(Source.Name).GetCustomAttributes() returns null.
Anoyingly when debugging and looking at Source.Metadata in a watch window I can see exactly what I want to access under Source.Metadata.Attributes - however this is not something that seems to be exposed outside the debugger.
Apologies for length of post - any pointers would be much appreciated (including tellimg me I am doing this all wrong!)
Upvotes: 0
Views: 1970
Reputation: 1683
Maybe this will help, this is what I use to add the attributes for unobtrusive validation when I create custom TagHelper
s. You can adapt this to whatever attribute you want to use.
From my experience, when you have the public member for ModelExpression
, just call it AspFor
, if you do not, it does not seem to get any of the attributes. But if the name matches, then I never have an issue. I'm currently using this on .NET 5.
public class BooleanSelectTagHelper: TagHelper {
public ModelExpression AspFor { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output){
//... setup excluded for this example
var attribute = this
.AspFor
.Metadata
.ContainerType
.GetProperty(AspFor.Name)
.GetCustomAttributes(typeof(RequiredAttribute), false)
.FirstOrDefault();
if (attribute is RequiredAttribute requiredAttribute) {
output.MergeAttribute("data-val", "true");
output.MergeAttribute("data-val-required", requiredAttribute.FormatErrorMessage(AspFor.Name));
}
//... code to display excluded for this example
}
}
I usually attempt to get the attribute, and then check whether it's of the desired type right inside of the if
statement. Then access whatever you need to inside of the if
branch.
Upvotes: 3
Reputation: 3374
You are missing HtmlTargetElement
attribute on your tag helper:
[HtmlTargetElement(Attributes = "asp-for")] // <== Add this
public class BooleanSelectTagHelper: TagHelper
{
[HtmlAttributeName("asp-for")]
public ModelExpression Source { get; set; }
}
Also, don't forget to import your own tag helpers in _ViewImports.cshtml
file after Microsoft's tag helpers. Replace the "WebApp" with the name of your assembly containing the tag helpers to add. Read more in official documentation.
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, WebApp
Upvotes: 0