索引:

目录索引

Adding Search to an ASP.NET Core MVC app

给程序添加搜索功能

2017-3-7 7 分钟阅读时长 作者

本文内容

1.Adding Search by genre

根据音乐流派添加搜索

2.Adding search by genre to the Index view

在 Index 视图添加音乐流派搜索功能

By Rick Anderson

In this section you add search capability to the Index action method that lets you search movies by genre or name.

在本节我们将给 Index 方法添加搜索功能,可以搜索音乐流派或音乐的名字。

Update the Index method with the following code:

用下面的代码更新 Index 方法:

 public async Task<IActionResult> Index(string searchString)

 {

     var movies = from m in _context.Movie

                  select m;

     if (!String.IsNullOrEmpty(searchString))

     {

         movies = movies.Where(s => s.Title.Contains(searchString));

     }

     return View(await movies.ToListAsync());

 }

C# code

The first line of the Index action method creates a LINQ query to select the movies:

Index 方法的第一行写了一个 LINQ 查询表达式,以查询出movie数据:

 var movies = from m in _context.Movie

              select m;

C# code

The query is only defined at this point, it has not been run against the database.

这个查询表达式仅仅在此刻定义了,他是惰性的,不会向数据库请求执行。

If the searchString parameter contains a string, the movies query is modified to filter on the value of the search string:

searchString 参数包含了一个字符串,movie查询会去根据这个搜索字符串过滤查询数据:

 if (!String.IsNullOrEmpty(id))

 {

     movies = movies.Where(s => s.Title.Contains(id));

 }

C# code

The s => s.Title.Contains() code above is a Lambda Expression.

上面的 s => s.Title.Contains() 是 Lambda 表达式。

Lambdas are used in method-based LINQqueries as arguments to standard query operator methods such as the Where method or Contains (used in the code above).

Lambda 表达式被用于基于函数为参数的标准操作函数,如: Where 方法或上面的 Contains 方法。

LINQ queries are not executed when they are defined or when they are modified by calling a method such as Where, Contains or OrderBy.

LINQ 查询表达式在定义的时候不会执行,当他们被 Where, Contains or OrderBy 修改时也不会执行。

Rather, query execution is deferred.

查询的执行是被延迟的,它是惰性执行的。

That means that the evaluation of an expression is delayed until its realized value is actually iterated over or the ToListAsyncmethod is called.

意思就是说,表达式的求值会被延迟到真正的去遍历或者调用了ToListAsync 方法,才会开始计算表达式的值。

For more information about deferred query execution, see Query Execution.

查看 Query Execution 以获取更多关于表达式延迟执行的信息。

Note: The Contains method is run on the database, not in the c# code shown above.

笔记: Contains 方法会被翻译为sql并在DB中执行,而不是在C#中调用执行。

The case sensitivity on the query depends on the database and the collation.

查询表达式是依赖于集合或者DB对象的。

On SQL Server, Contains maps to SQL LIKE, which is case insensitive.

在 SQL Server 上,Contains 方法会被智能的映射为 SQL LIKE

In SQLlite, with the default collation, it's case sensitive.

在 SQLlite 中,他会智能的默认矫正。

Navigate to /Movies/Index.

在地址栏导航到 /Movies/Index 。

Append a query string such as ?searchString=Ghost to the URL.

在URL后追加一段像 ?searchString=Ghost 的查询字符串。

The filtered movies are displayed.

过滤后的movie数据就显示出来了。

If you change the signature of the Index method to have a parameter named id,

如果你更改 Index 的方法签名,使其参数名字为 id ,

the id parameter will match the optional {id} placeholder for the default routes set in Startup.cs.

id 参数将会默认匹配 Startup.cs 文件中的 {id} 可选项参数的占位符。

 app.UseMvc(routes =>

 {

     routes.MapRoute(

         name: "default",

         template: "{controller=Home}/{action=Index}/{id?}");

 });

C# code

You can quickly rename the searchString parameter to id with the rename command.

你可以使用 rename 命令快速的重命名 searchString 参数为 id 。

Right click on searchString > Rename.

右击,并选择 > Rename 菜单。

The rename targets are highlighted.

需要重命名的目标将会全部高亮显示,如下:

