天天看點

ASP.net Mvc SportsSpore項目開發(三)

1.建立購物車

上一節中已經将每個産品的資訊,每類的産品資訊都顯示出來了,接下來,在每一個産品旁邊添加一個加入購物車按鈕。單擊此按鈕,将顯示該客戶目前已選産品的摘要,包括總費用,在這裡,客戶可以單擊繼續購物按鈕,回到上一個頁面。

購物車是業務域的一部分,是以,在域模型中建立一個購物車的實體是有意義的。在SportsStore.Domain項目的Entities檔案下添加一個名為Cart.cs的類檔案。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SportsStore.Domain.Entities
{
    public class Cart
    {
        private List<CartLine> lineCollection = new List<CartLine>();

        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 void Clear()
        {
            lineCollection.Clear();
        }
        public IEnumerable<CartLine> Lines
        {
            get { return lineCollection; }
        }
        public decimal ComputeTotalValue()
        {
            return lineCollection.Sum(p => p.Product.Price * p.Quantity);
        }
    }
    public class CartLine
    {//使用者索要購買的産品和數量
        public Product Product { get; set; }
        public int Quantity { get; set; }
    }
}
           

這裡的Cart類在同一個檔案中定義了CartLine類,以表示由客戶所選的一個産品和使用者項目購買的數量。還定義了一些方法,包括:給購物車添加物品、從購物車中删除已添加的物品、計算購物車物品的總價,以及删除全部物品重置購物車等。此外還提供了一個屬性,它使用IEnumerable<CartLine>對購物車的内容進行通路。所有這些都很直覺,利用一點點LINQ的輔助,很好的實作了。

首先添加加入購物車按鈕,編輯Views/Shared/ProductSummary.cshtml視圖

@model SportsStore.Domain.Entities.Product

<div class="well">
    <h3>
        <strong>@Model.Name</strong>
        <span class="pull-right label label-primary">@Model.Price.ToString("c")</span>
    </h3>

    @using (Html.BeginForm("AddToCart", "Cart"))
    {//BeginForm 輔助器會建立一個使用HTTPpost方法的表單,也可對其進行修改,使用get方法,但是HTTP規範要求get請求必須是幂等的,也就是說他們不會引起資料的變化,而此處将一個産品添加到購物車顯然是一個變化,是以這裡沒有用get
        <div class="pull-right">
            @Html.HiddenFor(x=>x.ProductID)
            @Html.Hidden("returnUrl",Request.Url.PathAndQuery)
            <input type="submit" class="btn btn-success" value="加入購物車"/>
        </div>
    }

    <span class="lead">@Model.Description</span>
</div>
           

在清單中添加了一個Razor代碼塊,為清單中的每一個産品建立一個小型的HTML表單。當該表單被遞交時,将調用Cart控制器中的AddToCart動作方法。

預設情況下,BeginForm 輔助器會建立一個使用HTTPpost方法的表單,也可對其進行修改,使用get方法,但是HTTP規範要求get請求必須是幂等的,也就是說他們不會引起資料的變化,而此處将一個産品添加到購物車顯然是一個變化,是以這裡沒有用get。

2.實作購物車控制器

此時需要一個控制器來處理“加入購物車”按鈕的單擊。為此,在SportsStore.WebUI項目中建立一個新的控制器,名稱為“CartController”,并編輯内容,使其與清單吻合。

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 CartController : Controller
    {
        private IProductsRepository repository;

        public CartController(IProductsRepository repo)
        {
            repository = repo;
        }

        public ViewResult Index(string returnUrl)
        {
            return View(new CartIndexViewModel
            {
                Cart = GetCart(),
                ReturnUrl = returnUrl
            });
        }

        public RedirectToRouteResult AddToCart(int productId,string returnUrl)
        {
            Product product = repository.Products.FirstOrDefault(p => p.ProductID == productId);
            if (product != null)
            {
                GetCart().AddItem(product, 1);
            }
            return RedirectToAction("Index", new { returnUrl });
        }

        public RedirectToRouteResult RemoveFromCart(int productId,string returnUrl)
        {
            Product product = repository.Products.FirstOrDefault(p => p.ProductID == productId);
            if (product != null)
            {
                GetCart().RemoveLine(product);
            }
            return RedirectToAction("Index", new { returnUrl });
        }
        //Asp.net 有一個很好的會話特性,使用重寫cookie或URL的辦法,将一個使用者的多個請求關聯在一起,形成一個單一的會話。
        private Cart GetCart()
        {
            Cart cart = (Cart)Session["Cart"];
            if (cart == null)
            {
                cart = new Cart();
                Session["Cart"] = cart;
            }
            return cart;
        }
    }
}
           

