从 C# 中的 StringLengthAttribute 获取当前长度

Get the current length from StringLengthAttribute in C#

我在模型中有 ASP.NET 个网站属性:

[Required]
[Display(Name = "bla bla")]
[MinMaxLength(50,2000)]
public string TextDetail { get; set; }

而且我已经本地化了

public class MinMaxLengthAttribute : StringLengthAttribute
{
    public MinMaxLengthAttribute(int minimum, int maximum)
       :base(maximum)
    {
        ErrorMessage = "{0} must contain from  {2} to {1} characters."; //this text is localized, that is why I need to use special class
        MinimumLength = minimum;
    }
}

当我查看日志时,我可以找到

Exception (level 0):
Message = bla bla must contain from 50 to 2000 characters.

如果用户写的字符串太短或太长,我想记录。有没有办法在 StringLengthAttribute 中记录字符串的当前长度?

最后,解决方法很简单:

public class MinMaxLengthAttribute : StringLengthAttribute
{
    int? _stringLength = null;

    public MinMaxLengthAttribute(int minimum, int maximum)
        : base(maximum)
    {
        SetErrorMessage();
        MinimumLength = minimum;
    }

    void SetErrorMessage()
    {
        ErrorMessage = "{0} must contain {2} to {1} characters." +
               " It contains " + (_stringLength ?? -1) + " characters.";
    }

    public override bool IsValid(object value)
    {
        string s = value as string;
        if (s != null)
        {
            _stringLength = s.Length;
            SetErrorMessage();
        }

        return base.IsValid(value);
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        string s = value as string;
        if (s != null)
        {
            _stringLength = s.Length;
            SetErrorMessage();
        }

        return base.IsValid(value, validationContext);
    }        
}

和单元测试:

using Common.Validators;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace Test.Model
{
    [TestClass]
    public class UnitTestDtaValidation
    {
        [TestMethod]
        public void TestMinMaxLengthAttribute()
        {
            MyModel model = new MyModel()
            {
                TextDetail = "a"
            };

            var validationContext = new ValidationContext(model, serviceProvider: null, items: null);
            var results = new List<ValidationResult>();
            var isValid = System.ComponentModel.DataAnnotations.Validator.TryValidateObject(model, validationContext, results, true);

            Assert.IsFalse(isValid);

            Assert.AreEqual(1, results.Count);

            Assert.AreEqual("Description must contain from 5 to 10 characters. It contains 1 characters.", results[0].ErrorMessage);
        }
    }

    public class MyModel
    {
        [Required]
        [Display(Name = "Description")]
        [MinMaxLength(5, 10)]
        public string TextDetail { get; set; }
    }

}

您可以像下面这样使用 StringLengthAttribute

[Required]
[Display(Name = "bla bla")]
[StringLength(20000, MinimumLength = 50, ErrorMessage = "{0} must contain from  {2} to {1} characters.")]
public string TextDetail { get; set; }

而且,如果要显示当前无效值,可以使用jQuery。不需要服务器端代码来做这么简单的事情。

StringLengthAttribute class 继承自 ValidationAttribute ,可以使用 ErrorMessageResourceTypeErrorMessageResourceName 从资源字符串本地化。所以你的例子变成:

public class MyModel
{
    [Required]
    [Display(Name = "Description")]
    [StringLength(10, MinimumLength = 5, ErrorMessageResourceType = typeof(MyStringsResource), ErrorMessageResourceName = "MyTextDetailErrorMessage"]
    public string TextDetail { get; set; }
}

并且在您本地化的 MyStringsResource 资源中,将名为 MyTextDetailErrorMessage 的字符串设置为 "{0} must contain {2} to {1} characters.".

如果您需要派生的 class 中的更动态的消息,您可以使用受保护的重载 ValidationAttribute(Func<string> errorMessageAccessor) 构造 MinMaxLengthAttribute 实例,它允许您提供一个函数来查找错误信息。抱歉,我没有经验可以分享。