Updating the music store application with the latest code.

Changes include
(1) Inclusion of all views (with non compiling code commented out)
(2) Inclusion of all models with data annotations
(3) images & setting up of static files
(4) MVC application setup and scripts to run the application
(5) Scripts to clean up the temporary files and capture LKG build.
This commit is contained in:
Praburaj 2014-03-24 15:15:43 -07:00
Родитель 43d4ca4a0d
Коммит 5497541e08
68 изменённых файлов: 28989 добавлений и 4553 удалений

15
Clean.cmd Normal file
Просмотреть файл

@ -0,0 +1,15 @@
REM Set your app's folder path appropriately here
SET APP_PATH=src\MusicStore\
REM cleaning all the generated files and installed nuget packages
rmdir /S /Q .nuget
rmdir /S /Q artifacts
rmdir /S /Q packages
rmdir /S /Q %APP_PATH%\bin
rmdir /S /Q %APP_PATH%\obj
rmdir /S /Q %APP_PATH%\Properties
del %APP_PATH%\*.csproj
del %APP_PATH%\*.v12.suo
del %APP_PATH%\*.csproj.user
del src\PlaceHolder\*.csproj
rmdir /S /Q src\PlaceHolder\bin

23
README.md Normal file
Просмотреть файл

@ -0,0 +1,23 @@
## Music store application
### Run the application:
1. Run build.cmd to restore all the necessary packages and generate project files
2. Open a command prompt and cd \src\MusicStore\
3. Execute CopyAspNetLoader.cmd to copy the AspNet.Loader.dll to the bin directory
4. Execute Run.cmd to launch the app on IISExpress.
### Adding a new package:
1. Edit the project.json to include the package you want to install
2. Do a build.cmd - This will restore the package and regenerate your csproj files to get intellisense for the installed packages.
### Work against the latest build:
1. Run Clean.cmd - This will clear all the packages and any temporary files generated
2. Continue the topic "Steps to run the application"
### Work against LKG Build:
1. Everytime you do a build.cmd you will get the latest packages of all the included packages. If you would like to go back to an LKG build checkout the LKG.json file in the MusicStore folder.
2. This is a captured snapshot of build numbers which worked for this application. This LKG will be captured once in a while.
### Note:
1. By default this script starts the application at http://localhost:5001/. Modify Run.cmd if you would like to change the url
2. Use Visual studio only for editing & intellisense. Don't try to build or run the app from Visual studio.

Просмотреть файл

@ -0,0 +1,70 @@
body {
padding-top: 50px;
padding-bottom: 20px;
}
/* Set padding to keep content from hitting the edges */
.body-content {
padding-left: 15px;
padding-right: 15px;
}
/* Set width on the form input elements since they're 100% wide by default */
input,
select,
textarea {
max-width: 280px;
}
/* styles for validation helpers */
.field-validation-error {
color: #b94a48;
}
.field-validation-valid {
display: none;
}
input.input-validation-error {
border: 1px solid #b94a48;
}
input[type="checkbox"].input-validation-error {
border: 0 none;
}
.validation-summary-errors {
color: #b94a48;
}
.validation-summary-valid {
display: none;
}
/* Music Store additions */
ul#album-list li {
height: 160px;
}
ul#album-list li img:hover {
box-shadow: 1px 1px 7px #777;
}
ul#album-list li img {
box-shadow: 1px 1px 5px #999;
border: none;
padding: 0;
}
ul#album-list li a, ul#album-details li a {
text-decoration:none;
}
ul#album-list li a:hover {
background: none;
-webkit-text-shadow: 1px 1px 2px #bbb;
text-shadow: 1px 1px 2px #bbb;
color: #363430;
}

6816
src/MusicStore/Content/bootstrap.css поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

20
src/MusicStore/Content/bootstrap.min.css поставляемый Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -1,419 +1,505 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Abstractions;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.InMemory;
using Microsoft.AspNet.Mvc;
//using Microsoft.Owin.Security;
using MvcMusicStore.Models;
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace MvcMusicStore.Controllers
{
//[Authorize]
public class AccountController : Controller
{
public AccountController()
: this(new UserManager<ApplicationUser, string>(new InMemoryUserStore<ApplicationUser>()))
{
}
//using Microsoft.AspNet.Identity;
//using Microsoft.AspNet.Identity.InMemory;
//using Microsoft.AspNet.Mvc;
//using Microsoft.AspNet.Mvc.ModelBinding;
//using MusicStore.Models;
//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Threading.Tasks;
public AccountController(UserManager<ApplicationUser, string> userManager)
{
UserManager = userManager;
}
//namespace MusicStore.Controllers
//{
// //[Authorize]
// 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 UserManager<ApplicationUser, string> UserManager { get; private set; }
// public AccountController(UserManager<ApplicationUser, string> userManager)
// {
// UserManager = userManager;
// }
private void MigrateShoppingCart(string userName)
{
//var storeDb = new MusicStoreEntities();
// public UserManager<ApplicationUser, string> UserManager { get; private set; }
// Associate shopping cart items with logged-in user
//var cart = ShoppingCart.GetCart(storeDb, this.HttpContext);
//cart.MigrateCart(userName);
//storeDb.SaveChanges();
// private void MigrateShoppingCart(string UserName)
// {
// //Bug: No EF
// //var storeDb = new MusicStoreEntities();
// var storeDb = MusicStoreEntities.Instance;
//Session[ShoppingCart.CartSessionKey] = userName;
}
// // Associate shopping cart items with logged-in user
// var cart = ShoppingCart.GetCart(storeDb, this.Context);
// cart.MigrateCart(UserName);
// storeDb.SaveChanges();
//
// GET: /Account/Login
//[AllowAnonymous]
public IActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
// //Bug: TODO
// //Session[ShoppingCart.CartSessionKey] = UserName;
// }
//
// POST: /Account/Login
//[HttpPost]
//[AllowAnonymous]
//[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string 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
{
// ModelState.AddModelError("", "Invalid username or password.");
}
//}
// //
// // GET: /Account/Login
// [AllowAnonymous]
// public IActionResult Login(string returnUrl)
// {
// //ViewBag.ReturnUrl = returnUrl;
// return View();
// }
// If we got this far, something failed, redisplay form
return View(model);
}
// //
// // POST: /Account/Login
// //Bug: HTTP verb attribs not available
// //[HttpPost]
// [AllowAnonymous]
// //[ValidateAntiForgeryToken]
// public async Task<IActionResult> Login(LoginViewModel model, string returnUrl)
// {
// //Bug: How to validate the model state?
// //if (ModelState.IsValid)
// {
// var user = await UserManager.Find(model.UserName, model.Password);
// if (user != null)
// {
// await SignIn(user, model.RememberMe);
// return RedirectToLocal(returnUrl);
// }
// else
// {
// //Bug: Model state error
// //ModelState.AddModelError("", "Invalid username or password.");
// }
// }
//
// GET: /Account/Register
//[AllowAnonymous]
public IActionResult Register()
{
return View();
}
// // If we got this far, something failed, redisplay form
// return View(model);
// }
//
// POST: /Account/Register
//[HttpPost]
//[AllowAnonymous]
//[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model)
{
//if (ModelState.IsValid)
//{
var user = new ApplicationUser() { UserName = model.UserName };
var result = await UserManager.Create(user, model.Password);
if (result.Succeeded)
{
await SignIn(user, isPersistent: false);
return null;//RedirectToAction("Index", "Home");
}
else
{
AddErrors(result);
}
//}
// //
// // GET: /Account/Register
// [AllowAnonymous]
// public IActionResult Register()
// {
// return View();
// }
// If we got this far, something failed, redisplay form
return View(model);
}
// //
// // POST: /Account/Register
// //Bug: Missing verb attributes
// //[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);
// }
// }
//
// POST: /Account/Disassociate
//[HttpPost]
//[ValidateAntiForgeryToken]
public async Task<IActionResult> Disassociate(string loginProvider, string providerKey)
{
ManageMessageId? message = null;
IdentityResult result = await UserManager.RemoveLogin(null /*User.Identity.GetUserId()*/, new UserLoginInfo(loginProvider, providerKey));
if (result.Succeeded)
{
message = ManageMessageId.RemoveLoginSuccess;
}
else
{
message = ManageMessageId.Error;
}
return null;//RedirectToAction("Manage", new { Message = message });
}
// // If we got this far, something failed, redisplay form
// return View(model);
// }
//
// 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();
//ViewBag.ReturnUrl = Url.Action("Manage");
return View();
}
// //
// // POST: /Account/Disassociate
// //Bug: HTTP verbs
// //[HttpPost]
// //[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();
// }
//
// POST: /Account/Manage
//[HttpPost]
//[ValidateAntiForgeryToken]
public async Task<IActionResult> Manage(ManageUserViewModel model)
{
bool hasPassword = HasPassword();
ViewBag.HasLocalPassword = hasPassword;
//ViewBag.ReturnUrl = Url.Action("Manage");
if (hasPassword)
{
//if (ModelState.IsValid)
//{
IdentityResult result = await UserManager.ChangePassword("userId" /*User.Identity.GetUserId()*/, model.OldPassword, model.NewPassword);
if (result.Succeeded)
{
return null;//RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess });
}
else
{
AddErrors(result);
}
//}
}
else
{
// User does not have a password so remove any validation errors caused by a missing OldPassword field
//ModelState state = ModelState["OldPassword"];
//if (state != null)
//{
// state.Errors.Clear();
//}
// //
// // 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();
// }
//if (ModelState.IsValid)
//{
IdentityResult result = await UserManager.AddPassword("userId" /*User.Identity.GetUserId()*/, model.NewPassword);
if (result.Succeeded)
{
return null;//RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess });
}
else
{
AddErrors(result);
}
//}
}
// //
// // 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)
// {
// 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 we got this far, something failed, redisplay form
return View(model);
}
// if (state != null)
// {
// state.Errors.Clear();
// }
//
// POST: /Account/ExternalLogin
//[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 }));
return null;
}
// //Bug: No model state validation
// //if (ModelState.IsValid)
// {
// IdentityResult result = await UserManager.AddPassword(User.Identity.GetUserId(), model.NewPassword);
// if (result.Succeeded)
// {
// //Bug: No helper method
// //return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess });
// }
// else
// {
// AddErrors(result);
// }
// }
// }
//
// GET: /Account/ExternalLoginCallback
//[AllowAnonymous]
public async Task<IActionResult> ExternalLoginCallback(string returnUrl)
{
//var loginInfo = await AuthenticationManager.GetExternalLoginInfo();
//if (loginInfo == null)
//{
// return RedirectToAction("Login");
//}
// // If we got this far, something failed, redisplay form
// return View(model);
// }
// Sign in the user with this external login provider if the user already has a login
var user = await UserManager.Find(null/*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 = null;//loginInfo.Login.LoginProvider;
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { /*UserName = loginInfo.DefaultUserName*/ });
}
}
// //
// // 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 }));
// }
//
// POST: /Account/LinkLogin
//[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"), User.Identity.GetUserId());
return null;
}
// //
// // 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();
// }
//
// GET: /Account/LinkLoginCallback
public async Task<IActionResult> LinkLoginCallback()
{
//var loginInfo = await AuthenticationManager.GetExternalLoginInfo(XsrfKey, User.Identity.GetUserId());
//if (loginInfo == null)
//{
// return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
//}
//var result = await UserManager.AddLogin(User.Identity.GetUserId(), loginInfo.Login);
//if (result.Succeeded)
//{
// return RedirectToAction("Manage");
//}
return null;//RedirectToAction("Manage", new { Message = ManageMessageId.Error });
}
// // 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/ExternalLoginConfirmation
//[HttpPost]
//[AllowAnonymous]
//[ValidateAntiForgeryToken]
public async Task<IActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl)
{
//if (User.Identity.IsAuthenticated)
//{
// return RedirectToAction("Manage");
//}
// //
// // 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());
// }
//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");
//}
var user = new ApplicationUser() { UserName = model.UserName };
var result = await UserManager.Create(user);
if (result.Succeeded)
{
result = await UserManager.AddLogin(user.Id, null/*info.Login*/);
if (result.Succeeded)
{
await SignIn(user, isPersistent: false);
return null;//RedirectToLocal(returnUrl);
}
}
AddErrors(result);
//}
// //
// // 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();
// }
ViewBag.ReturnUrl = returnUrl;
return View(model);
}
// //
// // 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();
// }
//
// POST: /Account/LogOff
//[HttpPost]
//[ValidateAntiForgeryToken]
public IActionResult LogOff()
{
//AuthenticationManager.SignOut();
return null;//RedirectToAction("Index", "Home");
}
// //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);
// }
//
// GET: /Account/ExternalLoginFailure
//[AllowAnonymous]
public IActionResult ExternalLoginFailure()
{
return View();
}
// //ViewBag.ReturnUrl = returnUrl;
// return View(model);
// }
//[ChildActionOnly]
public IActionResult RemoveAccountList()
{
//var linkedAccounts = UserManager.GetLogins(null /*User.Identity.GetUserId()*/);
//ViewBag.ShowRemoveButton = HasPassword() || linkedAccounts.Count > 1;
return null;//(IActionResult)PartialView("_RemoveAccountPartial", linkedAccounts);
}
// //
// // POST: /Account/LogOff
// //Bug: No HTTP verbs
// //[HttpPost]
// //[ValidateAntiForgeryToken]
// public IActionResult LogOff()
// {
// AuthenticationManager.SignOut();
// //return RedirectToAction("Index", "Home");
// return View();
// }
#region Helpers
// Used for XSRF protection when adding external logins
private const string XsrfKey = "XsrfId";
// //
// // GET: /Account/ExternalLoginFailure
// [AllowAnonymous]
// public IActionResult ExternalLoginFailure()
// {
// return View();
// }
//private IAuthenticationManager AuthenticationManager
//{
// get
// {
// return HttpContext.GetOwinContext().Authentication;
// }
//}
// //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();
// }
private async Task SignIn(ApplicationUser user, bool isPersistent)
{
//AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentity(user, "Application" /*DefaultAuthenticationTypes.ApplicationCookie */);
//AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
// //Bug: Controllers need to be disposable?
// protected void Dispose(bool disposing)
// {
// if (disposing && UserManager != null)
// {
// UserManager.Dispose();
// UserManager = null;
// }
// //base.Dispose(disposing);
// }
// Migrate the user's shopping cart
MigrateShoppingCart(user.UserName);
}
// #region Helpers
// // Used for XSRF protection when adding external logins
// private const string XsrfKey = "XsrfId";
private void AddErrors(IdentityResult result)
{
foreach (var error in result.Errors)
{
//ModelState.AddModelError("", error);
}
}
// //private IAuthenticationManager AuthenticationManager
// //{
// // get
// // {
// // //Will change to Context.Authentication
// // return new IAuthenticationManager();
// // }
// //}
private bool HasPassword()
{
// No sync helpers yet
//var user = UserManager.FindById(null /*User.Identity.GetUserId()*/);
//if (user != null)
//{
// return user.PasswordHash != null;
//}
return false;
}
// 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);
public enum ManageMessageId
{
ChangePasswordSuccess,
SetPasswordSuccess,
RemoveLoginSuccess,
Error
}
// // Migrate the user's shopping cart
// MigrateShoppingCart(user.UserName);
// }
private IActionResult RedirectToLocal(string returnUrl)
{
//if (Url.IsLocalUrl(returnUrl))
//{
// return Redirect(returnUrl);
//}
//else
//{
// return RedirectToAction("Index", "Home");
//}
return null;
}
// private void AddErrors(IdentityResult result)
// {
// foreach (var error in result.Errors)
// {
// //ModelState.AddModelError("", error);
// }
// }
//private class ChallengeResult : HttpUnauthorizedResult
//{
// public ChallengeResult(string provider, string redirectUri)
// : this(provider, redirectUri, null)
// {
// }
// 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 ChallengeResult(string provider, string redirectUri, string userId)
// {
// LoginProvider = provider;
// RedirectUri = redirectUri;
// UserId = userId;
// }
// public enum ManageMessageId
// {
// ChangePasswordSuccess,
// SetPasswordSuccess,
// RemoveLoginSuccess,
// Error
// }
// public string LoginProvider { get; set; }
// public string RedirectUri { get; set; }
// public string UserId { get; set; }
// private IActionResult RedirectToLocal(string returnUrl)
// {
// //Bug: No helpers available
// //if (Url.IsLocalUrl(returnUrl))
// //{
// // return Redirect(returnUrl);
// //}
// //else
// //{
// // return RedirectToAction("Index", "Home");
// //}
// return View();
// }
// public override void ExecuteResult(ControllerContext context)
// {
// var properties = new AuthenticationProperties() { RedirectUri = RedirectUri };
// if (UserId != null)
// {
// properties.Dictionary[XsrfKey] = UserId;
// }
// context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
// }
//}
#endregion
}
}
// 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; }
// }
// }
//}

