Share via


Bölüm 9: Kayıt ve Kasa İşlemleri

tarafından Jon Galloway

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 9, Kayıt ve Ödeme'ye değinmektedir.

Bu bölümde, alışveriş yapanın adresini ve ödeme bilgilerini toplayacak bir CheckoutController oluşturacağız. Kullanıcıların kullanıma almadan önce sitemize kaydolmasını zorunlu kılarız, bu nedenle bu denetleyici için yetkilendirme gerekir.

Kullanıcılar, "Alışverişi Tamamla" düğmesine tıklayarak alışveriş sepetlerinden ödeme işlemine gider.

Kullanıma Alma düğmesinin kırmızı okla vurgulandığı ödeme görünümünü gösteren Müzik Mağazası penceresinin ekran görüntüsü.

Kullanıcı oturum açmamışsa, oturum açması istenir.

Kullanıcı adı ve Parola alanlarıyla oturum açma görünümünü gösteren Müzik Deposu penceresinin ekran görüntüsü.

Oturum başarıyla açıldıktan sonra kullanıcıya Adres ve Ödeme görünümü gösterilir.

Adres ve ödeme görünümünün, sevkiyat adresi ve ödeme bilgilerini toplama alanlarının gösterildiği Müzik Mağazası penceresinin ekran görüntüsü.

Formu doldurup siparişi gönderdikten sonra sipariş onay ekranı gösterilir.

Kullanıcıya siparişin tamamlandığını bildiren alışverişi tamamlama görünümünü gösteren Müzik Mağazası penceresinin ekran görüntüsü.

Mevcut olmayan bir siparişi veya size ait olmayan bir siparişi görüntülemeye çalıştığınızda Hata görünümü gösterilir.

Kullanıcı başka bir kişinin siparişini veya kurgusal bir siparişi görüntülemeye çalıştığında hata görünümünü gösteren Müzik Mağazası penceresinin ekran görüntüsü.

Alışveriş Sepetini Geçirme

Alışveriş işlemi anonim olsa da, kullanıcı Kullanıma Al düğmesine tıkladığında kaydolması ve oturum açması gerekir. Kullanıcılar, alışveriş sepeti bilgilerini ziyaretler arasında tutmamızı bekler, bu nedenle kayıt veya oturum açma işlemlerini tamamlayan bir kullanıcıyla alışveriş sepeti bilgilerini ilişkilendirmemiz gerekir.

ShoppingCart sınıfımız zaten geçerli sepetteki tüm öğeleri bir kullanıcı adıyla ilişkilendirecek bir yönteme sahip olduğundan, bunu yapmak gerçekten çok basittir. Yalnızca bir kullanıcı kaydı veya oturum açmayı tamamladığında bu yöntemi çağırmamız gerekir.

Üyelik ve Yetkilendirmeyi ayarlarken eklediğimiz AccountController sınıfını açın. MvcMusicStore.Models'e başvuran bir using deyimi ekleyin ve ardından aşağıdaki MigrateShoppingCart yöntemini ekleyin:

private void MigrateShoppingCart(string UserName)
{
    // Associate shopping cart items with logged-in user
    var cart = ShoppingCart.GetCart(this.HttpContext);
 
    cart.MigrateCart(UserName);
    Session[ShoppingCart.CartSessionKey] = UserName;
}

Ardından, aşağıda gösterildiği gibi Kullanıcı doğrulandıktan sonra MigrateShoppingCart'ı çağırmak için LogOn gönderi eylemini değiştirin:

//
// POST: /Account/LogOn
[HttpPost]
 public ActionResult LogOn(LogOnModel model, string returnUrl)
 {
    if (ModelState.IsValid)
    {
        if (Membership.ValidateUser(model.UserName, model.Password))
        {
            MigrateShoppingCart(model.UserName);
                    
            FormsAuthentication.SetAuthCookie(model.UserName,
                model.RememberMe);
            if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1
                && returnUrl.StartsWith("/")
                && !returnUrl.StartsWith("//") &&
                !returnUrl.StartsWith("/\\"))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }
        else
        {
            ModelState.AddModelError("", "The user name or password provided is incorrect.");
        }
    }
    // If we got this far, something failed, redisplay form
    return View(model);
 }

Kullanıcı hesabı başarıyla oluşturulduktan hemen sonra Kayıt sonrası eyleminde de aynı değişikliği yapın:

