Model和ViewModel的验证最佳实践

本文关键字:最佳 验证 ViewModel Model | 更新日期: 2023-09-27 18:00:31

我有单独的模型和视图模型类。其中,视图模型类只进行UI级别的验证(请参阅:validation:Model或viewmodel)。

我可以在控制器中的后期操作中验证模型(vewmodel)是否有效。

问题:如何验证模型(带有数据注释的主要实体)

我没有使用模型对象开发视图模型。只是复制属性并添加该特定视图中可能需要的所有属性。

//Model Class
public class User
{
    [Required]
    public string Email {get; set;}
    [Required]
    public DateTime Created {get; set;}
}
//ViewModel Class
public class UserViewModel
{
    [Required]
    public string Email {get; set;}
    [Required]
    public string LivesIn {get; set;}
}
//Post action
public ActionResult(UserViewModel uvm)
{
    if( ModelState.IsValid)
        //means user entered data correctly and is validated
    User u = new User() {Email = uvm.Email, Created = DateTime.Now};
    //How do I validate "u"?
    return View();
}

应该这样做:

var results = new List<ValidationResult>();
var context = new ValidationContext(u, null, null);
var r = Validator.TryValidateObject(u, context, results);

我想的是在(业务实体的)基类中添加这种验证技术,并在从视图模型类映射到业务实体时对其进行验证。

有什么建议吗?

Model和ViewModel的验证最佳实践

1)对从用户检索信息的模型使用fluent验证。它比数据注释更灵活,更易于测试。

2) 您可能想要研究automapper,通过使用automapper您不必编写x.name = y.name

3) 对于您的数据库模型,我将坚持使用数据注释。

以下内容均基于新信息

首先,你应该像现在一样在两个位置进行实际模型验证,这就是我的做法。免责声明:这不是完美的方式

首先将UserViewModel更新为

public class UserViewModel
    {
        [Required()]
        [RegularExpression(@"^(([A-Za-z0-9]+_+)|([A-Za-z0-9]+'-+)|([A-Za-z0-9]+'.+)|([A-Za-z0-9]+'++))*[A-Za-z0-9]+@(('w+'-+)|('w+'.))*'w{1,63}'.[a-zA-Z]{2,6}$")]
        public String Email { get; set; }
    }

然后将操作方法更新为

        // Post action
        [HttpPost]
        public ActionResult register (UserViewModel uvm)
        {
            // This validates the UserViewModel
            if (ModelState.IsValid)
            {
                try
                {
                    // You should delegate this task to a service but to keep it simple we do it here
                    User u = new User() { Email = uvm.Email, Created = DateTime.Now };
                    RedirectToAction("Index"); // On success you go to other page right?
                }
                catch (Exception x)
                {
                    ModelState.AddModelError("RegistrationError", x); // Replace x with your error message
                }
            }       
            // Return your UserViewModel to the view if something happened               
            return View(uvm);
        }

现在,对于用户模型,它变得很棘手,并且您有许多可能的解决方案。我想出的解决方案(可能不是最好的)如下:

public class User
    {
        private string email;
        private DateTime created;
        public string Email
        {
            get
            {
                return email;
            }
            set
            {
                email = ValidateEmail(value);
            }
        }
        private string ValidateEmail(string value)
        {
            if (!validEmail(value))
                throw new NotSupportedException("Not a valid email address");     
            return value;
        }
        private bool validEmail(string value)
        {
            return Regex.IsMatch(value, @"^(([A-Za-z0-9]+_+)|([A-Za-z0-9]+'-+)|([A-Za-z0-9]+'.+)|([A-Za-z0-9]+'++))*[A-Za-z0-9]+@(('w+'-+)|('w+'.))*'w{1,63}'.[a-zA-Z]{2,6}$");
        }

最后一个单元测试来检查我自己的代码:

   [TestClass()]
    public class UserTest
    {
        /// <summary>
        /// If the email is valid it is stored in the private container
        /// </summary>
        [TestMethod()]
        public void UserEmailGetsValidated()
        {
            User x = new User();
            x.Email = "test@test.com";
            Assert.AreEqual("test@test.com", x.Email);
        }
        /// <summary>
        /// If the email is invalid it is not stored and an error is thrown in this application
        /// </summary>
        [TestMethod()]
        [ExpectedException(typeof(NotSupportedException))]
        public void UserEmailPropertyThrowsErrorWhenInvalidEmail()    
       {
           User x = new User();
           x.Email = "blah blah blah";
           Assert.AreNotEqual("blah blah blah", x.Email);
       }

        /// <summary>
        /// Clears an assumption that on object creation the email is validated when its set
        /// </summary>
        [TestMethod()]
        public void UserGetsValidatedOnConstructionOfObject()
        {
            User x = new User() { Email = "test@test.com" };
            x.Email = "test@test.com";
            Assert.AreEqual("test@test.com", x.Email);
        }
    }

我认为最好使用数据注释看看这个

ASP.NET MVC Valvation

对于服务器端验证,您可以使用fluent验证

看看这个问题