ASP.NET全棧開發驗證模塊之將先後臺校驗結合

前五篇博文分別介紹並實現了前端校驗和服務器校驗,這篇博文主要是介紹如何將二者結合起來使用,並總結。javascript

以前,咱們在ASP.NET MVC中集成了基於FluentValidator的驗證器,並經過擴展Controller,在ControllEx中 使用 OnActionExecuting 進行統一校驗。最後將全部錯誤信息存放在ViewData["Error"]內部後返回視圖。html

在視圖呈現方面,咱們使用了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

經過以上步驟咱們就實現了服務端的驗證。java

在前端,與前幾章說講的同樣,咱們使用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" })

爲何我會這樣寫?由於在正常狀況下,咱們前端會進行校驗,若是前端校驗不經過的時候,請求不會發送到後臺,因此這一行在正常狀況下是用不到的。框架

那在何時會用到他?在前端校驗失效時或僞造請求時。ui

首先分析第一種this

前端校驗失效,也就意味着javascript失效,這種狀況下咱們的

<p v-text="model.error.name"></p>

什麼都顯示不出來。

而在驗證失敗的時候 @Html.ValidatorMessageFor("Name", ViewData["Error"], "span", new { @class = "text-info" }) 就會起做用了,因爲咱們對標籤的呈現效果控制的靈活性,在視覺體驗上,沒有任何區別。

若是在第二種狀況下,他都不是一個正常的請求,我管它幹什麼?阻止就是了。

若是你認爲既然使用Vue,那爲何不將錯誤信息綁定到咱們的驗證器上呢?

事實上我也想過這麼作,一是它的工做量比如今這種方式更大(原諒我偷了個懶),二是,若是javascript失效的話,那豈不是根本顯示不出來?

綜上所述,因而我決定就讓它這樣簡單而愉快的結束吧。到此咱們的先後端校驗功能就算所有實現。

因爲博文是前五篇的延續,在一些重複的內容上,不過多介紹,若是您在閱讀時,有任何疑問,請從前面開始閱讀。

相關文章
相關標籤/搜索