Make MVC class property/class required conditional

2019-08-05 16:06发布

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?

3条回答
Deceive 欺骗
2楼-- · 2019-08-05 16:43

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

查看更多
走好不送
3楼-- · 2019-08-05 16:48

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;
        }
查看更多
地球回转人心会变
4楼-- · 2019-08-05 16:48

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.

查看更多
登录 后发表回答