Просмотреть файл

@ -1,65 +1,103 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;
using Microsoft.Data.Entity;
using MvcMusicStore.Models;
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace MvcMusicStore.Controllers
using Microsoft.AspNet.Mvc;
using MusicStore.Models;
using System;
using System.Linq;
namespace MusicStore.Controllers
{
//Bug: Missing auth filter
//[Authorize]
public class CheckoutController : Controller
{
private const string PromoCode = "FREE";
private readonly MusicStoreEntities _storeContext = new MusicStoreEntities();
//Bug: Missing EF
//MusicStoreEntities storeDB = new MusicStoreEntities();
MusicStoreEntities storeDB = MusicStoreEntities.Instance;
const string PromoCode = "FREE";
//
// GET: /Checkout/
public IActionResult AddressAndPayment()
{
return View();
}
//
// POST: /Checkout/AddressAndPayment
//Bug: Http verbs not available. Also binding to FormCollection is not available.
//[HttpPost]
public async Task<IActionResult> AddressAndPayment(IDictionary<string, string> values /*FormCollection values*/)
//public IActionResult AddressAndPayment(FormCollection values)
public IActionResult AddressAndPayment(int workaroundId)
{
var coll = this.Context.Request.GetFormAsync().Result;
var order = new Order();
//TryUpdateModel(order);
if (//ModelState.IsValid &&
string.Equals(values["PromoCode"], PromoCode, StringComparison.OrdinalIgnoreCase))
try
{
order.Username = "";//User.Identity.Name;
order.OrderDate = DateTime.Now;
//if (string.Equals(values["PromoCode"], PromoCode,
// StringComparison.OrdinalIgnoreCase) == false)
if (string.Equals(coll.GetValues("PromoCode").FirstOrDefault(), PromoCode,
StringComparison.OrdinalIgnoreCase) == false)
{
return View(order);
}
else
{
//Bug: Identity not available
order.Username = null; //User.Identity.Name;
order.OrderDate = DateTime.Now;
_storeContext.Orders.Add(order);
//Add the Order
storeDB.Orders.Add(order);
await ShoppingCart.GetCart(_storeContext, this).CreateOrder(order);
//Process the order
var cart = ShoppingCart.GetCart(storeDB, this.Context);
cart.CreateOrder(order);
await _storeContext.SaveChangesAsync();
// Save all changes
storeDB.SaveChanges();
//Bug: Helper not available
//return RedirectToAction("Complete",
// new { id = order.OrderId });
return View();
}
return null;//RedirectToAction("Complete", new { id = order.OrderId });
}
return View(order);
catch
{
//Invalid - redisplay with errors
return View(order);
}
}
//
// GET: /Checkout/Complete
public async Task<IActionResult> Complete(int id)
{
return await _storeContext.Orders.AnyAsync(o => o.OrderId == id && o.Username == "")//User.Identity.Name)
? View(id)
: View("Error");
}
//protected override void Dispose(bool disposing)
//{
// if (disposing)
// {
// _storeContext.Dispose();
// }
// base.Dispose(disposing);
//}
public IActionResult Complete(int id)
{
// 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 = storeDB.Orders.Any(
o => o.OrderId == id);
if (isValid)
{
return View(id);
}
else
{
return View("Error");
}
}
}
}

Просмотреть файл

@ -1,31 +1,36 @@
using System.Linq;
using System.Threading.Tasks;
// 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.Data.Entity;
using MvcMusicStore.Models;
using MusicStore.Models;
using System.Collections.Generic;
using System.Linq;
namespace MvcMusicStore.Controllers
{
public class HomeController : Controller
{
private readonly MusicStoreEntities _storeContext = new MusicStoreEntities();
/// Bug: Hacking to return a singleton. Should go away once we have EF.
//private MusicStoreEntities storeDB = new MusicStoreEntities();
private MusicStoreEntities storeDB = MusicStoreEntities.Instance;
//
// GET: /Home/
public async Task<IActionResult> Index()
public IActionResult Index()
{
return View(await _storeContext.Albums
.OrderByDescending(a => a.OrderDetails.Count())
.Take(6)
.ToListAsync());
// Get most popular albums
var albums = GetTopSellingAlbums(6);
return View(albums);
}
//protected override void Dispose(bool disposing)
//{
// if (disposing)
// {
// _storeContext.Dispose();
// }
// base.Dispose(disposing);
//}
private List<Album> GetTopSellingAlbums(int count)
{
// Group the order details by album and return
// the albums with the highest count
return storeDB.Albums
.OrderByDescending(a => a.OrderDetails.Count())
.Take(count)
.ToList();
}
}
}

Просмотреть файл

@ -1,94 +1,95 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;
using Microsoft.Data.Entity;
using MvcMusicStore.Models;
using MvcMusicStore.ViewModels;
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace MvcMusicStore.Controllers
using Microsoft.AspNet.Mvc;
using MusicStore.Models;
using MusicStore.ViewModels;
using System.Linq;
namespace MusicStore.Controllers
{
public class ShoppingCartController : Controller
{
private readonly MusicStoreEntities _storeContext = new MusicStoreEntities();
//Bug: No EF yet
//private MusicStoreEntities storeDB = new MusicStoreEntities();
private MusicStoreEntities storeDB = MusicStoreEntities.Instance;
//
// GET: /ShoppingCart/
public async Task<IActionResult> Index()
{
var cart = ShoppingCart.GetCart(_storeContext, this);
public IActionResult Index()
{
var cart = ShoppingCart.GetCart(storeDB, this.Context);
// Set up our ViewModel
var viewModel = new ShoppingCartViewModel
{
CartItems = await cart.GetCartItems().ToListAsync(),
CartTotal = await cart.GetTotal()
CartItems = cart.GetCartItems(),
CartTotal = cart.GetTotal()
};
// Return the view
return View(viewModel);
}
//
// GET: /ShoppingCart/AddToCart/5
public async Task<IActionResult> AddToCart(int id)
public IActionResult AddToCart(int id)
{
var cart = ShoppingCart.GetCart(_storeContext, this);
await cart.AddToCart(await _storeContext.Albums.SingleAsync(a => a.AlbumId == id));
// Retrieve the album from the database
var addedAlbum = storeDB.Albums
.Single(album => album.AlbumId == id);
await _storeContext.SaveChangesAsync();
// Add it to the shopping cart
var cart = ShoppingCart.GetCart(storeDB, this.Context);
return null;//RedirectToAction("Index");
cart.AddToCart(addedAlbum);
storeDB.SaveChanges();
// Go back to the main store page for more shopping
//Bug: Helper method not available
//return RedirectToAction("Index");
return View();
}
//
// AJAX: /ShoppingCart/RemoveFromCart/5
//Bug: Missing HTTP verb attribute
//[HttpPost]
public async Task<IActionResult> RemoveFromCart(int id)
public IActionResult RemoveFromCart(int id)
{
var cart = ShoppingCart.GetCart(_storeContext, this);
// Retrieve the current user's shopping cart
var cart = ShoppingCart.GetCart(storeDB, this.Context);
var albumName = await _storeContext.Carts
.Where(i => i.RecordId == id)
.Select(i => i.Album.Title)
.SingleOrDefaultAsync();
// Get the name of the album to display confirmation
string albumName = storeDB.Carts
.Single(item => item.RecordId == id).Album.Title;
var itemCount = await cart.RemoveFromCart(id);
// Remove from cart
int itemCount = cart.RemoveFromCart(id);
await _storeContext.SaveChangesAsync();
storeDB.SaveChanges();
var removed = (itemCount > 0) ? " 1 copy of " : string.Empty;
string removed = (itemCount > 0) ? " 1 copy of " : string.Empty;
// Display the confirmation message
var results = new ShoppingCartRemoveViewModel
{
Message = removed + albumName + " has been removed from your shopping cart.",
CartTotal = await cart.GetTotal(),
CartCount = await cart.GetCount(),
Message = removed + albumName +
" has been removed from your shopping cart.",
CartTotal = cart.GetTotal(),
CartCount = cart.GetCount(),
ItemCount = itemCount,
DeleteId = id
};
return Result.Json(results);
//Bug: Missing helper
//return Json(results);
return new JsonResult(results);
}
//[ChildActionOnly]
public IActionResult CartSummary()
{
var cart = ShoppingCart.GetCart(_storeContext, this);
var cartItems = cart.GetCartItems()
.Select(a => a.Album.Title)
.OrderBy(x => x)
.ToList();
ViewBag.CartCount = cartItems.Count();
ViewBag.CartSummary = string.Join("\n", cartItems.Distinct());
return null;//PartialView("CartSummary");
}
//protected override void Dispose(bool disposing)
//{
// if (disposing)
// {
// _storeContext.Dispose();
// }
// base.Dispose(disposing);
//}
}
}
}

Просмотреть файл

@ -1,55 +1,66 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;
using Microsoft.Data.Entity;
using MvcMusicStore.Models;
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace MvcMusicStore.Controllers
using Microsoft.AspNet.Mvc;
using MusicStore.Models;
using System.Linq;
namespace MusicStore.Controllers
{
public class StoreController : Controller
{
private readonly MusicStoreEntities _storeContext = new MusicStoreEntities();
//Bug: Need to remove singleton instance after EF is implemented.
//MusicStoreEntities storeDB = new MusicStoreEntities();
MusicStoreEntities storeDB = MusicStoreEntities.Instance;
//
// GET: /Store/
public async Task<IActionResult> Index()
public IActionResult Index()
{
return View(await _storeContext.Genres.ToListAsync());
var genres = storeDB.Genres.ToList();
return View(genres);
}
//
// GET: /Store/Browse?genre=Disco
public async Task<IActionResult> Browse(string genre)
public IActionResult Browse(string genre)
{
return View(await _storeContext.Genres.Include(e => e.Albums).SingleAsync(g => g.Name == genre));
// Retrieve Genre genre and its Associated associated Albums albums from database
//Bug: Include is part of EF. We need to work around this temporarily
//var genreModel = storeDB.Genres.Include("Albums")
// .Single(g => g.Name == genre);
var genreModel = storeDB.Genres.Single(g => g.Name == genre);
genreModel.Albums = storeDB.Albums.Where(a => a.GenreId == genreModel.GenreId).ToList();
return View(genreModel);
}
public async Task<IActionResult> Details(int id)
public IActionResult Details(int id)
{
var album = await _storeContext.Albums.SingleOrDefaultAsync(a => a.AlbumId == id);
//Bug: Need Find method from EF.
//var album = storeDB.Albums.Find(id);
var album = storeDB.Albums.Single(a => a.AlbumId == id);
return album != null ? View(album) : (IActionResult)null;//HttpNotFound();
return View(album);
}
///Bug: Missing [ChildActionOnly] attribute
//[ChildActionOnly]
public IActionResult GenreMenu()
{
var genres = _storeContext.Genres
var genres = storeDB.Genres
.OrderByDescending(
g => g.Albums.Sum(
a => a.OrderDetails.Sum(
od => od.Quantity)))
a => a.OrderDetails.Sum(
od => od.Quantity)))
.Take(9)
.ToList();
return null; //PartialView(genres);
//Bug: Missing PartialView method.
//return PartialView(genres);
return View();
}
//protected override void Dispose(bool disposing)
//{
// if (disposing)
// {
// _storeContext.Dispose();
// }
// base.Dispose(disposing);
//}
}
}

Просмотреть файл

