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

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - zqf620

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