Change the parameter to id and all occurrences of searchString change to id.

改变参数名为 id ,下面所有出现的 searchString 都会被命名为 id 。

The previous Index method:

前面的 Index 方法,如下:

 public async Task<IActionResult> Index(string searchString)

 {

     var movies = from m in _context.Movie

                  select m;

     if (!String.IsNullOrEmpty(searchString))

     {

         movies = movies.Where(s => s.Title.Contains(searchString));

     }

     return View(await movies.ToListAsync());

 }

C# code

The updated Index method with id parameter:

更新后的 Index 方法将带有名为 id  的参数,如下:

 public async Task<IActionResult> Index(string id)

 {

     var movies = from m in _context.Movie

                  select m;

     if (!String.IsNullOrEmpty(id))

     {

         movies = movies.Where(s => s.Title.Contains(id));

     }

     return View(await movies.ToListAsync());

 }

C# code

You can now pass the search title as route data (a URL segment) instead of as a query string value.

你现在就可以将搜索标题的字符串做为路由数据的一部分而不是一个查询字符串使用了。

However, you can't expect users to modify the URL every time they want to search for a movie.

然而,你不会期望用户每次去更改URL,当他们搜索他们想要的电影的时候。

So now you'll add UI to help them filter movies.

因此,你需要增加UI来帮助他们过滤想要的movies。

If you changed the signature of the Index method to test how to pass the route-bound ID parameter, change it back so that it takes a parameter named searchString:

如果你更改了 Index 方法的签名来测试路由数据绑定,现在把他改回来,如下:

 public async Task<IActionResult> Index(string searchString)

 {

     var movies = from m in _context.Movie

                  select m;

     if (!String.IsNullOrEmpty(searchString))

     {

         movies = movies.Where(s => s.Title.Contains(searchString));

     }

     return View(await movies.ToListAsync());

 }

C# code

Open the Views/Movies/Index.cshtml file, and add the <form> markup highlighted below:

打开 Views/Movies/Index.cshtml 文件,并且添加 <form> 标签,如下面高亮部分所示:

     ViewData["Title"] = "Index";

 }

 <h2>Index</h2>

 <p>

     <a asp-action="Create">Create New</a>

 </p>

 <form asp-controller="Movies" asp-action="Index">

     <p>

         Title: <input type="text" name="SearchString">

         <input type="submit" value="Filter" />

     </p>

 </form>

 <table class="table">

     <thead>

HTML Code

The HTML <form> tag uses the Form Tag Helper, so when you submit the form, the filter string is posted to the Index action of the movies controller.

<form> 标签使用了 Form Tag Helper ,因此当你提交表单时,过滤字符串被提交到了Index  方法。

Save your changes and then test the filter.

保存你的修改,然后测试搜索功能。

There's no [HttpPost] overload of the Index method as you might expect.

正如你所料,在 Index 方法上没有 [HttpPost] 特征标记类。

You don't need it, because the method isn't changing the state of the app, just filtering data.

你不需要他,因为这个方法不会变更应用的然和状态,仅仅是查询了一些数据。

You could add the following [HttpPost] Index method.

你也可以添加 [HttpPost] ,如下的 Index 方法:

 [HttpPost]

 public string Index(string searchString, bool notUsed)

 {

     return "From [HttpPost]Index: filter on " + searchString;

 }

C# code

The notUsed parameter is used to create an overload for the Index method.

notUsed 参数被用于创建了一个重载的 Index 方法。

We'll talk about that later in the tutorial.

我们将在后面的教程中对它进行讲解。

If you add this method, the action invoker would match the [HttpPost] Index method, and the [HttpPost] Index method would run as shown in the image below.

如果你添加这个方法,action 调用器将会匹配 [HttpPost] Index 方法,并且 [HttpPost] Index 将会执行并返回如下图所示信息:

However, even if you add this [HttpPost] version of the Index method, there's a limitation in how this has all been implemented.

然而,即使你添加了 [HttpPost] 版本的 Index 方法,这也有一些限制,就是你要怎么来实现。

Imagine that you want to bookmark a particular search or you want to send a link to friends that they can click in order to see the same filtered list of movies.

