• ASP.NET MVC验证


    本文主要体验通过jQuery异步验证。

    在很多的教材和案例中,MVC验证都是通过提交表单进行的。通过提交表单,可以很容易获得验证出错信息。因为,无论是客户端验证还是服务端验证,总能找到与Model属性或验证特性对应的html元素和属性,并把错误信息显示出来。可是,在实际项目中,经常会遇到需要异步提交的情况。那么,如何把服务端的验证错误信息传递给前端视图呢?

    □ 思路

    1、服务端的验证错误信息是可以收集起来的以json形式传递个视图的。
    2、服务端把错误信息存放在一个字典集合Dictionary<string, object>,让key是属性名,value是错误信息。
    3、前台视图中,显示错误信息的元素id,比方说是Err_Name,当遍历从服务端传来的字典集合时,取出key,然后把错误信息动态赋值给$('#Err_' + key)。

      View model

    using System;
    using System.ComponentModel.DataAnnotations;
     
    namespace DataAnnotationAjax.Models
    {
        public class Student
        {
            public int Id { get; set; }
     
            [Required(ErrorMessage = "姓名为必填项")]
            [Display(Name = "姓名")]
            public string Name { get; set; }
     
            [Required(ErrorMessage = "分数是必选项")]
            [Range(60, 100, ErrorMessage = "分数必须在60和100之间")]
            [Display(Name = "分数")]
            public int Score { get; set; }
     
            [Display(Name = "招收日期")]
            public DateTime Enrollment { get; set; }
        }
    }

      模拟一个仓储层,负责数据的初始化、添加和显示

    using System;
    using System.Collections.Generic;
    using DataAnnotationAjax.Models;
     
    namespace DataAnnotationAjax.Service
    {
        public static class StudentRepository
        {
            private static int _idSeed = 1;
            private static readonly List<Student>  _students = new List<Student>();
     
            static StudentRepository()
            {
                Random rand = new Random();
                for (int i = 0; i < 3; i++)
                {
                    var student = new Student();
                    int id = _idSeed++;
                    student.Id = id;
                    student.Name = "姓名" + id.ToString();
                    student.Score = (60 + Convert.ToInt16(rand.NextDouble()*40));
                    student.Enrollment = DateTime.Now;
                    _students.Add(student);
                }
            }
     
            public static void AddStudent(Student stu)
            {
                stu.Id = _idSeed++;
                stu.Enrollment = DateTime.Now;
                _students.Add(stu);
            }
     
            public static List<Student> GetStudents()
            {
                return _students;
            }
        }
    }
     

      BaseController

    前台视图为了显示错误信息等,需要控制器传来的json可能包含如下构成:

    1、是否验证通过:这个bool值很容易通过ModelState拿到。
    2、错误信息的字典集合:每个控制器都有可能用到,可以把获取错误信息的字典集合方法放到一个基控制器中去。
    3、再加一个福利:有时希望部分视图以字符串形式传递给某一视图,那就把根据视图名称和model返回视图字符串的方法也放到基控制器中。

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    
    namespace DataAnnotationAjax.Controllers
    {
        public class BaseController : Controller
        {
            /// <summary>
            /// 把部分视图转换成string
            /// </summary>
            /// <param name="viewName">部分视图名称</param>
            /// <param name="model">view model</param>
            /// <returns>部分视图字符串</returns>
            public string RenderPartialViewToString(string viewName, object model)
            {
                ViewData.Model = model;
                using (var sw = new StringWriter())
                {
                    //根据部分视图名称+ControllerContext获得ViewEngineResult
                    //ViewEngineResult中有View属性
                    var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
    
                    //创建ViewContext对象实例
                    var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
    
                    //把ViewEngineResult中的视图渲染到StringWriter实例中
                    viewResult.View.Render(viewContext,sw);
                    
                    //获取视图string
                    return sw.GetStringBuilder().ToString();
                }
            }
    
            /// <summary>
            /// 获取ModelState中的错误信息,以字典集合的形式返回
            /// </summary>
            /// <returns></returns>
            public Dictionary<string, object> GetErrorFromModelState()
            {
                var errors = new Dictionary<string, object>();
                foreach (var key in ModelState.Keys)
                {
                    if (ModelState[key].Errors.Count > 0)
                    {
                        errors[key] = ModelState[key].Errors;
                    }
                }
                return errors;
            }
        }
    }
    

      HomeController

    HomeController做了:


    1、显示一个异步提交的视图Index.cshtml
    2、完成了验证通过情况下的数据添加。
    3、不管是否验证通过,都要返回json字符串。

    using System.Web.Mvc;
    using DataAnnotationAjax.Models;
    using DataAnnotationAjax.Service;
     
    namespace DataAnnotationAjax.Controllers
    {
        public class HomeController : BaseController
        {
            public ActionResult Index()
            {
                return View(StudentRepository.GetStudents());
            }
     
            [HttpPost]
            public ActionResult AddStudent()
            {
                var student = new Student();
                var valid = TryUpdateModel(student);
                string studentPartialViewHtml = string.Empty;
                if (valid)
                {
                    StudentRepository.AddStudent(student);
                    var students = StudentRepository.GetStudents();
                    studentPartialViewHtml = RenderPartialViewToString("Students", students);
                }
                return Json(new {Valid = valid, Errors = GetErrorFromModelState(), StudentsPartial = studentPartialViewHtml});
            }
        }
    }
     

      部分视图Students.cshtml

    @model IEnumerable<DataAnnotationAjax.Models.Student>
    
    <table>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Name)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Score)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Enrollment)
            </th>
        </tr>
    
    @foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Name)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Score)
            </td>
            <td>
                @item.Enrollment.ToString("yy-MM-dd")
            </td>
        </tr>
    }
    
    </table>
    

      Index.cshtml异步提交的界面

    @model IEnumerable<DataAnnotationAjax.Models.Student>
     
    @{
        ViewBag.Title = "Index";
        Layout = "~/Views/Shared/_Layout.cshtml";
    }
    <style type="text/css">
        .errormsg {
            color: red;
        }
    </style>
     
    <div>
    <table cellpadding="0px">
        <tr>
            <td>姓名</td>
            <td><input type="text" id="Name" /></td>
        </tr>
        <tr>
            <td></td><td colspan="2" 
                  id="Err_Name" class="errormsg"></td>
        </tr>
        <tr>
            <td>分数</td>
            <td><input type="text" id="Score" /></td>
            <td>
                <button id="btnAddStudent">添加学生</button>
                <button id="btnClear">清空</button>
            </td>
        </tr>
        <tr>
            <td></td><td colspan="2" 
                  id="Err_Score" class="errormsg"></td>
        </tr>
    </table>
    </div>
     
    <div id="divStudent">
        @{Html.RenderPartial("Students",Model);}
    </div>
     
    @section scripts
    {
        <script type="text/javascript">
            $(function() {
                $('#btnAddStudent').click(function() {
                    var data = {
                        Name: $.trim($('#Name').val()),
                        Score: $.trim($('#Score').val())
                    };
     
                    $.ajax({
                        cache: false,
                        type: "POST",
                        url: '@Url.Action("AddStudent", "Home")',
                        data: data,
                        dataType: "json",
                        success: function(data) {
                            if (data.Valid) {
                                $('#divStudent').html(data.StudentsPartial);
                                $('input').val("");
                                return;
                            }
                            $.each(data.Errors, function(key, value) {
                                if (value != null) {
                                    $('#Err_' + key).html(value[value.length - 1].ErrorMessage);
                                }
                            });
                        },
                        error: function(xhr) {
                            alert(xhr.responseText);
                            alert("数据没有能提交到服务器!");
                        }
                    });
                });
     
                $('#btnClear').click(function() {
                    $('.errormsg').html("");
                    $("input").val("");
                });
     
                $("input").keyup(function() {
                    var $errorDiv = $("#Err_" + this.id);
                    if ($errorDiv.html() !="") {
                        $errorDiv.html("");
                    }
                });
            });
        </script>
    }
     


    几个关键点:
    1、显示错误信息的元素id的命名有讲究的:Err_Name,Name与Model中的属性一致。
    2、遍历服务端传来的错误信息字典集合时,对每个属性,即key,拿的是最近一次错误:$('#Err_' + key).html(value[value.length - 1].ErrorMessage)。

    没有填写信息报错:

    不填


    填写分数不在定义区间报错:

    分数


    全部填写正确,验证通过,把部分视图以string形式返回并加载到页面区域中:

    通过

  • 相关阅读:
    .net 调用spring boot rest api 的100Continue问题
    haproxy dataplaneapi 2.6 发布
    localstack 1.0 ga 了
    一些网络延迟测试工具
    nginx 的 ngx_http_addition_module 模块
    dremio arrow flight sql odbc 驱动支持mac 以及linux 了
    pixie k8s 原生应用即时监控工具
    wireshark ssl 解密处理
    cube.js cube store minio 集成
    使用py4j 实现python与java 的互调用
  • 原文地址:https://www.cnblogs.com/wangsai/p/4113324.html
Copyright © 2020-2023  润新知