验证 ASP.NET 网页 (Razor) 站点中的用户输入

作者 Tom FitzMacken

本文讨论如何验证从用户处获取的信息,即确保用户在 ASP.NET 网页 (Razor) 网站中以 HTML 表单输入有效信息。

学习内容:

  • 如何检查用户的输入是否与定义的验证条件匹配。
  • 如何确定是否已通过所有验证测试。
  • 如何 (显示验证错误以及如何) 设置这些错误的格式。
  • 如何验证不直接来自用户的数据。

以下是本文中介绍的 ASP.NET 编程概念:

  • 帮助 Validation 程序。
  • Html.ValidationSummaryHtml.ValidationMessage 方法。

本教程中使用的软件版本

  • ASP.NET 网页 (Razor) 3

本教程还适用于 ASP.NET 网页 2。

本文包含以下各节:

用户输入验证概述

如果要求用户在页面中输入信息(例如,在窗体中),请务必确保他们输入的值有效。 例如,你不希望处理缺少关键信息的表单。

当用户在 HTML 窗体中输入值时,他们输入的值是字符串。 在许多情况下,你需要的值是一些其他数据类型,如整数或日期。 因此,还必须确保用户输入的值可以正确转换为适当的数据类型。

也可能对值有一定的限制。 例如,即使用户正确输入整数,你也可能需要确保该值位于特定范围内。

屏幕截图显示使用 CSS 样式类的验证错误。

注意

重要 验证用户输入对于安全性也很重要。 限制用户可以在表单中输入的值时,可以减少有人输入可能危及网站安全性的值的可能性。

验证用户输入

