Aracılığıyla paylaş


Bölüm 5: İş Mantığı

tarafından Joe Stagner

Tailspin Spyworks, .NET platformu için güçlü, ölçeklenebilir uygulamalar oluşturmanın ne kadar basit olduğunu gösterir. Alışveriş, ödeme ve yönetim gibi çevrimiçi bir mağaza oluşturmak için ASP.NET 4'teki harika yeni özelliklerin nasıl kullanılacağını gösterir.

Bu öğretici serisi, Tailspin Spyworks örnek uygulamasını derlemek için atılan tüm adımların ayrıntılarını içerir. 5. Bölüm bazı iş mantığı ekler.

İş Mantığı Ekleme

Birisi web sitemizi her ziyaret edin, alışveriş deneyimimizin kullanılabilir olmasını istiyoruz. Ziyaretçiler, kayıtlı veya oturum açmamış olsalar bile alışveriş sepetine göz atabilir ve ürünler ekleyebilir. Kullanıma almak için hazır olduklarında kendilerine kimlik doğrulaması seçeneği verilir ve henüz üye değilse bir hesap oluşturabilirler.

Bu, alışveriş sepetini anonim durumdan "Kayıtlı Kullanıcı" durumuna dönüştürmek için mantığı uygulamamız gerektiği anlamına gelir.

Şimdi "Classes" adlı bir dizin oluşturalım, ardından klasöre Right-Click ve MyShoppingCart.cs adlı yeni bir "Sınıf" dosyası oluşturalım

Alışveriş Sepetim noktası C S adlı yeni Sınıf dosyasını gösteren ekran görüntüsü.

Sınıflar klasörünün içeriğini gösteren ekran görüntüsü.

Daha önce belirtildiği gibi MyShoppingCart.aspx sayfasını uygulayan sınıfını genişleteceğiz ve bunu kullanarak yapacağız. NET'in güçlü "Kısmi Sınıf" yapısı.

MyShoppingCart.aspx.cf dosyamız için oluşturulan çağrı şöyle görünür.

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

namespace TailspinSpyworks
{
    public partial class MyShoppingCart : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }
    }
}

"Partial" anahtar sözcüğünü kullanmaya dikkat edin.

Yeni oluşturduğumuz sınıf dosyası şöyle görünür.

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

namespace TailspinSpyworks.Classes
{
    public class MyShoppingCart
    {
    }
}

Bu dosyaya kısmi anahtar sözcüğünü de ekleyerek uygulamalarımızı birleştireceğiz.

Yeni sınıf dosyamız şimdi şöyle görünür.

namespace TailspinSpyworks.Classes
{
    public partial class MyShoppingCart
    {
    }
}

Sınıfımıza ekleyeceğimiz ilk yöntem "AddItem" yöntemidir. Bu, kullanıcı Ürün Listesi ve Ürün Ayrıntıları sayfalarında "Art'a Ekle" bağlantılarına tıkladığında nihai olarak çağrılacak yöntemdir.

Sayfanın en üstündeki using deyimlerine aşağıdakileri ekleyin.

using TailspinSpyworks.Data_Access;

Ve bu yöntemi MyShoppingCart sınıfına ekleyin.

//------------------------------------------------------------------------------------+
public void AddItem(string cartID, int productID, int quantity)
{
  using (CommerceEntities db = new CommerceEntities())
    {
    try 
      {
      var myItem = (from c in db.ShoppingCarts where c.CartID == cartID && 
                              c.ProductID == productID select c).FirstOrDefault();
      if(myItem == null)
        {
        ShoppingCart cartadd = new ShoppingCart();
        cartadd.CartID = cartID;
        cartadd.Quantity = quantity;
        cartadd.ProductID = productID;
        cartadd.DateCreated = DateTime.Now;
        db.ShoppingCarts.AddObject(cartadd);
        }
      else
        {
        myItem.Quantity += quantity;
        }
      db.SaveChanges();
      }
    catch (Exception exp)
      {
      throw new Exception("ERROR: Unable to Add Item to Cart - " + 
                                                          exp.Message.ToString(), exp);
      }
   }
}

Öğenin zaten sepette olup olmadığını görmek için LINQ to Entities kullanıyoruz. Bu durumda, maddenin sipariş miktarını güncelleştiririz, aksi takdirde seçili madde için yeni bir giriş oluştururuz