猜想你想标记一些详细的搜索,或者你想给朋友发送一个连接,这个连接可以让他们看到和你一样的movies检索结果。

Notice that the URL for the HTTP POST request is the same as the URL for the GET request (localhost:xxxxx/Movies/Index) -- there's no search information in the URL.

注意到 HTTP POST 请求的URL与GET请求的URL完全相同,在URL上没有检索字符串的数据。

The search string information is sent to the server as a form field value.

检索用的字符串被做为表单字段上的值传递给服务器。

You can verify that with the browser Developer tools or the excellent Fiddler tool.

你可以用浏览器开发者工具来证实。

The image below shows the Chrome browser Developer tools:

下图展示了 Chrome 浏览器的开发者工具:

You can see the search parameter and XSRF token in the request body.

你可以在请求体中看到 搜索参数 与 XSRF 令牌。

Note, as mentioned in the previous tutorial, the Form Tag Helper generates an XSRF anti-forgery token.

注意,如前边儿教程提到的一样,是 Form Tag Helper 生成了 XSRF 防伪造令牌。

We're not modifying data, so we don't need to validate the token in the controller method.

我们不去修改数据,因此也不需要在控制器中验证令牌。

Because the search parameter is in the request body and not the URL, you can't capture that search information to bookmark or share with others.

因为查询参数在请求体中,而不是在URL中,所以你无法捕获查询信息添加书签或分享给其他人。

We'll fix this by specifying the request should be HTTP GET.

我们修复这点只需要指定请求形式为 HTTP GET 即可。

Notice how intelliSense helps us update the markup.

注意vs的智能感知如何帮助我们更新html标记。

Notice the distinctive font in the <form> tag.

注意在 <form> 标签中的不用的字体颜色。

That distinctive font indicates the tag is supported by Tag Helpers.

不同的字体颜色指明了哪些受 Tag Helpers 支持。

Now when you submit a search, the URL contains the search query string.

现在,当你提交一个查询的时候,URL中就在查询字符串中包含了查询参数。

Searching will also go to the HttpGet Index action method, even if you have a HttpPost Index method.

查询将会直接调用 HttpGet Index ,即使已经存在了一个 HttpPost Index 方法。

The following markup shows the change to the form tag:

下面的标记展示了 form 标签的变更:

 <form asp-controller="Movies" asp-action="Index" method="get">

HTML Code

Adding Search by genre

添加根据流派进行搜索的功能

Add the following MovieGenreViewModel class to the Models folder:

Models 文件夹下添加 MovieGenreViewModel 类:

 using Microsoft.AspNetCore.Mvc.Rendering;

 using System.Collections.Generic;

 namespace MvcMovie.Models

 {

     public class MovieGenreViewModel

     {

         public List<Movie> movies;

         public SelectList genres;

         public string movieGenre { get; set; }

     }

 }

C# Code

The movie-genre view model will contain:

movie-genre 视图将包含:

  • A list of movies.

一个电影列表。

  • A SelectList containing the list of genres. This will allow the user to select a genre from the list.

SelectList 将包含一系列流派,这将使用户可以在其中选取流派。

  • movieGenre, which contains the selected genre.

movieGenre ,它包含了被选择的流派。

Replace the Index method in MoviesController.cs with the following code:

使用下面的代码替换到 MoviesController.cs 文件中的 Index 方法中:

 // Requires using Microsoft.AspNetCore.Mvc.Rendering;

 public async Task<IActionResult> Index(string movieGenre, string searchString)

 {

     // Use LINQ to get list of genres.

     IQueryable<string> genreQuery = from m in _context.Movie

                                     orderby m.Genre

                                     select m.Genre;

     var movies = from m in _context.Movie

                  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);

     }

     var movieGenreVM = new MovieGenreViewModel();

     movieGenreVM.genres = new SelectList(await genreQuery.Distinct().ToListAsync());

     movieGenreVM.movies = await movies.ToListAsync();

     return View(movieGenreVM);

 }

C# Code

The following code is a LINQ query that retrieves all the genres from the database.

下面是一个 LINQ 查询,他检索了数据库中的所有流派:

 // Use LINQ to get list of genres.

 IQueryable<string> genreQuery = from m in _context.Movie

                                 orderby m.Genre

                                 select m.Genre;