//
// POST: /Account/Register
[HttpPost]
 public ActionResult Register(RegisterModel model)
 {
    if (ModelState.IsValid)
    {
        // Attempt to register the user
        MembershipCreateStatus createStatus;
        Membership.CreateUser(model.UserName, model.Password, model.Email, 
               "question", "answer", true, null, out
               createStatus);
 
        if (createStatus == MembershipCreateStatus.Success)
        {
            MigrateShoppingCart(model.UserName);
                    
            FormsAuthentication.SetAuthCookie(model.UserName, false /*
                  createPersistentCookie */);
            return RedirectToAction("Index", "Home");
        }
        else
        {
            ModelState.AddModelError("", ErrorCodeToString(createStatus));
        }
    }
    // If we got this far, something failed, redisplay form
    return View(model);
 }

Hepsi bu kadar- artık başarılı bir kayıt veya oturum açma işleminden sonra anonim bir alışveriş sepeti otomatik olarak bir kullanıcı hesabına aktarılacak.

CheckoutController Oluşturma

Denetleyiciler klasörüne sağ tıklayın ve Boş denetleyici şablonunu kullanarak CheckoutController adlı projeye yeni bir Denetleyici ekleyin.

Denetleyici adı alanının Kullanıma Alma Denetleyicisi metniyle doldurulduğu Denetleyici Ekle penceresinin ekran görüntüsü.

İlk olarak, kullanıcıların kullanıma almadan önce kaydolmasını istemek için Denetleyici sınıfı bildiriminin üzerine Authorize özniteliğini ekleyin:

namespace MvcMusicStore.Controllers
{
    [Authorize]
    public class CheckoutController : Controller

Not: Bu, daha önce StoreManagerController'da yaptığımız değişikliğe benzer, ancak bu durumda Kullanıcının Yönetici rolünde olması için Authorize özniteliği gerekir. Kullanıma Alma Denetleyicisi'nde kullanıcının oturum açmasını zorunlu kılıyoruz ancak yönetici olmasını istemiyoruz.

Kolaylık olması için bu öğreticide ödeme bilgileriyle ilgilenmeyeceğiz. Bunun yerine kullanıcıların tanıtım kodu kullanarak kullanıma almalarına izin veririz. Bu promosyon kodunu PromoCode adlı bir sabit kullanarak depolayacağız.

StoreController'da olduğu gibi, storeDB adlı MusicStoreEntities sınıfının bir örneğini barındıracak bir alan bildireceğiz. MusicStoreEntities sınıfından yararlanmak için MvcMusicStore.Models ad alanı için bir using deyimi eklememiz gerekir. Kullanıma Alma denetleyicimizin üst kısmında aşağıda görünür.

using System;
using System.Linq;
using System.Web.Mvc;
using MvcMusicStore.Models;
 
namespace MvcMusicStore.Controllers
{
    [Authorize]
    public class CheckoutController : Controller
    {
        MusicStoreEntities storeDB = new MusicStoreEntities();
        const string PromoCode = "FREE";

CheckoutController aşağıdaki denetleyici eylemlerine sahip olacaktır:

AddressAndPayment (GET yöntemi), kullanıcının bilgilerini girmesine izin veren bir form görüntüler.

AddressAndPayment (POST yöntemi), girişi doğrular ve sırayı işler.

Kullanıcı kullanıma alma işlemini başarıyla tamamladıktan sonra Tamamlandı ifadesi gösterilir. Bu görünüm, onay olarak kullanıcının sipariş numarasını içerir.

İlk olarak, Dizin denetleyicisi eylemini (denetleyiciyi oluştururken oluşturulan) AddressAndPayment olarak yeniden adlandıralım. Bu denetleyici eylemi yalnızca kullanıma alma formunu görüntüler, bu nedenle herhangi bir model bilgisi gerektirmez.

//
// GET: /Checkout/AddressAndPayment
public ActionResult AddressAndPayment()
{
    return View();
}

AddressAndPayment POST yöntemimiz, StoreManagerController'da kullandığımız deseni izler: form gönderimini kabul etmeye ve siparişi tamamlamaya çalışır ve başarısız olursa formu yeniden görüntüler.

Form girişini doğruladıktan sonra Sipariş için doğrulama gereksinimlerimizi karşılıyorsa PromoCode form değerini doğrudan denetleyeceğiz. Her şeyin doğru olduğunu varsayarsak, güncelleştirilmiş bilgileri siparişle birlikte kaydeder, ShoppingCart nesnesine sipariş işlemini tamamlamasını söyler ve Tamamla eylemine yönlendiririz.

//
// POST: /Checkout/AddressAndPayment
[HttpPost]
public ActionResult AddressAndPayment(FormCollection values)
{
    var order = new Order();
    TryUpdateModel(order);
 
    try
    {
        if (string.Equals(values["PromoCode"], PromoCode,
            StringComparison.OrdinalIgnoreCase) == false)
        {
            return View(order);
        }
        else
        {
            order.Username = User.Identity.Name;
            order.OrderDate = DateTime.Now;
 
            //Save Order
            storeDB.Orders.Add(order);
            storeDB.SaveChanges();
            //Process the order
            var cart = ShoppingCart.GetCart(this.HttpContext);
            cart.CreateOrder(order);
 
            return RedirectToAction("Complete",
                new { id = order.OrderId });
        }
    }
    catch
    {
        //Invalid - redisplay with errors
        return View(order);
    }
}

Kullanıma alma işlemi başarıyla tamamlandıktan sonra kullanıcılar Tam denetleyici eylemine yönlendirilir. Bu eylem, sipariş numarasını onay olarak göstermeden önce siparişin gerçekten oturum açmış kullanıcıya ait olduğunu doğrulamak için basit bir denetim gerçekleştirir.

//
// GET: /Checkout/Complete
public ActionResult Complete(int id)
{
    // Validate customer owns this order
    bool isValid = storeDB.Orders.Any(
        o => o.OrderId == id &&
        o.Username == User.Identity.Name);
 
    if (isValid)
    {
        return View(id);
    }
    else
    {
        return View("Error");
    }
}

Not: Proje başlatıldığında Hata görünümü bizim için /Views/Shared klasöründe otomatik olarak oluşturuldu.

CheckoutController kodunun tamamı aşağıdaki gibidir:

using System;
using System.Linq;
using System.Web.Mvc;
using MvcMusicStore.Models;
 
namespace MvcMusicStore.Controllers
{
    [Authorize]
    public class CheckoutController : Controller
    {
        MusicStoreEntities storeDB = new MusicStoreEntities();
        const string PromoCode = "FREE";
        //
        // GET: /Checkout/AddressAndPayment
        public ActionResult AddressAndPayment()
        {
            return View();
        }
        //
        // POST: /Checkout/AddressAndPayment
        [HttpPost]
        public ActionResult AddressAndPayment(FormCollection values)
        {
            var order = new Order();
            TryUpdateModel(order);
 
            try
            {
                if (string.Equals(values["PromoCode"], PromoCode,
                    StringComparison.OrdinalIgnoreCase) == false)
                {
                    return View(order);
                }
                else
                {
                    order.Username = User.Identity.Name;
                    order.OrderDate = DateTime.Now;
 
                    //Save Order
                    storeDB.Orders.Add(order);
                    storeDB.SaveChanges();
                    //Process the order
                    var cart = ShoppingCart.GetCart(this.HttpContext);
                    cart.CreateOrder(order);
 
                    return RedirectToAction("Complete",
                        new { id = order.OrderId });
                }
            }
            catch
            {
                //Invalid - redisplay with errors
                return View(order);
            }
        }
        //
        // GET: /Checkout/Complete
        public ActionResult Complete(int id)
        {
            // Validate customer owns this order
            bool isValid = storeDB.Orders.Any(
                o => o.OrderId == id &&
                o.Username == User.Identity.Name);
 
            if (isValid)
            {
                return View(id);
            }
            else
            {
                return View("Error");
            }
        }
    }
}

AddressAndPayment görünümünü ekleme

Şimdi AddressAndPayment görünümünü oluşturalım. AddressAndPayment denetleyici eylemlerinden birine sağ tıklayın ve aşağıda gösterildiği gibi, kesinlikle Sipariş olarak yazılan ve Düzenle şablonunu kullanan AddressAndPayment adlı bir görünüm ekleyin.

Görünüm adı alanı, Görünüm oluştur onay kutusu ve Model sınıfı ile İskele açılan listelerinin kırmızıyla vurgulandığı Görünüm Ekle penceresinin ekran görüntüsü.

Bu görünümde StoreManagerEdit görünümünü oluştururken incelediğimiz iki teknik kullanılır:

  • Sipariş modelinin form alanlarını görüntülemek için Html.EditorForModel() kullanacağız
  • Doğrulama özniteliklerine sahip bir Order sınıfını kullanarak doğrulama kuralları kullanacağız

Başlangıç olarak form kodunu Html.EditorForModel() kullanacak şekilde güncelleştireceğiz ve ardından Promosyon Kodu için ek bir metin kutusu ekleyeceğiz. AddressAndPayment görünümünün tam kodu aşağıda gösterilmiştir.

@model MvcMusicStore.Models.Order
@{
    ViewBag.Title = "Address And Payment";
}
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")"
type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"
type="text/javascript"></script>
@using (Html.BeginForm()) {
    
    <h2>Address And Payment</h2>
    <fieldset>
        <legend>Shipping Information</legend>
        @Html.EditorForModel()
    </fieldset>
    <fieldset>
        <legend>Payment</legend>
        <p>We're running a promotion: all music is free 
            with the promo code: "FREE"</p>
        <div class="editor-label">
            @Html.Label("Promo Code")
        </div>
        <div class="editor-field">
            @Html.TextBox("PromoCode")
        </div>
    </fieldset>
    
    <input type="submit" value="Submit Order" />
}

Sipariş için doğrulama kuralları tanımlama

Artık görünümümüz ayarlandığından, Daha önce Albüm modeli için yaptığımız gibi Sipariş modelimiz için doğrulama kurallarını ayarlayacağız. Models klasörüne sağ tıklayın ve Order adlı bir sınıf ekleyin. Daha önce Albüm için kullandığımız doğrulama özniteliklerine ek olarak, kullanıcının e-posta adresini doğrulamak için Normal İfade de kullanacağız.

using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
 
namespace MvcMusicStore.Models
{
    [Bind(Exclude = "OrderId")]
    public partial class Order
    {
        [ScaffoldColumn(false)]
        public int OrderId { get; set; }
        [ScaffoldColumn(false)]
        public System.DateTime OrderDate { get; set; }
        [ScaffoldColumn(false)]
        public string Username { get; set; }
        [Required(ErrorMessage = "First Name is required")]
        [DisplayName("First Name")]
        [StringLength(160)]
        public string FirstName { get; set; }
        [Required(ErrorMessage = "Last Name is required")]
        [DisplayName("Last Name")]
        [StringLength(160)]
        public string LastName { get; set; }
        [Required(ErrorMessage = "Address is required")]
        [StringLength(70)]
        public string Address { get; set; }
        [Required(ErrorMessage = "City is required")]
        [StringLength(40)]
        public string City { get; set; }
        [Required(ErrorMessage = "State is required")]
        [StringLength(40)]
        public string State { get; set; }
        [Required(ErrorMessage = "Postal Code is required")]
        [DisplayName("Postal Code")]
        [StringLength(10)]
        public string PostalCode { get; set; }
        [Required(ErrorMessage = "Country is required")]
        [StringLength(40)]
        public string Country { get; set; }
        [Required(ErrorMessage = "Phone is required")]
        [StringLength(24)]
        public string Phone { get; set; }
        [Required(ErrorMessage = "Email Address is required")]
        [DisplayName("Email Address")]
       
        [RegularExpression(@"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}",
            ErrorMessage = "Email is is not valid.")]
        [DataType(DataType.EmailAddress)]
        public string Email { get; set; }
        [ScaffoldColumn(false)]
        public decimal Total { get; set; }
        public List<OrderDetail> OrderDetails { get; set; }
    }
}

Formu eksik veya geçersiz bilgilerle gönderme girişiminde artık istemci tarafı doğrulaması kullanılarak hata iletisi gösterilir.

Telefon ve e-posta alanlarında geçersiz bilgiler içeren adres ve ödeme görünümünü gösteren Müzik Mağazası penceresinin ekran görüntüsü.

Tamam, ödeme süreci için zor işlerin çoğunu yaptık; Bitirmemiz gereken birkaç şey var. İki basit görünüm eklememiz ve oturum açma işlemi sırasında sepet bilgilerinin teslimini yapmamız gerekiyor.

Kullanıma Alma Tamamlandı görünümünü ekleme

Yalnızca Sipariş Kimliğini görüntülemesi gerektiğinden, Kullanıma Alma Tamamlandı görünümü oldukça basittir. Denetleyiciyi tamamla eylemine sağ tıklayın ve tam olarak int olarak yazılan Complete adlı bir görünüm ekleyin.

Görünüm adı alanının ve Model sınıfı açılan listesinin kırmızı dikdörtgenler içinde vurgulandığı Görünüm Ekle penceresinin ekran görüntüsü.

Şimdi aşağıda gösterildiği gibi Sipariş Kimliğini görüntülemek için görünüm kodunu güncelleştireceğiz.

@model int
@{
    ViewBag.Title = "Checkout Complete";
}
<h2>Checkout Complete</h2>
<p>Thanks for your order! Your order number is: @Model</p>
<p>How about shopping for some more music in our 
    @Html.ActionLink("store",
"Index", "Home")
</p>

Hata görünümünü güncelleştirme

Varsayılan şablon, sitenin başka bir yerinde yeniden kullanılabilmesi için Paylaşılan görünümler klasöründe bir Hata görünümü içerir. Bu Hata görünümü çok basit bir hata içeriyor ve site düzenimizi kullanmadığından güncelleştireceğiz.

Bu genel bir hata sayfası olduğundan içerik çok basittir. Kullanıcı eylemini yeniden denemek istiyorsa, geçmişteki bir önceki sayfaya gitmek için bir ileti ve bağlantı ekleyeceğiz.

@{
    ViewBag.Title = "Error";
}
 
<h2>Error</h2>
 
<p>We're sorry, we've hit an unexpected error.
    <a href="javascript:history.go(-1)">Click here</a> 
    if you'd like to go back and try that again.</p>