Bu yöntemi çağırmak için, yalnızca bu yöntemi sınıflandıran değil, öğe eklendikten sonra geçerli alışveriş a=sepetini görüntüleyen bir AddToCart.aspx sayfası uygulayacağız.

Çözüm gezgininde çözüm adına Right-Click ve daha önce yaptığımız gibi AddToCart.aspx adlı yeni bir sayfa ekleyin.

Uygulamamızda düşük stok sorunları vb. gibi geçici sonuçları görüntülemek için bu sayfayı kullanabiliriz ancak sayfa aslında işlenmez, bunun yerine "Ekle" mantığını ve yeniden yönlendirmeyi çağırır.

Bunu gerçekleştirmek için Page_Load olayına aşağıdaki kodu ekleyeceğiz.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Diagnostics;

namespace TailspinSpyworks
{
    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) && Int32.TryParse(rawId, out productId))
            {
                MyShoppingCart usersShoppingCart = new MyShoppingCart();
                String cartId = usersShoppingCart.GetShoppingCartId();
                usersShoppingCart.AddItem(cartId, productId, 1);
            }
            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("MyShoppingCart.aspx");
        }
    }
}

Bir QueryString parametresinden alışveriş sepetine eklenecek ürünü aldığımızı ve sınıfımızın AddItem yöntemini çağırdığımıza dikkat edin.

Hiçbir hatayla karşılaşılmaması durumunda denetim, sonraki adımda tam olarak uygulayacağımız SHoppingCart.aspx sayfasına geçirilir. Hata olması gerekiyorsa bir özel durum oluştururuz.

Şu anda henüz genel bir hata işleyicisi uygulamadık, bu nedenle bu özel durum uygulamamız tarafından işlenmez ancak bunu kısa süre içinde düzelteceğiz.

Debug.Fail() deyiminin (aracılığıyla kullanılabilir) kullanımına da dikkat edin using System.Diagnostics;)

Uygulama hata ayıklayıcı içinde mi çalışıyor? Bu yöntem, belirttiğimiz hata iletisiyle birlikte uygulamaların durumu hakkında bilgi içeren ayrıntılı bir iletişim kutusu görüntüler.

Üretimde çalıştırılırken Debug.Fail() deyimi yoksayılır.

Yukarıdaki kodda alışveriş sepeti sınıf adlarımızdaki bir yönteme yapılan çağrıyı "GetShoppingCartId" olarak göreceksiniz.

yöntemini uygulamak için aşağıdaki kodu ekleyin.

Ayrıca güncelleştirme ve ödeme düğmelerini ve "toplam" sepetini görüntüleyebileceğimiz bir etiket eklediğimize dikkat edin.

public const string CartId = "TailSpinSpyWorks_CartID";

//--------------------------------------------------------------------------------------+
public String GetShoppingCartId()
{
  if (Session[CartId] == null)
     {
     Session[CartId] = System.Web.HttpContext.Current.Request.IsAuthenticated ? 
                                        User.Identity.Name : Guid.NewGuid().ToString();
     }
  return Session[CartId].ToString();
}

Artık alışveriş sepetimize ürün ekleyebiliriz ancak ürün eklendikten sonra sepeti görüntüleme mantığını uygulamadık.

Bu nedenle, MyShoppingCart.aspx sayfasında aşağıdaki gibi bir EntityDataSource denetimi ve bir GridVire denetimi ekleyeceğiz.