C# Code

The SelectList of genres is created by projecting the distinct genres (we don't want our select list to have duplicate genres).

SelectList 由工程创建并用来给流派去重:

 movieGenreVM.genres = new SelectList(await genreQuery.Distinct().ToListAsync())

C# Code

Adding search by genre to the Index view

将流派查询添加到 Index 视图上

Update Index.cshtml as follows:

用下面代码 更新 Index.cshtml 文件:

 @model MvcMovie.Models.MovieGenreViewModel

 @{

     ViewData["Title"] = "Index";

 }

 <h2>Index</h2>

 <p>

     <a asp-action="Create">Create New</a>

 </p>

 <form asp-controller="Movies" asp-action="Index" method="get">

     <p>

         <select asp-for="movieGenre" asp-items="Model.genres">

             <option value="">All</option>

         </select>

         Title: <input type="text" name="SearchString">

         <input type="submit" value="Filter" />

     </p>

 </form>

 <table class="table">

     <thead>

         <tr>

             <th>

                 @Html.DisplayNameFor(model => model.movies[0].Title)

             </th>

             <th>

                 @Html.DisplayNameFor(model => model.movies[0].ReleaseDate)

             </th>

             <th>

                 @Html.DisplayNameFor(model => model.movies[0].Genre)

             </th>

             <th>

                 @Html.DisplayNameFor(model => model.movies[0].Price)

             </th>

             <th></th>

         </tr>

     </thead>

     <tbody>

         @foreach (var item in Model.movies)

         {

             <tr>

                 <td>

                     @Html.DisplayFor(modelItem => item.Title)

                 </td>

                 <td>

                     @Html.DisplayFor(modelItem => item.ReleaseDate)

                 </td>

                 <td>

                     @Html.DisplayFor(modelItem => item.Genre)

                 </td>

                 <td>

                     @Html.DisplayFor(modelItem => item.Price)

                 </td>

                 <td>

                     <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |

                     <a asp-action="Details" asp-route-id="@item.ID">Details</a> |

                     <a asp-action="Delete" asp-route-id="@item.ID">Delete</a>

                 </td>

             </tr>

         }

     </tbody>

 </table>

HTML Code

Examine the lambda expression used in the following HTML Helper:

检查下面html中使用的 lambda 表达式:

 @Html.DisplayNameFor(model => model.movies[0].Title)

HTML Code

In the preceding code, the DisplayNameFor HTML Helper inspects the Title property referenced in the lambda expression to determine the display name.

在上面的代码中,DisplayNameFor html帮助器函数检查 Title 属性,并决定它的界面上的显示名。

Since the lambda expression is inspected rather than evaluated, you don't receive an access violation when model, model.movies, or model.movies[0] are null or empty.

当 lambda 去检查而不是去计算时,你不需接受或 model, model.movies, or model.movies[0] are null or empty 。

When the lambda expression is evaluated (for example, @Html.DisplayFor(modelItem => item.Title)), the model's property values are evaluated.

当 lambda 计算时(例如:@Html.DisplayFor(modelItem => item.Title)),模型的属性值是被计算的。

Test the app by searching by genre, by movie title, and by both.

通过检索流派或检索标题来测试本程序。

                                         蒙

                                    2017-08-21 16:18 周一

011.Adding Search to an ASP.NET Core MVC app --【给程序添加搜索功能】的更多相关文章

  1. 007.Adding a view to an ASP.NET Core MVC app -- 【在asp.net core mvc中添加视图】

    Adding a view to an ASP.NET Core MVC app 在asp.net core mvc中添加视图 2017-3-4 7 分钟阅读时长 本文内容 1.Changing vi ...

  2. 006.Adding a controller to a ASP.NET Core MVC app with Visual Studio -- 【在asp.net core mvc 中添加一个控制器】

    Adding a controller to a ASP.NET Core MVC app with Visual Studio 在asp.net core mvc 中添加一个控制器 2017-2-2 ...

  3. 008.Adding a model to an ASP.NET Core MVC app --【在 asp.net core mvc 中添加一个model (模型)】

    Adding a model to an ASP.NET Core MVC app在 asp.net core mvc 中添加一个model (模型)2017-3-30 8 分钟阅读时长 本文内容1. ...

  4. ASP.NET Core MVC通过IViewLocationExpander扩展视图搜索路径

    IViewLocationExpander API ExpandViewLocations Razor视图路径,视图引擎会搜索该路径. PopulateValues 每次调用都会填充路由 项目目录如下 ...

  5. ASP.NET Core 中文文档 第二章 指南(4.1)ASP.NET Core MVC 与 Visual Studio 入门

    原文:Getting started with ASP.NET Core MVC and Visual Studio 作者:Rick Anderson 翻译:娄宇(Lyrics) 校对:刘怡(Alex ...

  6. 【翻译】在Visual Studio中使用Asp.Net Core MVC创建你的第一个Web API应用(一)

    HTTP is not just for serving up web pages. It's also a powerful platform for building APIs that expo ...

  7. ASP.NET Core MVC 源码学习:MVC 启动流程详解

    前言 在 上一篇 文章中,我们学习了 ASP.NET Core MVC 的路由模块,那么在本篇文章中,主要是对 ASP.NET Core MVC 启动流程的一个学习. ASP.NET Core 是新一 ...

  8. ASP.NET Core MVC和Visual Studio入门

    本教程将教你使用Visual Studio 2017创建 ASP.NET Core MVC web应用程序的基础知识. 安装Visual Studio 2017 和.Net Core 安装Visual ...

  9. 005.Getting started with ASP.NET Core MVC and Visual Studio -- 【VS开发asp.net core mvc 入门】

    Getting started with ASP.NET Core MVC and Visual Studio VS开发asp.net core mvc 入门 2017-3-7 2 分钟阅读时长 本文 ...

随机推荐

  1. (转载)jConsole,jvisualvm和jmap使用

    原文链接:http://my.oschina.net/freegarden/blog/286372 摘要 Oracle JVM自带了一些工具,观察java程序的运行,用于排错调优.正文将会对 jCon ...

  2. var与let的区别

    var与let的区别 前言: 在没接触Es6之前,我们在js中声明都是通过var来声明变量的,var声明变量虽说方便,但是,又有一些自己的诟病,下边来说一说,这三个的区别! var var相信大家都不 ...

  3. C# 汉语转拼音

    汉语转拼音或首字母 通常不少网站上有汉语转拼音功能,今天就小记下这段汉语转拼音的代码,自己测试ok,现把代码贴出来,以备日后使用: 效果 用法很简单后台使用到了两个类文件,一个是:ConvertHzT ...

  4. spring boot controller路由 url 扫描不到问题

    spring boot项目出现controller的路由没被注册,原因:启动类application跟controller不在一个包中,扫描不到controller, 如启动类在com.oyx.a,c ...

  5. javascript事件轮询

    JavaScript 运行机制详解:再谈Event Loop 一.为什么JavaScript是单线程? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么Ja ...

  6. cocos 射线检测 3D物体 (Sprite3D点击)

    看了很多朋友问怎么用一个3D物体做一个按钮,而且网上好像还真比较难找到答案, 今天翻了一下cocos源码发现Ray 已经封装了intersects函数,那么剩下的工作其实很简单了, 从屏幕的一个poi ...

  7. docker~save与load的使用

    回到目录 对于没有私有仓库来说,将本地镜像放到其它服务器上执行时,我们可以使用save和load方法,前者用来把镜像保存一个tar文件,后台从一个tar文件恢复成一个镜像,这个功能对于我们开发者来说还 ...

  8. Python中的元类(metaclass)

    推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有 ...

  9. VerilogHDL概述与数字IC设计流程学习笔记

    一.HDL的概念和特征 HDL,Hard Discrimination Language的缩写,翻译过来就是硬件描述语言.那么什么是硬件描述语言呢?为什么不叫硬件设计语言呢?硬件描述语言,顾名思义就是 ...

  10. 如何重置密码 oracle sys和system

    有时候我们会忘记oracle sys和system的密码,不用担心,通过sqlplus即可修改密码.只能修改,不能找回. 方法如下: 1.打开 cmd界面,输入sqlplus /nolog 显示结果如 ...