是否可以将A RequiredAttribute绑定到函数?

时间:2017-11-20 12:44:24

标签: c# validationattribute

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";
    }

现在编译器抱怨如下: 属性参数必须是表达式或数组创建表达式的常量表达式。

那么,我正在尝试做甚么可能吗?

1 个答案:

答案 0 :(得分:0)

如评论中所述,这是不可能的。需要在编译时知道该值。此外,运行时如何知道何时调用此方法,以及如何在没有任何可用数据的情况下自定义它,例如无效的值。

还有其他方法,但这取决于您想要自定义错误消息的程度。

1。简单案例 - 内置消息格式

在最简单的情况下,您只需在消息文本中添加{0}占位符,以便在何处放置属性名称:

[Required(ErrorMessage = "Please enter {0}!")]
public string SenderName { get; set; }

或者,如果您希望稍后更新错误消息而不使用ErrorMessageResourceTypeErrorMessageResourceName属性重新编译代码,则可以引用资源字符串而不是硬编码的消息文本:

[Required(ErrorMessageResourceType = typeof(MyMessageResources), ErrorMessageResourceName = "SenderNameRequiredMessage")]
public string SenderName { get; set; }

2。自定义逻辑 - 不调用验证的实例

如果你需要逻辑来自定义错误信息,你最好创建一个RequiredAttribute的子类,并根据需要覆盖属性或方法,以便在那里添加逻辑。 / p>

例如,如果由于某些不明原因您想在错误消息中添加星期几,则可以覆盖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个类:

// 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;
    }
}