@ -1,141 +1,189 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;
using Microsoft.Data.Entity;
using MvcMusicStore.Models;
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace MvcMusicStore.Controllers
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.ModelBinding;
using MusicStore.Models;
using System.Linq;
namespace MusicStore.Controllers
{
//[Authorize(Roles = "Administrator")]
///Bug: No Authorize attribute
//[Authorize(Roles="Administrator")]
public class StoreManagerController : Controller
{
private readonly MusicStoreEntities _storeContext = new MusicStoreEntities();
//Bug: No EF yet
//private MusicStoreEntities db = new MusicStoreEntities();
private MusicStoreEntities db = MusicStoreEntities.Instance;
//
// GET: /StoreManager/
public async Task<IActionResult> Index()
public IActionResult Index()
{
return View(await _storeContext.Albums
.Include(a => a.Genre)
.Include(a => a.Artist)
.OrderBy(a => a.Price).ToListAsync());
//Bug: Include needs EF.
//var albums = db.Albums.Include(a => a.Genre).Include(a => a.Artist)
// .OrderBy(a => a.Price);
var albums = db.Albums;
foreach (var album in albums)
{
album.Genre = db.Genres.Single(g => g.GenreId == album.GenreId);
album.Artist = db.Artists.Single(a => a.ArtistId == album.ArtistId);
}
return View(albums.ToList());
}
//
// GET: /StoreManager/Details/5
public async Task<IActionResult> Details(int id = 0)
{
var album = await _storeContext.Albums.SingleOrDefaultAsync(e => e.AlbumId == id);
public IActionResult Details(int id = 0)
{
//Bug: Find needs EF
//Album album = db.Albums.Find(id);
Album album = db.Albums.Single(a => a.AlbumId == id);
if (album == null)
{
return null;//HttpNotFound();
//Bug: Need method HttpNotFound() on Controller
//return HttpNotFound();
return this.HttpNotFound();
}
return View(album);
}
//Bug: SelectList still not available
//
// GET: /StoreManager/Create
public async Task<IActionResult> Create()
{
return await BuildView(null);
}
//public IActionResult Create()
//{
// ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name");
// ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name");
// return View();
//}
//Bug: ModelState.IsValid not available
//Bug: RedirectToAction() not available
//Bug: SelectList not available
// POST: /StoreManager/Create
//[HttpPost]
public async Task<IActionResult> Create(Album album)
{
if (true)//ModelState.IsValid)
{
_storeContext.Albums.Add(album);
//public IActionResult Create(Album album)
//{
// if (ModelState.IsValid)
// {
// db.Albums.Add(album);
// db.SaveChanges();
// return RedirectToAction("Index");
// }
await _storeContext.SaveChangesAsync();
return null;//RedirectToAction("Index");
}
return await BuildView(album);
}
// ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name", album.GenreId);
// ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId);
// return View(album);
//}
//
// GET: /StoreManager/Edit/5
public async Task<IActionResult> Edit(int id = 0)
public IActionResult Edit(int id = 0)
{
var album = await _storeContext.Albums.SingleOrDefaultAsync(e => e.AlbumId == id);
//Bug: Need EF to implement Find
//Album album = db.Albums.Find(id);
Album album = db.Albums.Single(a => a.AlbumId == id);
if (album == null)
{
return null;//HttpNotFound();
//Bug: Need method HttpNotFound() on Controller
//return HttpNotFound();
return this.HttpNotFound();
}
return await BuildView(album);
//ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name", album.GenreId);
//ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId);
return View(album);
}
//
// POST: /StoreManager/Edit/5
//Bug: Http actions not available
//[HttpPost]
public async Task<IActionResult> Edit(Album album)
public IActionResult Edit(Album album)
{
if (true)//ModelState.IsValid)
//Bug: ModelState.IsValid missing
//if (ModelState.IsValid)
{
_storeContext.Albums.Update(album);
await _storeContext.SaveChangesAsync();
return null;//RedirectToAction("Index");
//Bug: Missing EF
//db.Entry(album).State = EntityState.Modified;
db.SaveChanges();
//Bug: Missing RedirectToAction helper
//return RedirectToAction("Index");
}
return await BuildView(album);
//ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name", album.GenreId);
//ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId);
return View(album);
}
//
// GET: /StoreManager/Delete/5
public async Task<IActionResult> Delete(int id = 0)
public IActionResult Delete(int id = 0)
{
var album = await _storeContext.Albums.SingleOrDefaultAsync(e => e.AlbumId == id);
//Bug: EF missing
//Album album = db.Albums.Find(id);
Album album = db.Albums.Single(a => a.AlbumId == id);
if (album == null)
{
return null;//HttpNotFound();
//Bug: Missing Helper
return this.HttpNotFound();
}
return View(album);
}
//
// POST: /StoreManager/Delete/5
//Bug: Missing HTTP verb & action name. ActionName out of scope for alpha - So fixing the name of method in code
//[HttpPost, ActionName("Delete")]
public async Task<IActionResult> DeleteConfirmed(int id)
//TODO: How to have an action with same name 'Delete'??
public IActionResult DeleteConfirmed(int id)
{
var album = await _storeContext.Albums.SingleOrDefaultAsync(e => e.AlbumId == id);
if (album == null)
{
return null;//HttpNotFound();
}
//Bug: EF missing
//Album album = db.Albums.Find(id);
Album album = db.Albums.Single(a => a.AlbumId == id);
db.Albums.Remove(album);
db.SaveChanges();
//Bug: Missing helper
//return RedirectToAction("Index");
_storeContext.Albums.Remove(album);
await _storeContext.SaveChangesAsync();
return null;//RedirectToAction("Index");
}
private async Task<IActionResult> 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);
return View();
}
//Bug: Can't dispose db.
//protected override void Dispose(bool disposing)
//{
// if (disposing)
// {
// _storeContext.Dispose();
// }
// db.Dispose();
// base.Dispose(disposing);
//}
}
/// <summary>
/// Bug: HttpNotFoundResult not available in Controllers. Work around.
/// </summary>
public class HttpNotFoundResult : HttpStatusCodeResult
{
public HttpNotFoundResult()
: base(404)
{
}
}
/// <summary>
/// Bug: HttpNotFoundResult not available in Controllers. Work around.
/// </summary>
public static class Extensions
{
public static IActionResult HttpNotFound(this Controller controller)
{
return new HttpNotFoundResult();
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
REM copy the AspNet.Loader.dll to bin folder
md bin
REM figure out the path of AspNet.Loader.dll
FOR /F %%j IN ('dir /b /o:-d ..\..\packages\Microsoft.AspNet.Loader.IIS.Interop*') do (SET AspNetLoaderPath=..\..\packages\%%j\tools\AspNet.Loader.dll)
echo Found AspNetLoader.dll at %AspNetLoaderPath%. Copying to bin\
copy %AspNetLoaderPath% bin\

Двоичные данные
src/MusicStore/Images/home-showcase.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 248 KiB

Двоичные данные
src/MusicStore/Images/logo.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.9 KiB

Просмотреть файл

@ -0,0 +1,303 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="77.981812"
height="38"
id="svg2"
version="1.1"
inkscape:version="0.48.2 r9819"
sodipodi:docname="logo.svg"
inkscape:export-filename="C:\Users\Jon\SkyDrive\Projects\Git\MvcMusicStore\MvcMusicStore\Content\Images\logo.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.313708"
inkscape:cx="68.62794"
inkscape:cy="21.563703"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1920"
inkscape:window-height="1137"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid4175"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-381.25,-434.47363)">
<g
id="g3138"
transform="matrix(0.99433276,0,0,0.99433276,2.6879598,-28.875086)">
<g
transform="matrix(0.95191143,0,0,0.94999997,-13.610187,70.866904)"
id="g4123">
<g
id="g4004"
transform="translate(6.4397225,-81.443549)">
<path
transform="matrix(1.037037,0,0,1.0566038,33.991419,-29.473365)"
d="m 439.46429,517.54077 c 0,7.84047 -6.47589,14.19643 -14.46429,14.19643 -7.9884,0 -14.46429,-6.35596 -14.46429,-14.19643 0,-7.84047 6.47589,-14.19643 14.46429,-14.19643 7.9884,0 14.46429,6.35596 14.46429,14.19643 z"
sodipodi:ry="14.196428"
sodipodi:rx="14.464286"
sodipodi:cy="517.54077"
sodipodi:cx="425"
id="path3007-1"
style="fill:#000000;fill-opacity:1;stroke:none"
sodipodi:type="arc" />
<path
transform="matrix(0.16151528,0,0,0.16456275,406.08815,432.19425)"
d="m 439.46429,517.54077 c 0,7.84047 -6.47589,14.19643 -14.46429,14.19643 -7.9884,0 -14.46429,-6.35596 -14.46429,-14.19643 0,-7.84047 6.47589,-14.19643 14.46429,-14.19643 7.9884,0 14.46429,6.35596 14.46429,14.19643 z"
sodipodi:ry="14.196428"
sodipodi:rx="14.464286"
sodipodi:cy="517.54077"
sodipodi:cx="425"
id="path3007-0-4"
style="fill:#ffffff;fill-opacity:1;stroke:none"
sodipodi:type="arc" />
</g>
<path
sodipodi:type="arc"
style="fill:none;stroke:#ffffff;stroke-width:1.31862605;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path3889-1"
sodipodi:cx="473.83929"
sodipodi:cy="447.98718"
sodipodi:rx="10.982142"
sodipodi:ry="10.982142"
d="m 484.82144,447.98718 c 0,6.06527 -4.91688,10.98215 -10.98215,10.98215 -6.06527,0 -10.98214,-4.91688 -10.98214,-10.98215 0,-6.06527 4.91687,-10.98214 10.98214,-10.98214 6.06527,0 10.98215,4.91687 10.98215,10.98214 z"
transform="matrix(0.5308556,0,0,0.5308556,229.63162,198.10213)" />
<path
sodipodi:type="arc"
style="fill:none;stroke:#ffffff;stroke-width:0.61952281;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path3889-4-1"
sodipodi:cx="473.83929"
sodipodi:cy="447.98718"
sodipodi:rx="10.982142"
sodipodi:ry="10.982142"
d="m 484.82144,447.98718 c 0,6.06527 -4.91688,10.98215 -10.98215,10.98215 -6.06527,0 -10.98214,-4.91688 -10.98214,-10.98215 0,-6.06527 4.91687,-10.98214 10.98214,-10.98214 6.06527,0 10.98215,4.91687 10.98215,10.98214 z"
transform="matrix(1.1299019,0,0,1.1299019,-54.220053,-70.262937)" />
<path
sodipodi:type="arc"
style="fill:none;stroke:#ffffff;stroke-width:0.8002516;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path3889-5-5"
sodipodi:cx="473.83929"
sodipodi:cy="447.98718"
sodipodi:rx="10.982142"
sodipodi:ry="10.982142"
d="m 484.82144,447.98718 c 0,6.06527 -4.91688,10.98215 -10.98215,10.98215 -6.06527,0 -10.98214,-4.91688 -10.98214,-10.98215 0,-6.06527 4.91687,-10.98214 10.98214,-10.98214 6.06527,0 10.98215,4.91687 10.98215,10.98214 z"
transform="matrix(0.83035093,0,0,0.83035093,87.718968,63.932058)" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.87783366px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 481.53079,442.83849 -0.0153,6.77692 c 9.55428,-0.16929 14.45853,-10.06218 12.50577,-19.31642 l -8.12484,3.61854 c 0.006,4.27743 -1.21305,6.01267 -4.23942,6.33245 z"
id="path3916-5-2-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc"
inkscape:transform-center-x="6.427012"
inkscape:transform-center-y="17.713434" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.87783366px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 480.46352,428.30022 0.0153,-6.77692 c -9.55428,0.16929 -14.45853,10.06218 -12.50577,19.31642 l 8.12484,-3.61854 c -0.006,-4.27743 1.21305,-6.01267 4.23942,-6.33245 z"
id="path3916-5-2-7-6"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc"
inkscape:transform-center-x="-6.4270161"
inkscape:transform-center-y="-17.713434" />
</g>
<g
transform="matrix(0.95191143,0,0,0.94999997,-63.034658,70.866904)"
id="g4123-1">
<g
id="g4004-4"
transform="translate(6.4397225,-81.443549)">
<path
transform="matrix(1.037037,0,0,1.0566038,33.991419,-29.473365)"
d="m 439.46429,517.54077 c 0,7.84047 -6.47589,14.19643 -14.46429,14.19643 -7.9884,0 -14.46429,-6.35596 -14.46429,-14.19643 0,-7.84047 6.47589,-14.19643 14.46429,-14.19643 7.9884,0 14.46429,6.35596 14.46429,14.19643 z"
sodipodi:ry="14.196428"
sodipodi:rx="14.464286"
sodipodi:cy="517.54077"
sodipodi:cx="425"
id="path3007-1-2"
style="fill:#000000;fill-opacity:1;stroke:none"
sodipodi:type="arc" />
<path
transform="matrix(0.16151528,0,0,0.16456275,406.08815,432.19425)"
d="m 439.46429,517.54077 c 0,7.84047 -6.47589,14.19643 -14.46429,14.19643 -7.9884,0 -14.46429,-6.35596 -14.46429,-14.19643 0,-7.84047 6.47589,-14.19643 14.46429,-14.19643 7.9884,0 14.46429,6.35596 14.46429,14.19643 z"
sodipodi:ry="14.196428"
sodipodi:rx="14.464286"
sodipodi:cy="517.54077"
sodipodi:cx="425"
id="path3007-0-4-3"
style="fill:#ffffff;fill-opacity:1;stroke:none"
sodipodi:type="arc" />
</g>
<path
sodipodi:type="arc"
style="fill:none;stroke:#ffffff;stroke-width:1.31862605;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path3889-1-2"
sodipodi:cx="473.83929"
sodipodi:cy="447.98718"
sodipodi:rx="10.982142"
sodipodi:ry="10.982142"
d="m 484.82144,447.98718 c 0,6.06527 -4.91688,10.98215 -10.98215,10.98215 -6.06527,0 -10.98214,-4.91688 -10.98214,-10.98215 0,-6.06527 4.91687,-10.98214 10.98214,-10.98214 6.06527,0 10.98215,4.91687 10.98215,10.98214 z"
transform="matrix(0.5308556,0,0,0.5308556,229.63162,198.10213)" />
<path
sodipodi:type="arc"
style="fill:none;stroke:#ffffff;stroke-width:0.61952281;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path3889-4-1-2"
sodipodi:cx="473.83929"
sodipodi:cy="447.98718"
sodipodi:rx="10.982142"
sodipodi:ry="10.982142"
d="m 484.82144,447.98718 c 0,6.06527 -4.91688,10.98215 -10.98215,10.98215 -6.06527,0 -10.98214,-4.91688 -10.98214,-10.98215 0,-6.06527 4.91687,-10.98214 10.98214,-10.98214 6.06527,0 10.98215,4.91687 10.98215,10.98214 z"
transform="matrix(1.1299019,0,0,1.1299019,-54.220053,-70.262937)" />
<path
sodipodi:type="arc"
style="fill:none;stroke:#ffffff;stroke-width:0.8002516;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path3889-5-5-1"
sodipodi:cx="473.83929"
sodipodi:cy="447.98718"
sodipodi:rx="10.982142"
sodipodi:ry="10.982142"
d="m 484.82144,447.98718 c 0,6.06527 -4.91688,10.98215 -10.98215,10.98215 -6.06527,0 -10.98214,-4.91688 -10.98214,-10.98215 0,-6.06527 4.91687,-10.98214 10.98214,-10.98214 6.06527,0 10.98215,4.91687 10.98215,10.98214 z"
transform="matrix(0.83035093,0,0,0.83035093,87.718968,63.932058)" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.87783366px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 481.53079,442.83849 -0.0153,6.77692 c 9.55428,-0.16929 14.45853,-10.06218 12.50577,-19.31642 l -8.12484,3.61854 c 0.006,4.27743 -1.21305,6.01267 -4.23942,6.33245 z"
id="path3916-5-2-7-68"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc"
inkscape:transform-center-x="6.427012"
inkscape:transform-center-y="17.713434" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.87783366px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 480.46352,428.30022 0.0153,-6.77692 c -9.55428,0.16929 -14.45853,10.06218 -12.50577,19.31642 l 8.12484,-3.61854 c -0.006,-4.27743 1.21305,-6.01267 4.23942,-6.33245 z"
id="path3916-5-2-7-6-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc"
inkscape:transform-center-x="-6.4270161"
inkscape:transform-center-y="-17.713434" />
</g>
<g
transform="matrix(0.95191143,0,0,0.94999997,5.2301333,72.549709)"
id="g4113">
<path
sodipodi:type="arc"
style="fill:#000000;fill-opacity:1;stroke:none"
id="path3007-7-8"
sodipodi:cx="425"
sodipodi:cy="517.54077"
sodipodi:rx="14.464286"
sodipodi:ry="14.196428"
d="m 439.46429,517.54077 c 0,7.84047 -6.47589,14.19643 -14.46429,14.19643 -7.9884,0 -14.46429,-6.35596 -14.46429,-14.19643 0,-7.84047 6.47589,-14.19643 14.46429,-14.19643 7.9884,0 14.46429,6.35596 14.46429,14.19643 z"
transform="matrix(1.382716,0,0,1.4088051,-152.12422,-294.96682)" />
<path
sodipodi:type="arc"
style="fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:1.23868203;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path3007-4-8"
sodipodi:cx="425"
sodipodi:cy="517.54077"
sodipodi:rx="14.464286"
sodipodi:ry="14.196428"
d="m 439.46429,517.54077 c 0,7.84047 -6.47589,14.19643 -14.46429,14.19643 -7.9884,0 -14.46429,-6.35596 -14.46429,-14.19643 0,-7.84047 6.47589,-14.19643 14.46429,-14.19643 7.9884,0 14.46429,6.35596 14.46429,14.19643 z"
transform="matrix(0.57659584,0,0,0.58747505,190.47685,130.10497)" />
<path
sodipodi:type="arc"
style="fill:#ffffff;fill-opacity:1;stroke:none"
id="path3007-0-2"
sodipodi:cx="425"
sodipodi:cy="517.54077"
sodipodi:rx="14.464286"
sodipodi:ry="14.196428"
d="m 439.46429,517.54077 c 0,7.84047 -6.47589,14.19643 -14.46429,14.19643 -7.9884,0 -14.46429,-6.35596 -14.46429,-14.19643 0,-7.84047 6.47589,-14.19643 14.46429,-14.19643 7.9884,0 14.46429,6.35596 14.46429,14.19643 z"
transform="matrix(0.27721059,0,0,0.282441,317.71558,287.97253)" />
<path
sodipodi:type="arc"
style="fill:none;stroke:#ffffff;stroke-width:0.66094333;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path3889"
sodipodi:cx="473.83929"
sodipodi:cy="447.98718"
sodipodi:rx="10.982142"
sodipodi:ry="10.982142"
d="m 484.82144,447.98718 c 0,6.06527 -4.91688,10.98215 -10.98215,10.98215 -6.06527,0 -10.98214,-4.91688 -10.98214,-10.98215 0,-6.06527 4.91687,-10.98214 10.98214,-10.98214 6.06527,0 10.98215,4.91687 10.98215,10.98214 z"
transform="matrix(1.0590923,0,0,1.0590923,-66.309468,-40.31252)" />
<path
sodipodi:type="arc"
style="fill:none;stroke:#ffffff;stroke-width:0.44283628;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path3889-4"
sodipodi:cx="473.83929"
sodipodi:cy="447.98718"
sodipodi:rx="10.982142"
sodipodi:ry="10.982142"
d="m 484.82144,447.98718 c 0,6.06527 -4.91688,10.98215 -10.98215,10.98215 -6.06527,0 -10.98214,-4.91688 -10.98214,-10.98215 0,-6.06527 4.91687,-10.98214 10.98214,-10.98214 6.06527,0 10.98215,4.91687 10.98215,10.98214 z"
transform="matrix(1.5807196,0,0,1.5807196,-313.47698,-273.99486)" />
<path
sodipodi:type="arc"
style="fill:none;stroke:#ffffff;stroke-width:0.53326446;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path3889-5"
sodipodi:cx="473.83929"
sodipodi:cy="447.98718"
sodipodi:rx="10.982142"
sodipodi:ry="10.982142"
d="m 484.82144,447.98718 c 0,6.06527 -4.91688,10.98215 -10.98215,10.98215 -6.06527,0 -10.98214,-4.91688 -10.98214,-10.98215 0,-6.06527 4.91687,-10.98214 10.98214,-10.98214 6.06527,0 10.98215,4.91687 10.98215,10.98214 z"
transform="matrix(1.3126696,0,0,1.3126696,-186.46436,-153.9119)" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.14413512px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 436.31917,443.49132 -0.10217,8.33905 c 12.45268,-0.22064 18.92699,-12.29179 16.38184,-24.35342 l -7.29812,4.63399 c 1.81826,5.98647 -4.04967,10.71674 -8.98155,11.38038 z"
id="path3916-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc"
inkscape:transform-center-x="8.3767009"
inkscape:transform-center-y="23.087015" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.14413512px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 434.01553,424.88159 0.48098,-8.21278 c -12.45268,0.22064 -18.92699,12.29179 -16.38184,24.35342 l 8.05573,-3.62383 c -1.81826,-5.98647 2.91325,-11.85317 7.84513,-12.51681 z"
id="path3916-5-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc"
inkscape:transform-center-x="-8.3766982"
inkscape:transform-center-y="-23.087015" />
</g>
</g>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 16 KiB

Двоичные данные
src/MusicStore/Images/placeholder.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

Просмотреть файл

@ -0,0 +1,112 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100"
height="100"
id="svg2"
version="1.1"
inkscape:version="0.48.2 r9819"
sodipodi:docname="New document 1">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6"
inkscape:cx="56.013691"
inkscape:cy="69.593676"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1920"
inkscape:window-height="1003"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-277.5,-381.16879)">
<g
id="g3797"
inkscape:export-filename="C:\Users\Jon\SkyDrive\Projects\Git\MvcMusicStore\MvcMusicStore\Content\Images\placeholder.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<rect
y="381.16879"
x="277.5"
height="100"
width="100"
id="rect3017"
style="fill:#ffffff;fill-opacity:1" />
<g
transform="translate(2.0535545,-3.2469826)"
id="g3787">
<rect
style="fill:#edecb3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.15819502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect2998"
width="78.591805"
height="78.591805"
x="286.15054"
y="395.11987" />
<g
style="font-size:10.29434204px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#90905a;fill-opacity:1;stroke:none;font-family:Segoe UI;-inkscape-font-specification:Segoe UI"
id="text3000">
<path
inkscape:connector-curvature="0"
d="m 290.05246,405.88284 0,-0.99526 c 0.11393,0.10054 0.25048,0.19101 0.40966,0.27144 0.15917,0.0804 0.32672,0.14828 0.50265,0.20357 0.17593,0.0553 0.35269,0.098 0.5303,0.12818 0.1776,0.0302 0.3418,0.0452 0.4926,0.0452 0.51941,0 0.90729,-0.0963 1.16364,-0.28903 0.25635,-0.19268 0.38453,-0.46998 0.38453,-0.83189 0,-0.19436 -0.0427,-0.36358 -0.12817,-0.50768 -0.0855,-0.14409 -0.20358,-0.27562 -0.35437,-0.39458 -0.1508,-0.11896 -0.32925,-0.2329 -0.53533,-0.34181 -0.20609,-0.1089 -0.4281,-0.22367 -0.66602,-0.34431 -0.25132,-0.12734 -0.4859,-0.25635 -0.70371,-0.38705 -0.21782,-0.13068 -0.40715,-0.27478 -0.568,-0.43228 -0.16085,-0.15749 -0.28735,-0.33593 -0.3795,-0.53533 -0.0922,-0.19938 -0.13823,-0.43311 -0.13823,-0.7012 0,-0.32839 0.072,-0.61407 0.21614,-0.85702 0.14409,-0.24294 0.33342,-0.44317 0.568,-0.60067 0.23457,-0.15749 0.50181,-0.27478 0.80173,-0.35186 0.29991,-0.0771 0.60569,-0.1156 0.91734,-0.11561 0.71042,1e-5 1.22815,0.0855 1.5532,0.25635 l 0,0.95002 c -0.42558,-0.29488 -0.9718,-0.44233 -1.63865,-0.44234 -0.18431,10e-6 -0.36861,0.0193 -0.55292,0.0578 -0.18431,0.0385 -0.34851,0.10137 -0.4926,0.18849 -0.14409,0.0871 -0.26138,0.1994 -0.35186,0.33678 -0.0905,0.1374 -0.13571,0.30495 -0.13571,0.50266 0,0.18431 0.0343,0.34348 0.10304,0.47752 0.0687,0.13404 0.17006,0.25635 0.30411,0.36693 0.13404,0.11059 0.2974,0.21782 0.49008,0.3217 0.19269,0.10389 0.41469,0.21782 0.66602,0.34181 0.25803,0.12734 0.50265,0.26138 0.73387,0.40212 0.23122,0.14074 0.43396,0.29657 0.60821,0.46747 0.17425,0.1709 0.31248,0.36023 0.41469,0.56799 0.10221,0.20777 0.15331,0.44569 0.15331,0.71377 0,0.35521 -0.0695,0.65597 -0.2086,0.90226 -0.13907,0.24631 -0.32673,0.44653 -0.56297,0.60068 -0.23625,0.15414 -0.50852,0.26556 -0.81681,0.33426 -0.3083,0.0687 -0.63335,0.10304 -0.97515,0.10304 -0.11394,0 -0.25468,-0.009 -0.42223,-0.0276 -0.16755,-0.0184 -0.33845,-0.0452 -0.5127,-0.0804 -0.17426,-0.0352 -0.3393,-0.0788 -0.49512,-0.13069 -0.15582,-0.0519 -0.28065,-0.10974 -0.37447,-0.17341 z"
id="path3005" />
<path
inkscape:connector-curvature="0"
d="m 299.43197,406.17438 -0.82435,0 0,-0.80425 -0.0201,0 c -0.35856,0.61659 -0.88635,0.92488 -1.58336,0.92488 -0.51271,0 -0.91399,-0.13571 -1.20385,-0.40715 -0.28987,-0.27143 -0.4348,-0.63166 -0.4348,-1.0807 0,-0.96174 0.56632,-1.52136 1.69897,-1.67886 l 1.54315,-0.21614 c -10e-6,-0.87462 -0.35354,-1.31192 -1.0606,-1.31193 -0.61994,10e-6 -1.17956,0.21112 -1.67886,0.63334 l 0,-0.84445 c 0.506,-0.3217 1.08908,-0.48255 1.74923,-0.48255 1.20971,0 1.81457,0.64005 1.81458,1.92014 z m -0.82435,-2.60375 -1.24156,0.1709 c -0.38202,0.0536 -0.6702,0.14829 -0.86456,0.284 -0.19436,0.13572 -0.29154,0.37616 -0.29154,0.72131 0,0.25133 0.0896,0.45658 0.26892,0.61575 0.17928,0.15918 0.41804,0.23876 0.71628,0.23876 0.40882,0 0.74644,-0.14325 1.01285,-0.42977 0.2664,-0.28651 0.3996,-0.64926 0.39961,-1.08824 z"
id="path3007" />
<path
inkscape:connector-curvature="0"
d="m 308.3038,406.17438 -0.82435,0 0,-2.9556 c -10e-6,-0.56968 -0.088,-0.98185 -0.26389,-1.23653 -0.17594,-0.25468 -0.47167,-0.38201 -0.88719,-0.38202 -0.35186,10e-6 -0.65094,0.16085 -0.89723,0.48255 -0.24631,0.3217 -0.36946,0.70707 -0.36945,1.1561 l 0,2.9355 -0.82436,0 0,-3.05614 c 0,-1.012 -0.39039,-1.518 -1.17118,-1.51801 -0.36191,10e-6 -0.66015,0.15164 -0.89472,0.4549 -0.23457,0.30327 -0.35186,0.69786 -0.35186,1.18375 l 0,2.9355 -0.82435,0 0,-5.14717 0.82435,0 0,0.81429 0.0201,0 c 0.36526,-0.62328 0.89807,-0.93493 1.59844,-0.93493 0.35185,0 0.65847,0.098 0.91985,0.29405 0.26138,0.19604 0.44066,0.45323 0.53784,0.77157 0.38201,-0.71041 0.95169,-1.06562 1.70902,-1.06562 1.13264,0 1.69896,0.69869 1.69897,2.09606 z"
id="path3009" />
<path
inkscape:connector-curvature="0"
d="m 310.70648,405.43045 -0.0201,0 0,3.11143 -0.82435,0 0,-7.51467 0.82435,0 0,0.90477 0.0201,0 c 0.40548,-0.6836 0.99861,-1.02541 1.7794,-1.02541 0.6635,0 1.18123,0.23039 1.5532,0.69115 0.37195,0.46077 0.55794,1.07819 0.55794,1.85228 0,0.86121 -0.20944,1.55068 -0.62831,2.06841 -0.41889,0.51774 -0.99191,0.7766 -1.71908,0.7766 -0.66686,0 -1.18124,-0.28818 -1.54315,-0.86456 z m -0.0201,-2.07596 0,0.7188 c 0,0.42558 0.13823,0.78665 0.41469,1.08321 0.27645,0.29657 0.62747,0.44485 1.05306,0.44485 0.4993,0 0.89053,-0.191 1.17369,-0.57302 0.28316,-0.38202 0.42474,-0.91315 0.42474,-1.59341 0,-0.57303 -0.13237,-1.02206 -0.39709,-1.34711 -0.26474,-0.32505 -0.6233,-0.48757 -1.07568,-0.48758 -0.4792,10e-6 -0.86457,0.16672 -1.1561,0.50014 -0.29154,0.33343 -0.43731,0.75147 -0.43731,1.25412 z"
id="path3011" />
<path
inkscape:connector-curvature="0"
d="m 316.73833,406.17438 -0.82436,0 0,-7.62023 0.82436,0 z"
id="path3013" />
<path
inkscape:connector-curvature="0"
d="m 322.54397,403.80688 -3.63418,0 c 0.0134,0.57303 0.16755,1.01536 0.46244,1.327 0.29489,0.31165 0.70036,0.46747 1.21642,0.46747 0.57972,0 1.11254,-0.191 1.59844,-0.57302 l 0,0.77408 c -0.45239,0.3284 -1.05055,0.4926 -1.79448,0.4926 -0.72717,0 -1.29852,-0.23373 -1.71404,-0.7012 -0.41553,-0.46746 -0.62329,-1.1251 -0.62329,-1.97291 0,-0.80089 0.22703,-1.4535 0.68109,-1.95784 0.45406,-0.50432 1.01787,-0.75649 1.69143,-0.75649 0.67355,0 1.19464,0.21782 1.56325,0.65345 0.36861,0.43564 0.55292,1.0405 0.55292,1.81458 z m -0.84446,-0.69869 c -0.003,-0.47584 -0.11812,-0.84613 -0.34431,-1.11086 -0.2262,-0.26473 -0.54036,-0.39709 -0.94248,-0.3971 -0.38872,10e-6 -0.7188,0.13907 -0.99023,0.4172 -0.27143,0.27814 -0.43898,0.64173 -0.50265,1.09076 z"
id="path3015" />
</g>
</g>
</g>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 8.4 KiB

45
src/MusicStore/LKG.json Normal file
Просмотреть файл

@ -0,0 +1,45 @@
{
"version": "0.1-alpha-*",
"dependencies": {
"Helios": "0.1-alpha-098",
"Microsoft.AspNet.Abstractions": "0.1-alpha-152",
"Microsoft.AspNet.Mvc": "0.1-alpha-296",
"Microsoft.AspNet.Razor": "0.1-alpha-136",
"Microsoft.AspNet.ConfigurationModel": "0.1-alpha-108",
"Microsoft.AspNet.DependencyInjection": "0.1-alpha-159",
"Microsoft.AspNet.RequestContainer": "0.1-alpha-124",
"Microsoft.AspNet.Routing": "0.1-alpha-100",
"Microsoft.AspNet.Mvc.ModelBinding": "0.1-alpha-296",
"Microsoft.AspNet.Mvc.Core": "0.1-alpha-296",
"Microsoft.AspNet.Mvc.Razor": "0.1-alpha-296",
"Microsoft.AspNet.Mvc.Rendering": "0.1-alpha-296",
"Microsoft.AspNet.StaticFiles": "0.1-alpha-081",
"System.Security.Claims": "0.1-alpha-045",
"Microsoft.AspNet.Security.DataProtection": "0.1-alpha-092",
"Microsoft.AspNet.Identity": "0.1-alpha-155",
"Microsoft.AspNet.Identity.Entity": "0.1-alpha-155",
"Microsoft.AspNet.Identity.InMemory": "0.1-alpha-155"
},
"configurations": {
"net45": {
"dependencies": {
"System.Runtime": "",
"System.ComponentModel.DataAnnotations": ""
}
},
"k10": {
"dependencies": {
"System.Collections": "4.0.0.0",
"System.Linq": "4.0.0.0",
"System.Runtime": "4.0.20.0",
"System.Dynamic.Runtime": "4.0.0.0",
"System.Threading.Tasks": "4.0.0.0",
"System.ComponentModel": "4.0.0.0",
"System.Console": "4.0.0.0",
"System.Diagnostics.Debug": "4.0.10.0",
"System.Diagnostics.Tools": "4.0.0.0",
"Microsoft.ComponentModel.DataAnnotations": "0.1-alpha-032"
}
}
}
}

Просмотреть файл

@ -1,63 +1,65 @@
// using System.ComponentModel.DataAnnotations;
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace MvcMusicStore.Models
using System.ComponentModel.DataAnnotations;
namespace MusicStore.Models
{
public class ExternalLoginConfirmationViewModel
{
//[Required]
//[Display(Name = "User name")]
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
}
public class ManageUserViewModel
{
//[Required]
//[DataType(DataType.Password)]
//[Display(Name = "Current password")]
[Required]
[DataType(DataType.Password)]
[Display(Name = "Current password")]
public string OldPassword { get; set; }
//[Required]
//[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
//[DataType(DataType.Password)]
//[Display(Name = "New password")]
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "New password")]
public string NewPassword { get; set; }
//[DataType(DataType.Password)]
//[Display(Name = "Confirm new password")]
//[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
[DataType(DataType.Password)]
[Display(Name = "Confirm new password")]
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
public class LoginViewModel
{
//[Required]
//[Display(Name = "User name")]
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
//[Required]
//[DataType(DataType.Password)]
//[Display(Name = "Password")]
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
//[Display(Name = "Remember me?")]
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
public class RegisterViewModel
{
//[Required]
//[Display(Name = "User name")]
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
//[Required]
//[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
//[DataType(DataType.Password)]
//[Display(Name = "Password")]
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
//[DataType(DataType.Password)]
//[Display(Name = "Confirm password")]
//[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
}
}

Просмотреть файл

@ -1,31 +1,43 @@
using System.Collections.Generic;
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace MvcMusicStore.Models
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace MusicStore.Models
{
public class Album
{
//[ScaffoldColumn(false)]
[ScaffoldColumn(false)]
public int AlbumId { get; set; }
public int GenreId { get; set; }
public int ArtistId { get; set; }
//[Required]
//[StringLength(160, MinimumLength = 2)]
[Required]
[StringLength(160, MinimumLength = 2)]
public string Title { get; set; }
//[Required]
//[Range(0.01, 100.00)]
//[DataType(DataType.Currency)]
[Required]
[Range(0.01, 100.00)]
[DataType(DataType.Currency)]
public decimal Price { get; set; }
//[DisplayName("Album Art URL")]
//[StringLength(1024)]
[Display(Name = "Album Art URL")]
[StringLength(1024)]
public string AlbumArtUrl { get; set; }
public virtual Genre Genre { get; set; }
public virtual Artist Artist { get; set; }
public virtual List<OrderDetail> OrderDetails { get; set; }
/// <summary>
/// Bug: We use this to populate the order details. This should be removed once we have an actual DB with EF.
/// </summary>
public Album()
{
this.OrderDetails = new List<OrderDetail>();
}
}
}

Просмотреть файл

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

Просмотреть файл

@ -1,16 +1,19 @@
using System;
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace MvcMusicStore.Models
using System;
using System.ComponentModel.DataAnnotations;
namespace MusicStore.Models
{
public class Cart
{
//[Key]
[Key]
public int RecordId { get; set; }
public string CartId { get; set; }
public int AlbumId { get; set; }
public int Count { get; set; }
//[DataType(DataType.DateTime)]
[DataType(DataType.DateTime)]
public DateTime DateCreated { get; set; }
public virtual Album Album { get; set; }

Просмотреть файл

@ -1,6 +1,8 @@
using System.Collections.Generic;
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace MvcMusicStore.Models
using System.Collections.Generic;
namespace MusicStore.Models
{
public class Genre
{
@ -9,4 +11,4 @@ namespace MvcMusicStore.Models
public string Description { get; set; }
public List<Album> Albums { get; set; }
}
}
}

Просмотреть файл

@ -1,8 +1,9 @@
using Microsoft.AspNet.Identity.InMemory;
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace MvcMusicStore.Models
using Microsoft.AspNet.Identity.InMemory;
namespace MusicStore.Models
{
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : InMemoryUser
{
}

Просмотреть файл

@ -1,18 +1,58 @@
using Microsoft.Data.Entity;
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace MvcMusicStore.Models
using System.Collections.Generic;
namespace MusicStore.Models
{
public class MusicStoreEntities : EntityContext
/// <summary>
/// Bug: Mocked entities set. We should substitute this with DbSet once EF is available.
/// </summary>
public class MusicStoreEntities
{
public MusicStoreEntities()
: base(null) // TODO: Fix after discussion of which patterns to use here
public List<Album> Albums { get; set; }
public List<Genre> Genres { get; set; }
public List<Artist> Artists { get; set; }
public List<Cart> Carts { get; set; }
public List<Order> Orders { get; set; }
public List<OrderDetail> OrderDetails { get; set; }
/// <summary>
/// Bug: Need to remove this method. Just adding this to unblock from compilation errors
/// </summary>
public void SaveChanges()
{
}
public EntitySet<Album> Albums { get; set; }
public EntitySet<Genre> Genres { get; set; }
public EntitySet<Artist> Artists { get; set; }
public EntitySet<Cart> Carts { get; set; }
public EntitySet<Order> Orders { get; set; }
private static MusicStoreEntities instance;
public static MusicStoreEntities Instance
{
get
{
//TODO: Sync issues not handled.
if (instance == null)
{
instance = new MusicStoreEntities();
SampleData.Seed(instance);
}
return instance;
}
}
/// <summary>
/// Bug: This is to just initialize the lists. Once we have EF this should be removed.
/// </summary>
/// <param name="dummy"></param>
private MusicStoreEntities()
{
this.Albums = new List<Album>();
this.Genres = new List<Genre>();
this.Artists = new List<Artist>();
this.Carts = new List<Cart>();
this.Orders = new List<Order>();
this.OrderDetails = new List<OrderDetail>();
}
}
}

Просмотреть файл

@ -1,68 +1,66 @@
using System.Collections.Generic;
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
namespace MvcMusicStore.Models
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace MusicStore.Models
{
//[Bind(Include = "FirstName,LastName,Address,City,State,PostalCode,Country,Phone,Email")]
public class Order
{
public Order()
{
OrderDetails = new List<OrderDetail>();
}
//[ScaffoldColumn(false)]
[ScaffoldColumn(false)]
public int OrderId { get; set; }
//[ScaffoldColumn(false)]
[ScaffoldColumn(false)]
public System.DateTime OrderDate { get; set; }
//[ScaffoldColumn(false)]
[ScaffoldColumn(false)]
public string Username { get; set; }
//[Required]
//[DisplayName("First Name")]
//[StringLength(160)]
[Required]
[Display(Name = "First Name")]
[StringLength(160)]
public string FirstName { get; set; }
//[Required]
//[DisplayName("Last Name")]
//[StringLength(160)]
[Required]
[Display(Name = "Last Name")]
[StringLength(160)]
public string LastName { get; set; }
//[Required]
//[StringLength(70, MinimumLength = 3)]
[Required]
[StringLength(70, MinimumLength = 3)]
public string Address { get; set; }
//[Required]
//[StringLength(40)]
[Required]
[StringLength(40)]
public string City { get; set; }
//[Required]
//[StringLength(40)]
[Required]
[StringLength(40)]
public string State { get; set; }
//[Required]
//[DisplayName("Postal Code")]
//[StringLength(10, MinimumLength = 5)]
[Required]
[Display(Name = "Postal Code")]
[StringLength(10, MinimumLength = 5)]
public string PostalCode { get; set; }
//[Required]
//[StringLength(40)]
[Required]
[StringLength(40)]
public string Country { get; set; }
//[Required]
//[StringLength(24)]
//[DataType(DataType.PhoneNumber)]
[Required]
[StringLength(24)]
[DataType(DataType.PhoneNumber)]
public string Phone { get; set; }
//[Required]
//[DisplayName("Email Address")]
//[RegularExpression(@"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}",
// ErrorMessage = "Email is is not valid.")]
//[DataType(DataType.EmailAddress)]
[Required]
[Display(Name = "Email Address")]
[RegularExpression(@"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}",
ErrorMessage = "Email is is not valid.")]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
//[ScaffoldColumn(false)]
[ScaffoldColumn(false)]
public decimal Total { get; set; }
public List<OrderDetail> OrderDetails { get; set; }

Просмотреть файл

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

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,159 +1,202 @@
using System;
using System.Linq;
using System.Threading.Tasks;
// 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.Mvc;
using Microsoft.Data.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
namespace MvcMusicStore.Models
namespace MusicStore.Models
{
public class ShoppingCart
public partial class ShoppingCart
{
MusicStoreEntities _db;
string ShoppingCartId { get; set; }
public ShoppingCart(MusicStoreEntities db)
{
_db = db;
}
public const string CartSessionKey = "CartId";
private readonly MusicStoreEntities _storeContext;
private readonly string _cartId;
private ShoppingCart(MusicStoreEntities storeContext, string cartId)
public static ShoppingCart GetCart(MusicStoreEntities db, HttpContext context)
{
_storeContext = storeContext;
_cartId = cartId;
var cart = new ShoppingCart(db);
cart.ShoppingCartId = cart.GetCartId(context);
return cart;
}
public static ShoppingCart GetCart(MusicStoreEntities storeContext, Controller controller)
//TODO: Not used by anyone. Not sure why we have this.
// Helper method to simplify shopping cart calls
//public static ShoppingCart GetCart(MusicStoreEntities db, Controller controller)
//{
// return GetCart(db, controller.HttpContext);
//}
public void AddToCart(Album album)
{
return new ShoppingCart(storeContext, GetCartId(controller.Context));
}
private static string GetCartId(HttpContext context)
{
throw new NotImplementedException();
//if (context.Session[CartSessionKey] == null)
//{
// var username = context.User.Identity.Name;
// context.Session[CartSessionKey] = !string.IsNullOrWhiteSpace(username)
// ? username
// : Guid.NewGuid().ToString();
//}
//return context.Session[CartSessionKey].ToString();
}
public async Task AddToCart(Album album)
{
var cartItem = await GetCartItem(album.AlbumId);
// 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 = _cartId,
CartId = ShoppingCartId,
Count = 1,
DateCreated = DateTime.Now
};
_storeContext.Carts.Add(cartItem);
_db.Carts.Add(cartItem);
}
else
{
// If the item does exist in the cart, then add one to the quantity
cartItem.Count++;
}
}
public async Task<int> RemoveFromCart(int id)
public int RemoveFromCart(int id)
{
var cartItem = await GetCartItem(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)
{
return --cartItem.Count;
cartItem.Count--;
itemCount = cartItem.Count;
}
else
{
_db.Carts.Remove(cartItem);
}
_storeContext.Carts.Remove(cartItem);
}
return 0;
return itemCount;
}
private Task<Cart> GetCartItem(int albumId)
public void EmptyCart()
{
return _storeContext.Carts.SingleOrDefaultAsync(
c => c.CartId == _cartId && c.AlbumId == albumId);
var cartItems = _db.Carts.Where(cart => cart.CartId == ShoppingCartId);
foreach (var cartItem in cartItems)
{
_db.Carts.Remove(cartItem);
}
}
public IQueryable<Cart> GetCartItems()
public List<Cart> GetCartItems()
{
return _storeContext.Carts.Where(c => c.CartId == _cartId);
return _db.Carts.Where(cart => cart.CartId == ShoppingCartId).ToList();
}
public Task<int> GetCount()
public int GetCount()
{
return _storeContext.Carts
.Where(c => c.CartId == _cartId)
.Select(c => c.Count)
.SumAsync();
// 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 Task<decimal> GetTotal()
public decimal GetTotal()
{
return _storeContext.Carts
.Where(c => c.CartId == _cartId)
.Select(c => c.Count * c.Album.Price)
.SumAsync();
// 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 async Task<int> CreateOrder(Order order)
public int CreateOrder(Order order)
{
decimal orderTotal = 0;
var cartItems = await _storeContext.Carts
.Where(c => c.CartId == _cartId)
.Include(c => c.Album)
.ToListAsync();
var cartItems = GetCartItems();
// Iterate over the items in the cart, adding the order details for each
foreach (var item in cartItems)
{
order.OrderDetails.Add(new OrderDetail
//Bug: Missing EF
//var album = _db.Albums.Find(item.AlbumId);
var album = _db.Albums.Single(a => a.AlbumId == item.AlbumId);
var orderDetail = new OrderDetail
{
AlbumId = item.AlbumId,
OrderId = order.OrderId,
UnitPrice = item.Album.Price,
UnitPrice = album.Price,
Quantity = item.Count,
});
};
orderTotal += item.Count * item.Album.Price;
// 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;
await EmptyCart();
// Empty the shopping cart
EmptyCart();
// Return the OrderId as the confirmation number
return order.OrderId;
}
private async Task EmptyCart()
// We're using HttpContextBase to allow access to cookies.
public string GetCartId(HttpContext context)
{
foreach (var cartItem in await _storeContext.Carts.Where(
c => c.CartId == _cartId).ToListAsync())
{
_storeContext.Carts.Remove(cartItem);
}
//Bug: Session not in scope. But we should substitute this with cookies when available.
//if (context.Session[CartSessionKey] == 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
// context.Session[CartSessionKey] = tempCartId.ToString();
// }
//}
//return context.Session[CartSessionKey].ToString();
return string.Empty;
}
public async Task MigrateCart(string userName)
// When a user has logged in, migrate their shopping cart to
// be associated with their username
public void MigrateCart(string userName)
{
var carts = await _storeContext.Carts.Where(c => c.CartId == _cartId).ToListAsync();
var shoppingCart = _db.Carts.Where(c => c.CartId == ShoppingCartId);
foreach (var item in carts)
foreach (Cart item in shoppingCart)
{
item.CartId = userName;
}
await _storeContext.SaveChangesAsync();
}
}
}

1
src/MusicStore/Run.cmd Normal file
Просмотреть файл

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

Двоичные данные
src/MusicStore/Scripts/_references.js Normal file

Двоичный файл не отображается.

2014
src/MusicStore/Scripts/bootstrap.js поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

21
src/MusicStore/Scripts/bootstrap.min.js поставляемый Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

2671
src/MusicStore/Scripts/jquery-1.10.2.intellisense.js поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

9803
src/MusicStore/Scripts/jquery-1.10.2.js поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

23
src/MusicStore/Scripts/jquery-1.10.2.min.js поставляемый Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

1302
src/MusicStore/Scripts/jquery.validate-vsdoc.js поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

1245
src/MusicStore/Scripts/jquery.validate.js поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

16
src/MusicStore/Scripts/jquery.validate.min.js поставляемый Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

344
src/MusicStore/Scripts/jquery.validate.unobtrusive.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,344 @@
/* NUGET: BEGIN LICENSE TEXT
*
* Microsoft grants you the right to use these script files for the sole
* purpose of either: (i) interacting through your browser with the Microsoft
* website or online service, subject to the applicable licensing or use
* terms; or (ii) using the files as included with a Microsoft product subject
* to that product's license terms. Microsoft reserves all other rights to the
* files not expressly granted by Microsoft, whether by implication, estoppel
* or otherwise. Insofar as a script file is dual licensed under GPL,
* Microsoft neither took the code under GPL nor distributes it thereunder but
* under the terms set out in this paragraph. All notices and licenses
* below are for informational purposes only.
*
* NUGET: END LICENSE TEXT */
/*!
** Unobtrusive validation support library for jQuery and jQuery Validate
** Copyright (C) Microsoft Corporation. All rights reserved.
*/
/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
/*global document: false, jQuery: false */
(function ($) {
var $jQval = $.validator,
adapters,
data_validation = "unobtrusiveValidation";
function setValidationValues(options, ruleName, value) {
options.rules[ruleName] = value;
if (options.message) {
options.messages[ruleName] = options.message;
}
}
function splitAndTrim(value) {
return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
}
function escapeAttributeValue(value) {
// As mentioned on http://api.jquery.com/category/selectors/
return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
}
function getModelPrefix(fieldName) {
return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
}
function appendModelPrefix(value, prefix) {
if (value.indexOf("*.") === 0) {
value = value.replace("*.", prefix);
}
return value;
}
function onError(error, inputElement) { // 'this' is the form element
var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
replaceAttrValue = container.attr("data-valmsg-replace"),
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
container.removeClass("field-validation-valid").addClass("field-validation-error");
error.data("unobtrusiveContainer", container);
if (replace) {
container.empty();
error.removeClass("input-validation-error").appendTo(container);
}
else {
error.hide();
}
}
function onErrors(event, validator) { // 'this' is the form element
var container = $(this).find("[data-valmsg-summary=true]"),
list = container.find("ul");
if (list && list.length && validator.errorList.length) {
list.empty();
container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
$.each(validator.errorList, function () {
$("<li />").html(this.message).appendTo(list);
});
}
}
function onSuccess(error) { // 'this' is the form element
var container = error.data("unobtrusiveContainer"),
replaceAttrValue = container.attr("data-valmsg-replace"),
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;
if (container) {
container.addClass("field-validation-valid").removeClass("field-validation-error");
error.removeData("unobtrusiveContainer");
if (replace) {
container.empty();
}
}
}
function onReset(event) { // 'this' is the form element
var $form = $(this);
$form.data("validator").resetForm();
$form.find(".validation-summary-errors")
.addClass("validation-summary-valid")
.removeClass("validation-summary-errors");
$form.find(".field-validation-error")
.addClass("field-validation-valid")
.removeClass("field-validation-error")
.removeData("unobtrusiveContainer")
.find(">*") // If we were using valmsg-replace, get the underlying error
.removeData("unobtrusiveContainer");
}
function validationInfo(form) {
var $form = $(form),
result = $form.data(data_validation),
onResetProxy = $.proxy(onReset, form);
if (!result) {
result = {
options: { // options structure passed to jQuery Validate's validate() method
errorClass: "input-validation-error",
errorElement: "span",
errorPlacement: $.proxy(onError, form),
invalidHandler: $.proxy(onErrors, form),
messages: {},
rules: {},
success: $.proxy(onSuccess, form)
},
attachValidation: function () {
$form
.unbind("reset." + data_validation, onResetProxy)
.bind("reset." + data_validation, onResetProxy)
.validate(this.options);
},
validate: function () { // a validation function that is called by unobtrusive Ajax
$form.validate();
return $form.valid();
}
};
$form.data(data_validation, result);
}
return result;
}
$jQval.unobtrusive = {
adapters: [],
parseElement: function (element, skipAttach) {
/// <summary>
/// Parses a single HTML element for unobtrusive validation attributes.
/// </summary>
/// <param name="element" domElement="true">The HTML element to be parsed.</param>
/// <param name="skipAttach" type="Boolean">[Optional] true to skip attaching the
/// validation to the form. If parsing just this single element, you should specify true.
/// If parsing several elements, you should specify false, and manually attach the validation
/// to the form when you are finished. The default is false.</param>
var $element = $(element),
form = $element.parents("form")[0],
valInfo, rules, messages;
if (!form) { // Cannot do client-side validation without a form
return;
}
valInfo = validationInfo(form);
valInfo.options.rules[element.name] = rules = {};
valInfo.options.messages[element.name] = messages = {};
$.each(this.adapters, function () {
var prefix = "data-val-" + this.name,
message = $element.attr(prefix),
paramValues = {};
if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy)
prefix += "-";
$.each(this.params, function () {
paramValues[this] = $element.attr(prefix + this);
});
this.adapt({
element: element,
form: form,
message: message,
params: paramValues,
rules: rules,
messages: messages
});
}
});
$.extend(rules, { "__dummy__": true });
if (!skipAttach) {
valInfo.attachValidation();
}
},
parse: function (selector) {
/// <summary>
/// Parses all the HTML elements in the specified selector. It looks for input elements decorated
/// with the [data-val=true] attribute value and enables validation according to the data-val-*
/// attribute values.
/// </summary>
/// <param name="selector" type="String">Any valid jQuery selector.</param>
var $forms = $(selector)
.parents("form")
.andSelf()
.add($(selector).find("form"))
.filter("form");
// :input is a psuedoselector provided by jQuery which selects input and input-like elements
// combining :input with other selectors significantly decreases performance.
$(selector).find(":input").filter("[data-val=true]").each(function () {
$jQval.unobtrusive.parseElement(this, true);
});
$forms.each(function () {
var info = validationInfo(this);
if (info) {
info.attachValidation();
}
});
}
};
adapters = $jQval.unobtrusive.adapters;
adapters.add = function (adapterName, params, fn) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="params" type="Array" optional="true">[Optional] An array of parameter names (strings) that will
/// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
/// mmmm is the parameter name).</param>
/// <param name="fn" type="Function">The function to call, which adapts the values from the HTML
/// attributes into jQuery Validate rules and/or messages.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
if (!fn) { // Called with no params, just a function
fn = params;
params = [];
}
this.push({ name: adapterName, params: params, adapt: fn });
return this;
};
adapters.addBool = function (adapterName, ruleName) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation rule has no parameter values.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
/// of adapterName will be used instead.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, function (options) {
setValidationValues(options, ruleName || adapterName, true);
});
};
adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
/// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="minRuleName" type="String">The name of the jQuery Validate rule to be used when you only
/// have a minimum value.</param>
/// <param name="maxRuleName" type="String">The name of the jQuery Validate rule to be used when you only
/// have a maximum value.</param>
/// <param name="minMaxRuleName" type="String">The name of the jQuery Validate rule to be used when you
/// have both a minimum and maximum value.</param>
/// <param name="minAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
/// contains the minimum value. The default is "min".</param>
/// <param name="maxAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
/// contains the maximum value. The default is "max".</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
var min = options.params.min,
max = options.params.max;
if (min && max) {
setValidationValues(options, minMaxRuleName, [min, max]);
}
else if (min) {
setValidationValues(options, minRuleName, min);
}
else if (max) {
setValidationValues(options, maxRuleName, max);
}
});
};
adapters.addSingleVal = function (adapterName, attribute, ruleName) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation rule has a single value.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>
/// <param name="attribute" type="String">[Optional] The name of the HTML attribute that contains the value.
/// The default is "val".</param>
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
/// of adapterName will be used instead.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, [attribute || "val"], function (options) {
setValidationValues(options, ruleName || adapterName, options.params[attribute]);
});
};
$jQval.addMethod("__dummy__", function (value, element, params) {
return true;
});
$jQval.addMethod("regex", function (value, element, params) {
var match;
if (this.optional(element)) {
return true;
}
match = new RegExp(params).exec(value);
return (match && (match.index === 0) && (match[0].length === value.length));
});
$jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
var match;
if (nonalphamin) {
match = value.match(/\W/g);
match = match && match.length >= nonalphamin;
}
return match;
});
if ($jQval.methods.extension) {
adapters.addSingleVal("accept", "mimtype");
adapters.addSingleVal("extension", "extension");
} else {
// for backward compatibility, when the 'extension' validation method does not exist, such as with versions
// of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for
// validating the extension, and ignore mime-type validations as they are not supported.
adapters.addSingleVal("extension", "extension", "accept");
}
adapters.addSingleVal("regex", "pattern");
adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
adapters.add("equalto", ["other"], function (options) {
var prefix = getModelPrefix(options.element.name),
other = options.params.other,
fullOtherName = appendModelPrefix(other, prefix),
element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0];
setValidationValues(options, "equalTo", element);
});
adapters.add("required", function (options) {
// jQuery Validate equates "required" with "mandatory" for checkbox elements
if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
setValidationValues(options, "required", true);
}
});
adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
var value = {
url: options.params.url,
type: options.params.type || "GET",
data: {}
},
prefix = getModelPrefix(options.element.name);
$.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
var paramName = appendModelPrefix(fieldName, prefix);
value.data[paramName] = function () {
return $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']").val();
};
});
setValidationValues(options, "remote", value);
});
adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
if (options.params.min) {
setValidationValues(options, "minlength", options.params.min);
}
if (options.params.nonalphamin) {
setValidationValues(options, "nonalphamin", options.params.nonalphamin);
}
if (options.params.regex) {
setValidationValues(options, "regex", options.params.regex);
}
});
$(function () {
$jQval.unobtrusive.parse(document);
});
}(jQuery));

19
src/MusicStore/Scripts/jquery.validate.unobtrusive.min.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,19 @@
/* NUGET: BEGIN LICENSE TEXT
*
* Microsoft grants you the right to use these script files for the sole
* purpose of either: (i) interacting through your browser with the Microsoft
* website or online service, subject to the applicable licensing or use
* terms; or (ii) using the files as included with a Microsoft product subject
* to that product's license terms. Microsoft reserves all other rights to the
* files not expressly granted by Microsoft, whether by implication, estoppel
* or otherwise. Insofar as a script file is dual licensed under GPL,
* Microsoft neither took the code under GPL nor distributes it thereunder but
* under the terms set out in this paragraph. All notices and licenses
* below are for informational purposes only.
*
* NUGET: END LICENSE TEXT */
/*
** Unobtrusive validation support library for jQuery and jQuery Validate
** Copyright (C) Microsoft Corporation. All rights reserved.
*/
(function(a){var d=a.validator,b,e="unobtrusiveValidation";function c(a,b,c){a.rules[b]=c;if(a.message)a.messages[b]=a.message}function j(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function f(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function h(a){return a.substr(0,a.lastIndexOf(".")+1)}function g(a,b){if(a.indexOf("*.")===0)a=a.replace("*.",b);return a}function m(c,e){var b=a(this).find("[data-valmsg-for='"+f(e[0].name)+"']"),d=b.attr("data-valmsg-replace"),g=d?a.parseJSON(d)!==false:null;b.removeClass("field-validation-valid").addClass("field-validation-error");c.data("unobtrusiveContainer",b);if(g){b.empty();c.removeClass("input-validation-error").appendTo(b)}else c.hide()}function l(e,d){var c=a(this).find("[data-valmsg-summary=true]"),b=c.find("ul");if(b&&b.length&&d.errorList.length){b.empty();c.addClass("validation-summary-errors").removeClass("validation-summary-valid");a.each(d.errorList,function(){a("<li />").html(this.message).appendTo(b)})}}function k(d){var b=d.data("unobtrusiveContainer"),c=b.attr("data-valmsg-replace"),e=c?a.parseJSON(c):null;if(b){b.addClass("field-validation-valid").removeClass("field-validation-error");d.removeData("unobtrusiveContainer");e&&b.empty()}}function n(){var b=a(this);b.data("validator").resetForm();b.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors");b.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}function i(c){var b=a(c),d=b.data(e),f=a.proxy(n,c);if(!d){d={options:{errorClass:"input-validation-error",errorElement:"span",errorPlacement:a.proxy(m,c),invalidHandler:a.proxy(l,c),messages:{},rules:{},success:a.proxy(k,c)},attachValidation:function(){b.unbind("reset."+e,f).bind("reset."+e,f).validate(this.options)},validate:function(){b.validate();return b.valid()}};b.data(e,d)}return d}d.unobtrusive={adapters:[],parseElement:function(b,h){var d=a(b),f=d.parents("form")[0],c,e,g;if(!f)return;c=i(f);c.options.rules[b.name]=e={};c.options.messages[b.name]=g={};a.each(this.adapters,function(){var c="data-val-"+this.name,i=d.attr(c),h={};if(i!==undefined){c+="-";a.each(this.params,function(){h[this]=d.attr(c+this)});this.adapt({element:b,form:f,message:i,params:h,rules:e,messages:g})}});a.extend(e,{__dummy__:true});!h&&c.attachValidation()},parse:function(b){var c=a(b).parents("form").andSelf().add(a(b).find("form")).filter("form");a(b).find(":input").filter("[data-val=true]").each(function(){d.unobtrusive.parseElement(this,true)});c.each(function(){var a=i(this);a&&a.attachValidation()})}};b=d.unobtrusive.adapters;b.add=function(c,a,b){if(!b){b=a;a=[]}this.push({name:c,params:a,adapt:b});return this};b.addBool=function(a,b){return this.add(a,function(d){c(d,b||a,true)})};b.addMinMax=function(e,g,f,a,d,b){return this.add(e,[d||"min",b||"max"],function(b){var e=b.params.min,d=b.params.max;if(e&&d)c(b,a,[e,d]);else if(e)c(b,g,e);else d&&c(b,f,d)})};b.addSingleVal=function(a,b,d){return this.add(a,[b||"val"],function(e){c(e,d||a,e.params[b])})};d.addMethod("__dummy__",function(){return true});d.addMethod("regex",function(b,c,d){var a;if(this.optional(c))return true;a=(new RegExp(d)).exec(b);return a&&a.index===0&&a[0].length===b.length});d.addMethod("nonalphamin",function(c,d,b){var a;if(b){a=c.match(/\W/g);a=a&&a.length>=b}return a});if(d.methods.extension){b.addSingleVal("accept","mimtype");b.addSingleVal("extension","extension")}else b.addSingleVal("extension","extension","accept");b.addSingleVal("regex","pattern");b.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");b.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range");b.add("equalto",["other"],function(b){var i=h(b.element.name),j=b.params.other,d=g(j,i),e=a(b.form).find(":input").filter("[name='"+f(d)+"']")[0];c(b,"equalTo",e)});b.add("required",function(a){(a.element.tagName.toUpperCase()!=="INPUT"||a.element.type.toUpperCase()!=="CHECKBOX")&&c(a,"required",true)});b.add("remote",["url","type","additionalfields"],function(b){var d={url:b.params.url,type:b.params.type||"GET",data:{}},e=h(b.element.name);a.each(j(b.params.additionalfields||b.element.name),function(i,h){var c=g(h,e);d.data[c]=function(){return a(b.form).find(":input").filter("[name='"+f(c)+"']").val()}});c(b,"remote",d)});b.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&c(a,"minlength",a.params.min);a.params.nonalphamin&&c(a,"nonalphamin",a.params.nonalphamin);a.params.regex&&c(a,"regex",a.params.regex)});a(function(){d.unobtrusive.parse(document)})})(jQuery);

1416
src/MusicStore/Scripts/modernizr-2.6.2.js поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,340 @@
/* NUGET: BEGIN LICENSE TEXT
*
* Microsoft grants you the right to use these script files for the sole
* purpose of either: (i) interacting through your browser with the Microsoft
* website or online service, subject to the applicable licensing or use
* terms; or (ii) using the files as included with a Microsoft product subject
* to that product's license terms. Microsoft reserves all other rights to the
* files not expressly granted by Microsoft, whether by implication, estoppel
* or otherwise. Insofar as a script file is dual licensed under GPL,
* Microsoft neither took the code under GPL nor distributes it thereunder but
* under the terms set out in this paragraph. All notices and licenses
* below are for informational purposes only.
*
* NUGET: END LICENSE TEXT */
/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
window.matchMedia = window.matchMedia || (function(doc, undefined){
var bool,
docElem = doc.documentElement,
refNode = docElem.firstElementChild || docElem.firstChild,
// fakeBody required for <FF4 when executed in <head>
fakeBody = doc.createElement('body'),
div = doc.createElement('div');
div.id = 'mq-test-1';
div.style.cssText = "position:absolute;top:-100em";
fakeBody.style.background = "none";
fakeBody.appendChild(div);
return function(q){
div.innerHTML = '&shy;<style media="'+q+'"> #mq-test-1 { width: 42px; }</style>';
docElem.insertBefore(fakeBody, refNode);
bool = div.offsetWidth == 42;
docElem.removeChild(fakeBody);
return { matches: bool, media: q };
};
})(document);
/*! Respond.js v1.2.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */
(function( win ){
//exposed namespace
win.respond = {};
//define update even in native-mq-supporting browsers, to avoid errors
respond.update = function(){};
//expose media query support flag for external use
respond.mediaQueriesSupported = win.matchMedia && win.matchMedia( "only all" ).matches;
//if media queries are supported, exit here
if( respond.mediaQueriesSupported ){ return; }
//define vars
var doc = win.document,
docElem = doc.documentElement,
mediastyles = [],
rules = [],
appendedEls = [],
parsedSheets = {},
resizeThrottle = 30,
head = doc.getElementsByTagName( "head" )[0] || docElem,
base = doc.getElementsByTagName( "base" )[0],
links = head.getElementsByTagName( "link" ),
requestQueue = [],
//loop stylesheets, send text content to translate
ripCSS = function(){
var sheets = links,
sl = sheets.length,
i = 0,
//vars for loop:
sheet, href, media, isCSS;
for( ; i < sl; i++ ){
sheet = sheets[ i ],
href = sheet.href,
media = sheet.media,
isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
//only links plz and prevent re-parsing
if( !!href && isCSS && !parsedSheets[ href ] ){
// selectivizr exposes css through the rawCssText expando
if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
translate( sheet.styleSheet.rawCssText, href, media );
parsedSheets[ href ] = true;
} else {
if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base)
|| href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){
requestQueue.push( {
href: href,
media: media
} );
}
}
}
}
makeRequests();
},
//recurse through request queue, get css text
makeRequests = function(){
if( requestQueue.length ){
var thisRequest = requestQueue.shift();
ajax( thisRequest.href, function( styles ){
translate( styles, thisRequest.href, thisRequest.media );
parsedSheets[ thisRequest.href ] = true;
makeRequests();
} );
}
},
//find media blocks in css text, convert to style blocks
translate = function( styles, href, media ){
var qs = styles.match( /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi ),
ql = qs && qs.length || 0,
//try to get CSS path
href = href.substring( 0, href.lastIndexOf( "/" )),
repUrls = function( css ){
return css.replace( /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, "$1" + href + "$2$3" );
},
useMedia = !ql && media,
//vars used in loop
i = 0,
j, fullq, thisq, eachq, eql;
//if path exists, tack on trailing slash
if( href.length ){ href += "/"; }
//if no internal queries exist, but media attr does, use that
//note: this currently lacks support for situations where a media attr is specified on a link AND
//its associated stylesheet has internal CSS media queries.
//In those cases, the media attribute will currently be ignored.
if( useMedia ){
ql = 1;
}
for( ; i < ql; i++ ){
j = 0;
//media attr
if( useMedia ){
fullq = media;
rules.push( repUrls( styles ) );
}
//parse for styles
else{
fullq = qs[ i ].match( /@media *([^\{]+)\{([\S\s]+?)$/ ) && RegExp.$1;
rules.push( RegExp.$2 && repUrls( RegExp.$2 ) );
}
eachq = fullq.split( "," );
eql = eachq.length;
for( ; j < eql; j++ ){
thisq = eachq[ j ];
mediastyles.push( {
media : thisq.split( "(" )[ 0 ].match( /(only\s+)?([a-zA-Z]+)\s?/ ) && RegExp.$2 || "all",
rules : rules.length - 1,
hasquery: thisq.indexOf("(") > -1,
minw : thisq.match( /\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ),
maxw : thisq.match( /\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" )
} );
}
}
applyMedia();
},
lastCall,
resizeDefer,
// returns the value of 1em in pixels
getEmValue = function() {
var ret,
div = doc.createElement('div'),
body = doc.body,
fakeUsed = false;
div.style.cssText = "position:absolute;font-size:1em;width:1em";
if( !body ){
body = fakeUsed = doc.createElement( "body" );
body.style.background = "none";
}
body.appendChild( div );
docElem.insertBefore( body, docElem.firstChild );
ret = div.offsetWidth;
if( fakeUsed ){
docElem.removeChild( body );
}
else {
body.removeChild( div );
}
//also update eminpx before returning
ret = eminpx = parseFloat(ret);
return ret;
},
//cached container for 1em value, populated the first time it's needed
eminpx,
//enable/disable styles
applyMedia = function( fromResize ){
var name = "clientWidth",
docElemProp = docElem[ name ],
currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[ name ] || docElemProp,
styleBlocks = {},
lastLink = links[ links.length-1 ],
now = (new Date()).getTime();
//throttle resize calls
if( fromResize && lastCall && now - lastCall < resizeThrottle ){
clearTimeout( resizeDefer );
resizeDefer = setTimeout( applyMedia, resizeThrottle );
return;
}
else {
lastCall = now;
}
for( var i in mediastyles ){
var thisstyle = mediastyles[ i ],
min = thisstyle.minw,
max = thisstyle.maxw,
minnull = min === null,
maxnull = max === null,
em = "em";
if( !!min ){
min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
}
if( !!max ){
max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
}
// if there's no media query at all (the () part), or min or max is not null, and if either is present, they're true
if( !thisstyle.hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ) ){
if( !styleBlocks[ thisstyle.media ] ){
styleBlocks[ thisstyle.media ] = [];
}
styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] );
}
}
//remove any existing respond style element(s)
for( var i in appendedEls ){
if( appendedEls[ i ] && appendedEls[ i ].parentNode === head ){
head.removeChild( appendedEls[ i ] );
}
}
//inject active styles, grouped by media type
for( var i in styleBlocks ){
var ss = doc.createElement( "style" ),
css = styleBlocks[ i ].join( "\n" );
ss.type = "text/css";
ss.media = i;
//originally, ss was appended to a documentFragment and sheets were appended in bulk.
//this caused crashes in IE in a number of circumstances, such as when the HTML element had a bg image set, so appending beforehand seems best. Thanks to @dvelyk for the initial research on this one!
head.insertBefore( ss, lastLink.nextSibling );
if ( ss.styleSheet ){
ss.styleSheet.cssText = css;
}
else {
ss.appendChild( doc.createTextNode( css ) );
}
//push to appendedEls to track for later removal
appendedEls.push( ss );
}
},
//tweaked Ajax functions from Quirksmode
ajax = function( url, callback ) {
var req = xmlHttp();
if (!req){
return;
}
req.open( "GET", url, true );
req.onreadystatechange = function () {
if ( req.readyState != 4 || req.status != 200 && req.status != 304 ){
return;
}
callback( req.responseText );
}
if ( req.readyState == 4 ){
return;
}
req.send( null );
},
//define ajax obj
xmlHttp = (function() {
var xmlhttpmethod = false;
try {
xmlhttpmethod = new XMLHttpRequest();
}
catch( e ){
xmlhttpmethod = new ActiveXObject( "Microsoft.XMLHTTP" );
}
return function(){
return xmlhttpmethod;
};
})();
//translate CSS
ripCSS();
//expose update for re-running respond later on
respond.update = ripCSS;
//adjust on resize
function callMedia(){
applyMedia( true );
}
if( win.addEventListener ){
win.addEventListener( "resize", callMedia, false );
}
else if( win.attachEvent ){
win.attachEvent( "onresize", callMedia );
}
})(this);

20
src/MusicStore/Scripts/respond.min.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,20 @@
/* NUGET: BEGIN LICENSE TEXT
*
* Microsoft grants you the right to use these script files for the sole
* purpose of either: (i) interacting through your browser with the Microsoft
* website or online service, subject to the applicable licensing or use
* terms; or (ii) using the files as included with a Microsoft product subject
* to that product's license terms. Microsoft reserves all other rights to the
* files not expressly granted by Microsoft, whether by implication, estoppel
* or otherwise. Insofar as a script file is dual licensed under GPL,
* Microsoft neither took the code under GPL nor distributes it thereunder but
* under the terms set out in this paragraph. All notices and licenses
* below are for informational purposes only.
*
* NUGET: END LICENSE TEXT */
/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
window.matchMedia=window.matchMedia||(function(e,f){var c,a=e.documentElement,b=a.firstElementChild||a.firstChild,d=e.createElement("body"),g=e.createElement("div");g.id="mq-test-1";g.style.cssText="position:absolute;top:-100em";d.style.background="none";d.appendChild(g);return function(h){g.innerHTML='&shy;<style media="'+h+'"> #mq-test-1 { width: 42px; }</style>';a.insertBefore(d,b);c=g.offsetWidth==42;a.removeChild(d);return{matches:c,media:h}}})(document);
/*! Respond.js v1.2.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */
(function(e){e.respond={};respond.update=function(){};respond.mediaQueriesSupported=e.matchMedia&&e.matchMedia("only all").matches;if(respond.mediaQueriesSupported){return}var w=e.document,s=w.documentElement,i=[],k=[],q=[],o={},h=30,f=w.getElementsByTagName("head")[0]||s,g=w.getElementsByTagName("base")[0],b=f.getElementsByTagName("link"),d=[],a=function(){var D=b,y=D.length,B=0,A,z,C,x;for(;B<y;B++){A=D[B],z=A.href,C=A.media,x=A.rel&&A.rel.toLowerCase()==="stylesheet";if(!!z&&x&&!o[z]){if(A.styleSheet&&A.styleSheet.rawCssText){m(A.styleSheet.rawCssText,z,C);o[z]=true}else{if((!/^([a-zA-Z:]*\/\/)/.test(z)&&!g)||z.replace(RegExp.$1,"").split("/")[0]===e.location.host){d.push({href:z,media:C})}}}}u()},u=function(){if(d.length){var x=d.shift();n(x.href,function(y){m(y,x.href,x.media);o[x.href]=true;u()})}},m=function(I,x,z){var G=I.match(/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi),J=G&&G.length||0,x=x.substring(0,x.lastIndexOf("/")),y=function(K){return K.replace(/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,"$1"+x+"$2$3")},A=!J&&z,D=0,C,E,F,B,H;if(x.length){x+="/"}if(A){J=1}for(;D<J;D++){C=0;if(A){E=z;k.push(y(I))}else{E=G[D].match(/@media *([^\{]+)\{([\S\s]+?)$/)&&RegExp.$1;k.push(RegExp.$2&&y(RegExp.$2))}B=E.split(",");H=B.length;for(;C<H;C++){F=B[C];i.push({media:F.split("(")[0].match(/(only\s+)?([a-zA-Z]+)\s?/)&&RegExp.$2||"all",rules:k.length-1,hasquery:F.indexOf("(")>-1,minw:F.match(/\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:F.match(/\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}}j()},l,r,v=function(){var z,A=w.createElement("div"),x=w.body,y=false;A.style.cssText="position:absolute;font-size:1em;width:1em";if(!x){x=y=w.createElement("body");x.style.background="none"}x.appendChild(A);s.insertBefore(x,s.firstChild);z=A.offsetWidth;if(y){s.removeChild(x)}else{x.removeChild(A)}z=p=parseFloat(z);return z},p,j=function(I){var x="clientWidth",B=s[x],H=w.compatMode==="CSS1Compat"&&B||w.body[x]||B,D={},G=b[b.length-1],z=(new Date()).getTime();if(I&&l&&z-l<h){clearTimeout(r);r=setTimeout(j,h);return}else{l=z}for(var E in i){var K=i[E],C=K.minw,J=K.maxw,A=C===null,L=J===null,y="em";if(!!C){C=parseFloat(C)*(C.indexOf(y)>-1?(p||v()):1)}if(!!J){J=parseFloat(J)*(J.indexOf(y)>-1?(p||v()):1)}if(!K.hasquery||(!A||!L)&&(A||H>=C)&&(L||H<=J)){if(!D[K.media]){D[K.media]=[]}D[K.media].push(k[K.rules])}}for(var E in q){if(q[E]&&q[E].parentNode===f){f.removeChild(q[E])}}for(var E in D){var M=w.createElement("style"),F=D[E].join("\n");M.type="text/css";M.media=E;f.insertBefore(M,G.nextSibling);if(M.styleSheet){M.styleSheet.cssText=F}else{M.appendChild(w.createTextNode(F))}q.push(M)}},n=function(x,z){var y=c();if(!y){return}y.open("GET",x,true);y.onreadystatechange=function(){if(y.readyState!=4||y.status!=200&&y.status!=304){return}z(y.responseText)};if(y.readyState==4){return}y.send(null)},c=(function(){var x=false;try{x=new XMLHttpRequest()}catch(y){x=new ActiveXObject("Microsoft.XMLHTTP")}return function(){return x}})();a();respond.update=a;function t(){j(true)}if(e.addEventListener){e.addEventListener("resize",t,false)}else{if(e.attachEvent){e.attachEvent("onresize",t)}}})(this);

96
src/MusicStore/Startup.cs Normal file
Просмотреть файл

@ -0,0 +1,96 @@
// 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.Abstractions;
using Microsoft.AspNet.ConfigurationModel;
using Microsoft.AspNet.DependencyInjection;
using Microsoft.AspNet.DependencyInjection.Fallback;
using Microsoft.AspNet.DependencyInjection.NestedProviders;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.InMemory;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Routing;
using MusicStore.Models;
using System;
using System.Collections.Generic;
public class Startup
{
public void Configuration(IBuilder app)
{
CreateAdminUser();
app.UseFileServer();
var serviceProvider = MvcServices.GetDefaultServices().BuildServiceProvider(app.ServiceProvider);
var routes = new RouteCollection()
{
DefaultHandler = new MvcApplication(serviceProvider),
};
routes.MapRoute(
"{controller}/{action}",
new { controller = "Home", action = "Index" });
routes.MapRoute(
"{controller}",
new { controller = "Home" });
app.UseRouter(routes);
}
//Bug: We need EF to integrate with SQL server. Until then we will use in memory store
//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);
// }
// var user = await userManager.FindByNameAsync(_username);
// if (user == null)
// {
// user = new ApplicationUser { UserName = _username };
// await userManager.CreateAsync(user, _password);
// await userManager.AddToRoleAsync(user.Id, _role);
// }
//}
private async void CreateAdminUser()
{
//How to read from local appSettings?
var configuration = new Configuration();
string _username = "Administrator"; // configuration.Get("DefaultAdminUsername");
string _password = "YouShouldChangeThisPassword"; // configuration.Get("DefaultAdminPassword");
string _role = "Administrator";
var userManager = new UserManager<ApplicationUser, string>(new InMemoryUserStore<ApplicationUser>());
var roleManager = new RoleManager<InMemoryRole>(new InMemoryRoleStore());
var role = new InMemoryRole(_role);
var result = await roleManager.RoleExists(_role);
if (result == false)
{
await roleManager.Create(role);
}
var user = await userManager.FindByName(_username);
if (user == null)
{
user = new ApplicationUser { UserName = _username };
await userManager.Create(user, _password);
await userManager.AddToRole(user.Id, _role);
}
}
}

Просмотреть файл

@ -1,18 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
namespace MvcMusicStore
{
public static class ListExtensions
{
public static void ForEach<T>(this List<T> list, Action<T> each)
{
foreach (var item in list)
{
each(item);
}
}
}
}

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -0,0 +1,26 @@
@*Bug: Having a ViewBag.Title throws compilation error: https://github.com/aspnet/WebFx/issues/67*@
@{
//Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Home Page";
}
<div class="jumbotron">
<h1>MVC Music Store</h1>
@*Bug: Having a ~ in url throws compilation error : https://github.com/aspnet/WebFx/issues/66*@
<img src="/Images/home-showcase.png" />
</div>
<ul class="row list-unstyled" id="album-list">
@foreach (var album in Model)
{
<li class="col-lg-2 col-md-2 col-sm-2 col-xs-4 container">
<a href="@Url.Action("Details", "Store", new { id = album.AlbumId })">
@*Bug: Url helpers not implemented yet*@
@*<img alt="@album.Title" src="@Url.Content(@album.AlbumArtUrl)" />*@
<img alt="@album.Title" src="@album.AlbumArtUrl" />
<h4>@album.Title</h4>
</a>
</li>
}
</ul>

Просмотреть файл

@ -0,0 +1,57 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title – MVC Music Store</title>
@*Bug: No Style and Script helpers yet. Manually including the script files*@
@*@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")*@
<link rel="stylesheet" href="/Content/bootstrap.min.css" />
<link rel="stylesheet" href="/Content/Site.css" />
<script type="text/javascript" src="/Scripts/modernizr-2.6.2.js"></script>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
@*Bug: no Html helpers yet*@
@*@Html.ActionLink("ASP.NET MVC Music Store", "Index", "Home", null, new { @class = "navbar-brand" })*@
<a class="navbar-brand" href="/">ASP.NET MVC Music Store</a>
</div>
@*Bug: HtmlHelpers missing*@
@*<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>@Html.ActionLink("Home", "Index", "Home")</li>
@Html.Action("GenreMenu", "Store")
@Html.Action("CartSummary", "ShoppingCart")
</ul>
@Html.Partial("_LoginPartial")
</div>*@
</div>
</div>
<div class="container body-content">
@RenderBody()
<hr />
<footer class="navbar navbar-fixed-bottom navbar-default text-center">
<p><a href="http://mvcmusicstore.codeplex.com">mvcmusicstore.codeplex.com</a></p>
<small>@Html.ActionLink("admin", "Index", "StoreManager")</small>
</footer>
</div>
@*Bug: No script helpers yet*@
@*@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)*@
<script src="/Scripts/jquery-1.10.2.js"></script>
<script src="/Scripts/bootstrap.js"></script>
<script src="/Scripts/respond.js"></script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,9 @@
@if (ViewBag.CartCount > 0)
{
<li>
<a href="@Url.Action("Index", "ShoppingCart")" title="@ViewBag.CartSummary">
<span class="glyphicon glyphicon glyphicon-shopping-cart"></span>
@ViewBag.CartCount
</a>
</li>
}

Просмотреть файл

@ -0,0 +1,90 @@
@model MvcMusicStore.ViewModels.ShoppingCartViewModel
@{
ViewBag.Title = "Shopping Cart";
}
@section Scripts {
<script type="text/javascript">
$(function () {
// Document.ready -> link up remove event handler
$(".RemoveLink").click(function () {
// Get the id from the link
var recordToDelete = $(this).attr("data-id");
var PostToUrl = $(this).attr("data-url");
if (recordToDelete != '') {
// Perform the ajax post
$.post(PostToUrl, { "id": recordToDelete },
function (data) {
// Successful requests get here
// Update the page elements
if (data.ItemCount == 0) {
$('#row-' + data.DeleteId).fadeOut('slow');
} else {
$('#item-count-' + data.DeleteId).text(data.ItemCount);
}
$('#cart-total').text(data.CartTotal);
$('#update-message').text(data.Message);
$('#cart-status').text('Cart (' + data.CartCount + ')');
});
}
});
});
</script>
}
<h3>
<em>Review</em> your cart:
</h3>
<p class="button">
@Html.ActionLink("Checkout >>", "AddressAndPayment", "Checkout")
</p>
<div id="update-message">
</div>
<table id="cart-summary">
<tr>
<th>
Album Name
</th>
<th>
Price (each)
</th>
<th>
Quantity
</th>
<th></th>
</tr>
@foreach (var item in Model.CartItems)
{
<tr id="row-@item.RecordId">
<td>
@Html.ActionLink(item.Album.Title,
"Details", "Store", new { id = item.AlbumId }, null)
</td>
<td>
@item.Album.Price
</td>
<td id="item-count-@item.RecordId">
@item.Count
</td>
<td>
<a href="#" class="RemoveLink" data-id="@item.RecordId"
data-url='@Url.Content("~/ShoppingCart/RemoveFromCart")'>
Remove from cart
</a>
</td>
</tr>
}
<tr>
<td>
Total
</td>
<td></td>
<td></td>
<td id="cart-total">
@Model.CartTotal
</td>
</tr>
</table>

Просмотреть файл

@ -0,0 +1,26 @@
@model MusicStore.Models.Genre
@{
ViewBag.Title = "Browse Albums";
}
<div class="genre">
<h3>
<em>@Model.Name</em> Albums
</h3>
<ul id="album-list" class="list-unstyled">
@foreach (var album in Model.Albums)
{
<li class="col-lg-2 col-md-2 col-sm-2 col-xs-4 container">
<a href="@Url.Action("Details", new { id = album.AlbumId })">
@if (!string.IsNullOrEmpty(album.AlbumArtUrl))
{
@*Bug: Url helpers not implemented yet*@
@*<img alt="@album.Title" src="@Url.Content(@album.AlbumArtUrl)" />*@
<img alt="@album.Title" src="@album.AlbumArtUrl" />
}
<h5 class="control-label">@album.Title</h5>
</a>
</li>
}
</ul>
</div>

Просмотреть файл

@ -0,0 +1,34 @@
@model MusicStore.Models.Album
@{
ViewBag.Title = "Album - " + Model.Title;
}
<h2>@Model.Title</h2>
<p>
@*Bug: Url helpers not implemented yet*@
@*<img alt="@Model.Title" src="@Url.Content(@Model.AlbumArtUrl)" />*@
<img alt="@Model.Title" src="@Model.AlbumArtUrl" />
</p>
<div id="album-details">
<p>
<em>Genre:</em>
@Model.Genre.Name
</p>
<p>
<em>Artist:</em>
@Model.Artist.Name
</p>
<p>
<em>Price:</em>
@*Bug: HTML helpers not implemented yet*@
@*@Html.DisplayFor(model => model.Price)*@
</p>
<p class="button">
@*Bug: HTML helpers not implemented yet*@
@*@Html.ActionLink("Add to cart", "AddToCart",
"ShoppingCart", new { id = Model.AlbumId }, "")*@
</p>
</div>

Просмотреть файл

@ -0,0 +1,21 @@
@*Bug: intellisense changes the case of the type. Need to use a normal text editor to edit this view.
Bug: Child actions not implemented yet*@
@*@model System.Collections.Generic.IEnumerable<mvcmusicstore.models.genre>*@
<li class="dropdown">
<a href="@Url.Action("Store")" class="dropdown-toggle" data-toggle="dropdown">Store <b class="caret"></b></a>
<ul class="dropdown-menu">
@foreach (var genre in Model)
{
<li>
@Html.ActionLink(genre.Name,
"Browse", "Store",
new { Genre = genre.Name }, null)
</li>
}
<li class="divider"></li>
<li>
@Html.ActionLink("More...", "Index", "Store")
</li>
</ul>
</li>

Просмотреть файл

@ -0,0 +1,17 @@
@model IEnumerable<MusicStore.Models.Genre>
@{
ViewBag.Title = "Store";
}
<h3>Browse Genres</h3>
<p>
Select from @Model.Count() genres:
</p>
<ul class="list-group">
@foreach (var genre in Model)
{
//Bug: Html helpers ActionLink is not implemented still
@*<li class="list-group-item">@Html.ActionLink(genre.Name, "Browse", new { genre = genre.Name })</li>*@
<li class="list-group-item"><a href="@Url.Action("Browse", "Store", new { genre = genre.Name })">@genre.Name</a></li>
}
</ul>

Просмотреть файл

@ -0,0 +1,73 @@
@*Bug: Fully dependent on HTML helpers*@
@model MvcMusicStore.Models.Album
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Album</h4>
<hr />
@Html.ValidationSummary(true)
<div class="form-group">
@Html.LabelFor(model => model.GenreId, "GenreId", new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("GenreId", String.Empty)
@Html.ValidationMessageFor(model => model.GenreId)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ArtistId, "ArtistId", new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("ArtistId", String.Empty)
@Html.ValidationMessageFor(model => model.ArtistId)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Title)
@Html.ValidationMessageFor(model => model.Title)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Price, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Price)
@Html.ValidationMessageFor(model => model.Price)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.AlbumArtUrl, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.AlbumArtUrl)
@Html.ValidationMessageFor(model => model.AlbumArtUrl)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}

Просмотреть файл

@ -0,0 +1,24 @@
@*Bug: Dependent on Htmlhelpers*@
@model MvcMusicStore.Models.Album
@{
ViewBag.Title = "Delete";
}
<h2>Delete Confirmation</h2>
<p>
Are you sure you want to delete the album titled
<strong>@Model.Title</strong>?
</p>
@using (Html.BeginForm())
{
<p>
<input type="submit" value="Delete" />
</p>
<p>
@Html.ActionLink("Back to List", "Index")
</p>
}

Просмотреть файл

@ -0,0 +1,59 @@
@*Bug: Dependent on Htmlhelpers*@
@model MvcMusicStore.Models.Album
@{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<div>
<h4>Album</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.Artist.Name)
</dt>
<dd>
@Html.DisplayFor(model => model.Artist.Name)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Genre.Name)
</dt>
<dd>
@Html.DisplayFor(model => model.Genre.Name)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Title)
</dt>
<dd>
@Html.DisplayFor(model => model.Title)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Price)
</dt>
<dd>
@Html.DisplayFor(model => model.Price)
</dd>
<dt>
@Html.DisplayNameFor(model => model.AlbumArtUrl)
</dt>
<dd>
@Html.DisplayFor(model => model.AlbumArtUrl)
</dd>
</dl>
</div>
<p>
@Html.ActionLink("Edit", "Edit", new { id = Model.AlbumId }) |
@Html.ActionLink("Back to List", "Index")
</p>

Просмотреть файл

@ -0,0 +1,74 @@
@*Bug: Dependent on Htmlhelpers*@
@model MvcMusicStore.Models.Album
@{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Album</h4>
<hr />
@Html.ValidationSummary(true)
@Html.HiddenFor(model => model.AlbumId)
<div class="form-group">
@Html.LabelFor(model => model.GenreId, "GenreId", new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("GenreId", String.Empty)
@Html.ValidationMessageFor(model => model.GenreId)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ArtistId, "ArtistId", new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("ArtistId", String.Empty)
@Html.ValidationMessageFor(model => model.ArtistId)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Title)
@Html.ValidationMessageFor(model => model.Title)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Price, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Price)
@Html.ValidationMessageFor(model => model.Price)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.AlbumArtUrl, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.AlbumArtUrl)
@Html.ValidationMessageFor(model => model.AlbumArtUrl)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}

Просмотреть файл

@ -0,0 +1,65 @@
@*Bug: Dependent on Htmlhelpers*@
@model IEnumerable<mvcmusicstore.models.album>
@helper Truncate(string input, int length)
{
if (input.Length <= length)
{
@input
}
else
{
@input.Substring(0, length)<text>...</text>
}
}
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.Genre.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Artist.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Price)
</th>
<th></th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Genre.Name)
</td>
<td>
@Truncate(item.Artist.Name, 25)
</td>
<td>
@Truncate(item.Title, 25)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = item.AlbumId }) |
@Html.ActionLink("Details", "Details", new { id = item.AlbumId }) |
@Html.ActionLink("Delete", "Delete", new { id = item.AlbumId })
</td>
</tr>
}
</table>

