前五篇博文分别介绍并实现了前端校验和服务器校验, 这篇博文主要是介绍如何将两者结合起来使用, 并总结.
之前, 我们在 ASP.NET MVC 中集成了基于 FluentValidator 的验证器, 并通过扩展 Controller, 在 ControllEx 中 使用 OnActionExecuting 进行统一校验. 最后将所有错误信息存放在 ViewData["Error"] 内部后返回视图.
在视图呈现方面, 我们使用了 htmlHelper 的扩展方法来帮呈现, 这样有效避免了 Null 的尴尬局面.
- /// <summary>
- /// 显示指定属性的错误消息
- /// </summary>
- /// <param name="htmlHelper">HtmlHelper</param>
- /// <param name="property"> 指定的属性 </param>
- /// <param name="error">ViewData["Error"]</param>
- /// <param name="tagType"> 标签类型 </param>
- /// <param name="htmlAttribute"> 标签属性 </param>
- /// <returns></returns>
- public static MvcHtmlString ValidatorMessageFor(this HtmlHelper htmlHelper, string property, object error, string tagType = "p", object htmlAttribute = null)
- {
- var dicError = error as Dictionary<string, string>;
- if (dicError != null) // 没有错误
- {
- if (dicError.ContainsKey(property))
- {
- StringBuilder sb = new StringBuilder();
- if (htmlAttribute != null)
- {
- htmlAttribute.GetType().GetProperties().ToList().ForEach((p) =>
- {
- string key = p.Name;
- string value = p.GetValue(htmlAttribute).ToString();
- sb.AppendFormat("{0}='{1}' ", key, value);
- });
- }
- return new MvcHtmlString(string.Format("<{0} {2}>{1}</{0}>", tagType, dicError[property], sb.ToString()));
- }
- }
- return new MvcHtmlString("");
- }
如今我对 HtmlHelper 做了一定修改, 使它支持自定义标签类型和定义 Html 的属性, 这会让我们好的管理呈现效果. 比方为他加一个样式.
通过以上步骤我们就实现了服务端的验证.
在前端, 与前几章说讲的一样, 我们使用 vue, 并自编写了基于 Vue 的验证插件 vuefluentvalidator, 为什么叫它 vuefluentvalidator, 因为编写它的时候就是借鉴的咱们后台验证框架 FluentValidator 的使用方式.
- @using ValidationwebTest.Mvc.MvcHelperEx
- @{
- ViewBag.Title = "ValidatorTest";
- }
- <h2>ValidatorTest</h2>
- <div id="box">
- @using (Html.BeginForm())
- {
- @Html.AntiForgeryToken()
- <div class="form-horizontal">
- <h4>Person</h4>
- <hr />
- @Html.ValidationSummary(true, "", new { @class ="text-danger" })
- <div class="form-group">
- <label for="Name" class="control-label col-md-2"> 姓名 </label>
- <div class="col-md-10">
- <input type="text" name="Name" class="form-control" v-model="model.name" />
- <p v-text="model.error.name"></p>
- @Html.ValidatorMessageFor("Name", ViewData["Error"], "span", new { @class = "text-info" })
- </div>
- </div>
- <div class="form-group">
- <label for="Age" class="control-label col-md-2"> 年龄 </label>
- <div class="col-md-10">
- <input type="text" name="Age" class="form-control" v-model="model.age" />
- <p v-text="model.error.age"></p>
- @Html.ValidatorMessageFor("Age", ViewData["Error"], "strong")
- </div>
- </div>
- <div class="form-group">
- <label for="Home" class="control-label col-md-2"> 住址 </label>
- <div class="col-md-10">
- <input type="text" name="Address.Home" class="form-control" v-model="model.address.home" />
- <p v-text="model.error.address.home"></p>
- @Html.ValidatorMessageFor("Address.Home", ViewData["Error"])
- </div>
- </div>
- <div class="form-group">
- <label for="Phone" class="control-label col-md-2"> 电话 </label>
- <div class="col-md-10">
- <input type="text" name="Address.Phone" class="form-control" v-model="model.address.phone" />
- <p v-text="model.error.address.phone"></p>
- @Html.ValidatorMessageFor("Address.Phone", ViewData["Error"])
- </div>
- </div>
- <div class="form-group">
- <div class="col-md-offset-2 col-md-10">
- <input type="submit" value="Create" class="btn btn-default" v-on:click="formSubmit($event)" />
- </div>
- </div>
- </div>
- }
- </div>
- @section scripts{
- <script src="~/Content/vue.js"></script>
- <script src="~/Content/vuefluentvalidator.js"></script>
- <script>
- let vm = new Vue({
- el: '#box',
- data: {
- validator: new Validator({
- model: {
- name: undefined,
- age: undefined,
- address: {
- home: undefined,
- phone: undefined
- },
- },
- rule: function (than) {
- than.ruleFor("name")
- .NotEmpty()
- .WithMessage("姓名不能为空")
- .MinimumLength(5)
- .WithMessage("最短长度为 5");
- than.ruleFor("age")
- .NotEmpty()
- .WithMessage("年龄不能为空");
- than.ruleFor("address.home")
- .NotEmpty()
- .WithMessage("家庭地址不能为空");
- than.ruleFor("address.phone")
- .NotEmpty()
- .WithMessage("电话不能为空");
- }
- }),
- },
- methods: {
- formSubmit: function (ev) {
- if (this.validator.passValidation()) {
- return;
- }
- ev.preventDefault();
- this.validator.validation(ev.target);
- }
- },
- computed: {
- model: function () {
- return this.validator.model;
- }
- }
- });
- </script>
- }
使用方式和之前前端验证所讲的都一模一样, 只是在验证下边加了一行
@Html.ValidatorMessageFor("Name", ViewData["Error"], "span", new { @class = "text-info" })
为什么我会这样写? 因为在正常情况下, 我们前端会进行校验, 如果前端校验不通过的时候, 请求不会发送到后台, 所以这一行在正常情况下是用不到的.
那在什么时候会用到他? 在前端校验失效时或伪造请求时.
首先分析第一种
前端校验失效, 也就意味着 javascript 失效, 这种情况下我们的
<p v-text="model.error.name"></p>
什么都显示不出来.
而在验证失败的时候 @Html.ValidatorMessageFor("Name", ViewData["Error"], "span", new { @class = "text-info" }) 就会起作用了, 由于我们对标签的呈现效果控制的灵活性, 在视觉体验上, 没有任何区别.
如果在第二种情况下, 他都不是一个正常的请求, 我管它干什么? 阻止就是了.
如果你认为既然使用 Vue, 那为什么不将错误信息绑定到我们的验证器上呢?
事实上我也想过这么做, 一是它的工作量比现在这种方式更大 (原谅我偷了个懒), 二是, 如果 javascript 失效的话, 那岂不是根本显示不出来?
综上所述, 于是我决定就让它这样简单而愉快的结束吧. 到此我们的前后端校验功能就算全部实现.
由于博文是前五篇的延续, 在一些重复的内容上, 不过多介绍, 如果您在阅读时, 有任何疑问, 请从前面开始阅读.
来源: https://www.cnblogs.com/Gxqsd/p/9345678.html