惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Security Latest
Security Latest
量子位
博客园 - 三生石上(FineUI控件)
小众软件
小众软件
S
SegmentFault 最新的问题
The GitHub Blog
The GitHub Blog
AWS News Blog
AWS News Blog
T
Threat Research - Cisco Blogs
博客园 - Franky
Vercel News
Vercel News
H
Help Net Security
Martin Fowler
Martin Fowler
Security Archives - TechRepublic
Security Archives - TechRepublic
L
LINUX DO - 热门话题
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
L
Lohrmann on Cybersecurity
Cyberwarzone
Cyberwarzone
W
WeLiveSecurity
V2EX - 技术
V2EX - 技术
C
CERT Recently Published Vulnerability Notes
S
Secure Thoughts
C
Cyber Attacks, Cyber Crime and Cyber Security
B
Blog RSS Feed
H
Hacker News: Front Page
P
Proofpoint News Feed
博客园 - 聂微东
N
News and Events Feed by Topic
C
Cybersecurity and Infrastructure Security Agency CISA
D
Docker
博客园_首页
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
人人都是产品经理
人人都是产品经理
The Hacker News
The Hacker News
S
Security @ Cisco Blogs
博客园 - 【当耐特】
F
Fortinet All Blogs
The Register - Security
The Register - Security
A
About on SuperTechFans
D
Darknet – Hacking Tools, Hacker News & Cyber Security
S
Schneier on Security
NISL@THU
NISL@THU
Attack and Defense Labs
Attack and Defense Labs
Help Net Security
Help Net Security
Cisco Talos Blog
Cisco Talos Blog
月光博客
月光博客
IT之家
IT之家
有赞技术团队
有赞技术团队
Know Your Adversary
Know Your Adversary
Hugging Face - Blog
Hugging Face - Blog

博客园 - zqf620

.NET PetShop 3.0 FAQ novalidate选项无效的问题 .NET方向高级开发人员面试时应该事先考虑的问题 (zt) UML中的图 从一组数中每次抽取出一个数,并规定了每个数出现的概率 从一个表中随即抽取100条记录 PL/SQL User's Guide and Reference, Release 2 (9.2) chm版 下载 Oracle中实现自动增长列 在开发过程中运用UML 输出到html页面的字符串的格式化 在DataGrid控件中编辑数据项 在DataGrid控件中获取数据项中各列的数据内容 DataGrid控件的分页 DTD简介 W3C XML Schema (XSD) XML相关技术概览 将web窗体页文件(test.aspx)转换成用户控件文件(test.ascx) access作为后台数据库遇到的访问权限问题 HTML实体
.Net PetShop 3.0中购物车总价计算的bug
zqf620 · 2007-03-08 · via 博客园 - zqf620

.Net PetShop 3.0中购物车总价计算的bug

  当在购物车页面(ShoppingCart.aspx)中,更改了购物车中某一个商品的数量(Quantity栏)后,点击Update按钮来更新购物车的总价(Total),但是购物车的总价并没有被更新,这是一个bug。

  在业务逻辑层(BLL)中,购物车由Cart类表示,而购物车中每个商品记录则由Mode模块的CartItemInfo类来表示。CartItemInfo类的Price、Quantity和Subtotal属性表示购物车中每个商品记录的单价、数量和价格小计(Subtotal=Price*Quantity),而Cart类的Total属性表示购物车的总价。购物车的总价应该是购物车中每个商品记录的价格小计的总和。

  在什么时候计算购物车的总价,有两种可选的方式:
