Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 31 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
31
Dung lượng
1,42 MB
Nội dung
Chương : Cửa hàng thể thao trực tuyến : điều hướng Điều khiển điều hướng: Các ứng dụng cửa hàng thể thao trực tuyến hữu dụng khách hàng lựa chọn sản phẩm dựa theo mục Ở có ba giai đoạn: Nâng cao hoạt động model List class ProductControllerđể chọn lọc dụng cụ kho hàng .Sử dụng lại nâng cao đề án URL rà soát lại chiến lược định tuyến .Tạo danh mục mà đưa vào sidebar site, làm bật danh mục lien kết chúng với thứ khác Lọc theo danh mục sản phẩm: Nâng cao view model class class ProcductsListViewModel, class thêm vào project SportsStore.WebUIở chương trước Cần có giao tiếp ( kết nối) tới view trả cho sidebar Listing 8-1 thể thay đổi file ProductListView.cs Listing 8-1: Nâng cấp file Productview.cs using System.Collections.Generic; using SportsStore.Domain.Entities; namespace SportsStore.WebUI.Models { public class ProductsListViewModel { public IEnumerable Products { get; set; } public PagingInfo PagingInfo { get; set; } public string CurrentCategory { get; set; } } } CurrentCategorylà tham số thêm vào Bước nâng cấp Product controllers để phương thức hoạt động củaListsẽ lọc Product sản phẩm theo danh mục sử dụng tham số để xem mẫu mà chọn lựa danh mục Điều thể torng Listing 8-2 Listing 8-2:thêm Category Support vào phương thức hoạt động List file ProcductController.cs using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using SportsStore.Domain.Abstract; using SportsStore.Domain.Entities; using SportsStore.WebUI.Models; namespace SportsStore.WebUI.Controllers { public class ProductController : Controller { private IProductRepository repository; public int PageSize = 4; public ProductController(IProductRepository productRepository) { this.repository = productRepository; } public ViewResult List(string category , int page = 1) { ProductsListViewModel model = new ProductsListViewModel { Products = repository.Products Where(p => category == null || p.Category ==category) OrderBy(p => p.ProductID) Skip((page - 1) * PageSize) Take(PageSize), PagingInfo = new PagingInfo { CurrentPage = page, ItemsPerPage = PageSize, TotalItems = repository.Products.Count() }, CurrentCategory = category }; return View(model); } } } Đã có thay đổi đến phương thức hoạt động Đầu tiên, thông số category thêm vào Thông số category sử dụng thay đổi thứ hai Listing, thông số nâng cấp đến truy vấn LINQ Nếu mà Category khơng có giá trị null, có đối tượng Product khớp với categoryđã chọn Thay đổi cuối đặt lại giá trị tham số CurrentCategory thêm vào class ProductListViewModel.cs, Tuy nhiên, thay đổi làm tính tốn giá trị PagInfo.TotalItems sai lệch UNIT TEST: UPDATING EXISTING UNIT TEST Thay đổi tín hiệu phương thức hoạt động List, mà ngăn chặn số phương thức hữu unit test từ biên dịch.Để thực hiện, cần phải đặt Null tham số phương thức List unit test mà đơn vị làm việc với controllers Ví dụ, kiểm tra Can_Paginate, section hoat động unit test trở thành: [TestMethod] public void Can_Send_Pagination_View_Model() { // Arrange Mock mock = new Mock(); mock.Setup(m => m.Products).Returns(new Product[] { new Product {ProductID = 1, Name = "P1"}, new Product {ProductID = 2, Name = "P2"}, new Product {ProductID = 3, Name = "P3"}, new Product {ProductID = 4, Name = "P4"}, new Product {ProductID = 5, Name = "P5"} }); // Arrange ProductController controller = new ProductController(mock.Object); controller.PageSize = 3; // Act ProductsListViewModel result = (ProductsListViewModel)controller.List(null, 2).Model; // Assert PagingInfo pageInfo = result.PagingInfo; Assert.AreEqual(pageInfo.CurrentPage, 2); Assert.AreEqual(pageInfo.ItemsPerPage, 3); Assert.AreEqual(pageInfo.TotalItems, 5); Assert.AreEqual(pageInfo.TotalPages, 2); } Giữ cho việc đồng giữ unit test với thay đổi nhanh chóng code trở thành chất thứ hai bạn bắt đầu thử nghiệm mind-set Những ảnh hưởng việc lọc danh mục hiển nhiên, thay đổi nhỏ Khởi động chương trình chọn lựa danh mục dựa vào chuỗi truy vấn, thay đổi port để chúng tương thích với dự án visual bạn: http://localhost:51280/?category=Soccer Bạn nhận sản phẩm có danh mục Soccer, Figure 81: Chăc chắn, người dùng không muốn điều hướng tới danh mục URL, bạn có thề thấy thay đổi nhỏ có ảnh hưởng lớn chương trình MVC framework cấu trúc đặt UNIT TEST: CATEGORY FILTERING Cần có unit test kiểm tra chức lọc danh sách, để chắn lộc lọc xác sản phẩm danh mục : [TestMethod] public void Can_Filter_Products() { // Arrange // - create the mock repository Mock mock = new Mock(); mock.Setup(m => m.Products).Returns(new Product[] { new Product {ProductID = 1, Name = "P1", Category = "Cat1"}, new Product {ProductID = 2, Name = "P2", Category = "Cat2"}, new Product {ProductID = 3, Name = "P3", Category = "Cat1"}, new Product {ProductID = 4, Name = "P4", Category = "Cat2"}, new Product {ProductID = 5, Name = "P5", Category = "Cat3"} }); // Arrange - create a controller and make the page size items ProductController controller = new ProductController(mock.Object); controller.PageSize = 3; // Action Product[] result = ((ProductsListViewModel)controller.List("Cat2",1).Model) Products.ToArray(); // Assert Assert.AreEqual(result.Length, 2); Assert.IsTrue(result[0].Name == "P2" && result[0].Category =="Cat2"); Assert.IsTrue(result[1].Name == "P4" && result[1].Category =="Cat2"); } Việc test tạo kho lưu trữ mơ hình đối tượng Product mà thuộc loạt danh mục Khi danh mục cụ thể yêu cầu sử dụng dung phương thức Action, kết kiểm tra để chắn kết với đối tượng sản phẩm đươc yêu cầu Refining the URL Scheme Không người dùng muốn thấy hay sử dụng URL xấu /?categiry=Soccer.Để thay đổi, cần xem lại hướng định tuyến để tạo cách tiếp cận khác tốt cho người quản trị khách hàng đến URL Để thực đổi đề án, cần thay đổi phương thức RegisterRoutes file App_Start/RouteConfig.cs Listing 8-3: làm URL Scheme file RouteConfig.cs using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace SportsStore.WebUI { public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute(null,"", new { controller = "Product", action = "List", category = (string)null, page = } ); routes.MapRoute(null,"Page{page}", new { controller = "Product", action = "List", category =(string)null }, new { page = @"\d+" } ); routes.MapRoute(null,"{category}", new { controller = "Product", action = "List", page = } ); routes.MapRoute(null,"{category}/Page{page}", new { controller = "Product", action = "List" }, new { page = @"\d+" } ); routes.MapRoute(null, "{controller}/{action}"); } } } Lưu ý : việc thêm vào định tuyến Listing 8-3 cho ta thấy quan trọng Định tuyến áp dụng thứ mà chúng định nghĩa, bạn thấy thay đổi bạn đổi thứ tự Table 8-1 mô tả những định tuyến đại diện cho URL Scheme Table 8-1 : Route Summary URL Lead To / Trang sản phẩm mục /Page Các trang định khác, thể sản phẩm danh mục Soccer Thể trang mục định /Soccer/Page Thể trang định sản phẩm danh mục định Định tuyến ASP.NET dựa tảng MVC để giải yêu cầu imcoming từ client, tạo outcoming URL để phù hợp với URL Scheme nhúng vào Web page Bằng việc sử dụng hệ thống định tuyến để giải yêu cầu đến tạo outgoing URLs, chắn tất URLs chương trình điều thích hợp Phương thức Url.Action phương thức thuận tiện để tạo liên kết Ở chương trước, tác giả sử dụng cách thức hữu dụng phương thức List để xem hiển thị trang liên kết Tác giả thêm trợ giúp cho việc lọc danh mục, tác giả cần phải quay lại đặt thông tin cho phương thức giúp đỡ Listing 8-4 :Thêm vào thông tin danh mục cho Pagination Link file List.cshtml @model SportsStore.WebUI.Models.ProductsListViewModel @{ ViewBag.Title = "Products"; } @foreach (var p in Model.Products) { @Html.Partial("ProductSummary", p) } @Html.PageLinks(Model.PagingInfo, x => Url.Action("List", new { page = x, category = Model.CurrentCategory })) Qua thay đổi này, đường dẫn tạo cho liên kết pagination có dạng: http://:/Page1 Nếu người dùng chọn vào đường dẫn trang trên, lọc danh mục mà người đăng kí bị mất, thay vào thể trang chứa sản phẩm từ danh mục việc thêm danh mục tại, lấy từ mơ hình điểm, tác giả tạo URL sau: http:// : /Chess/Page1 Khi người dùng chọn vào link kiểu trên, danh mục chuyển tới hoạt động phương thức List, lọc đươc bảo quản Sau bạn thực bước thay đổi này, bạn vào URL /Chess or /Soccer, bạn thấy xác liên kết trang trang danh mục sản phẩm Xây dựng danh mục điều hướng thể loại Cần cung cấp cho người dùng hướng để chọn danh mục mà khơng cần phải nhập liệu vào URLs Điều có nghĩa thể chúng với danh sách danh mục tồn định, có, chọn Như việc xây dựng chương trình, tác giả sử dụng danh sách danh mục cho nhiều controller, nên cần có có tính khép kín tái sử dụng ASP.NET MVC Framework có khái niệm Child action, khái niệm tuyệt vời tạo sản phẩm dựa việc tái sử dụng việc điều khiển điều hướng Child action dựa phương pháp trợ giúp HTML gọi Html.Action,phương thức cho phép bạn bao gồm đầu từ phương pháp hành động tuỳ tiện giao diện Trong trường hợp này, tạo điều khiển ( gọi NavController) với phương thức hoạt động ( gọi Menu) hướng tới menu điều hướng Html.Action sử dụng để đưa output từ phương thức vào layout Các tiếp cận giúp mang lại điều khiển thực mà có thề chứa ứng dụng logic đươc sử dụng unit test điều khiển khác Đây hướng tốt để tạo segment nhỏ ứng dụng bảo quản cách tiếp cận MVC tổng thể Tạo điều khiển điều hướng Nhấn chuột phải vào thư mục Controller đề án Sportstore.WebUI chọn Add->Controller từ pop-up menu Chọn thẻ MVC Controller – Empty, sau chọn Add, đặt tên cho controller NavController chọn Add để tạo lớp NavController.cs Xoá bỏ phương thức Index Visual Studio thêm vào mặc định điều khiển phương thức hoạt động Menu Listing 8-5: Thêm menu phương thức hoạt động vào NavController.cs using System.Web.Mvc; namespace SportsStore.WebUI.Controllers { public class NavController : Controller { public string Menu() { return "Hello from NavController"; } } } Phương thức trả chuỗi thông báo tĩnh nhiêu đủ để bắt đầu tích hợp Child action cịn lại chương trình Tác giả muốn danh sách thể loại xuất tất trang, tác giả trả lại Child action vào layout, có nhìn cụ thể Điều chỉnh View/Shared/_Layout.cshtml để gọi phương thức trợ giúp từ Html.Action Listing 8-6: Thêm hoạt động trả vào file _Layout.cshtml @ViewBag.Title SPORTS STORE @Html.Action("Menu", "Nav") @RenderBody() Ở xoá văn giữ chỗ thay lệnh gọi phương thức Html.Action Những thông số phương thức tên phương thức hoạt động mà tác giả muốn gọi (Menu) điều khiển thuộc (Nav) Nếu bạn chạy ứng dụng, bạn thấy ngõ phương thức Menu bao gồm phản hồi đươc gởi tới trình duyệt Figure 8-2: Khởi tạo danh sách thể loại Bây tác giả trả giá trị cho controller Nav khởi tạo giá trị thể loại thật.Tác giả không muốn khởi tạo URLs thể loại controller.Thay vào đó, tác giả sữ dụng phương thức hỗ trợ view để thực Mọi thứ cần làm phương thức hoạt đông Menu tạo danh sách thể loại, đươc thực Listing 8-7 Listing 8-7:Triển khai thực Menu Method NavController.cs using System.Collections.Generic; using System.Web.Mvc; using SportsStore.Domain.Abstract; using System.Linq; namespace SportsStore.WebUI.Controllers { public class NavController : Controller { private IProductRepository repository; public NavController(IProductRepository repo) { repository = repo; } public PartialViewResult Menu() { IEnumerable categories = repository.Products Select(x => x.Category) Distinct() OrderBy(x => x); return PartialView(categories); Cần làm đường dẫn đến trang để chọn category chúng hoạt động Hiện tại, số trang phụ thuộc vào tổng số sản phẩm có kho khơng phải số sản phẩm category đươc chọn Điều có nghĩa customer chọn đường dẫn đến trang category Chessvà trang trống từ đầu đến cuối khơng có đủ sản phẩm để chia làm trang Figure 8-5: Có thể sửa lỗi cách cập nhật lại phương thức hoạt động Listtrong controller Product thông tin số trang đươc đưa vào account từ thể loại Bạn thấy thay đổi Listing 8-11 Listing 8-11: tạo Category-Aware Pageination Data file ProductController.cs … public ViewResult List(string category, int page = 1) { ProductsListViewModel viewModel = new ProductsListViewModel { Products = repository.Products Where(p => category == null || p.Category == category) OrderBy(p => p.ProductID) Skip((page - 1) * PageSize) Take(PageSize), PagingInfo = new PagingInfo { CurrentPage = page, ItemsPerPage = PageSize, TotalItems = category == null ? repository.Products.Count() : repository.Products.Where(e => e.Category ==category).Count() }, CurrentCategory = category }; return View(viewModel); } Nếu mà category chọn, trả số sản phẩm có category đó; khơng, trả tổng số sản phẩm kho Bây mà ta xem category, đường dẫn cuối trang hiển thị số sản phẩm category Figure 8-6 Figure 8-6: UNIT TEST: CATEGORY-SPECIFIC PRODUCTION COUNT Bài test cho phép tác giả tạo số lượng sản phẩm khác cách đơn giản Tác giả tạo kho lưu trữ giả chứa liệu đươc biết đến loạt category sau yêu cầu gọi phương thức hoạt động List category lượt [TestMethod] public void Generate_Category_Specific_Product_Count() { // Arrange // - create the mock repository Mock mock = new Mock(); mock.Setup(m => m.Products).Returns(new Product[] { new Product {ProductID = 1, Name = "P1", Category = "Cat1"}, new Product {ProductID = 2, Name = "P2", Category = "Cat2"}, new Product {ProductID = 3, Name = "P3", Category = "Cat1"}, new Product {ProductID = 4, Name = "P4", Category = "Cat2"}, new Product {ProductID = 5, Name = "P5", Category = "Cat3"} }); // Arrange - create a controller and make the page size items ProductController target = new ProductController(mock.Object); target.PageSize = 3; // Action - test the product counts for different categories int res1 = ((ProductsListViewModel)target List("Cat1").Model).PagingInfo.TotalItems; int res2 = ((ProductsListViewModel)target List("Cat2").Model).PagingInfo.TotalItems; int res3 = ((ProductsListViewModel)target List("Cat3").Model).PagingInfo.TotalItems; int resAll = ((ProductsListViewModel)target List(null).Model).PagingInfo.TotalItems; // Assert Assert.AreEqual(res1, 2); Assert.AreEqual(res2, 2); Assert.AreEqual(res3, 1); Assert.AreEqual(resAll, 5); } Chú ý: tác giả gọi phương thức List,quy định cụ thể không category, để chắn tác giả có số lượng đếm Xây dựng giỏ hàng Ứng dụng có bước tiến độc đáo, chưa thể bán đươc sản phẩm giỏ hàng đươc đưa vào Trong section này, tác giả tạo trãi nghiệm mua sắm với giỏ hàng, trình bày Figure 8-7 Điều quen thuộc với thực toán trực tuyến Figure 8-7: Nút Add to Cart xuất bên cạnh sản phẩm catalog Nhấn vào nút thể thiện tổng số sản phẩm mà customer lựa chọn thời điểm đó, bao gồm tổng tiền Lúc này, customer nhấn vào nút Continue Shopping để quay trở lại trang danh mục sản phẩm, nhấn nút Checkout Now để hoàn tất việc đặt hàng kết thúc việc shopping Defining Cart Entity Giỏ hàng phần lĩnh vực kinh doanh, tạo cảm giác dại diện cho giỏ hàng cách tạo thực thể domain model Thêm class với tên Cart.cs vào thư mục Entities project SportStore.Domain dùng để định nghĩa class Listing 8-12 Listing 8-12: using System.Collections.Generic; using System.Linq; namespace SportsStore.Domain.Entities { public class Cart { private List lineCollection = new List(); public void AddItem(Product product, int quantity) { CartLine line = lineCollection Where(p => p.Product.ProductID == product.ProductID) FirstOrDefault(); if (line == null) { lineCollection.Add(new CartLine { Product = product, Quantity = quantity }); } else { line.Quantity += quantity; } } public void RemoveLine(Product product) { lineCollection.RemoveAll(l => l.Product.ProductID ==product.ProductID); } public decimal ComputeTotalValue() { return lineCollection.Sum(e => e.Product.Price * e.Quantity); } public void Clear() { lineCollection.Clear(); } public IEnumerable Lines { get { return lineCollection; } } } public class CartLine { public Product Product { get; set; } public int Quantity { get; set; } } } Class CartLine sử dụng cho class Cart, định nghĩa chung tên, để đại diện cho sản phẩm chọn bở customer lượng lớn người dùng muốn mua Tác giả định nghĩa phương thức để có thê thêm sản phẩm vào giỏ hàng, xóa sản phẩm thêm trước khỏi giỏ hàng, tính tổng số tiền sản phẩm giỏ hàng, tái tạo giỏ hàng cách xóa hết sản phẩm Tác giả cung cấp quyền sở hữu cho phép truy cập vào nội dung giỏ hàng cách sử dụng Ienumrable Đây công cụ đơn giản, dễ dàng thực C# với giúp đỡ cửa LINQ UNIT TEST: TESTING THE CART Class Cart tương đối đơn giản, việc quan trọng giỏ hàng phải hoạt động Một giỏ hàng làm suy yếu toàn ứng dụng SportStore Tác giả chia nhỏ tính thử nghiệm chúng riêng Tác giả tạo file Unit Test project SportStore.UnitTes gọi CartTest.cs để chứa kiểm tra Các hành vi quan mà thêm vào giỏ hàng Nếu lần thêm sản phẩm vào giỏ hàng, tác giả muốn có CartLine bổ sung Dưới test, bao gồm việc định nghĩa lớp thử nghiệm đơn vị: using System Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; using SportsStore.Domain.Entities; namespace SportsStore.UnitTests { [TestClass] public class CartTests { [TestMethod] public void Can_Add_New_Lines() { // Arrange - create some test products Product p1 = new Product { ProductID = 1, Name = "P1" }; Product p2 = new Product { ProductID = 2, Name = "P2" }; // Arrange - create a new cart Cart target = new Cart(); // Act target.AddItem(p1, 1); target.AddItem(p2, 1); CartLine[] results = target.Lines.ToArray(); // Assert Assert.AreEqual(results.Length, 2); Assert.AreEqual(results[0].Product, p1); Assert.AreEqual(results[1].Product, p2); } } } Tác giả cần kiểm tra người dùng thay đổi ý định xóa bỏ sản phẩm giỏ hàng Việc giải phương thức RemoveLine Đây test: … [TestMethod] public void Can_Add_Quantity_For_Existing_Lines() { // Arrange - create some test products Product p1 = new Product { ProductID = 1, Name = "P1" }; Product p2 = new Product { ProductID = 2, Name = "P2" }; // Arrange - create a new cart Cart target = new Cart(); // Act target.AddItem(p1, 1); target.AddItem(p2, 1); target.AddItem(p1, 10); CartLine[] results = target.Lines.OrderBy(c =>c.Product.ProductID).ToArray(); // Assert Assert.AreEqual(results.Length, 2); Assert.AreEqual(results[0].Quantity, 11); Assert.AreEqual(results[1].Quantity, 1); } Bài test cuối tác giả muốn chắn thứ liên quan đến giỏ hàng xóa bỏ reset Đây test: … [TestMethod] public void Can_Clear_Contents() { // Arrange - create some test products Product p1 = new Product { ProductID = 1, Name = "P1", Price = 100M }; Product p2 = new Product { ProductID = 2, Name = "P2", Price = 50M }; // Arrange - create a new cart Cart target = new Cart(); // Arrange - add some items target.AddItem(p1, 1); target.AddItem(p2, 1); // Act - reset the cart target.Clear(); // Assert Assert.AreEqual(target.Lines.Count(), 0); } Đôi khi, trường hợp này, code yêu cầu cho phương thức dài phức tạp mang lại Đừng để điều làm bạn bỏ qua việc viết unit test Những khuyết điểm Class có tác động lớn, đặt biệt thứ đóng vai trị quan trọng Cart đến ví dụ ứng dụng Adding the Add to Cart button Ở tác giả cần chỉnh sửa lớp view Views/Shared/ProductSummary.cshtml để thêm button vào danh sách sản phẩm Thay đổi thể Listing 8-13: Listing 8-13: Thêm button vào file view Product Summary.cshtml @model SportsStore.Domain.Entities.Product @Model.Name@Model.Price.ToString("c") @using (Html.BeginForm("AddToCart", "Cart")) { @Html.HiddenFor(x => x.ProductID) @Html.Hidden("returnUrl", Request.Url.PathAndQuery) } @Model.Description Tác giả thêm Razor block mà tạo đoạn HTML nhỏ sản phẩm danh sách Khi form đươc thơng qua, gọi phương thức hoạt động AddToCart controller Cart Chú ý: Ở mặc định, phương thức trợ giúp BeginForm tạo form mà sử dụng phương thức HTML POST Bạn thay đổi điều cách cho sử dụng phương thức GET, cần suy nghĩ kĩ thực điều Các đặc điểm kỉ thuật HTML yêu cầu yêu cầu GET phải idempotent, nghĩ chúng không quền thay đổi, thêm sản phẩm vào giỏ hàng thay đổi xác định Điều nhắc tới nhiều chương 16, kể việc giải thích xảy bạn phớt lờ điều cần có yêu cầu idempotent GET CREATING MULTIPLE HTML FORMS IN A PAGE Sử dụng Html.BeginForm trợ giúp danh sách sản phẩm nghĩa nút Add to Cart kết xuất yếu tố HTML Form riêng biệt Điều khiến bạn ngạc nhiên bạn phát triển với tảng ASP.NET Web Forms mà có cho phép giới hạn hình thức cho trang bạn sử dụng chức xem state feature điều khiển phức tạp (có xu hướng dựa view state) Từ mà ASP.NET khơng cịn sử dụng view state, khơng cịn giới hạn hình thức mà bạn tạo Cơng hơn, khơng có cơng thức ( yêu cầu) cho việc tao form cho button Tuy nhiên, form đăng tải trở lại phương thức điều khiển có, với số thơng số khác biệt, tuyệt hướng đơn giản để giải quyêt nút button Implementing the Cart Controller Tác giả cần controller để giải việc nhấn liên tục nút Add to Cart Tạo controller gọi CartController project SportStore.WebUI chỉnh sửa thuộc cho khớp với Listing 8-14 Listing 8-14: nội dung CartController.cs using System.Linq; using System.Web.Mvc; using SportsStore.Domain.Abstract; using SportsStore.Domain.Entities; namespace SportsStore.WebUI.Controllers { public class CartController : Controller { private IProductRepository repository; public CartController(IProductRepository repo) { repository = repo; } public RedirectToRouteResult AddToCart(int productId, stringreturnUrl) { Product product = repository.Products FirstOrDefault(p => p.ProductID == productId);