简体   繁体   English

服务器端自定义数据注释验证MVC 3

[英]Server Side Custom Data Annotation Validation MVC 3

I have been trying to make an EmailAddress custom data annotation attribute properly validate emails, and it doesn't seem to be working for me in my tests. 我一直在尝试使EmailAddress自定义数据注释属性正确地验证电子邮件,并且在我的测试中似乎不起作用。

Here's the test: 这是测试:

    [Test]
    public void ModelStateValidation()
    {
        var invalidEmails = new[] { "testtestcom", "test@testcom", "testtest.com" };
        var validEmail = "test@test.com";

        //Invalid Email addresses 
        foreach (var invalidEmail in invalidEmails)
        {
            var subscription = new SubscriberModel() { FirstName = "f", LastName = "l", Email = invalidEmail, ConfirmEmail = invalidEmail, DateSubscribed = DateTime.Now };
            ValidateModelAsFalse(subscription);
        }

        var subscription2 = new SubscriberModel() { FirstName = "f", LastName = "l", Email = "t", ConfirmEmail = "t", DateSubscribed = DateTime.Now };
        ValidateModelAsFalse(subscription2);

        //Valid Email address
        var subscription3 = new SubscriberModel() { FirstName = "f", LastName = "l", Email = validEmail, ConfirmEmail = validEmail, DateSubscribed = DateTime.Now };
        ValidateModelAsTrue(subscription3);

        //Last Name doesn't exists
        var subscription4 = new SubscriberModel() { FirstName = "f", LastName = "", Email = validEmail, ConfirmEmail = validEmail, DateSubscribed = DateTime.Now };
        ValidateModelAsFalse(subscription4);

        //First Name doesn't exists
        var subscription5 = new SubscriberModel() { FirstName = "", LastName = "l", Email = validEmail, ConfirmEmail = validEmail, DateSubscribed = DateTime.Now };
        ValidateModelAsFalse(subscription5);

        //Email addresses are equal
        var subscription6 = new SubscriberModel() { FirstName = "f", LastName = "l", Email = "test@test.com", ConfirmEmail = "test2@test.com", DateSubscribed = DateTime.Now };
        ValidateModelAsFalse(subscription6);
    }

    private static void ValidateModelAsFalse(SubscriberModel subscription3)
    {
        SubscriptionController controller = new SubscriptionController();
        controller.ValidateModel(subscription3);
        AssertIsFalse(controller);
    }

    private static void ValidateModelAsTrue(SubscriberModel subscription3)
    {
        SubscriptionController controller = new SubscriptionController();
        controller.ValidateModel(subscription3);
        AssertIsTrue(controller);
    }

    private static void AssertIsTrue(SubscriptionController controller)
    {
        Assert.That(controller.ModelState.IsValid, Is.True);
    }

    private static void AssertIsFalse(SubscriptionController controller)
    {
        Assert.That(controller.ModelState.IsValid, Is.False);
    }

Here's the ValidateModel method: 这是ValidateModel方法:

<!-- language: c# -->
public static void ValidateModel<T>(this Controller controller, T model)
    {
        var validationContext = new ValidationContext(model, null, null);
        var validationResults = new List<ValidationResult>();
        Validator.TryValidateObject(model, validationContext, validationResults);
        foreach (var validationResult in validationResults)
        {
            controller.ModelState.AddModelError(validationResult.MemberNames.First(), validationResult.ErrorMessage);
        }
    }

Model: 模型:

<!-- language: c# -->
public partial class SubscriberModel
{
    public int SubscriberID { get; set; }

    [Required]
    [DisplayName("First Name")]
    public string FirstName { get; set; }

    [Required]
    [DisplayName("Last Name")]
    public string LastName { get; set; }

    [Required]
    [EmailAddress]
    [Compare("ConfirmEmail", ErrorMessage = "The emails must match")]
    [DisplayName("E-mail")]
    public string Email { get; set; }

    [Required]
    [DisplayName("Confirm E-mail")]
    public string ConfirmEmail { get; set; }

    [Required]
    [DisplayName("Date Subscribed")]
    public DateTime DateSubscribed { get; set; }
}

Controller: 控制器:

    public partial class SubscriptionController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    [CaptchaValidator]
    [HttpPost]
    public ActionResult Index(SubscriberModel subscription, bool captchaValid)
    {
        subscription.DateSubscribed = DateTime.Now;
        ModelStateValid = ModelState.IsValid;

        if(captchaValid)
        {
            if (ModelState.IsValid)
            {
                var test = "";
            }
        }

        return View(subscription);
    }
}

EmailAttribute class: EmailAttribute类:

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
public sealed class EmailAddressAttribute : ValidationAttribute, IClientValidatable
{ 
    private static Regex _regex = new Regex(@"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);

    public EmailAddressAttribute()
        : base()
    {
        ErrorMessage = "Invalid Email";
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) {
        yield return new ModelClientValidationRule {
            ValidationType = "email",
            ErrorMessage = FormatErrorMessage(metadata.GetDisplayName())
        };
    }

    public override bool IsValid(object value) 
    {
        if (value == null) {
            return false;
        }

        string valueAsString = value as string;
        return _regex.Match(valueAsString).Success;
    }
}

The IsValid method seems to validate email addresses as I intend, but for some reason when I go to run the unit test on the Controller.ValidateModel, it doesn't return false and match my Assertion. IsValid方法似乎可以按预期验证电子邮件地址,但是由于某些原因,当我在Controller.ValidateModel上运行单元测试时,它不会返回false并匹配我的断言。

I used something like this once and implementing the IClientValidatable interface was just the first step. 我曾经使用过类似的东西,而实现IClientValidatable接口只是第一步。 then I had to add jQuery validation on the client side. 然后我必须在客户端添加jQuery验证。 I think that custom validations can only be executed on the client using jQuery 我认为自定义验证只能在使用jQuery的客户端上执行

here is an example: 这是一个例子:

<script type="text/javascript">
    (function ($) {
        $.validator.addMethod("yourValidationTypeName", function (value, element) {
            //do validation here
        });
        $.validator.unobtrusive.adapters.addBool("yourValidationTypeName");
    } (jQuery));
</script>

Using the built in attribute [Regularexpression] with unobtusive javascript and client validation enabled might solve your problem. 使用内置属性[Regularexpression]并启用清晰的JavaScript并启用客户端验证可能会解决您的问题。

Correct me if I'm wrong, but I'm not an expert with MVC3 如果我错了,请纠正我,但我不是MVC3的专家

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM