Merge pull request #1 from aspnet/ControllerUpdates

Everything but the kitchen async... (Updates to how Music Store controllers use data)
    
Specifically:
    - Dispose contexts
    - Use async wherever possible
    - Stop using initializers (currently hard-coded to drop and recreate each run)
    - Some general cleanup
    - Stop using AttachDbFilename
    
Not included here:
    - No major changes to app structure
    - No major changes to data model
    - No major changes to error handling, concurrency, etc.
This commit is contained in:
Arthur Vickers 2014-01-29 08:46:43 -08:00
commit b8f5824114
15 changed files with 4207 additions and 1022 deletions

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Sake" version="0.2" />
</packages>

View File

@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MusicStore.k10", "src\Music
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MusicStore.net45", "src\MusicStore\MusicStore.net45.csproj", "{9C8A2D1F-D430-46DF-8F00-39E378EC8FB2}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MusicStore.net45", "src\MusicStore\MusicStore.net45.csproj", "{9C8A2D1F-D430-46DF-8F00-39E378EC8FB2}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{44621553-AA7D-4893-8834-79582A7D8348}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU

View File

@ -1,46 +1,54 @@
using Microsoft.AspNet.Identity; using System.Configuration;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework; using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using MvcMusicStore.Models; using MvcMusicStore.Models;
using Owin; using Owin;
using System.Configuration;
using System.Threading.Tasks;
namespace MvcMusicStore namespace MvcMusicStore
{ {
public partial class Startup public partial class Startup
{ {
private const string RoleName = "Administrator";
public void ConfigureApp(IAppBuilder app) public void ConfigureApp(IAppBuilder app)
{ {
System.Data.Entity.Database.SetInitializer(new MvcMusicStore.Models.SampleData()); using (var context = new MusicStoreEntities())
CreateAdminUser();
}
private async void CreateAdminUser()
{
string _username = ConfigurationManager.AppSettings["DefaultAdminUsername"];
string _password = ConfigurationManager.AppSettings["DefaultAdminPassword"];
string _role = "Administrator";
var context = new ApplicationDbContext();
var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
var role = new IdentityRole(_role);
var result = await roleManager.RoleExistsAsync(_role);
if (result == false)
{ {
await roleManager.CreateAsync(role); context.Database.Delete();
context.Database.Create();
new SampleData().Seed(context);
} }
var user = await userManager.FindByNameAsync(_username); CreateAdminUser().Wait();
if (user == null) }
private async Task CreateAdminUser()
{
var username = ConfigurationManager.AppSettings["DefaultAdminUsername"];
var password = ConfigurationManager.AppSettings["DefaultAdminPassword"];
using (var context = new ApplicationDbContext())
{ {
user = new ApplicationUser { UserName = _username }; var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
await userManager.CreateAsync(user, _password); var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
await userManager.AddToRoleAsync(user.Id, _role);
var role = new IdentityRole(RoleName);
var result = await roleManager.RoleExistsAsync(RoleName);
if (!result)
{
await roleManager.CreateAsync(role);
}
var user = await userManager.FindByNameAsync(username);
if (user == null)
{
user = new ApplicationUser { UserName = username };
await userManager.CreateAsync(user, password);
await userManager.AddToRoleAsync(user.Id, RoleName);
}
} }
} }
} }

View File

@ -1,12 +1,11 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
using System.Web.Mvc; using System.Web.Mvc;
using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework; using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security; using Microsoft.Owin.Security;
using MvcMusicStore.Models; using MvcMusicStore.Models;
@ -15,6 +14,18 @@ namespace MvcMusicStore.Controllers
[Authorize] [Authorize]
public class AccountController : Controller public class AccountController : Controller
{ {
public enum ManageMessageId
{
ChangePasswordSuccess,
SetPasswordSuccess,
RemoveLoginSuccess,
Error
}
private const string XsrfKey = "XsrfId";
private UserManager<ApplicationUser> _userManager;
public AccountController() public AccountController()
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()))) : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
{ {
@ -22,33 +33,35 @@ namespace MvcMusicStore.Controllers
public AccountController(UserManager<ApplicationUser> userManager) public AccountController(UserManager<ApplicationUser> userManager)
{ {
UserManager = userManager; _userManager = userManager;
} }
public UserManager<ApplicationUser> UserManager { get; private set; } private IAuthenticationManager AuthenticationManager
private void MigrateShoppingCart(string UserName)
{ {
var storeDb = new MusicStoreEntities(); get { return HttpContext.GetOwinContext().Authentication; }
}
// Associate shopping cart items with logged-in user
var cart = ShoppingCart.GetCart(storeDb, this.HttpContext); private async Task MigrateShoppingCart(string userName)
cart.MigrateCart(UserName); {
storeDb.SaveChanges(); using (var storeContext = new MusicStoreEntities())
{
Session[ShoppingCart.CartSessionKey] = UserName; var cart = ShoppingCart.GetCart(storeContext, this);
await cart.MigrateCart(userName);
Session[ShoppingCart.CartSessionKey] = userName;
}
} }
//
// GET: /Account/Login // GET: /Account/Login
[AllowAnonymous] [AllowAnonymous]
public ActionResult Login(string returnUrl) public ActionResult Login(string returnUrl)
{ {
ViewBag.ReturnUrl = returnUrl; ViewBag.ReturnUrl = returnUrl;
return View(); return View();
} }
//
// POST: /Account/Login // POST: /Account/Login
[HttpPost] [HttpPost]
[AllowAnonymous] [AllowAnonymous]
@ -57,23 +70,20 @@ namespace MvcMusicStore.Controllers
{ {
if (ModelState.IsValid) if (ModelState.IsValid)
{ {
var user = await UserManager.FindAsync(model.UserName, model.Password); var user = await _userManager.FindAsync(model.UserName, model.Password);
if (user != null) if (user != null)
{ {
await SignInAsync(user, model.RememberMe); await SignInAsync(user, model.RememberMe);
return RedirectToLocal(returnUrl); return RedirectToLocal(returnUrl);
} }
else
{ ModelState.AddModelError("", "Invalid username or password.");
ModelState.AddModelError("", "Invalid username or password.");
}
} }
// If we got this far, something failed, redisplay form
return View(model); return View(model);
} }
//
// GET: /Account/Register // GET: /Account/Register
[AllowAnonymous] [AllowAnonymous]
public ActionResult Register() public ActionResult Register()
@ -81,7 +91,6 @@ namespace MvcMusicStore.Controllers
return View(); return View();
} }
//
// POST: /Account/Register // POST: /Account/Register
[HttpPost] [HttpPost]
[AllowAnonymous] [AllowAnonymous]
@ -90,85 +99,92 @@ namespace MvcMusicStore.Controllers
{ {
if (ModelState.IsValid) if (ModelState.IsValid)
{ {
var user = new ApplicationUser() { UserName = model.UserName }; var user = new ApplicationUser { UserName = model.UserName };
var result = await UserManager.CreateAsync(user, model.Password); var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded) if (result.Succeeded)
{ {
await SignInAsync(user, isPersistent: false); await SignInAsync(user, false);
return RedirectToAction("Index", "Home"); return RedirectToAction("Index", "Home");
} }
else
{ AddErrors(result);
AddErrors(result);
}
} }
// If we got this far, something failed, redisplay form
return View(model); return View(model);
} }
//
// POST: /Account/Disassociate // POST: /Account/Disassociate
[HttpPost] [HttpPost]
[ValidateAntiForgeryToken] [ValidateAntiForgeryToken]
public async Task<ActionResult> Disassociate(string loginProvider, string providerKey) public async Task<ActionResult> Disassociate(string loginProvider, string providerKey)
{ {
ManageMessageId? message = null; var result = await _userManager.RemoveLoginAsync(
IdentityResult result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(), new UserLoginInfo(loginProvider, providerKey)); User.Identity.GetUserId(),
if (result.Succeeded) new UserLoginInfo(loginProvider, providerKey));
{
message = ManageMessageId.RemoveLoginSuccess; return RedirectToAction(
} "Manage",
else new { Message = result.Succeeded ? ManageMessageId.RemoveLoginSuccess : ManageMessageId.Error });
{
message = ManageMessageId.Error;
}
return RedirectToAction("Manage", new { Message = message });
} }
//
// GET: /Account/Manage // GET: /Account/Manage
public ActionResult Manage(ManageMessageId? message) public async Task<ActionResult> Manage(ManageMessageId? message)
{ {
ViewBag.StatusMessage = switch (message)
message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed." {
: message == ManageMessageId.SetPasswordSuccess ? "Your password has been set." case ManageMessageId.ChangePasswordSuccess:
: message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed." ViewBag.StatusMessage = "Your password has been changed.";
: message == ManageMessageId.Error ? "An error has occurred." break;
: ""; case ManageMessageId.SetPasswordSuccess:
ViewBag.HasLocalPassword = HasPassword(); ViewBag.StatusMessage = "Your password has been set.";
break;
case ManageMessageId.RemoveLoginSuccess:
ViewBag.StatusMessage = "The external login was removed.";
break;
case ManageMessageId.Error:
ViewBag.StatusMessage = "An error has occurred.";
break;
default:
ViewBag.StatusMessage = "";
break;
}
ViewBag.HasLocalPassword = await HasPasswordAsync();
ViewBag.ReturnUrl = Url.Action("Manage"); ViewBag.ReturnUrl = Url.Action("Manage");
return View(); return View();
} }
//
// POST: /Account/Manage // POST: /Account/Manage
[HttpPost] [HttpPost]
[ValidateAntiForgeryToken] [ValidateAntiForgeryToken]
public async Task<ActionResult> Manage(ManageUserViewModel model) public async Task<ActionResult> Manage(ManageUserViewModel model)
{ {
bool hasPassword = HasPassword(); bool hasPassword = await HasPasswordAsync();
ViewBag.HasLocalPassword = hasPassword; ViewBag.HasLocalPassword = hasPassword;
ViewBag.ReturnUrl = Url.Action("Manage"); ViewBag.ReturnUrl = Url.Action("Manage");
if (hasPassword) if (hasPassword)
{ {
if (ModelState.IsValid) if (ModelState.IsValid)
{ {
IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword); var result = await _userManager.ChangePasswordAsync(
User.Identity.GetUserId(),
model.OldPassword,
model.NewPassword);
if (result.Succeeded) if (result.Succeeded)
{ {
return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess }); return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess });
} }
else
{ AddErrors(result);
AddErrors(result);
}
} }
} }
else else
{ {
// User does not have a password so remove any validation errors caused by a missing OldPassword field var state = ModelState["OldPassword"];
ModelState state = ModelState["OldPassword"];
if (state != null) if (state != null)
{ {
state.Errors.Clear(); state.Errors.Clear();
@ -176,34 +192,32 @@ namespace MvcMusicStore.Controllers
if (ModelState.IsValid) if (ModelState.IsValid)
{ {
IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword); var result = await _userManager.AddPasswordAsync(
User.Identity.GetUserId(),
model.NewPassword);
if (result.Succeeded) if (result.Succeeded)
{ {
return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess }); return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess });
} }
else
{ AddErrors(result);
AddErrors(result);
}
} }
} }
// If we got this far, something failed, redisplay form
return View(model); return View(model);
} }
//
// POST: /Account/ExternalLogin // POST: /Account/ExternalLogin
[HttpPost] [HttpPost]
[AllowAnonymous] [AllowAnonymous]
[ValidateAntiForgeryToken] [ValidateAntiForgeryToken]
public ActionResult ExternalLogin(string provider, string returnUrl) public ActionResult ExternalLogin(string provider, string returnUrl)
{ {
// Request a redirect to the external login provider return new ChallengeResult(provider,
return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl })); Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
} }
//
// GET: /Account/ExternalLoginCallback // GET: /Account/ExternalLoginCallback
[AllowAnonymous] [AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl) public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
@ -214,55 +228,56 @@ namespace MvcMusicStore.Controllers
return RedirectToAction("Login"); return RedirectToAction("Login");
} }
// Sign in the user with this external login provider if the user already has a login var user = await _userManager.FindAsync(loginInfo.Login);
var user = await UserManager.FindAsync(loginInfo.Login);
if (user != null) if (user != null)
{ {
await SignInAsync(user, isPersistent: false); await SignInAsync(user, false);
return RedirectToLocal(returnUrl); return RedirectToLocal(returnUrl);
} }
else
{ ViewBag.ReturnUrl = returnUrl;
// If the user does not have an account, then prompt the user to create an account ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
ViewBag.ReturnUrl = returnUrl;
ViewBag.LoginProvider = loginInfo.Login.LoginProvider; return View("ExternalLoginConfirmation",
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { UserName = loginInfo.DefaultUserName }); new ExternalLoginConfirmationViewModel { UserName = loginInfo.DefaultUserName });
}
} }
//
// POST: /Account/LinkLogin // POST: /Account/LinkLogin
[HttpPost] [HttpPost]
[ValidateAntiForgeryToken] [ValidateAntiForgeryToken]
public ActionResult LinkLogin(string provider) public ActionResult LinkLogin(string provider)
{ {
// Request a redirect to the external login provider to link a login for the current user
return new ChallengeResult(provider, Url.Action("LinkLoginCallback", "Account"), User.Identity.GetUserId()); return new ChallengeResult(provider, Url.Action("LinkLoginCallback", "Account"), User.Identity.GetUserId());
} }
//
// GET: /Account/LinkLoginCallback // GET: /Account/LinkLoginCallback
public async Task<ActionResult> LinkLoginCallback() public async Task<ActionResult> LinkLoginCallback()
{ {
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId()); var loginInfo =
await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId());
if (loginInfo == null) if (loginInfo == null)
{ {
return RedirectToAction("Manage", new { Message = ManageMessageId.Error }); return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
} }
var result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login);
var result = await _userManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login);
if (result.Succeeded) if (result.Succeeded)
{ {
return RedirectToAction("Manage"); return RedirectToAction("Manage");
} }
return RedirectToAction("Manage", new { Message = ManageMessageId.Error }); return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
} }
//
// POST: /Account/ExternalLoginConfirmation // POST: /Account/ExternalLoginConfirmation
[HttpPost] [HttpPost]
[AllowAnonymous] [AllowAnonymous]
[ValidateAntiForgeryToken] [ValidateAntiForgeryToken]
public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl) public async Task<ActionResult> ExternalLoginConfirmation(
ExternalLoginConfirmationViewModel model,
string returnUrl)
{ {
if (User.Identity.IsAuthenticated) if (User.Identity.IsAuthenticated)
{ {
@ -277,35 +292,39 @@ namespace MvcMusicStore.Controllers
{ {
return View("ExternalLoginFailure"); return View("ExternalLoginFailure");
} }
var user = new ApplicationUser() { UserName = model.UserName };
var result = await UserManager.CreateAsync(user); var user = new ApplicationUser { UserName = model.UserName };
var result = await _userManager.CreateAsync(user);
if (result.Succeeded) if (result.Succeeded)
{ {
result = await UserManager.AddLoginAsync(user.Id, info.Login); result = await _userManager.AddLoginAsync(user.Id, info.Login);
if (result.Succeeded) if (result.Succeeded)
{ {
await SignInAsync(user, isPersistent: false); await SignInAsync(user, false);
return RedirectToLocal(returnUrl); return RedirectToLocal(returnUrl);
} }
} }
AddErrors(result); AddErrors(result);
} }
ViewBag.ReturnUrl = returnUrl; ViewBag.ReturnUrl = returnUrl;
return View(model); return View(model);
} }
//
// POST: /Account/LogOff // POST: /Account/LogOff
[HttpPost] [HttpPost]
[ValidateAntiForgeryToken] [ValidateAntiForgeryToken]
public ActionResult LogOff() public ActionResult LogOff()
{ {
AuthenticationManager.SignOut(); AuthenticationManager.SignOut();
return RedirectToAction("Index", "Home"); return RedirectToAction("Index", "Home");
} }
//
// GET: /Account/ExternalLoginFailure // GET: /Account/ExternalLoginFailure
[AllowAnonymous] [AllowAnonymous]
public ActionResult ExternalLoginFailure() public ActionResult ExternalLoginFailure()
@ -316,41 +335,34 @@ namespace MvcMusicStore.Controllers
[ChildActionOnly] [ChildActionOnly]
public ActionResult RemoveAccountList() public ActionResult RemoveAccountList()
{ {
var linkedAccounts = UserManager.GetLogins(User.Identity.GetUserId()); var linkedAccounts = _userManager.GetLogins(User.Identity.GetUserId());
ViewBag.ShowRemoveButton = HasPassword() || linkedAccounts.Count > 1; ViewBag.ShowRemoveButton = HasPassword() || linkedAccounts.Count > 1;
return (ActionResult)PartialView("_RemoveAccountPartial", linkedAccounts);
return PartialView("_RemoveAccountPartial", linkedAccounts);
} }
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
if (disposing && UserManager != null) if (disposing && _userManager != null)
{ {
UserManager.Dispose(); _userManager.Dispose();
UserManager = null; _userManager = null;
} }
base.Dispose(disposing); base.Dispose(disposing);
} }
#region Helpers
// Used for XSRF protection when adding external logins
private const string XsrfKey = "XsrfId";
private IAuthenticationManager AuthenticationManager
{
get
{
return HttpContext.GetOwinContext().Authentication;
}
}
private async Task SignInAsync(ApplicationUser user, bool isPersistent) private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{ {
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie); AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
// Migrate the user's shopping cart var identity =
MigrateShoppingCart(user.UserName); await _userManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = isPersistent }, identity);
await MigrateShoppingCart(user.UserName);
} }
private void AddErrors(IdentityResult result) private void AddErrors(IdentityResult result)
@ -363,61 +375,47 @@ namespace MvcMusicStore.Controllers
private bool HasPassword() private bool HasPassword()
{ {
var user = UserManager.FindById(User.Identity.GetUserId()); var user = _userManager.FindById(User.Identity.GetUserId());
if (user != null)
{ return user != null && user.PasswordHash != null;
return user.PasswordHash != null;
}
return false;
} }
public enum ManageMessageId private async Task<bool> HasPasswordAsync()
{ {
ChangePasswordSuccess, var user = await _userManager.FindByIdAsync(User.Identity.GetUserId());
SetPasswordSuccess,
RemoveLoginSuccess, return user != null && user.PasswordHash != null;
Error
} }
private ActionResult RedirectToLocal(string returnUrl) private ActionResult RedirectToLocal(string returnUrl)
{ {
if (Url.IsLocalUrl(returnUrl)) return Url.IsLocalUrl(returnUrl)
{ ? (ActionResult)Redirect(returnUrl)
return Redirect(returnUrl); : RedirectToAction("Index", "Home");
}
else
{
return RedirectToAction("Index", "Home");
}
} }
private class ChallengeResult : HttpUnauthorizedResult private class ChallengeResult : HttpUnauthorizedResult
{ {
public ChallengeResult(string provider, string redirectUri) : this(provider, redirectUri, null) private readonly string _loginProvider;
{ private readonly string _redirectUri;
} private readonly string _userId;
public ChallengeResult(string provider, string redirectUri, string userId) public ChallengeResult(string provider, string redirectUri, string userId = null)
{ {
LoginProvider = provider; _loginProvider = provider;
RedirectUri = redirectUri; _redirectUri = redirectUri;
UserId = userId; _userId = userId;
} }
public string LoginProvider { get; set; }
public string RedirectUri { get; set; }
public string UserId { get; set; }
public override void ExecuteResult(ControllerContext context) public override void ExecuteResult(ControllerContext context)
{ {
var properties = new AuthenticationProperties() { RedirectUri = RedirectUri }; var properties = new AuthenticationProperties { RedirectUri = _redirectUri };
if (UserId != null) if (_userId != null)
{ {
properties.Dictionary[XsrfKey] = UserId; properties.Dictionary[XsrfKey] = _userId;
} }
context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider); context.HttpContext.GetOwinContext().Authentication.Challenge(properties, _loginProvider);
} }
} }
#endregion
} }
} }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Linq; using System.Data.Entity;
using System.Threading.Tasks;
using System.Web.Mvc; using System.Web.Mvc;
using MvcMusicStore.Models; using MvcMusicStore.Models;
@ -8,78 +9,56 @@ namespace MvcMusicStore.Controllers
[Authorize] [Authorize]
public class CheckoutController : Controller public class CheckoutController : Controller
{ {
MusicStoreEntities storeDB = new MusicStoreEntities(); private const string PromoCode = "FREE";
const string PromoCode = "FREE";
private readonly MusicStoreEntities _storeContext = new MusicStoreEntities();
//
// GET: /Checkout/ // GET: /Checkout/
public ActionResult AddressAndPayment() public ActionResult AddressAndPayment()
{ {
return View(); return View();
} }
//
// POST: /Checkout/AddressAndPayment // POST: /Checkout/AddressAndPayment
[HttpPost] [HttpPost]
public ActionResult AddressAndPayment(FormCollection values) public async Task<ActionResult> AddressAndPayment(FormCollection values)
{ {
var order = new Order(); var order = new Order();
TryUpdateModel(order); TryUpdateModel(order);
try if (ModelState.IsValid
&& string.Equals(values["PromoCode"], PromoCode, StringComparison.OrdinalIgnoreCase))
{ {
if (string.Equals(values["PromoCode"], PromoCode, order.Username = User.Identity.Name;
StringComparison.OrdinalIgnoreCase) == false) order.OrderDate = DateTime.Now;
{
return View(order);
}
else
{
order.Username = User.Identity.Name;
order.OrderDate = DateTime.Now;
//Add the Order _storeContext.Orders.Add(order);
storeDB.Orders.Add(order);
//Process the order await ShoppingCart.GetCart(_storeContext, this).CreateOrder(order);
var cart = ShoppingCart.GetCart(storeDB, this.HttpContext);
cart.CreateOrder(order);
// Save all changes await _storeContext.SaveChangesAsync();
storeDB.SaveChanges();
return RedirectToAction("Complete",
new { id = order.OrderId });
}
return RedirectToAction("Complete", new { id = order.OrderId });
} }
catch
{ return View(order);
//Invalid - redisplay with errors
return View(order);
}
} }
//
// GET: /Checkout/Complete // GET: /Checkout/Complete
public async Task<ActionResult> Complete(int id)
public ActionResult Complete(int id)
{ {
// Validate customer owns this order return await _storeContext.Orders.AnyAsync(o => o.OrderId == id && o.Username == User.Identity.Name)
bool isValid = storeDB.Orders.Any( ? View(id)
o => o.OrderId == id && : View("Error");
o.Username == User.Identity.Name); }
if (isValid) protected override void Dispose(bool disposing)
{
if (disposing)
{ {
return View(id); _storeContext.Dispose();
}
else
{
return View("Error");
} }
base.Dispose(disposing);
} }
} }
} }

