A few changes with this checkin:

1. Removing copyright text from all files per a code review feedback
2. Adding a cookie based session to the application to retrieve the cart Id.
3. Enabled the Accounts controller as we now have the necessary Http abstractions for User, SignIn, SignOut etc.
4. Changing self hosting scripts to run on coreclr by default.
5. Enabling the layout page on all required views.
6. Adding a favico.ico
7. Renaming the Cart property in the EF context to CartItems as it returns a CartItems list.
8. Uncommenting some code which was previously accessing unavailable APIs. They are available now (but yet to validate them).
This commit is contained in:
Praburaj 2014-04-02 18:40:25 -07:00
parent dabb68cc6d
commit 4709bca281
41 changed files with 595 additions and 659 deletions

View File

@ -11,5 +11,3 @@ rmdir /S /Q %APP_PATH%\Properties
del %APP_PATH%\*.csproj del %APP_PATH%\*.csproj
del %APP_PATH%\*.v12.suo del %APP_PATH%\*.v12.suo
del %APP_PATH%\*.csproj.user del %APP_PATH%\*.csproj.user
del src\PlaceHolder\*.csproj
rmdir /S /Q src\PlaceHolder\bin

View File

@ -2,10 +2,9 @@
### Run the application: ### Run the application:
1. Run build.cmd to restore all the necessary packages and generate project files 1. Run build.cmd to restore all the necessary packages and generate project files
2. Open a command prompt and cd \src\MusicStore\ 2. Open a command prompt and cd \src\<AppFolder>\
3. [Helios]: 3. [Helios]:
4. Execute CopyAspNetLoader.cmd to copy the AspNet.Loader.dll to the bin directory 4. Helios.cmd to launch the app on IISExpress.
5. Helios.cmd to launch the app on IISExpress.
4. [SelfHost]: 4. [SelfHost]:
5. Run Selfhost.cmd (This runs k web) (Note: If your changes to C# files are not picked up in successive builds - try deleting the bin and obj folder) 5. Run Selfhost.cmd (This runs k web) (Note: If your changes to C# files are not picked up in successive builds - try deleting the bin and obj folder)
5. [CustomHost]: 5. [CustomHost]:
@ -24,5 +23,5 @@
2. This is a captured snapshot of build numbers which worked for this application. This LKG will be captured once in a while. 2. This is a captured snapshot of build numbers which worked for this application. This LKG will be captured once in a while.
### Note: ### Note:
1. By default this script starts the application at http://localhost:5001/. Modify Run.cmd if you would like to change the url 1. By default the scripts will start the application at http://localhost:5001/. Modify the scripts to change the url.
2. Use Visual studio only for editing & intellisense. Don't try to build or run the app from Visual studio. 2. Use Visual studio only for editing & intellisense. Don't try to build or run the app from Visual studio.

View File

@ -1,505 +1,484 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using Microsoft.AspNet.Abstractions;
using Microsoft.AspNet.Abstractions.Security;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.InMemory;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.ModelBinding;
using MusicStore.Models;
using System.Security.Principal;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;
//using Microsoft.AspNet.Identity; namespace MusicStore.Controllers
//using Microsoft.AspNet.Identity.InMemory; {
//using Microsoft.AspNet.Mvc; //[Authorize]
//using Microsoft.AspNet.Mvc.ModelBinding; public class AccountController : Controller
//using MusicStore.Models; {
//using System; public AccountController()
//using System.Collections.Generic; //Bug: No EF yet - using an in memory store
//using System.Linq; //: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
//using System.Threading.Tasks; : this(new UserManager<ApplicationUser, string>(new InMemoryUserStore<ApplicationUser>()))
{
}
//namespace MusicStore.Controllers public AccountController(UserManager<ApplicationUser, string> userManager)
//{ {
// //[Authorize] UserManager = userManager;
// public class AccountController : Controller }
// {
// public AccountController()
// //Bug: No EF yet - using an in memory store
// //: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
// : this(new UserManager<ApplicationUser, string>(new InMemoryUserStore<ApplicationUser>()))
// {
// }
// public AccountController(UserManager<ApplicationUser, string> userManager) public UserManager<ApplicationUser, string> UserManager { get; private set; }
// {
// UserManager = userManager;
// }
// public UserManager<ApplicationUser, string> UserManager { get; private set; } //
// GET: /Account/Login
[AllowAnonymous]
public IActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
// private void MigrateShoppingCart(string UserName) //
// { // POST: /Account/Login
// //Bug: No EF //Bug: HTTP verb attribs not available
// //var storeDb = new MusicStoreEntities(); //[HttpPost]
// var storeDb = MusicStoreEntities.Instance; [AllowAnonymous]
//[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid == true)
{
var user = await UserManager.Find(model.UserName, model.Password);
if (user != null)
{
await SignIn(user, model.RememberMe);
return RedirectToLocal(returnUrl);
}
else
{
ModelState.AddModelError("", "Invalid username or password.");
}
}
// // Associate shopping cart items with logged-in user // If we got this far, something failed, redisplay form
// var cart = ShoppingCart.GetCart(storeDb, this.Context); return View(model);
// cart.MigrateCart(UserName); }
// storeDb.SaveChanges();
// //Bug: TODO //
// //Session[ShoppingCart.CartSessionKey] = UserName; // GET: /Account/Register
// } [AllowAnonymous]
public IActionResult Register()
{
return View();
}
// // //
// // GET: /Account/Login // POST: /Account/Register
// [AllowAnonymous] //Bug: Missing verb attributes
// public IActionResult Login(string returnUrl) //[HttpPost]
// { [AllowAnonymous]
// //ViewBag.ReturnUrl = returnUrl; //[ValidateAntiForgeryToken]
// return View(); public async Task<IActionResult> Register(RegisterViewModel model)
// } {
if (ModelState.IsValid == true)
{
var user = new ApplicationUser() { UserName = model.UserName };
var result = await UserManager.Create(user, model.Password);
if (result.Succeeded)
{
await SignIn(user, isPersistent: false);
//Bug: No helper methods
//return RedirectToAction("Index", "Home");
}
else
{
AddErrors(result);
}
}
// // // If we got this far, something failed, redisplay form
// // POST: /Account/Login return View(model);
// //Bug: HTTP verb attribs not available }
// //[HttpPost]
// [AllowAnonymous] //
// //[ValidateAntiForgeryToken] // POST: /Account/Disassociate
// public async Task<IActionResult> Login(LoginViewModel model, string returnUrl) //Bug: HTTP verbs
//[HttpPost]
//[ValidateAntiForgeryToken]
public async Task<IActionResult> Disassociate(string loginProvider, string providerKey)
{
ManageMessageId? message = null;
IdentityResult result = await UserManager.RemoveLogin(this.Context.User.Identity.GetUserId(), new UserLoginInfo(loginProvider, providerKey));
if (result.Succeeded)
{
message = ManageMessageId.RemoveLoginSuccess;
}
else
{
message = ManageMessageId.Error;
}
//Bug: No helpers available
//return RedirectToAction("Manage", new { Message = message });
return View();
}
//
// GET: /Account/Manage
public IActionResult Manage(ManageMessageId? message)
{
ViewBag.StatusMessage =
message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
: message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
: message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
: message == ManageMessageId.Error ? "An error has occurred."
: "";
ViewBag.HasLocalPassword = HasPassword();
//Bug: No Action method with single parameter
//ViewBag.ReturnUrl = Url.Action("Manage");
//ViewBag.ReturnUrl = Url.Action("Manage", "Account", null);
return View();
}
//
// POST: /Account/Manage
//Bug: No verb attributes
//[HttpPost]
//[ValidateAntiForgeryToken]
public async Task<IActionResult> Manage(ManageUserViewModel model)
{
bool hasPassword = await HasPassword();
ViewBag.HasLocalPassword = hasPassword;
//Bug: No Action method with single parameter
//ViewBag.ReturnUrl = Url.Action("Manage");
//ViewBag.ReturnUrl = Url.Action("Manage", "Account", null);
if (hasPassword)
{
if (ModelState.IsValid == true)
{
IdentityResult result = await UserManager.ChangePassword(this.Context.User.Identity.GetUserId(), model.OldPassword, model.NewPassword);
if (result.Succeeded)
{
//Bug: No helper method
//return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess });
return View();
}
else
{
AddErrors(result);
}
}
}
else
{
// User does not have a password so remove any validation errors caused by a missing OldPassword field
ModelState state = null;
ModelState.TryGetValue("OldPassword", out state);
if (state != null)
{
state.Errors.Clear();
}
if (ModelState.IsValid == true)
{
IdentityResult result = await UserManager.AddPassword(this.Context.User.Identity.GetUserId(), model.NewPassword);
if (result.Succeeded)
{
//Bug: No helper method
//return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess });
}
else
{
AddErrors(result);
}
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
//
// POST: /Account/ExternalLogin
//Bug: No verb attributes
//[HttpPost]
[AllowAnonymous]
//[ValidateAntiForgeryToken]
public IActionResult ExternalLogin(string provider, string returnUrl)
{
// Request a redirect to the external login provider
return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
}
//
// GET: /Account/ExternalLoginCallback
[AllowAnonymous]
public async Task<IActionResult> ExternalLoginCallback(string returnUrl)
{
var loginInfo = await this.Context.Response.GetExternalLoginInfo();
if (loginInfo == null)
{
//Bug: No helper
//return RedirectToAction("Login");
return View();
}
// Sign in the user with this external login provider if the user already has a login
var user = await UserManager.Find(loginInfo.Login);
if (user != null)
{
await SignIn(user, isPersistent: false);
return RedirectToLocal(returnUrl);
}
else
{
// If the user does not have an account, then prompt the user to create an account
ViewBag.ReturnUrl = returnUrl;
ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { UserName = loginInfo.DefaultUserName });
}
}
//
// POST: /Account/LinkLogin
//Bug: No HTTP verbs
//[HttpPost]
//[ValidateAntiForgeryToken]
public IActionResult 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", null), this.Context.User.Identity.GetUserId());
}
//
// GET: /Account/LinkLoginCallback
public async Task<IActionResult> LinkLoginCallback()
{
var loginInfo = await this.Context.Response.GetExternalLoginInfo(XsrfKey, this.Context.User.Identity.GetUserId());
if (loginInfo == null)
{
//Bug: No helper method
//return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
return View();
}
var result = await UserManager.AddLogin(this.Context.User.Identity.GetUserId(), loginInfo.Login);
if (result.Succeeded)
{
//Bug: No helper method
//return RedirectToAction("Manage");
return View();
}
//Bug: No helper method
//return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
return View();
}
//
// POST: /Account/ExternalLoginConfirmation
//Bug: No HTTP verbs
//[HttpPost]
[AllowAnonymous]
//[ValidateAntiForgeryToken]
public async Task<IActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl)
{
if (this.Context.User.Identity.IsAuthenticated)
{
//Bug: No helper yet
//return RedirectToAction("Manage");
return View();
}
if (ModelState.IsValid == true)
{
// Get the information about the user from the external login provider
var info = await this.Context.Response.GetExternalLoginInfo();
if (info == null)
{
return View("ExternalLoginFailure");
}
var user = new ApplicationUser() { UserName = model.UserName };
var result = await UserManager.Create(user);
if (result.Succeeded)
{
result = await UserManager.AddLogin(user.Id, info.Login);
if (result.Succeeded)
{
await SignIn(user, isPersistent: false);
return RedirectToLocal(returnUrl);
}
}
AddErrors(result);
}
ViewBag.ReturnUrl = returnUrl;
return View(model);
}
//
// POST: /Account/LogOff
//Bug: No HTTP verbs
//[HttpPost]
//[ValidateAntiForgeryToken]
public IActionResult LogOff()
{
this.Context.Response.SignOut();
//Bug: No helper
//return RedirectToAction("Index", "Home");
return View();
}
//
// GET: /Account/ExternalLoginFailure
[AllowAnonymous]
public IActionResult ExternalLoginFailure()
{
return View();
}
//Bug: Need this attribute
//[ChildActionOnly]
public async Task<IActionResult> RemoveAccountList()
{
var linkedAccounts = await UserManager.GetLogins(this.Context.User.Identity.GetUserId());
ViewBag.ShowRemoveButton = await HasPassword() || linkedAccounts.Count > 1;
//Bug: We dont have partial views yet
//return (IActionResult)PartialView("_RemoveAccountPartial", linkedAccounts);
return View();
}
//Bug: Controllers need to be disposable?
protected void Dispose(bool disposing)
{
if (disposing && UserManager != null)
{
UserManager.Dispose();
UserManager = null;
}
//base.Dispose(disposing);
}
#region Helpers
// Used for XSRF protection when adding external logins
private const string XsrfKey = "XsrfId";
private async Task SignIn(ApplicationUser user, bool isPersistent)
{
this.Context.Response.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentity(user, DefaultAuthenticationTypes.ApplicationCookie);
this.Context.Response.SignIn(identity, new AuthenticationProperties() { IsPersistent = isPersistent });
}
private void AddErrors(IdentityResult result)
{
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error);
}
}
private async Task<bool> HasPassword()
{
var user = await UserManager.FindById(this.Context.User.Identity.GetUserId());
if (user != null)
{
return user.PasswordHash != null;
}
return false;
}
public enum ManageMessageId
{
ChangePasswordSuccess,
SetPasswordSuccess,
RemoveLoginSuccess,
Error
}
private IActionResult RedirectToLocal(string returnUrl)
{
//Bug: No helpers available
//if (Url.IsLocalUrl(returnUrl))
//{ //{
// //Bug: How to validate the model state? // return Redirect(returnUrl);
// //if (ModelState.IsValid)
// {
// var user = await UserManager.Find(model.UserName, model.Password);
// if (user != null)
// {
// await SignIn(user, model.RememberMe);
// return RedirectToLocal(returnUrl);
//} //}
//else //else
//{ //{
// //Bug: Model state error // return RedirectToAction("Index", "Home");
// //ModelState.AddModelError("", "Invalid username or password.");
// }
//} //}
return View();
}
// // If we got this far, something failed, redisplay form private class ChallengeResult : HttpStatusCodeResult
// return View(model); {
// } public ChallengeResult(string provider, string redirectUri)
: this(provider, redirectUri, null)
{
}
// // public ChallengeResult(string provider, string redirectUri, string userId)
// // GET: /Account/Register : base(401)
// [AllowAnonymous] {
// public IActionResult Register() LoginProvider = provider;
// { RedirectUri = redirectUri;
// return View(); UserId = userId;
// } }
// // public string LoginProvider { get; set; }
// // POST: /Account/Register public string RedirectUri { get; set; }
// //Bug: Missing verb attributes public string UserId { get; set; }
// //[HttpPost]
// [AllowAnonymous]
// //[ValidateAntiForgeryToken]
// public async Task<IActionResult> Register(RegisterViewModel model)
// {
// //Bug: How to validate the model state?
// //if (ModelState.IsValid)
// {
// //Bug: Replacing it with InmemoryUser
// var user = new ApplicationUser() { UserName = model.UserName };
// var result = await UserManager.Create(user, model.Password);
// if (result.Succeeded)
// {
// await SignIn(user, isPersistent: false);
// //Bug: No helper methods
// //return RedirectToAction("Index", "Home");
// }
// else
// {
// AddErrors(result);
// }
// }
// // If we got this far, something failed, redisplay form new public void ExecuteResultAsync(ActionContext context)
// return View(model); {
// } var properties = new AuthenticationProperties() { RedirectUri = RedirectUri };
if (UserId != null)
{
properties.Dictionary[XsrfKey] = UserId;
}
// // context.HttpContext.Response.Challenge(LoginProvider, properties);
// // POST: /Account/Disassociate }
// //Bug: HTTP verbs }
// //[HttpPost] #endregion
// //[ValidateAntiForgeryToken] }
// public async Task<IActionResult> Disassociate(string loginProvider, string providerKey)
// {
// ManageMessageId? message = null;
// IdentityResult result = await UserManager.RemoveLogin(User.Identity.GetUserId(), new UserLoginInfo(loginProvider, providerKey));
// if (result.Succeeded)
// {
// message = ManageMessageId.RemoveLoginSuccess;
// }
// else
// {
// message = ManageMessageId.Error;
// }
// //Bug: No helpers available
// //return RedirectToAction("Manage", new { Message = message });
// return View();
// }
// // /// <summary>
// // GET: /Account/Manage /// TODO: Temporary APIs to unblock build. Need to remove this once we have these APIs available.
// public IActionResult Manage(ManageMessageId? message) /// </summary>
// { public static class Extensions
// //ViewBag.StatusMessage = {
// // message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed." public static string GetUserId(this IIdentity user)
// // : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set." {
// // : message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed." return string.Empty;
// // : message == ManageMessageId.Error ? "An error has occurred." }
// // : "";
// //ViewBag.HasLocalPassword = HasPassword();
// //Bug: No Action method with single parameter
// //ViewBag.ReturnUrl = Url.Action("Manage");
// //ViewBag.ReturnUrl = Url.Action("Manage", "Account", null);
// return View();
// }
// // public static Task<ExternalLoginInfo> GetExternalLoginInfo(this HttpResponse response)
// // POST: /Account/Manage {
// //Bug: No verb attributes return Task.FromResult<ExternalLoginInfo>(new ExternalLoginInfo());
// //[HttpPost] }
// //[ValidateAntiForgeryToken]
// public async Task<IActionResult> Manage(ManageUserViewModel model)
// {
// bool hasPassword = await HasPassword();
// //ViewBag.HasLocalPassword = hasPassword;
// //Bug: No Action method with single parameter
// //ViewBag.ReturnUrl = Url.Action("Manage");
// //ViewBag.ReturnUrl = Url.Action("Manage", "Account", null);
// if (hasPassword)
// {
// //if (ModelState.IsValid)
// {
// IdentityResult result = await UserManager.ChangePassword(User.Identity.GetUserId(), model.OldPassword, model.NewPassword);
// if (result.Succeeded)
// {
// //Bug: No helper method
// //return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess });
// return View();
// }
// else
// {
// AddErrors(result);
// }
// }
// }
// else
// {
// // User does not have a password so remove any validation errors caused by a missing OldPassword field
// //Bug: Still controller does not have a ModelState property
// //ModelState state = ModelState["OldPassword"];
// ModelState state = null;
// if (state != null) public static Task<ExternalLoginInfo> GetExternalLoginInfo(this HttpResponse response, string xsrfKey, string expectedValue)
// { {
// state.Errors.Clear(); return Task.FromResult<ExternalLoginInfo>(new ExternalLoginInfo());
// } }
}
// //Bug: No model state validation /// <summary>
// //if (ModelState.IsValid) /// TODO: Temporary APIs to unblock build. Need to remove this once we have these APIs available.
// { /// </summary>
// IdentityResult result = await UserManager.AddPassword(User.Identity.GetUserId(), model.NewPassword); public class ExternalLoginInfo
// if (result.Succeeded) {
// { public string DefaultUserName { get; set; }
// //Bug: No helper method public UserLoginInfo Login { get; set; }
// //return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess }); }
// }
// else
// {
// AddErrors(result);
// }
// }
// }
// // If we got this far, something failed, redisplay form /// <summary>
// return View(model); /// TODO: Temporary APIs to unblock build. Need to remove this once we have these APIs available.
// } /// </summary>
public static class DefaultAuthenticationTypes
// // {
// // POST: /Account/ExternalLogin public const string ApplicationCookie = "Application";
// //Bug: No verb attributes public const string ExternalCookie = "External";
// //[HttpPost] }
// [AllowAnonymous] }
// //[ValidateAntiForgeryToken]
// public IActionResult ExternalLogin(string provider, string returnUrl)
// {
// // Request a redirect to the external login provider
// return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
// }
// //
// // GET: /Account/ExternalLoginCallback
// [AllowAnonymous]
// public async Task<IActionResult> ExternalLoginCallback(string returnUrl)
// {
// var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
// if (loginInfo == null)
// {
// //Bug: No helper
// //return RedirectToAction("Login");
// return View();
// }
// // Sign in the user with this external login provider if the user already has a login
// var user = await UserManager.Find(loginInfo.Login);
// if (user != null)
// {
// await SignIn(user, isPersistent: false);
// return RedirectToLocal(returnUrl);
// }
// else
// {
// // If the user does not have an account, then prompt the user to create an account
// //ViewBag.ReturnUrl = returnUrl;
// //ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
// return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { UserName = loginInfo.DefaultUserName });
// }
// }
// //
// // POST: /Account/LinkLogin
// //Bug: No HTTP verbs
// //[HttpPost]
// //[ValidateAntiForgeryToken]
// public IActionResult 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", null), User.Identity.GetUserId());
// }
// //
// // GET: /Account/LinkLoginCallback
// public async Task<IActionResult> LinkLoginCallback()
// {
// var loginInfo = null;// await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId());
// if (loginInfo == null)
// {
// //Bug: No helper method
// //return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
// return View();
// }
// var result = await UserManager.AddLogin(User.Identity.GetUserId(), loginInfo.Login);
// if (result.Succeeded)
// {
// //Bug: No helper method
// //return RedirectToAction("Manage");
// return View();
// }
// //Bug: No helper method
// //return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
// return View();
// }
// //
// // POST: /Account/ExternalLoginConfirmation
// //Bug: No HTTP verbs
// //[HttpPost]
// [AllowAnonymous]
// //[ValidateAntiForgeryToken]
// public async Task<IActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl)
// {
// if (User.Identity.IsAuthenticated)
// {
// //Bug: No helper yet
// //return RedirectToAction("Manage");
// return View();
// }
// //Bug: No model state validation
// //if (ModelState.IsValid)
// {
// // Get the information about the user from the external login provider
// var info = await AuthenticationManager.GetExternalLoginInfoAsync();
// if (info == null)
// {
// return View("ExternalLoginFailure");
// }
// //Using InMemory user
// var user = new ApplicationUser() { UserName = model.UserName };
// var result = await UserManager.Create(user);
// if (result.Succeeded)
// {
// result = await UserManager.AddLogin(user.Id, info.Login);
// if (result.Succeeded)
// {
// await SignIn(user, isPersistent: false);
// return RedirectToLocal(returnUrl);
// }
// }
// AddErrors(result);
// }
// //ViewBag.ReturnUrl = returnUrl;
// return View(model);
// }
// //
// // POST: /Account/LogOff
// //Bug: No HTTP verbs
// //[HttpPost]
// //[ValidateAntiForgeryToken]
// public IActionResult LogOff()
// {
// AuthenticationManager.SignOut();
// //return RedirectToAction("Index", "Home");
// return View();
// }
// //
// // GET: /Account/ExternalLoginFailure
// [AllowAnonymous]
// public IActionResult ExternalLoginFailure()
// {
// return View();
// }
// //Bug: Need this attribute
// //[ChildActionOnly]
// public async Task<IActionResult> RemoveAccountList()
// {
// var linkedAccounts = await UserManager.GetLogins(User.Identity.GetUserId());
// //ViewBag.ShowRemoveButton = await HasPassword() || linkedAccounts.Count > 1;
// //Bug: We dont have partial views yet
// //return (IActionResult)PartialView("_RemoveAccountPartial", linkedAccounts);
// return View();
// }
// //Bug: Controllers need to be disposable?
// protected void Dispose(bool disposing)
// {
// if (disposing && UserManager != null)
// {
// UserManager.Dispose();
// UserManager = null;
// }
// //base.Dispose(disposing);
// }
// #region Helpers
// // Used for XSRF protection when adding external logins
// private const string XsrfKey = "XsrfId";
// //private IAuthenticationManager AuthenticationManager
// //{
// // get
// // {
// // //Will change to Context.Authentication
// // return new IAuthenticationManager();
// // }
// //}
// private async Task SignIn(ApplicationUser user, bool isPersistent)
// {
// //Bug: No cookies middleware now.
// //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
// MigrateShoppingCart(user.UserName);
// }
// private void AddErrors(IdentityResult result)
// {
// foreach (var error in result.Errors)
// {
// //ModelState.AddModelError("", error);
// }
// }
// private async Task<bool> HasPassword()
// {
// //Bug: Need to get the User object somehow: TODO
// //var user = await UserManager.FindById(User.Identity.GetUserId());
// var user = await UserManager.FindById("TODO");
// if (user != null)
// {
// return user.PasswordHash != null;
// }
// return false;
// }
// public enum ManageMessageId
// {
// ChangePasswordSuccess,
// SetPasswordSuccess,
// RemoveLoginSuccess,
// Error
// }
// private IActionResult RedirectToLocal(string returnUrl)
// {
// //Bug: No helpers available
// //if (Url.IsLocalUrl(returnUrl))
// //{
// // return Redirect(returnUrl);
// //}
// //else
// //{
// // return RedirectToAction("Index", "Home");
// //}
// return View();
// }
// private class ChallengeResult : HttpStatusCodeResult
// {
// public ChallengeResult(string provider, string redirectUri)
// : this(provider, redirectUri, null)
// {
// }
// public ChallengeResult(string provider, string redirectUri, string userId)
// : base(401)
// {
// LoginProvider = provider;
// RedirectUri = redirectUri;
// UserId = userId;
// }
// public string LoginProvider { get; set; }
// public string RedirectUri { get; set; }
// public string UserId { get; set; }
// new public void ExecuteResultAsync(ActionContext context)
// {
// //Bug: No security package yet
// //var properties = new AuthenticationProperties() { RedirectUri = RedirectUri };
// //if (UserId != null)
// //{
// // properties.Dictionary[XsrfKey] = UserId;
// //}
// //context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
// }
// }
// #endregion
// }
// //Bug: To remove this. Until we have ClaimsPrincipal available
// internal class User
// {
// public static IdentityInstance Identity { get; set; }
// public User()
// {
// if (Identity == null)
// {
// Identity = new IdentityInstance();
// }
// }
// internal class IdentityInstance
// {
// public string GetUserId()
// {
// return string.Empty;
// }
// public bool IsAuthenticated { get; set; }
// }
// }
//}

