Search code examples
e-commerceshopping-carthttpcontext

How can I keep track of a shopping cart across multiple projects?


First some background, we are creating a new "eGov" application. Eventually, a citizen can request permits and pay for licenses along with pay their utility bills and parking tickets online. Our vision has a shopping cart so a person can pay for multiple items in one transaction. To keep things organized better, we are going to break each section into a different project. This also allows me to work on one project while the other developer works another. The person making a payment could be a registered user or could remain unregistered. We feel a person from out of our jurisdiction probably doesn't want to register just to pay their parking ticket or pay for a one-time business license.

This project will be on Windows Server 2008 and IIS7 and using ASP.NET MVC 3. We will probably use a single domain (maybe egov.domain.gov) and in multiple sub directories (/cart, /permit, /billing, etc) though that is not 100% decided yet.

Now the problem. How do we track a shopping cart across multiple projects? There was talk of using a cookie that expires at a certain point or using a state machine. We are uncertain if using a session id would work. If we use a state machine, I have never used that and only understand it in concept (it works across multiple machines and SO uses it).

One other note, we are going to be building this on a VMWare server, so the possibility of having this run across multiple servers is a possibility in the future.

What would you use and why?

Update: It appears like many seem to recommend storing the cart in HttpContext. Is this the same across multiple applications?


Solution

  • First you need to setup your SQL Server to accept session state connections.

    Then add the following to your Web.config file:

    <sessionState mode="SQLServer" sqlConnectionString="Server=.\SQLEXPRESS;Integrated Security=SSPI;Initial Catalog=ASPState;Application Name=name" timeout="20" allowCustomSqlDatabase="true" />` within `<system.web>
    

    I then created a class library that has two classes: Cart and CartItem.

    CartItem defined to hold each individual shopping cart item

    [Serializable]
    public class CartItem
    {
        [Key]
        public int RecordId { set; get; }
        public string ItemNumber { set; get; }
        public string Description { set; get; }
        public DateTime DateTimeCreated { set; get; }
        public decimal Cost { get; set; }
    }
    

    Cart works with your shopping cart

    public class Cart
    {
        HttpContextBase httpContextBase = null;
        public const string CartSessionKey = "shoppingCart";
    
        /// <summary>
        /// Initializes a new instance of the <see cref="ShoppingCart"/> class.
        /// </summary>
        /// <param name="context">The context.</param>
        public Cart(HttpContextBase context)
        {
            httpContextBase = context;
        }
    
        /// <summary>
        /// Gets the cart items.
        /// </summary>
        /// <returns></returns>
        public List<CartItem> GetCartItems()
        {
            return (List<CartItem>)httpContextBase.Session[CartSessionKey];
        }
    
        /// <summary>
        /// Adds to cart.
        /// </summary>
        /// <param name="cartItem">The cart item.</param>
        public void AddToCart(CartItem cartItem)
        {
            var shoppingCart = GetCartItems();
    
            if (shoppingCart == null)
            {
                shoppingCart = new List<CartItem>();
            }
    
            cartItem.RecordId = shoppingCart.Count + 1;
            cartItem.DateTimeCreated = DateTime.Now;
            shoppingCart.Add(cartItem);
    
            httpContextBase.Session[CartSessionKey] = shoppingCart;
        }
    
        /// <summary>
        /// Removes from cart.
        /// </summary>
        /// <param name="id">The id.</param>
        public void RemoveFromCart(int id)
        {
            var shoppingCart = GetCartItems();
            var cartItem = shoppingCart.Single(cart => cart.RecordId == id);
            shoppingCart.Remove(cartItem);
            httpContextBase.Session[CartSessionKey] = shoppingCart;
        }
    
        /// <summary>
        /// Empties the cart.
        /// </summary>
        public void EmptyCart()
        {
            httpContextBase.Session[CartSessionKey] = null;
        }
    
        /// <summary>
        /// Gets the count.
        /// </summary>
        /// <returns></returns>
        public int GetCount()
        {
            return GetCartItems().Count;
        }
    
        /// <summary>
        /// Gets the total.
        /// </summary>
        /// <returns></returns>
        public decimal GetTotal()
        {
            return GetCartItems().Sum(items => items.Cost);
        }
    }
    

    To test this, first in my shopping cart project in my home controller I did the following:

        public ActionResult Index()
        {
            var shoppingCart = new Cart(this.HttpContext);
            var cartItem = new CartItem
            {
                Description = "Item 1",
                ItemNumber = "123"
                Cost = 20,
                DateTimeCreated = DateTime.Now
            };
    
            shoppingCart.AddToCart(cartItem);
    
            cartItem = new CartItem
            {
                Description = "Item 2",
                ItemNumber = "234"
                Cost = 15,
                DateTimeCreated = DateTime.Now
            };
    
            shoppingCart.AddToCart(cartItem);
    
            var viewModel = new ShoppingCartViewModel
            {
                CartItems = shoppingCart.GetCartItems(),
                CartTotal = shoppingCart.GetTotal()
            };
    
            return View(viewModel);
        }
    

    In my second project's home controller, I added the following:

        public ActionResult Index()
        {
            var shoppingCart = new Cart(this.HttpContext);
            var cartItem = new CartItem
            {
                Description = "Item 3",
                ItemNumber = "345"
                Cost = 55,
                DateTimeCreated = DateTime.Now
            };
    
            shoppingCart.AddToCart(cartItem);
    
            return View();
        }
    

    This seemed to work for me great.