View File

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Data.Entity;
using System.Linq; using System.Linq;
using System.Web; using System.Threading.Tasks;
using System.Web.Mvc; using System.Web.Mvc;
using MvcMusicStore.Models; using MvcMusicStore.Models;
@ -8,28 +8,24 @@ namespace MvcMusicStore.Controllers
{ {
public class HomeController : Controller public class HomeController : Controller
{ {
private MusicStoreEntities storeDB = new MusicStoreEntities(); private readonly MusicStoreEntities _storeContext = new MusicStoreEntities();
//
// GET: /Home/ // GET: /Home/
public async Task<ActionResult> Index()
public ActionResult Index()
{ {
// Get most popular albums return View(await _storeContext.Albums
var albums = GetTopSellingAlbums(6); .OrderByDescending(a => a.OrderDetails.Count())
.Take(6)
return View(albums); .ToListAsync());
} }
protected override void Dispose(bool disposing)
private List<Album> GetTopSellingAlbums(int count)
{ {
// Group the order details by album and return if (disposing)
// the albums with the highest count {
_storeContext.Dispose();
return storeDB.Albums }
.OrderByDescending(a => a.OrderDetails.Count()) base.Dispose(disposing);
.Take(count)
.ToList();
} }
} }
} }

View File

@ -1,4 +1,6 @@
using System.Linq; using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Mvc; using System.Web.Mvc;
using MvcMusicStore.Models; using MvcMusicStore.Models;
using MvcMusicStore.ViewModels; using MvcMusicStore.ViewModels;
@ -7,75 +9,56 @@ namespace MvcMusicStore.Controllers
{ {
public class ShoppingCartController : Controller public class ShoppingCartController : Controller
{ {
MusicStoreEntities storeDB = new MusicStoreEntities(); private readonly MusicStoreEntities _storeContext = new MusicStoreEntities();
//
// GET: /ShoppingCart/ // GET: /ShoppingCart/
public async Task<ActionResult> Index()
public ActionResult Index()
{ {
var cart = ShoppingCart.GetCart(storeDB, this.HttpContext); var cart = ShoppingCart.GetCart(_storeContext, this);
// Set up our ViewModel
var viewModel = new ShoppingCartViewModel var viewModel = new ShoppingCartViewModel
{ {
CartItems = cart.GetCartItems(), CartItems = await cart.GetCartItems().ToListAsync(),
CartTotal = cart.GetTotal() CartTotal = await cart.GetTotal()
}; };
// Return the view
return View(viewModel); return View(viewModel);
} }
//
// GET: /ShoppingCart/AddToCart/5 // GET: /ShoppingCart/AddToCart/5
public async Task<ActionResult> AddToCart(int id)
public ActionResult AddToCart(int id)
{ {
var cart = ShoppingCart.GetCart(_storeContext, this);
// Retrieve the album from the database await cart.AddToCart(await _storeContext.Albums.SingleAsync(a => a.AlbumId == id));
var addedAlbum = storeDB.Albums
.Single(album => album.AlbumId == id);
// Add it to the shopping cart await _storeContext.SaveChangesAsync();
var cart = ShoppingCart.GetCart(storeDB, this.HttpContext);
cart.AddToCart(addedAlbum);
storeDB.SaveChanges();
// Go back to the main store page for more shopping
return RedirectToAction("Index"); return RedirectToAction("Index");
} }
//
// AJAX: /ShoppingCart/RemoveFromCart/5 // AJAX: /ShoppingCart/RemoveFromCart/5
[HttpPost] [HttpPost]
public ActionResult RemoveFromCart(int id) public async Task<ActionResult> RemoveFromCart(int id)
{ {
// Retrieve the current user's shopping cart var cart = ShoppingCart.GetCart(_storeContext, this);
var cart = ShoppingCart.GetCart(storeDB, this.HttpContext);
// Get the name of the album to display confirmation var albumName = await _storeContext.Carts
string albumName = storeDB.Carts .Where(i => i.RecordId == id)
.Single(item => item.RecordId == id).Album.Title; .Select(i => i.Album.Title)
.SingleOrDefaultAsync();
// Remove from cart var itemCount = await cart.RemoveFromCart(id);
int itemCount = cart.RemoveFromCart(id);
storeDB.SaveChanges(); await _storeContext.SaveChangesAsync();
string removed = (itemCount > 0) ? " 1 copy of " : string.Empty; var removed = (itemCount > 0) ? " 1 copy of " : string.Empty;
// Display the confirmation message
var results = new ShoppingCartRemoveViewModel var results = new ShoppingCartRemoveViewModel
{ {
Message = removed + albumName + Message = removed + albumName + " has been removed from your shopping cart.",
" has been removed from your shopping cart.", CartTotal = await cart.GetTotal(),
CartTotal = cart.GetTotal(), CartCount = await cart.GetCount(),
CartCount = cart.GetCount(),
ItemCount = itemCount, ItemCount = itemCount,
DeleteId = id DeleteId = id
}; };
@ -86,16 +69,26 @@ namespace MvcMusicStore.Controllers
[ChildActionOnly] [ChildActionOnly]
public ActionResult CartSummary() public ActionResult CartSummary()
{ {
var cart = ShoppingCart.GetCart(storeDB, this.HttpContext); var cart = ShoppingCart.GetCart(_storeContext, this);
var cartItems = cart.GetCartItems() var cartItems = cart.GetCartItems()
.Select(a => a.Album.Title) .Select(a => a.Album.Title)
.OrderBy(x => x); .OrderBy(x => x)
.ToList();
ViewBag.CartCount = cartItems.Count(); ViewBag.CartCount = cartItems.Count();
ViewBag.CartSummary = string.Join("\n", cartItems.Distinct()); ViewBag.CartSummary = string.Join("\n", cartItems.Distinct());
return PartialView("CartSummary"); return PartialView("CartSummary");
} }
protected override void Dispose(bool disposing)
{
if (disposing)
{
_storeContext.Dispose();
}
base.Dispose(disposing);
}
} }
} }

View File

@ -1,57 +1,49 @@
using MvcMusicStore.Models; using System.Data.Entity;
using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Web; using System.Threading.Tasks;
using System.Web.Mvc; using System.Web.Mvc;
using MvcMusicStore.Models;
namespace MvcMusicStore.Controllers namespace MvcMusicStore.Controllers
{ {
public class StoreController : Controller public class StoreController : Controller
{ {
MusicStoreEntities storeDB = new MusicStoreEntities(); private readonly MusicStoreEntities _storeContext = new MusicStoreEntities();
//
// GET: /Store/ // GET: /Store/
public async Task<ActionResult> Index()
public ActionResult Index()
{ {
var genres = storeDB.Genres.ToList(); return View(await _storeContext.Genres.ToListAsync());
return View(genres);
} }
//
// GET: /Store/Browse?genre=Disco // GET: /Store/Browse?genre=Disco
public async Task<ActionResult> Browse(string genre)
public ActionResult Browse(string genre)
{ {
// Retrieve Genre genre and its Associated associated Albums albums from database return View(await _storeContext.Genres.Include("Albums").SingleAsync(g => g.Name == genre));
var genreModel = storeDB.Genres.Include("Albums")
.Single(g => g.Name == genre);
return View(genreModel);
} }
public ActionResult Details(int id) public async Task<ActionResult> Details(int id)
{ {
var album = storeDB.Albums.Find(id); var album = await _storeContext.Albums.FindAsync(id);
return View(album); return album != null ? View(album) : (ActionResult)HttpNotFound();
} }
[ChildActionOnly] [ChildActionOnly]
public ActionResult GenreMenu() public ActionResult GenreMenu()
{ {
var genres = storeDB.Genres return PartialView(
.OrderByDescending( _storeContext.Genres.OrderByDescending(
g => g.Albums.Sum( g => g.Albums.Sum(a => a.OrderDetails.Sum(od => od.Quantity))).Take(9).ToList());
a => a.OrderDetails.Sum( }
od => od.Quantity)))
.Take(9)
.ToList();
return PartialView(genres); protected override void Dispose(bool disposing)
{
if (disposing)
{
_storeContext.Dispose();
}
base.Dispose(disposing);
} }
} }
} }

View File

@ -1,9 +1,6 @@
using System; using System.Data.Entity;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq; using System.Linq;
using System.Web; using System.Threading.Tasks;
using System.Web.Mvc; using System.Web.Mvc;
using MvcMusicStore.Models; using MvcMusicStore.Models;
@ -12,119 +9,132 @@ namespace MvcMusicStore.Controllers
[Authorize(Roles = "Administrator")] [Authorize(Roles = "Administrator")]
public class StoreManagerController : Controller public class StoreManagerController : Controller
{ {
private MusicStoreEntities db = new MusicStoreEntities(); private readonly MusicStoreEntities _storeContext = new MusicStoreEntities();
//
// GET: /StoreManager/ // GET: /StoreManager/
public async Task<ActionResult> Index()
public ActionResult Index()
{ {
var albums = db.Albums.Include(a => a.Genre).Include(a => a.Artist) return View(await _storeContext.Albums
.OrderBy(a => a.Price); .Include(a => a.Genre)
return View(albums.ToList()); .Include(a => a.Artist)
.OrderBy(a => a.Price).ToListAsync());
} }
//
// GET: /StoreManager/Details/5 // GET: /StoreManager/Details/5
public async Task<ActionResult> Details(int id = 0)
public ActionResult Details(int id = 0)
{ {
Album album = db.Albums.Find(id); var album = await _storeContext.Albums.FindAsync(id);
if (album == null) if (album == null)
{ {
return HttpNotFound(); return HttpNotFound();
} }
return View(album); return View(album);
} }
//
// GET: /StoreManager/Create // GET: /StoreManager/Create
public async Task<ActionResult> Create()
public ActionResult Create()
{ {
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name"); return await BuildView(null);
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name");
return View();
} }
//
// POST: /StoreManager/Create // POST: /StoreManager/Create
[HttpPost] [HttpPost]
public ActionResult Create(Album album) public async Task<ActionResult> Create(Album album)
{ {
if (ModelState.IsValid) if (ModelState.IsValid)
{ {
db.Albums.Add(album); _storeContext.Albums.Add(album);
db.SaveChanges();
await _storeContext.SaveChangesAsync();
return RedirectToAction("Index"); return RedirectToAction("Index");
} }
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name", album.GenreId); return await BuildView(album);
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId);
return View(album);
} }
//
// GET: /StoreManager/Edit/5 // GET: /StoreManager/Edit/5
public async Task<ActionResult> Edit(int id = 0)
public ActionResult Edit(int id = 0)
{ {
Album album = db.Albums.Find(id); var album = await _storeContext.Albums.FindAsync(id);
if (album == null) if (album == null)
{ {
return HttpNotFound(); return HttpNotFound();
} }
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name", album.GenreId);
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId); return await BuildView(album);
return View(album);
} }
//
// POST: /StoreManager/Edit/5 // POST: /StoreManager/Edit/5
[HttpPost] [HttpPost]
public ActionResult Edit(Album album) public async Task<ActionResult> Edit(Album album)
{ {
if (ModelState.IsValid) if (ModelState.IsValid)
{ {
db.Entry(album).State = EntityState.Modified; _storeContext.Entry(album).State = EntityState.Modified;
db.SaveChanges();
await _storeContext.SaveChangesAsync();
return RedirectToAction("Index"); return RedirectToAction("Index");
} }
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name", album.GenreId);
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId); return await BuildView(album);
return View(album);
} }
//
// GET: /StoreManager/Delete/5 // GET: /StoreManager/Delete/5
public async Task<ActionResult> Delete(int id = 0)
public ActionResult Delete(int id = 0)
{ {
Album album = db.Albums.Find(id); var album = await _storeContext.Albums.FindAsync(id);
if (album == null) if (album == null)
{ {
return HttpNotFound(); return HttpNotFound();
} }
return View(album); return View(album);
} }
//
// POST: /StoreManager/Delete/5 // POST: /StoreManager/Delete/5
[HttpPost, ActionName("Delete")] [HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id) public async Task<ActionResult> DeleteConfirmed(int id)
{ {
Album album = db.Albums.Find(id); var album = await _storeContext.Albums.FindAsync(id);
db.Albums.Remove(album); if (album == null)
db.SaveChanges(); {
return HttpNotFound();
}
_storeContext.Albums.Remove(album);
await _storeContext.SaveChangesAsync();
return RedirectToAction("Index"); return RedirectToAction("Index");
} }
private async Task<ActionResult> BuildView(Album album)
{
ViewBag.GenreId = new SelectList(
await _storeContext.Genres.ToListAsync(),
"GenreId",
"Name",
album == null ? null : (object)album.GenreId);
ViewBag.ArtistId = new SelectList(
await _storeContext.Artists.ToListAsync(),
"ArtistId",
"Name",
album == null ? null : (object)album.ArtistId);
return View(album);
}
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
db.Dispose(); if (disposing)
{
_storeContext.Dispose();
}
base.Dispose(disposing); base.Dispose(disposing);
} }
} }

