搜索

注意

此处使用最新版本的 Visual Studio 提供了本教程的更新版本。 新教程使用 ASP.NET Core MVC,这比本教程提供了许多改进。

本教程介绍具有控制器和视图的 ASP.NET Core MVC。 Razor Pages 是 ASP.NET Core 中的一种新替代方法,它是一种基于页面的编程模型,可简化 Web UI 的生成过程并提高效率。 建议先尝试 Razor 页面教程,再使用 MVC 版本。 Razor 页面教程:

  • 易于关注。
  • 涵盖更多功能。
  • 是新应用开发的首选方法。

添加搜索方法和搜索视图

在本部分中,你将向操作方法添加搜索功能 Index ,以便按流派或名称搜索电影。

先决条件

若要匹配本部分的屏幕截图,需要 (F5) 运行应用程序,并将以下电影添加到数据库。

标题 发布日期 流派 价格
鬼怪 6/8/1984 喜剧 6.99
幽灵怪人 II 6/16/1989 喜剧 6.99
猿行星 3/27/1986 操作 5.99

更新索引窗体

首先,将 Index 操作方法更新为现有 MoviesController 类。 代码如下:

public ActionResult Index(string searchString) 
{           
    var movies = from m in db.Movies 
                 select m; 
 
    if (!String.IsNullOrEmpty(searchString)) 
    { 
        movies = movies.Where(s => s.Title.Contains(searchString)); 
    } 
 
    return View(movies); 
}

方法的第一行 Index 创建以下 LINQ 查询以选择电影:

var movies = from m in db.Movies 
                 select m;

此时已定义查询,但尚未针对数据库运行。

searchString如果 参数包含字符串,则使用以下代码修改电影查询以筛选搜索字符串的值:

if (!String.IsNullOrEmpty(searchString)) 
{ 
    movies = movies.Where(s => s.Title.Contains(searchString)); 
}

上面的 s => s.Title 代码是 Lambda 表达式。 Lambda 在基于方法的 LINQ 查询中用作标准查询运算符方法的参数,例如上述代码中使用的 Where 方法。 在定义 LINQ 查询或通过调用 或 OrderByWhere方法进行修改时,不会执行 LINQ 查询。 相反,查询执行是延迟的,这意味着表达式的计算会延迟,直到实际循环访问其实现的值或 ToList 调用 方法。 在 Search 示例中,查询在 Index.cshtml 视图中执行。 有关延迟执行查询的详细信息,请参阅Query Execution(查询执行)。

注意

Contains 方法在数据库上运行,而不是上面的 c# 代码。 在数据库上, Contains 映射到 SQL LIKE,这不区分大小写。

现在,可以更新 Index 将窗体显示给用户的视图。

运行应用程序并导航到 /Movies/Index。 将查询字符串(如 ?searchString=ghost)追加到 URL。 筛选的电影将显示出来。

SearchQryStr

如果将 方法的 Index 签名更改为具有名为 id的参数,该 id 参数将匹配 {id}App_Start\RouteConfig.cs 文件中设置的默认路由的占位符。

{controller}/{action}/{id}

原始 Index 方法如下所示:

public ActionResult Index(string searchString) 
{           
    var movies = from m in db.Movies 
                 select m; 
 
    if (!String.IsNullOrEmpty(searchString)) 
    { 
        movies = movies.Where(s => s.Title.Contains(searchString)); 
    } 
 
    return View(movies); 
}

修改后 Index 的方法如下所示:

public ActionResult Index(string id) 
{ 
    string searchString = id; 
    var movies = from m in db.Movies 
                 select m; 
 
    if (!String.IsNullOrEmpty(searchString)) 
    { 
        movies = movies.Where(s => s.Title.Contains(searchString)); 
    } 
 
    return View(movies); 
}

现可将搜索标题作为路由数据( URL 段)而非查询字符串值进行传递。

显示“M V C 电影索引”页的屏幕截图。本地主机冒号 1 2 3 4 正斜杠 电影正斜杠索引正斜杠幽灵位于 U R L 字段,并用红色圈。

