ASP.NET 网页简介 - HTML 表单基础知识

作者 Tom FitzMacken

本教程介绍了如何使用 ASP.NET 网页 (Razor) 创建输入表单以及如何处理用户的输入。 现在,你已拥有一个数据库,你将使用表单技能让用户在数据库中查找特定电影。 它假设你已完成使用 ASP.NET 网页 显示数据简介系列。

学习内容:

  • 如何使用标准 HTML 元素创建表单。
  • 如何在窗体中读取用户的输入。
  • 如何创建使用用户提供的搜索词有选择地获取数据的 SQL 查询。
  • 如何让页面中的字段“记住”用户输入的内容。

已讨论的功能/技术:

  • Request 对象。
  • SQL Where 子句。

所需操作

在上一教程中,你创建了一个数据库,向其中添加了数据,然后使用 WebGrid 帮助程序来显示数据。 在本教程中,你将添加一个搜索框,用于查找特定流派或标题包含输入的任何字词的电影。 (例如,你将能够找到其流派为“Action”或标题包含“Harry”或“Adventure”的所有电影。)

完成本教程后,你将有一个如下所示的页面:

包含流派和标题搜索的电影页面

页面的列表部分与上一教程中的列表部分相同 - 网格。 区别在于网格仅显示你搜索的电影。

关于 HTML 窗体

(如果你有创建 HTML 表单的经验,并且具有 和 POST之间的差异GET,则可以跳过本部分。)

窗体包含用户输入元素 - 文本框、按钮、单选按钮、检查框、下拉列表等。 用户填写这些控件或进行选择,然后通过单击按钮提交表单。

此示例演示了表单的基本 HTML 语法:

<form method="post">
  <input type="text" name="name" value="" />
  <br/>
  <input type="submit" name="submit" value="Submit" />
</form>

当此标记在页面中运行时,它会创建一个简单的窗体,如下所示:

浏览器中呈现的基本 HTML 表单

元素 <form> 将要提交的 HTML 元素括起来。 (一个容易犯的错误是将元素添加到页面,但随后忘记将它们放入元素中 <form> 。在这种情况下,不会提交任何内容。) 属性 method 告知浏览器如何提交用户输入。 如果要在服务器上执行更新,请将此设置 post 设置为 ; get 如果只是从服务器提取数据,则设置为 。

提示

GET、POST 和 HTTP 谓词安全

HTTP 是浏览器和服务器用来交换信息的协议,其基本操作非常简单。 浏览器仅使用几个谓词向服务器发出请求。 为 Web 编写代码时,了解这些谓词以及浏览器和服务器如何使用它们会很有帮助。 最常用谓词包括:

  • GET. 浏览器使用此谓词从服务器中提取内容。 例如,在浏览器中键入 URL 时,浏览器会执行操作 GET 来请求所需的页面。 如果页面包含图形,浏览器将执行其他 GET 操作来获取图像。 GET如果操作必须向服务器传递信息,则信息将作为查询字符串中 URL 的一部分传递。
  • POST. 浏览器发送请求 POST 以提交要在服务器上添加或更改的数据。 例如, POST 谓词用于在数据库中创建记录或更改现有记录。 大多数情况下,当你填写表单并单击“提交”按钮时,浏览器会执行操作 POSTPOST在操作中,传递给服务器的数据位于页面正文中。

这些谓词之间的一个重要区别在于, GET 操作不应更改服务器上的任何内容,或者以稍微更抽象的方式表示, GET 操作不会导致服务器上的状态更改。 可以根据需要多次对同一 GET 资源执行操作,但这些资源不会更改。 (操作 GET 通常称为“安全”,或者使用技术术语,是 幂等的。) 相反,当然, POST 每次执行操作时,请求都会更改服务器上的某些内容。

