MVC Tutorial Movie DIY
Razor cshtml
Razor cshtml
Razor即cshtml,是MVC的视图设计引擎.
view 目录下的 _ViewStart.cshtml
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
指定模板页 (即把_Layout.cshtml作为母页)
sample列表
>MovieStore
http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/adding-a-model
(3)index.cshtml (显示列表的Razor页)
>This @model
directive allows you to access the list of movies that the controller passed to the view by using a Model
object that's strongly typed
(model就是Controller传个Razor页的Movie对象)
@model IEnumerable<MvcMovie.Models.MoviesModel>
@{
ViewBag.Title = "Index";
}
<h2>Movies List</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
@Html.DisplayNameFor(model => model.Price)
</th>
<th>
@Html.DisplayNameFor(model => model.Title)
</th>
<th>
@Html.DisplayNameFor(model => model.RealeaseDate)
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.RealeaseDate)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
@Html.ActionLink("Details", "Details", new { id=item.ID }) |
@Html.ActionLink("Delete", "Delete", new { id=item.ID })
</td>
</tr>
}
</table>
@model IEnumearable<>
IEnumerable <类名>
枚举器,类似于集合。 使用 foreach(var item in ) 来遍历
(5)index.cshtml 和 Detail.cshtml比较
index.cshtml @model IEnumerable<MvcMovie.Models.MoviesModel>
detail.cshtml @model MvcMovie.Models.MoviesModel
index接收的是db.Movies.ToList();
detail接收的db.Movies.Find(id)
Html.DisplayFor 和 Html.ActionLink
// Html.ActionLink 根据controller传的值动态生成链接地址
@Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
(1)链接名 (2)调用Controller中的哪个Action (3)route data
The first argument to the ActionLink
method is the link text to render (for example, <a>Edit Me</a>
). The second argument is the name of the action method to invoke. The final argument is an anonymous object that generates the route data (in this case, the ID of 4).
The generated link shown in the previous image is http://localhost:xxxxx/Movies/Edit/4. The default route (established in Global.asax.cs) takes the URL pattern {controller}/{action}/{id}
. Therefore, ASP.NET translates http://localhost:xxxxx/Movies/Edit/4 into a request to the Edit
action method of the Movies
controller with the parameter ID
equal to 4.
Html.LabelFor 、 Html. EditorFor、Html.ValidationMessageFor
The Html.LabelFor
helper displays the name of the field ("Title", "ReleaseDate", "Genre", or "Price").
"). The Html.EditorFor
helper displays an HTML <input>
element
The Html.ValidationMessageFor
helper displays any validation messages associated with that property.
Html.DisplayFor
显示表的字段名
Controller里面 [HttpPost] ActionResult Edit。查看页面源码,form method=’post’. 编辑将触发
<![if !vml]><![endif]>
ModelState.IsValid (
验证数据)
The ASP.NET MVC model binder takes the posted form values and creates a Movie
object that's passed as the movie
parameter. The ModelState.IsValid
method verifies that the data submitted in the form can be used to modify (edit or update) a Movie
object. If the data is valid, the movie data is saved to the Movies
collection of the db (MovieDBContext
instance). The new movie data is saved to the database by calling the SaveChanges
method of MovieDBContext
. After saving the data, the code redirects the user to the Index
action method of the MoviesController
class, which displays the of movie collection, including the changes just made..
禁用Get 方法修改数据
Modifying data in an HTTP GET method is a security risk, as described in the blog post entry ASP.NET MVC Tip #46 – Don’t use Delete Links because they create Security Holes
Linq简介
. LINQ的处理的核心对象就是IEnumerable可枚举对象也包括了泛型枚举,换句话说当你要处理的对象为IEnumerable类型对象时即可使用LINQ操作它
语法说明,每个LINQ语句都以from作为开头,以select作为结束,这点和T-SQL语法不通的切记先入为主的思考。其他关键字如where则类似T-SQL作为筛选判断条件。
样例:IEnumerable<T> nums = from n in nums where ....orderby... select....
1. 关键字var :
指示编译器根据初始化语句右侧的表达式推断变量的类型。 推断类型可以是内置类型、匿名类型、用户定义类型或 .NET Framework 类库中定义的类型。这样我们就可以在上述的LINQ表达式中 例如可简写为:
var nums = from n in nums where .... orderby... select....
实例:
(1)
A:List, B:List. 将A、B中共有的 添加到List C中
IEnumerable<int> C = from a in A
from b in B
where a==b
select a;
(2)
普通查询
var query = from num in num
select num.ProperyA
筛选查询
var query = from obj in objs
where obj.ProperyA > Condition
select obj
分组查询
var query = from obj in objs
groupobj by obj.PropertyA into g
orderby g.Key
select g;
注意,在此示例里,关键字 into 不是必须的,使用 into 时,必须继续编写该查询,并最终用一个 select 语句或另一个 group 子句结束该查询。
内联查询
var query= from obj1 in objs1
join obj2 in objs2 on obj1.ID equals obj2.ID
selectnew { A= obj1.Property, B = obj2.Property };
左外联查询
var query = from obj1 in objs1
join obj2 in objs2 on obj1.ID equals obj2.Obj1ID into g
from subpet in g.DefaultIfEmpty()
selectnew { P1 = obj1.P1, P2 = (subpet == null ? null : subpet.P2 ) };
添加Search方法
(1)在MovieController中添加 ActionResult
public ActionResult SearchIndex(string key)
{
var movies = from model in db.MoviesModel
select model;
if (!String.IsNullOrEmpty(key))
{
movies = movies.Where(s => s.Title.Contains(key));
}
return View(movies);
}
(2)为ActionResult添加VIew
<![if !vml]><![endif]>
这样,会生成
SearchIndex.cshtml视图。
(3)检测关键字搜索功能:
在url中输入以下
http://localhost:1379/Movies/SearchIndex?key=
<![if !vml]><![endif]>
http://localhost:1379/Movies/SearchIndex?key=Harry
<![if !vml]><![endif]>
这就是搜索功能
现在改成按id搜索
添加输入框
Lambda表达式 =>
常用在Linq语句的条件中
http://msdn.microsoft.com/en-us/library/bb397687.aspx
相当于 匿名函数。 x=>x*x
=>左侧是函数参数
=>右侧是函数体
返回值就是 函数体的值。
Html.BeginForm
The Html.BeginForm
helper creates an opening <form>
tag. The Html.BeginForm
helper causes the form to post to itself when the user submits the form by clicking the Filter button.
从前台控制调用 Get方法还是HttpPost方法
//调用Get方法
@using (Html.BeginForm("SearchIndex", "Movies", FormMethod.Get))
{
<p> Title: @Html.TextBox("SearchString")
<input type="submit" value="Filter" /></p>
}
//调用Post方法
@using (Html.BeginForm("SearchIndex", "Movies", FormMethod.Post))
{
<p> Title: @Html.TextBox("SearchString")
<input type="submit" value="Filter" /></p>
}
按名称搜索
在Controller中添加
public ActionResult SearchIndex(string key) //输入Movies/SearchIndex时调用按名称搜索
{
var movies = from model in db.MoviesModel
select model;
if (!String.IsNullOrEmpty(key))
{
movies = movies.Where(s =>s.Title.Contains(key));
}
return View(movies);
}
右键点击SearchIndex内部,àAdd View
<![if !vml]><![endif]>
在SearchIndex.cshtml中添加 被注释的部分
@Html.ActionLink("Create New", "Create")
<!--@using (Html.BeginForm("SearchIndex", "Movies", FormMethod.Get))
{
<p> Title: @Html.TextBox("key") <!--textBox的名称要和ActionResult的形参同名-->
<input type="submit" value="Filter" /></p>
} 按名称搜索-->
Search By Genre 按Genre和名称搜索
将Controller中的SearchIndex Action替换成
public ActionResult SearchIndex(string movieGenre, string searchString) //输入Movies/SearchIndex时调用按名称搜索
{
var GenreLst = new List<string>();
var GenreQry = from d in db.MoviesModel
orderby d.Genre
select d.Genre;
GenreLst.AddRange(GenreQry.Distinct());
ViewBag.movieGenre = new SelectList(GenreLst);
var movies = from m in db.MoviesModel
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString));
}
if (string.IsNullOrEmpty(movieGenre))
return View(movies);
else
{
return View(movies.Where(x => x.Genre == movieGenre));
}
}
修改Model的字段,通过Initializer自动重建数据库
//备注:这样会删除已有的所有数据。
(1)在Model中添加字段
(2)在Model目录下添加MovieInitializer类
(3)在Globe.asax页的Application_Start的第一句添加上
Database.SetInitializer<DbMovieContext>(new MoviesInitialter());
Validating Model (输入数值 validating)
当用户add 和Edit时候,确保MovieModel输入有效
MVC和EF的 “DRY” (don’t repeat yourself) 理念
The validation support provided by ASP.NET MVC and Entity Framework Code First is a great example of the DRY principle in action. You can declaratively specify validation rules in one place (in the model class) and the rules are enforced everywhere in the application.
(1)在MoviesModel中添加引用 System.ComponentModel.DataAnnotations
(2)给MoviesModel的字段添加 约束条件(validation condition)
Now update the Movie
class to take advantage of the built-in Required
, StringLength
, and Range
validation attributes. Use the following code as an example of where to apply the attributes.
常见约束条件(放在属性前面)
必填 [Required]
日期类型 [DataType(DataType.Date)]
数值范围 [Range(1,100)]
字符串最大长度 [StriingLength(5)]
如下代码会报错:
MovieDBContext db =newMovieDBContext();
Movie movie =newMovie();
movie.Title="Gone with the Wind";
movie.Price=0.0M;
db.Movies.Add(movie);
db.SaveChanges(); // <= Will throw validation exception
总结:
不需要改变Controller和View只要在Model字段的属性上添加即可
Validate方法在哪被执行
MovieController.cs (ModelState.IsValid) 会检查Model中的所有Validation
//
// GET: /Movies/Create
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(MoviesModel moviesmodel)
{
if (ModelState.IsValid)
{
db.MoviesModel.Add(moviesmodel); //moviesmodel 是一条记录
db.SaveChanges();
return RedirectToAction("Index");
}
return View(moviesmodel);
}
The first (HTTP GET) Create
action method displays the initial Create form. The second handles the form post. The second Create
method (The HttpPost
version) calls ModelState.IsValid
to check whether the movie has any validation errors. Calling this method evaluates any validation attributes that have been applied to the object. If the object has validation errors, the Create
method redisplays the form. If there are no errors, the method saves the new movie in the database. In our movie example we are using, the form is not posted to the server when their are validation errors detetected on the client side; the second Create
method is never called. If you disable JavaScript in your browser, client validation is disabled and the second Create
method calls ModelState.IsValid
to check whether the movie has any validation errors.
Format Setting(控制显示格式)
Open the Movie.cs file and examine the Movie
class. The System.ComponentModel.DataAnnotations
namespace provides formatting attributes in addition to the built-in set of validation attributes. We've allready applied the DisplayFormat
attribute and a DataType
enumeration value to the release date and to the price fields. The following code shows the ReleaseDate
and Price
properties with the appropriate DisplayFormat
attribute.
同时添加约束和格式限制
[Range(0,100)][DataType(DataType.Currency)]
public decimal Price { get; set; }
Details和Examine
//hacker通过输入错误url看数据库错误,获取漏洞
Code First makes it easy to search for data using the Find
method. An important security feature built into the method is that the code verifies that the Find
method has found a movie before the code tries to do anything with it. For example, a hacker could introduce errors into the site by changing the URL created by the links from http://localhost:xxxx/Movies/Details/1 to something like http://localhost:xxxx/Movies/Details/12345 (or some other value that doesn't represent an actual movie). If you did not check for a null movie, a null movie would result in a database error.
Note that the HTTP Get Delete
method doesn't delete the specified movie, it returns a view of the movie where you can submit (HttpPost
) the deletion.. Performing a delete operation in response to a GET request (or for that matter, performing an edit operation, create operation, or any other operation that changes data) opens up a security hole. For more information about this, see Stephen Walther's blog entry ASP.NET MVC Tip #46 — Don't use Delete Links because they create Security Holes.
如何寻址两个Delete方法?
The HttpPost
method that deletes the data is named DeleteConfirmed
to give the HTTP POST method a unique signature or name. The two method signatures are shown below:
<![if !vml]><![endif]>
The common language runtime (CLR) requires overloaded methods to have a unique signature (same method name but different list of parameters). However, here you need two Delete methods -- one for GET and one for POST -- that both have the same signature. (They both need to accept a single integer as a parameter.)
To sort this out, you can do a couple of things. One is to give the methods different names. That's what the scaffolding mechanism did in he preceding example. However, this introduces a small problem: ASP.NET maps segments of a URL to action methods by name, and if you rename a method, routing normally wouldn't be able to find that method. The solution is what you see in the example, which is to add the ActionName(
"Delete")
attribute to the DeleteConfirmed
method. This effectively performs mapping for the routing system so that a URL that includes /Delete/ for a POST request will find the DeleteConfirmed
method.
DIY Movie
(1)增删改
(2)查 Controller中添加方法。
public ActionResult SearchIndex(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))
return View(movies);
else
{
return View(movies.Where(x => x.Genre == movieGenre));
}
}
添加SearchIndex(view),并在上面添加UI
@Html.ActionLink("Create New", "Create")
@using (Html.BeginForm("SearchIndex","Movies",FormMethod.Get)){
<p>Genre: @Html.DropDownList("movieGenre", "All")
Title: @Html.TextBox("SearchString")
<input type="submit" value="Filter" /></p>
}
(3)添加字段
>在Model中添加字段
>在Model目录下添加MovieInitializer类
public class MoviesInitializor : DropCreateDatabaseIfModelChanges<MovieDbContext>
{
protected override void Seed(MovieDbContext context)
{
var movies = new List<Movie> {
new Movie { Title = "When Harry Met Sally",
ReleasedDate=DateTime.Parse("1989-1-11"),
Genre="Romantic Comedy",
Rating ="R",
Price=7.99M},
new Movie { Title = "Ghostbusters ",
ReleasedDate=DateTime.Parse("1984-3-13"),
Genre="Comedy",
Rating ="R",
Price=8.99M},
new Movie { Title = "Ghostbusters 2",
ReleasedDate=DateTime.Parse("1986-2-23"),
Genre="Comedy",
Rating ="R",
Price=9.99M},
new Movie { Title = "Rio Bravo",
ReleasedDate=DateTime.Parse("1959-4-15"),
Genre="Western",
Rating ="R",
Price=3.99M},
};
movies.ForEach(d => context.Movies.Add(d));
}
}
>在Globe.asax页的Application_Start的第一句添加上
Database.SetInitializer<DbMovieContext>(new MoviesInitialter());
>在View中(Index,Edit,Delete,Details)添加显示