65.9K
CodeProject 正在变化。 阅读更多。
Home

MVC4 中的模型验证

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.73/5 (20投票s)

2014年10月10日

CPOL

4分钟阅读

viewsIcon

140116

在本文中,我们将了解如何在 ASP.NET MVC 应用程序中为模型应用基本验证。

引言

最常见的 Web 应用程序安全弱点是未能正确验证来自客户端或环境的输入。绝不应该信任来自客户端的数据,因为客户端有各种可能性来篡改数据。因此,需要确保数据不仅得到验证,而且业务规则也是正确的。

本文介绍了如何在 ASP.NET MVC 应用程序中实现验证。我将使用一个简单的表单来演示 MVC4 中的基本验证。在这里,我们将看到从客户端和服务器端验证数据的不同方法。

基本上,本文包含以下方法:

  1. 使用数据注解 (Data Annotations)
  2. 使用 ModelState 对象(显式模型验证)
  3. 使用 jQuery 验证插件
  4. 使用 Fluent Validation 包

Using the Code

在 MVC 中,Model 是包含领域类和验证的类。验证在 Model 中起着核心作用。

首先,让我们创建一个带有示例模型、视图和控制器的应用程序。之后,我们将应用不同的方法来验证数据。

模型 (UserModel.cs)

namespace SampleApplication.Models
{
    public class UserModel
    {
        public string Name { get; set; }
        public string Email { get; set; }   
        public string MobileNo { get; set; }
    }
} 

视图 (User.cshtml)