两个示例将有助于说明这一区别。 使用必应或 Google 等引擎执行搜索时,填写由一个文本框组成的表单,然后单击搜索按钮。 浏览器执行操作 GET ,输入框中的值作为 URL 的一部分传递。 GET对这种类型的表单使用操作是可以的,因为搜索操作不会更改服务器上的任何资源,它只是提取信息。

现在,请考虑在线订购内容的过程。 填写订单详细信息,然后单击“提交”按钮。 此操作将是一个 POST 请求,因为该操作将导致服务器上的更改,例如新订单记录、帐户信息更改以及许多其他更改。 GET与操作不同,不能重复请求 - 如果重复POST请求,则每次重新提交请求时,都会在服务器上生成新订单。 (在这种情况下,网站通常会警告你不要多次单击提交按钮,或者禁用提交按钮,以免意外重新提交表单。)

在本教程中,你将使用 GET 操作和 POST 操作来处理 HTML 表单。 在每种情况下,我们都会解释你使用的谓词为何是合适的动词。

(若要详细了解 HTTP 谓词,请参阅 W3C 站点上的 方法定义 一文。)

大多数用户输入元素都是 HTML <input> 元素。 它们类似于<input type="type" name="name">,类型指示所需用户输入控件的类型。 这些元素是常见的元素:

  • 文本框: <input type="text">
  • 复选框: <input type="check">
  • 单选按钮: <input type="radio">
  • 按钮: <input type="button">
  • “提交”按钮: <input type="submit">

还可以使用 <textarea> 元素创建多行文本框,并使用 <select> 元素创建下拉列表或可滚动列表。 (有关 HTML 表单元素的详细信息,请参阅 W3Schools 网站上的 HTML 窗体和输入 。)

属性 name 非常重要,因为名称是稍后获取元素值的方式,稍后将看到。

有趣的部分是页面开发人员对用户输入执行的操作。 没有与这些元素关联的内置行为。 相反,必须获取用户已输入或选择的值,并使用它们执行某些操作。 这就是本教程中将学习的内容。

提示

HTML5 和输入表单

如你所知,HTML 处于过渡阶段,最新版本 (HTML5) 包括对用户输入信息更直观的方式的支持。 例如,在 HTML5 中, (页面开发人员) 可以告诉页面你希望用户输入日期。 然后,浏览器可以自动显示日历,而无需用户手动输入日期。 但是,HTML5 是新的,并非所有浏览器都支持。

ASP.NET 网页在用户浏览器支持的范围内支持 HTML5 输入。 有关 HTML5 中元素的新属性 <input> 的概念,请参阅 W3Schools 网站上的 HTML <输入> 类型 Attribute

创建窗体

在 WebMatrix 的 “文件” 工作区中,打开 Movies.cshtml 页。

在结束</h1>标记之后和调用的grid.GetHtml开始<div>标记之前,添加以下标记:

<form method="get">
  <div>
    <label for="searchGenre">Genre to look for:</label>
    <input type="text" name="searchGenre" value="" />
    <input type="Submit" value="Search Genre" /><br/>
    (Leave blank to list all movies.)<br/>
    </div>
</form>

此标记创建包含名为 searchGenre 的文本框和提交按钮的窗体。 文本框和提交按钮包含在属性设置为 getmethod元素中<form>。 (请记住,如果不将文本框和提交按钮放在元素内 <form> ,则单击按钮时不会提交任何内容。) 在此处使用 GET 谓词,因为您正在创建一个窗体,该窗体不会在服务器上进行任何更改 , 它只会导致搜索。 (在上一教程中,你使用了一种方法 post ,即向服务器提交更改的方式。你将在下一教程中看到这一点。)

运行页面。 尽管尚未定义窗体的任何行为,但可以看到它的外观:

包含“流派”搜索框的“电影”页

在文本框中输入一个值,如“喜剧”。然后单击“ 搜索流派”。

记下页面的 URL。 由于将 <form> 元素的 method 属性设置为 get,因此输入的值现在是 URL 中查询字符串的一部分,如下所示:

http://localhost:45661/Movies.cshtml?searchGenre=Comedy

读取窗体值

该页已包含一些代码,这些代码获取数据库数据并在网格中显示结果。 现在,必须添加一些读取文本框值的代码,以便可以运行包含搜索词的 SQL 查询。

由于将窗体的 方法设置为 get,因此可以使用如下所示的代码读取输入到文本框中的值:

var searchTerm = Request.QueryString["searchGenre"];

对象 Request.QueryString (QueryString 对象的 属性 Request) 包括作为操作的一部分 GET 提交的元素的值。 属性 Request.QueryString 包含一个 集合 (窗体中提交的值的列表) 。 若要获取任何单个值,请指定所需的元素的名称。 因此,必须在创建文本框的元素 (searchTerm) 上<input>具有 name 属性。 (有关对象的详细信息 Request ,请参阅 稍后的边栏 。)

它非常简单,可以读取文本框的值。 但是,如果用户未在文本框中输入任何内容,但单击了“ 搜索 ”,则可以忽略该单击,因为没有任何可搜索内容。

下面的代码是演示如何实现这些条件的示例。 (你无需添加此代码;稍后你将完成此操作。)

if(!Request.QueryString["searchGenre"].IsEmpty() ) {
     // Do something here
}

测试以这种方式分解:

  • 获取 的值Request.QueryString["searchGenre"],即在名为 searchGenre的元素中<input>输入的值。
  • 使用 IsEmpty 方法找出它是否为空。 此方法是确定某些 ((例如,窗体元素) 是否包含值)的标准方法。 但真的,你只关心它 不是 空的,因此...
  • ! 测试前面 IsEmpty 添加 运算符。 (运算符 ! 表示逻辑 NOT) 。

在纯英语中,整个 if 条件将转换为以下内容: 如果窗体的 searchGenre 元素不为空,则...

此块设置创建使用搜索词的查询的阶段。 将在下一部分执行该操作。

提示

Request 对象

对象 Request 包含请求或提交页面时浏览器发送给应用程序的所有信息。 此对象包括用户提供的任何信息,例如文本框值或要上传的文件。 它还包括各种附加信息,如 Cookie、URL 查询字符串 ((如果有任何) )中的值、正在运行的页面的文件路径、用户使用的浏览器类型、在浏览器中设置的语言列表等。

对象 Request 是值的 集合 (列表) 。 通过指定其名称,从集合中获取单个值:

var someValue = Request["name"];

