是否可以将 RequiredAttribute 绑定到函数?
Is it possible to bind A RequiredAttribute to a function?
public partial class TaskScheduling
{
public Guid EvaluationTemplateId { get; set; }
//[Required(ErrorMessage = "TaskScheduling.OwnerUser")]
[Required(ErrorMessage = ResolveErrorMessage())]
public string SenderName { get; set; }
[Required]
public string SenderMail { get; set; }
[Required]
public string Subject { get; set; }
[Required]
public string BodyMessage { get; set; }
private string ResolveErrorMessage()
{
//Code to customize the error message here.
return "test";
}
}
我正在尝试将错误消息绑定到一个函数,这样我就可以自定义要显示的消息类型。
但是当我尝试将错误消息设置为函数 ResolveErrorMessage 时,编译器说:需要对象引用才能访问非静态字段、方法或 属性 'TaskScheduling.ResolveErrorMessage()'.
因此我尝试将 ResolveErrorMessage 设置为静态函数。
private static string ResolveErrorMessage()
{
//Code to customize the error message here.
return "test";
}
现在编译器抱怨如下:
属性参数必须是常量表达式 typeof 表达式或数组创建表达式。
那么,我尝试做的事情是否可行?
如评论中所述,这是不可能的。该值需要在编译时知道。此外,运行时如何知道何时调用此方法,以及如何在没有任何可用数据的情况下自定义它,例如无效值。
还有其他解决方法,但这取决于您要自定义错误消息的程度。
1。简单案例 - 内置消息格式
在最简单的情况下,您可以简单地在消息文本中添加一个 {0}
占位符,用于放置 属性 名称的位置:
[Required(ErrorMessage = "Please enter {0}!")]
public string SenderName { get; set; }
或者,如果您想稍后更新错误消息而不重新编译代码,您可以引用资源字符串而不是硬编码的消息文本,使用 ErrorMessageResourceType
和 ErrorMessageResourceName
属性:
[Required(ErrorMessageResourceType = typeof(MyMessageResources), ErrorMessageResourceName = "SenderNameRequiredMessage")]
public string SenderName { get; set; }
2。自定义逻辑 - 不调用经过验证的实例
如果您 需要逻辑来自定义错误消息,您最好创建 RequiredAttribute
的子 class 并覆盖属性或方法根据需要在那里添加逻辑。
例如,如果出于某些不明确的原因您想将星期几添加到错误消息中,您可以覆盖 FormatErrorMessage()
来执行此操作:
public class DayOfWeekRequiredAttribute : RequiredAttribute
{
public override string FormatErrorMessage(string propertyName)
{
string day = DateTime.Today.DayOfWeek.ToString();
return string.Format(this.ErrorMessage, propertyName, day);
}
}
public partial class TaskScheduling
{
// {0} is property name, {1} is day of week
[DayOfWeekRequired(ErrorMessage = "Hey, it's {1} and {0} is a required field!")]
public string SenderName { get; set; }
}
你可以让它更通用一点,并传递一个负责解析错误消息的类型,这样你就不需要很多 XXXXRequireAttribute
classes:
// interface representing a class for resolving the error message
public interface IErrorMessageResolver
{
// The attribute will call this method
string ResolveErrorMessage(string propertyName, object value);
}
public class MessageResolverRequiredAttribute : RequiredAttribute
{
// Stores the type responsible for resolving the error message
public Type MessageResolverType { get; set; }
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
// call the built-in RequiredAttribute validator
ValidationResult result = base.IsValid(value, validationContext);
// if not valid, attempt to get the custom error message
if (!result.Equals(ValidationResult.Success))
{
if (this.MessageResolverType != null)
{
// create the resolver and check it actually is a resolver
IErrorMessageResolver handler = Activator.CreateInstance(this.MessageResolverType) as IErrorMessageResolver;
if (handler == null)
{
throw new Exception("MessageResolverType is not an IErrorMessageResolver");
}
// get the custom error message, if returns null, don't override the built-in error message
string customError = handler.ResolveErrorMessage(validationContext.MemberName, value);
if (customError != null)
{
result.ErrorMessage = customError;
}
}
}
return result;
}
}
public partial class TaskScheduling
{
[MessageResolverRequired(MessageResolverType = typeof(MyMessageResolver))]
public string SenderName { get; set; }
}
3。自定义逻辑 - 使用经过验证的实例
要向正在验证自身的实例询问错误消息,您可以使用与上述通用自定义逻辑相同的主体,但它将是需要实现的实例 IErrorMessageResolver
。您可以使用 validationContext.ObjectInstance
属性 来获取它。我会说这真的只有在您需要在实例中使用 private
数据来创建错误消息时才有用。否则它有点奇怪,非 SOLID 模式。
// interface representing a class for resolving the error message
public interface IErrorMessageResolver
{
// The attribute will call this method
string ResolveErrorMessage(string propertyName, object value);
}
public class MessageResolverRequiredAttribute : RequiredAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
ValidationResult result = base.IsValid(value, validationContext);
if (!result.Equals(ValidationResult.Success))
{
IErrorMessageResolver handler = validationContext.ObjectInstance as IErrorMessageResolver;
if (handler == null)
{
throw new Exception("Not validating an IErrorMessageResolver");
}
string customError = handler.ResolveErrorMessage(validationContext.MemberName, value);
if (customError != null)
{
result.ErrorMessage = customError;
}
}
return result;
}
}
public partial class TaskScheduling
: IErrorMessageResolver
{
[MessageResolverRequired(MessageResolverType = typeof(MyMessageResolver))]
public string SenderName { get; set; }
public string ResolveErrorMessage(string propertyName, object value)
{
if (propertyName == "SenderName")
{
return "You need to set a Sender!";
}
return null;
}
}
public partial class TaskScheduling
{
public Guid EvaluationTemplateId { get; set; }
//[Required(ErrorMessage = "TaskScheduling.OwnerUser")]
[Required(ErrorMessage = ResolveErrorMessage())]
public string SenderName { get; set; }
[Required]
public string SenderMail { get; set; }
[Required]
public string Subject { get; set; }
[Required]
public string BodyMessage { get; set; }
private string ResolveErrorMessage()
{
//Code to customize the error message here.
return "test";
}
}
我正在尝试将错误消息绑定到一个函数,这样我就可以自定义要显示的消息类型。 但是当我尝试将错误消息设置为函数 ResolveErrorMessage 时,编译器说:需要对象引用才能访问非静态字段、方法或 属性 'TaskScheduling.ResolveErrorMessage()'.
因此我尝试将 ResolveErrorMessage 设置为静态函数。
private static string ResolveErrorMessage()
{
//Code to customize the error message here.
return "test";
}
现在编译器抱怨如下: 属性参数必须是常量表达式 typeof 表达式或数组创建表达式。
那么,我尝试做的事情是否可行?
如评论中所述,这是不可能的。该值需要在编译时知道。此外,运行时如何知道何时调用此方法,以及如何在没有任何可用数据的情况下自定义它,例如无效值。
还有其他解决方法,但这取决于您要自定义错误消息的程度。
1。简单案例 - 内置消息格式
在最简单的情况下,您可以简单地在消息文本中添加一个 {0}
占位符,用于放置 属性 名称的位置:
[Required(ErrorMessage = "Please enter {0}!")]
public string SenderName { get; set; }
或者,如果您想稍后更新错误消息而不重新编译代码,您可以引用资源字符串而不是硬编码的消息文本,使用 ErrorMessageResourceType
和 ErrorMessageResourceName
属性:
[Required(ErrorMessageResourceType = typeof(MyMessageResources), ErrorMessageResourceName = "SenderNameRequiredMessage")]
public string SenderName { get; set; }
2。自定义逻辑 - 不调用经过验证的实例
如果您 需要逻辑来自定义错误消息,您最好创建 RequiredAttribute
的子 class 并覆盖属性或方法根据需要在那里添加逻辑。
例如,如果出于某些不明确的原因您想将星期几添加到错误消息中,您可以覆盖 FormatErrorMessage()
来执行此操作:
public class DayOfWeekRequiredAttribute : RequiredAttribute
{
public override string FormatErrorMessage(string propertyName)
{
string day = DateTime.Today.DayOfWeek.ToString();
return string.Format(this.ErrorMessage, propertyName, day);
}
}
public partial class TaskScheduling
{
// {0} is property name, {1} is day of week
[DayOfWeekRequired(ErrorMessage = "Hey, it's {1} and {0} is a required field!")]
public string SenderName { get; set; }
}
你可以让它更通用一点,并传递一个负责解析错误消息的类型,这样你就不需要很多 XXXXRequireAttribute
classes:
// interface representing a class for resolving the error message
public interface IErrorMessageResolver
{
// The attribute will call this method
string ResolveErrorMessage(string propertyName, object value);
}
public class MessageResolverRequiredAttribute : RequiredAttribute
{
// Stores the type responsible for resolving the error message
public Type MessageResolverType { get; set; }
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
// call the built-in RequiredAttribute validator
ValidationResult result = base.IsValid(value, validationContext);
// if not valid, attempt to get the custom error message
if (!result.Equals(ValidationResult.Success))
{
if (this.MessageResolverType != null)
{
// create the resolver and check it actually is a resolver
IErrorMessageResolver handler = Activator.CreateInstance(this.MessageResolverType) as IErrorMessageResolver;
if (handler == null)
{
throw new Exception("MessageResolverType is not an IErrorMessageResolver");
}
// get the custom error message, if returns null, don't override the built-in error message
string customError = handler.ResolveErrorMessage(validationContext.MemberName, value);
if (customError != null)
{
result.ErrorMessage = customError;
}
}
}
return result;
}
}
public partial class TaskScheduling
{
[MessageResolverRequired(MessageResolverType = typeof(MyMessageResolver))]
public string SenderName { get; set; }
}
3。自定义逻辑 - 使用经过验证的实例
要向正在验证自身的实例询问错误消息,您可以使用与上述通用自定义逻辑相同的主体,但它将是需要实现的实例 IErrorMessageResolver
。您可以使用 validationContext.ObjectInstance
属性 来获取它。我会说这真的只有在您需要在实例中使用 private
数据来创建错误消息时才有用。否则它有点奇怪,非 SOLID 模式。
// interface representing a class for resolving the error message
public interface IErrorMessageResolver
{
// The attribute will call this method
string ResolveErrorMessage(string propertyName, object value);
}
public class MessageResolverRequiredAttribute : RequiredAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
ValidationResult result = base.IsValid(value, validationContext);
if (!result.Equals(ValidationResult.Success))
{
IErrorMessageResolver handler = validationContext.ObjectInstance as IErrorMessageResolver;
if (handler == null)
{
throw new Exception("Not validating an IErrorMessageResolver");
}
string customError = handler.ResolveErrorMessage(validationContext.MemberName, value);
if (customError != null)
{
result.ErrorMessage = customError;
}
}
return result;
}
}
public partial class TaskScheduling
: IErrorMessageResolver
{
[MessageResolverRequired(MessageResolverType = typeof(MyMessageResolver))]
public string SenderName { get; set; }
public string ResolveErrorMessage(string propertyName, object value)
{
if (propertyName == "SenderName")
{
return "You need to set a Sender!";
}
return null;
}
}