View File

@ -1,6 +1,4 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc;
using MusicStore.Models; using MusicStore.Models;
using System; using System;
using System.Linq; using System.Linq;
@ -26,20 +24,16 @@ namespace MusicStore.Controllers
// //
// POST: /Checkout/AddressAndPayment // POST: /Checkout/AddressAndPayment
//Bug: Http verbs not available. Also binding to FormCollection is not available. //Bug: Http verbs not available.
//Bug: Using direct model binding until we have TryUpdateModel available.
//[HttpPost] //[HttpPost]
//public IActionResult AddressAndPayment(FormCollection values) //public IActionResult AddressAndPayment(FormCollection values)
public async Task<IActionResult> AddressAndPayment(int workaroundId) public async Task<IActionResult> AddressAndPayment(Order order)
{ {
var formCollection = await Context.Request.GetFormAsync(); var formCollection = await Context.Request.GetFormAsync();
var order = new Order();
//TryUpdateModel(order);
try try
{ {
//if (string.Equals(values["PromoCode"], PromoCode,
// StringComparison.OrdinalIgnoreCase) == false)
if (string.Equals(formCollection.GetValues("PromoCode").FirstOrDefault(), PromoCode, if (string.Equals(formCollection.GetValues("PromoCode").FirstOrDefault(), PromoCode,
StringComparison.OrdinalIgnoreCase) == false) StringComparison.OrdinalIgnoreCase) == false)
{ {
@ -52,20 +46,9 @@ namespace MusicStore.Controllers
? db.Orders.Max(o => o.OrderId) + 1 ? db.Orders.Max(o => o.OrderId) + 1
: 1; : 1;
//Bug: Object values should come from page (putting in hard coded values as EF can't work with nulls against SQL Server yet)
//Bug: Identity not available
order.Username = "unknown"; //User.Identity.Name;
order.OrderId = nextId; order.OrderId = nextId;
order.Username = this.Context.User.Identity.Name;
order.OrderDate = DateTime.Now; order.OrderDate = DateTime.Now;
order.FirstName = "John";
order.LastName = "Doe";
order.Address = "One Microsoft Way";
order.City = "Redmond";
order.State = "WA";
order.Country = "USA";
order.Email = "john.doe@example.com";
order.Phone = "555-555-5555";
order.PostalCode = "98052";
//Add the Order //Add the Order
db.Orders.Add(order); db.Orders.Add(order);
@ -82,7 +65,6 @@ namespace MusicStore.Controllers
// new { id = order.OrderId }); // new { id = order.OrderId });
return View(); return View();
} }
} }
catch catch
{ {
@ -97,13 +79,9 @@ namespace MusicStore.Controllers
public IActionResult Complete(int id) public IActionResult Complete(int id)
{ {
// Validate customer owns this order // Validate customer owns this order
//Bug: Identity not available
//bool isValid = storeDB.Orders.Any(
// o => o.OrderId == id &&
// o.Username == User.Identity.Name);
bool isValid = db.Orders.Any( bool isValid = db.Orders.Any(
o => o.OrderId == id); o => o.OrderId == id &&
o.Username == this.Context.User.Identity.Name);
if (isValid) if (isValid)
{ {

View File

@ -1,6 +1,4 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc;
using MusicStore.Models; using MusicStore.Models;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;

View File

@ -1,6 +1,4 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc;
using MusicStore.Models; using MusicStore.Models;
using MusicStore.ViewModels; using MusicStore.ViewModels;
using System.Linq; using System.Linq;
@ -64,7 +62,7 @@ namespace MusicStore.Controllers
// Get the name of the album to display confirmation // Get the name of the album to display confirmation
// TODO [EF] Turn into one query once query of related data is enabled // TODO [EF] Turn into one query once query of related data is enabled
int albumId = db.Carts.Single(item => item.CartItemId == id).AlbumId; int albumId = db.CartItems.Single(item => item.CartItemId == id).AlbumId;
string albumName = db.Albums.Single(a => a.AlbumId == albumId).Title; string albumName = db.Albums.Single(a => a.AlbumId == albumId).Title;
// Remove from cart // Remove from cart

View File

@ -1,6 +1,4 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc;
using MusicStore.Models; using MusicStore.Models;
using System.Linq; using System.Linq;

View File

@ -1,6 +1,4 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.Data.Entity; using Microsoft.Data.Entity;
using MusicStore.Models; using MusicStore.Models;
@ -49,32 +47,31 @@ namespace MusicStore.Controllers
// //
// GET: /StoreManager/Create // GET: /StoreManager/Create
//public IActionResult Create() public IActionResult Create()
//{ {
//ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name"); //ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name");
//ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name"); //ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name");
// return View(); return View();
//} }
//Bug: ModelState.IsValid not available
//Bug: RedirectToAction() not available
//Bug: SelectList not available //Bug: SelectList not available
// POST: /StoreManager/Create // POST: /StoreManager/Create
//[HttpPost] //[HttpPost]
//public IActionResult Create(Album album) public IActionResult Create(Album album)
//{ {
// if (ModelState.IsValid) if (ModelState.IsValid == true)
// { {
// db.Albums.Add(album); db.Albums.Add(album);
// db.SaveChanges(); db.SaveChanges();
//Bug: RedirectToAction() not available
//return RedirectToAction("Index"); //return RedirectToAction("Index");
// } return View();
}
//ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name", album.GenreId); //ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name", album.GenreId);
//ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId); //ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId);
// return View(album); return View(album);
//} }
// //
// GET: /StoreManager/Edit/5 // GET: /StoreManager/Edit/5
@ -100,13 +97,13 @@ namespace MusicStore.Controllers
//[HttpPost] //[HttpPost]
public IActionResult Edit(Album album) public IActionResult Edit(Album album)
{ {
//Bug: ModelState.IsValid missing if (ModelState.IsValid == true)
//if (ModelState.IsValid)
{ {
db.ChangeTracker.Entry(album).State = EntityState.Modified; db.ChangeTracker.Entry(album).State = EntityState.Modified;
db.SaveChanges(); db.SaveChanges();
//Bug: Missing RedirectToAction helper //Bug: Missing RedirectToAction helper
//return RedirectToAction("Index"); //return RedirectToAction("Index");
return View();
} }
//ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name", album.GenreId); //ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name", album.GenreId);
//ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId); //ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId);

View File

@ -1,3 +1,6 @@
REM run on k10 by default. Assign it to an empty value to run on desktop CLR.
SET TARGET_FRAMEWORK=k10
REM Selfhost does not need this bin folder REM Selfhost does not need this bin folder
rmdir /S /Q bin rmdir /S /Q bin

View File

@ -1 +1,4 @@
REM copy the AspNet.Loader.dll to the bin folder
call CopyAspNetLoader.cmd
"%ProgramFiles(x86)%\iis Express\iisexpress.exe" /port:5001 /path:"%cd%" "%ProgramFiles(x86)%\iis Express\iisexpress.exe" /port:5001 /path:"%cd%"

View File

@ -1,31 +1,32 @@
{ {
"version": "0.1-alpha-*", "version": "0.1-alpha-*",
"dependencies": { "dependencies": {
"Helios": "0.1-alpha-107", "Helios": "0.1-alpha-168",
"Microsoft.AspNet.Abstractions": "0.1-alpha-162", "Microsoft.AspNet.Abstractions": "0.1-alpha-210",
"Microsoft.AspNet.Mvc": "0.1-alpha-324", "Microsoft.AspNet.Mvc": "0.1-alpha-449",
"Microsoft.AspNet.Razor": "0.1-alpha-144", "Microsoft.AspNet.Razor": "0.1-alpha-181",
"Microsoft.AspNet.ConfigurationModel": "0.1-alpha-117", "Microsoft.AspNet.ConfigurationModel": "0.1-alpha-167",
"Microsoft.AspNet.DependencyInjection": "0.1-alpha-169", "Microsoft.AspNet.DependencyInjection": "0.1-alpha-232",
"Microsoft.AspNet.RequestContainer": "0.1-alpha-133", "Microsoft.AspNet.RequestContainer": "0.1-alpha-201",
"Microsoft.AspNet.Routing": "0.1-alpha-115", "Microsoft.AspNet.Routing": "0.1-alpha-182",
"Microsoft.AspNet.Mvc.ModelBinding": "0.1-alpha-324", "Microsoft.AspNet.Mvc.ModelBinding": "0.1-alpha-449",
"Microsoft.AspNet.Mvc.Core": "0.1-alpha-324", "Microsoft.AspNet.Mvc.Core": "0.1-alpha-449",
"Microsoft.AspNet.Mvc.Razor": "0.1-alpha-324", "Microsoft.AspNet.Mvc.Razor": "0.1-alpha-449",
"Microsoft.AspNet.Mvc.Rendering": "0.1-alpha-324", "Microsoft.AspNet.Mvc.Rendering": "0.1-alpha-449",
"Microsoft.AspNet.StaticFiles": "0.1-alpha-090", "Microsoft.AspNet.StaticFiles": "0.1-alpha-146",
"System.Security.Claims": "0.1-alpha-052", "System.Security.Claims": "0.1-alpha-094",
"Microsoft.AspNet.Security.DataProtection": "0.1-alpha-100", "System.Security.Principal": "4.0.0.0",
"Microsoft.AspNet.Identity": "0.1-alpha-164", "Microsoft.AspNet.Security.DataProtection": "0.1-alpha-141",
"Microsoft.AspNet.Identity.Entity": "0.1-alpha-164", "Microsoft.AspNet.Identity": "0.1-alpha-238",
"Microsoft.AspNet.Identity.InMemory": "0.1-alpha-164", "Microsoft.AspNet.Identity.Entity": "0.1-alpha-238",
"Microsoft.Data.Entity": "0.1-alpha-284", "Microsoft.AspNet.Identity.InMemory": "0.1-alpha-238",
"Microsoft.Data.Relational": "0.1-alpha-284", "Microsoft.Data.Entity": "0.1-alpha-380",
"Microsoft.Data.SqlServer": "0.1-pre-284", "Microsoft.Data.Relational": "0.1-alpha-380",
"Microsoft.Data.InMemory": "0.1-alpha-284", "Microsoft.Data.SqlServer": "0.1-pre-380",
"Microsoft.AspNet.Diagnostics": "0.1-alpha-025", "Microsoft.Data.InMemory": "0.1-alpha-380",
"Microsoft.AspNet.Hosting": "0.1-alpha-133", "Microsoft.AspNet.Diagnostics": "0.1-alpha-081",
"Microsoft.AspNet.Server.WebListener": "0.1-alpha-039" "Microsoft.AspNet.Hosting": "0.1-alpha-201",
"Microsoft.AspNet.Server.WebListener": "0.1-alpha-105"
}, },
"configurations": { "configurations": {
"net45": { "net45": {
@ -41,7 +42,7 @@
"System.Linq": "4.0.0.0", "System.Linq": "4.0.0.0",
"System.Runtime": "4.0.20.0", "System.Runtime": "4.0.20.0",
"System.Dynamic.Runtime": "4.0.0.0", "System.Dynamic.Runtime": "4.0.0.0",
"System.Threading.Tasks": "4.0.0.0", "System.Threading.Tasks": "4.0.10.0",
"System.ComponentModel": "4.0.0.0", "System.ComponentModel": "4.0.0.0",
"System.Console": "4.0.0.0", "System.Console": "4.0.0.0",
"System.Diagnostics.Debug": "4.0.10.0", "System.Diagnostics.Debug": "4.0.10.0",

View File

@ -1,6 +1,4 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations;
namespace MusicStore.Models namespace MusicStore.Models
{ {

View File

@ -1,6 +1,4 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System.Collections.Generic;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace MusicStore.Models namespace MusicStore.Models

View File

@ -1,6 +1,4 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations;
namespace MusicStore.Models namespace MusicStore.Models
{ {

View File

@ -1,12 +1,11 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System;
using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace MusicStore.Models namespace MusicStore.Models
{ {
public class CartItem public class CartItem
{ {
[Key]
public int CartItemId { get; set; } public int CartItemId { get; set; }
[Required] [Required]

View File

@ -1,6 +1,4 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System.Collections.Generic;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace MusicStore.Models namespace MusicStore.Models

View File

@ -1,6 +1,4 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using Microsoft.AspNet.Identity.InMemory;
using Microsoft.AspNet.Identity.InMemory;
namespace MusicStore.Models namespace MusicStore.Models
{ {

View File

@ -1,6 +1,4 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using Microsoft.Data.Entity;
using Microsoft.Data.Entity;
using Microsoft.Data.Entity.Metadata; using Microsoft.Data.Entity.Metadata;
using Microsoft.Data.InMemory; using Microsoft.Data.InMemory;
using Microsoft.Data.SqlServer; using Microsoft.Data.SqlServer;
@ -13,7 +11,7 @@ namespace MusicStore.Models
public EntitySet<Artist> Artists { get; set; } public EntitySet<Artist> Artists { get; set; }
public EntitySet<Order> Orders { get; set; } public EntitySet<Order> Orders { get; set; }
public EntitySet<Genre> Genres { get; set; } public EntitySet<Genre> Genres { get; set; }
public EntitySet<CartItem> Carts { get; set; } public EntitySet<CartItem> CartItems { get; set; }
public EntitySet<OrderDetail> OrderDetails { get; set; } public EntitySet<OrderDetail> OrderDetails { get; set; }
protected override void OnConfiguring(EntityConfigurationBuilder builder) protected override void OnConfiguring(EntityConfigurationBuilder builder)

View File

@ -1,6 +1,4 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System.Collections.Generic;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace MusicStore.Models namespace MusicStore.Models

View File

@ -1,6 +1,4 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. namespace MusicStore.Models
namespace MusicStore.Models
{ {
public class OrderDetail public class OrderDetail
{ {

View File

@ -1,6 +1,4 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using Microsoft.Data.Entity;
using Microsoft.Data.Entity;
using Microsoft.Data.SqlServer; using Microsoft.Data.SqlServer;
using MusicStore.Models; using MusicStore.Models;
using System; using System;

View File

@ -1,7 +1,4 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using Microsoft.AspNet.Abstractions;
using Microsoft.AspNet.Abstractions;
using Microsoft.AspNet.Mvc;
using Microsoft.Data.Entity; using Microsoft.Data.Entity;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -19,8 +16,6 @@ namespace MusicStore.Models
_db = db; _db = db;
} }
public const string CartSessionKey = "CartId";
public static ShoppingCart GetCart(MusicStoreContext db, HttpContext context) public static ShoppingCart GetCart(MusicStoreContext db, HttpContext context)
{ {
var cart = new ShoppingCart(db); var cart = new ShoppingCart(db);
@ -38,15 +33,15 @@ namespace MusicStore.Models
public void AddToCart(Album album) public void AddToCart(Album album)
{ {
// Get the matching cart and album instances // Get the matching cart and album instances
var cartItem = _db.Carts.SingleOrDefault( var cartItem = _db.CartItems.SingleOrDefault(
c => c.CartId == ShoppingCartId c => c.CartId == ShoppingCartId
&& c.AlbumId == album.AlbumId); && c.AlbumId == album.AlbumId);
if (cartItem == null) if (cartItem == null)
{ {
// TODO [EF] Swap to store generated key once we support identity pattern // TODO [EF] Swap to store generated key once we support identity pattern
var nextCartItemId = _db.Carts.Any() var nextCartItemId = _db.CartItems.Any()
? _db.Carts.Max(c => c.CartItemId) + 1 ? _db.CartItems.Max(c => c.CartItemId) + 1
: 1; : 1;
// Create a new cart item if no cart item exists // Create a new cart item if no cart item exists
@ -59,7 +54,7 @@ namespace MusicStore.Models
DateCreated = DateTime.Now DateCreated = DateTime.Now
}; };
_db.Carts.Add(cartItem); _db.CartItems.Add(cartItem);
} }
else else
{ {
@ -67,14 +62,14 @@ namespace MusicStore.Models
cartItem.Count++; cartItem.Count++;
// TODO [EF] Remove this line once change detection is available // TODO [EF] Remove this line once change detection is available
_db.ChangeTracker.Entry(cartItem).State = Microsoft.Data.Entity.EntityState.Modified; _db.ChangeTracker.Entry(cartItem).State = EntityState.Modified;
} }
} }
public int RemoveFromCart(int id) public int RemoveFromCart(int id)
{ {
// Get the cart // Get the cart
var cartItem = _db.Carts.Single( var cartItem = _db.CartItems.Single(
cart => cart.CartId == ShoppingCartId cart => cart.CartId == ShoppingCartId
&& cart.CartItemId == id); && cart.CartItemId == id);
@ -93,7 +88,7 @@ namespace MusicStore.Models
} }
else else
{ {
_db.Carts.Remove(cartItem); _db.CartItems.Remove(cartItem);
} }
} }
@ -103,7 +98,7 @@ namespace MusicStore.Models
public void EmptyCart() public void EmptyCart()
{ {
var cartItems = _db.Carts.Where(cart => cart.CartId == ShoppingCartId); var cartItems = _db.CartItems.Where(cart => cart.CartId == ShoppingCartId);
foreach (var cartItem in cartItems) foreach (var cartItem in cartItems)
{ {
@ -115,13 +110,13 @@ namespace MusicStore.Models
public List<CartItem> GetCartItems() public List<CartItem> GetCartItems()
{ {
return _db.Carts.Where(cart => cart.CartId == ShoppingCartId).ToList(); return _db.CartItems.Where(cart => cart.CartId == ShoppingCartId).ToList();
} }
public int GetCount() public int GetCount()
{ {
// Get the count of each item in the cart and sum them up // Get the count of each item in the cart and sum them up
int? count = (from cartItems in _db.Carts int? count = (from cartItems in _db.CartItems
where cartItems.CartId == ShoppingCartId where cartItems.CartId == ShoppingCartId
select (int?)cartItems.Count).Sum(); select (int?)cartItems.Count).Sum();
@ -137,7 +132,7 @@ namespace MusicStore.Models
// TODO Collapse to a single query once EF supports querying related data // TODO Collapse to a single query once EF supports querying related data
decimal total = 0; decimal total = 0;
foreach (var item in _db.Carts.Where(c => c.CartId == ShoppingCartId)) foreach (var item in _db.CartItems.Where(c => c.CartId == ShoppingCartId))
{ {
var album = _db.Albums.Single(a => a.AlbumId == item.AlbumId); var album = _db.Albums.Single(a => a.AlbumId == item.AlbumId);
total += item.Count * album.Price; total += item.Count * album.Price;
@ -194,38 +189,23 @@ namespace MusicStore.Models
// We're using HttpContextBase to allow access to cookies. // We're using HttpContextBase to allow access to cookies.
public string GetCartId(HttpContext context) public string GetCartId(HttpContext context)
{ {
//Bug: Session not in scope. But we should substitute this with cookies when available. var sessionCookie = context.Request.Cookies.Get("Session");
//if (context.Session[CartSessionKey] == null) string cartId = 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 if (string.IsNullOrWhiteSpace(sessionCookie))
// context.Session[CartSessionKey] = tempCartId.ToString();
// }
//}
//return context.Session[CartSessionKey].ToString();
return string.Empty;
}
// When a user has logged in, migrate their shopping cart to
// be associated with their username
public void MigrateCart(string userName)
{ {
var shoppingCart = _db.Carts.Where(c => c.CartId == ShoppingCartId); //A GUID to hold the cartId.
cartId = Guid.NewGuid().ToString();
foreach (CartItem item in shoppingCart) // Send cart Id as a cookie to the client.
context.Response.Cookies.Append("Session", cartId);
}
else
{ {
item.CartId = userName; cartId = sessionCookie;
} }
return cartId;
} }
} }
} }

View File

@ -1 +0,0 @@
"%ProgramFiles(x86)%\iis Express\iisexpress.exe" /port:5001 /path:"%cd%"

View File

@ -1,3 +1,6 @@
REM run on k10 by default. Assign it to an empty value to run on desktop CLR.
SET TARGET_FRAMEWORK=k10
REM Selfhost does not need this bin folder REM Selfhost does not need this bin folder
rmdir /S /Q bin rmdir /S /Q bin

View File

@ -1,11 +1,10 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using Microsoft.AspNet;
using Microsoft.AspNet;
using Microsoft.AspNet.Abstractions; using Microsoft.AspNet.Abstractions;
using Microsoft.AspNet.ConfigurationModel; using Microsoft.AspNet.ConfigurationModel;
using Microsoft.AspNet.DependencyInjection; using Microsoft.AspNet.DependencyInjection;
using Microsoft.AspNet.DependencyInjection.Fallback; using Microsoft.AspNet.DependencyInjection.Fallback;
using Microsoft.AspNet.DependencyInjection.NestedProviders; using Microsoft.AspNet.DependencyInjection.NestedProviders;
using Microsoft.AspNet.RequestContainer;
using Microsoft.AspNet.Diagnostics; using Microsoft.AspNet.Diagnostics;
using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.InMemory; using Microsoft.AspNet.Identity.InMemory;
@ -22,11 +21,13 @@ public class Startup
{ {
CreateAdminUser(); CreateAdminUser();
//ErrorPageOptions.ShowAll to be used only at development time. Not recommended for production.
app.UseErrorPage(ErrorPageOptions.ShowAll); app.UseErrorPage(ErrorPageOptions.ShowAll);
app.UseFileServer(); app.UseFileServer();
var serviceProvider = MvcServices.GetDefaultServices().BuildServiceProvider(app.ServiceProvider); var serviceProvider = MvcServices.GetDefaultServices().BuildServiceProvider(app.ServiceProvider);
app.UseContainer(serviceProvider);
var routes = new RouteCollection() var routes = new RouteCollection()
{ {

View File

@ -1,6 +1,4 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. namespace MusicStore.ViewModels
namespace MusicStore.ViewModels
{ {
public class ShoppingCartRemoveViewModel public class ShoppingCartRemoveViewModel
{ {

View File

@ -1,6 +1,4 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System.Collections.Generic;
using System.Collections.Generic;
using MusicStore.Models; using MusicStore.Models;
namespace MusicStore.ViewModels namespace MusicStore.ViewModels

View File

@ -1,6 +1,5 @@
@*Bug: Having a ViewBag.Title throws compilation error: https://github.com/aspnet/WebFx/issues/67*@ @{
@{ Layout = "/Views/Shared/_Layout.cshtml";
//Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Home Page"; ViewBag.Title = "Home Page";
} }

View File

@ -41,7 +41,8 @@
<hr /> <hr />
<footer class="navbar navbar-fixed-bottom navbar-default text-center"> <footer class="navbar navbar-fixed-bottom navbar-default text-center">
<p><a href="http://mvcmusicstore.codeplex.com">mvcmusicstore.codeplex.com</a></p> <p><a href="http://mvcmusicstore.codeplex.com">mvcmusicstore.codeplex.com</a></p>
<small>@Html.ActionLink("admin", "Index", "StoreManager")</small> @*Bug: No Html helpers yet*@
@*<small>@Html.ActionLink("admin", "Index", "StoreManager")</small>*@
</footer> </footer>
</div> </div>

View File

@ -1,4 +1,9 @@
@if (ViewBag.CartCount > 0) @{
//Bug: Need to have a way to specify an application level layout page
Layout = "/Views/Shared/_Layout.cshtml";
}
@if (ViewBag.CartCount > 0)
{ {
<li> <li>
<a href="@Url.Action("Index", "ShoppingCart")" title="@ViewBag.CartSummary"> <a href="@Url.Action("Index", "ShoppingCart")" title="@ViewBag.CartSummary">

View File

@ -1,9 +1,11 @@
@model MvcMusicStore.ViewModels.ShoppingCartViewModel @model MusicStore.ViewModels.ShoppingCartViewModel
@{ @{
//Bug: Need to have a way to specify an application level layout page
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Shopping Cart"; ViewBag.Title = "Shopping Cart";
} }
@section Scripts { @*//@section Scripts {*@
<script type="text/javascript"> <script type="text/javascript">
$(function () { $(function () {
// Document.ready -> link up remove event handler // Document.ready -> link up remove event handler
@ -33,13 +35,13 @@
}); });
</script> </script>
} @*}*@
<h3> <h3>
<em>Review</em> your cart: <em>Review</em> your cart:
</h3> </h3>
<p class="button"> <p class="button">
@Html.ActionLink("Checkout >>", "AddressAndPayment", "Checkout") @*@Html.ActionLink("Checkout >>", "AddressAndPayment", "Checkout")*@
</p> </p>
<div id="update-message"> <div id="update-message">
</div> </div>
@ -58,22 +60,22 @@
</tr> </tr>
@foreach (var item in Model.CartItems) @foreach (var item in Model.CartItems)
{ {
<tr id="row-@item.RecordId"> <tr id="row-@item.CartItemId">
<td> <td>
@Html.ActionLink(item.Album.Title, @*@Html.ActionLink(item.Album.Title,
"Details", "Store", new { id = item.AlbumId }, null) "Details", "Store", new { id = item.AlbumId }, null)*@
</td> </td>
<td> <td>
@item.Album.Price @item.Album.Price
</td> </td>
<td id="item-count-@item.RecordId"> <td id="item-count-@item.CartItemId">
@item.Count @item.Count
</td> </td>
<td> <td>
<a href="#" class="RemoveLink" data-id="@item.RecordId" @*<a href="#" class="RemoveLink" data-id="@item.RecordId"
data-url='@Url.Content("~/ShoppingCart/RemoveFromCart")'> data-url='@Url.Content("~/ShoppingCart/RemoveFromCart")'>
Remove from cart Remove from cart
</a> </a>*@
</td> </td>
</tr> </tr>
} }

View File

@ -1,5 +1,7 @@
@model MusicStore.Models.Genre @model MusicStore.Models.Genre
@{ @{
//Bug: Need to have a way to specify an application level layout page
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Browse Albums"; ViewBag.Title = "Browse Albums";
} }
<div class="genre"> <div class="genre">

View File

@ -1,6 +1,8 @@
@model MusicStore.Models.Album @model MusicStore.Models.Album
@{ @{
//Bug: Need to have a way to specify an application level layout page
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Album - " + Model.Title; ViewBag.Title = "Album - " + Model.Title;
} }

View File

@ -1,5 +1,7 @@
@model IEnumerable<MusicStore.Models.Genre> @model IEnumerable<MusicStore.Models.Genre>
@{ @{
//Bug: Need to have a way to specify an application level layout page
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Store"; ViewBag.Title = "Store";
} }
<h3>Browse Genres</h3> <h3>Browse Genres</h3>

View File

@ -2,6 +2,8 @@
@model MvcMusicStore.Models.Album @model MvcMusicStore.Models.Album
@{ @{
//Bug: Need to have a way to specify an application level layout page
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Create"; ViewBag.Title = "Create";
} }

View File

@ -2,6 +2,8 @@
@model MvcMusicStore.Models.Album @model MvcMusicStore.Models.Album
@{ @{
//Bug: Need to have a way to specify an application level layout page
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Delete"; ViewBag.Title = "Delete";
} }

View File

@ -2,6 +2,8 @@
@model MvcMusicStore.Models.Album @model MvcMusicStore.Models.Album
@{ @{
//Bug: Need to have a way to specify an application level layout page
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Details"; ViewBag.Title = "Details";
} }

View File

@ -2,6 +2,8 @@
@model MvcMusicStore.Models.Album @model MvcMusicStore.Models.Album
@{ @{
//Bug: Need to have a way to specify an application level layout page
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Edit"; ViewBag.Title = "Edit";
} }

View File

@ -14,6 +14,8 @@
} }
@{ @{
//Bug: Need to have a way to specify an application level layout page
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Index"; ViewBag.Title = "Index";
} }

BIN
src/MusicStore/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -15,6 +15,7 @@
"Microsoft.AspNet.Mvc.Rendering": "0.1-alpha-*", "Microsoft.AspNet.Mvc.Rendering": "0.1-alpha-*",
"Microsoft.AspNet.StaticFiles": "0.1-alpha-*", "Microsoft.AspNet.StaticFiles": "0.1-alpha-*",
"System.Security.Claims": "0.1-alpha-*", "System.Security.Claims": "0.1-alpha-*",
"System.Security.Principal": "4.0.0.0",
"Microsoft.AspNet.Security.DataProtection": "0.1-alpha-*", "Microsoft.AspNet.Security.DataProtection": "0.1-alpha-*",
"Microsoft.AspNet.Identity": "0.1-alpha-*", "Microsoft.AspNet.Identity": "0.1-alpha-*",
"Microsoft.AspNet.Identity.Entity": "0.1-alpha-*", "Microsoft.AspNet.Identity.Entity": "0.1-alpha-*",