MVC步步深入:10
当用户购物完成以后就需要进行付款了,但是我们前面说到了,我们允许没有登陆的用户购买,所以在付款的时候需要验证是否已经登陆。
如果登陆了就好,但是没有登陆就需要进行注册了。当用户注册以后,因为开始是匿名购买,所以需要合并订单到现在的用户中来:
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;
}
下面是登录函数:
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(model.UserName, model.Password))
{
MigrateShoppingCart(model.UserName);
FormsService.SignIn(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(returnUrl))
{
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);
}
以及注册函数:
[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
MembershipCreateStatus createStatus =
MembershipService.CreateUser(model.UserName, model.Password, model.Email);
if (createStatus == MembershipCreateStatus.Success)
{
MigrateShoppingCart(model.UserName);
FormsService.SignIn(model.UserName, false /* createPersistentCookie
*/);
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("", AccountValidation.ErrorCodeToString(createStatus));
}
}
// If we got this far, something failed, redisplay form
ViewBag.PasswordLength = MembershipService.MinPasswordLength;
return View(model);
}
紧接着的付款需要使用付款控制器,首先自然是创建一个啦:
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.AddToOrders(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");
}
}
最后就是添加视图,这个很简单,大家都会,不过因为需要验证,所以,我们复习下验证的特性:
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 OrderDetails { get; set; }
}
}
最后就是更新一下错误提示页面:
@{
ViewBag.Title = "Error";
}
Error
We're sorry, we've hit an unexpected error.
Click here
if you'd like to go back and try that again.
现在我们的音乐商店基本上已经完工了,最后还一步骤就是添加导航。
接下来,添加信息提示的局部页面:
//
// GET: /ShoppingCart/CartSummary
[ChildActionOnly]
public ActionResult CartSummary()
{
var cart = ShoppingCart.GetCart(this.HttpContext);
ViewData["CartCount"] = cart.GetCount();
return PartialView("CartSummary");
}
注意到这个ChildActionOnly没?他是必须的,这样页面才知道这一款相当于一个局部的模板。
修改前台:
@Html.ActionLink("Cart
(" + ViewData["CartCount"] + ")",
"Index",
"ShoppingCart",
new { id = "cart-status" })
同时我们还可以通过
@Html.RenderAction("CartSummary", "ShoppingCart")在页面的其他地方来显示这个小局部页面。
接下来再创建菜单栏,如图:
/
// GET: /Store/GenreMenu
[ChildActionOnly]
public ActionResult GenreMenu()
{
var genres = storeDB.Genres.ToList();
return PartialView(genres);
}
然后更新总的模板:
@{Html.RenderAction("GenreMenu",
"Store");}
@RenderBody()
@model MvcMusicStore.Models.Genre
@{
ViewBag.Title = "Browse Albums";
}
@Model.Name Albums
@foreach (var album in Model.Albums)
{
-
@album.Title
}
下面我们再提出一个小小的要求,那就是置顶畅销的专辑。
更新一下Album类:
public virtual Genre Genre { get; set;
}
public virtual Artist Artist { get; set; }
public virtual List
OrderDetails { get; set; }
}
}
然后对于HomeController做出如下的修改:
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using MvcMusicStore.Models;
namespace MvcMusicStore.Controllers
{
public class HomeController : Controller
{
//
// GET: /Home/
MusicStoreEntities storeDB = new MusicStoreEntities();
public ActionResult Index()
{
// Get most popular albums
var albums = GetTopSellingAlbums(5);
return View(albums);
}
private List GetTopSellingAlbums(int count)
{
// Group the order details by album and return
// the albums with the highest count
return storeDB.Albums
.OrderByDescending(a => a.OrderDetails.Count())
.Take(count)
.ToList();
}
}
}
最后就是更新视图:让他能够正确显示这些专辑
@model List@{ ViewBag.Title = "ASP.NET MVC Music Store"; } Fresh off the grill
@foreach (var album in Model) {
@album.Title }
这就是最后的成果,帅吧~呜哈哈,其实MVC的功能比这个更加强大~我们以后会慢慢说来,这算是第二个阶段结束了,新的“冒险”开始了~开船吧~