پیاده سازی سبد خرید با استفاده از Session

پنجشنبه 29 آبان 1393

در این مقاله چگونگی مدیریت سبد خرید را با استفاده از Session ها خواهیم آموخت

پیاده سازی سبد خرید با استفاده از Session

مدیریت سبد خرید با استفاده از Session ها برای مبتدیان ASP.NET گیج کننده است.در این مقاله نگاهی به چگونگی انجام آن می اندازیم بنابراین آیتم ها  قبل از اینکه خریداری شوند  به راحتی توسط مشتری به سبد خرید اضافه و کم می شوند . 

در این تمرین من از ASP.NET web Forms و دیتابیس Northwind استفاده می کنم.در این جا من قصد دارم کاربری را با انتخاب تعدادی از محصولات بر اساس دسته بندی به نمایش بگذارم.

وقتی کاربرگروه محصول خود  را تغییر می دهد یک postback رخ می دهد که به این معنی است که محصول انتخاب شده از بین می رود مگر اینکه یکسری مکانیزم مدیریتی اتخاذ شود.

Session یکی از این مکانیزم هاست که البته باید درست استفاده شود تا حافظه سرور برای هر کاربر زیاد مصرف نشود.

بنابراین تمام آن چیزی که من ذخیره می کنم ID محصول انتخاب شده است.این دوصفحه نمونه که با هم می خواهیم ببینیم شامل یک dropdownlist از دسته بندی محصولات و یک GridView برای نمایش  لیست محصولات بر اساس انتخاب گروه محصولات است.

کاربر به راحتی می تواند محصولات مورد نظر خود را با استفاده از checkBox تعریف شده در GridView انتخاب کند، و به صفحه CheckOut که تمامی محصولات انتخابی در آنجا به نمایش در می آید بفرستد.

در این جا کاربر می تواند هزینه کل محصولاتی را که  سفارش شده را ببیند و اگر  خواست محصول را از سبد خرید حذف کند.

این صفحه کد علاوه بر کنترل های DropDown و GridView شامل دو دکمه برای اضافه کردن به سبد خرید و دیگری برای فرستادن به صفحه CheckOut است.

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" 
			CodeBehind="ShoppingCart.aspx.cs" Inherits="SessionShoppingCart.ShoppingCart" %>
<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
   <p>
      Select Category:
      <asp:DropDownList ID="Categories" runat="server" DataSourceID="CategoriesData" 
        DataTextField="CategoryName" DataValueField="CategoryID" AutoPostBack="true" />
      <asp:SqlDataSource ID="CategoriesData" runat="server" 
        ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
        SelectCommand="SELECT [CategoryID], [CategoryName] FROM [Categories]"></asp:SqlDataSource>
    </p>
    <asp:GridView ID="Products" runat="server" AutoGenerateColumns="False" DataKeyNames="ProductID"
      DataSourceID="ProductsData" GridLines="None" EnableViewState="False">
      <Columns>
        <asp:TemplateField HeaderText="Add To Cart">
          <ItemTemplate>
            <asp:CheckBox ID="SelectedProducts" runat="server" />
          </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField DataField="ProductName" HeaderText="Product" SortExpression="ProductName" />
        <asp:BoundField DataField="CategoryName" HeaderText="Category" SortExpression="CategoryName" />
        <asp:BoundField DataField="UnitPrice" HeaderText="Price" SortExpression="UnitPrice"
          DataFormatString="{0:c}" />
      </Columns>
    </asp:GridView>
    <asp:Button ID="AddToCart" runat="server" Text="Select Products" OnClick="AddToCart_Click" /> 
    &nbsp;&nbsp;&nbsp;&nbsp;
    <asp:Button ID="Checkout" runat="server" Text="Check Out" OnClick="Checkout_Click" />
    <asp:SqlDataSource ID="ProductsData" runat="server" 
      ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
      SelectCommand="SELECT Products.ProductID, Products.ProductName, Categories.CategoryName, 
        Products.UnitPrice FROM Products INNER JOIN Categories ON Products.CategoryID = Categories.CategoryID 
        WHERE Products.CategoryID = @CategoryID">
      <SelectParameters>
        <asp:ControlParameter ControlID="Categories" Name="CategoryID" PropertyName="SelectedValue"
          DefaultValue="1" />
      </SelectParameters>
    </asp:SqlDataSource>
