Solved

HttpContext Issue

Posted on 2011-09-10
3
226 Views
Last Modified: 2012-05-12
I have some code that I copied from a shopping cart tutorial in C#, the one issue that I see with the code is that when you add things to the shopping cart for one user(user A) it also adds things to the shopping cart for another user(user B).  How do I make a distinct update to a shopping cart for each individual user as they user the shopping cart?  I have the code below that is attached.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace ShoppingCart
{
    public class ShoppingCart
    {
        #region Properties

        public List<CartItem> Items { get; private set; }

        #endregion

        #region Singleton Implementation

        //Readonly properties can only be set in initialization or in a constructor
        public static readonly ShoppingCart Instance;

        //The static constructor is called as soon as the class is loaded into memory
        static ShoppingCart()
        {
            //If the cart is not in the session, create one and put it there
            //Otherwise, get it from the session
            if (HttpContext.Current.Session["ASPNETShoppingCart"] == null)
            {
                Instance = new ShoppingCart();
                Instance.Items = new List<CartItem>();
                HttpContext.Current.Session["ASPNETShoppingCart"] = Instance;
            }
            else
            {
                Instance = (ShoppingCart)HttpContext.Current.Session["ASPNETShoppingCart"];
            }
        }

        //A protected constructor ensures that an object can't be created from outside
        protected ShoppingCart() { }

        #endregion

        #region Item Modification Methods
        /**
         * AddItem() - Adds an item to the shopping
         */
        public void AddItem(int productId)
        {
            //Create a new item to add to the shopping cart
            CartItem newItem = new CartItem(productId);

            //If this item already exists in our list of items, increase the quantity
            //Otherwise, add the new item to the list
            if (Items.Contains(newItem))
            {
                foreach (CartItem item in Items)
                {
                    if (item.Equals(newItem))
                    {
                        item.Quantity++;
                        return;
                    }
                }
            }
            else
            {
                newItem.Quantity = 1;
                Items.Add(newItem);
            }
        }


        public void SetItemQuantity(int productId, int quantity)
        {
            //If we are setting the quantity to 0, remove the item entirely
            if (quantity == 0)
            {
                RemoveItem(productId);
                return;
            }

        }

        public void RemoveItem(int productId)
        {
            CartItem removeItem = new CartItem(productId);
            Items.Remove(removeItem);
        }
        #endregion

        #region Reporting Methods
        /**GetSubTotal() - returns the total price of all the items
         *              before tax, shipping, etc.
         */
        public decimal GetSubTotal()
        {
            decimal subTotal = 0;
            foreach (CartItem item in Items)
            
                subTotal += item.TotalPrice;

                return subTotal;            
        }
        #endregion
    }
}

Open in new window

0
Comment
Question by:VBBRett
  • 2
3 Comments
 
LVL 11

Expert Comment

by:azarc3
ID: 36518890
Have you tested this yet? it looks to me like it actually will result in a separate ShoppingCart instance for each user. The constructor for looks into the currently executing Session, not the Application, so it should result in what you want.

This is kind of clumsy because, at the end of the day, you're still going to have multiple instances of the ShoppingCart class in memory... So I don't see the value of using the singleton pattern for this. To get rid of the confusion, I'd suggest removing the "static"'s and adjusting your code appropriately.
0
 

Author Comment

by:VBBRett
ID: 36519123
Ok, besides getting rid of the statics, what else should I do?  Can you show me example of code that would correct what I am doing?
0
 
LVL 11

Accepted Solution

by:
azarc3 earned 500 total points
ID: 36535819
It's important to note that I'm only going to be able to steer you in a direction, and this is because I don't have the full application or intent of what you're trying to accomplish. The "fix" is two-pronged:

1. You need a way to distinguish users.
2. You want maintain the integrity of the example code your using so that you won't get "lost".

DISCLAIMER: I haven't tested this, but this is close to what I'd do given the constraints above. You'll probably have to tweak this class a bit for your own "fit". Also, it may simply have a bug or two.

The change at line 12 necessitates many other major changes. It's all still very similar, but importantly different. Please note also that the change to line 12 is going to require modifications to any part of your application that access the Shopping Cart directly.

You're going to have to assign a Guid to every user when it makes sense to you... I'd suggest it be when the session starts (just to make it easier on yourself), but it could be when the user adds their first item to the Shopping Cart. The code necessary for this is:
Guid shopperId = Guid.NewGuid();

