1

In my ASP.NET MVC 5 (C#) application, I have a class called Name:

public class Name
{
    public virtual string? First { get; set; }
    public virtual string? Middle { get; set; }
    public virtual string? Last { get; set; }
    public virtual string? Suffix { get; set; }
}

I also have several models containing a property (of type name) called NameFull:

[RequiredProps(nameof(Name.First), nameof(Name.Last))] // *** More about this in a minute. ***
public Name? NameFull { get; set; }

These model properties get used by a custom tag helper like this: <field asp-for="NameFull" />. There's logic inside the custom tag helper detects that the model property is a complex type and generates a custom HTML helper since HTML helpers can handle complex objects unlike tag helpers. So basically this code <field asp-for="NameFull" /> generates multiple input elements. That's the background, here's my problem...


I want to be able to make some of those inputs required on a case-by-case basis. So maybe in one model first and last name are required. In another model, none of them are required. So I created a custom attribute named RequiredPropsAttribute (see model example above). It inherits from ValidationAttribute and implements IClientModelValidator AttributeAdapter to apply client-side validation like so:

public sealed class RequiredPropsAttribute : ValidationAttribute, IClientModelValidator
{
    //most of the logic has been omitted for brevity...
    public void AddValidation(ClientModelValidationContext context)
    {
        var properties = context.ModelMetadata.Properties;
        if (!context.Attributes.ContainsKey("data-val"))
        {
            context.Attributes.Add("data-val", "true");
        }
        if (!context.Attributes.ContainsKey("data-val-required"))
        {
            context.Attributes.Add("data-val-required", $"The {string.Join(", ", properties)} fields are all required.");
        }
    }
}

This does allow me to add validation to the parent property (Name), but what I want is to apply the validation to its nested children. In short, I want something similar to the above code that injects data-val="true" and data-val-required="This field is required" into the nested child inputs (Name.First, Name.Middle, Name.Last, Name.Suffix). I've tried accessing the children using context.ModelMetadata.Properties, but the collection isn't set up in such a way to where I can write code like this: property.Attributes.Add("data-val", "true"). Which leads me to my question...

QUESTION: How do I write logic inside AddValidation that lets me basically say: loop through the child properties of Name and add attributes to each of them so each child <input> gets data- validation attributes. Is this possible? And if not, is there any other way I can conditionally add a required attribute to the name properties based on attributes applied to name, e.g. add a RequiredIf to First that says "if Name has a RequiredProps attribute containing First, then make first required, etc.?

Thanks in advance for your help, everyone!

dhughes
  • 295
  • 5
  • 10
  • Maybe this could help you? https://stackoverflow.com/questions/5367287/disable-required-validation-attribute-under-certain-circumstances/17067983 – Marcio Feb 27 '21 at 14:59
  • @Marcio Thanks for the reply - I'll look into it! – dhughes Feb 27 '21 at 16:06
  • Hi @dhughes, did you find the solution? – Rena May 13 '21 at 06:33
  • Hi-ya. Sorry it's been a while since I've logged on here. No, I never did quite get anything to work the way I envisioned it. What I ended up settling on was creating two different models: a RequiredNameModel and an OptionalNameModel and – dhughes Dec 02 '21 at 21:15

0 Answers0