Bắt đầu với ASP.NET MVC3 (Phần 6: Examining the Edit Methods and Edit View)
Trong phần này, chúng ta sẽ kiểm tra các phương thức và view đã được tạo cho movie controller. Sau đó chúng ta sẽ thêm mới trang search.
Chạy ứng dụng và browse đến controller Movies bằng cách thêm /Movies vào URL. Click vào liên kết Edit để thấy URL được liên kết tới.
Liên kết Edit đã được tao ra bởi phương thức Html.ActionLink trong view Views\Movies\Index.cshtml:
@Html.ActionLink("Edit", "Edit", new { id=item.ID })
Đối tượng Html là một hepler, các thuộc tính của đối tượng này thuộc class WebViewPage. phương thức ActionLink giúp chúng ta dễ dàng tạo ra các siêu liên kết HTML động liên kết đến các phương thức trên controller. Argument đầu tiên của phương thức này là link text (ví dụ, Edit). Argument thứ hai là tên của phương thức gọi ra. cuối cùng là một
đối tượng anonymous để tạo ra đường đi (trong trường hợp này là giá trị của ID là 4).
Liên kết được tạo ra trong ảnh trước đó là
http://localhost:xxxxx/Movies/Edit/4. URL mặc định chúng ta nhận được có dạng {controller}/{action}/{id}. Vì thế, ASP.NET phiên dịch
http://localhost:xxxxx/Movies/Edit/4 thành một yêu cầu đến phương thức Edit của Movies controller với tham số ID là 4.
Ngoài ra chúng ta có thể truyền tham số vào cho phương thức bằng cách sử dụng chuỗi truy vấn. Ví dụ, một URL
http://localhost:xxxxx/Movies/Edit?ID=4 để truyền tham số ID là 4 cho phương thức của Movies controller.
Mở controller Movies và chỉnh sửa 2 phương thức như sau:
//
// GET: /Movies/Edit/5
public ActionResult Edit(int id)
{
Movie movie = db.Movies.Find(id);
return View(movie);
}
//
// POST: /Movies/Edit/5
[HttpPost]
public ActionResult Edit(Movie movie)
{
if (ModelState.IsValid)
{
db.Entry(movie).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(movie);
}
Lưu ý là phương thức Edit được xử lí bởi thuộc tính HttpPost. Thuộc tính này chỉ định rằng sự nạp chồng phương thức Edit có thể được gọi ra cho POST request. Chúng ta có thể áp dụng thuộc tính HttpGet cho phương thức edit đầu tiên, nhưng không cần thiết bởi vì nó đã mặc định như thế.
Phương thức HttpGet Edit nhận vào tham số là ID của movie, sau đó sẽ tìm movie bằng cách sử dụng phương thức EF Find, và trả về movie được chọn để Edit view. Khi hệ thống scaffold tạo Edit view, nó sẽ kiểm tra class Movie và tao code để render ra thành phần
và cho mỗi thuộc tính của class. Ví dụ sau cho thấy Edit view đã được tạo: @model MvcMovie.Models.Movie @{ ViewBag.Title = "Edit"; }Edit type="text/javascript"> type="text/javascript"> @using (Html.BeginForm()) { @Html.ValidationSummary(true) Movie @Html.HiddenFor(model => model.ID) @Html.LabelFor(model => model.Title)
@Html.EditorFor(model => model.Title) @Html.ValidationMessageFor(model => model.Title)
@Html.LabelFor(model => model.ReleaseDate)
@Html.EditorFor(model => model.ReleaseDate) @Html.ValidationMessageFor(model => model.ReleaseDate)
@Html.LabelFor(model => model.Genre)
@Html.EditorFor(model => model.Genre) @Html.ValidationMessageFor(model => model.Genre)
@Html.LabelFor(model => model.Price)
@Html.EditorFor(model => model.Price) @Html.ValidationMessageFor(model => model.Price)
} @Html.ActionLink("Back to List", "Index")
Scaffold code sử dụng một vài phương thức helper để tổ chức luồng HTML markup. Html.LabelFor dùng để hiển thị tên trường (ví dụ như tiêu đề, Ngày phát hành, Thể loại, Gía). Html.EditorFor hiển thị một thẻ . Html.ValidationMessageFor hiển thị bấy kì tin nhắn kiểm tra dữ liệu liên kết với thuộc tính đó. (Scaffold là có nghĩa là giàn giáo. Ở nước ngoài, giàn giáo xếp lại được, khi cần dựng lên, ghép cao hơn để xây dựng. Thuật ngữ Scaffold xuất hiện phổ biến trong Ruby On Rails để mô tả về khung mã nguồn tự động sinh ra cho các hàm Create, Read, Update, Delete (CRUD). Như vậy lập trình không phải viết nhiều đoạn code lặp đi lặp lại nữa) Chạy ứng dụng và điều hướng đến /Movies URL. Click liên kết Edit. Trong trình duyệt, xem source của trang chúng ta sẽ thấy như trong ví dụ sau: Edit Thành phần là một thành phần của HTML Form mà thuộc tính action được set post đến URL /Movies/Edit. Dữ liệu form sẽ được post đến server khi button Edit được click. Xử lí POST request List sau đây trình bày phiên bản HttpPost của phương thức Edit [HttpPost] public ActionResult Edit(Movie movie) { if (ModelState.IsValid) { db.Entry(movie).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(movie); } ASP.NET framework model gắn kết các giá trị của form được post và tạo một đối tượng Movie được truyên đi như một tham số. Model.IsValid kiểm tra dữ submit trong form có thể dùng để điều chỉnh đối tượng Movie. Nếu dữ liệu là hợp lệ, code xử lí sẽ lưu dữ liệu movie đến đối tượng Movies collection của MovieDBContext. Sau đó sẽ lưu dữ liệu movie mới này nào database bằng cách gọi phương thức SaveChanges của MovieDBContext để lưu thay đổi vào database. Sau khi lưu dữ liệu, code sẽ redirect người dùng đến phương thức Index của class MoviesController, và hiển thị danh sách các bộ phim vừa được cập nhật.Làm cho phương thức Edit trở nên mạnh mẽ hơn Phương thức HttpGet Edit được sinh ra bởi hệ thống scafffolding không có kiểm tra dữ liệu được truyền vào (trong trường hợp này là ID). Nếu người dùng bỏ đi phần ID của URL (http://localhost:xxxxx/Movies/Edit ) sẽ xuất hiện lỗi như sau: Ngoài ra người dùng có thể truyền vào ID không tồn tại trong cơ sở dữ liệu, ví dụ http://localhost:xxxxx/Movies/Edit/1234. Chúng ta có thể tránh xảy ra lỗi này bằng cách điều chỉnh phương thức Http Edit. Trước hết, thay đổi tham số ID về giá trị mặc định là 0 khi ID được truyền vào không rõ ràng. Ngoài ra chúng ta có thể kiểm tra bằng phương thức Find để tìm một bộ phim tồn tại thực sự trước khi return đối tượng movie về cho view template. Phương thức update được cập nhật như sau: public ActionResult Edit(int id = 0) { Movie movie = db.Movies.Find(id); if (movie == null) { return HttpNotFound(); } return View(movie); } Nếu như không tìm thấy phim, phương thức HttpNotFound sẽ được gọi. Tất cả các phương thức HttpGet sau đây điều có cùng mẫu (pattern) tương tự nhau. Chúng lấy một đối tượng (hoặc danh sách các đối tượng, trong trường hợp này là phương thức Index), và truyền model đến view. Phương thức create truyền một đối tượng movie rỗng đến Create view. Tất cả các phương thức create, edit, delete, hoặc các phương thức điều chỉnh dữ liệu khác cũng thực hiện tương tự trong nạp chồng phương thức HttpPost.Thêm phương thức Search và Search View Trong phần này chúng ta sẽ thêm một phương thức SearchIndex cho phép chúng ta tìm kiếm các bộ phim theo tên hoặc thể loại. URL sử dụng cho phương thức này là /Movies/SearchIndex. Yêu cầu hiển thị dưới dạng HTML form chứa input cho phép người dùng điền thông tin tìm kiếm. Khi người dùng submit form, phương thức sẽ lấy giá trị tìm kiếm được nhập vào bởi người dùng và sử dụng giá trị đó để tìm kiếm trong database.Hiển thị form SearchIndex Bắt đầu bằng cách thêm một phương thức SearchIndex vào class MoviesController. Phương thức này sẽ trả về một view chứa đựng HTML form. Đây là code: public ActionResult SearchIndex(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); } Dòng đầu tiên của phương thức là tạo một truy vấn LINQ để chọn ra các bộ phim thỏa điều kiện tìm kiếm: var movies = from m in db.Movies select m; Nếu tham số searchString chứa chuỗi, câu truy vấn sẽ được điều chỉnh để lọc kết quả dựa trên chuỗi giá trị tìm kiếm, sử dụng code sau đây: if (!String.IsNullOrEmpty(searchString)) { movies = movies.Where(s => s.Title.Contains(searchString)); } Truy vấn LINQ không thực thi ngay khi được định nghĩa hoặc khi chúng được điều chỉnh bằng cách gọi một phương thức như Where hoặc OrderBy. Thay vào đó, việc thực thi truy vấn sẽ được hoãn lại. Trong ví dụ SearchIndex, truy vấn được thực thi trong SearchIndex view. Để biết thêm thông tin về hoãn thực thi truy vấn, chúng ta có thể xem Query Execution Bây giờ chúng ta đã có thể triển khai SearchIndex view, view này sẽ hiển thị form cho người dùng. Click phải vào phương thức SearchIndex và sau đó click Add View. Trong họp thoại Add View, chỉ định như trong hình để truyền một đối tượng Movie đến view template. Trong danh sách scaffold template, chọn List, sau đó click Add. Khi chúng ta click Add, view template Views\Movies\SearchIndex.cshtml sẽ được tạo. Bởi vì chúng ta đã chọn trong danh sách scaffold template, Visual web developer tự động sinh ra nội dung (code) mặc định trong view. Scaffolf đã tạo một HTML form. Nó kiểm tra class Movie và đã tạo ra code để render ra thành phần cho mỗi thuộc tính của class. Sau đây là code sinh ra khi tạo view: @model IEnumerable @{ ViewBag.Title = "SearchIndex"; }SearchIndex @Html.ActionLink("Create New", "Create")
Title ReleaseDate Genre Price @foreach (var item in Model) { @Html.DisplayFor(modelItem => item.Title) @Html.DisplayFor(modelItem => item.ReleaseDate) @Html.DisplayFor(modelItem => item.Genre) @Html.DisplayFor(modelItem => item.Price) @Html.ActionLink("Edit", "Edit", new { id=item.ID }) | @Html.ActionLink("Details", "Details", new { id=item.ID }) | @Html.ActionLink("Delete", "Delete", new { id=item.ID }) }
Chạy ứng dụng và điều hướng đến /Movies/SearchIndex. Thêm vào url chuỗi truy vấn ?searchString=ghost. Các bộ phim đã lọc ra được hiển thị. Nếu chúng ta điều chỉnh phương thức SearchIndex để có một tham số với tên là id, tham số id này sẽ được ghép với vị trí {id} cho đường dẫn mặc định được gán trong tập tin Global.asax. {controller}/{action}/{id} Phương thức SearchIndex được điều chỉnh như sau: public ActionResult SearchIndex(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); } Bây giờ chúng ta có thể truyền giá trị tìm kiếm như một đường dẫn dữ liệu (một phần của URL) thay vì phải truyền một chuỗi truy vấn giá trị. Tuy nhiên, chúng ta không thể mong đợi người dùng điều chỉnh URL cho mỗi lần tìm kiếm. vì vậy, bây giờ chúng ta sẽ tạo thêm một User Interface để giúp họ lọc ra các bộ phim, thay đổi phương thức SearchIndex để nhận vào chuỗi tham số có tên searchString: public ActionResult SearchIndex(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); } Mở tập tin Views\Movies\SearchIndex.cshtml, thêm đoạn mã sau vào sau @Html.ActionLink(“Create New”, “Create”) @using (Html.BeginForm()){ Title: @Html.TextBox("SearchString")
} Ví dụ sau hiển thị một phần tập tin Views\Movies\SearchIndex.cshtml đã được thêm vào các thẻ đánh dấu lọc thông tin. @model IEnumerable @{ ViewBag.Title = "SearchIndex"; }SearchIndex @Html.ActionLink("Create New", "Create") @using (Html.BeginForm()){
Title: @Html.TextBox("SearchString")
} Html.BeginForm tạo ra một form dạng post back khi người dùng submit form bằng cách click vào nút Filter. Hãy chạy ứng dụng và thử tìm kiếm một bộ phim. Sẽ không có nạp chồng phương thức HtpPost SearchIndex. Chúng ta không cần nó, bởi vì phương thức này không làm thay đổi trạng thái của ứng dụng mà nó chỉ lọc dữ liệu. Chúng ta có thể thêm phương thưc HttpPost SearchIndex. trong trường hợp này, hành động gọi ra sẽ được ghép với phương thức HttpPost SearchIndex, và phương thức này sẽ chạy như hình hiển thị bên dưới. [HttpPost] public string SearchIndex(FormCollection fc, string searchString) { return " From [HttpPost]SearchIndex: " + searchString + " "; } Để giải quyết vấn đề trên là sử dụng nạp chồng phương thức của BeginForm chỉ định rõ POST request nên thêm vào thông tin tìm kiếm vào URL và thông tin này sẽ được gửi đến HttpGet của phương thức SearchIndex. Đặt các tham số sau vào phương thức BeginForm như sau: @using (Html.BeginForm("SearchIndex","Movies",FormMethod.Get)) Bầy giờ chúng ta submit một tìm kiếm, URL chứa một chuỗi truy vấn. Tìm kiếm sẽ đi đến phương thức HttpGet SearchIndex, thậm chí chúng ta có phương thức HtpPost SearchIndex. Thêm tìm kiếm theo thể loại Nếu chúng ta đã thêm một phiên bản HttpPost của phương thức SearchIndex thì hãy xóa nó đi. Tiếp theo, chúng ta sẽ thêm một tính năng mới cho phép người dùng tìm kiếm các bộ phim theo thể loại. Đặt đoạn mã sau vào phương thức SearchIndex: public ActionResult SearchIndex(string movieGenre, string searchString) { var GenreLst = new List(); 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)); } } Phiên bản này của phương thức SearchIndex nhận vào một tham số là tên thể loại. Dòng đầu tiên của đoạn mã trên là tạo một danh sách đối tượng để lưu trữ các thể loại phim từ cơ sở dữ liệu. Đoạn mã sau đây là một truy vấn LINQ để lấy tất cả các thể loại trong cơ sở dữ liệu. var GenreQry = from d in db.Movies orderby d.Genre select d.Genre; Đoạn mã sử dụng phương thức AddRange của generic List collection để thêm tất cả các thể loại(Không trùng nhau) vào trong list. Dòng tiếp theo sau dùng để lưu danh sách các thể loại vào trong đối tượng ViewBag. Đoạn mã sau dùng để kiểm tra tham số movieGenre truyền vào. Nếu tham số truyền vào khác rỗng, kết quả trả về là danh sách các bộ phim được chọn thỏa điều điều kiện là tên thể loại có chứa giá trị của tham số truyền vào. if (string.IsNullOrEmpty(movieGenre)) return View(movies); else { return View(movies.Where(x => x.Genre == movieGenre)); } Thêm các thể markup vào SearchIndex View để hỗ trợ việc tìm kiếm theo thể loại Thêm một helper Html.DropDownList vào tập tin Views\Movies\SearchIndex.cshtml ngay trước helper Textbox. Markup hoàn chỉnh như sau: @Html.ActionLink("Create New", "Create") @using (Html.BeginForm()){
Genre: @Html.DropDownList("movieGenre", "All") Title: @Html.TextBox("SearchString")
} Chạy ứng dụng và browse đến /Movies/SearchIndex. Hãy thử tìm kiếm theo thể loại, theo tên, và theo cả hai. Trong phần này chúng ta đã kiễm tra các phương thức CRUD và các view được sinh ra bởi framework. Chúng ta đã tạo một phương thức search và view cho phép người dùng tìm kiếm theo tiêu đề và thể loại Trong phần tiếp theo, chúng ta sẽ biết được cách thêm một thuộc tính vào model Movie như thế nào. Bài viết được dịch từ Examining the Edit Methods and Edit View (C#)