Step by step create a simple MVC e-commerce website BooksStore (2), mvcbooksstore

Source: Internet
Author: User

Step by step create a simple MVC e-commerce website BooksStore (2), mvcbooksstore

Build a simple MVC e-commerce website step by step-BooksStore (2)

GitHub address: https://github.com/liqingwen2015/Wen.BooksStore

Building a simple MVC e-commerce website step by step-BooksStore (I)

Building a simple MVC e-commerce website step by step-BooksStore (II)

Building a simple MVC e-commerce website step by step-BooksStore (III)

Building a simple MVC e-commerce website step by step-BooksStore (4)

Introduction

Last time we tried: Create a project architecture, create a domain model entity, create a unit test, create a controller and view, create a page, and add a style. In this section, we will complete two functions, CATEGORY navigation and shopping cart.

The main functions and knowledge points are as follows:

Category, product browsing, shopping cart, settlement, CRUD (add, delete, modify, and query) management, mail, paging, model binding, authentication filter, and unit test (the remaining two are expected, it is expected to be released tomorrow (because there is no holiday on Saturday) and Wednesday (because there is no work on Tuesday ).

[Note] the project is developed using VS2015 + C #6. If you have any questions, please post them in the message area. Also, the page looks ugly. Sorry.

Directory

Add category navigation

Add to shopping cart

Create a Partial View

1. Add category navigation

The last time we divided the web page into three modules, the content in the left navigation bar was not completed yet, and the left navigation bar had the function of displaying books by category.

Figure 1

1. Return to the previous BookDetailsViewModels view model, and we will add a new attribute for classification (CurrentCategory ):

/// <Summary> // Book details view model /// </summary> public class BookDetailsViewModels: PagingInfo {public IEnumerable <Book> Books {get; set ;} /// <summary> /// current category /// </summary> public string CurrentCategory {get; set ;}}

2. After modifying the view model, you should modify the Details method in the corresponding BookController.

/// <Summary> /// details /// </summary> /// <param name = "category"> category </param> /// <param name = "pageIndex"> page number </param> // <returns> </returns> public ActionResult Details (string category, int pageIndex = 1) {var model = new BookDetailsViewModels {Books = _ bookRepository. books. where (x => category = null | x. category = category ). orderBy (x => x. id ). skip (pageIndex-1) * PageSize ). take (PageSize), CurrentCategory = category, PageSize = PageSize, PageIndex = pageIndex, TotalItems = _ bookRepository. books. count (x => category = null | x. category = category)}; return View (model );}

BookController. cs

Namespace Wen. booksStore. webUI. controllers {public class BookController: Controller {private readonly IBookRepository _ bookRepository; public int PageSize = 5; public BookController (IBookRepository bookRepository) {_ bookRepository = bookRepository ;} /// <summary> /// details /// </summary> /// <param name = "category"> category </param> /// <param name = "pageIndex"> page number </param> // <returns> </returns> public ActionResult Details (string category, int pageIndex = 1) {var model = new BookDetailsViewModels {Books = _ bookRepository. books. where (x => category = null | x. category = category ). orderBy (x => x. id ). skip (pageIndex-1) * PageSize ). take (PageSize), CurrentCategory = category, PageSize = PageSize, PageIndex = pageIndex, TotalItems = _ bookRepository. books. count (x => category = null | x. category = category)}; return View (model );}}}

The category parameter is added to obtain the classification string. The value assignment statement corresponding to the attribute in Books is changed to _ bookRepository. books. where (x => category = null | x. category = category), where the Lambda expression x => category = null | x. category = category: If the Category string is empty, all Book objects in the database are taken. If the category string is not empty, the collection is filtered based on the Category.

The property CurrentCategory is also assigned a value.

Don't forget, because the page is based on the TotalItems attribute, You need to modify the location _ bookRepository. books. count (x => category = null | x. category = category). Use LINQ to count the number of different categories.

3. The page helper in Details. cshtml corresponding to the Controller also needs to be modified to add new route parameters:

<div class="pager"> @Html.PageLinks(Model, x => Url.Action("Details", new { pageIndex = x, category = Model.CurrentCategory }))</div>

Details. cshtml

@model Wen.BooksStore.WebUI.Models.BookDetailsViewModels@{ ViewBag.Title = "Books";}@foreach (var item in Model.Books){ <div class="item"> 

4. You should modify the routing area.

RouteConfig. cs

public static void RegisterRoutes(RouteCollection routes) {  routes.IgnoreRoute("{resource}.axd/{*pathInfo}");  routes.MapRoute(  name: "Default",  url: "{controller}/{action}",  defaults: new { controller = "Book", action = "Details" }  );  routes.MapRoute(  name: null,  url: "{controller}/{action}/{category}",  defaults: new { controller = "Book", action = "Details" }  );  routes.MapRoute(  name: null,  url: "{controller}/{action}/{category}/{pageIndex}",  defaults: new { controller = "Book", action = "Details", pageIndex = UrlParameter.Optional }  ); }

5. Create a controller named NavController and add a method named Sidebar to render the left Sidebar.

However, the returned View type is PartialView:

public PartialViewResult Sidebar(string category = null) {  var categories = _bookRepository.Books.Select(x => x.Category).Distinct().OrderBy(x => x);  return PartialView(categories); }

Right-click the method body, add a view, and check to create a branch view.

Modify Sidebar. cshtml:

@ Model IEnumerable <string> <ul> <li> @ Html. actionLink ("all categories", "Details", "Book") </li> @ foreach (var item in Model) {<li> @ Html. routeLink (item, new {controller = "Book", action = "Details", category = item, pageIndex = 1}, new {@ class = item = ViewBag. currentCategory? "Selected": null}) </li >}</ul>

The MVC framework has a concept called "Child Action", which can be used to reuse navigation controls and other things, using methods similar to RenderAction, output the specified action method in the current view.

Because the Division view in another Action needs to be displayed in the parent view, the original _ Layout. cshtml Layout page is modified as follows:

Now, the starting result should be the same as Figure 1. Try to click the category in the left sidebar to observe the changes in the main area.

2. Add to shopping cart

Figure 2

The general function 2 of the interface adds a link (added to the shopping cart) in the area of each book. A new page is displayed, showing the details of the shopping cart-shopping list, you can also go to a new page through the "Settlement" link.

The shopping cart is part of the application business domain. Therefore, the shopping cart entity should be a domain model.

1. Add two classes:

Cart. cs has the following functions: add, remove, clear, and collect statistics:

/// <Summary> /// shopping car/// </summary> public class Cart {private readonly List <CartItem> _ cartItems = new List <CartItem> (); /// <summary> /// obtain all items in the shopping cart /// </summary> public IList <CartItem> GetCartItems => _ cartItems; /// <summary> /// Add the book Model /// </summary> /// <param name = "book"> </param> /// <param name = "quantity"> </param> public void AddBook (Book book, int quantity) {if (_ cartItems. count = 0) {_ cartItems. add (new CartItem () {Book = book, Quantity = quantity}); return;} var model = _ cartItems. firstOrDefault (x => x. book. id = book. id); if (model = null) {_ cartItems. add (new CartItem () {Book = book, Quantity = quantity}); return;} model. quantity + = quantity ;} /// <summary> /// remove the book Model /// </summary> /// <param name = "Book"> </param> public void RemoveBook (book) {var model = _ cartItems. firstOrDefault (x => x. book. id = book. id); if (model = null) {return;} _ cartItems. removeAll (x => x. book. id = book. id);} // <summary> // Clear the shopping cart // </summary> public void Clear () {_ cartItems. clear () ;}/// <summary> /// total statistics /// </summary> /// <returns> </returns> public decimal ComputeTotalValue () {return _ cartItems. sum (x => x. book. price * x. quantity );}}

CartItem. cs indicates each item in the shopping cart:

/// <Summary> /// shopping cart item /// </summary> public class CartItem {// <summary> /// book /// </summary> public book {get; set ;}//< summary> /// Quantity /// </summary> public int Quantity {get; set ;}}

2. Modify the previous Details. cshtml and add the "add to shopping cart" button:

@ Model Wen. booksStore. webUI. models. bookDetailsViewModels @ {ViewBag. title = "Books" ;}@ foreach (var item in Model. books) {<div class = "item"> 

[Remarks] @ Html. by default, the BeginForm () method creates a form for the Post request method. Why not directly use the Get request? The HTTP standard requirements may cause data changes. Do not use Get requests, adding a product to a shopping cart significantly changes the data. Therefore, you should not use the Get request to directly display the page or list data in this case.

3. First modify the style in css

body {}#header, #content, #sideBar { display: block;}#header { background-color: green; border-bottom: 2px solid #111; color: White;}#header, .title { font-size: 1.5em; padding: .5em;}#sideBar { float: left; width: 8em; padding: .3em;}#content { border-left: 2px solid gray; margin-left: 10em; padding: 1em;}.pager { text-align: right; padding: .5em 0 0 0; margin-top: 1em;} .pager A { font-size: 1.1em; color: #666; padding: 0 .4em 0 .4em; } .pager A:hover {  background-color: Silver; } .pager A.selected {  background-color: #353535;  color: White; }.item input { float: right; color: White; background-color: green;}.table { width: 100%; padding: 0; margin: 0;} .table th { font: bold 12px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif; color: #4f6b72; border-right: 1px solid #C1DAD7; border-bottom: 1px solid #C1DAD7; border-top: 1px solid #C1DAD7; letter-spacing: 2px; text-transform: uppercase; text-align: left; padding: 6px 6px 6px 12px; background: #CAE8EA no-repeat; } .table td { border-right: 1px solid #C1DAD7; border-bottom: 1px solid #C1DAD7; background: #fff; font-size: 14px; padding: 6px 6px 6px 12px; color: #4f6b72; } .table td.alt {  background: #F5FAFA;  color: #797268; } .table th.spec, td.spec { border-left: 1px solid #C1DAD7; }

4. Add another CartController.

/// <Summary> /// shopping car/// </summary> public class CartController: Controller {private readonly IBookRepository _ bookRepository; public CartController (IBookRepository bookRepository) {_ bookRepository = bookRepository ;} /// <summary> /// homepage /// </summary> /// <param name = "returnUrl"> </param> /// <returns> </ returns> public ViewResult Index (string returnUrl) {return View (new CartIndexViewModel (){ Cart = GetCart (), ReturnUrl = returnUrl });} /// <summary> /// add to shopping cart /// </summary> /// <param name = "id"> </param> /// <param name = "returnUrl"> </param> // <returns> </returns> public RedirectToRouteResult AddToCart (int id, string returnUrl) {var book = _ bookRepository. books. firstOrDefault (x => x. id = id); if (book! = Null) {GetCart (). addBook (book, 1);} return RedirectToAction ("Index", new {returnUrl });} /// <summary> /// remove from the shopping cart /// </summary> /// <param name = "id"> </param> /// <param name = "returnUrl"> </param> // <returns> </returns> public RedirectToRouteResult RemoveFromCart (int id, string returnUrl) {var book = _ bookRepository. books. firstOrDefault (x => x. id = id); if (book! = Null) {GetCart (). removeBook (book);} return RedirectToAction ("Index", new {returnUrl });} /// <summary> /// get the shopping Cart /// </summary> /// <returns> </returns> private cart GetCart () {var Cart = (Cart) session ["Cart"]; if (cart! = Null) return cart; cart = new Cart (); Session ["Cart"] = cart; return cart ;}}

[Note] the shopping Cart stores the user's Cart object through Session state. When a session expires (typically because the user has not initiated any request to the server for a long time), the data associated with the session will be deleted, this means that you do not need to manage the lifecycle of the Cart object.

[Note] RedirectToAction () method: Send an HTTP redirection command to the client browser, requesting the browser to request a new Url.

5. Right-click the Index method and choose new view to display the shopping list:

Code in Index. cshtml:

@ Model Wen. booksStore. webUI. models. cartIndexViewModel 

I think this must be an exciting moment, because we have completed this basic addition to the shopping cart function.

3. Create a Partial View

The segment view is a content segment embedded in another view and can be reused across views. This helps reduce duplication, especially when the same data needs to be reused in multiple places.

Create a view named _ BookSummary. cshtml in Shared, and sort out the previous Details. cshtml code.

Two modified views:

Details. cshtml

@model Wen.BooksStore.WebUI.Models.BookDetailsViewModels@{ ViewBag.Title = "Books";}@foreach (var item in Model.Books){ Html.RenderPartial("_BookSummary", item);}<div class="pager"> @Html.PageLinks(Model, x => Url.Action("Details", new { pageIndex = x, category = Model.CurrentCategory }))</div>

_ BookSummary. cshtml

@ Model Wen. booksStore. domain. entities. book <div class = "item"> 

The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.