Solved

HttpContext Issue

Posted on 2011-09-10
3
235 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In order to hide the "ugly" records selectors (triangles) in the rowheaders, here are some suggestions. Microsoft doesn't have a direct method/property to do it. You can only hide the rowheader column. First solution, the easy way The first sol…
Entity Framework is a powerful tool to help you interact with the DataBase but still doesn't help much when we have a Stored Procedure that returns more than one resultset. The solution takes some of out-of-the-box thinking; read on!
NetCrunch network monitor is a highly extensive platform for network monitoring and alert generation. In this video you'll see a live demo of NetCrunch with most notable features explained in a walk-through manner. You'll also get to know the philos…
This is my first video review of Microsoft Bookings, I will be doing a part two with a bit more information, but wanted to get this out to you folks.

691 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