<div id="ShoppingCartTitle" runat="server" class="ContentHead">Shopping Cart</div>
<asp:GridView ID="MyList" runat="server" AutoGenerateColumns="False" ShowFooter="True" 
                          GridLines="Vertical" CellPadding="4"
                          DataSourceID="EDS_Cart"  
                          DataKeyNames="ProductID,UnitCost,Quantity" 
                          CssClass="CartListItem">              
  <AlternatingRowStyle CssClass="CartListItemAlt" />
  <Columns>
    <asp:BoundField DataField="ProductID" HeaderText="Product ID" ReadOnly="True" 
                                          SortExpression="ProductID"  />
    <asp:BoundField DataField="ModelNumber" HeaderText="Model Number" 
                                            SortExpression="ModelNumber" />
    <asp:BoundField DataField="ModelName" HeaderText="Model Name" 
                                          SortExpression="ModelName"  />
    <asp:BoundField DataField="UnitCost" HeaderText="Unit Cost" ReadOnly="True" 
                                         SortExpression="UnitCost" 
                                         DataFormatString="{0:c}" />         
    <asp:TemplateField> 
      <HeaderTemplate>Quantity</HeaderTemplate>
      <ItemTemplate>
         <asp:TextBox ID="PurchaseQuantity" Width="40" runat="server" 
                      Text='<%# Bind("Quantity") %>'></asp:TextBox> 
      </ItemTemplate>
    </asp:TemplateField>           
    <asp:TemplateField> 
      <HeaderTemplate>Item Total</HeaderTemplate>
      <ItemTemplate>
        <%# (Convert.ToDouble(Eval("Quantity")) *  
             Convert.ToDouble(Eval("UnitCost")))%>
      </ItemTemplate>
    </asp:TemplateField>
    <asp:TemplateField> 
    <HeaderTemplate>Remove Item</HeaderTemplate>
      <ItemTemplate>
        <center>
          <asp:CheckBox id="Remove" runat="server" />
        </center>
      </ItemTemplate>
    </asp:TemplateField>
  </Columns>
  <FooterStyle CssClass="CartListFooter"/>
  <HeaderStyle  CssClass="CartListHead" />
</asp:GridView>

<div>
  <strong>
    <asp:Label ID="LabelTotalText" runat="server" Text="Order Total : ">  
    </asp:Label>
    <asp:Label CssClass="NormalBold" id="lblTotal" runat="server" 
                                                   EnableViewState="false">
    </asp:Label>
  </strong> 
</div>
<br />
<asp:imagebutton id="UpdateBtn" runat="server" ImageURL="Styles/Images/update_cart.gif" 
                                onclick="UpdateBtn_Click"></asp:imagebutton>
<asp:imagebutton id="CheckoutBtn" runat="server"  
                                  ImageURL="Styles/Images/final_checkout.gif"    
                                  PostBackUrl="~/CheckOut.aspx">
</asp:imagebutton>
<asp:EntityDataSource ID="EDS_Cart" runat="server" 
                      ConnectionString="name=CommerceEntities" 
                      DefaultContainerName="CommerceEntities" EnableFlattening="False" 
                      EnableUpdate="True" EntitySetName="ViewCarts" 
                      AutoGenerateWhereClause="True" EntityTypeFilter="" Select=""                         
                      Where="">
  <WhereParameters>
    <asp:SessionParameter Name="CartID" DefaultValue="0" 
                                        SessionField="TailSpinSpyWorks_CartID" />
  </WhereParameters>
</asp:EntityDataSource>

Sepeti Güncelleştir düğmesine çift tıklayabilmeniz ve işaretlemedeki bildirimde belirtilen tıklama olayı işleyicisini oluşturabilmeniz için formu tasarımcıda çağırın.

Ayrıntıları daha sonra uygulayacağız ancak bunu yapmak, uygulamamızı hatasız olarak derlememize ve çalıştırmamıza olanak sağlar.

Uygulamayı çalıştırdığınızda ve alışveriş sepetine bir öğe eklediğinizde bunu görürsünüz.

Güncelleştirilmiş alışveriş sepetini gösteren ekran görüntüsü.

Üç özel sütun uygulayarak "varsayılan" kılavuz görüntüsünden saptık.

İlki, Miktar için Düzenlenebilir, "Sınırlanmış" bir alandır:

<asp:TemplateField> 
      <HeaderTemplate>Quantity</HeaderTemplate>
      <ItemTemplate>
         <asp:TextBox ID="PurchaseQuantity" Width="40" runat="server" 
                      Text='<%# Bind("Quantity") %>'></asp:TextBox> 
      </ItemTemplate>
    </asp:TemplateField>

Sonraki sütun, satır madde toplamını görüntüleyen bir "hesaplanan" sütundur (madde maliyeti sipariş edilecek miktarın çarpımını gösterir):