該控制器有幾點需要注意。第一是為了存儲和接收Cart對象,這裡使用了Asp.net的會話狀态特性,這是GetCart方法的目的。Asp.net有一個很好的會話特性,它使用重寫cookies或URL的辦法,将一個使用者的多個請求關聯在一起,形成一個單一的浏覽會話。與之有關的一個特性是會話狀态,它可以将資料與會話關聯起來,這對Cart類很合适。這可以使每個使用者有自己的購物車,并且購物車在各次請求之間是保持有效的。當會話過期(典型的情況是使用者很長時間沒有任何請求)時,與會話關聯的資料會被删除,這意味着不需要對Cart對象的存儲或其生命周期進行管理。為了給會話狀态添加一個對象,隻要為Session對象上設定一個鍵的值即可:Session["Cart"] = cart;    Cart cart = (Cart)Session["Cart"];

會話狀态對象(Session對象)預設存儲在ASp.net伺服器的記憶體中,但你可以配置不同的存儲方式,包括使用資料庫。

對于AddToCart和RemoveFromCart方法,使用了HTML表單中input元素相比對的參數名,這些HTML表單是在ProductSummary.cshtml視圖中建立的。這可以讓MVC架構将輸入表單的post變量與這些參數關聯起來,意即,不需要自己去處理這個表單。

3.顯示購物車内容

對于Cart控制器,要注意的是AddToCart和RemoveFromCart方法都調用了RedirectToAction方法。其效果是,将一個HTTP的重定向指令發送到用戶端浏覽器,要求浏覽器請求一個新的URL。在此例中,要求浏覽器請求的URL是調用Cart控制器的Index動作方法。

在SportsStore.WebUI項目的models檔案下添加一個CartIndexViewModel.cs檔案

using SportsStore.Domain.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace SportsStore.WebUI.Models
{
    public class CartIndexViewModel
    {
        public Cart Cart { get; set; }
        public string ReturnUrl { get; set; }
    }
}
           

建立Index.cshtml視圖,右擊Index動作方法,添加視圖:

@model SportsStore.WebUI.Models.CartIndexViewModel

@{ 
    ViewBag.Title = "我的購物車";
}

<h2>我的購物車</h2>
<table class="table">
    <thead>
        <tr>
            <th class="text-center">數量</th>
            <th class="text-center">産品</th>
            <th class="text-center">價格</th>
            <th class="text-center">總價</th>
        </tr>
    </thead>
    <tbody>
        @foreach(var line in Model.Cart.Lines)
        {
            <tr>
                <td class="text-center">@line.Quantity</td>
                <td class="text-center">@line.Product.Name</td>
                <td class="text-center">@line.Product.Price.ToString("c")</td>
                <td class="text-center">@((line.Quantity*line.Product.Price).ToString("c"))</td>
            </tr>
        }
    </tbody>

    <tfoot>
        <tr>
            <td></td>
            <td></td>
            <td colspan="1" class="text-center">總價:</td>
            <td class="text-center">
                @Model.Cart.ComputeTotalValue().ToString("c")
            </td>
        </tr>
    </tfoot>
</table>

<div class="text-center">
    <a class="btn btn-primary" href="@Model.ReturnUrl" target="_blank" rel="external nofollow" >繼續購物</a>
</div>
           

該視圖枚舉了購物車中的各條資訊,并在一個HTML的表格中為各條資訊添加一個表格行,并帶有各行的總價以及整個購物車的總價。給這些元素的class标簽屬性所賦的值對應于Bootsrap用于表格和元素對齊的樣式。

效果展示

ASP.net Mvc SportsSpore項目開發(三)
ASP.net Mvc SportsSpore項目開發(三)

項目代碼連結:點選打開連結

繼續閱讀