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">继续购物</a>
</div>

该视图枚举了购物车中的各条信息,并在一个HTML的表格中为各条信息添加一个表格行,并带有各行的总价以及整个购物车的总价。给这些元素的class标签属性所赋的值对应于Bootsrap用于表格和元素对齐的样式。

效果展示



项目代码链接:点击打开链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨中深巷的油纸伞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值