@model SampleApplication.Models.UserModel
@{
    ViewBag.Title = "User Details";
}
<br /><br />
    @using (Html.BeginForm())
    {
       <fieldset>
        <legend>Form</legend>  
        <div class="form-group">
            @Html.LabelFor(model => model.Name, new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.TextBoxFor(model => model.Name, new { @class = "form-control" })                
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.Email, new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.TextBoxFor(model => model.Email, new { @class = "form-control" })
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.MobileNo, new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.TextBoxFor(model => model.MobileNo, new { @class = "form-control" })
            </div>
        </div>        
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" class="btn btn-default" value="OK" />
            </div>
        </div>
      </fieldset>
   }

控制器 (UserController.cs)

namespace SampleApplication.Controllers
{
    public class UserController : Controller
    {
        public ActionResult User()
        {
            return View();
        }
    }
}

 

使用数据注解 (Data Annotations)

在 ASP.NET MVC 中,验证模型的一种最佳方法是使用数据注解 (Data Annotations)。它在 System.ComponentModel.DataAnnotations 程序集中定义了一组属性和类。数据注解允许我们使用元数据来修饰模型类。这些元数据描述了一组用于验证属性的规则。

要使用 DataAnnotations,我们需要向模型类添加对 System.ComponentModel.DataAnnotations 程序集的引用。

using System.ComponentModel.DataAnnotations;

namespace SampleApplication.Models
{
    public class UserModel
    {
        [Required(ErrorMessage = "Please Enter Name")]
        [Display(Name = "Name")]
        public string Name { get; set; }
        
        [Required(ErrorMessage = "Please Enter Email Address")]
        [Display(Name = "Email")]
        [RegularExpression(@"^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$", 
        ErrorMessage = "Please Enter Correct Email Address")]
        public string Email { get; set; } 

        [Required(ErrorMessage = "Please Enter Mobile No")]
        [Display(Name = "Mobile")]
        [StringLength(10, ErrorMessage = "The Mobile must contains 10 characters", MinimumLength = 10)] 
        public string MobileNo { get; set; }
    }
} 

现在,我们需要启用 validationsummary 并在视图页面中添加验证消息。

@Html.ValidationSummary() 方法会在视图页面中显示模型的所有验证错误。

@Html.ValidationSummary(true)

@model SampleApplication.Models.UserModel
@{
    ViewBag.Title = "User Details";
}

<br /><br />

    @using (Html.BeginForm())
    {
       @Html.ValidationSummary(true)
       <fieldset>
        <legend>Form</legend>  
        <div class="form-group">
            @Html.LabelFor(model => model.Name, new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.TextBoxFor(model => model.Name, new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.Name)                
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.Email, new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.TextBoxFor(model => model.Email, new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.Email)
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.MobileNo, new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.TextBoxFor(model => model.MobileNo, new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.MobileNo) 
            </div>
        </div>        
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" class="btn btn-default" value="OK" />
            </div>
        </div>
      </fieldset>
    }

UserController.cs

namespace SampleApplication.Controllers
{
    public class UserController : Controller
    {
        public ActionResult User()
        {
            return View();
        }

        [HttpPost]
        public ActionResult ServerMeta(RegistrationMetaModel mRegister)
        {
            if (ModelState.IsValid)
            {
                return View("Completed");
            }
            else
            {            
                 return View();
            }
        }
    }
}

 

使用 ModelState 对象(显式模型验证)

如果你想显式地验证模型,那么在控制器中的 ActionMethod 中使用 ModelState Object 是最佳方法。只需以 (key, value) 对的形式向 ModelState 添加错误消息,当数据在模型中未经验证时,该消息将在视图中显示。

Model 类将显示如下:

namespace SampleApplication.Models
{
    public class UserModel
    {
        public string Name { get; set; }
        public string Email { get; set; }   
        public string MobileNo { get; set; }
    }
} 

现在我们将向 ModelState 对象添加 errormessage

using System.Text.RegularExpressions;
using System.Web.Mvc;
using SampleApplication.Models;

namespace SampleApplication.Controllers
{
    public class UserController : Controller
    {
        public ActionResult User()
        {
            return View();
        }
       
        [HttpPost]
        public ActionResult User(UserModel model)
        {
            if (string.IsNullOrEmpty(model.Name))
            {
                ModelState.AddModelError("Name", "Please Enter Name");
            }
            if (!string.IsNullOrEmpty(model.Email))
            {
                string emailRegex = @"^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$";
                Regex re = new Regex(emailRegex);
                if (!re.IsMatch(model.Email))
                {
                    ModelState.AddModelError("Email", "Please Enter Correct Email Address");
                }
            }
            else
            {
                ModelState.AddModelError("Email", "Please Enter Email Address");
            }
            if (string.IsNullOrEmpty(model.MobileNo))
            {
                ModelState.AddModelError("MobileNo", "Please enter your mobile no");
            }
            if (ModelState.IsValid)
            {
                return View("Completed");
            }
            else
            {            
                 return View();
            }
        }
    }
}

视图 User.cshtml 将显示如下验证消息:

@model SampleApplication.Models.UserModel
@{
    ViewBag.Title = "User Details";
}
<br /><br />
    @using (Html.BeginForm())
    {
       @Html.ValidationSummary(true)
       <fieldset>
        <legend>Form</legend>  
        <div class="form-group">
            @Html.LabelFor(model => model.Name, new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.TextBoxFor(model => model.Name, new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.Name)                
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.Email, new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.TextBoxFor(model => model.Email, new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.Email)
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.MobileNo, new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.TextBoxFor(model => model.MobileNo, new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.MobileNo) 
            </div>
        </div>        
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" class="btn btn-default" value="OK" />
            </div>
        </div>                                                                                                 </fieldset>
    }

 

使用 jQuery 验证插件

客户端验证有助于应用程序减少服务器负载,还可以节省最终用户的时间。因此,对于客户端验证,我们使用以下 jQuery 验证插件。

  1. jquery.validate.min.js
  2. jquery.validate.unobtrusive.min.js

如果这些文件不存在于 Scripts 文件夹中,请将它们添加到你的应用程序中。

Scripts

首先,我们需要在 web.config 文件中添加以下 config 设置:

<appSettings>
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>

在 MVC4 中,上述 appsetting 在 config 文件中默认是启用的。但在进行客户端验证之前,我们需要确保 ClientValidationEnabled UnobtrusiveJavaScriptEnabled 的值为 true

现在,我们可以编写 clientside JavaScript 代码来验证数据,或者使用Model 中的DataAnnotations 属性。

让我们利用客户端验证中的 DataAnnotations API。因此,将 DataAnnotations 添加到模型中。

UserModel.cs

using System.ComponentModel.DataAnnotations;

namespace SampleApplication.Models
{
    public class UserModel
    {
        [Required(ErrorMessage = "Please Enter Name")]
        [Display(Name = "Name")]
        public string Name { get; set; }
        
        [Required(ErrorMessage = "Please Enter Email Address")]
        [Display(Name = "Email")]
        [RegularExpression(@"^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$", 
        ErrorMessage = "Please Enter Correct Email Address")]
        public string Email { get; set; } 

        [Required(ErrorMessage = "Please Enter Mobile No")]
        [Display(Name = "Mobile")]
        [StringLength(10, ErrorMessage = "The Mobile must contains 10 characters", MinimumLength = 10)] 
        public string MobileNo { get; set; }
    }
} 

UserController.cs

namespace SampleApplication.Controllers
{
    public class UserController : Controller
    {
        public ActionResult User()
        {
            return View();
        }

        [HttpPost]
        public ActionResult ServerMeta(RegistrationMetaModel mRegister)
        {
            if (ModelState.IsValid)
            {
                return View("Completed");
            }
            else
            {            
                 return View();
            }
        }
    }
}

在创建 MVC 项目时,应用程序会在 App_Start 文件夹下添加一个 BundleConfig.cs 文件。此类用于将脚本和样式包含在捆绑包中。

BundleConfig.cs 文件中,将验证插件包含到 BundleCollection 对象中。

捆绑代码如下:

bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
                             "~/Scripts/jquery.validate*"));

新 MVC 4 项目创建的页面模板(_Layout.cshtml)在页面底部包含此代码,但未加载 jQuery 验证库。

@RenderSection("scripts", required: false)

为了“启用”单个视图的 jQuery 验证,以下代码需要位于视图的末尾。

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

User.cshtml

@model SampleApplication.Models.UserModel
@{
    ViewBag.Title = "User Details";
}
<br /><br />
    @using (Html.BeginForm())
    {
       @Html.ValidationSummary(true)
       <fieldset>
        <legend>Form</legend>  
        <div class="form-group">
            @Html.LabelFor(model => model.Name, new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.TextBoxFor(model => model.Name, new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.Name)                
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.Email, new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.TextBoxFor(model => model.Email, new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.Email)
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.MobileNo, new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.TextBoxFor(model => model.MobileNo, new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.MobileNo) 
            </div>
        </div>        
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" class="btn btn-default" value="OK" />
            </div>
        </div>                                                                                                 </fieldset>
    }
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

 

使用 Fluent Validation 包

FluentValidation 库提供了一种简单的方法来单元测试验证规则,可以将验证规则完全从底层模型中分离出来。特别是在需要将依赖项注入验证规则时,这会很有帮助。

现在我们将通过替换 Model 中的 DataAnnotations 来使用 FluentValidation 类库。

Fluent Validation 可作为 Nuget 包使用,因此搜索 FluentValidation.MVC4 并从 Nuget 包管理器中安装。安装后,你将在应用程序中找到两个新程序集,分别名为 Fluent Validation 和 Fluent Validation.Mvc。

FluentValidation

添加一个名为 UserModelValidator 的新类,并将所有验证规则放在其中。

namespace SampleApplication.Models
{
    public class UserModelValidator : AbstractValidator<UserModel>
    {
        public UserModelValidator()
        {
            RuleFor(x => x.Name)
                .NotNull();
            RuleFor(x => x.Email)
                .NotNull()
                .EmailAddress();
            RuleFor(x => x.MobileNo)
                .NotNull()
                .Length(6, 10);
         }
     }
?}

带有数据注解的现有模型

using System.ComponentModel.DataAnnotations;

namespace SampleApplication.Models
{
    public class UserModel
    {
        [Required(ErrorMessage = "Please Enter Name")]
        [Display(Name = "Name")]
        public string Name { get; set; }
        
        [Required(ErrorMessage = "Please Enter Email Address")]
        [Display(Name = "Email")]
        [RegularExpression(@"^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$", ErrorMessage = "Please Enter Correct Email Address")]
        public string Email { get; set; } 

        [Required(ErrorMessage = "Please Enter Mobile No")]
        [Display(Name = "Mobile")]
        [StringLength(10, ErrorMessage = "The Mobile must contains 10 characters", MinimumLength = 10)] 
        public string MobileNo { get; set; }
    }
} 

现在,通过在 Validator 属性中指定,将 UserModelValidator 验证类链接到 UserModel 类,如下所示:

[FluentValidation.Attributes.Validator(typeof(UserModelValidator))]
public class UserModel
{
    [Display(Name = "Name")]
    public string Name { get; set; }

    [Display(Name = "Email")]
    public string Email { get; set; }

    [Display(Name = "Mobile")]
    public string Mobileno { get; set; }
}

最后一步是在你的 global.asax 文件中调用 FluentValidationModelValidatorProvider.Configure() 方法。

namespace SampleApplication
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();

            FluentValidationModelValidatorProvider.Configure();
        }
    }
}

有关 FluentValidation 的更多信息,请参阅以下链接:

错误消息显示如下:

Validation Message

我参考了以下链接:

历史

我很快就会发布使用 AngularJS 在 MVC 中进行数据绑定的内容。希望这对像我一样的初学者有所帮助。

© . All rights reserved.