1)在向购物车中添加商品记录、删除商品记录和修改购物车中某商品记录的数量时,修改购物车总价
2)在要读取购物车总价时,遍历购物车中每个商品记录来计算购物车总价
  从类的设计角度来讲,第二种方式明显要好于第一种方式。因为,第一种方式中,计算总价的逻辑被分散到多个地方(Cart类的Add、Remove、RemoveAt方法和UI层的Update按钮的事件处理方法)来实现。第二种方式中,只需要在Cart类的Total属性的代码中来实现计算总价的逻辑。
  令人不解的是,.net PetShop使用的是第一种方式,在Cart类的Add、Remove、RemoveAt方法编写了计算总价的代码,但是在Update按钮的事件处理方法(PetShop.Web.ShoppingCart类的CommandClicked方法)中却没有修改购物车总价的代码,这就是Bug的所在。
  CommandClicked方法的代码如下:
---------------------------------------------------------
  /// <summary>
  /// Function to control user clicking on a button on the page
  /// 处理Remove和Update按钮的事件
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  protected void CommandClicked(object sender, RepeaterCommandEventArgs e)
  {
   // Check for update button
   if (e.CommandName == CMD_UPDATE)
   {
    TextBox txt;
    int qty;
    int index;

    // Go through each item on the page
    // 遍历购物车中每一条商品记录,如果其数量在页面上被修改了,则更新之
    // cart(ViewStatePager控件)和myCart(Cart对象)保持一致
    for (int i = 0, j = cart.Items.Count; i < j; i++){

     // lookup the control
     txt = (TextBox)cart.Items[i].FindControl(ID_TXT);

     try
     {
      // 得到商品记录的数量
      qty = int.Parse(txt.Text);
      // 得到商品记录在购物车中的下标
      index = cart.CurrentPageIndex * cart.PageSize + i;
      
      // If the new qty is zero, remove the item from the cart
      if (qty <= 0)
       myCart.RemoveAt(index);     
      // Update the item with the new quantity
      else
       //在购物车对象中更新指定商品记录的数量
       //这时,购物车的总价发生了变化,但这里没有作相应的处理,是一个bug
       myCart[index].Quantity = qty;
     }
     catch
     {}    //忽略所有异常
    }   
   }
   else
    // otherwise the command is to remove the an item
    myCart.Remove((string)e.CommandArgument);

   // Refresh the contents of the cart page
   Refresh();

   // Update the page count if required
   int pageCount = (myCart.Count - 1) / cart.PageSize;
   cart.SetPage(Math.Min(cart.CurrentPageIndex, pageCount));
  }
-------------------------------------------------------

  相应的,可以用上述的两种方式来修补这个bug。第一种方式只需要在UI层的ShoppingCart类的CommandClicked方法中加上修改购物车总价的代码。第二种方式,需要删除Cart类的Add、Remove、RemoveAt方法中相关的代码,然后重新编写Cart类的Total属性的实现代码。
  这里采用第二种方式,Cart的代码如下:
-----------------------------------------------------
using System;
using System.Collections;

//References to PetShop specific libraries
//PetShop busines entity library
using PetShop.Model;

namespace PetShop.BLL {
 
 /// <summary>
 /// An object to represent a customer's shopping cart
 /// 购物车类
 /// </summary>
 [Serializable]
 public class Cart : IEnumerable {

  /// <summary>
  /// Internal storage for a cart
  /// 数组列表中保存的是CartItemInfo对象实例
  /// </summary>
  private ArrayList _items = new ArrayList();
  //Fixbug bug001: 修改了属性Total,下面的一条语句就不需要了(被注释掉)
//  private decimal _total=0;

  /// <summary>
  /// Returns an enumerator for the cart items in a cart
  /// </summary>
  /// <returns></returns>
  public IEnumerator GetEnumerator() {
   return _items.GetEnumerator();
  }

  // Properties  
  public decimal Total
  {
   //Fixbug bug001: Total属性应该是只读的,其值应该是自动计算的
//   get { return _total; }
//   set { _total = value; }
   //Fixbug bug001: 重写的代码
     get{
    Decimal total = 0;
    foreach(CartItemInfo cartItem in _items)
    {
     total += cartItem.Subtotal;
    }
    return total;
   }
  }

