Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asp.Net Core Model Validation *Multiple* Attributes

I have a Asp.Net Core REST service and I'm using the built in validation. I needed some additional functionality, so I found some examples of validation attributes that I needed, so here is a small part of my model:

    [RequiredIfEmpty("B")]
    [RequiredIfEmpty("C")]
    public string A { get; set; }
    public string B { get; set; }
    public string C { get; set; }

So, pretty obvious what I'm going for. I want to validate that A is specified if B or C is empty.

When I send a JSON request that will fail validation, I only get:

"A is required when B is empty."

I'm expecting to get:

"A is required when B is empty."
"A is required when C is empty."

So, it seems like the validation code does a distinct on the attributes based on type because it ignores the 2nd one. This is further proven if I do:

    [RequiredIfEmpty("B")]
    [RequiredIfEmpty2("C")]
    public string A { get; set; }
    public string B { get; set; }
    public string C { get; set; }

RequiredIfEmpty2 is just derived from RequiredIfEmpty, no additional code. Now I get the expected:

"A is required when B is empty."
"A is required when C is empty."

In this example, I only have 2 dependent properties, so no biggie to create a 2 version, but its very hacky and I don't like it.

I thought about changing the RequiredIfEmpty attribute to take a string[] of properties, but it doesn't appear like the MVC infrastructure would allow multiple error strings returned by a single attribute.

I did report it to Microsoft, but wondering if anybody else can think of a work-around besides having a 2 version?

like image 917
SledgeHammer Avatar asked Jan 28 '26 13:01

SledgeHammer


1 Answers

.Net Core + .Net Framework

You can override the Equals and GetHashCode methods in the attribute to create distinctions between AllowMultiple attributes.

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = false)]
public sealed class RequiredIfEmptyAttribute : RequiredAttribute
{
    private object _instance = new object();

    public override bool Equals(object obj) => _instance.Equals(obj);

    public override int GetHashCode() => _instance.GetHashCode();

    // all the rest of the code
}

.Net Framework Only

If you're only targeting the .Net Framework, you can use the TypeId property to be a unique identifier between two attributes of the same type. (MSDN documentation)

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = false)]
public sealed class RequiredIfEmptyAttribute : RequiredAttribute
{
    public override object TypeId { get; } = new object();

    // all the rest of the code
}

I thought about changing the RequiredIfEmpty attribute to take a string[] of properties, but it doesn't appear like the MVC infrastructure would allow multiple error strings returned by a single attribute.

Correct. You cannot return more than one message per attribute. You could implement the IValidatableObject interface to achieve this, however.

like image 142
Will Ray Avatar answered Jan 30 '26 03:01

Will Ray



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!