zoukankan      html  css  js  c++  java
  • ASP.NET MVC Part.4(Validation、ActionResult)

           整理好 Edit.aspx 试图后,应该考虑要为用户的输入增加验证。从数据模型可以获得部分支持。如果用户给某个数值类型的字段输入了字符串,他会看到一个错误页面,可能是默认的 ASP.NET 栈信息或者自定义错误页面(如果在控制器和应用程序中启用了自定义错误处理)。

           绝大部分用户都不能够通过栈追踪信息知道自己输入了非法的值,并且他们也不应该知道,这就是为什么 MVC 框架内置了某些强大的验证功能

    执行基本的验证

           MVC 框架使数据从客户端回发到控制器时的错误验证检查变得非常简单。我们修改了 Edit 方法获取用户数据的签名,这样 MVC 框架就会通过表单的值自动创建 ProductListWrapper 的实例

           通过 ModelState.IsValid 方法检查验证错误,如果有问题,及时从方法中返回,指定把传给 Edit 方法的 ProductListWrapper 实例使用 Edit 视图显示。要注意的是,这里再次把供应商和类别名作为视图数据的一部分,这是因为 Edit.aspx 依赖于这些数据来呈现,如果没有这些就会抛出一个异常

    public ActionResult Edit(int id, ProductListWrapper pwrap)
    {
        try
        {
            if (!ModelState.IsValid)
            {
                ViewData["categories"] = nwa.GetAllCategories();
                ViewData["suppliers"] = nwa.GetAllSuppliers();
                return View("Edit", pwrap);
            }
     
            Products prod = nwa.GetProduct(id);
            if (prod != null)
            {
                ProductListWrapper wrapper = new ProductListWrapper()
                {
                    product = prod
                };
                UpdateModel(wrapper);
                prod.SupplierID = nwa.GetSupplierID(wrapper.SelectedSupplier);
                prod.CategoryID = nwa.GetCategoryID(wrapper.SelectedCategory);
                nwa.SaveChanges();
                return RedirectToAction("Index");
            }
            else
            {
                throw new NoSuchRecordException();
            }
        }
        catch
        {
            return View();
        }
    }

           还需要在 Edit.aspx 里添加一行代码以享用验证支持带来的便利:

    ......
    <legend>Edit Product Details</legend>
     
    <%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>
    ......

           现在如果尝试输入一些非法数据,可以看见如下效果(产生问题的输入框也高亮显示着):

    image

           如果要把验证提醒消息放在数据字段的旁边,可以使用 ValidationMessageFor 辅助方法,它为指定的数据项生成验证警告。例如,下边是被应用到 RecordLevel 字段的辅助方法:

    <tr>
        <td>Reorder Level:</td>
        <td>
            <%: Html.TextBoxFor(e => e.product.ReorderLevel)%>
            <%: Html.ValidationMessageFor(e => e.product.ReorderLevel) %>
        </td>
    </tr>

    image

    增加验证标注

           MVC 框架支持验证的元数据标注,它让你能使用标准的标注强制通用的验证标准并自定义约束。可以通过部分类的功能把元数据类和数据模型类关联到一起,然后对之应用 C# 标注

           直观一点,这个元数据类为 Product 模型数据类型的 UnitInStock 属性应用一系列的验证检查,Product 模型数据类型是在 Models 项目目录里创建的:

    using System.ComponentModel.DataAnnotations;
     
    namespace BasicMvcApplication.Models
    {
        // MetadataType 指定用 ProductsMetaData 类保存 Products 类的元数据
        [MetadataType(typeof(ProductsMetaData))]
        public partial class Products // 分布类与实体框架数据模型产生的类具有相同的签名
        {
            public class ProductsMetaData
            {
                // 为要验证的字段定义相同名称的属性,类型并不需要对应,元数据系统基于成员名称工作
                // 添加了 Range 特性
                [Range(1, 50)]
                public object UnitsInStock { get; set; } 
            }
        }
    }

           这非常不直观,但先记住这些,对于每个要标注的数据模型类型都只要做一次就可以了。

           现在,如果编辑超出范围的值就会产生一个错误,如图:

    image

           验证属性在 System.ComponentModel.DataAnnotations 命名空间中。我们已经使用了 RangeAttribute,另外还有些属性较为常用:StringLengthAttributeRegularExpressionAttributeRequiredAttributeDataTypeAttribute 等。

           还可以从 ValidationAttribute 类继承以创建自定义的验证属性!下面的属性确保数值要么是偶数,要么是奇数:

    using System.ComponentModel.DataAnnotations;
     
    namespace BasicMvcApplication.Models
    {
        public class OddOrEvenAttribute : ValidationAttribute
        {
            public Mode mode { get; set; }
            public OddOrEvenAttribute(Mode m)
            {
                mode = m;
            }
     
            public override bool IsValid(object value)
            {
                try
                {
                    if (int.Parse(value.ToString()) % 2 == 0)
                    {
                        return mode == Mode.Even;
                    }
                    else
                    {
                        return mode == Mode.Odd;
                    }
                }
                catch
                {
                    return false;
                }
            }
     
            public enum Mode
            {
                Odd,
                Even
            }
        }
    }

           当属性应用的数据模型字段被提交数据时,MVC 框架会调用 IsValid 方法来检查字段值的合法性。下面是通过元数据类被应用到 UnitsInStock 的自定义属性:

    [Range(1, 50)]
    [OddOrEven(OddOrEvenAttribute.Mode.Even, 
        ErrorMessage = "Units In Stock must be even.")]
    public object UnitsInStock { get; set; }

           现在,如果提交了不合适的值可以看到如下效果:

    image

    使用动作结果

           在控制器方法里,我们返回 View 方法的结果,或者在某种情况下返回 RedirectToAction 方法。这一小节我将解释这些方法的意义并演示如何通过它们控制 MVC 应用程序。

           MVC 框架要求所有控制器活动方法都返回 ActionResult 的实例,这样框架才能知道后续如何处理(为用户呈现视图、调用其他活动等)。为了让 MVC 程序员更轻松,微软还提供了一系列辅助方法,我们可以通过它们创建 ActionResult 的子类的实例以获得不同的效果。

           例如,为了告诉 MVC 框架为用户程序视图,我们返回 ViewResult 的实例(它是 ActionResult 的子类),用来创建 ViewResult 的辅助方法是 View(),这是我们一直大量使用它的原因。View 有一系列的重载,把某个对象作为唯一的参数传给 View,MVC 框架就会根据活动方法的名称来决定要使用的视图,并用它来显示传入的对象

           如果要返回另一个控制器方法的结果,可以使用 RedirectToAction 方法轻松创建 RedirectToRouteResult 类。下表是最有用的控制器辅助方法以及它们的返回类型:

    辅助方法

    ActionResult 子类

    描  述

    Views() ViewResult 呈现视图
    RedirectToAction() RedirectResult 返回另一个控制器方法的结果
    Json() JsonResult 使用 Json 序列化数据模型对象
    JavaScript() JavaScriptResult 返回客户端要执行的脚本
    FileResult() FileResult 返回文件的内容

    返回 JSON 数据

           使用脚本 (包括 jQuery 编写的脚本) 时经常需要从模型返回 JSON 格式的数据。可以直接传递对象给 JSON 辅助方法来返回 JSON 数据,但在使用由实体框架或 LINQ to SQL 向导生成的数据模型类时还是要小心。自动生成的数据模型为了在不同表间进行导航而使用了循环引用,这对 JSON 注入器来说是一件相当痛苦的事情。因此我们给控制器新增加了一个活动方法,它以 JSON 格式输出产品的细节:

    [HandleError(View = "NoSuchRecordError", ExceptionType = typeof(NoSuchRecordException))]
    public ActionResult JsonDetails(int id)
    {
        Products prod = nwa.GetProduct(id);
        if (prod == null)
        {
            throw new NoSuchRecordException();
        }
        else
        {
            return Json(
                new
                {
                    ProductID = prod.ProductID,
                    ProductName = prod.ProductName,
                    SupplierID = prod.SupplierID,
                    CategoryID = prod.CategoryID,
                    UnitPrice = prod.UnitPrice,
                    UnitsInStock = prod.UnitsInStock,
                    UnitsOnOrder = prod.UnitsOnOrder,
                    ReorderLevel = prod.ReorderLevel,
                    Discontinued = prod.Discontinued
                }, JsonRequestBehavior.AllowGet);
        }
    }

           如果给 JSON 方法传入 Product 实例,会发生异常,报告说发现了循环依赖。通过创建一个匿名类型规避了这一问题。这个匿名类型只包含了我们需要序列化的属性。通过类似下面的 URL 调用这个方法:

    http://localhost:7537/Product/JsonDetails/1

           会得到如下的 JSON 数据:

    {
        "ProductID":1,
        "ProductName":"Chai",
        "SupplierID":1,
        "CategoryID":1
        ,"UnitPrice":19.2300
        ,"UnitsInStock":20,
        "UnitsOnOrder":0,
        "ReorderLevel":10,
        "Discontinued":false
    }

           JsonRequestBehavior 枚举定义的一个 AllowGet 值,它是 MVC 2 中增加的一个安全度量,它要求显式的允许为 HTTP GET 请求返回 JSON 数据。

    调用其他控制器方法

           之前的文章曾经演示过如何创建自定义的错误视图。那样做不错,但需要为每个不同的应用程序异常分别创建一个视图,这对于简单的示例还不错,但对于真正的项目来说那就太麻烦了

           这里我将重拾之前的错误处理以演示 RedirectToAction 辅助方法的应用。假设我们要创建一个通用的错误处理视图,用它显示两个字符串,一个用于说明用户面临的问题而另一个用于帮助程序员识别代码中发生了什么问题。

           首先,在 ProductController 类里增加一个新方法:

    public ActionResult CustomError(string message, string detail)
    {
        ViewData["ErrorMessage"] = message;
        ViewData["ErrorDetail"] = detail;
        return View("CustomError");
    }

           这个方法非常简单,使用视图数据(ViewData)为视图提供一个消息字符串和一个详细信息字符串。然后调用 View 辅助方法来显示名为"CustomError” 的视图。

           创建 Views/Shared/CustomError.aspx 视图,内容如下:

    <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
    Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
     
    <asp:Content ID="errorTitle" ContentPlaceHolderID="TitleContent" runat="server">
        Error
    </asp:Content>
     
    <asp:Content ID="errorContent" ContentPlaceHolderID="MainContent" runat="server">
        <h2>Sorry, an error occurred while processing your request.</h2>
        <h3><%: ViewData["ErrorMessage"] %></h3>
        <h4><%= ViewData["ErrorDetail"] %></h4>
    </asp:Content>

           为了演示新方法,我们更新 Details 方法以在处理不存在记录的请求时使用 CustomError 视图:

    public ActionResult Details(int id)
    {
        Products prod = nwa.GetProduct(id);
        if (prod == null)
        {
            return RedirectToAction("CustomError",
                new
                {
                    message = "You requested an unknown product.",
                    detail = string.Format("No record for ID of {0}.", id)
                });
        }
        else
        {
            ViewData["CatName"] = nwa.GetCategoryName(prod);
            ViewData["SupName"] = nwa.GetSupplierName(prod);
            return View(prod);
        }
    }

           使用 RedirectToAction 方法时,必须提供要调用的控制器方法的名称并提供一个对象(它的属性和目标方法参数相匹配)。

           现在,请求一条不存在的记录会出现这个视图:

    image

  • 相关阅读:
    学习笔记—查找
    水晶报表图表制作问题
    Chrome对最小字体的限制
    Devexpress的ASPxDateEdit控件设置其‘today’ 为客户端当前日期
    水晶报表多表数据源
    System.Web.HttpValueCollection.ThrowIfMaxHttpCollectionKeysExceeded
    利用水晶报表制作甘特图
    水晶报表打印时最后多打印一空白页
    day3学习
    Python高级自动化培训day1
  • 原文地址:https://www.cnblogs.com/SkySoot/p/2975248.html
Copyright © 2011-2022 走看看