I have an Address class that is used for both a MailingAddress and BillingAddress property in my Model. I want the MailingAddress to be required, but not the BillingAddress, but am not seeing a way to do this with DataAnnotations.
If I were able to set the [Required] attribute on the MailingAddress property and somehow define the logic for how the Address class is supposed to handle the required logic, I feel like that would be a simple solution.
Any ideas?
If your question is how to use the Required attribute in your own logic, the answer is by use of reflection. Forgive me if that is not your question.
Get all properties from the type in question, then see if it is decorated with a RequiredAttribute or not.
class ParentClass
{
[Required]
public Address MailingAddress { get; set; }
public Address BillingAddress { get; set; }
}
(...)
Type t = typeof(ParentClass);
foreach (PropertyInfo p in t.GetProperties())
{
Attribute a = Attribute.GetCustomAttribute(p, typeof(RequiredAttribute));
if (a != null)
{
// The property is required, apply your logic
}
else
{
// The property is not required, apply your logic
}
}
Edit: Fixed a typo in code
Edit 2: Extended code example
This is just an odd quirk which popped into my head:
A simple solution might be to subclass Address to OptionalAddress.
I don't think the Required attributes would be inherited to the child class.
[AttributeUsage (Inherited = False)]
also comes to mind if needed.
A more MVCish solution might be to implement a custom model binder (completely untested):
public override object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
var address = base.BindModel(controllerContext, bindingContext) as Address;
if (bindingContext.ModelName.EndsWith("BillingAddress"))
{
foreach (PropertyInfo p in address.GetType().GetProperties())
{
Attribute a = Attribute.GetCustomAttribute(p, typeof(RequiredAttribute));
if (a != null
&& propertyInfo.GetValue(address, null) == null
&& bindingContext.ModelState[bindingContext.ModelName
+ "." + p.Name].Errors.Count == 1)
{
bindingContext.ModelState[bindingContext.ModelName + "." + p.Name].Errors.Clear();
}
}
return address;
}
Many options available at this previously asked question:
ASP.NET MVC Conditional validation
Do you need this validation done on the client side or not?
IValidateableObject will be used in conjunction with any of your existing attributes and can provide for the additional custom validation.