1
src/MusicStore/lkg.cmd Normal file
Просмотреть файл

@ -0,0 +1 @@
\\indigofs\commonshare\prabht\k\LKGTools\LkgProjectGenerator.exe "%CD%\..\..\Packages"

Просмотреть файл

@ -1,19 +1,45 @@
{
"dependencies": {
"Microsoft.AspNet.Abstractions": "0.1-alpha-*",
"Microsoft.AspNet.DependencyInjection" : "0.1-alpha-*",
"Microsoft.AspNet.Mvc.Core" : "0.1-alpha-*",
"Microsoft.Data.Entity" : "0.1-alpha-*",
"Microsoft.AspNet.Identity" : "0.1-alpha-*",
"Microsoft.AspNet.Identity.InMemory" : "0.1-alpha-*"
},
"configurations": {
"net45": {
"dependencies": {
"System.Runtime" : "",
"System.Collections" : ""
}
"version": "0.1-alpha-*",
"dependencies": {
"Helios": "0.1-alpha-*",
"Microsoft.AspNet.Abstractions": "0.1-alpha-*",
"Microsoft.AspNet.Mvc": "0.1-alpha-*",
"Microsoft.AspNet.Razor": "0.1-alpha-*",
"Microsoft.AspNet.ConfigurationModel": "0.1-alpha-*",
"Microsoft.AspNet.DependencyInjection": "0.1-alpha-*",
"Microsoft.AspNet.RequestContainer": "0.1-alpha-*",
"Microsoft.AspNet.Routing": "0.1-alpha-*",
"Microsoft.AspNet.Mvc.ModelBinding": "0.1-alpha-*",
"Microsoft.AspNet.Mvc.Core": "0.1-alpha-*",
"Microsoft.AspNet.Mvc.Razor": "0.1-alpha-*",
"Microsoft.AspNet.Mvc.Rendering": "0.1-alpha-*",
"Microsoft.AspNet.StaticFiles": "0.1-alpha-*",
"System.Security.Claims": "0.1-alpha-*",
"Microsoft.AspNet.Security.DataProtection": "0.1-alpha-*",
"Microsoft.AspNet.Identity": "0.1-alpha-*",
"Microsoft.AspNet.Identity.Entity": "0.1-alpha-*",
"Microsoft.AspNet.Identity.InMemory": "0.1-alpha-*"
},
"k10": {}
}
"configurations": {
"net45": {
"dependencies": {
"System.Runtime": "",
"System.ComponentModel.DataAnnotations": ""
}
},
"k10": {
"dependencies": {
"System.Collections": "4.0.0.0",
"System.Linq": "4.0.0.0",
"System.Runtime": "4.0.20.0",
"System.Dynamic.Runtime": "4.0.0.0",
"System.Threading.Tasks": "4.0.0.0",
"System.ComponentModel": "4.0.0.0",
"System.Console": "4.0.0.0",
"System.Diagnostics.Debug": "4.0.10.0",
"System.Diagnostics.Tools": "4.0.0.0",
"Microsoft.ComponentModel.DataAnnotations": "0.1-alpha-*"
}
}
}
}

16
src/MusicStore/web.config Normal file
Просмотреть файл

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<appSettings>
<add key="K" value="false" />
<add key="DefaultAdminUsername" value="Administrator" />
<add key="DefaultAdminPassword" value="YouShouldChangeThisPassword" />
</appSettings>
</configuration>

Просмотреть файл

@ -62,39 +62,41 @@
<HintPath>..\..\packages\Microsoft.AspNet.Identity.Owin.1.0.0\lib\net45\Microsoft.AspNet.Identity.Owin.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.Owin">
<HintPath>..\..\packages\Microsoft.Owin.2.0.2\lib\net45\Microsoft.Owin.dll</HintPath>
<Reference Include="Microsoft.Owin, Version=2.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Microsoft.Owin.2.1.0\lib\net45\Microsoft.Owin.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Owin.Host.SystemWeb">
<HintPath>..\..\packages\Microsoft.Owin.Host.SystemWeb.2.0.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll</HintPath>
<HintPath>..\..\packages\Microsoft.Owin.Host.SystemWeb.2.1.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Owin.Security">
<HintPath>..\..\packages\Microsoft.Owin.Security.2.0.2\lib\net45\Microsoft.Owin.Security.dll</HintPath>
<Reference Include="Microsoft.Owin.Security, Version=2.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Microsoft.Owin.Security.2.1.0\lib\net45\Microsoft.Owin.Security.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Owin.Security.Cookies">
<HintPath>..\..\packages\Microsoft.Owin.Security.Cookies.2.0.2\lib\net45\Microsoft.Owin.Security.Cookies.dll</HintPath>
<HintPath>..\..\packages\Microsoft.Owin.Security.Cookies.2.1.0\lib\net45\Microsoft.Owin.Security.Cookies.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Owin.Security.Facebook">
<HintPath>..\..\packages\Microsoft.Owin.Security.Facebook.2.0.0\lib\net45\Microsoft.Owin.Security.Facebook.dll</HintPath>
<HintPath>..\..\packages\Microsoft.Owin.Security.Facebook.2.1.0\lib\net45\Microsoft.Owin.Security.Facebook.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Owin.Security.Google">
<HintPath>..\..\packages\Microsoft.Owin.Security.Google.2.0.0\lib\net45\Microsoft.Owin.Security.Google.dll</HintPath>
<HintPath>..\..\packages\Microsoft.Owin.Security.Google.2.1.0\lib\net45\Microsoft.Owin.Security.Google.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Owin.Security.MicrosoftAccount">
<HintPath>..\..\packages\Microsoft.Owin.Security.MicrosoftAccount.2.0.0\lib\net45\Microsoft.Owin.Security.MicrosoftAccount.dll</HintPath>
<HintPath>..\..\packages\Microsoft.Owin.Security.MicrosoftAccount.2.1.0\lib\net45\Microsoft.Owin.Security.MicrosoftAccount.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Owin.Security.OAuth">
<HintPath>..\..\packages\Microsoft.Owin.Security.OAuth.2.0.2\lib\net45\Microsoft.Owin.Security.OAuth.dll</HintPath>
<HintPath>..\..\packages\Microsoft.Owin.Security.OAuth.2.1.0\lib\net45\Microsoft.Owin.Security.OAuth.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Owin.Security.Twitter">
<HintPath>..\..\packages\Microsoft.Owin.Security.Twitter.2.0.0\lib\net45\Microsoft.Owin.Security.Twitter.dll</HintPath>
<HintPath>..\..\packages\Microsoft.Owin.Security.Twitter.2.1.0\lib\net45\Microsoft.Owin.Security.Twitter.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>..\..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll</HintPath>
<HintPath>..\..\packages\Newtonsoft.Json.5.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Owin">
<HintPath>..\..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>

Просмотреть файл

@ -50,19 +50,19 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.2.0" newVersion="2.0.2.0" />
<bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.2.0" newVersion="2.0.2.0" />
<bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.2.0" newVersion="2.0.2.0" />
<bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.2.0" newVersion="2.0.2.0" />
<bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>

Просмотреть файл

@ -13,15 +13,15 @@
<package id="Microsoft.AspNet.Web.Optimization" version="1.1.1" targetFramework="net45" />
<package id="Microsoft.AspNet.WebPages" version="3.0.0" targetFramework="net45" />
<package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.0.0" targetFramework="net45" />
<package id="Microsoft.Owin" version="2.0.2" targetFramework="net45" />
<package id="Microsoft.Owin.Host.SystemWeb" version="2.0.2" targetFramework="net45" />
<package id="Microsoft.Owin.Security" version="2.0.2" targetFramework="net45" />
<package id="Microsoft.Owin.Security.Cookies" version="2.0.2" targetFramework="net45" />
<package id="Microsoft.Owin.Security.Facebook" version="2.0.2" targetFramework="net45" />
<package id="Microsoft.Owin.Security.Google" version="2.0.2" targetFramework="net45" />
<package id="Microsoft.Owin.Security.MicrosoftAccount" version="2.0.2" targetFramework="net45" />
<package id="Microsoft.Owin.Security.OAuth" version="2.0.2" targetFramework="net45" />
<package id="Microsoft.Owin.Security.Twitter" version="2.0.2" targetFramework="net45" />
<package id="Microsoft.Owin" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Host.SystemWeb" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security.Cookies" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security.Facebook" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security.Google" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security.MicrosoftAccount" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security.OAuth" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Owin.Security.Twitter" version="2.1.0" targetFramework="net45" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
<package id="Modernizr" version="2.6.2" targetFramework="net45" />
<package id="Newtonsoft.Json" version="5.0.8" targetFramework="net45" />