Reputation: 7690
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?
Upvotes: 3
Views: 2641
Reputation: 10879
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
}
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.
Upvotes: 2