【问题标题】:ASP.NET MVC ValidationAttribute Get Other Property Display NameASP.NET MVC ValidationAttribute 获取其他属性显示名称
【发布时间】:2011-12-07 09:08:19
【问题描述】:

我通过复制 ASP.NET MVC 3 CompareAttribute 创建了一个自定义的 CompareLessThan 验证属性,而不是检查相等性,而是检查一个属性是否小于另一个属性。如果出现客户端错误,则会向用户显示消息“{0} 必须小于 {1}”。

我的模型设置如下,显示属性引用资源文件。

[CompareLessThan("AmountAvailable", ErrorMessageResourceName="CompareLessThan", ErrorMessageResourceType = typeof(Resources.ValidationMessages))]
[Display(Name = "Amount", ResourceType = typeof(Resources.Labels))]
public decimal Amount { get; set; }

[Display(Name = "AmountAvailable", ResourceType = typeof(Resources.Labels))]
public decimal AmountAvailable { get; set; }

那么自定义验证GetClientValidationRules方法和CompareAttribute中的方法一模一样

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{            
    yield return new ModelClientValidationLessThanRule(FormatErrorMessage(metadata.DisplayName), FormatPropertyForClientValidation(OtherProperty), this.AllowEquality);
}

这里我们正在生成错误消息,如果出现问题,将向用户显示。我可以从用我的自定义 CompareLessThan 属性装饰的属性的资源文件中获取显示名称,但我的问题是如何获取我们正在比较的“其他”属性的显示名称?在 IsValid 方法中,我们有一个对 validationContext 的引用,我可以从中为“其他”属性生成一个 PropertyInfo 对象,并且我认为可以获取显示名称。但是,在 GetClientValidationRules 中我无权访问它。

我总是可以为另一个属性的显示名称传入另一个值,但我希望有一种方法可以派生它,因为我已经用数据注释指定了它。

有什么想法吗?

【问题讨论】:

    标签: asp.net-mvc validation client-side-validation validationattribute


    【解决方案1】:

    从 ASP.NET MVC 4 开始,这是我设法获得其他属性的方式:

    PropertyInfo otherPropertyInfo =
                      this.Metadata.ContainerType.GetProperty(attribute.DependentProperty);
    

    然后我从物业那里得到了Display attribute

    var displayAttribute =
        otherPropertyInfo.GetCustomAttributes(typeof(DisplayAttribute), true).
        FirstOrDefault() as DisplayProperty;
    

    在你的情况下:

    // GetName() is important to get the translated name if you're using a resource file...
    this.otherPropertyDisplayName = displayAttribute.GetName();
    

    GetName()参考:

    http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.displayattribute.name%28v=vs.95%29.aspx

    【讨论】:

    • 这意味着“作为 DisplayProperty”还是“作为 DisplayAttribute”?我的不适用于 DisplayProperty,但适用于 DisplayAttribute。否则很好的解决方案。
    • @MVCKarl:我认为你是对的......也许在这里输入答案时有点混乱。我无法准确记录我当时的所作所为。 :)
    【解决方案2】:

    nemesv 提供的答案不起作用,因为 metadata.Model 属性的值为 0。但是,通过元数据,我们确实拥有模型的全名,因此可以创建该模型的新实例然后从该创建实例创建一个新的 DataAnnonationsModelMetadataProvider 。从那里我们可以得到另一个属性的显示名称。

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        Type type = Type.GetType(metadata.ContainerType.FullName);
        var model = Activator.CreateInstance(type);
    
        var provider = new DataAnnotationsModelMetadataProvider();
        var otherMetaData = provider.GetMetadataForProperty(() => model, type, this.OtherProperty);
    
        this.otherPropertyDisplayName = otherMetaData.DisplayName;
    
        yield return new ModelClientValidationLessThanRule(FormatErrorMessage(metadata.DisplayName), FormatPropertyForClientValidation(this.OtherProperty), this.AllowEquality);
    }
    

    我真的不喜欢这个解决方案(即使它有效),因为它似乎应该有更好的方法。还有人有其他想法吗?

    【讨论】:

      【解决方案3】:

      我还没有尝试过,但是您可以使用 metadata.Properties 属性获取模型属性

      metadata.Properties.Single(p => p.PropertyName == "OtherPropName").DisplayName;
      

      编辑:因为 Properties 是空的,你总是可以做的(虽然它非常优雅)。您可以自己生成元数据。

      var provider = new DataAnnotationsModelMetadataProvider();
      var otherMetaData = provider.GetMetadataForProperty(() => metaData.Model, metaData.ModelType, "OtherPropertyName");
      

      【讨论】:

      • 好主意,但属性集合总是空的。
      • @NickOlsen 太可悲了。我已经用一些“解决方法”更新了我的答案。
      • 这也不起作用,因为 metadata.Model 属性只是值 0。使用您的逻辑,我能够找到另一种方法(请参阅其他答案),但我没有真喜欢它。我希望其他人可以提供更好的方法。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-07-23
      • 2020-09-06
      • 2011-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多