但是,不能指望用户在每次要搜索电影时都修改 URL。 因此需要添加 UI 来帮助他们筛选电影。 如果更改了 方法的 Index 签名以测试如何传递路由绑定 ID 参数,请重新更改它,以便 Index 方法采用名为 的 searchString字符串参数:

public ActionResult Index(string searchString) 
{           
    var movies = from m in db.Movies 
                 select m; 
 
    if (!String.IsNullOrEmpty(searchString)) 
    { 
        movies = movies.Where(s => s.Title.Contains(searchString)); 
    } 
 
    return View(movies); 
}

打开 Views\Movies\Index.cshtml 文件,然后在 之后 @Html.ActionLink("Create New", "Create")添加下面突出显示的表单标记:

@model IEnumerable<MvcMovie.Models.Movie> 
 
@{ 
    ViewBag.Title = "Index"; 
} 
 
<h2>Index</h2> 
 
<p> 
    @Html.ActionLink("Create New", "Create") 
     
     @using (Html.BeginForm()){    
         <p> Title: @Html.TextBox("SearchString") <br />   
         <input type="submit" value="Filter" /></p> 
        } 
</p>

帮助 Html.BeginForm 程序创建一个开始 <form> 标记。 当用户 Html.BeginForm 通过单击“ 筛选 ”按钮提交表单时,帮助程序会使表单发布到自己。

Visual Studio 2013在显示和编辑“查看”文件时得到了很好的改进。 在打开视图文件的情况下运行应用程序时,Visual Studio 2013调用正确的控制器操作方法来显示视图。

显示索引点 c s h t m l 选项卡和解决方案资源管理器打开的屏幕截图。在解决方案资源管理器中,子文件夹“电影”处于打开状态,并选择了“索引点 c s h t m l”。

在 Visual Studio 中打开“索引”视图 (如上图) 所示,点击“Ctr F5”或“F5”以运行该应用程序,然后尝试搜索电影。

显示“索引”页的屏幕截图,其中已将标题输入到“标题”字段。

方法没有 HttpPost 重载 Index 。 不需要它,因为 方法不会更改应用程序的状态,只是筛选数据。

可添加以下 HttpPost Index 方法。 在这种情况下,操作调用程序将匹配 HttpPost Index 方法,并且 HttpPost Index 该方法将按下图所示运行。

[HttpPost] 
public string Index(FormCollection fc, string searchString) 
{ 
    return "<h3> From [HttpPost]Index: " + searchString + "</h3>"; 
}

SearchPostGhost

但是,即使添加 Index 方法的 HttpPost 版本,其实现方式也受到限制。 假设你想要将特定搜索加入书签,或向朋友发送一个链接,让他们单击链接即可查看筛选出的相同电影列表。 请注意,HTTP POST 请求的 URL 与 get 请求的 URL 相同, (localhost:xxxxx/Movies/Index) -- URL 本身中没有搜索信息。 现在,搜索字符串信息作为表单字段值发送到服务器。 这意味着无法捕获该搜索信息以添加书签或以 URL 发送给好友。

解决方案是使用 的 BeginForm 重载,该重载指定 POST 请求应将搜索信息添加到 URL,并应将其路由到 HttpGet 方法的版本 Index 。 将现有的无 BeginForm 参数方法替换为以下标记:

@using (Html.BeginForm("Index","Movies",FormMethod.Get))

BeginFormPost_SM

现在,提交搜索时,URL 包含搜索查询字符串。 即使具备 HttpPost Index 方法,搜索也将转到 HttpGet Index 操作方法。

IndexWithGetURL

添加按流派搜索

如果添加了 HttpPost 方法的版本 Index ,请立即将其删除。

接下来,你将添加一项功能,让用户按流派搜索电影。 将 Index 方法替换为以下代码:

public ActionResult Index(string movieGenre, string searchString)
{
    var GenreLst = new List<string>();

    var GenreQry = from d in db.Movies
                   orderby d.Genre
                   select d.Genre;

    GenreLst.AddRange(GenreQry.Distinct());
    ViewBag.movieGenre = new SelectList(GenreLst);

    var movies = from m in db.Movies
                 select m;

    if (!String.IsNullOrEmpty(searchString))
    {
        movies = movies.Where(s => s.Title.Contains(searchString));
    }

    if (!string.IsNullOrEmpty(movieGenre))
    {
        movies = movies.Where(x => x.Genre == movieGenre);
    }

    return View(movies);
}

此方法的 Index 此版本采用其他参数,即 movieGenre。 前几行代码创建一个 List 对象,用于保存数据库中的电影流派。

下面的代码是一种 LINQ 查询,可从数据库中检索所有流派。

var GenreQry = from d in db.Movies 
                   orderby d.Genre 
                   select d.Genre;

代码使用 AddRange 泛型 List 集合的 方法将所有不同的流派添加到列表中。 (如果没有 Distinct 修饰符,则会添加重复的流派,例如,将在示例) 中添加喜剧两次。 然后,代码将流派列表存储在 对象中 ViewBag.MovieGenre 。 将类别数据存储 (此类电影流派) 为 中的 SelectList 对象 ViewBag,然后访问下拉列表框中的类别数据是 MVC 应用程序的典型方法。

以下代码演示如何检查 movieGenre 参数。 如果它不为空,则代码会进一步限制电影查询,以将所选电影限制为指定的流派。

if (!string.IsNullOrEmpty(movieGenre))
{
    movies = movies.Where(x => x.Genre == movieGenre);
}

如前所述,在操作方法返回) 之后,在对视图中发生的 (循环访问电影列表之前 Index ,不会在数据库上运行查询。

向索引视图添加标记以支持按流派搜索

Html.DropDownList将帮助程序添加到 Views\Movies\Index.cshtml 文件,就在帮助程序前面TextBox。 完成的标记如下所示:

@model IEnumerable<MvcMovie.Models.Movie>
@{
    ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
    @Html.ActionLink("Create New", "Create")
    @using (Html.BeginForm("Index", "Movies", FormMethod.Get))
    {
    <p>
        Genre: @Html.DropDownList("movieGenre", "All")
        Title: @Html.TextBox("SearchString")
        <input type="submit" value="Filter" />
    </p>
    }
</p>
<table class="table">

在以下代码中:

@Html.DropDownList("movieGenre", "All")

参数“MovieGenre”为帮助程序提供了在 中ViewBag查找 IEnumerable<SelectListItem> 的键DropDownListViewBag在操作方法中填充了 :

public ActionResult Index(string movieGenre, string searchString)
{
    var GenreLst = new List<string>();

    var GenreQry = from d in db.Movies
                   orderby d.Genre
                   select d.Genre;

    GenreLst.AddRange(GenreQry.Distinct());
    ViewBag.movieGenre = new SelectList(GenreLst);

    var movies = from m in db.Movies
                 select m;

    if (!String.IsNullOrEmpty(searchString))
    {
        movies = movies.Where(s => s.Title.Contains(searchString));
    }

    if (!string.IsNullOrEmpty(movieGenre))
    {
        movies = movies.Where(x => x.Genre == movieGenre);
    }

    return View(movies);
}

参数“All”提供选项标签。 如果在浏览器中检查该选项,将看到其“value”属性为空。 由于控制器仅筛选 if 字符串不 null 为空或为空,因此提交一 movieGenre 个空值会显示所有流派。

还可以将选项设置为默认选中。 如果希望将“喜剧”作为默认选项,可以按如下所示更改控制器中的代码:

ViewBag.movieGenre = new SelectList(GenreLst, "Comedy");

运行应用程序并浏览到 /Movies/Index。 尝试按流派、电影名称和这两个条件进行搜索。

显示“索引”页的屏幕截图。选择一种流派。

在本部分中,你创建了一个搜索操作方法和视图,使用户能够按电影标题和流派进行搜索。 在下一部分中,你将了解如何向模型添加属性 Movie ,以及如何添加自动创建测试数据库的初始值设定项。