<asp:TemplateField> 
      <HeaderTemplate>Item Total</HeaderTemplate>
      <ItemTemplate>
        <%# (Convert.ToDouble(Eval("Quantity")) *  
             Convert.ToDouble(Eval("UnitCost")))%>
      </ItemTemplate>
    </asp:TemplateField>

Son olarak, kullanıcının öğenin alışveriş grafiğinden kaldırılması gerektiğini belirtmek için kullanacağı Bir CheckBox denetimi içeren özel bir sütuna sahibiz.

<asp:TemplateField> 
    <HeaderTemplate>Remove Item</HeaderTemplate>
      <ItemTemplate>
        <center>
          <asp:CheckBox id="Remove" runat="server" />
        </center>
      </ItemTemplate>
    </asp:TemplateField>

Güncelleştirilmiş Miktar ve Öğeleri Kaldır'ı gösteren ekran görüntüsü.

Gördüğünüz gibi Sipariş Toplamı satırı boş olduğundan Sipariş Toplamı'nı hesaplamak için biraz mantık ekleyelim.

İlk olarak MyShoppingCart Sınıfımıza bir "GetTotal" yöntemi uygulayacağız.

MyShoppingCart.cs dosyasına aşağıdaki kodu ekleyin.

//--------------------------------------------------------------------------------------+
public decimal GetTotal(string cartID)
{
    using (CommerceEntities db = new CommerceEntities())
    {
        decimal cartTotal = 0;
        try
        {
            var myCart = (from c in db.ViewCarts where c.CartID == cartID select c);
            if (myCart.Count() > 0)
            {
                cartTotal = myCart.Sum(od => (decimal)od.Quantity * (decimal)od.UnitCost);
            }
        }
        catch (Exception exp)
        {
            throw new Exception("ERROR: Unable to Calculate Order Total - " + 
            exp.Message.ToString(), exp);
        }
        return (cartTotal);
     }
}

Ardından Page_Load olay işleyicisinde GetTotal yöntemimizi çağırabiliriz. Aynı zamanda alışveriş sepetinin boş olup olmadığını görmek ve varsa ekranı buna göre ayarlamak için bir test ekleyeceğiz.

Şimdi alışveriş sepeti boşsa şunu alacağız:

Boş alışveriş sepetini gösteren ekran görüntüsü.

Ve eğer değilse, toplamımızı görürüz.

Alışveriş sepetindeki öğelerin toplam tutarını gösteren ekran görüntüsü.

Ancak, bu sayfa henüz tamamlanmamıştır.

Kullanıcı tarafından kılavuzda bazı değişiklikler yapılmış olabileceğinden, kaldırılmak üzere işaretlenmiş öğeleri kaldırarak ve yeni miktar değerlerini belirleyerek alışveriş sepetini yeniden hesaplamak için ek mantığa ihtiyacımız olacak.

Bir kullanıcı öğeyi kaldırma için işaretlediğinde olayı işlemek için MyShoppingCart.cs'deki alışveriş sepeti sınıfımıza bir "RemoveItem" yöntemi ekleyelim.

//------------------------------------------------------------------------------------+
public void RemoveItem(string cartID, int  productID)
{
    using (CommerceEntities db = new CommerceEntities())
    {
        try
        {
            var myItem = (from c in db.ShoppingCarts where c.CartID == cartID && 
                         c.ProductID == productID select c).FirstOrDefault();
            if (myItem != null)
            {
                db.DeleteObject(myItem);
                db.SaveChanges();
            }
        }
        catch (Exception exp)
        {
            throw new Exception("ERROR: Unable to Remove Cart Item - " + 
                                  exp.Message.ToString(), exp);
        }
    }
}

Şimdi bir kullanıcının GridView'da sipariş edilecek kaliteyi değiştirmesi durumunu ele almak için bir yöntem ekleyelim.

//--------------------------------------------------------------------------------------+
public void UpdateItem(string cartID, int productID, int quantity)
{
    using (CommerceEntities db = new CommerceEntities())
    {
        try
        {
            var myItem = (from c in db.ShoppingCarts where c.CartID == cartID && 
                    c.ProductID == productID 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);
        }
    }
}

Temel Kaldır ve Güncelleştir özellikleri mevcutken, veritabanındaki alışveriş sepetini gerçekten güncelleştiren mantığı uygulayabiliriz. (MyShoppingCart.cs içinde)

