MVC中的验证规则和业务规则

时间:2015-04-25 14:59:21

标签: c# asp.net-mvc validation business-rules

我有一个MVC网络项目。根据最佳实践,添加验证规则和业务规则的正确位置在哪里?

验证规则将是必填字段和所需格式。

业务规则将是“此电子邮件已在数据库中使用”

以下是我目前在注册模式中执行此操作的方法:

public class RegisterModel : IValidatableObject
{
    [Display(Name = "Email address")]
    [Required(ErrorMessage = "The email address is required")]
    [EmailAddress(ErrorMessage = "Invalid Email Address")]
    public string Email { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        var retVal = new List<ValidationResult>();
        using (var entity = new AcademicUniteDatabaseEntities())
        {
            if (entity.UserProfiles.Any(x => x.UserName == this.Email))
            {
                retVal.Add(new ValidationResult("Email already exist", new List<string> { "Email" }));
            }
        }

        return retVal;
    }
}

这是我的注册管理员

    public ActionResult Register()
    {
        var model = new RegisterModel();
        return this.View(model);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Register(RegisterModel model)
    {
        if (!this.ModelState.IsValid)
        {
            return this.View(model);
        }

        model.CreateAccount();
        return this.View("WaitConfirmEmail");
    }

为什么我这样做

  1. 当我检查控制器中的ModelState.IsValid时,它将检查电子邮件的格式以及它是否已存在于数据库中。我没有在我的控制器中调用数据库,只在我的模型中。 (这是最佳做法吗?)
  2. 它还将“已存在的电子邮件”验证结果绑定到我的电子邮件属性,以便我可以在我的视图中显示验证结果。
  3. 这是最佳做法吗?

    1. 这是在MVC中添加业务规则的正确方法吗?
    2. 为什么或为什么不呢?
    3. 如果这不是最佳做法,您能否提供一个示例,说明如何最好地编程此注册模型以检查业务规则(如果电子邮件已存在)?

2 个答案:

答案 0 :(得分:2)

使用注释验证模型适用于需要验证的小型应用程序,但是当验证规则开始变得越来越复杂并且模型开始变得越来越复杂时,我建议您查看类似{{{}的库。 3}}。

通过属性验证模型的问题是它可能非常混乱,您将开始遭受大量重复;使用像Fluent验证这样的库所获得的好处是:

  • 让您保持模特干净整洁
  • 借助DI支持,创建更具可维护性和可重用性的验证规则。
  • 不像ModelState.IsValid那样绑定到UI,因此可以在业务逻辑层等中重复使用。

典型的Fluent验证规则示例:

public class CustomerValidator: AbstractValidator<Customer>
{
    public CustomerValidator()
    {
        RuleFor(customer => customer.Surname).NotEmpty();
        RuleFor(customer => customer.Forename).NotEmpty().WithMessage("Please specify a first name");
        RuleFor(customer => customer.Discount).NotEqual(0).When(customer => customer.HasDiscount);
        RuleFor(customer => customer.Address).Length(20, 250);
        RuleFor(customer => customer.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode");
    }

    private bool BeAValidPostcode(string postcode)
    {
        // custom postcode validating logic goes here
    }
}

Customer customer = new Customer();
CustomerValidator validator = new CustomerValidator();
ValidationResult results = validator.Validate(customer);

bool validationSucceeded = results.IsValid;
IList<ValidationFailure> failures = results.Errors;

答案 1 :(得分:0)

另一种方法是创建自定义验证器属性。使用您的解决方案,您可能会得到非常大的模型。另一种方法是创建可以插入控制器的静态助手。这里没有正确答案,它只是您组织代码的方式。我倾向于将业务逻辑分布在可以即插即用的自定义属性上。这样你就可以无缝地重构。