diff --git a/eShopOnWeb.sln b/eShopOnWeb.sln index ef492ec..609ebbc 100644 --- a/eShopOnWeb.sln +++ b/eShopOnWeb.sln @@ -24,8 +24,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Web", "src\Web\Web.csproj", "{227CF035-29B0-448D-97E4-944F9EA850E5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebRazorPages", "src\WebRazorPages\WebRazorPages.csproj", "{E2D75FD9-84A8-46B1-97E4-9AC67F919D11}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -56,10 +54,6 @@ Global {227CF035-29B0-448D-97E4-944F9EA850E5}.Debug|Any CPU.Build.0 = Debug|Any CPU {227CF035-29B0-448D-97E4-944F9EA850E5}.Release|Any CPU.ActiveCfg = Release|Any CPU {227CF035-29B0-448D-97E4-944F9EA850E5}.Release|Any CPU.Build.0 = Release|Any CPU - {E2D75FD9-84A8-46B1-97E4-9AC67F919D11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E2D75FD9-84A8-46B1-97E4-9AC67F919D11}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E2D75FD9-84A8-46B1-97E4-9AC67F919D11}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E2D75FD9-84A8-46B1-97E4-9AC67F919D11}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -71,7 +65,6 @@ Global {0F576306-7E2D-49B7-87B1-EB5D94CFD5FC} = {15EA4737-125B-4E6E-A806-E13B7EBCDCCF} {7EFB5482-F942-4C3D-94B0-9B70596E6D0A} = {15EA4737-125B-4E6E-A806-E13B7EBCDCCF} {227CF035-29B0-448D-97E4-944F9EA850E5} = {419A6ACE-0419-4315-A6FB-B0E63D39432E} - {E2D75FD9-84A8-46B1-97E4-9AC67F919D11} = {419A6ACE-0419-4315-A6FB-B0E63D39432E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {49813262-5DA3-4D61-ABD3-493C74CE8C2B} diff --git a/src/Web/Constants.cs b/src/Web/Constants.cs index fbc5855..3117820 100644 --- a/src/Web/Constants.cs +++ b/src/Web/Constants.cs @@ -3,5 +3,7 @@ public static class Constants { public const string BASKET_COOKIENAME = "eShop"; + public const int ITEMS_PER_PAGE = 10; + public const string DEFAULT_USERNAME = "Guest"; } } diff --git a/src/Web/Controllers/AccountController.cs b/src/Web/Controllers/AccountController.cs index a03a963..281497b 100644 --- a/src/Web/Controllers/AccountController.cs +++ b/src/Web/Controllers/AccountController.cs @@ -12,7 +12,7 @@ namespace Microsoft.eShopWeb.Web.Controllers { [ApiExplorerSettings(IgnoreApi = true)] [Route("[controller]/[action]")] - [Authorize] + [Authorize] // Controllers that mainly require Authorization still use Controller/View; other pages use Pages public class AccountController : Controller { private readonly UserManager _userManager; @@ -150,7 +150,7 @@ namespace Microsoft.eShopWeb.Web.Controllers { await _signInManager.SignOutAsync(); - return RedirectToAction(nameof(CatalogController.Index), "Catalog"); + return RedirectToPage("/Index"); } [AllowAnonymous] @@ -186,7 +186,7 @@ namespace Microsoft.eShopWeb.Web.Controllers { if (userId == null || code == null) { - return RedirectToAction(nameof(CatalogController.Index), "Catalog"); + return RedirectToPage("/Index"); } var user = await _userManager.FindByIdAsync(userId); if (user == null) @@ -217,7 +217,7 @@ namespace Microsoft.eShopWeb.Web.Controllers } else { - return RedirectToAction(nameof(CatalogController.Index), "Catalog"); + return RedirectToPage("/Index"); } } diff --git a/src/Web/Controllers/BasketController.cs b/src/Web/Controllers/BasketController.cs deleted file mode 100644 index 1f679a8..0000000 --- a/src/Web/Controllers/BasketController.cs +++ /dev/null @@ -1,112 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Mvc; -using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate; -using Microsoft.eShopWeb.ApplicationCore.Interfaces; -using Microsoft.eShopWeb.Infrastructure.Identity; -using Microsoft.eShopWeb.Web.Interfaces; -using Microsoft.eShopWeb.Web.ViewModels; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Microsoft.eShopWeb.Web.Controllers -{ - [ApiExplorerSettings(IgnoreApi = true)] - [Route("[controller]/[action]")] - public class BasketController : Controller - { - private readonly IBasketService _basketService; - private readonly IUriComposer _uriComposer; - private readonly SignInManager _signInManager; - private readonly IAppLogger _logger; - private readonly IOrderService _orderService; - private readonly IBasketViewModelService _basketViewModelService; - - public BasketController(IBasketService basketService, - IBasketViewModelService basketViewModelService, - IOrderService orderService, - IUriComposer uriComposer, - SignInManager signInManager, - IAppLogger logger) - { - _basketService = basketService; - _uriComposer = uriComposer; - _signInManager = signInManager; - _logger = logger; - _orderService = orderService; - _basketViewModelService = basketViewModelService; - } - - [HttpGet] - public async Task Index() - { - var basketModel = await GetBasketViewModelAsync(); - - return View(basketModel); - } - - [HttpPost] - public async Task Index(Dictionary items) - { - var basketViewModel = await GetBasketViewModelAsync(); - await _basketService.SetQuantities(basketViewModel.Id, items); - - return View(await GetBasketViewModelAsync()); - } - - - // POST: /Basket/AddToBasket - [HttpPost] - public async Task AddToBasket(CatalogItemViewModel productDetails) - { - if (productDetails?.Id == null) - { - return RedirectToAction("Index", "Catalog"); - } - var basketViewModel = await GetBasketViewModelAsync(); - - await _basketService.AddItemToBasket(basketViewModel.Id, productDetails.Id, productDetails.Price, 1); - - return RedirectToAction("Index"); - } - - [HttpPost] - [Authorize] - public async Task Checkout(Dictionary items) - { - var basketViewModel = await GetBasketViewModelAsync(); - await _basketService.SetQuantities(basketViewModel.Id, items); - - await _orderService.CreateOrderAsync(basketViewModel.Id, new Address("123 Main St.", "Kent", "OH", "United States", "44240")); - - await _basketService.DeleteBasketAsync(basketViewModel.Id); - - return View("Checkout"); - } - - private async Task GetBasketViewModelAsync() - { - if (_signInManager.IsSignedIn(HttpContext.User)) - { - return await _basketViewModelService.GetOrCreateBasketForUser(User.Identity.Name); - } - string anonymousId = GetOrSetBasketCookie(); - return await _basketViewModelService.GetOrCreateBasketForUser(anonymousId); - } - - private string GetOrSetBasketCookie() - { - if (Request.Cookies.ContainsKey(Constants.BASKET_COOKIENAME)) - { - return Request.Cookies[Constants.BASKET_COOKIENAME]; - } - string anonymousId = Guid.NewGuid().ToString(); - var cookieOptions = new CookieOptions(); - cookieOptions.Expires = DateTime.Today.AddYears(10); - Response.Cookies.Append(Constants.BASKET_COOKIENAME, anonymousId, cookieOptions); - return anonymousId; - } - } -} diff --git a/src/Web/Controllers/CatalogController.cs b/src/Web/Controllers/CatalogController.cs deleted file mode 100644 index e32d24a..0000000 --- a/src/Web/Controllers/CatalogController.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.eShopWeb.Web.Services; -using System.Threading.Tasks; - -namespace Microsoft.eShopWeb.Web.Controllers -{ - [ApiExplorerSettings(IgnoreApi = true)] - [Route("")] - public class CatalogController : Controller - { - private readonly ICatalogService _catalogService; - - public CatalogController(ICatalogService catalogService) => _catalogService = catalogService; - - [HttpGet] - [HttpPost] - public async Task Index(int? brandFilterApplied, int? typesFilterApplied, int? page) - { - var itemsPage = 10; - var catalogModel = await _catalogService.GetCatalogItems(page ?? 0, itemsPage, brandFilterApplied, typesFilterApplied); - return View(catalogModel); - } - - [HttpGet("Error")] - public IActionResult Error() - { - return View(); - } - } -} diff --git a/src/Web/Controllers/ManageController.cs b/src/Web/Controllers/ManageController.cs index 07704d7..4f6886e 100644 --- a/src/Web/Controllers/ManageController.cs +++ b/src/Web/Controllers/ManageController.cs @@ -15,7 +15,7 @@ using System.Threading.Tasks; namespace Microsoft.eShopWeb.Web.Controllers { [ApiExplorerSettings(IgnoreApi = true)] - [Authorize] + [Authorize] // Controllers that mainly require Authorization still use Controller/View; other pages use Pages [Route("[controller]/[action]")] public class ManageController : Controller { diff --git a/src/Web/Controllers/OrderController.cs b/src/Web/Controllers/OrderController.cs index 3c314c9..b60cd32 100644 --- a/src/Web/Controllers/OrderController.cs +++ b/src/Web/Controllers/OrderController.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; namespace Microsoft.eShopWeb.Web.Controllers { [ApiExplorerSettings(IgnoreApi = true)] - [Authorize] + [Authorize] // Controllers that mainly require Authorization still use Controller/View; other pages use Pages [Route("[controller]/[action]")] public class OrderController : Controller { diff --git a/src/Web/Interfaces/IBasketViewModelService.cs b/src/Web/Interfaces/IBasketViewModelService.cs index 7a5c845..3be5c84 100644 --- a/src/Web/Interfaces/IBasketViewModelService.cs +++ b/src/Web/Interfaces/IBasketViewModelService.cs @@ -1,4 +1,4 @@ -using Microsoft.eShopWeb.Web.ViewModels; +using Microsoft.eShopWeb.Web.Pages.Basket; using System.Threading.Tasks; namespace Microsoft.eShopWeb.Web.Interfaces diff --git a/src/Web/ViewModels/BasketItemViewModel.cs b/src/Web/Pages/Basket/BasketItemViewModel.cs similarity index 88% rename from src/Web/ViewModels/BasketItemViewModel.cs rename to src/Web/Pages/Basket/BasketItemViewModel.cs index 5f74436..129f0e2 100644 --- a/src/Web/ViewModels/BasketItemViewModel.cs +++ b/src/Web/Pages/Basket/BasketItemViewModel.cs @@ -1,4 +1,4 @@ -namespace Microsoft.eShopWeb.Web.ViewModels +namespace Microsoft.eShopWeb.Web.Pages.Basket { public class BasketItemViewModel { diff --git a/src/Web/ViewModels/BasketViewModel.cs b/src/Web/Pages/Basket/BasketViewModel.cs similarity index 90% rename from src/Web/ViewModels/BasketViewModel.cs rename to src/Web/Pages/Basket/BasketViewModel.cs index 901bef9..264df2b 100644 --- a/src/Web/ViewModels/BasketViewModel.cs +++ b/src/Web/Pages/Basket/BasketViewModel.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; -namespace Microsoft.eShopWeb.Web.ViewModels +namespace Microsoft.eShopWeb.Web.Pages.Basket { public class BasketViewModel { diff --git a/src/Web/Views/Basket/Checkout.cshtml b/src/Web/Pages/Basket/Checkout.cshtml similarity index 71% rename from src/Web/Views/Basket/Checkout.cshtml rename to src/Web/Pages/Basket/Checkout.cshtml index 907bddc..01e0a78 100644 --- a/src/Web/Views/Basket/Checkout.cshtml +++ b/src/Web/Pages/Basket/Checkout.cshtml @@ -1,6 +1,7 @@ -@{ +@page + @model CheckoutModel +@{ ViewData["Title"] = "Checkout Complete"; - @model BasketViewModel }
@@ -11,5 +12,5 @@

Thanks for your Order!

- Continue Shopping... + Continue Shopping...
diff --git a/src/Web/Pages/Basket/Checkout.cshtml.cs b/src/Web/Pages/Basket/Checkout.cshtml.cs new file mode 100644 index 0000000..5646f11 --- /dev/null +++ b/src/Web/Pages/Basket/Checkout.cshtml.cs @@ -0,0 +1,83 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate; +using Microsoft.eShopWeb.ApplicationCore.Interfaces; +using Microsoft.eShopWeb.Infrastructure.Identity; +using Microsoft.eShopWeb.Web.Interfaces; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Microsoft.eShopWeb.Web.Pages.Basket +{ + public class CheckoutModel : PageModel + { + private readonly IBasketService _basketService; + private readonly IUriComposer _uriComposer; + private readonly SignInManager _signInManager; + private readonly IOrderService _orderService; + private string _username = null; + private readonly IBasketViewModelService _basketViewModelService; + + public CheckoutModel(IBasketService basketService, + IBasketViewModelService basketViewModelService, + IUriComposer uriComposer, + SignInManager signInManager, + IOrderService orderService) + { + _basketService = basketService; + _uriComposer = uriComposer; + _signInManager = signInManager; + _orderService = orderService; + _basketViewModelService = basketViewModelService; + } + + public BasketViewModel BasketModel { get; set; } = new BasketViewModel(); + + public void OnGet() + { + } + + public async Task OnPost(Dictionary items) + { + await SetBasketModelAsync(); + + await _basketService.SetQuantities(BasketModel.Id, items); + + await _orderService.CreateOrderAsync(BasketModel.Id, new Address("123 Main St.", "Kent", "OH", "United States", "44240")); + + await _basketService.DeleteBasketAsync(BasketModel.Id); + + return RedirectToPage(); + } + + private async Task SetBasketModelAsync() + { + if (_signInManager.IsSignedIn(HttpContext.User)) + { + BasketModel = await _basketViewModelService.GetOrCreateBasketForUser(User.Identity.Name); + } + else + { + GetOrSetBasketCookieAndUserName(); + BasketModel = await _basketViewModelService.GetOrCreateBasketForUser(_username); + } + } + + private void GetOrSetBasketCookieAndUserName() + { + if (Request.Cookies.ContainsKey(Constants.BASKET_COOKIENAME)) + { + _username = Request.Cookies[Constants.BASKET_COOKIENAME]; + } + if (_username != null) return; + + _username = Guid.NewGuid().ToString(); + var cookieOptions = new CookieOptions(); + cookieOptions.Expires = DateTime.Today.AddYears(10); + Response.Cookies.Append(Constants.BASKET_COOKIENAME, _username, cookieOptions); + } + } +} diff --git a/src/Web/Views/Basket/Index.cshtml b/src/Web/Pages/Basket/Index.cshtml similarity index 87% rename from src/Web/Views/Basket/Index.cshtml rename to src/Web/Pages/Basket/Index.cshtml index 1cc318d..c1dc5f4 100644 --- a/src/Web/Views/Basket/Index.cshtml +++ b/src/Web/Pages/Basket/Index.cshtml @@ -1,4 +1,5 @@ -@model BasketViewModel +@page "{handler?}" +@model IndexModel @{ ViewData["Title"] = "Basket"; } @@ -10,7 +11,7 @@
- @if (Model.Items.Any()) + @if (Model.BasketModel.Items.Any()) {
@@ -22,9 +23,9 @@
Cost
- @for (int i = 0; i < Model.Items.Count; i++) + @for (int i = 0; i < Model.BasketModel.Items.Count; i++) { - var item = Model.Items[i]; + var item = Model.BasketModel.Items[i];
@@ -42,6 +43,10 @@
+ @*
+ @item.ProductId +
*@ + }
@@ -52,7 +57,7 @@
-
$ @Model.Total().ToString("N2")
+
$ @Model.BasketModel.Total().ToString("N2")
@@ -65,10 +70,10 @@
-
diff --git a/src/Web/Pages/Basket/Index.cshtml.cs b/src/Web/Pages/Basket/Index.cshtml.cs new file mode 100644 index 0000000..a31fcde --- /dev/null +++ b/src/Web/Pages/Basket/Index.cshtml.cs @@ -0,0 +1,92 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.eShopWeb.ApplicationCore.Interfaces; +using Microsoft.eShopWeb.Infrastructure.Identity; +using Microsoft.eShopWeb.Web.Interfaces; +using Microsoft.eShopWeb.Web.ViewModels; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Microsoft.eShopWeb.Web.Pages.Basket +{ + public class IndexModel : PageModel + { + private readonly IBasketService _basketService; + private const string _basketSessionKey = "basketId"; + private readonly IUriComposer _uriComposer; + private readonly SignInManager _signInManager; + private string _username = null; + private readonly IBasketViewModelService _basketViewModelService; + + public IndexModel(IBasketService basketService, + IBasketViewModelService basketViewModelService, + IUriComposer uriComposer, + SignInManager signInManager) + { + _basketService = basketService; + _uriComposer = uriComposer; + _signInManager = signInManager; + _basketViewModelService = basketViewModelService; + } + + public BasketViewModel BasketModel { get; set; } = new BasketViewModel(); + + public async Task OnGet() + { + await SetBasketModelAsync(); + } + + public async Task OnPost(CatalogItemViewModel productDetails) + { + if (productDetails?.Id == null) + { + return RedirectToPage("/Index"); + } + await SetBasketModelAsync(); + + await _basketService.AddItemToBasket(BasketModel.Id, productDetails.Id, productDetails.Price, 1); + + await SetBasketModelAsync(); + + return RedirectToPage(); + } + + public async Task OnPostUpdate(Dictionary items) + { + await SetBasketModelAsync(); + await _basketService.SetQuantities(BasketModel.Id, items); + + await SetBasketModelAsync(); + } + + private async Task SetBasketModelAsync() + { + if (_signInManager.IsSignedIn(HttpContext.User)) + { + BasketModel = await _basketViewModelService.GetOrCreateBasketForUser(User.Identity.Name); + } + else + { + GetOrSetBasketCookieAndUserName(); + BasketModel = await _basketViewModelService.GetOrCreateBasketForUser(_username); + } + } + + private void GetOrSetBasketCookieAndUserName() + { + if (Request.Cookies.ContainsKey(Constants.BASKET_COOKIENAME)) + { + _username = Request.Cookies[Constants.BASKET_COOKIENAME]; + } + if (_username != null) return; + + _username = Guid.NewGuid().ToString(); + var cookieOptions = new CookieOptions { IsEssential = true }; + cookieOptions.Expires = DateTime.Today.AddYears(10); + Response.Cookies.Append(Constants.BASKET_COOKIENAME, _username, cookieOptions); + } + } +} diff --git a/src/Web/Pages/Error.cshtml b/src/Web/Pages/Error.cshtml new file mode 100644 index 0000000..6f92b95 --- /dev/null +++ b/src/Web/Pages/Error.cshtml @@ -0,0 +1,26 @@ +@page +@model ErrorModel +@{ + ViewData["Title"] = "Error"; +} + +

Error.

+

An error occurred while processing your request.

+ +@if (Model.ShowRequestId) +{ +

+ Request ID: @Model.RequestId +

+} + +

Development Mode

+

+ Swapping to the Development environment displays detailed information about the error that occurred. +

+

+ The Development environment shouldn't be enabled for deployed applications. + It can result in displaying sensitive information from exceptions to end users. + For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development + and restarting the app. +

diff --git a/src/Web/Pages/Error.cshtml.cs b/src/Web/Pages/Error.cshtml.cs new file mode 100644 index 0000000..5ec6f2e --- /dev/null +++ b/src/Web/Pages/Error.cshtml.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using System.Diagnostics; + +namespace Microsoft.eShopWeb.Web.Pages +{ + [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] + public class ErrorModel : PageModel + { + public string RequestId { get; set; } + + public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + + public void OnGet() + { + RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; + } + } +} diff --git a/src/Web/Views/Catalog/Index.cshtml b/src/Web/Pages/Index.cshtml similarity index 56% rename from src/Web/Views/Catalog/Index.cshtml rename to src/Web/Pages/Index.cshtml index 4ebe225..2c3e9fb 100644 --- a/src/Web/Views/Catalog/Index.cshtml +++ b/src/Web/Pages/Index.cshtml @@ -1,43 +1,40 @@ -@{ +@page +@{ ViewData["Title"] = "Catalog"; - @model CatalogIndexViewModel + @model IndexModel }
-
- +
-
- - @if (Model.CatalogItems.Any()) + @if (Model.CatalogModel.CatalogItems.Any()) { - +
- @foreach (var catalogItem in Model.CatalogItems) + @foreach (var catalogItem in Model.CatalogModel.CatalogItems) {
- +
}
- - + } else { diff --git a/src/Web/Pages/Index.cshtml.cs b/src/Web/Pages/Index.cshtml.cs new file mode 100644 index 0000000..7e32c30 --- /dev/null +++ b/src/Web/Pages/Index.cshtml.cs @@ -0,0 +1,26 @@ +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.eShopWeb.Web.Services; +using Microsoft.eShopWeb.Web.ViewModels; +using System.Threading.Tasks; + +namespace Microsoft.eShopWeb.Web.Pages +{ + public class IndexModel : PageModel + { + private readonly ICatalogService _catalogService; + + public IndexModel(ICatalogService catalogService) + { + _catalogService = catalogService; + } + + public CatalogIndexViewModel CatalogModel { get; set; } = new CatalogIndexViewModel(); + + public async Task OnGet(CatalogIndexViewModel catalogModel, int? pageId) + { + CatalogModel = await _catalogService.GetCatalogItems(pageId ?? 0, Constants.ITEMS_PER_PAGE, catalogModel.BrandFilterApplied, catalogModel.TypesFilterApplied); + } + + + } +} diff --git a/src/Web/Views/Home/Privacy.cshtml b/src/Web/Pages/Privacy.cshtml similarity index 80% rename from src/Web/Views/Home/Privacy.cshtml rename to src/Web/Pages/Privacy.cshtml index af4fb19..46ba966 100644 --- a/src/Web/Views/Home/Privacy.cshtml +++ b/src/Web/Pages/Privacy.cshtml @@ -1,4 +1,6 @@ -@{ +@page +@model PrivacyModel +@{ ViewData["Title"] = "Privacy Policy"; }

@ViewData["Title"]

diff --git a/src/Web/Pages/Privacy.cshtml.cs b/src/Web/Pages/Privacy.cshtml.cs new file mode 100644 index 0000000..b3f4e58 --- /dev/null +++ b/src/Web/Pages/Privacy.cshtml.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace Microsoft.eShopWeb.Web.Pages +{ + public class PrivacyModel : PageModel + { + public void OnGet() + { + } + } +} diff --git a/src/Web/ViewComponents/Basket.cs b/src/Web/Pages/Shared/Components/BasketComponent/Basket.cs similarity index 88% rename from src/Web/ViewComponents/Basket.cs rename to src/Web/Pages/Shared/Components/BasketComponent/Basket.cs index 4d870f1..f1155dd 100644 --- a/src/Web/ViewComponents/Basket.cs +++ b/src/Web/Pages/Shared/Components/BasketComponent/Basket.cs @@ -1,12 +1,13 @@ -using Microsoft.eShopWeb.Infrastructure.Identity; -using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; +using Microsoft.eShopWeb.Infrastructure.Identity; using Microsoft.eShopWeb.Web.Interfaces; +using Microsoft.eShopWeb.Web.Pages.Basket; using Microsoft.eShopWeb.Web.ViewModels; using System.Linq; using System.Threading.Tasks; -namespace Microsoft.eShopWeb.Web.ViewComponents +namespace Microsoft.eShopWeb.Web.Pages.Shared.Components.BasketComponent { public class Basket : ViewComponent { diff --git a/src/Web/Pages/Shared/Components/BasketComponent/Default.cshtml b/src/Web/Pages/Shared/Components/BasketComponent/Default.cshtml new file mode 100644 index 0000000..b2a53f6 --- /dev/null +++ b/src/Web/Pages/Shared/Components/BasketComponent/Default.cshtml @@ -0,0 +1,13 @@ +@model BasketComponentViewModel +@{ + ViewData["Title"] = "My Basket"; +} + +
+ +
+
+ @Model.ItemsCount +
+
diff --git a/src/Web/Views/Catalog/_pagination.cshtml b/src/Web/Pages/Shared/_pagination.cshtml similarity index 78% rename from src/Web/Views/Catalog/_pagination.cshtml rename to src/Web/Pages/Shared/_pagination.cshtml index 6ba9f4f..ab5ecee 100644 --- a/src/Web/Views/Catalog/_pagination.cshtml +++ b/src/Web/Pages/Shared/_pagination.cshtml @@ -7,9 +7,7 @@
@@ -24,9 +22,7 @@
diff --git a/src/Web/Views/Catalog/_product.cshtml b/src/Web/Pages/Shared/_product.cshtml similarity index 59% rename from src/Web/Views/Catalog/_product.cshtml rename to src/Web/Pages/Shared/_product.cshtml index 2c1fcdb..d27d2e4 100644 --- a/src/Web/Views/Catalog/_product.cshtml +++ b/src/Web/Pages/Shared/_product.cshtml @@ -1,22 +1,14 @@ @model CatalogItemViewModel - -
- + -
@Model.Name
@Model.Price.ToString("N2")
- @* - - - - *@ diff --git a/src/Web/Pages/_ViewImports.cshtml b/src/Web/Pages/_ViewImports.cshtml new file mode 100644 index 0000000..2bf31ee --- /dev/null +++ b/src/Web/Pages/_ViewImports.cshtml @@ -0,0 +1,9 @@ +@using Microsoft.eShopWeb.Web +@using Microsoft.eShopWeb.Web.ViewModels +@using Microsoft.eShopWeb.Web.ViewModels.Account +@using Microsoft.eShopWeb.Web.ViewModels.Manage +@using Microsoft.eShopWeb.Web.Pages +@using Microsoft.AspNetCore.Identity +@using Microsoft.eShopWeb.Infrastructure.Identity +@namespace Microsoft.eShopWeb.Web.Pages +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/src/Web/Pages/_ViewStart.cshtml b/src/Web/Pages/_ViewStart.cshtml new file mode 100644 index 0000000..a5f1004 --- /dev/null +++ b/src/Web/Pages/_ViewStart.cshtml @@ -0,0 +1,3 @@ +@{ + Layout = "_Layout"; +} diff --git a/src/Web/Properties/launchSettings.json b/src/Web/Properties/launchSettings.json index 652d021..5a578c5 100644 --- a/src/Web/Properties/launchSettings.json +++ b/src/Web/Properties/launchSettings.json @@ -1,4 +1,4 @@ -{ +{ "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, @@ -15,12 +15,12 @@ "ASPNETCORE_ENVIRONMENT": "Development" } }, - "Web": { + "Web - PROD": { "commandName": "Project", "launchBrowser": true, "applicationUrl": "https://localhost:5001;http://localhost:5000", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" + "ASPNETCORE_ENVIRONMENT": "Production" } } } diff --git a/src/Web/Services/BasketViewModelService.cs b/src/Web/Services/BasketViewModelService.cs index 7aa9b9a..11e9612 100644 --- a/src/Web/Services/BasketViewModelService.cs +++ b/src/Web/Services/BasketViewModelService.cs @@ -1,9 +1,9 @@ -using Microsoft.eShopWeb.ApplicationCore.Interfaces; -using Microsoft.eShopWeb.ApplicationCore.Specifications; -using Microsoft.eShopWeb.ApplicationCore.Entities; +using Microsoft.eShopWeb.ApplicationCore.Entities; using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; +using Microsoft.eShopWeb.ApplicationCore.Interfaces; +using Microsoft.eShopWeb.ApplicationCore.Specifications; using Microsoft.eShopWeb.Web.Interfaces; -using Microsoft.eShopWeb.Web.ViewModels; +using Microsoft.eShopWeb.Web.Pages.Basket; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -30,7 +30,7 @@ namespace Microsoft.eShopWeb.Web.Services var basketSpec = new BasketWithItemsSpecification(userName); var basket = (await _basketRepository.ListAsync(basketSpec)).FirstOrDefault(); - if(basket == null) + if (basket == null) { return await CreateBasketForUser(userName); } diff --git a/src/Web/Services/CatalogService.cs b/src/Web/Services/CatalogService.cs index fbbd323..ad7fbeb 100644 --- a/src/Web/Services/CatalogService.cs +++ b/src/Web/Services/CatalogService.cs @@ -1,13 +1,13 @@ -using System.Collections.Generic; +using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.eShopWeb.ApplicationCore.Entities; +using Microsoft.eShopWeb.ApplicationCore.Interfaces; +using Microsoft.eShopWeb.ApplicationCore.Specifications; +using Microsoft.eShopWeb.Web.ViewModels; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc.Rendering; -using Microsoft.eShopWeb.Web.ViewModels; -using Microsoft.eShopWeb.ApplicationCore.Entities; -using Microsoft.Extensions.Logging; -using Microsoft.eShopWeb.ApplicationCore.Interfaces; -using System; -using Microsoft.eShopWeb.ApplicationCore.Specifications; namespace Microsoft.eShopWeb.Web.Services { diff --git a/src/Web/Startup.cs b/src/Web/Startup.cs index e66d563..cea6f26 100644 --- a/src/Web/Startup.cs +++ b/src/Web/Startup.cs @@ -118,7 +118,13 @@ namespace Microsoft.eShopWeb.Web options.Conventions.Add(new RouteTokenTransformerConvention( new SlugifyParameterTransformer())); } - ).SetCompatibilityVersion(CompatibilityVersion.Version_2_2); + ) + .AddRazorPagesOptions(options => + { + options.Conventions.AuthorizePage("/Basket/Checkout"); + }) + .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); + services.AddHttpContextAccessor(); services.AddSwaggerGen(c => { @@ -184,7 +190,7 @@ namespace Microsoft.eShopWeb.Web } else { - app.UseExceptionHandler("/Home/Error"); + app.UseExceptionHandler("/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } diff --git a/src/Web/Views/Home/Index.cshtml b/src/Web/Views/Home/Index.cshtml deleted file mode 100644 index d2d19bd..0000000 --- a/src/Web/Views/Home/Index.cshtml +++ /dev/null @@ -1,8 +0,0 @@ -@{ - ViewData["Title"] = "Home Page"; -} - -
-

Welcome

-

Learn about building Web apps with ASP.NET Core.

-
diff --git a/src/Web/Views/Order/Detail.cshtml b/src/Web/Views/Order/Detail.cshtml index 788766b..3977ecd 100644 --- a/src/Web/Views/Order/Detail.cshtml +++ b/src/Web/Views/Order/Detail.cshtml @@ -25,14 +25,14 @@
@*
-
-
Description
-
+
+
Description
+
-
-
@Model.Description
-
-
*@ +
+
@Model.Description
+
+ *@
@@ -80,7 +80,7 @@
-
$ @Model.Total
+
$ @Model.Total.ToString("N2")
diff --git a/src/Web/Views/Shared/_Layout.cshtml b/src/Web/Views/Shared/_Layout.cshtml index d3730f0..c6408ee 100644 --- a/src/Web/Views/Shared/_Layout.cshtml +++ b/src/Web/Views/Shared/_Layout.cshtml @@ -1,77 +1,66 @@  - - - @ViewData["Title"] - Microsoft.eShopOnWeb - - - - - - - - - + + + @ViewData["Title"] - Microsoft.eShopOnWeb + + + + + + + + - + - + @RenderBody() +
+
+
+
+
+ +
+
+
+
+ + + + + + + + + + + @RenderSection("scripts", required: false) diff --git a/src/Web/Views/_ViewImports.cshtml b/src/Web/Views/_ViewImports.cshtml index fa5c648..2bf31ee 100644 --- a/src/Web/Views/_ViewImports.cshtml +++ b/src/Web/Views/_ViewImports.cshtml @@ -2,6 +2,8 @@ @using Microsoft.eShopWeb.Web.ViewModels @using Microsoft.eShopWeb.Web.ViewModels.Account @using Microsoft.eShopWeb.Web.ViewModels.Manage +@using Microsoft.eShopWeb.Web.Pages @using Microsoft.AspNetCore.Identity @using Microsoft.eShopWeb.Infrastructure.Identity -@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers \ No newline at end of file +@namespace Microsoft.eShopWeb.Web.Pages +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/src/Web/Web.csproj b/src/Web/Web.csproj index 27899b3..9e2848c 100644 --- a/src/Web/Web.csproj +++ b/src/Web/Web.csproj @@ -14,7 +14,6 @@ - @@ -66,11 +65,6 @@ <_ContentIncludedByDefault Remove="Views\Account\LoginWith2fa.cshtml" /> <_ContentIncludedByDefault Remove="Views\Account\Register.cshtml" /> <_ContentIncludedByDefault Remove="Views\Account\Signin.cshtml" /> - <_ContentIncludedByDefault Remove="Views\Basket\Checkout.cshtml" /> - <_ContentIncludedByDefault Remove="Views\Basket\Index.cshtml" /> - <_ContentIncludedByDefault Remove="Views\Catalog\Index.cshtml" /> - <_ContentIncludedByDefault Remove="Views\Catalog\_pagination.cshtml" /> - <_ContentIncludedByDefault Remove="Views\Catalog\_product.cshtml" /> <_ContentIncludedByDefault Remove="Views\Manage\ChangePassword.cshtml" /> <_ContentIncludedByDefault Remove="Views\Manage\Disable2fa.cshtml" /> <_ContentIncludedByDefault Remove="Views\Manage\EnableAuthenticator.cshtml" /> @@ -95,21 +89,6 @@ - - - - - - - - - - - - - - - diff --git a/src/WebRazorPages/Services/CatalogService.cs b/src/WebRazorPages/Services/CatalogService.cs index 8f4d968..613d5c3 100644 --- a/src/WebRazorPages/Services/CatalogService.cs +++ b/src/WebRazorPages/Services/CatalogService.cs @@ -1,7 +1,7 @@ -using Microsoft.eShopWeb.ApplicationCore.Interfaces; -using Microsoft.eShopWeb.ApplicationCore.Specifications; -using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.eShopWeb.ApplicationCore.Entities; +using Microsoft.eShopWeb.ApplicationCore.Interfaces; +using Microsoft.eShopWeb.ApplicationCore.Specifications; using Microsoft.eShopWeb.RazorPages.Interfaces; using Microsoft.eShopWeb.RazorPages.ViewModels; using Microsoft.Extensions.Logging; diff --git a/tests/FunctionalTests/FunctionalTests.csproj b/tests/FunctionalTests/FunctionalTests.csproj index 056258c..21b873e 100644 --- a/tests/FunctionalTests/FunctionalTests.csproj +++ b/tests/FunctionalTests/FunctionalTests.csproj @@ -22,11 +22,14 @@ - + + + + diff --git a/tests/FunctionalTests/Web/Controllers/OrderControllerIndex.cs b/tests/FunctionalTests/Web/Controllers/OrderControllerIndex.cs index 8f6e085..5d0da19 100644 --- a/tests/FunctionalTests/Web/Controllers/OrderControllerIndex.cs +++ b/tests/FunctionalTests/Web/Controllers/OrderControllerIndex.cs @@ -22,7 +22,7 @@ namespace Microsoft.eShopWeb.FunctionalTests.Web.Controllers [Fact] public async Task ReturnsRedirectGivenAnonymousUser() { - var response = await Client.GetAsync("/Order/Index"); + var response = await Client.GetAsync("/order/my-orders"); var redirectLocation = response.Headers.Location.OriginalString; Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); diff --git a/tests/FunctionalTests/Web/Controllers/CustomWebApplicationFactory.cs b/tests/FunctionalTests/Web/CustomWebApplicationFactory.cs similarity index 100% rename from tests/FunctionalTests/Web/Controllers/CustomWebApplicationFactory.cs rename to tests/FunctionalTests/Web/CustomWebApplicationFactory.cs diff --git a/tests/FunctionalTests/WebRazorPages/HomePageOnGet.cs b/tests/FunctionalTests/Web/Pages/HomePageOnGet.cs similarity index 72% rename from tests/FunctionalTests/WebRazorPages/HomePageOnGet.cs rename to tests/FunctionalTests/Web/Pages/HomePageOnGet.cs index 323ce90..1a795e1 100644 --- a/tests/FunctionalTests/WebRazorPages/HomePageOnGet.cs +++ b/tests/FunctionalTests/Web/Pages/HomePageOnGet.cs @@ -1,13 +1,14 @@ -using Microsoft.eShopWeb.RazorPages; +using Microsoft.eShopWeb.FunctionalTests.Web.Controllers; +using Microsoft.eShopWeb.Web; using System.Net.Http; using System.Threading.Tasks; using Xunit; namespace Microsoft.eShopWeb.FunctionalTests.WebRazorPages { - public class HomePageOnGet : IClassFixture> + public class HomePageOnGet : IClassFixture> { - public HomePageOnGet(CustomWebRazorPagesApplicationFactory factory) + public HomePageOnGet(CustomWebApplicationFactory factory) { Client = factory.CreateClient(); } diff --git a/tests/FunctionalTests/WebRazorPages/CustomWebRazorPagesApplicationFactory.cs b/tests/FunctionalTests/WebRazorPages/CustomWebRazorPagesApplicationFactory.cs deleted file mode 100644 index 9f0126d..0000000 --- a/tests/FunctionalTests/WebRazorPages/CustomWebRazorPagesApplicationFactory.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.EntityFrameworkCore; -using Microsoft.eShopWeb.Infrastructure.Data; -using Microsoft.eShopWeb.Infrastructure.Identity; -using Microsoft.eShopWeb.RazorPages; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using System; - -namespace Microsoft.eShopWeb.FunctionalTests.WebRazorPages -{ - public class CustomWebRazorPagesApplicationFactory - : WebApplicationFactory - { - protected override void ConfigureWebHost(IWebHostBuilder builder) - { - builder.ConfigureServices(services => - { - // Create a new service provider. - var serviceProvider = new ServiceCollection() - .AddEntityFrameworkInMemoryDatabase() - .BuildServiceProvider(); - - // Add a database context (ApplicationDbContext) using an in-memory - // database for testing. - services.AddDbContext(options => - { - options.UseInMemoryDatabase("InMemoryDbForTesting"); - options.UseInternalServiceProvider(serviceProvider); - }); - - services.AddDbContext(options => - { - options.UseInMemoryDatabase("Identity"); - options.UseInternalServiceProvider(serviceProvider); - }); - - // Build the service provider. - var sp = services.BuildServiceProvider(); - - // Create a scope to obtain a reference to the database - // context (ApplicationDbContext). - using (var scope = sp.CreateScope()) - { - var scopedServices = scope.ServiceProvider; - var db = scopedServices.GetRequiredService(); - var loggerFactory = scopedServices.GetRequiredService(); - - var logger = scopedServices - .GetRequiredService>>(); - - // Ensure the database is created. - db.Database.EnsureCreated(); - - try - { - // Seed the database with test data. - CatalogContextSeed.SeedAsync(db, loggerFactory).Wait(); - } - catch (Exception ex) - { - logger.LogError(ex, $"An error occurred seeding the " + - "database with test messages. Error: {ex.Message}"); - } - } - }); - } - } -} diff --git a/tests/FunctionalTests/WebRazorPages/OrderIndexOnGet.cs b/tests/FunctionalTests/WebRazorPages/OrderIndexOnGet.cs deleted file mode 100644 index 4f1d41f..0000000 --- a/tests/FunctionalTests/WebRazorPages/OrderIndexOnGet.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.eShopWeb.RazorPages; -using System.Net; -using System.Net.Http; -using System.Threading.Tasks; -using Xunit; - -namespace Microsoft.eShopWeb.FunctionalTests.WebRazorPages -{ - public class OrderIndexOnGet : IClassFixture> - { - public OrderIndexOnGet(CustomWebRazorPagesApplicationFactory factory) - { - Client = factory.CreateClient(new WebApplicationFactoryClientOptions - { - AllowAutoRedirect = false - }); - } - - public HttpClient Client { get; } - - [Fact] - public async Task ReturnsRedirectGivenAnonymousUser() - { - var response = await Client.GetAsync("/Order/Index"); - var redirectLocation = response.Headers.Location.OriginalString; - - Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); - Assert.Contains("Account/Login", redirectLocation); - } - } -}