쇼핑 카트

작성자: Erik Reitan

Wingtip Toys 샘플 프로젝트 다운로드(C#) 또는 전자책 다운로드(PDF)

이 자습서 시리즈에서는 웹용 ASP.NET 4.5 및 Microsoft Visual Studio Express 2013을 사용하여 ASP.NET Web Forms 애플리케이션을 빌드하는 기본 사항을 설명합니다. C# 소스 코드가 있는 Visual Studio 2013 프로젝트는 이 자습서 시리즈와 함께 사용할 수 있습니다.

이 자습서에서는 Wingtip Toys 샘플 ASP.NET Web Forms 애플리케이션에 쇼핑 카트를 추가하는 데 필요한 비즈니스 논리에 대해 설명합니다. 이 자습서는 이전 자습서 "데이터 항목 및 세부 정보 표시"를 기반으로 하며 Wingtip Toy Store 자습서 시리즈의 일부입니다. 이 자습서를 완료하면 샘플 앱의 사용자가 쇼핑 카트에서 제품을 추가, 제거 및 수정할 수 있습니다.

학습할 내용:

  1. 웹 애플리케이션에 대한 쇼핑 카트를 만드는 방법입니다.
  2. 사용자가 쇼핑 카트에 항목을 추가할 수 있도록 하는 방법입니다.
  3. GridView 컨트롤을 추가하여 쇼핑 카트 세부 정보를 표시하는 방법입니다.
  4. 주문 합계를 계산하고 표시하는 방법입니다.
  5. 쇼핑 카트에서 항목을 제거하고 업데이트하는 방법입니다.
  6. 쇼핑 카트 카운터를 포함하는 방법.

이 자습서의 코드 기능:

  1. Entity Framework Code First
  2. 데이터 주석
  3. 강력한 형식의 데이터 컨트롤
  4. 모델 바인딩

쇼핑 카트 만들기

이 자습서 시리즈의 앞부분에서는 데이터베이스에서 제품 데이터를 볼 수 있는 페이지와 코드를 추가했습니다. 이 자습서에서는 사용자가 구매하려는 제품을 관리하는 쇼핑 카트를 만듭니다. 사용자는 등록되거나 로그인하지 않은 경우에도 쇼핑 카트에 항목을 찾아 추가할 수 있습니다. 쇼핑 카트 액세스를 관리하려면 사용자가 처음으로 쇼핑 카트에 액세스할 때 GUID(Globally Unique Identifier)를 사용하여 고유한 ID 사용자를 할당합니다. ASP.NET 세션 상태를 사용하여 저장 ID 합니다.

참고

ASP.NET 세션 상태는 사용자가 사이트를 떠난 후 만료되는 사용자별 정보를 저장하는 편리한 장소입니다. 세션 상태의 오용은 대규모 사이트에 성능에 영향을 미칠 수 있지만 세션 상태를 가볍게 사용하는 것은 데모 목적으로 잘 작동합니다. Wingtip Toys 샘플 프로젝트는 외부 공급자 없이 세션 상태를 사용하는 방법을 보여 하며, 여기서 세션 상태는 사이트를 호스트하는 웹 서버에 in-process로 저장됩니다. 애플리케이션의 여러 인스턴스를 제공하는 대규모 사이트 또는 다른 서버에서 애플리케이션의 여러 인스턴스를 실행하는 사이트의 경우 Windows Azure Cache Service를 사용하는 것이 좋습니다. 이 Cache Service는 웹 사이트 외부에 있는 분산 캐싱 서비스를 제공하고 In-process 세션 상태를 사용하는 문제를 해결합니다. 자세한 내용은 Windows Azure 웹 사이트에서 ASP.NET 세션 상태를 사용하는 방법을 참조하세요.

모델 클래스로 CartItem 추가

이 자습서 시리즈의 앞부분에서는 Models 폴더에 및 클래스를 만들어 Category 범주 및 Product 제품 데이터에 대한 스키마를 정의했습니다. 이제 새 클래스를 추가하여 쇼핑 카트의 스키마를 정의합니다. 이 자습서의 뒷부분에서는 테이블에 대한 데이터 액세스를 처리하는 클래스를 CartItem 추가합니다. 이 클래스는 쇼핑 카트에서 항목을 추가, 제거 및 업데이트하는 비즈니스 논리를 제공합니다.

  1. Models 폴더를 마우스 오른쪽 단추로 클릭하고 추가 ->새 항목을 선택합니다.

    쇼핑 카트 - 새 항목

  2. 새 항목 추가 대화 상자가 표시됩니다. 코드를 선택한 다음, 클래스를 선택합니다.

    쇼핑 카트 - 새 항목 추가 대화 상자

  3. 이 새 클래스 의 이름을 CartItem.cs로 지정합니다.

  4. 추가를 클릭합니다.
    새 클래스 파일이 편집기에서 표시됩니다.

  5. 기본 코드를 다음 코드로 바꿉니다.

    using System.ComponentModel.DataAnnotations;
    
    namespace WingtipToys.Models
    {
        public class CartItem
        {
            [Key]
            public string ItemId { get; set; }
    
            public string CartId { get; set; }
    
            public int Quantity { get; set; }
    
            public System.DateTime DateCreated { get; set; }
    
            public int ProductId { get; set; }
    
            public virtual Product Product { get; set; }
    
        }
    }
    

클래스에는 CartItem 사용자가 쇼핑 카트에 추가하는 각 제품을 정의하는 스키마가 포함되어 있습니다. 이 클래스는 이 자습서 시리즈의 앞부분에서 만든 다른 스키마 클래스와 비슷합니다. 규칙에 따라 Entity Framework Code First는 테이블의 기본 키가 CartItem 또는 ID이 될 CartItemId 것으로 예상합니다. 그러나 코드는 데이터 주석 [Key] 특성을 사용하여 기본 동작을 재정의합니다. ItemId 속성의 특성은 Key 속성이 기본 키임을 ItemID 지정합니다.

속성은 CartId 구매할 항목과 연결된 사용자의 를 지정 ID 합니다. 사용자가 쇼핑 카트에 액세스할 때 이 사용자를 ID 만드는 코드를 추가합니다. ASP.NET ID 세션 변수로도 저장됩니다.

제품 컨텍스트 업데이트

클래스를 CartItem 추가하는 것 외에도 엔터티 클래스를 관리하고 데이터베이스에 대한 데이터 액세스를 제공하는 데이터베이스 컨텍스트 클래스를 업데이트해야 합니다. 이렇게 하려면 새로 만든 CartItem 모델 클래스를 클래스에 추가합니다 ProductContext .

  1. 솔루션 탐색기Models 폴더에서 ProductContext.cs 파일을 찾아 엽니다.

  2. 강조 표시된 코드를 다음과 같이 ProductContext.cs 파일에 추가합니다.

    using System.Data.Entity;
     
    namespace WingtipToys.Models
    {
        public class ProductContext : DbContext
        {
            public ProductContext()
                : base("WingtipToys")
            {
            }
     
            public DbSet<Category> Categories { get; set; }
            public DbSet<Product> Products { get; set; }
            public DbSet<CartItem> ShoppingCartItems { get; set; }
        }
    }
    

이 자습서 시리즈의 앞에서 설명한 것처럼 ProductContext.cs 파일의 코드는 Entity Framework의 모든 핵심 기능에 액세스할 수 있도록 네임스페이스를 추가합니다 System.Data.Entity . 이 기능에는 강력한 형식의 개체를 사용하여 데이터를 쿼리, 삽입, 업데이트 및 삭제하는 기능이 포함됩니다. 클래스는 ProductContext 새로 추가 CartItem 된 모델 클래스에 대한 액세스를 추가합니다.

쇼핑 카트 비즈니스 논리 관리

다음으로 새 Logic 폴더에 ShoppingCart 클래스를 만듭니다. 클래스는 ShoppingCart 테이블에 대한 데이터 액세스를 CartItem 처리합니다. 클래스에는 쇼핑 카트에서 항목을 추가, 제거 및 업데이트하는 비즈니스 논리도 포함됩니다.

추가할 쇼핑 카트 논리에는 다음 작업을 관리하는 기능이 포함됩니다.

  1. 쇼핑 카트에 항목 추가
  2. 쇼핑 카트에서 항목 제거
  3. 쇼핑 카트 ID 가져오기
  4. 쇼핑 카트에서 항목 검색
  5. 모든 장바구니 항목의 양 합계
  6. 쇼핑 카트 데이터 업데이트

쇼핑 카트 페이지(ShoppingCart.aspx)와 쇼핑 카트 클래스가 함께 사용하여 쇼핑 카트 데이터에 액세스합니다. 쇼핑 카트 페이지에는 사용자가 장바구니에 추가하는 모든 항목이 표시됩니다. 쇼핑 카트 페이지 및 클래스 외에도 장바구니에 제품을 추가하는 페이지(AddToCart.aspx)를 만듭니다. 또한 사용자가 장바구니에 제품을 추가할 수 있도록 AddToCart.aspx 페이지에 대한 링크를 제공하는 ProductList.aspx 페이지 및 ProductDetails.aspx 페이지에 코드를 추가합니다.

다음 다이어그램에서는 사용자가 장바구니에 제품을 추가할 때 발생하는 기본 프로세스를 보여 줍니다.

쇼핑 카트 - 쇼핑 카트에 추가

사용자가 ProductList.aspx 페이지 또는 ProductDetails.aspx 페이지에서 카트에 추가 링크를 클릭하면 애플리케이션이 AddToCart.aspx 페이지로 이동한 다음 자동으로 ShoppingCart.aspx 페이지로 이동합니다. AddToCart.aspx 페이지는 ShoppingCart 클래스에서 메서드를 호출하여 쇼핑 카트에 선택 제품을 추가합니다. ShoppingCart.aspx 페이지에는 장바구니에 추가된 제품이 표시됩니다.

쇼핑 카트 클래스 만들기

클래스는 ShoppingCart 모델(Models 폴더), 페이지(루트 폴더) 및 논리(논리 폴더)를 명확하게 구분할 수 있도록 애플리케이션의 별도 폴더에 추가됩니다.

  1. 솔루션 탐색기WingtipToys프로젝트를 마우스 오른쪽 단추로 클릭하고 추가-새 폴더를> 선택합니다. 새 폴더 이름을 Logic로 지정합니다.

  2. Logic 폴더를 마우스 오른쪽 단추로 클릭한 다음 추가 ->새 항목을 선택합니다.

  3. ShoppingCartActions.cs라는 새 클래스 파일을 추가합니다.

  4. 기본 코드를 다음 코드로 바꿉니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using WingtipToys.Models;
    
    namespace WingtipToys.Logic
    {
      public class ShoppingCartActions : IDisposable
      {
        public string ShoppingCartId { get; set; }
    
        private ProductContext _db = new ProductContext();
    
        public const string CartSessionKey = "CartId";
    
        public void AddToCart(int id)
        {
          // Retrieve the product from the database.           
          ShoppingCartId = GetCartId();
    
          var cartItem = _db.ShoppingCartItems.SingleOrDefault(
              c => c.CartId == ShoppingCartId
              && c.ProductId == id);
          if (cartItem == null)
          {
            // Create a new cart item if no cart item exists.                 
            cartItem = new CartItem
            {
              ItemId = Guid.NewGuid().ToString(),
              ProductId = id,
              CartId = ShoppingCartId,
              Product = _db.Products.SingleOrDefault(
               p => p.ProductID == id),
              Quantity = 1,
              DateCreated = DateTime.Now
            };
    
            _db.ShoppingCartItems.Add(cartItem);
          }
          else
          {
            // If the item does exist in the cart,                  
            // then add one to the quantity.                 
            cartItem.Quantity++;
          }
          _db.SaveChanges();
        }
    
        public void Dispose()
        {
          if (_db != null)
          {
            _db.Dispose();
            _db = null;
          }
        }
    
        public string GetCartId()
        {
          if (HttpContext.Current.Session[CartSessionKey] == null)
          {
            if (!string.IsNullOrWhiteSpace(HttpContext.Current.User.Identity.Name))
            {
              HttpContext.Current.Session[CartSessionKey] = HttpContext.Current.User.Identity.Name;
            }
            else
            {
              // Generate a new random GUID using System.Guid class.     
              Guid tempCartId = Guid.NewGuid();
              HttpContext.Current.Session[CartSessionKey] = tempCartId.ToString();
            }
          }
          return HttpContext.Current.Session[CartSessionKey].ToString();
        }
    
        public List<CartItem> GetCartItems()
        {
          ShoppingCartId = GetCartId();
    
          return _db.ShoppingCartItems.Where(
              c => c.CartId == ShoppingCartId).ToList();
        }
      }
    }
    

메서드 AddToCart 를 사용하면 개별 제품을 제품에 ID따라 쇼핑 카트에 포함할 수 있습니다. 제품이 카트에 추가되거나 카트에 해당 제품에 대한 항목이 이미 포함된 경우 수량이 증가합니다.

메서드는 GetCartId 사용자의 카트 ID 를 반환합니다. 카트 ID 는 사용자가 장바구니에 있는 항목을 추적하는 데 사용됩니다. 사용자에게 기존 카트가 없는 경우 새 카트 IDID 가 만들어집니다. 사용자가 등록된 사용자로 로그인하면 카트 ID 가 사용자 이름으로 설정됩니다. 그러나 사용자가 로그인하지 않은 경우 카트 ID 는 고유 값(GUID)으로 설정됩니다. GUID를 통해 세션에 따라 각 사용자에 대해 하나의 카트만 생성됩니다.

메서드는 GetCartItems 사용자의 쇼핑 카트 항목 목록을 반환합니다. 이 자습서의 뒷부분에서는 모델 바인딩이 메서드를 사용하여 GetCartItems 장바구니에 카트 항목을 표시하는 데 사용되는 것을 볼 수 있습니다.

카트에 추가 기능 만들기

앞에서 설명한 대로 사용자의 쇼핑 카트에 새 제품을 추가하는 데 사용할 AddToCart.aspx 라는 처리 페이지를 만듭니다. 이 페이지에서는 방금 만든 클래스의 메서드를 ShoppingCart 호출 AddToCart 합니다. AddToCart.aspx 페이지에는 제품이 ID 전달될 것으로 예상됩니다. 이 제품은 ID 클래스에서 ShoppingCart 메서드를 호출할 AddToCart 때 사용됩니다.

참고

페이지 UI(AddToCart.aspx)가 아닌 이 페이지의 코드 숨김(AddToCart.aspx.cs)을 수정합니다.

카트에 추가 기능을 만들려면 다음을 수행합니다.

  1. 솔루션 탐색기WingtipToys프로젝트를 마우스 오른쪽 단추로 클릭하고 추가 ->새 항목을 클릭합니다.
    새 항목 추가 대화 상자가 표시됩니다.

  2. AddToCart.aspx라는 애플리케이션에 표준 새 페이지(웹 양식)를 추가합니다.

    쇼핑 카트 - 웹 양식 추가

  3. 솔루션 탐색기AddToCart.aspx 페이지를 마우스 오른쪽 단추로 클릭한 다음 코드 보기를 클릭합니다. AddToCart.aspx.cs 코드 숨김 파일이 편집기에서 열립니다.

  4. AddToCart.aspx.cs 코드 숨김의 기존 코드를 다음으로 바꿉니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Diagnostics;
    using WingtipToys.Logic;
    
    namespace WingtipToys
    {
      public partial class AddToCart : System.Web.UI.Page
      {
        protected void Page_Load(object sender, EventArgs e)
        {
          string rawId = Request.QueryString["ProductID"];
          int productId;
          if (!String.IsNullOrEmpty(rawId) && int.TryParse(rawId, out productId))
          {
            using (ShoppingCartActions usersShoppingCart = new ShoppingCartActions())
            {
              usersShoppingCart.AddToCart(Convert.ToInt16(rawId));
            }
    
          }
          else
          {
            Debug.Fail("ERROR : We should never get to AddToCart.aspx without a ProductId.");
            throw new Exception("ERROR : It is illegal to load AddToCart.aspx without setting a ProductId.");
          }
          Response.Redirect("ShoppingCart.aspx");
        }
      }
    }
    

AddToCart.aspx 페이지가 로드되면 제품이 ID 쿼리 문자열에서 검색됩니다. 다음으로, 쇼핑 카트 클래스의 instance 만들어지고 이 자습서의 앞부분에서 추가한 AddToCart 메서드를 호출하는 데 사용됩니다. ShoppingCartActions.cs 파일에 포함된 메서드에는 AddToCart 선택한 제품을 쇼핑 카트에 추가하거나 선택한 제품의 제품 수량을 증가하는 논리가 포함됩니다. 제품이 쇼핑 카트에 추가되지 않은 경우 제품이 데이터베이스 테이블에 추가 CartItem 됩니다. 제품이 이미 쇼핑 카트에 추가되고 사용자가 동일한 제품의 추가 항목을 추가하는 경우 제품 수량이 테이블에서 증가합니다 CartItem . 마지막으로, 이 페이지는 다음 단계에서 추가할 ShoppingCart.aspx 페이지로 다시 리디렉션됩니다. 여기서 사용자는 카트에 업데이트된 항목 목록을 볼 수 있습니다.

앞서 언급했듯이 사용자는 특정 사용자 ID 와 연결된 제품을 식별하는 데 사용됩니다. 사용자가 ID 장바구니에 CartItem 제품을 추가할 때마다 테이블의 행에 추가됩니다.

쇼핑 카트 UI 만들기

ShoppingCart.aspx 페이지에는 사용자가 장바구니에 추가한 제품이 표시됩니다. 또한 쇼핑 카트에서 항목을 추가, 제거 및 업데이트하는 기능도 제공합니다.

  1. 솔루션 탐색기WingtipToys를 마우스 오른쪽 단추로 클릭하고 추가 ->새 항목을 클릭합니다.
    새 항목 추가 대화 상자가 표시됩니다.

  2. 마스터 페이지를 사용하여 웹 양식을 선택하여 master 페이지를 포함하는 새 페이지(웹 양식)를 추가합니다. 새 페이지의 이름을 ShoppingCart.aspx로 지정합니다.

  3. Site.Master를 선택하여 새로 만든 .aspx 페이지에 master 페이지를 연결합니다.

  4. ShoppingCart.aspx 페이지에서 기존 태그를 다음 태그로 바꿉 있습니다.

    <%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="ShoppingCart.aspx.cs" Inherits="WingtipToys.ShoppingCart" %>
    <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
        <div id="ShoppingCartTitle" runat="server" class="ContentHead"><h1>Shopping Cart</h1></div>
        <asp:GridView ID="CartList" runat="server" AutoGenerateColumns="False" ShowFooter="True" GridLines="Vertical" CellPadding="4"
            ItemType="WingtipToys.Models.CartItem" SelectMethod="GetShoppingCartItems" 
            CssClass="table table-striped table-bordered" >   
            <Columns>
            <asp:BoundField DataField="ProductID" HeaderText="ID" SortExpression="ProductID" />        
            <asp:BoundField DataField="Product.ProductName" HeaderText="Name" />        
            <asp:BoundField DataField="Product.UnitPrice" HeaderText="Price (each)" DataFormatString="{0:c}"/>     
            <asp:TemplateField   HeaderText="Quantity">            
                    <ItemTemplate>
                        <asp:TextBox ID="PurchaseQuantity" Width="40" runat="server" Text="<%#: Item.Quantity %>"></asp:TextBox> 
                    </ItemTemplate>        
            </asp:TemplateField>    
            <asp:TemplateField HeaderText="Item Total">            
                    <ItemTemplate>
                        <%#: String.Format("{0:c}", ((Convert.ToDouble(Item.Quantity)) *  Convert.ToDouble(Item.Product.UnitPrice)))%>
                    </ItemTemplate>        
            </asp:TemplateField> 
            <asp:TemplateField HeaderText="Remove Item">            
                    <ItemTemplate>
                        <asp:CheckBox id="Remove" runat="server"></asp:CheckBox>
                    </ItemTemplate>        
            </asp:TemplateField>    
            </Columns>    
        </asp:GridView>
        <div>
            <p></p>
            <strong>
                <asp:Label ID="LabelTotalText" runat="server" Text="Order Total: "></asp:Label>
                <asp:Label ID="lblTotal" runat="server" EnableViewState="false"></asp:Label>
            </strong> 
        </div>
        <br />
    </asp:Content>
    

ShoppingCart.aspx 페이지에는 라는 CartListGridView 컨트롤이 포함되어 있습니다. 이 컨트롤은 모델 바인딩을 사용하여 데이터베이스의 쇼핑 카트 데이터를 GridView 컨트롤에 바인딩합니다. GridView 컨트롤의 속성을 설정 ItemType 하면 컨트롤의 태그에서 데이터 바인딩 식을 Item 사용할 수 있으며 컨트롤이 강력한 형식이 됩니다. 이 자습서 시리즈의 앞부분에서 설명한 대로 IntelliSense를 사용하여 개체의 Item 세부 정보를 선택할 수 있습니다. 모델 바인딩을 사용하여 데이터를 선택하도록 데이터 컨트롤을 구성하려면 컨트롤의 속성을 설정합니다 SelectMethod . 위의 태그에서 개체 목록을 CartItem 반환하는 GetShoppingCartItems 메서드를 사용하도록 를 설정합니다SelectMethod. GridView 데이터 컨트롤은 페이지 수명 주기에서 적절한 시간에 메서드를 호출하고 반환된 데이터를 자동으로 바인딩합니다. 메서드는 GetShoppingCartItems 계속 추가해야 합니다.

장바구니 항목 검색

다음으로 , ShoppingCart.aspx.cs 코드 숨김에 코드를 추가하여 쇼핑 카트 UI를 검색하고 채웁니다.

  1. 솔루션 탐색기ShoppingCart.aspx 페이지를 마우스 오른쪽 단추로 클릭한 다음 코드 보기를 클릭합니다. 편집기에서 ShoppingCart.aspx.cs 코드 숨김 파일이 열립니다.

  2. 기존 코드를 다음으로 바꿉니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using WingtipToys.Models;
    using WingtipToys.Logic;
    
    namespace WingtipToys
    {
      public partial class ShoppingCart : System.Web.UI.Page
      {
        protected void Page_Load(object sender, EventArgs e)
        {
    
        }
    
        public List<CartItem> GetShoppingCartItems()
        {
          ShoppingCartActions actions = new ShoppingCartActions();
          return actions.GetCartItems();
        }
      }
    }
    

위에서 설명한 대로 데이터 컨트롤은 GridView 페이지 수명 주기에서 적절한 시간에 메서드를 호출 GetShoppingCartItems 하고 반환된 데이터를 자동으로 바인딩합니다. 메서드는 GetShoppingCartItems 개체의 ShoppingCartActions instance 만듭니다. 그런 다음 코드는 해당 instance 사용하여 메서드를 호출 GetCartItems 하여 카트의 항목을 반환합니다.

쇼핑 카트에 제품 추가

ProductList.aspx 또는 ProductDetails.aspx 페이지가 표시되면 사용자는 링크를 사용하여 장바구니에 제품을 추가할 수 있습니다. 링크를 클릭하면 애플리케이션이 AddToCart.aspx라는 처리 페이지로 이동합니다. AddToCart.aspx 페이지는 이 자습서의 AddToCart 앞부분에서 추가한 클래스의 ShoppingCart 메서드를 호출합니다.

이제 ProductList.aspx 페이지와 ProductDetails.aspx 페이지에 카트에 추가 링크를 추가합니다. 이 링크에는 데이터베이스에서 검색되는 제품이 ID 포함됩니다.

  1. 솔루션 탐색기ProductList.aspx라는 페이지를 찾아 엽니다.

  2. 전체 페이지가 다음과 같이 표시되도록 ProductList.aspx 페이지에 노란색으로 강조 표시된 태그를 추가합니다.

    <%@ Page Title="Products" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" 
             CodeBehind="ProductList.aspx.cs" Inherits="WingtipToys.ProductList" %>
    <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
        <section>
            <div>
                <hgroup>
                    <h2><%: Page.Title %></h2>
                </hgroup>
    
                <asp:ListView ID="productList" runat="server" 
                    DataKeyNames="ProductID" GroupItemCount="4"
                    ItemType="WingtipToys.Models.Product" SelectMethod="GetProducts">
                    <EmptyDataTemplate>
                        <table runat="server">
                            <tr>
                                <td>No data was returned.</td>
                            </tr>
                        </table>
                    </EmptyDataTemplate>
                    <EmptyItemTemplate>
                        <td runat="server" />
                    </EmptyItemTemplate>
                    <GroupTemplate>
                        <tr id="itemPlaceholderContainer" runat="server">
                            <td id="itemPlaceholder" runat="server"></td>
                        </tr>
                    </GroupTemplate>
                    <ItemTemplate>
                        <td runat="server">
                            <table>
                                <tr>
                                    <td>
                                        <a href="ProductDetails.aspx?productID=<%#:Item.ProductID%>">
                                            <img src="/Catalog/Images/Thumbs/<%#:Item.ImagePath%>"
                                                width="100" height="75" style="border: solid" /></a>
                                    </td>
                                </tr>
                                <tr>
                                    <td>
                                        <a href="ProductDetails.aspx?productID=<%#:Item.ProductID%>">
                                            <span>
                                                <%#:Item.ProductName%>
                                            </span>
                                        </a>
                                        <br />
                                        <span>
                                            <b>Price: </b><%#:String.Format("{0:c}", Item.UnitPrice)%>
                                        </span>
                                        <br />
                                        <a href="/AddToCart.aspx?productID=<%#:Item.ProductID %>">               
                                            <span class="ProductListItem">
                                                <b>Add To Cart<b>
                                            </span>           
                                        </a>
                                    </td>
                                </tr>
                                <tr>
                                    <td>&nbsp;</td>
                                </tr>
                            </table>
                            </p>
                        </td>
                    </ItemTemplate>
                    <LayoutTemplate>
                        <table runat="server" style="width:100%;">
                            <tbody>
                                <tr runat="server">
                                    <td runat="server">
                                        <table id="groupPlaceholderContainer" runat="server" style="width:100%">
                                            <tr id="groupPlaceholder" runat="server"></tr>
                                        </table>
                                    </td>
                                </tr>
                                <tr runat="server">
                                    <td runat="server"></td>
                                </tr>
                                <tr></tr>
                            </tbody>
                        </table>
                    </LayoutTemplate>
                </asp:ListView>
            </div>
        </section>
    </asp:Content>
    

쇼핑 카트 테스트

애플리케이션을 실행하여 장바구니에 제품을 추가하는 방법을 확인합니다.

  1. F5 키를 눌러 애플리케이션을 실행합니다.
    프로젝트가 데이터베이스를 다시 만들면 브라우저가 열리고 Default.aspx 페이지가 표시됩니다.

  2. 범주 탐색 메뉴에서 자동차를 선택합니다.
    ProductList.aspx 페이지에는 "자동차" 범주에 포함된 제품만 표시됩니다.

    쇼핑 카트 - 자동차

  3. 나열된 첫 번째 제품(컨버터블 자동차) 옆에 있는 카트에 추가 링크를 클릭합니다.
    쇼핑 카트의 선택 항목을 보여 주는 ShoppingCart.aspx 페이지가 표시됩니다.

    쇼핑 카트 - 카트

  4. 범주 탐색 메뉴에서 평면 을 선택하여 추가 제품을 봅니다.

  5. 나열된 첫 번째 제품 옆에 있는 카트에 추가 링크를 클릭합니다.
    ShoppingCart.aspx 페이지는 추가 항목과 함께 표시됩니다.

  6. 브라우저를 닫습니다.

주문 합계 계산 및 표시

쇼핑 카트에 제품을 추가하는 것 외에도 클래스에 메서드를 GetTotalShoppingCart 추가하고 쇼핑 카트 페이지에 총 주문 금액을 표시합니다.

  1. 솔루션 탐색기Logic 폴더에서 ShoppingCartActions.cs 파일을 엽니다.

  2. 클래스가 다음과 같이 표시되도록 노란색으로 ShoppingCart 강조 표시된 다음 GetTotal 메서드를 클래스에 추가합니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using WingtipToys.Models;
    
    namespace WingtipToys.Logic
    {
      public class ShoppingCartActions : IDisposable
      {
        public string ShoppingCartId { get; set; }
    
        private ProductContext _db = new ProductContext();
    
        public const string CartSessionKey = "CartId";
    
        public void AddToCart(int id)
        {
          // Retrieve the product from the database.           
          ShoppingCartId = GetCartId();
    
          var cartItem = _db.ShoppingCartItems.SingleOrDefault(
              c => c.CartId == ShoppingCartId
              && c.ProductId == id);
          if (cartItem == null)
          {
            // Create a new cart item if no cart item exists.                 
            cartItem = new CartItem
            {
              ItemId = Guid.NewGuid().ToString(),
              ProductId = id,
              CartId = ShoppingCartId,
              Product = _db.Products.SingleOrDefault(
               p => p.ProductID == id),
              Quantity = 1,
              DateCreated = DateTime.Now
            };
    
            _db.ShoppingCartItems.Add(cartItem);
          }
          else
          {
            // If the item does exist in the cart,                  
            // then add one to the quantity.                 
            cartItem.Quantity++;
          }
          _db.SaveChanges();
        }
    
        public void Dispose()
        {
          if (_db != null)
          {
            _db.Dispose();
            _db = null;
          }
        }
    
        public string GetCartId()
        {
          if (HttpContext.Current.Session[CartSessionKey] == null)
          {
            if (!string.IsNullOrWhiteSpace(HttpContext.Current.User.Identity.Name))
            {
              HttpContext.Current.Session[CartSessionKey] = HttpContext.Current.User.Identity.Name;
            }
            else
            {
              // Generate a new random GUID using System.Guid class.     
              Guid tempCartId = Guid.NewGuid();
              HttpContext.Current.Session[CartSessionKey] = tempCartId.ToString();
            }
          }
          return HttpContext.Current.Session[CartSessionKey].ToString();
        }
    
        public List<CartItem> GetCartItems()
        {
          ShoppingCartId = GetCartId();
    
          return _db.ShoppingCartItems.Where(
              c => c.CartId == ShoppingCartId).ToList();
        }
    
        public decimal GetTotal()
        {
          ShoppingCartId = GetCartId();
          // Multiply product price by quantity of that product to get        
          // the current price for each of those products in the cart.  
          // Sum all product price totals to get the cart total.   
          decimal? total = decimal.Zero;
          total = (decimal?)(from cartItems in _db.ShoppingCartItems
                             where cartItems.CartId == ShoppingCartId
                             select (int?)cartItems.Quantity *
                             cartItems.Product.UnitPrice).Sum();
          return total ?? decimal.Zero;
        }
      }
    }
    

먼저 메서드는 GetTotal 사용자의 쇼핑 카트 ID를 가져옵니다. 그런 다음, 메서드는 카트에 나열된 각 제품의 제품 수량에 제품 가격을 곱하여 카트 합계를 가져옵니다.

참고

위의 코드는 nullable 형식 "int?"을 사용합니다. Nullable 형식은 기본 형식의 모든 값을 나타낼 수 있으며 null 값으로도 나타낼 수 있습니다. 자세한 내용은 Nullable 형식 사용을 참조하세요.

쇼핑 카트 디스플레이 수정

다음으로 , ShoppingCart.aspx 페이지의 코드를 수정하여 메서드를 호출 GetTotal 하고 페이지가 로드되면 해당 합계를 ShoppingCart.aspx 페이지에 표시합니다.

  1. 솔루션 탐색기ShoppingCart.aspx 페이지를 마우스 오른쪽 단추로 클릭하고 코드 보기를 선택합니다.

  2. ShoppingCart.aspx.cs 파일에서 노란색으로 강조 표시된 다음 코드를 추가하여 처리기를 업데이트 Page_Load 합니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using WingtipToys.Models;
    using WingtipToys.Logic;
    
    namespace WingtipToys
    {
      public partial class ShoppingCart : System.Web.UI.Page
      {
        protected void Page_Load(object sender, EventArgs e)
        {
          using (ShoppingCartActions usersShoppingCart = new ShoppingCartActions())
          {
            decimal cartTotal = 0;
            cartTotal = usersShoppingCart.GetTotal();
            if (cartTotal > 0)
            {
              // Display Total.
              lblTotal.Text = String.Format("{0:c}", cartTotal);
            }
            else
            {
              LabelTotalText.Text = "";
              lblTotal.Text = "";
              ShoppingCartTitle.InnerText = "Shopping Cart is Empty";
            }
          }
        }
    
        public List<CartItem> GetShoppingCartItems()
        {
          ShoppingCartActions actions = new ShoppingCartActions();
          return actions.GetCartItems();
        }
      }
    }
    

ShoppingCart.aspx 페이지가 로드되면 쇼핑 카트 개체를 로드한 다음 클래스의 메서드를 호출하여 쇼핑 카트 합계를 GetTotalShoppingCart 검색합니다. 쇼핑 카트가 비어 있으면 해당 효과에 대한 메시지가 표시됩니다.

쇼핑 카트 총계 테스트

지금 애플리케이션을 실행하여 쇼핑 카트에 제품을 추가할 수 있는 방법뿐만 아니라 쇼핑 카트 합계를 볼 수 있는 방법을 확인합니다.

  1. F5 키를 눌러 애플리케이션을 실행합니다.
    브라우저가 열리고 Default.aspx 페이지가 표시됩니다.

  2. 범주 탐색 메뉴에서 자동차를 선택합니다.

  3. 첫 번째 제품 옆에 있는 카트에 추가 링크를 클릭합니다.
    주문 합계와 함께 ShoppingCart.aspx 페이지가 표시됩니다.

    쇼핑 카트 - 카트 합계

  4. 카트에 다른 제품(예: 평면)을 추가합니다.

  5. ShoppingCart.aspx 페이지에는 추가한 모든 제품에 대한 업데이트된 합계가 표시됩니다.

    쇼핑 카트 - 여러 제품

  6. 브라우저 창을 닫아 실행 중인 앱을 중지합니다.

쇼핑 카트에 업데이트 및 체크 아웃 단추 추가

사용자가 쇼핑 카트를 수정할 수 있도록 하기 위해 업데이트 단추와 체크 아웃 단추를 쇼핑 카트 페이지에 추가합니다. 체크 아웃 단추는 이 자습서 시리즈의 뒷부분까지 사용되지 않습니다.

  1. 솔루션 탐색기 웹 애플리케이션 프로젝트의 루트에서 ShoppingCart.aspx 페이지를 엽니다.

  2. 업데이트 단추와 체크 아웃 단추를 ShoppingCart.aspx 페이지에 추가하려면 다음 코드와 같이 노란색으로 강조 표시된 태그를 기존 태그에 추가합니다.

    <%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="ShoppingCart.aspx.cs" Inherits="WingtipToys.ShoppingCart" %>
    <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
        <div id="ShoppingCartTitle" runat="server" class="ContentHead"><h1>Shopping Cart</h1></div>
        <asp:GridView ID="CartList" runat="server" AutoGenerateColumns="False" ShowFooter="True" GridLines="Vertical" CellPadding="4"
            ItemType="WingtipToys.Models.CartItem" SelectMethod="GetShoppingCartItems"  
            CssClass="table table-striped table-bordered" >   
            <Columns>
            <asp:BoundField DataField="ProductID" HeaderText="ID" SortExpression="ProductID" />        
            <asp:BoundField DataField="Product.ProductName" HeaderText="Name" />        
            <asp:BoundField DataField="Product.UnitPrice" HeaderText="Price (each)" DataFormatString="{0:c}"/>     
            <asp:TemplateField   HeaderText="Quantity">            
                    <ItemTemplate>
                        <asp:TextBox ID="PurchaseQuantity" Width="40" runat="server" Text="<%#: Item.Quantity %>"></asp:TextBox> 
                    </ItemTemplate>        
            </asp:TemplateField>    
            <asp:TemplateField HeaderText="Item Total">            
                    <ItemTemplate>
                        <%#: String.Format("{0:c}", ((Convert.ToDouble(Item.Quantity)) *  Convert.ToDouble(Item.Product.UnitPrice)))%>
                    </ItemTemplate>        
            </asp:TemplateField> 
            <asp:TemplateField HeaderText="Remove Item">            
                    <ItemTemplate>
                        <asp:CheckBox id="Remove" runat="server"></asp:CheckBox>
                    </ItemTemplate>        
            </asp:TemplateField>    
            </Columns>    
        </asp:GridView>
        <div>
            <p></p>
            <strong>
                <asp:Label ID="LabelTotalText" runat="server" Text="Order Total: "></asp:Label>
                <asp:Label ID="lblTotal" runat="server" EnableViewState="false"></asp:Label>
            </strong> 
        </div>
      <br />
        <table> 
        <tr>
          <td>
            <asp:Button ID="UpdateBtn" runat="server" Text="Update" OnClick="UpdateBtn_Click" />
          </td>
          <td>
            <!--Checkout Placeholder -->
          </td>
        </tr>
        </table>
    </asp:Content>
    

사용자가 업데이트 단추를 UpdateBtn_Click 클릭하면 이벤트 처리기가 호출됩니다. 이 이벤트 처리기는 다음 단계에서 추가할 코드를 호출합니다.

다음으로, ShoppingCart.aspx.cs 파일에 포함된 코드를 업데이트하여 카트 항목을 반복하고 및 UpdateItem 메서드를 호출할 RemoveItem 수 있습니다.

  1. 솔루션 탐색기 웹 애플리케이션 프로젝트의 루트에서 ShoppingCart.aspx.cs 파일을 엽니다.

  2. 노란색으로 강조 표시된 다음 코드 섹션을 ShoppingCart.aspx.cs 파일에 추가합니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using WingtipToys.Models;
    using WingtipToys.Logic;
    using System.Collections.Specialized;
    using System.Collections;
    using System.Web.ModelBinding;
    
    namespace WingtipToys
    {
      public partial class ShoppingCart : System.Web.UI.Page
      {
        protected void Page_Load(object sender, EventArgs e)
        {
          using (ShoppingCartActions usersShoppingCart = new ShoppingCartActions())
          {
            decimal cartTotal = 0;
            cartTotal = usersShoppingCart.GetTotal();
            if (cartTotal > 0)
            {
              // Display Total.
              lblTotal.Text = String.Format("{0:c}", cartTotal);
            }
            else
            {
              LabelTotalText.Text = "";
              lblTotal.Text = "";
              ShoppingCartTitle.InnerText = "Shopping Cart is Empty";
              UpdateBtn.Visible = false;
            }
          }
        }
    
        public List<CartItem> GetShoppingCartItems()
        {
          ShoppingCartActions actions = new ShoppingCartActions();
          return actions.GetCartItems();
        }
    
        public List<CartItem> UpdateCartItems()
        {
          using (ShoppingCartActions usersShoppingCart = new ShoppingCartActions())
          {
            String cartId = usersShoppingCart.GetCartId();
    
            ShoppingCartActions.ShoppingCartUpdates[] cartUpdates = new ShoppingCartActions.ShoppingCartUpdates[CartList.Rows.Count];
            for (int i = 0; i < CartList.Rows.Count; i++)
            {
              IOrderedDictionary rowValues = new OrderedDictionary();
              rowValues = GetValues(CartList.Rows[i]);
              cartUpdates[i].ProductId = Convert.ToInt32(rowValues["ProductID"]);
    
              CheckBox cbRemove = new CheckBox();
              cbRemove = (CheckBox)CartList.Rows[i].FindControl("Remove");
              cartUpdates[i].RemoveItem = cbRemove.Checked;
    
              TextBox quantityTextBox = new TextBox();
              quantityTextBox = (TextBox)CartList.Rows[i].FindControl("PurchaseQuantity");
              cartUpdates[i].PurchaseQuantity = Convert.ToInt16(quantityTextBox.Text.ToString());
            }
            usersShoppingCart.UpdateShoppingCartDatabase(cartId, cartUpdates);
            CartList.DataBind();
            lblTotal.Text = String.Format("{0:c}", usersShoppingCart.GetTotal());
            return usersShoppingCart.GetCartItems();
          }
        }
    
        public static IOrderedDictionary GetValues(GridViewRow row)
        {
          IOrderedDictionary values = new OrderedDictionary();
          foreach (DataControlFieldCell cell in row.Cells)
          {
            if (cell.Visible)
            {
              // Extract values from the cell.
              cell.ContainingField.ExtractValuesFromCell(values, cell, row.RowState, true);
            }
          }
          return values;
        }
    
        protected void UpdateBtn_Click(object sender, EventArgs e)
        {
          UpdateCartItems();
        }
      }
    }
    

사용자가 ShoppingCart.aspx 페이지에서 업데이트 단추를 클릭하면 UpdateCartItems 메서드가 호출됩니다. UpdateCartItems 메서드는 쇼핑 카트의 각 항목에 대해 업데이트된 값을 가져옵니다. 그런 다음 UpdateCartItems 메서드는 메서드를 호출 UpdateShoppingCartDatabase 하여(다음 단계에서 추가 및 설명) 쇼핑 카트에서 항목을 추가하거나 제거합니다. 데이터베이스가 쇼핑 카트에 대한 업데이트를 반영하도록 업데이트되면 GridView 컨트롤은 GridView에 대한 메서드를 호출 DataBind 하여 쇼핑 카트 페이지에서 업데이트됩니다. 또한 쇼핑 카트 페이지의 총 주문 금액이 업데이트된 항목 목록을 반영하도록 업데이트됩니다.

쇼핑 카트 항목 업데이트 및 제거

ShoppingCart.aspx 페이지에서 항목의 수량을 업데이트하고 항목을 제거하기 위해 컨트롤이 추가된 것을 볼 수 있습니다. 이제 이러한 컨트롤이 작동할 코드를 추가합니다.

  1. 솔루션 탐색기Logic 폴더에서 ShoppingCartActions.cs 파일을 엽니다.

  2. 노란색으로 강조 표시된 다음 코드를 ShoppingCartActions.cs 클래스 파일에 추가합니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using WingtipToys.Models;
    
    namespace WingtipToys.Logic
    {
      public class ShoppingCartActions : IDisposable
      {
        public string ShoppingCartId { get; set; }
    
        private ProductContext _db = new ProductContext();
    
        public const string CartSessionKey = "CartId";
    
        public void AddToCart(int id)
        {
          // Retrieve the product from the database.           
          ShoppingCartId = GetCartId();
    
          var cartItem = _db.ShoppingCartItems.SingleOrDefault(
              c => c.CartId == ShoppingCartId
              && c.ProductId == id);
          if (cartItem == null)
          {
            // Create a new cart item if no cart item exists.                 
            cartItem = new CartItem
            {
              ItemId = Guid.NewGuid().ToString(),
              ProductId = id,
              CartId = ShoppingCartId,
              Product = _db.Products.SingleOrDefault(
               p => p.ProductID == id),
              Quantity = 1,
              DateCreated = DateTime.Now
            };
    
            _db.ShoppingCartItems.Add(cartItem);
          }
          else
          {
            // If the item does exist in the cart,                  
            // then add one to the quantity.                 
            cartItem.Quantity++;
          }
          _db.SaveChanges();
        }
    
        public void Dispose()
        {
          if (_db != null)
          {
            _db.Dispose();
            _db = null;
          }
        }
    
        public string GetCartId()
        {
          if (HttpContext.Current.Session[CartSessionKey] == null)
          {
            if (!string.IsNullOrWhiteSpace(HttpContext.Current.User.Identity.Name))
            {
              HttpContext.Current.Session[CartSessionKey] = HttpContext.Current.User.Identity.Name;
            }
            else
            {
              // Generate a new random GUID using System.Guid class.     
              Guid tempCartId = Guid.NewGuid();
              HttpContext.Current.Session[CartSessionKey] = tempCartId.ToString();
            }
          }
          return HttpContext.Current.Session[CartSessionKey].ToString();
        }
    
        public List<CartItem> GetCartItems()
        {
          ShoppingCartId = GetCartId();
    
          return _db.ShoppingCartItems.Where(
              c => c.CartId == ShoppingCartId).ToList();
        }
    
        public decimal GetTotal()
        {
          ShoppingCartId = GetCartId();
          // Multiply product price by quantity of that product to get        
          // the current price for each of those products in the cart.  
          // Sum all product price totals to get the cart total.   
          decimal? total = decimal.Zero;
          total = (decimal?)(from cartItems in _db.ShoppingCartItems
                             where cartItems.CartId == ShoppingCartId
                             select (int?)cartItems.Quantity *
                             cartItems.Product.UnitPrice).Sum();
          return total ?? decimal.Zero;
        }
    
        public ShoppingCartActions GetCart(HttpContext context)
        {
          using (var cart = new ShoppingCartActions())
          {
            cart.ShoppingCartId = cart.GetCartId();
            return cart;
          }
        }
    
        public void UpdateShoppingCartDatabase(String cartId, ShoppingCartUpdates[] CartItemUpdates)
        {
          using (var db = new WingtipToys.Models.ProductContext())
          {
            try
            {
              int CartItemCount = CartItemUpdates.Count();
              List<CartItem> myCart = GetCartItems();
              foreach (var cartItem in myCart)
              {
                // Iterate through all rows within shopping cart list
                for (int i = 0; i < CartItemCount; i++)
                {
                  if (cartItem.Product.ProductID == CartItemUpdates[i].ProductId)
                  {
                    if (CartItemUpdates[i].PurchaseQuantity < 1 || CartItemUpdates[i].RemoveItem == true)
                    {
                      RemoveItem(cartId, cartItem.ProductId);
                    }
                    else
                    {
                      UpdateItem(cartId, cartItem.ProductId, CartItemUpdates[i].PurchaseQuantity);
                    }
                  }
                }
              }
            }
            catch (Exception exp)
            {
              throw new Exception("ERROR: Unable to Update Cart Database - " + exp.Message.ToString(), exp);
            }
          }
        }
    
        public void RemoveItem(string removeCartID, int removeProductID)
        {
          using (var _db = new WingtipToys.Models.ProductContext())
          {
            try
            {
              var myItem = (from c in _db.ShoppingCartItems where c.CartId == removeCartID && c.Product.ProductID == removeProductID select c).FirstOrDefault();
              if (myItem != null)
              {
                // Remove Item.
                _db.ShoppingCartItems.Remove(myItem);
                _db.SaveChanges();
              }
            }
            catch (Exception exp)
            {
              throw new Exception("ERROR: Unable to Remove Cart Item - " + exp.Message.ToString(), exp);
            }
          }
        }
    
        public void UpdateItem(string updateCartID, int updateProductID, int quantity)
        {
          using (var _db = new WingtipToys.Models.ProductContext())
          {
            try
            {
              var myItem = (from c in _db.ShoppingCartItems where c.CartId == updateCartID && c.Product.ProductID == updateProductID select c).FirstOrDefault();
              if (myItem != null)
              {
                myItem.Quantity = quantity;
                _db.SaveChanges();
              }
            }
            catch (Exception exp)
            {
              throw new Exception("ERROR: Unable to Update Cart Item - " + exp.Message.ToString(), exp);
            }
          }
        }
    
        public void EmptyCart()
        {
          ShoppingCartId = GetCartId();
          var cartItems = _db.ShoppingCartItems.Where(
              c => c.CartId == ShoppingCartId);
          foreach (var cartItem in cartItems)
          {
            _db.ShoppingCartItems.Remove(cartItem);
          }
          // Save changes.             
          _db.SaveChanges();
        }
    
        public int GetCount()
        {
          ShoppingCartId = GetCartId();
    
          // Get the count of each item in the cart and sum them up          
          int? count = (from cartItems in _db.ShoppingCartItems
                        where cartItems.CartId == ShoppingCartId
                        select (int?)cartItems.Quantity).Sum();
          // Return 0 if all entries are null         
          return count ?? 0;
        }
    
        public struct ShoppingCartUpdates
        {
          public int ProductId;
          public int PurchaseQuantity;
          public bool RemoveItem;
        }
      }
    }
    

UpdateShoppingCartDatabaseShoppingCart.aspx.cs 페이지의 메서드에서 UpdateCartItems 호출되는 메서드에는 쇼핑 카트에서 항목을 업데이트하거나 제거하는 논리가 포함되어 있습니다. 메서드는 UpdateShoppingCartDatabase 쇼핑 카트 목록 내의 모든 행을 반복합니다. 장바구니 항목이 제거된 것으로 표시되었거나 수량이 1보다 작은 경우 메서드가 RemoveItem 호출됩니다. 그렇지 않으면 메서드가 호출되면 쇼핑 카트 항목에서 UpdateItem 업데이트를 확인합니다. 쇼핑 카트 항목이 제거되거나 업데이트되면 데이터베이스 변경 내용이 저장됩니다.

구조는 ShoppingCartUpdates 모든 쇼핑 카트 항목을 보유하는 데 사용됩니다. 메서드는 UpdateShoppingCartDatabaseShoppingCartUpdates 구조를 사용하여 항목을 업데이트하거나 제거해야 하는지 여부를 확인합니다.

다음 자습서에서는 메서드를 EmptyCart 사용하여 제품을 구매한 후 쇼핑 카트를 지웁니다. 하지만 지금은 방금 ShoppingCartActions.cs 파일에 추가한 메서드를 사용하여 GetCount 쇼핑 카트에 있는 항목 수를 확인합니다.

쇼핑 카트 카운터 추가

사용자가 쇼핑 카트의 총 항목 수를 볼 수 있도록 하려면 Site.Master 페이지에 카운터를 추가합니다. 이 카운터는 쇼핑 카트에 대한 링크로도 작동합니다.

  1. 솔루션 탐색기Site.Master 페이지를 엽니다.

  2. 다음과 같이 표시되도록 탐색 섹션에 노란색으로 표시된 대로 쇼핑 카트 카운터 링크를 추가하여 태그를 수정합니다.

    <ul class="nav navbar-nav">
          <li><a runat="server" href="~/">Home</a></li>
          <li><a runat="server" href="~/About">About</a></li>
          <li><a runat="server" href="~/Contact">Contact</a></li>
          <li><a runat="server" href="~/ProductList">Products</a></li>
          <li><a runat="server" href="~/ShoppingCart" ID="cartCount">&nbsp;</a></li>
      </ul>
    
  3. 다음으로 다음과 같이 노란색으로 강조 표시된 코드를 추가하여 Site.Master.cs 파일의 코드 숨김을 업데이트합니다.

    using System;
    using System.Collections.Generic;
    using System.Security.Claims;
    using System.Security.Principal;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Linq;
    using WingtipToys.Models;
    using WingtipToys.Logic;
    
    namespace WingtipToys
    {
        public partial class SiteMaster : MasterPage
        {
            private const string AntiXsrfTokenKey = "__AntiXsrfToken";
            private const string AntiXsrfUserNameKey = "__AntiXsrfUserName";
            private string _antiXsrfTokenValue;
    
            protected void Page_Init(object sender, EventArgs e)
            {
                // The code below helps to protect against XSRF attacks
                var requestCookie = Request.Cookies[AntiXsrfTokenKey];
                Guid requestCookieGuidValue;
                if (requestCookie != null && Guid.TryParse(requestCookie.Value, out requestCookieGuidValue))
                {
                    // Use the Anti-XSRF token from the cookie
                    _antiXsrfTokenValue = requestCookie.Value;
                    Page.ViewStateUserKey = _antiXsrfTokenValue;
                }
                else
                {
                    // Generate a new Anti-XSRF token and save to the cookie
                    _antiXsrfTokenValue = Guid.NewGuid().ToString("N");
                    Page.ViewStateUserKey = _antiXsrfTokenValue;
    
                    var responseCookie = new HttpCookie(AntiXsrfTokenKey)
                    {
                        HttpOnly = true,
                        Value = _antiXsrfTokenValue
                    };
                    if (FormsAuthentication.RequireSSL && Request.IsSecureConnection)
                    {
                        responseCookie.Secure = true;
                    }
                    Response.Cookies.Set(responseCookie);
                }
    
                Page.PreLoad += master_Page_PreLoad;
            }
    
            protected void master_Page_PreLoad(object sender, EventArgs e)
            {
                if (!IsPostBack)
                {
                    // Set Anti-XSRF token
                    ViewState[AntiXsrfTokenKey] = Page.ViewStateUserKey;
                    ViewState[AntiXsrfUserNameKey] = Context.User.Identity.Name ?? String.Empty;
                }
                else
                {
                    // Validate the Anti-XSRF token
                    if ((string)ViewState[AntiXsrfTokenKey] != _antiXsrfTokenValue
                        || (string)ViewState[AntiXsrfUserNameKey] != (Context.User.Identity.Name ?? String.Empty))
                    {
                        throw new InvalidOperationException("Validation of Anti-XSRF token failed.");
                    }
                }
            }
    
            protected void Page_Load(object sender, EventArgs e)
            {
    
            }
    
            protected void Page_PreRender(object sender, EventArgs e)
            {
              using (ShoppingCartActions usersShoppingCart = new ShoppingCartActions())
              {
                string cartStr = string.Format("Cart ({0})", usersShoppingCart.GetCount());
                cartCount.InnerText = cartStr;
              }
            }
    
            public IQueryable<Category> GetCategories()
            {
              var _db = new WingtipToys.Models.ProductContext();
              IQueryable<Category> query = _db.Categories;
              return query;
            }
    
            protected void Unnamed_LoggingOut(object sender, LoginCancelEventArgs e)
            {
                Context.GetOwinContext().Authentication.SignOut();
            }
        }
    }
    

페이지가 HTML Page_PreRender 로 렌더링되기 전에 이벤트가 발생합니다. 처리기 Page_PreRender 에서 쇼핑 카트의 총 수는 메서드를 호출 GetCount 하여 결정됩니다. 반환된 값은 Site.Master 페이지의 태그에 포함된 범위에 추가 cartCount 됩니다. <span> 태그를 사용하면 내부 요소를 제대로 렌더링할 수 있습니다. 사이트의 페이지가 표시되면 쇼핑 카트 합계가 표시됩니다. 사용자는 쇼핑 카트 합계를 클릭하여 장바구니를 표시할 수도 있습니다.

완성된 쇼핑 카트 테스트

이제 애플리케이션을 실행하여 쇼핑 카트에서 항목을 추가, 삭제 및 업데이트하는 방법을 확인할 수 있습니다. 장바구니 합계는 장바구니에 있는 모든 항목의 총 비용을 반영합니다.

  1. F5 키를 눌러 애플리케이션을 실행합니다.
    브라우저가 열리고 Default.aspx 페이지가 표시됩니다.

  2. 범주 탐색 메뉴에서 자동차를 선택합니다.

  3. 첫 번째 제품 옆에 있는 카트에 추가 링크를 클릭합니다.
    주문 합계와 함께 ShoppingCart.aspx 페이지가 표시됩니다.

  4. 범주 탐색 메뉴에서 평면 을 선택합니다.

  5. 첫 번째 제품 옆에 있는 카트에 추가 링크를 클릭합니다.

  6. 쇼핑 카트에서 첫 번째 항목의 수량을 3으로 설정하고 두 번째 항목의 항목 검사 제거 상자를 선택합니다.

  7. 업데이트 단추를 클릭하여 쇼핑 카트 페이지를 업데이트하고 새 주문 합계를 표시합니다.

    쇼핑 카트 - 카트 업데이트

요약

이 자습서에서는 Wingtip Toys Web Forms 샘플 애플리케이션용 쇼핑 카트를 만들었습니다. 이 자습서에서는 Entity Framework Code First, 데이터 주석, 강력한 형식의 데이터 컨트롤 및 모델 바인딩을 사용했습니다.

쇼핑 카트는 사용자가 구매를 위해 선택한 항목 추가, 삭제 및 업데이트를 지원합니다. 쇼핑 카트 기능을 구현하는 것 외에도 GridView 컨트롤에 쇼핑 카트 항목을 표시하고 주문 합계를 계산하는 방법을 배웠습니다.

실제 비즈니스 애플리케이션에서 설명된 기능이 작동하는 방식을 이해하기 위해 nopCommerce - ASP.NET 기반 오픈 소스 전자 상거래 쇼핑 카트의 예를 볼 수 있습니다. 원래, 그것은 Web Forms 구축 하 고 수년에 걸쳐 그것은 MVC로 이동 하 고 지금 ASP.NET Core.

추가 정보

ASP.NET 세션 상태 개요