  /// <summary>
  /// Returns number of items in cart
  /// 返回购物车中商品项的数目
  /// </summary>
  public int Count {
   get { return _items.Count; }
  }

  /// <summary>
  /// Return CartItem representation of object at a given address
  /// 索引器。获取购物车中任一商品项的信息
  /// </summary>
  ///
  public CartItemInfo this[int index] {
   get { return (CartItemInfo)_items[index]; }
  }

  /// <summary>
  /// Add an item to the cart
  /// 添加一个商品项到购物车
  /// </summary>
  /// <param name="ItemId">ItemId of item to add</param>
  public void Add(string ItemId)
  {
   foreach (CartItemInfo cartItem in _items) //如果商品项已经存在于购物车中
   {
    if (ItemId == cartItem.ItemId) {
     cartItem.Quantity++; // 该商品项的个数加一
     // 判定该商品项是否还有库存
     cartItem.InStock = (GetInStock(ItemId) - cartItem.Quantity) >= 0 ? true : false;
     //Fixbug bug001: 修改了属性Total,下面的一条语句就不需要了(被注释掉)
//     _total = _total+(cartItem.Price*cartItem.Quantity); //修改购物车中商品的总价
     return;
    }
   }

   Item item = new Item();
   ItemInfo data = item.GetItem(ItemId);
   CartItemInfo newItem = new  CartItemInfo(ItemId,data.Name,(data.Quantity >= 1),1,(decimal)data.Price);

   _items.Add(newItem);
   //Fixbug bug001: 修改了属性Total,下面的一条语句就不需要了(被注释掉)
//   _total = _total+(data.Price);
  }

  /// <summary>
  /// Remove item from the cart based on itemId
  /// 从购物车中移除一个商品项
  /// </summary>
  /// <param name="itemId">ItemId of item to remove</param>
  public void Remove(string itemId) {
   foreach (CartItemInfo item in _items) {
    if (itemId == item.ItemId)  //找到指定的商品项id
    {
     _items.Remove(item);
     //Fixbug bug001: 修改了属性Total,下面的一条语句就不需要了(被注释掉)
//     _total = _total-(item.Price*item.Quantity); //修改总价
     return;
    }
   }
  }

  /// <summary>
  /// Removes item from cart at specific index
  /// 从购物车中移除一个商品项(指定索引)
  /// </summary>
  /// <param name="index">Element number of item to remove</param>
  public void RemoveAt(int index)
  {
   CartItemInfo item = (CartItemInfo)_items[index];
   //Fixbug bug001: 修改了属性Total,下面的一条语句就不需要了(被注释掉)
//   _total = _total-(item.Price*item.Quantity);
   _items.RemoveAt(index);   
  }

  /// <summary>
  /// Returs internal array list of cart items
  /// </summary>
  /// <returns></returns>
  public ArrayList GetCartItems() {
   return _items;
  }

  /// <summary>
  /// Method to convert internal array of cart items to order line items
  /// 将购物车中的商品项信息转换为订单明细信息
  /// </summary>
  /// <returns>New array list of order line items</returns>
  public ArrayList GetOrderLineItems() {

   ArrayList orderLineItems = new ArrayList();

   int lineNum = 1;

   foreach (CartItemInfo item in _items) {
    // 购物车中每一个商品项就生成一条订单明细行
    LineItemInfo lineItem = new LineItemInfo(item.ItemId,item.Name,lineNum,item.Quantity,item.Price);
    orderLineItems.Add(lineItem);
    lineNum++;
   }

   return orderLineItems;
  }

  
  /// <summary>
  /// Internal method to get the stock level of an item
  /// 获得指定商品项的库存数
  /// </summary>
  /// <param name="ItemId">Unique identifier of item to get stock level of</param>
  /// <returns></returns>
  private int GetInStock(string ItemId)
  {
   Inventory inventory = new Inventory();
   return inventory.CurrentQuantityInStock(ItemId);
  }
 }
}