访问其他模型属性的自定义验证方法

时间:2015-01-23 23:12:43

标签: c# asp.net-mvc entity-framework validation

我尝试为我的某个实体创建自定义验证方法,因此我创建了一个继承自ValidationAttribute的类:

public class OneWheelchairPerTrainAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        // This is where I need to access the other entity property
    }
}

我正在努力解决的问题是如何访问实体上的其他属性。这是我的实体:

public class Ticket
{
    public int Id { get; set; }

    [Required]
    public int TimetableId { get; set; }

    [Required]
    public bool Wheelchair { get; set; }

    public virtual Timetable Timetable { get; set; }
}

我写的验证注释将应用于Wheelchair属性,我需要从验证方法中访问TimetableId属性。

2 个答案:

答案 0 :(得分:4)

您可以使用IsValid overload传递ValidationContext,如下所示:

public class OneWheelchairPerTrainAttribute : ValidationAttribute
{
  public override bool IsValid(object value, ValidationContext context)
  {
    Object instance = context.ObjectInstance;
    Type type = instance.GetType();
    // Here is your timetableId
    Object timeTableId = type.GetProperty("TimetableId ").GetValue(instance, null);

    //Do validation ...
   }
}

答案 1 :(得分:3)

另一种(在我看来,更好)验证多个属性的方法是在class级别上进行。

这与您的回答中的情况完全相同,但仍涉及多个属性验证。

想象一下,你想让轮椅成为身份或新对象,但你仍然只想允许一个:

我的ExactlyOneRequired属性示例:

[AttributeUsage(AttributeTargets.Class)]
public class ExactlyOneRequiredAttribute : ValidationAttribute
{
    public string FirstPropertyName { get; set; }
    public string SecondPropertyName { get; set; }

    //Constructor to take in the property names that are supposed to be checked
    public ExactlyOneRequiredAttribute(string firstPropertyName, string secondPropertyName)
    {
        FirstPropertyName = firstPropertyName;
        SecondPropertyName = secondPropertyName;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value == null) 
           return new ValidationResult("Object must have a value;");

        var neededProperties = validationContext.ObjectType.GetProperties().Where(propertyInfo => propertyInfo.Name == FirstPropertyName || propertyInfo.Name == SecondPropertyName).Take(2).ToArray();
        var value1 = neededProperties[0].GetValue(value);
        var value2 = neededProperties[1].GetValue(value);

        if (value1 == null | value2 == null)
            return ValidationResult.Success;

        return FailedValidationResult();
    }

    public override string FormatErrorMessage(string name) => $"One of the fields: '{FirstPropertyName} or {SecondPropertyName}' is required, it is not allowed to set both.";

    private ValidationResult FailedValidationResult() => new ValidationResult(FormatErrorMessage(FirstPropertyName), new List<string> {FirstPropertyName, SecondPropertyName});
}

用法:

[ExactlyOneRequired(nameof(WheelChairId), nameof(WheelChair))]
public class Train
{
    public int? WheelChairId { get; set; }

    public WheelChair WheelChair { get; set; }
}

您当然可以期望尽可能多的属性,并根据需要将其设为 generic 。我的观点是,不是字符串检查在属性中的属性名称,注入属性名称是 cleaner 的方式,