</asp:Content>

 

با کلید کردن روی دکمه اول یک  سبد در session ایجاد می کند و آیتم های انتخابی را به آن اضافه می کند.

protected void AddToCart_Click(object sender, EventArgs e)
{
  var selectedProducts = Products.Rows.Cast<GridViewRow>()
    .Where(row => ((CheckBox)row.FindControl("SelectedProducts")).Checked)
    .Select(row => Products.DataKeys[row.RowIndex].Value.ToString()).ToList();
  if (Session["Cart"] == null)
  {
    Session["Cart"] = selectedProducts;
  }
  else
  {
    var cart = (List<string>)Session["Cart"];
    foreach (var product in selectedProducts)
      cart.Add(product);
    Session["Cart"] = cart;
  }
  foreach (GridViewRow row in Products.Rows)
  {
    CheckBox cb = (CheckBox)row.FindControl("SelectedProducts");
    if (cb.Checked)
      cb.Checked = false;
  }
}

خط اول کد که یک query است مجموعه ردیف های GridView که همان محصولات است را بررسی می کند و value ردیف هایی که CheckBox شان تیک خورده را بدست می آورد و این ها را تبدیل به لیستی از جنس string می کند.

در این صورت لیست به متغیر session نسبت داده می شود و به طور اتوماتیکSession  ایجاد می شود.

اگر محصولات قبلا انتخاب و به لیست اضافه شده باشند ،از متغیر session واکشی می شوند و محصول جدید به آن اضافه می شود و البته این قبل ازآن است که تغییرات لیست جدید به متغیر session منتسب شوند.

اگر هیچ محصولی انتخاب نشده باشد،Session ایجاد نمی شود و null خواهد بود.

و در نهایت همه CheckBox ها Clear می شوند تا مانع از چک شدنشان وقتی صفحه ShoppingCart دو باره باز می شود شویم.

Codebehind کلید دوم:

protected void Checkout_Click(object sender, EventArgs e)
{
  if (Session["Cart"] != null)
    Response.Redirect("Checkout.aspx");
}

اگر سبد خرید خالی نباشد کاربر به صفحه CheckOut هدایت می شود.

صفحه CheckOut:

همان طور که شاهدید آیتم های انتخاب شده در این صفحه همراه با یک Checkbox کنارشان وجود دارند که به کاربر اجازه حذف می دهد و همین طور قیمت کل نیز موجود است.

نمونه کد:

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true"
  CodeBehind="Checkout.aspx.cs" Inherits="SessionShoppingCart.Checkout" %>

<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
  <asp:GridView ID="Basket" runat="server" AutoGenerateColumns="False" 
    GridLines="None" EnableViewState="False" ShowFooter="True" 
    DataKeyNames="ProductID" OnRowCreated="Basket_RowCreated">
    <Columns>
      <asp:TemplateField HeaderText="Remove">
        <ItemTemplate>
          <asp:CheckBox ID="RemovedProducts" runat="server" />
        </ItemTemplate>
      </asp:TemplateField>
      <asp:TemplateField HeaderText="Product" SortExpression="ProductName">
        <ItemTemplate>
          <asp:Label ID="ProductName" runat="server" Text='<%# Eval("ProductName") %>' />
        </ItemTemplate>
        <FooterTemplate>
          <strong>
            Total Price:
          </strong>
        </FooterTemplate>
      </asp:TemplateField>
      <asp:TemplateField HeaderText="Price" SortExpression="UnitPrice">
        <ItemTemplate>
          <asp:Label ID="UnitPrice" runat="server" Text='<%# Eval("UnitPrice", "{0:c}") %>' />
        </ItemTemplate>
        <FooterTemplate>
          <strong>
            <asp:Literal ID="TotalPrice" runat="server" />
          </strong>
        </FooterTemplate>
      </asp:TemplateField>
    </Columns>
  </asp:GridView>
  <asp:Button ID="RemoveProduct" runat="server" 
    Text="Remove From Basket" OnClick="RemoveProduct_Click" />
  &nbsp;&nbsp;&nbsp;&nbsp;
  <asp:Button ID="ConfirmPurchase" runat="server" Text="Confirm Purchase" />
  <asp:SqlDataSource ID="BasketData" runat="server" 
    ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>">
  </asp:SqlDataSource>