在 ASP.NET 网页 2 中,可以使用Validator帮助程序测试用户输入。 基本方法是执行以下操作:

  1. 确定要验证) 字段 (输入元素。

    通常验证窗体中元素中的 <input> 值。 但是,最好验证所有输入,甚至是来自受约束元素(如列表)的 <select> 输入。 这有助于确保用户不会绕过页面上的控件并提交表单。

  2. 在页面代码中,使用帮助程序的方法 Validation 为每个输入元素添加单独的验证检查。

    若要为必填字段检查,请将Validation.RequireField(field, [error message]) (用于单个字段) ,或Validation.RequireFields(field1, field2, ...))对) 字段列表使用 (。 对于其他类型的验证,请使用 Validation.Add(field, ValidationType)。 对于 ValidationType,可以使用以下选项:

    Validator.DateTime ([error message])
    Validator.Decimal([error message])
    Validator.EqualsTo(otherField [, error message])
    Validator.Float([error message])
    Validator.Integer([error message])
    Validator.Range(min, max [, error message])
    Validator.RegEx(pattern [, error message])
    Validator.Required([error message])
    Validator.StringLength(length)
    Validator.Url([error message])

  3. 提交页面后,检查检查 Validation.IsValid是否已通过验证:

    if(IsPost && Validation.IsValid()){
        // Process form submit
    }
    

    如果存在任何验证错误,则跳过正常的页面处理。 例如,如果页面的目的是更新数据库,则在修复所有验证错误之前,你不会这样做。

  4. 如果存在验证错误,请使用 Html.ValidationSummary 或 或 Html.ValidationMessage两者在页面的标记中显示错误消息。

以下示例演示了说明这些步骤的页面。

@{
    var message="";
    // Specify validation requirements for different fields.
    Validation.RequireField("coursename", "Class name is required");
    Validation.RequireField("credits", "Credits is required");
    Validation.Add("coursename", Validator.StringLength(5));
    Validation.Add("credits", Validator.Integer("Credits must be an integer"));
    Validation.Add("credits", Validator.Range(1, 5, "Credits must be between 1 and 5"));
    Validation.Add("startDate", Validator.DateTime("Start date must be a date"));

    if (IsPost)  {
        // Before processing anything, make sure that all user input is valid.
        if (Validation.IsValid()) {
            var coursename = Request["coursename"];
            var credits = Request["credits"].AsInt();
            var startDate = Request["startDate"].AsDateTime();
            message += @"For Class, you entered " + coursename;
            message += @"<br/>For Credits, you entered " + credits.ToString();
            message += @"<br/>For Start Date, you entered " + startDate.ToString("dd-MMM-yyyy");

            // Further processing here
        }
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
  <title>Validation Example</title>
  <style>
      body {margin: 1in; font-family: 'Segoe UI'; font-size: 11pt; }
   </style>
</head>
<body>
  <h1>Validation Example</h1>
  <p>This example page asks the user to enter information about some classes at school.</p>
  <form method="post">
    @Html.ValidationSummary()
    <div>
      <label for="coursename">Course name: </label>
      <input type="text"
         name="coursename"
         value="@Request["coursename"]"
      />
      @Html.ValidationMessage("coursename")
    </div>

    <div>
      <label for="credits">Credits: </label>
      <input type="text"
         name="credits"
         value="@Request["credits"]"
      />
      @Html.ValidationMessage("credits")
    </div>

    <div>
      <label for="startDate">Start date: </label>
      <input type="text"
         name="startDate"
         value="@Request["startDate"]"
      />
      @Html.ValidationMessage("startDate")
    </div>

   <div>
      <input type="submit" value="Submit" class="submit" />
    </div>

    <div>
      @if(IsPost){
        <p>@Html.Raw(message)</p>
      }
    </div>
  </form>
</body>
</html>

若要查看验证的工作原理,请运行此页面并故意犯错误。 例如,如果忘记输入课程名称、输入了 ,并且输入了无效日期,页面的外观如下所示:

呈现页中的验证错误

添加Client-Side验证

默认情况下,用户输入在用户提交页面后进行验证,即在服务器代码中执行验证。 此方法的一个缺点是用户直到提交页面后才知道自己已出错。 如果表单较长或复杂,则仅在提交页面后报告错误可能会对用户不方便。

可以添加在客户端脚本中执行验证的支持。 在这种情况下,将在用户在浏览器中工作时执行验证。 例如,假设指定值应为整数。 如果用户输入非整数值,则会在用户离开输入字段后立即报告错误。 用户立即获得反馈,这对他们来说很方便。 基于客户端的验证还可以减少用户必须提交表单以更正多个错误的次数。

注意

即使使用客户端验证,也始终在服务器代码中执行验证。 在服务器代码中执行验证是一种安全措施,以防用户绕过基于客户端的验证。

  1. 在页面中注册以下 JavaScript 库:

    <script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.2.js">
    </script>
    <script
    src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.8.1/jquery.validate.js">
    </script>
    <script src="~/Scripts/jquery.validate.unobtrusive.js">
    </script>
    

    可以从内容分发网络 (CDN) 加载两个库,因此不必将它们放在计算机或服务器上。 但是,必须具有 jquery.validate.unobtrusive.js的本地副本。 如果尚未使用包含库的 WebMatrix 模板 (如 Starter Site ) ,请创建基于 初学者网站的网页网站。 然后将 .js 文件复制到当前站点。

  2. 在标记中,对于要验证的每个元素,请添加对 的 Validation.For(field)调用。 此方法发出客户端验证使用的属性。 (方法发出特性 data-val-...,而不是发出实际的 JavaScript 代码。这些属性支持使用 jQuery 执行工作的不显眼客户端验证。)

以下页面演示如何将客户端验证功能添加到前面所示的示例。

@{
    // Note that client validation as implemented here will work only with
    // ASP.NET Web Pages 2.

    var message="";
    // Specify validation requirements for different fields.
    Validation.RequireField("coursename", "Class name is required");
    Validation.RequireField("credits", "Credits is required");
    Validation.Add("coursename", Validator.StringLength(5));
    Validation.Add("credits", Validator.Integer("Credits must be an integer"));
    Validation.Add("credits", Validator.Range(1, 5, "Credits must be between 1 and 5"));
    Validation.Add("startDate", Validator.DateTime("Start date must be a date"));

    if (IsPost)  {
        // Before processing anything, make sure that all user input is valid.
        if (Validation.IsValid()) {
            var coursename = Request["coursename"];
            var credits = Request["credits"].AsInt();
            var startDate = Request["startDate"].AsDateTime();
            message += @"For Class, you entered " + coursename;
            message += @"<br/>For Credits, you entered " + credits.ToString();
            message += @"<br/>For Start Date, you entered " + startDate.ToString("dd-MMM-yyyy");

            // Further processing here
        }
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
  <title>Validation Example with Client Validation</title>
  <style>
      body {margin: 1in; font-family: 'Segoe UI'; font-size: 11pt; }
   </style>
    <script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.2.js"></script>
    <script
        src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.8.1/jquery.validate.js">
    </script>
    <script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
</head>
<body>
  <h1>Validation Example with Client Validation</h1>
  <p>This example page asks the user to enter information about some classes at school.</p>
  <form method="post">
    @Html.ValidationSummary()
    <div>
      <label for="coursename">Course name: </label>
      <input type="text"
         name="coursename"
         value="@Request["coursename"]"
         @Validation.For("coursename")
      />
      @Html.ValidationMessage("coursename")
    </div>

    <div>
      <label for="credits">Credits: </label>
      <input type="text"
         name="credits"
         value="@Request["credits"]"
         @Validation.For("credits")
      />
      @Html.ValidationMessage("credits")
    </div>

    <div>
      <label for="startDate">Start date: </label>
      <input type="text"
         name="startDate"
         value="@Request["startDate"]"
         @Validation.For("startDate")
      />
      @Html.ValidationMessage("startDate")
    </div>

   <div>
      <input type="submit" value="Submit" class="submit" />
    </div>

    <div>
      @if(IsPost){
        <p>@Html.Raw(message)</p>
      }
    </div>
  </form>
</body>
</html>

并非所有验证检查都在客户端上运行。 具体而言,数据类型验证 (整数、日期等,) 不会在客户端上运行。 以下检查适用于客户端和服务器:

  • Required
  • Range(minValue, maxValue)
  • StringLength(maxLength[, minLength])
  • Regex(pattern)
  • EqualsTo(otherField)

在此示例中,有效日期的测试在客户端代码中不起作用。 但是,测试将在服务器代码中执行。

格式设置验证错误

可以通过定义具有以下保留名称的 CSS 类来控制验证错误的显示方式:

  • field-validation-error. 定义方法显示错误时的输出 Html.ValidationMessage
  • field-validation-valid. 在没有错误时定义 方法的 Html.ValidationMessage 输出。
  • input-validation-error. 定义发生错误时元素的呈现方式 <input> 。 (例如,如果输入元素的值无效,可以使用此类将输入>元素的背景色<设置为其他颜色。) 此 CSS 类仅在 ASP.NET 网页 2) 中的客户端验证 (期间使用。
  • input-validation-valid. 定义没有错误时元素的外观 <input>
  • validation-summary-errors. 定义它显示错误列表的方法的输出 Html.ValidationSummary
  • validation-summary-valid. 在没有错误时定义 方法的 Html.ValidationSummary 输出。

以下 <style> 块显示了错误条件的规则。

<style>
.validation-summary-errors {
  border:2px solid red;
  color:red;
  font-weight:bold;
  margin:6px;
  width:30%;
}

.field-validation-error{
  color:red;
   font-weight:bold;
   background-color:yellow;
}

.input-validation-error{
  color:red;
  font-weight:bold;
  background-color:pink;
}
</style>

如果在本文前面的示例页中包含此样式块,则错误显示将如下图所示:

使用 CSS 样式类的验证错误

注意

如果未在 ASP.NET 网页 2 中使用客户端验证,则元素的 <input> CSS 类 (input-validation-errorinput-validation-valid没有任何效果。

静态和动态错误显示

CSS 规则成对出现,例如 validation-summary-errorsvalidation-summary-valid。 通过这些对,你可以为两个条件定义规则:错误条件和“正常” (非错误) 条件。 请务必了解,即使没有错误,也会始终呈现错误显示的标记。 例如,如果页面在标记中具有 Html.ValidationSummary 方法,则页面源将包含以下标记,即使第一次请求页面:

<div class="validation-summary-valid" data-valmsg-summary="true"><ul></ul></div>

换句话说, Html.ValidationSummary 方法始终呈现 <div> 元素和列表,即使错误列表为空。 同样, Html.ValidationMessage 方法始终将 <span> 元素呈现为单个字段错误的占位符,即使没有错误也是如此。

在某些情况下,显示错误消息可能会导致页面重新排列,并可能导致页面上的元素四处移动。 以 结尾 -valid 的 CSS 规则允许你定义有助于防止此问题的布局。 例如,可以将 和 field-validation-valid 定义为field-validation-error具有相同固定大小。 这样,字段的显示区域是静态的,如果显示错误消息,则不会更改页面流。

验证不是直接来自用户的数据

有时,必须验证不是直接来自 HTML 表单的信息。 典型示例是一个页面,其中值在查询字符串中传递,如以下示例所示:

http://server/myapp/EditClassInformation?classid=1022

在这种情况下,需要确保传递给页面的值在此处 (,1022 表示) 的值 classid 有效。 不能直接使用 Validation 帮助程序来执行此验证。 但是,可以使用验证系统的其他功能,例如显示验证错误消息的功能。

注意

重要 始终验证从 任何 源获取的值,包括表单字段值、查询字符串值和 Cookie 值。 人们很容易将这些值更改为 (可能出于恶意目的) 。 因此,必须检查这些值以保护应用程序。

以下示例演示如何验证在查询字符串中传递的值。 代码测试该值是否不为空且是否为整数。

if(!IsPost){
    if(!Request.QueryString["classid"].IsEmpty() && Request.QueryString["classid"].IsInt()) {
        // Process the value
    }
    else{
        Validation.AddFormError("No class was selected.");
    }
}

请注意,当请求不是表单提交 () if(!IsPost) 时,将执行测试。 此测试将在首次请求页面时通过,但在请求为表单提交时不会通过。

若要显示此错误,可以通过调用 Validation.AddFormError("message")将错误添加到验证错误列表。 如果页面包含对 方法的 Html.ValidationSummary 调用,则会显示错误,就像用户输入验证错误一样。

其他资源

在 ASP.NET 网页 网站中使用 HTML 表单