【问题标题】:FluentValidation.NET equivalent to [Display(Name)]FluentValidation.NET 等效于 [Display(Name)]
【发布时间】:2017-05-12 03:11:15
【问题描述】:

FluentValidation.NET 之前,我可以像这样给一个自定义标签:

[Display(Name="Blah")]
public string BlahBlahBlah { get; set; }

我可以通过多种方式使用它:

@Html.LabelFor(m => m.BlahBlahBlah)
@Html.DisplayNameFor(m => m.BlahBlahBlah)

<label asp-for="BlahBlahBlah"></label>

现在我想从我的模型中删除所有数据注释,并转向流畅的验证。在我的验证器中,我有这个:

RuleFor(o => o.BlahBlahBlah)
    .NotEmpty()
    .WithName("Blah");

但这不起作用。为什么?

【问题讨论】:

    标签: c# asp.net-mvc asp.net-core .net-core fluentvalidation


    【解决方案1】:

    FluentValidation 中的WithName 方法仅用于调整验证错误消息,如果您想替换 C# 属性名称以更加用户友好(请参阅 Overriding the Default Property Name 了解详细信息)。

    所以答案是 - 一般情况下,您不能将 Display 替换为 WithName(),仅用于验证错误消息。

    【讨论】:

    • 有没有办法使用 Fluent Validation 添加显示?
    • 不,这个库只用于验证。
    • 这是令人沮丧的信息。现在我希望这个库被称为“Fluent Annotation”!
    • 我想摆脱Display 属性的唯一简单选择是直接在Razor 中指定显示文本,其中一个重载为LabelFor。另一种方法是编写您的自定义 MyLabelFor 扩展方法,您可以在其中从任何您想要的来源获取文本。
    【解决方案2】:

    如果有帮助,我将一个小属性和助手放在一起,以使其更具动态性。

    WithDisplayNameAttribute.cs

    [AttributeUsage(AttributeTargets.Property)]
    public class WithDisplayNameAttribute : Attribute
    {
        public WithDisplayNameAttribute(string displayName)
        {
            DisplayName = displayName;
        }
    
        /// <summary>
        /// The preferred friendly name to display for this property during validation.
        /// </summary>
        public string DisplayName { get; set; }
    }
    

    WithDisplayNameHelper.cs

    internal static class WithDisplayNameHelper
    {
        public static IReadOnlyDictionary<string, string> Map { get; }
    
        static WithDisplayNameHelper()
        {
            var core = typeof(WithDisplayNameHelper).Assembly;
            var map = new Dictionary<string, string>();
            foreach (var parentModelType in core.GetExportedTypes().Where(x => x.IsClass))
            {
                foreach (var prop in parentModelType.GetProperties())
                {
                    var att = prop.GetCustomAttribute<WithDisplayNameAttribute>();
                    if (att == null) continue;
                    var key = GetKey(parentModelType, prop);
                    if (!map.ContainsKey(key))
                    {
                        map.Add(key, att.DisplayName);
                    }
                }
            }
    
            Map = new ReadOnlyDictionary<string, string>(map);
        }
    
        /// <summary>
        /// Gets the key to use for this property.
        /// </summary>
        /// <param name="parent">The parent class containing the property.</param>
        /// <param name="prop">The property described by the display name.</param>
        /// <returns></returns>
        private static string GetKey(Type parent, PropertyInfo prop) => GetKey(parent, prop.Name);
        
        /// <inheritdoc cref="GetKey(System.Type,System.Reflection.PropertyInfo)"/>
        private static string GetKey(Type parent, string prop) => $"{parent.FullName}.{prop}";
    
        /// <summary>
        /// Retrieves the display name if one was set using the <see cref="WithDisplayNameAttribute"/>. Otherwise will return the given <paramref name="propertyName"/>.
        /// </summary>
        /// <param name="parent">The parent class containing the property.</param>
        /// <param name="propertyName">The property name.</param>
        /// <returns></returns>
        public static string GetDisplayNameOrDefault(Type parent, string propertyName) =>
            Map.TryGetValue(GetKey(parent, propertyName), out var value)
            ? value
            : propertyName;
    
        /// <summary>
        /// Attempts to retrieve the display name if one was set using the <see cref="WithDisplayNameAttribute"/>.
        /// </summary>
        /// <inheritdoc cref="GetDisplayNameOrDefault"/>
        /// <returns></returns>
        public static bool TryGetDisplayName(Type parent, string propertyName, out string result) =>
            Map.TryGetValue(GetKey(parent, propertyName), out result);
    
    
    }
    

    以及扩展方法:

        /// <summary>
        /// Specifies a custom property name to use within the error message.
        /// </summary>
        /// <param name="rule">The current rule</param>
        /// <returns></returns>
        public static IRuleBuilderOptions<T, TProperty> WithDisplayName<T, TProperty>(
            this IRuleBuilderOptions<T, TProperty> rule)
        {
            
            return rule.Configure(x =>
            {
                if (WithDisplayNameHelper.TryGetDisplayName(typeof(T), x.PropertyName, out var displayName))
                    x.DisplayName = new StaticStringSource(displayName);
            });
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-30
      • 2018-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-17
      • 1970-01-01
      • 2020-09-23
      相关资源
      最近更新 更多