</asp:Content>

در اینجا همه ستون ها به TemplateField تبدیل می شوند و بنابراین من می توانم یک ردیف footer به انتهای ستون  نام محصول و قیمت محصول اضافه کنم که قیمت کل سفارشات را نمایش دهد.شما همچنین باید توجه کنید که

event handler ی برای نمایش قیمت فراخوانی می شود .

همان گونه که شاهدید در اینجا دوباره دو دکمه تعریف شده که اولی برای حذف آیتم تعریف شده و دومی که در اینجا ما برایش چیزی ننوشته ایم برای وقتی است که می خواهیم کاربر را به صفحه پرداخت هدایت کنیم.

نمونه کد فرم به طور کلی:

public partial class Checkout : Page
{
  Decimal cost;
  protected void Page_Load(object sender, EventArgs e)
  {
    if (Session["Cart"] == null)
      Response.Redirect("ShoppingCart.aspx");
    BindBasket();
  }

  protected void RemoveProduct_Click(object sender, EventArgs e)
  {
    var cart = (List<string>)Session["Cart"];
    var removedProducts = Basket.Rows.Cast<GridViewRow>()
      .Where(row => ((CheckBox)row.FindControl("RemovedProducts")).Checked)
      .Select(row => Basket.DataKeys[row.RowIndex].Value.ToString()).ToList();
    cart.RemoveAll(removedProducts.Contains);
    BindBasket();
  }

  protected void BindBasket()
  {
    var sql = "SELECT ProductID, ProductName, UnitPrice FROM Products WHERE ProductID IN ({0})";
    var values = (List<string>)Session["Cart"];
    if (values.Count > 0)
    {
      var parms = values.Select((s, i) => "@p" + i.ToString()).ToArray();
      var inclause = string.Join(",", parms);
      BasketData.SelectCommand = string.Format(sql, inclause);
      BasketData.SelectParameters.Clear();
      for (var i = 0; i < parms.Length; i++)
      {
        BasketData.SelectParameters.Add(parms[i].Replace("@", ""), values[i]);
      }

      DataView view = (DataView)BasketData.Select(DataSourceSelectArguments.Empty);

      var costQuery = view.Cast<DataRowView>().Select(drv => drv.Row.Field<decimal>("UnitPrice"));
      cost = costQuery.Sum();
      Basket.DataSource = view;
      Basket.DataBind();
    }
  }

  protected void Basket_RowCreated(object sender, GridViewRowEventArgs e)
  {
    if (e.Row.RowType == DataControlRowType.Footer)
    {
      Literal total = (Literal)e.Row.FindControl("TotalPrice");
      total.Text = cost.ToString("c");
    }
  }
}

یک متغیر decimal cost تعریف کرده ایم که برای نگه داری قیمت کل آیتم های انتخاب شده است.در طی لود شدن صفحه چک می شود که آیا هنوز session موجود است یا خیر.

و اگر نه کاربر به صفحه ShoppingCart هدایت می شود

 

 

 

فایل های ضمیمه

جعفری

نویسنده 22 مقاله در برنامه نویسان

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید