Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
oleh Jon Galloway
MVC Music Store adalah aplikasi tutorial yang memperkenalkan dan menjelaskan langkah demi langkah cara menggunakan ASP.NET MVC dan Visual Studio untuk pengembangan web.
MVC Music Store adalah implementasi penyimpanan sampel ringan yang menjual album musik secara online, dan mengimplementasikan administrasi situs dasar, rincian masuk pengguna, dan fungsionalitas ke cart belanja.
Seri tutorial ini merinci semua langkah yang diambil untuk membangun aplikasi sampel MVC Music Store ASP.NET. Bagian 9 mencakup Pendaftaran dan Checkout.
Di bagian ini, kami akan membuat CheckoutController yang akan mengumpulkan alamat pembeli dan informasi pembayaran. Kami akan mengharuskan pengguna untuk mendaftar dengan situs kami sebelum check out, sehingga pengontrol ini akan memerlukan otorisasi.
Pengguna akan menavigasi ke proses checkout dari ke cart belanja mereka dengan mengeklik tombol "Checkout".
Jika pengguna tidak masuk, mereka akan diminta.
Setelah berhasil masuk, pengguna kemudian ditampilkan tampilan Alamat dan Pembayaran.
Setelah mengisi formulir dan mengirimkan pesanan, mereka akan ditampilkan layar konfirmasi pesanan.
Mencoba melihat urutan yang tidak ada atau urutan yang bukan milik Anda akan menampilkan tampilan Kesalahan.
Memigrasikan Kemudi Belanja
Meskipun proses belanja bersifat anonim, ketika pengguna mengklik tombol Checkout, mereka akan diminta untuk mendaftar dan masuk. Pengguna akan mengharapkan bahwa kami akan mempertahankan informasi keliaran belanja mereka di antara kunjungan, jadi kami perlu mengaitkan informasi kelir belanja dengan pengguna ketika mereka menyelesaikan pendaftaran atau masuk.
Ini sebenarnya sangat mudah dilakukan, karena kelas ShoppingCart kami sudah memiliki metode yang akan mengaitkan semua item di keranjang saat ini dengan nama pengguna. Kami hanya perlu memanggil metode ini ketika pengguna menyelesaikan pendaftaran atau masuk.
Buka kelas AccountController yang kami tambahkan saat menyiapkan Keanggotaan dan Otorisasi. Tambahkan pernyataan penggunaan yang mereferensikan MvcMusicStore.Models, lalu tambahkan metode MigrateShoppingCart berikut:
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;
}
Selanjutnya, ubah tindakan posting LogOn untuk memanggil MigrateShoppingCart setelah pengguna divalidasi, seperti yang ditunjukkan di bawah ini:
//
// 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);
}
Lakukan perubahan yang sama pada tindakan Daftarkan postingan, segera setelah akun pengguna berhasil dibuat:
//
// 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);
}
Itu saja - sekarang ke cart belanja anonim akan secara otomatis ditransfer ke akun pengguna setelah pendaftaran atau login berhasil.
Membuat CheckoutController
Klik kanan pada folder Pengontrol dan tambahkan Pengontrol baru ke proyek bernama CheckoutController menggunakan templat Pengontrol kosong.
Pertama, tambahkan atribut Otorisasi di atas deklarasi kelas Pengontrol untuk mengharuskan pengguna mendaftar sebelum checkout:
namespace MvcMusicStore.Controllers
{
[Authorize]
public class CheckoutController : Controller
Catatan: Ini mirip dengan perubahan yang sebelumnya kami lakukan pada StoreManagerController, tetapi dalam hal ini atribut Otorisasi mengharuskan pengguna berada dalam peran Administrator. Di Pengontrol Checkout, kami mengharuskan pengguna masuk tetapi tidak mengharuskan mereka menjadi administrator.
Demi kesederhanaan, kami tidak akan berurusan dengan informasi pembayaran dalam tutorial ini. Sebaliknya, kami mengizinkan pengguna untuk memeriksa menggunakan kode promosi. Kami akan menyimpan kode promosi ini menggunakan konstanta bernama PromoCode.
Seperti di StoreController, kami akan mendeklarasikan bidang untuk menyimpan instans kelas MusicStoreEntities, bernama storeDB. Untuk menggunakan kelas MusicStoreEntities, kita perlu menambahkan pernyataan penggunaan untuk namespace layanan MvcMusicStore.Models. Bagian atas pengontrol Checkout kami muncul di bawah ini.
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 akan memiliki tindakan pengontrol berikut:
AddressAndPayment (metode GET) akan menampilkan formulir untuk memungkinkan pengguna memasukkan informasi mereka.
AddressAndPayment (metode POST) akan memvalidasi input dan memproses pesanan.
Selesai akan ditampilkan setelah pengguna berhasil menyelesaikan proses pembayaran. Tampilan ini akan menyertakan nomor pesanan pengguna, sebagai konfirmasi.
Pertama, mari kita ganti nama tindakan Pengontrol indeks (yang dihasilkan saat kita membuat pengontrol) menjadi AddressAndPayment. Tindakan pengontrol ini hanya menampilkan formulir checkout, sehingga tidak memerlukan informasi model apa pun.
//
// GET: /Checkout/AddressAndPayment
public ActionResult AddressAndPayment()
{
return View();
}
Metode POST AddressAndPayment kami akan mengikuti pola yang sama dengan yang kami gunakan di StoreManagerController: metode tersebut akan mencoba menerima pengiriman formulir dan menyelesaikan pesanan, dan akan menampilkan kembali formulir jika gagal.
Setelah memvalidasi input formulir memenuhi persyaratan validasi kami untuk Pesanan, kami akan memeriksa nilai formulir PromoCode secara langsung. Dengan asumsi semuanya benar, kami akan menyimpan informasi yang diperbarui dengan pesanan, memberi tahu objek ShoppingCart untuk menyelesaikan proses pesanan, dan mengalihkan ke tindakan Selesai.
//
// 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);
}
}
Setelah berhasil menyelesaikan proses checkout, pengguna akan diarahkan ke tindakan Selesaikan pengontrol. Tindakan ini akan melakukan pemeriksaan sederhana untuk memvalidasi bahwa pesanan memang milik pengguna yang masuk sebelum menunjukkan nomor pesanan sebagai konfirmasi.
//
// 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");
}
}
Catatan: Tampilan Kesalahan secara otomatis dibuat untuk kami di folder /Views/Shared saat kami memulai proyek.
Kode CheckoutController lengkap adalah sebagai berikut:
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");
}
}
}
}
Menambahkan tampilan AddressAndPayment
Sekarang, mari kita buat tampilan AddressAndPayment. Klik kanan pada salah satu tindakan pengontrol AddressAndPayment dan tambahkan tampilan bernama AddressAndPayment yang sangat diketik sebagai Pesanan dan menggunakan templat Edit, seperti yang ditunjukkan di bawah ini.
Tampilan ini akan menggunakan dua teknik yang kita lihat saat membangun tampilan StoreManagerEdit:
- Kami akan menggunakan Html.EditorForModel() untuk menampilkan bidang formulir untuk model Pesanan
- Kami akan memanfaatkan aturan validasi menggunakan kelas Pesanan dengan atribut validasi
Kita akan mulai dengan memperbarui kode formulir untuk menggunakan Html.EditorForModel(), diikuti dengan kotak teks tambahan untuk Kode Promo. Kode lengkap untuk tampilan AddressAndPayment ditunjukkan di bawah ini.
@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" />
}
Menentukan aturan validasi untuk Pesanan
Sekarang setelah tampilan kami disiapkan, kami akan menyiapkan aturan validasi untuk model Pesanan kami seperti yang kami lakukan sebelumnya untuk model Album. Klik kanan pada folder Model dan tambahkan kelas bernama Order. Selain atribut validasi yang kami gunakan sebelumnya untuk Album, kami juga akan menggunakan Ekspresi Reguler untuk memvalidasi alamat email pengguna.
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; }
}
}
Mencoba mengirimkan formulir dengan informasi yang hilang atau tidak valid sekarang akan menampilkan pesan kesalahan menggunakan validasi sisi klien.
Oke, kami telah melakukan sebagian besar kerja keras untuk proses checkout; kita hanya memiliki beberapa peluang dan berakhir untuk menyelesaikan. Kita perlu menambahkan dua tampilan sederhana, dan kita perlu mengurus penyerahan informasi ke cart selama proses login.
Menambahkan tampilan Selesai Checkout
Tampilan Checkout Complete cukup sederhana, karena hanya perlu menampilkan ID Pesanan. Klik kanan pada tindakan Selesaikan pengontrol dan tambahkan tampilan bernama Lengkap yang sangat diketik sebagai int.
Sekarang kita akan memperbarui kode tampilan untuk menampilkan ID Pesanan, seperti yang ditunjukkan di bawah ini.
@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>
Memperbarui tampilan Kesalahan
Templat default menyertakan tampilan Kesalahan di folder Tampilan bersama sehingga dapat digunakan kembali di tempat lain di situs. Tampilan Kesalahan ini berisi kesalahan yang sangat sederhana dan tidak menggunakan Tata Letak situs kami, jadi kami akan memperbaruinya.
Karena ini adalah halaman kesalahan umum, kontennya sangat sederhana. Kami akan menyertakan pesan dan tautan untuk menavigasi ke halaman sebelumnya dalam riwayat jika pengguna ingin mencoba kembali tindakan mereka.
@{
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>