FluentValidation.NET 等同于 [Display(Name)]
FluentValidation.NET equivalent to [Display(Name)]
在 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");
但这不起作用。为什么?
FluentValidation 中的 WithName
方法仅用于调整验证错误消息,如果您想将 C# 属性 名称替换为更用户友好的名称(请参阅
覆盖默认 属性 名称 以获取详细信息)。
所以答案是 - 通常不能将 Display
替换为 WithName()
,仅用于验证错误消息。
如果有帮助,我将一些属性和助手组合在一起,使其更加动态。
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);
});
}
在 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");
但这不起作用。为什么?
WithName
方法仅用于调整验证错误消息,如果您想将 C# 属性 名称替换为更用户友好的名称(请参阅
覆盖默认 属性 名称 以获取详细信息)。
所以答案是 - 通常不能将 Display
替换为 WithName()
,仅用于验证错误消息。
如果有帮助,我将一些属性和助手组合在一起,使其更加动态。
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);
});
}