Search code examples
c#asp.net-coretag-helpers

Getting property attributes in TagHelpers


Some of model properties has "Required" data annotation, that I need to read in a TagHelper class.

public partial class Sale
{
    [Required]
    public string CustomerId { get; set; }
    ...

In the sales view I create a custom select for customer:

<customer asp-for="CustomerId " value="@Model.CustomerId"></customer>

And in the CustomerTagHelper class there is the process method:

public override void Process(TagHelperContext context, TagHelperOutput output)
{

How can I discover at this point, if the current bind property has the "required" attribute? I´m using asp-net core.


Solution

  • The tag helper doesn't know about anything other than what you provide as input for its attributes. So you want to create a tag helper that you can use as follows:

    @model WebApplication4.Models.Sale
    ...
    <customer asp-for="CustomerId" />
    

    Then you would declare a property of type ModelSource associated with the asp-for attribute. That would give you access to not just the value of the property but also metadata like the following (and more!):

    • property value: source.Model
    • property name: source.Name
    • container model type: source.Metadata.ContainerType
    • IsRequired flag: source.Metadata.IsRequired

    You will also get intellisense in VS to select one of properties in your model for the asp-for model and it will throw an error if the value isnt the name of a model property.


    As an example, take a look at this tag helper:

    public class CustomerTagHelper: 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 contents = $@"
                Model name: {Source.Metadata.ContainerType.FullName}<br/>
                Property name: {Source.Name}<br/>
                Current Value: {Source.Model}<br/> 
                Is Required: {Source.Metadata.IsRequired}";
    
            output.Content.SetHtmlContent(new HtmlString(contents));
        }
    }
    

    Then if you had these 2 models:

    public class Sale
    {
        [Required]
        public string CustomerId { get; set; }
    }
    public class Promotion
    {        
        public string CustomerId { get; set; }
    }
    

    Which are used in these 2 actions and views:

    public IActionResult Sale()
    {
        return View();
    }
    
    @model WebApplication4.Models.Sale
    ...
    <customer asp-for="CustomerId" />
    
    
    public IActionResult Promotion()
    {
        return View(new Models.Promotion { CustomerId = "abc-123" });
    }
    
    @model WebApplication4.Models.Promotion
    ...
    <customer asp-for="CustomerId" />
    

    Will produce these outputs:

    Tag helper for: WebApplication4.Models.Sale
    Property name: CustomerId
    Current Value: 
    Is Required: True
    
    Model name: WebApplication4.Models.Promotion
    Property name: CustomerId
    Current Value: abc-123
    Is Required: False