//-------------------------------------------------------------------------------------+
public void UpdateShoppingCartDatabase(String cartId, 
                                       ShoppingCartUpdates[] CartItemUpdates)
{
  using (CommerceEntities db = new CommerceEntities())
    {
    try
      {
      int CartItemCOunt = CartItemUpdates.Count();
      var myCart = (from c in db.ViewCarts where c.CartID == cartId select c);
      foreach (var cartItem in myCart)
        {
        // Iterate through all rows within shopping cart list
        for (int i = 0; i < CartItemCOunt; i++)
          {
          if (cartItem.ProductID == CartItemUpdates[i].ProductId)
             {
             if (CartItemUpdates[i].PurchaseQantity < 1 || 
   CartItemUpdates[i].RemoveItem == true)
                {
                RemoveItem(cartId, cartItem.ProductID);
                }
             else 
                {
                UpdateItem(cartId, cartItem.ProductID, 
                                   CartItemUpdates[i].PurchaseQantity);
                }
              }
            }
          }
        }
      catch (Exception exp)
        {
        throw new Exception("ERROR: Unable to Update Cart Database - " + 
                             exp.Message.ToString(), exp);
        }            
    }           
}

Bu yöntemin iki parametre beklediğini unutmayın. Bunlardan biri alışveriş sepeti kimliği, diğeri ise kullanıcı tanımlı türde bir nesne dizisidir.

Mantığımızın kullanıcı arabirimi özelliklerine bağımlılığını en aza indirmek için yöntemimizin GridView denetimine doğrudan erişmesine gerek kalmadan alışveriş sepeti öğelerini kodumuza geçirmek için kullanabileceğimiz bir veri yapısı tanımladık.

public struct ShoppingCartUpdates
{
    public int ProductId;
    public int PurchaseQantity;
    public bool RemoveItem;
}

MyShoppingCart.aspx.cs dosyamızda bu yapıyı Aşağıdaki gibi Güncelleştir Düğmesi Tıklama olay işleyicimizde kullanabiliriz. Sepeti güncelleştirmenin yanı sıra sepet toplamını da güncelleştireceğiz.

//--------------------------------------------------------------------------------------+
protected void UpdateBtn_Click(object sender, ImageClickEventArgs e)
{
  MyShoppingCart usersShoppingCart = new MyShoppingCart();
  String cartId = usersShoppingCart.GetShoppingCartId();

  ShoppingCartUpdates[] cartUpdates = new ShoppingCartUpdates[MyList.Rows.Count];
  for (int i = 0; i < MyList.Rows.Count; i++)
    {
    IOrderedDictionary rowValues = new OrderedDictionary();
    rowValues = GetValues(MyList.Rows[i]);
    cartUpdates[i].ProductId =  Convert.ToInt32(rowValues["ProductID"]);
    cartUpdates[i].PurchaseQantity = Convert.ToInt32(rowValues["Quantity"]); 

    CheckBox cbRemove = new CheckBox();
    cbRemove = (CheckBox)MyList.Rows[i].FindControl("Remove");
    cartUpdates[i].RemoveItem = cbRemove.Checked;
    }

   usersShoppingCart.UpdateShoppingCartDatabase(cartId, cartUpdates);
   MyList.DataBind();
   lblTotal.Text = String.Format("{0:c}", usersShoppingCart.GetTotal(cartId));
}

Bu kod satırının özellikle ilgilendiğini unutmayın:

rowValues = GetValues(MyList.Rows[i]);

GetValues(), MyShoppingCart.aspx.cs dosyasında aşağıdaki gibi uygulayacağımız özel bir yardımcı işlevdir.

//--------------------------------------------------------------------------------------+
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;
}

Bu, GridView denetimimizdeki bağlı öğelerin değerlerine erişmek için temiz bir yol sağlar. "Öğeyi Kaldır" CheckBox Denetimimiz bağlı olmadığından, bu denetime FindControl() yöntemiyle erişeceğiz.

Projenizin geliştirilmesinin bu aşamasında, kullanıma alma işlemini uygulamaya hazırlanıyoruz.

Bunu yapmadan önce Visual Studio'yu kullanarak üyelik veritabanını oluşturalım ve üyelik deposuna bir kullanıcı ekleyelim.