【问题标题】:How to get property name by one of it's attributes' value using reflection or how to get property info of data property which is currently validating?如何使用反射通过属性值之一获取属性名称或如何获取当前正在验证的数据属性的属性信息?
【发布时间】:2014-01-30 22:07:33
【问题描述】:

我想编写自定义验证属性,并在验证结果中添加有验证错误的其他成员名称。问题是我想根据属性名称和无效的匹配属性索引或键(我想验证 IEnumerables 或 IDictionaries)动态生成成员名称,例如 Names[0]Names[1]Names[key] 等。例如:

型号:

public class ModelClass
{
    [ItemMaxLength(10)]
    [Display(ResourceType = typeof(CategoriesRename), Name = "CategoryNamesFieldName")]
    public IDictionary<string, string> Names { get; set; }
}

属性:

public class ItemMaxLengthAttribute : ValidationAttribute
{
    private readonly int _maxLength = int.MaxValue;

    public ItemMaxLengthAttribute(int maxLength)
    {
        _maxLength = maxLength;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        ...
        // I can get instance and it's type from validation context
        var instance = validationContext.ObjectInstance; // which is instance of ModelClass
        var instanceType = validationContext.ObjectType; //which is typeof(ModelClass)
        var dispayName = validationContext.DisplayName; //which is value of Display attribute
        ...
    }
}

所以主要思想是(我不喜欢它)让当前属性通过它的DysplayName 属性值(dispayName)进行验证。我有点卡在这里一段时间。也许还有其他方法可以获取正在验证的属性的属性信息?

P.S.我已经尝试过MemberName 属性,正如Alexandre Rondeau 所建议的那样,但问题是validationContext.MemberName = null 所以它不能被使用。 MSDN 还说 此属性表示实体成员名称,而不是相应数据字段的名称,我需要 相应数据字段的名称

【问题讨论】:

  • 1) 在您的示例 ModelClass 中,[ItemMaxLength] 未应用于 Names 属性。您在哪里应用验证属性? 2) 当您在该示例中说 相应数据字段的名称 时,该名称是什么?不是名字吗?
  • @AlexandreRondeau, 1) 我已经将属性应用于Names 属性(我可能只是忘记在示例中演示它)2) 是的,它是Names。 .. 应该是...但是validationContext.MemberNamenull。所以我在获取 Names 时遇到了一些麻烦。

标签: c# asp.net-mvc validation reflection properties


【解决方案1】:

使用该代码,两个测试都通过了,所以 MemberName 不为空。

[TestClass]
public class RefectionInValidationTest
{
    [TestMethod]
    public void GivenAModelWithItemMaxAttributeOnFieldName_WhenValidating_ThenModelClassIsValid()
    {
        //Arange
        var validModelClass = new ModelClass();
        var validations = new Collection<ValidationResult>();

        //Act
        var isValid = Validator.TryValidateObject(validModelClass, new ValidationContext(validModelClass, null, null), validations, true);

        //Assert
        Assert.IsTrue(isValid);
    }

    [TestMethod]
    public void GivenAModelWithItemMaxAttributeOnFieldNotName_WhenValidating_ThenModelClassIsInvalid()
    {
        //Arange
        var invalidaModelClass = new InvalidModelClass();
        var validations = new Collection<ValidationResult>();

        //Act
        var isValid = Validator.TryValidateObject(invalidaModelClass, new ValidationContext(invalidaModelClass, null, null), validations, true);

        //Assert
        Assert.IsFalse(isValid);
    }
}

public class ModelClass
{
    [ItemMaxLength(10)]
    public IDictionary<string, string> Names { get; set; }
}
public class InvalidModelClass
{
    [ItemMaxLength(10)]
    public IDictionary<string, string> NotNames { get; set; }
}

public class ItemMaxLengthAttribute : ValidationAttribute
{
    private readonly int _maxLength = int.MaxValue;

    public ItemMaxLengthAttribute(int maxLength)
    {
        _maxLength = maxLength;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var propretyInfo = validationContext.ObjectType.GetProperty(validationContext.MemberName);
        if (propretyInfo.Name == "Names")
            return ValidationResult.Success;

        return new ValidationResult("The property isn't 'Names'");
    }
}

【讨论】:

  • validationContext.MemberName 为空。所以它只是抛出ArgumentNullException
  • 我已经发布了我的测试类代码。包括所有班级。您能否运行这两个测试并告诉我它们是否通过了您的系统。
【解决方案2】:

您必须使用validationContext.MemberName 属性。

例子:

protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
        var userManager = validationContext.GetService<UserManager<ApplicationUser>>();
        
        var findingTask = userManager.FindByEmailAsync((string)value);
        findingTask.Wait();

        var user = findingTask.Result;

        return user == null
                ? ValidationResult.Success
                : new ValidationResult("This email already in use", new string[] { validationContext.MemberName });
}

【讨论】:

    猜你喜欢
    • 2010-11-15
    • 2013-07-18
    • 2011-10-02
    • 2013-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多