Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
MVC Müzik Deposu, web geliştirme için ASP.NET MVC ve Visual Studio'yu kullanmayı adım adım tanıtır ve açıklayan bir öğretici uygulamasıdır.
MVC Music Store, müzik albümlerini çevrimiçi olarak satan ve temel site yönetimi, kullanıcı oturum açma ve alışveriş sepeti işlevlerini uygulayan basit bir örnek mağaza uygulamasıdır.
Bu öğretici serisi, ASP.NET MVC Müzik Deposu örnek uygulamasını derlemek için atılan tüm adımların ayrıntılarını içerir. Bölüm 8, Ajax Güncelleştirmeler ile Alışveriş Sepetini kapsar.
Kullanıcıların kayıt yapmadan albümleri sepetlerine yerleştirmelerine izin vereceğiz, ancak alışverişi tamamlamak için konuk olarak kaydolmaları gerekir. Alışveriş ve ödeme işlemi iki denetleyiciye ayrılacak: bir sepete anonim olarak öğe eklemeye izin veren bir ShoppingCart Denetleyicisi ve ödeme işlemini gerçekleştiren bir Kullanıma Alma Denetleyicisi. Bu bölümde Alışveriş Sepeti ile başlayacağız, ardından aşağıdaki bölümde Kullanıma Alma işlemini oluşturacağız.
Cart, Order ve OrderDetail model sınıflarını ekleme
Alışveriş Sepeti ve Ödeme süreçlerimiz bazı yeni sınıflardan yararlanacaktır. Models klasörüne sağ tıklayın ve aşağıdaki kodla bir Cart sınıfı (Cart.cs) ekleyin.
using System.ComponentModel.DataAnnotations;
namespace MvcMusicStore.Models
{
public class Cart
{
[Key]
public int RecordId { get; set; }
public string CartId { get; set; }
public int AlbumId { get; set; }
public int Count { get; set; }
public System.DateTime DateCreated { get; set; }
public virtual Album Album { get; set; }
}
}
Bu sınıf, RecordId özelliğinin [Key] özniteliği dışında şimdiye kadar kullandığımız diğer sınıflara oldukça benzer. Sepet öğelerimizin anonim alışverişe izin vermek için CartID adlı bir dize tanımlayıcısı olacaktır, ancak tabloda RecordId adlı bir tamsayı birincil anahtarı bulunur. Kural gereği, Entity Framework Code-First Cart adlı tablonun birincil anahtarının CartId veya ID olmasını bekler, ancak isterseniz bunu ek açıklamalar veya kod aracılığıyla kolayca geçersiz kılabiliriz. Bu, Entity Framework'teki basit kuralları bize uygun olduğunda Code-First nasıl kullanabileceğimize bir örnektir, ancak bunlar uygun olmadığında onlar tarafından kısıtlanmaz.
Ardından, aşağıdaki kodla bir Order sınıfı (Order.cs) ekleyin.
using System.Collections.Generic;
namespace MvcMusicStore.Models
{
public partial class Order
{
public int OrderId { get; set; }
public string Username { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public decimal Total { get; set; }
public System.DateTime OrderDate { get; set; }
public List<OrderDetail> OrderDetails { get; set; }
}
}
Bu sınıf, bir siparişin özet ve teslim bilgilerini izler. Henüz oluşturmadığımız bir sınıfa bağlı olan bir OrderDetails gezinti özelliğine sahip olduğundan henüz derlenmez. Şimdi OrderDetail.cs adlı bir sınıf ekleyerek ve aşağıdaki kodu ekleyerek bunu düzeltelim.
namespace MvcMusicStore.Models
{
public class OrderDetail
{
public int OrderDetailId { get; set; }
public int OrderId { get; set; }
public int AlbumId { get; set; }
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
public virtual Album Album { get; set; }
public virtual Order Order { get; set; }
}
}
MusicStoreEntities sınıfımızda DbSets'i içerecek şekilde son bir güncelleştirme yapacağız. Bu güncelleştirme, dbSet<Artist> de dahil olmak üzere bu yeni Model sınıflarını kullanıma sunar. Güncelleştirilmiş MusicStoreEntities sınıfı aşağıdaki gibi görünür.
using System.Data.Entity;
namespace MvcMusicStore.Models
{
public class MusicStoreEntities : DbContext
{
public DbSet<Album> Albums { get; set; }
public DbSet<Genre> Genres { get; set; }
public DbSet<Artist> Artists {
get; set; }
public DbSet<Cart>
Carts { get; set; }
public DbSet<Order> Orders
{ get; set; }
public DbSet<OrderDetail>
OrderDetails { get; set; }
}
}
Alışveriş Sepeti iş mantığını yönetme
Ardından Models klasöründe ShoppingCart sınıfını oluşturacağız. ShoppingCart modeli Sepet tablosuna veri erişimini işler. Buna ek olarak, alışveriş sepetine öğe ekleme ve alışveriş sepetinden öğe kaldırmaya yönelik iş mantığını işler.
Kullanıcıların yalnızca alışveriş sepetlerine öğe eklemek için bir hesaba kaydolmalarını gerektirmek istemediğimiz için, kullanıcılara alışveriş sepetine erişirken geçici bir benzersiz tanımlayıcı (GUID veya genel olarak benzersiz tanımlayıcı kullanarak) atarız. Bu kimliği ASP.NET Session sınıfını kullanarak depolayacağız.
Not: ASP.NET Oturumu, siteden ayrıldıktan sonra süresi dolacak olan kullanıcıya özgü bilgileri depolamak için uygun bir yerdir. Oturum durumunun kötüye kullanılması daha büyük sitelerde performans açısından etkilere neden olsa da, ışık kullanımımız gösterim amacıyla iyi çalışır.
ShoppingCart sınıfı aşağıdaki yöntemleri kullanıma sunar:
AddToCart parametre olarak bir Albüm alır ve bunu kullanıcının sepetine ekler. Cart tablosu her albümün miktarını izlediğinden, gerekirse yeni bir satır oluşturma mantığı veya kullanıcı albümün bir kopyasını sipariş etmişse miktarı artırma mantığı içerir.
RemoveFromCart bir Albüm Kimliği alır ve bunu kullanıcının sepetinden kaldırır. Kullanıcının sepetinde albümün yalnızca bir kopyası varsa, satır kaldırılır.
EmptyCart kullanıcının alışveriş sepetindeki tüm öğeleri kaldırır.
GetCartItems , görüntüleme veya işleme için CartItems listesini alır.
GetCount , kullanıcının alışveriş sepetindeki toplam albüm sayısını alır.
GetTotal , sepetteki tüm öğelerin toplam maliyetini hesaplar.
CreateOrder , alışveriş sepetini ödeme aşamasında bir siparişe dönüştürür.
GetCart , denetleyicilerimizin bir sepet nesnesi almasını sağlayan statik bir yöntemdir. Kullanıcının oturumundan CartId değerini okumayı işlemek için GetCartId yöntemini kullanır. GetCartId yöntemi, kullanıcının oturumundan kullanıcının CartId değerini okuyabilmesi için HttpContextBase gerektirir.
İşte tam ShoppingCart sınıfı:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcMusicStore.Models
{
public partial class ShoppingCart
{
MusicStoreEntities storeDB = new MusicStoreEntities();
string ShoppingCartId { get; set; }
public const string CartSessionKey = "CartId";
public static ShoppingCart GetCart(HttpContextBase context)
{
var cart = new ShoppingCart();
cart.ShoppingCartId = cart.GetCartId(context);
return cart;
}
// Helper method to simplify shopping cart calls
public static ShoppingCart GetCart(Controller controller)
{
return GetCart(controller.HttpContext);
}
public void AddToCart(Album album)
{
// Get the matching cart and album instances
var cartItem = storeDB.Carts.SingleOrDefault(
c => c.CartId == ShoppingCartId
&& c.AlbumId == album.AlbumId);
if (cartItem == null)
{
// Create a new cart item if no cart item exists
cartItem = new Cart
{
AlbumId = album.AlbumId,
CartId = ShoppingCartId,
Count = 1,
DateCreated = DateTime.Now
};
storeDB.Carts.Add(cartItem);
}
else
{
// If the item does exist in the cart,
// then add one to the quantity
cartItem.Count++;
}
// Save changes
storeDB.SaveChanges();
}
public int RemoveFromCart(int id)
{
// Get the cart
var cartItem = storeDB.Carts.Single(
cart => cart.CartId == ShoppingCartId
&& cart.RecordId == id);
int itemCount = 0;
if (cartItem != null)
{
if (cartItem.Count > 1)
{
cartItem.Count--;
itemCount = cartItem.Count;
}
else
{
storeDB.Carts.Remove(cartItem);
}
// Save changes
storeDB.SaveChanges();
}
return itemCount;
}
public void EmptyCart()
{
var cartItems = storeDB.Carts.Where(
cart => cart.CartId == ShoppingCartId);
foreach (var cartItem in cartItems)
{
storeDB.Carts.Remove(cartItem);
}
// Save changes
storeDB.SaveChanges();
}
public List<Cart> GetCartItems()
{
return storeDB.Carts.Where(
cart => cart.CartId == ShoppingCartId).ToList();
}
public int GetCount()
{
// Get the count of each item in the cart and sum them up
int? count = (from cartItems in storeDB.Carts
where cartItems.CartId == ShoppingCartId
select (int?)cartItems.Count).Sum();
// Return 0 if all entries are null
return count ?? 0;
}
public decimal GetTotal()
{
// Multiply album price by count of that album to get
// the current price for each of those albums in the cart
// sum all album price totals to get the cart total
decimal? total = (from cartItems in storeDB.Carts
where cartItems.CartId == ShoppingCartId
select (int?)cartItems.Count *
cartItems.Album.Price).Sum();
return total ?? decimal.Zero;
}
public int CreateOrder(Order order)
{
decimal orderTotal = 0;
var cartItems = GetCartItems();
// Iterate over the items in the cart,
// adding the order details for each
foreach (var item in cartItems)
{
var orderDetail = new OrderDetail
{
AlbumId = item.AlbumId,
OrderId = order.OrderId,
UnitPrice = item.Album.Price,
Quantity = item.Count
};
// Set the order total of the shopping cart
orderTotal += (item.Count * item.Album.Price);
storeDB.OrderDetails.Add(orderDetail);
}
// Set the order's total to the orderTotal count
order.Total = orderTotal;
// Save the order
storeDB.SaveChanges();
// Empty the shopping cart
EmptyCart();
// Return the OrderId as the confirmation number
return order.OrderId;
}
// We're using HttpContextBase to allow access to cookies.
public string GetCartId(HttpContextBase context)
{
if (context.Session[CartSessionKey] == null)
{
if (!string.IsNullOrWhiteSpace(context.User.Identity.Name))
{
context.Session[CartSessionKey] =
context.User.Identity.Name;
}
else
{
// Generate a new random GUID using System.Guid class
Guid tempCartId = Guid.NewGuid();
// Send tempCartId back to client as a cookie
context.Session[CartSessionKey] = tempCartId.ToString();
}
}
return context.Session[CartSessionKey].ToString();
}
// When a user has logged in, migrate their shopping cart to
// be associated with their username
public void MigrateCart(string userName)
{
var shoppingCart = storeDB.Carts.Where(
c => c.CartId == ShoppingCartId);
foreach (Cart item in shoppingCart)
{
item.CartId = userName;
}
storeDB.SaveChanges();
}
}
}
Görünüm Modelleri
Alışveriş Sepeti Denetleyicimizin görünümlerine bazı karmaşık bilgiler iletmesi gerekir ve bu bilgiler Model nesnelerimizle düzgün bir şekilde eşlenmez. Modellerimizi görünümlerimize uyacak şekilde değiştirmek istemiyoruz; Model sınıfları, kullanıcı arabirimini değil etki alanımızı temsil etmelidir. Çözümlerden biri, Store Manager açılan bilgileriyle yaptığımız gibi ViewBag sınıfını kullanarak bilgileri Görünümlerimize geçirmek olabilir, ancak ViewBag aracılığıyla çok fazla bilgi geçirmek zorlaşır.
Bunun bir çözümü ViewModel desenini kullanmaktır. Bu düzeni kullanırken, belirli görünüm senaryolarımız için iyileştirilmiş ve görünüm şablonlarımız için gereken dinamik değerler/içerik için özellikleri kullanıma sunan kesin türe sahip sınıflar oluştururuz. Ardından denetleyici sınıflarımız bu görünüm için iyileştirilmiş sınıfları doldurabilir ve kullanmak üzere görünüm şablonumuza geçirebilir. Bu, görünüm şablonları içinde tür güvenliği, derleme zamanı denetimi ve düzenleyici IntelliSense'i etkinleştirir.
Alışveriş Sepeti denetleyicimizde kullanmak üzere iki Görünüm Modeli oluşturacağız: ShoppingCartViewModel kullanıcının alışveriş sepetinin içeriğini barındıracak ve kullanıcı sepetinden bir şey kaldırdığında onay bilgilerini görüntülemek için ShoppingCartRemoveViewModel kullanılacak.
Şimdi işleri düzenli tutmak için projemizin kökünde yeni bir ViewModels klasörü oluşturalım. Projeye sağ tıklayın, Ekle / Yeni Klasör'e tıklayın.
Klasörü ViewModels olarak adlandırın.
Ardından, ViewModels klasörüne ShoppingCartViewModel sınıfını ekleyin. İki özelliği vardır: Sepet öğelerinin listesi ve sepetteki tüm öğelerin toplam fiyatını tutan ondalık değer.
using System.Collections.Generic;
using MvcMusicStore.Models;
namespace MvcMusicStore.ViewModels
{
public class ShoppingCartViewModel
{
public List<Cart> CartItems { get; set; }
public decimal CartTotal { get; set; }
}
}
Şimdi Aşağıdaki dört özellik ile ShoppingCartRemoveViewModel'i ViewModels klasörüne ekleyin.
namespace MvcMusicStore.ViewModels
{
public class ShoppingCartRemoveViewModel
{
public string Message { get; set; }
public decimal CartTotal { get; set; }
public int CartCount { get; set; }
public int ItemCount { get; set; }
public int DeleteId { get; set; }
}
}
Alışveriş Sepeti Denetleyicisi
Alışveriş Sepeti denetleyicisinin üç ana amacı vardır: bir sepete ürün ekleme, sepetten öğeleri kaldırma ve sepetteki öğeleri görüntüleme. Yeni oluşturduğumuz üç sınıfı kullanacaktır: ShoppingCartViewModel, ShoppingCartRemoveViewModel ve ShoppingCart. StoreController ve StoreManagerController'da olduğu gibi, MusicStoreEntities örneğini barındıracak bir alan ekleyeceğiz.
Boş denetleyici şablonunu kullanarak projeye yeni bir Alışveriş Sepeti denetleyicisi ekleyin.
İşte tam ShoppingCart Controller. Dizin ve Denetleyici Ekle eylemleri çok tanıdık görünmelidir. Remove ve CartSummary denetleyici eylemleri, aşağıdaki bölümde ele alacağımız iki özel durumla ilgilenir.
using System.Linq;
using System.Web.Mvc;
using MvcMusicStore.Models;
using MvcMusicStore.ViewModels;
namespace MvcMusicStore.Controllers
{
public class ShoppingCartController : Controller
{
MusicStoreEntities storeDB = new MusicStoreEntities();
//
// GET: /ShoppingCart/
public ActionResult Index()
{
var cart = ShoppingCart.GetCart(this.HttpContext);
// Set up our ViewModel
var viewModel = new ShoppingCartViewModel
{
CartItems = cart.GetCartItems(),
CartTotal = cart.GetTotal()
};
// Return the view
return View(viewModel);
}
//
// GET: /Store/AddToCart/5
public ActionResult AddToCart(int id)
{
// Retrieve the album from the database
var addedAlbum = storeDB.Albums
.Single(album => album.AlbumId == id);
// Add it to the shopping cart
var cart = ShoppingCart.GetCart(this.HttpContext);
cart.AddToCart(addedAlbum);
// Go back to the main store page for more shopping
return RedirectToAction("Index");
}
//
// AJAX: /ShoppingCart/RemoveFromCart/5
[HttpPost]
public ActionResult RemoveFromCart(int id)
{
// Remove the item from the cart
var cart = ShoppingCart.GetCart(this.HttpContext);
// Get the name of the album to display confirmation
string albumName = storeDB.Carts
.Single(item => item.RecordId == id).Album.Title;
// Remove from cart
int itemCount = cart.RemoveFromCart(id);
// Display the confirmation message
var results = new ShoppingCartRemoveViewModel
{
Message = Server.HtmlEncode(albumName) +
" has been removed from your shopping cart.",
CartTotal = cart.GetTotal(),
CartCount = cart.GetCount(),
ItemCount = itemCount,
DeleteId = id
};
return Json(results);
}
//
// GET: /ShoppingCart/CartSummary
[ChildActionOnly]
public ActionResult CartSummary()
{
var cart = ShoppingCart.GetCart(this.HttpContext);
ViewData["CartCount"] = cart.GetCount();
return PartialView("CartSummary");
}
}
}
JQuery ile Ajax Güncelleştirmeler
Bir sonraki adımda ShoppingCartViewModel'e kesin olarak yazılan ve daha önce olduğu gibi aynı yöntemi kullanarak Liste Görünümü şablonunu kullanan bir Alışveriş Sepeti Dizini sayfası oluşturacağız.
Ancak, sepetten öğeleri kaldırmak için Html.ActionLink kullanmak yerine, bu görünümdeki HTML sınıfı RemoveLink'e sahip tüm bağlantılar için tıklama olayını "bağlamak" için jQuery kullanacağız. Bu tıklama olayı işleyicisi, formu göndermek yerine RemoveFromCart denetleyici eylemimize bir AJAX geri çağırması yapar. RemoveFromCart, jQuery geri çağırmamızın jQuery kullanarak ayrıştırdığı ve sayfada dört hızlı güncelleştirme gerçekleştirdiği JSON serileştirilmiş bir sonuç döndürür:
-
- Silinen albümü listeden kaldırır
-
- Üst bilgideki sepet sayısını Güncelleştirmeler
-
- Kullanıcıya bir güncelleştirme iletisi görüntüler
-
- Sepet toplam fiyatını Güncelleştirmeler
Kaldırma senaryosu Dizin görünümünde bir Ajax geri çağırması tarafından işlendiğinden RemoveFromCart eylemi için ek bir görünüme ihtiyacımız yoktur. /ShoppingCart/Index görünümünün tam kodu aşağıdadır:
@model MvcMusicStore.ViewModels.ShoppingCartViewModel
@{
ViewBag.Title = "Shopping Cart";
}
<script src="/Scripts/jquery-1.4.4.min.js"
type="text/javascript"></script>
<script type="text/javascript">
$(function () {
// Document.ready -> link up remove event handler
$(".RemoveLink").click(function () {
// Get the id from the link
var recordToDelete = $(this).attr("data-id");
if (recordToDelete != '') {
// Perform the ajax post
$.post("/ShoppingCart/RemoveFromCart", {"id": recordToDelete },
function (data) {
// Successful requests get here
// Update the page elements
if (data.ItemCount == 0) {
$('#row-' + data.DeleteId).fadeOut('slow');
} else {
$('#item-count-' + data.DeleteId).text(data.ItemCount);
}
$('#cart-total').text(data.CartTotal);
$('#update-message').text(data.Message);
$('#cart-status').text('Cart (' + data.CartCount + ')');
});
}
});
});
</script>
<h3>
<em>Review</em> your cart:
</h3>
<p class="button">
@Html.ActionLink("Checkout
>>", "AddressAndPayment", "Checkout")
</p>
<div id="update-message">
</div>
<table>
<tr>
<th>
Album Name
</th>
<th>
Price (each)
</th>
<th>
Quantity
</th>
<th></th>
</tr>
@foreach (var item in
Model.CartItems)
{
<tr id="row-@item.RecordId">
<td>
@Html.ActionLink(item.Album.Title,
"Details", "Store", new { id = item.AlbumId }, null)
</td>
<td>
@item.Album.Price
</td>
<td id="item-count-@item.RecordId">
@item.Count
</td>
<td>
<a href="#" class="RemoveLink"
data-id="@item.RecordId">Remove
from cart</a>
</td>
</tr>
}
<tr>
<td>
Total
</td>
<td>
</td>
<td>
</td>
<td id="cart-total">
@Model.CartTotal
</td>
</tr>
</table>
Bunu test etmek için alışveriş sepetimize ürün ekleyebilmemiz gerekiyor. Mağaza Ayrıntıları görünümümüzü bir "Sepete ekle" düğmesi içerecek şekilde güncelleştireceğiz. Bu aşamadayken, bu görünümü en son güncelleştirdiğimizden beri eklediğimiz Albüm ek bilgilerinden bazılarını ekleyebiliriz: Tarz, Sanatçı, Fiyat ve Albüm Resmi. Güncelleştirilmiş Mağaza Ayrıntıları görünüm kodu aşağıda gösterildiği gibi görünür.
@model MvcMusicStore.Models.Album
@{
ViewBag.Title = "Album - " + Model.Title;
}
<h2>@Model.Title</h2>
<p>
<img alt="@Model.Title"
src="@Model.AlbumArtUrl" />
</p>
<div id="album-details">
<p>
<em>Genre:</em>
@Model.Genre.Name
</p>
<p>
<em>Artist:</em>
@Model.Artist.Name
</p>
<p>
<em>Price:</em>
@String.Format("{0:F}",
Model.Price)
</p>
<p class="button">
@Html.ActionLink("Add to
cart", "AddToCart",
"ShoppingCart", new { id = Model.AlbumId }, "")
</p>
</div>
Şimdi mağazaya tıklayabilir ve alışveriş sepetimize albüm ekleme ve kaldırma test edebiliriz. Uygulamayı çalıştırın ve Mağaza Dizini'ne göz atın.
Ardından, albüm listesini görüntülemek için bir Tarz'a tıklayın.
Bir Albüm başlığına tıkladığınızda artık "Sepete ekle" düğmesi de dahil olmak üzere güncelleştirilmiş Albüm Ayrıntıları görünümümüz gösterilir.
"Sepete ekle" düğmesine tıklanması, alışveriş sepeti özet listesini içeren Alışveriş Sepeti Dizini görünümümüzü gösterir.
Alışveriş sepetinizi yükledikten sonra Alışveriş sepetinize yönelik Ajax güncelleştirmesini görmek için Sepetten kaldır bağlantısına tıklayabilirsiniz.
Kayıtlı olmayan kullanıcıların sepetlerine ürün eklemesine olanak tanıyan çalışan bir alışveriş sepeti oluşturmuş olduk. Aşağıdaki bölümde, kaydolmalarına ve ödeme işlemini tamamlamalarına izin vereceğiz.