I've also added a helper method to find a particular Item for a particular User. Compare the two to understand what I've done. It may also be instructive to read up on the generic Dictionary construct.

There is definite room for optimization in this example... I left if fairly verbose so it's easier to follow.



using System;
using System.Collections.Generic;
using System.Web;
using System.Linq;

namespace TestProject1
{
    public class ShoppingCart
    {
        #region Properties

        public Dictionary<Guid, List<CartItem>> Items { get; private set; }

        #endregion

        #region Singleton Implementation

        //Readonly properties can only be set in initialization or in a constructor
        public static readonly ShoppingCart Instance;

        //The static constructor is called as soon as the class is loaded into memory
        static ShoppingCart()
        {
            //If the cart is not in the session, create one and put it there
            //Otherwise, get it from the session
            if (HttpContext.Current.Session["ASPNETShoppingCart"] == null)
            {
                Instance = new ShoppingCart();
                Instance.Items = new Dictionary<Guid, List<CartItem>>();
                HttpContext.Current.Session["ASPNETShoppingCart"] = Instance;
            }
            else
            {
                Instance = (ShoppingCart)HttpContext.Current.Session["ASPNETShoppingCart"];
            }
        }

        //A protected constructor ensures that an object can't be created from outside
        protected ShoppingCart() { }

        #endregion

        #region Item Modification Methods
        /**
         * AddItem() - Adds an item to the shopping
         */
        public void AddItem(Guid shopperId, int productId)
        {
            //Create a new item to add to the shopping cart
            CartItem newItem = new CartItem(productId) { Quantity = 1 };

            //If this item already exists in our list of items, increase the quantity
            //Otherwise, add the new item to the list

            // Do I already have a cart setup for this user?
            // If not, add them and the selected product... then exit the method
            if (!Items.ContainsKey(shopperId))
            {
                Items.Add(shopperId, new List<CartItem> { newItem });
                return;
            }

            // Does this user already have anything picked?
            // If not, add the new item and exit the method
            if (Items[shopperId].Count == 0)
            {
                Items[shopperId].Add(newItem);
                return;
            }

            // Does this user already have the item picked?
            // If not, add the item and exit the method
            var myItem = GetSelectionIndex(shopperId, productId);

            if (myItem < 0)
            {
                Items[shopperId].Add(newItem);
                return;
            }

            // We've found the user and the picked item...
            // Increase the quanity of the selected item.
            Items[shopperId][myItem].Quantity++;
        }


        public void SetItemQuantity(Guid shopperId, int productId, int quantity)
        {
            // Does the user have a cart? If not, exit
            if (!Items.ContainsKey(shopperId)) return;

            // Find the item for this user
            var myItem = GetSelectionIndex(shopperId, productId);

            // Item not picked? exit
            if (myItem < 0) return;

            //If we are setting the quantity to 0, remove the item entirely
            if (quantity == 0)
            {
                RemoveItem(shopperId, productId);
                return;
            }

            // everything checks out; set the quantity approporiately
            Items[shopperId][myItem].Quantity = quantity;
        }

        public void RemoveItem(Guid shopperId, int productId)
        {
            int index = GetSelectionIndex(shopperId, productId);
            CartItem removeItem = Items[shopperId][index];
            Items[shopperId].Remove(removeItem);
        }
        #endregion

        #region Reporting Methods
        /**GetSubTotal() - returns the total price of all the items
         *              before tax, shipping, etc.
         */
        public decimal GetSubTotal(Guid shopperId)
        {
            decimal subTotal = 0;
            if (Items.ContainsKey(shopperId)) subTotal = Items[shopperId].Sum(a => a.TotalPrice);
            return subTotal;
        }

        public int GetSelectionIndex(Guid shopperId, int productId)
        {
            return Items[shopperId].FindIndex(a => a.ProductId == productId);
        }
        #endregion
    }
}

Open in new window

0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

Extention Methods in C# 3.0 by Ivo Stoykov C# 3.0 offers extension methods. They allow extending existing classes without changing the class's source code or relying on inheritance. These are static methods invoked as instance method. This…
Introduction Although it is an old technology, serial ports are still being used by many hardware manufacturers. If you develop applications in C#, Microsoft .NET framework has SerialPort class to communicate with the serial ports.  I needed to…
This video discusses moving either the default database or any database to a new volume.
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now