对象 Request 实际上公开了多个子集。 例如:

  • Request.Form如果请求是POST请求,则从提交的<form>元素内的元素中提供值。
  • Request.QueryString 仅提供 URL 的查询字符串中的值。 (在类似于 的 http://mysite/myapp/page?searchGenre=action&page=2URL 中, ?searchGenre=action&page=2 URL 的 节是查询字符串。)
  • Request.Cookies 集合使你能够访问浏览器发送的 Cookie。

若要获取已知位于已提交的表单中的值,可以使用 Request["name"]。 或者,可以将更具体的版本 Request.Form["name"] (用于 POST 请求) 或 Request.QueryString["name"] (GET) 的请求。 当然, name 是要获取的项的名称。

要获取的项的名称在所使用的集合中必须是唯一的。 这就是为什么 对象提供 和 等Request.FormRequest.QueryString子集的原因Request。 假设页面包含名为 的 userName 表单元素, 并且还 包含名为 的 userNameCookie。 如果获得 Request["userName"],则不明确是要窗体值还是 Cookie。 但是,如果获取 Request.Form["userName"]Request.Cookie["userName"],则明确表示要获取哪个值。

最好是具体化并使用你感兴趣的 子 Request 集,例如 Request.FormRequest.QueryString。 对于在本教程中创建的简单页面,它可能没有任何区别。 但是,在创建更复杂的页面时,使用显式版本 Request.FormRequest.QueryString 有助于避免页面包含表单 (或多个窗体) 、Cookie、查询字符串值等时可能出现的问题。

使用搜索词创建查询

了解如何获取用户输入的搜索词后,可以创建使用该搜索词的查询。 请记住,若要从数据库中获取所有电影项,将使用类似于以下语句的 SQL 查询:

SELECT * FROM Movies

若要仅获取某些电影,必须使用包含 子句的 Where 查询。 此子句允许设置查询返回的行的条件。 下面是一个示例:

SELECT * FROM Movies WHERE Genre = 'Action'

基本格式为 WHERE column = value。 除了 之外 =,还可以使用不同的运算符,例如 > , (大于) 、 < (小于) 、 <> (不等于) 、 <= (小于或等于) 等,具体取决于要查找的内容。

如果你想知道,SQL 语句不区分大小写 - SELECT 与 (甚至select) 相同Select。 但是,人们通常会在 SQL 语句(如 SELECTWHERE)中大写关键字,使其更易于阅读。

将搜索词作为参数传递

() WHERE Genre = 'Action' 搜索特定流派非常简单,但你希望能够搜索用户输入的任何流派。 为此,请创建 SQL 查询,其中包含要搜索的值的占位符。 它将类似于以下命令:

SELECT * FROM Movies WHERE Genre = @0

占位符是 @ 后跟零的字符。 你可能猜到,一个查询可以包含多个占位符,它们将被命名为 @0@1@2等。

若要设置查询并实际向其传递值,请使用如下所示的代码:

selectCommand = "SELECT * FROM Movies WHERE Genre = @0";
selectedData = db.Query(selectCommand, Request.QueryString["searchGenre"]);

此代码类似于你为在网格中显示数据所做的操作。 只存在下述区别:

  • 查询包含占位符 (WHERE Genre = @0") 。
  • 查询将放入变量 (selectCommand) ;之前,将查询直接传递给 方法 db.Query
  • 调用 db.Query 方法时,将同时传递查询和要用于占位符的值。 (如果查询有多个占位符,则将它们作为单独的值传递给 method.)

如果将所有这些元素放在一起,将获得以下代码:

if(!Request.QueryString["searchGenre"].IsEmpty() ) { 
    searchTerm = Request.QueryString["searchGenre"];
    selectCommand = "SELECT * FROM Movies WHERE Genre = @0";
    selectedData = db.Query(selectCommand, searchTerm);
}

注意

重要说明! 使用占位符 ((如 @0) )将值传递给 SQL 命令对于安全性 非常重要 。 在此处使用变量数据的占位符查看它的方式是构造 SQL 命令的唯一方法。

切勿通过将 (从用户那里获取的文本和值串联) 来构造 SQL 语句。 将用户输入串联到 SQL 语句中会打开站点,从而遭到 SQL 注入攻击 ,恶意用户会将值提交到你的页面,从而攻击数据库。 (可以在 MSDN 网站的 SQL 注入 一文中了解详细信息)

使用搜索代码更新电影页面

现在可以更新 Movies.cshtml 文件中的代码。 若要开始,请将页面顶部的代码块中的代码替换为以下代码:

var db = Database.Open("WebPagesMovies");
var selectCommand = "SELECT * FROM Movies";
var searchTerm = "";

此处的区别在于,你已将查询放入变量中 selectCommand ,稍后将传递给 db.Query 该变量。 通过将 SQL 语句放入变量中,可以更改语句,这是执行搜索时要执行的操作。

你还删除了这两行,稍后将放回这些行:

var selectedData = db.Query("SELECT * FROM Movies");
var grid = new WebGrid(source: selectedData, rowsPerPage: 3);

你不想运行查询, (即调用 db.Query) ,并且你也不想初始化 WebGrid 帮助程序。 在确定必须运行哪个 SQL 语句后,你将执行这些操作。

在此重写块之后,可以添加用于处理搜索的新逻辑。 完成的代码如下所示。 更新页面中的代码,使其与以下示例匹配:

@{
    var db = Database.Open("WebPagesMovies") ;
    var selectCommand = "SELECT * FROM Movies";
    var searchTerm = "";

    if(!Request.QueryString["searchGenre"].IsEmpty() ) {
        selectCommand = "SELECT * FROM Movies WHERE Genre = @0";
        searchTerm = Request.QueryString["searchGenre"];
    }

    var selectedData = db.Query(selectCommand, searchTerm);
    var grid = new WebGrid(source: selectedData, defaultSort: "Genre", rowsPerPage:3);
}

页面现在的工作方式如下所示。 每次页面运行时,代码都会打开数据库, selectCommand 并将 变量设置为 SQL 语句,该语句从 Movies 表中获取所有记录。 该代码还会初始化 searchTerm 变量。

但是,如果当前请求包含 元素的值 searchGenre ,则代码将设置为 selectCommand 不同的查询,即,设置为包含 Where 用于搜索流派的 子句的查询。 它还将 设置为 searchTerm 为搜索框传递的任何内容, (这可能不) 。

无论 中的 selectCommandSQL 语句是什么,代码都会调用 db.Query 来运行查询,并向其传递 中 searchTerm的内容。 如果 中 searchTerm没有任何内容,则无关紧要,因为在这种情况下,没有参数可向 selectCommand 其中传递值。

最后,代码使用查询结果初始化 WebGrid 帮助程序,就像之前一样。

通过将 SQL 语句和搜索词放入变量中,可以看到,为代码增加了灵活性。 如本教程后面部分所示,可以使用此基本框架并不断为不同类型的搜索添加逻辑。

测试按流派搜索功能

在 WebMatrix 中,运行 Movies.cshtml 页。 你将看到包含“流派”文本框的页面。

输入已为其中一个测试记录输入的流派,然后单击“ 搜索”。 这一次,你只看到与该流派匹配的电影列表:

搜索流派“喜剧”后的电影页面列表

输入其他流派并再次搜索。 尝试使用所有小写字母或全大写字母进入流派,以便可以看到搜索不区分大小写。

“记住”用户输入的内容

你可能已注意到,在输入流派并单击“ 搜索流派”后,会看到该流派的列表。 但是,搜索文本框为空,换句话说,它不记得你输入的内容。

请务必了解发生此行为的原因。 提交页面时,浏览器会向 Web 服务器发送请求。 当 ASP.NET 获取请求时,它会创建页面的全新实例,运行其中的代码,然后再次将页面呈现到浏览器。 但实际上,页面并不知道你只是使用以前的版本本身。 它只知道它收到了一个请求,其中包含一些表单数据。

每次请求页面(无论是第一次还是通过提交页面)时,你都会获得一个新页面。 Web 服务器没有上次请求的内存。 ASP.NET,浏览器也不 ASP.NET。 页面的这些独立实例之间的唯一连接是你在它们之间传输的任何数据。 例如,如果提交页面,则新页面实例可以获取先前实例发送的表单数据。 (在页面之间传递数据的另一种方法是使用 cookies.)

描述这种情况的正式方法是说网页是 无状态的。 Web 服务器和页面本身以及页面中的元素不维护有关页面先前状态的任何信息。 Web 是这样设计的,因为维护单个请求的状态会迅速耗尽 Web 服务器的资源,后者通常每秒处理数千个甚至数十万个请求。

因此,文本框为空。 提交页面后,ASP.NET 创建了页面的新实例,并运行代码和标记。 该代码中没有任何内容告知 ASP.NET 将值放入文本框中。 因此,ASP.NET 未执行任何操作,并且文本框呈现时没有值。

实际上有一种简单的方法来解决此问题。 在代码 中,可在 文本框中输入的流派 - 它位于 中 Request.QueryString["searchGenre"]

更新文本框的标记,使 value 特性从 searchTerm获取其值,如以下示例:

<input type="text" name="searchGenre" value="@Request.QueryString["searchGenre"]" />

在此页中,还可以将 属性设置为 valuesearchTerm 变量,因为该变量还包含你输入的流派。 但是, Request 使用 对象设置 属性, value 如下所示是完成此任务的标准方法。 (假设你甚至想要执行此操作 -在某些情况下,你可能想要呈现页面, 而不 在字段中显示值。这完全取决于应用的情况。)

注意

无法“记住”用于密码的文本框的值。 允许用户使用代码填写密码字段将是一个安全漏洞。

再次运行页面,输入流派,然后单击“ 搜索流派”。 这一次,你不仅会看到搜索结果,而且文本框会记住上次输入的内容:

显示文本框已“记住”上一个条目的页面

在游戏中搜索任何Word

现在可以搜索任何流派,但可能还需要搜索标题。 搜索时很难完全正确获取标题,因此可以搜索标题内任何位置显示的单词。 若要在 SQL 中执行此操作,请使用 LIKE 运算符和语法,如下所示:

SELECT * FROM Movies WHERE Title LIKE '%adventure%'

此命令获取其标题包含“adventure”的所有电影。 使用 LIKE 运算符时,可以在搜索词中包含通配符 % 。 搜索 LIKE 'adventure%' 意味着“从'adventure'开始”。 (技术上,它意味着“字符串'adventure'后跟任何内容”。) 同样,搜索词 LIKE '%adventure' 表示“任何内容后跟字符串'adventure'”,这是另一种表示“以'adventure'结尾”的方式。

因此,搜索词 LIKE '%adventure%' 的意思是“具有'adventure'在标题中的任何位置。” (技术上,“标题中的任何内容,后跟'adventure',后跟任何内容。)

在 元素内<form>,紧跟在结束元素 (的结束标记 (的结束</div></form>标记下添加以下标记) :

<div>
  <label for="SearchTitle">Movie title contains the following:</label>
  <input type="text" name="searchTitle" value="@Request.QueryString["searchTitle"]" />
  <input type="Submit" value="Search Title" /><br/>
</div>

处理此搜索的代码类似于流派搜索的代码,但必须组合 LIKE 搜索。 在页面顶部的代码块内,在流派搜索的块后面if添加此if块:

if(!Request.QueryString["searchTitle"].IsEmpty() ) {
    selectCommand = "SELECT * FROM Movies WHERE Title LIKE @0";
    searchTerm = "%" + Request["searchTitle"] + "%";
}

此代码使用前面看到的相同逻辑,只不过搜索使用 LIKE 运算符,并且代码在搜索词前后放置“%”。

请注意,将另一个搜索添加到页面是多么容易。 你只需执行以下操作:

  • 创建一个 if 块,用于测试相关搜索框是否具有值。
  • selectCommand 变量设置为新的 SQL 语句。
  • searchTerm 变量设置为要传递给查询的值。

下面是完整的代码块,其中包含游戏搜索的新逻辑:

@{
    var db = Database.Open("WebPagesMovies") ;
    var selectCommand = "SELECT * FROM Movies";
    var searchTerm = "";

    if(!Request.QueryString["searchGenre"].IsEmpty() ) {
        selectCommand = "SELECT * FROM Movies WHERE Genre = @0";
        searchTerm = Request.QueryString["searchGenre"];
    }

   if(!Request.QueryString["searchTitle"].IsEmpty() ) {
        selectCommand = "SELECT * FROM Movies WHERE Title LIKE @0";
        searchTerm = "%" + Request["searchTitle"] + "%";
    }

    var selectedData = db.Query(selectCommand, searchTerm);
    var grid = new WebGrid(source: selectedData, defaultSort: "Genre", rowsPerPage:8);
}

下面总结了此代码的用途:

  • 变量 searchTermselectCommand 在顶部初始化。 你将将这些变量设置为相应的搜索词 ((如果有任何) )以及基于用户在页面中执行的操作的适当 SQL 命令。 默认搜索是从数据库获取所有电影的简单情况。
  • 在 和 searchTitle的测试searchGenre中,代码将设置为searchTerm要搜索的值。 这些代码块还设置为 selectCommand 该搜索的相应 SQL 命令。
  • 方法 db.Query 仅调用一次,使用 中 selectedCommand 任何 SQL 命令以及 中 searchTerm的任何值。 如果没有搜索词 (没有流派,也没有标题词) ,则 的值 searchTerm 是空字符串。 但是,这并不重要,因为在这种情况下,查询不需要参数。

测试标题搜索功能

现在可以测试已完成的搜索页面。 运行 Movies.cshtml

输入流派并单击“ 搜索流派”。 网格显示该流派的电影,就像以前一样。

输入标题词,然后单击“ 搜索标题”。 网格显示标题中具有该单词的电影。

在标题中搜索“The”后的电影页面列表

将两个文本框留空,然后单击任一按钮。 网格显示所有电影。

组合查询

你可能会注意到,可以执行的搜索是独占的。 不能同时搜索标题和流派,即使两个搜索框中都有值。 例如,无法搜索标题包含“Adventure”的所有动作电影。 (现在对页面进行编码时,如果同时输入流派和标题的值,则标题搜索将优先。) 若要创建组合条件的搜索,则必须创建具有以下语法的 SQL 查询:

SELECT * FROM Movies WHERE Genre = @0 AND Title LIKE @1

并且必须使用类似以下语句来运行查询 (大致) :

var selectedData = db.Query(selectCommand, searchGenre, searchTitle);

如你所看到的,创建逻辑以允许搜索条件的许多排列可能会有点复杂。 因此,我们将在此处停止。

即将推出下一步

在下一教程中,你将创建一个页面,该页面使用表单允许用户将电影添加到数据库。

@{
    var db = Database.Open("WebPagesMovies") ;
    var selectCommand = "SELECT * FROM Movies";
    var searchTerm = "";

    if(!Request.QueryString["searchGenre"].IsEmpty() ) {
        selectCommand = "SELECT * FROM Movies WHERE Genre = @0";
        searchTerm = Request.QueryString["searchGenre"];
    }

    if(!Request.QueryString["searchTitle"].IsEmpty() ) {
        selectCommand = "SELECT * FROM Movies WHERE Title LIKE @0";
        searchTerm = "%" + Request["searchTitle"] + "%";
    }

    var selectedData = db.Query(selectCommand, searchTerm);
    var grid = new WebGrid(source: selectedData, defaultSort: "Genre", rowsPerPage:3);
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Movies</title>
    <style type="text/css">
      .grid { margin: 4px; border-collapse: collapse; width: 600px; }
      .grid th, .grid td { border: 1px solid #C0C0C0; padding: 5px; }
      .head { background-color: #E8E8E8; font-weight: bold; color: #FFF; }
      .alt { background-color: #E8E8E8; color: #000; }
    </style>
  </head>
  <body>
    <h1>Movies</h1>
      <form method="get">
        <div>
        <label for="searchGenre">Genre to look for:</label>
        <input type="text" name="searchGenre" value="@Request.QueryString["searchGenre"]" />
        <input type="Submit" value="Search Genre" /><br/>
        (Leave blank to list all movies.)<br/>
        </div>

        <div>
          <label for="SearchTitle">Movie title contains the following:</label>
          <input type="text" name="searchTitle" value="@Request.QueryString["searchTitle"]" />
          <input type="Submit" value="Search Title" /><br/>
        </div>
      </form>

    <div>
      @grid.GetHtml(
        tableStyle: "grid",
        headerStyle: "head",
        alternatingRowStyle: "alt",
        columns: grid.Columns(
          grid.Column("Title"),
          grid.Column("Genre"),
          grid.Column("Year")
        )
      )
    </div>
  </body>
</html>

其他资源