View File

@ -16,8 +16,6 @@ namespace MvcMusicStore
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes); RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles); BundleConfig.RegisterBundles(BundleTable.Bundles);
System.Data.Entity.Database.SetInitializer(new MvcMusicStore.Models.SampleData());
} }
} }
} }

View File

@ -4,6 +4,11 @@ namespace MvcMusicStore.Models
{ {
public class MusicStoreEntities : DbContext public class MusicStoreEntities : DbContext
{ {
public MusicStoreEntities()
: base("name=MusicStoreEntities")
{
}
public DbSet<Album> Albums { get; set; } public DbSet<Album> Albums { get; set; }
public DbSet<Genre> Genres { get; set; } public DbSet<Genre> Genres { get; set; }
public DbSet<Artist> Artists { get; set; } public DbSet<Artist> Artists { get; set; }

View File

@ -8,6 +8,11 @@ namespace MvcMusicStore.Models
[Bind(Include = "FirstName,LastName,Address,City,State,PostalCode,Country,Phone,Email")] [Bind(Include = "FirstName,LastName,Address,City,State,PostalCode,Country,Phone,Email")]
public class Order public class Order
{ {
public Order()
{
OrderDetails = new List<OrderDetail>();
}
[ScaffoldColumn(false)] [ScaffoldColumn(false)]
public int OrderId { get; set; } public int OrderId { get; set; }

File diff suppressed because it is too large Load Diff

View File

@ -1,195 +1,159 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.Entity;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using System.Web; using System.Web;
using System.Web.Mvc; using System.Web.Mvc;
namespace MvcMusicStore.Models namespace MvcMusicStore.Models
{ {
public partial class ShoppingCart public class ShoppingCart
{ {
MusicStoreEntities _db;
string ShoppingCartId { get; set; }
public ShoppingCart(MusicStoreEntities db)
{
_db = db;
}
public const string CartSessionKey = "CartId"; public const string CartSessionKey = "CartId";
public static ShoppingCart GetCart(MusicStoreEntities db, HttpContextBase context) private readonly MusicStoreEntities _storeContext;
private readonly string _cartId;
private ShoppingCart(MusicStoreEntities storeContext, string cartId)
{ {
var cart = new ShoppingCart(db); _storeContext = storeContext;
cart.ShoppingCartId = cart.GetCartId(context); _cartId = cartId;
return cart;
} }
// Helper method to simplify shopping cart calls public static ShoppingCart GetCart(MusicStoreEntities storeContext, Controller controller)
public static ShoppingCart GetCart(MusicStoreEntities db, Controller controller)
{ {
return GetCart(db, controller.HttpContext); return new ShoppingCart(storeContext, GetCartId(controller.HttpContext));
} }
public void AddToCart(Album album) private static string GetCartId(HttpContextBase context)
{
// Get the matching cart and album instances
var cartItem = _db.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
};
_db.Carts.Add(cartItem);
}
else
{
// If the item does exist in the cart, then add one to the quantity
cartItem.Count++;
}
}
public int RemoveFromCart(int id)
{
// Get the cart
var cartItem = _db.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
{
_db.Carts.Remove(cartItem);
}
}
return itemCount;
}
public void EmptyCart()
{
var cartItems = _db.Carts.Where(cart => cart.CartId == ShoppingCartId);
foreach (var cartItem in cartItems)
{
_db.Carts.Remove(cartItem);
}
}
public List<Cart> GetCartItems()
{
return _db.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 _db.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 _db.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 album = _db.Albums.Find(item.AlbumId);
var orderDetail = new OrderDetail
{
AlbumId = item.AlbumId,
OrderId = order.OrderId,
UnitPrice = album.Price,
Quantity = item.Count,
};
// Set the order total of the shopping cart
orderTotal += (item.Count * item.Album.Price);
_db.OrderDetails.Add(orderDetail);
}
// Set the order's total to the orderTotal count
order.Total = orderTotal;
// 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 (context.Session[CartSessionKey] == null)
{ {
if (!string.IsNullOrWhiteSpace(context.User.Identity.Name)) var username = 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] = !string.IsNullOrWhiteSpace(username)
context.Session[CartSessionKey] = tempCartId.ToString(); ? username
} : Guid.NewGuid().ToString();
} }
return context.Session[CartSessionKey].ToString(); return context.Session[CartSessionKey].ToString();
} }
// When a user has logged in, migrate their shopping cart to public async Task AddToCart(Album album)
// be associated with their username
public void MigrateCart(string userName)
{ {
var shoppingCart = _db.Carts.Where(c => c.CartId == ShoppingCartId); var cartItem = await GetCartItem(album.AlbumId);
foreach (Cart item in shoppingCart) if (cartItem == null)
{
cartItem = new Cart
{
AlbumId = album.AlbumId,
CartId = _cartId,
Count = 1,
DateCreated = DateTime.Now
};
_storeContext.Carts.Add(cartItem);
}
else
{
cartItem.Count++;
}
}
public async Task<int> RemoveFromCart(int id)
{
var cartItem = await GetCartItem(id);
if (cartItem != null)
{
if (cartItem.Count > 1)
{
return --cartItem.Count;
}
_storeContext.Carts.Remove(cartItem);
}
return 0;
}
private Task<Cart> GetCartItem(int albumId)
{
return _storeContext.Carts.SingleOrDefaultAsync(
c => c.CartId == _cartId && c.AlbumId == albumId);
}
public IQueryable<Cart> GetCartItems()
{
return _storeContext.Carts.Where(c => c.CartId == _cartId);
}
public Task<int> GetCount()
{
return _storeContext.Carts
.Where(c => c.CartId == _cartId)
.Select(c => c.Count)
.SumAsync();
}
public Task<decimal> GetTotal()
{
return _storeContext.Carts
.Where(c => c.CartId == _cartId)
.Select(c => c.Count * c.Album.Price)
.SumAsync();
}
public async Task<int> CreateOrder(Order order)
{
decimal orderTotal = 0;
var cartItems = await _storeContext.Carts
.Where(c => c.CartId == _cartId)
.Include(c => c.Album)
.ToListAsync();
foreach (var item in cartItems)
{
order.OrderDetails.Add(new OrderDetail
{
AlbumId = item.AlbumId,
OrderId = order.OrderId,
UnitPrice = item.Album.Price,
Quantity = item.Count,
});
orderTotal += item.Count * item.Album.Price;
}
order.Total = orderTotal;
await EmptyCart();
return order.OrderId;
}
private async Task EmptyCart()
{
foreach (var cartItem in await _storeContext.Carts.Where(
c => c.CartId == _cartId).ToListAsync())
{
_storeContext.Carts.Remove(cartItem);
}
}
public async Task MigrateCart(string userName)
{
var carts = await _storeContext.Carts.Where(c => c.CartId == _cartId).ToListAsync();
foreach (var item in carts)
{ {
item.CartId = userName; item.CartId = userName;
} }
await _storeContext.SaveChangesAsync();
} }
} }
} }

View File

@ -9,8 +9,8 @@
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --></configSections> <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --></configSections>
<connectionStrings> <connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\aspnet-MvcMusicStore-20131025034205.mdf;Initial Catalog=aspnet-MvcMusicStore-20131025034205;Integrated Security=True" providerName="System.Data.SqlClient" /> <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=aspnet-MvcMusicStore-20131025034205;Integrated Security=True" providerName="System.Data.SqlClient" />
<add name="MusicStoreEntities" connectionString="Data Source=(LocalDB)\v11.0; AttachDbFilename=|DataDirectory|\MvcMusicStore.mdf; Integrated Security=True" providerName="System.Data.SqlClient" /> <add name="MusicStoreEntities" connectionString="Data Source=(LocalDB)\v11.0;Initial Catalog=MusicStore;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings> </connectionStrings>
<appSettings> <appSettings>
<add key="DefaultAdminUsername" value="Administrator" /> <add key="DefaultAdminUsername" value="Administrator" />