Consolidate Web and WebRazorPages Projects (#192)

* Moved Privacy, Home page to Razor Pages

* Migrating Basket from RazorPages to Web.

* Removed BasketController; refactored viewmodels

* Moved BasketComponent into Pages/Shared
Added auth rules to Startup for Pages
Added notes to controllers about Pages usage.

* Fixed broken my orders test
Consolidated Functional Tests

* Fixed logo link to home page
Fixed Order Detail Total $ format
This commit is contained in:
Steve Smith
2019-01-18 13:29:00 -05:00
committed by GitHub
parent 483340f21e
commit 99c416142f
42 changed files with 430 additions and 431 deletions

View File

@@ -24,8 +24,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Web", "src\Web\Web.csproj", "{227CF035-29B0-448D-97E4-944F9EA850E5}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Web", "src\Web\Web.csproj", "{227CF035-29B0-448D-97E4-944F9EA850E5}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebRazorPages", "src\WebRazorPages\WebRazorPages.csproj", "{E2D75FD9-84A8-46B1-97E4-9AC67F919D11}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU 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}.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.ActiveCfg = Release|Any CPU
{227CF035-29B0-448D-97E4-944F9EA850E5}.Release|Any CPU.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -71,7 +65,6 @@ Global
{0F576306-7E2D-49B7-87B1-EB5D94CFD5FC} = {15EA4737-125B-4E6E-A806-E13B7EBCDCCF} {0F576306-7E2D-49B7-87B1-EB5D94CFD5FC} = {15EA4737-125B-4E6E-A806-E13B7EBCDCCF}
{7EFB5482-F942-4C3D-94B0-9B70596E6D0A} = {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} {227CF035-29B0-448D-97E4-944F9EA850E5} = {419A6ACE-0419-4315-A6FB-B0E63D39432E}
{E2D75FD9-84A8-46B1-97E4-9AC67F919D11} = {419A6ACE-0419-4315-A6FB-B0E63D39432E}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {49813262-5DA3-4D61-ABD3-493C74CE8C2B} SolutionGuid = {49813262-5DA3-4D61-ABD3-493C74CE8C2B}

View File

@@ -3,5 +3,7 @@
public static class Constants public static class Constants
{ {
public const string BASKET_COOKIENAME = "eShop"; public const string BASKET_COOKIENAME = "eShop";
public const int ITEMS_PER_PAGE = 10;
public const string DEFAULT_USERNAME = "Guest";
} }
} }

View File

@@ -12,7 +12,7 @@ namespace Microsoft.eShopWeb.Web.Controllers
{ {
[ApiExplorerSettings(IgnoreApi = true)] [ApiExplorerSettings(IgnoreApi = true)]
[Route("[controller]/[action]")] [Route("[controller]/[action]")]
[Authorize] [Authorize] // Controllers that mainly require Authorization still use Controller/View; other pages use Pages
public class AccountController : Controller public class AccountController : Controller
{ {
private readonly UserManager<ApplicationUser> _userManager; private readonly UserManager<ApplicationUser> _userManager;
@@ -150,7 +150,7 @@ namespace Microsoft.eShopWeb.Web.Controllers
{ {
await _signInManager.SignOutAsync(); await _signInManager.SignOutAsync();
return RedirectToAction(nameof(CatalogController.Index), "Catalog"); return RedirectToPage("/Index");
} }
[AllowAnonymous] [AllowAnonymous]
@@ -186,7 +186,7 @@ namespace Microsoft.eShopWeb.Web.Controllers
{ {
if (userId == null || code == null) if (userId == null || code == null)
{ {
return RedirectToAction(nameof(CatalogController.Index), "Catalog"); return RedirectToPage("/Index");
} }
var user = await _userManager.FindByIdAsync(userId); var user = await _userManager.FindByIdAsync(userId);
if (user == null) if (user == null)
@@ -217,7 +217,7 @@ namespace Microsoft.eShopWeb.Web.Controllers
} }
else else
{ {
return RedirectToAction(nameof(CatalogController.Index), "Catalog"); return RedirectToPage("/Index");
} }
} }

View File

@@ -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<ApplicationUser> _signInManager;
private readonly IAppLogger<BasketController> _logger;
private readonly IOrderService _orderService;
private readonly IBasketViewModelService _basketViewModelService;
public BasketController(IBasketService basketService,
IBasketViewModelService basketViewModelService,
IOrderService orderService,
IUriComposer uriComposer,
SignInManager<ApplicationUser> signInManager,
IAppLogger<BasketController> logger)
{
_basketService = basketService;
_uriComposer = uriComposer;
_signInManager = signInManager;
_logger = logger;
_orderService = orderService;
_basketViewModelService = basketViewModelService;
}
[HttpGet]
public async Task<IActionResult> Index()
{
var basketModel = await GetBasketViewModelAsync();
return View(basketModel);
}
[HttpPost]
public async Task<IActionResult> Index(Dictionary<string, int> items)
{
var basketViewModel = await GetBasketViewModelAsync();
await _basketService.SetQuantities(basketViewModel.Id, items);
return View(await GetBasketViewModelAsync());
}
// POST: /Basket/AddToBasket
[HttpPost]
public async Task<IActionResult> 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<IActionResult> Checkout(Dictionary<string, int> 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<BasketViewModel> 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;
}
}
}

View File

@@ -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<IActionResult> 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();
}
}
}

View File

@@ -15,7 +15,7 @@ using System.Threading.Tasks;
namespace Microsoft.eShopWeb.Web.Controllers namespace Microsoft.eShopWeb.Web.Controllers
{ {
[ApiExplorerSettings(IgnoreApi = true)] [ApiExplorerSettings(IgnoreApi = true)]
[Authorize] [Authorize] // Controllers that mainly require Authorization still use Controller/View; other pages use Pages
[Route("[controller]/[action]")] [Route("[controller]/[action]")]
public class ManageController : Controller public class ManageController : Controller
{ {

View File

@@ -9,7 +9,7 @@ using System.Threading.Tasks;
namespace Microsoft.eShopWeb.Web.Controllers namespace Microsoft.eShopWeb.Web.Controllers
{ {
[ApiExplorerSettings(IgnoreApi = true)] [ApiExplorerSettings(IgnoreApi = true)]
[Authorize] [Authorize] // Controllers that mainly require Authorization still use Controller/View; other pages use Pages
[Route("[controller]/[action]")] [Route("[controller]/[action]")]
public class OrderController : Controller public class OrderController : Controller
{ {

View File

@@ -1,4 +1,4 @@
using Microsoft.eShopWeb.Web.ViewModels; using Microsoft.eShopWeb.Web.Pages.Basket;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.eShopWeb.Web.Interfaces namespace Microsoft.eShopWeb.Web.Interfaces

View File

@@ -1,4 +1,4 @@
namespace Microsoft.eShopWeb.Web.ViewModels namespace Microsoft.eShopWeb.Web.Pages.Basket
{ {
public class BasketItemViewModel public class BasketItemViewModel
{ {

View File

@@ -2,7 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace Microsoft.eShopWeb.Web.ViewModels namespace Microsoft.eShopWeb.Web.Pages.Basket
{ {
public class BasketViewModel public class BasketViewModel
{ {

View File

@@ -1,6 +1,7 @@
@{ @page
@model CheckoutModel
@{
ViewData["Title"] = "Checkout Complete"; ViewData["Title"] = "Checkout Complete";
@model BasketViewModel
} }
<section class="esh-catalog-hero"> <section class="esh-catalog-hero">
<div class="container"> <div class="container">
@@ -11,5 +12,5 @@
<div class="container"> <div class="container">
<h1>Thanks for your Order!</h1> <h1>Thanks for your Order!</h1>
<a asp-controller="Catalog" asp-action="Index">Continue Shopping...</a> <a asp-page="/Index">Continue Shopping...</a>
</div> </div>

View File

@@ -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<ApplicationUser> _signInManager;
private readonly IOrderService _orderService;
private string _username = null;
private readonly IBasketViewModelService _basketViewModelService;
public CheckoutModel(IBasketService basketService,
IBasketViewModelService basketViewModelService,
IUriComposer uriComposer,
SignInManager<ApplicationUser> 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<IActionResult> OnPost(Dictionary<string, int> 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);
}
}
}

View File

@@ -1,4 +1,5 @@
@model BasketViewModel @page "{handler?}"
@model IndexModel
@{ @{
ViewData["Title"] = "Basket"; ViewData["Title"] = "Basket";
} }
@@ -10,7 +11,7 @@
<div class="container"> <div class="container">
@if (Model.Items.Any()) @if (Model.BasketModel.Items.Any())
{ {
<form method="post"> <form method="post">
<article class="esh-basket-titles row"> <article class="esh-basket-titles row">
@@ -22,9 +23,9 @@
<section class="esh-basket-title col-xs-2">Cost</section> <section class="esh-basket-title col-xs-2">Cost</section>
</article> </article>
<div class="esh-catalog-items row"> <div class="esh-catalog-items row">
@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];
<article class="esh-basket-items row"> <article class="esh-basket-items row">
<div> <div>
<section class="esh-basket-item esh-basket-item--middle col-lg-3 hidden-lg-down"> <section class="esh-basket-item esh-basket-item--middle col-lg-3 hidden-lg-down">
@@ -42,6 +43,10 @@
</div> </div>
</article> </article>
@*<div class="esh-catalog-item col-md-4">
@item.ProductId
</div>*@
} }
<div class="container"> <div class="container">
@@ -52,7 +57,7 @@
<article class="esh-basket-items row"> <article class="esh-basket-items row">
<section class="esh-basket-item col-xs-10"></section> <section class="esh-basket-item col-xs-10"></section>
<section class="esh-basket-item esh-basket-item--mark col-xs-2">$ @Model.Total().ToString("N2")</section> <section class="esh-basket-item esh-basket-item--mark col-xs-2">$ @Model.BasketModel.Total().ToString("N2")</section>
</article> </article>
<article class="esh-basket-items row"> <article class="esh-basket-items row">
@@ -65,10 +70,10 @@
<section class="esh-basket-item col-xs-push-8 col-xs-4"> <section class="esh-basket-item col-xs-push-8 col-xs-4">
<button class="btn esh-basket-checkout" name="updatebutton" value="" type="submit" <button class="btn esh-basket-checkout" name="updatebutton" value="" type="submit"
asp-action="Index"> asp-page-handler="Update">
[ Update ] [ Update ]
</button> </button>
<input type="submit" asp-action="Checkout" <input type="submit" asp-page="Checkout"
class="btn esh-basket-checkout" class="btn esh-basket-checkout"
value="[ Checkout ]" name="action" /> value="[ Checkout ]" name="action" />
</section> </section>

View File

@@ -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<ApplicationUser> _signInManager;
private string _username = null;
private readonly IBasketViewModelService _basketViewModelService;
public IndexModel(IBasketService basketService,
IBasketViewModelService basketViewModelService,
IUriComposer uriComposer,
SignInManager<ApplicationUser> 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<IActionResult> 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<string, int> 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);
}
}
}

View File

@@ -0,0 +1,26 @@
@page
@model ErrorModel
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>

View File

@@ -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;
}
}
}

View File

@@ -1,43 +1,40 @@
@{ @page
@{
ViewData["Title"] = "Catalog"; ViewData["Title"] = "Catalog";
@model CatalogIndexViewModel @model IndexModel
} }
<section class="esh-catalog-hero"> <section class="esh-catalog-hero">
<div class="container"> <div class="container">
<img class="esh-catalog-title" src="~/images/main_banner_text.png" /> <img class="esh-catalog-title" src="~/images/main_banner_text.png" />
</div> </div>
</section> </section>
<section class="esh-catalog-filters"> <section class="esh-catalog-filters">
<div class="container"> <div class="container">
<form asp-action="Index" asp-controller="Catalog" method="post"> <form method="get">
<label class="esh-catalog-label" data-title="brand"> <label class="esh-catalog-label" data-title="brand">
<select asp-for="@Model.BrandFilterApplied" asp-items="@Model.Brands" class="esh-catalog-filter"></select> <select asp-for="@Model.CatalogModel.BrandFilterApplied" asp-items="@Model.CatalogModel.Brands" class="esh-catalog-filter"></select>
</label> </label>
<label class="esh-catalog-label" data-title="type"> <label class="esh-catalog-label" data-title="type">
<select asp-for="@Model.TypesFilterApplied" asp-items="@Model.Types" class="esh-catalog-filter"></select> <select asp-for="@Model.CatalogModel.TypesFilterApplied" asp-items="@Model.CatalogModel.Types" class="esh-catalog-filter"></select>
</label> </label>
<input class="esh-catalog-send" type="image" src="images/arrow-right.svg" /> <input class="esh-catalog-send" type="image" src="images/arrow-right.svg" />
</form> </form>
</div> </div>
</section> </section>
<div class="container"> <div class="container">
@if (Model.CatalogModel.CatalogItems.Any())
@if (Model.CatalogItems.Any())
{ {
<partial name="_pagination" for="PaginationInfo" /> <partial name="_pagination" for="CatalogModel.PaginationInfo" />
<div class="esh-catalog-items row"> <div class="esh-catalog-items row">
@foreach (var catalogItem in Model.CatalogItems) @foreach (var catalogItem in Model.CatalogModel.CatalogItems)
{ {
<div class="esh-catalog-item col-md-4"> <div class="esh-catalog-item col-md-4">
<partial name="_product" model="catalogItem" /> <partial name="_product" for="@catalogItem" />
</div> </div>
} }
</div> </div>
<partial name="_pagination" for="CatalogModel.PaginationInfo" />
<partial name="_pagination" for="PaginationInfo" />
} }
else else
{ {

View File

@@ -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);
}
}
}

View File

@@ -1,4 +1,6 @@
@{ @page
@model PrivacyModel
@{
ViewData["Title"] = "Privacy Policy"; ViewData["Title"] = "Privacy Policy";
} }
<h1>@ViewData["Title"]</h1> <h1>@ViewData["Title"]</h1>

View File

@@ -0,0 +1,11 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Microsoft.eShopWeb.Web.Pages
{
public class PrivacyModel : PageModel
{
public void OnGet()
{
}
}
}

View File

@@ -1,12 +1,13 @@
using Microsoft.eShopWeb.Infrastructure.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.Web.Interfaces; using Microsoft.eShopWeb.Web.Interfaces;
using Microsoft.eShopWeb.Web.Pages.Basket;
using Microsoft.eShopWeb.Web.ViewModels; using Microsoft.eShopWeb.Web.ViewModels;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.eShopWeb.Web.ViewComponents namespace Microsoft.eShopWeb.Web.Pages.Shared.Components.BasketComponent
{ {
public class Basket : ViewComponent public class Basket : ViewComponent
{ {

View File

@@ -0,0 +1,13 @@
@model BasketComponentViewModel
@{
ViewData["Title"] = "My Basket";
}
<a class="esh-basketstatus "
asp-page="/Basket/Index">
<div class="esh-basketstatus-image">
<img src="~/images/cart.png" />
</div>
<div class="esh-basketstatus-badge">
@Model.ItemsCount
</div>
</a>

View File

@@ -7,9 +7,7 @@
<div class="col-md-2 col-xs-12"> <div class="col-md-2 col-xs-12">
<a class="esh-pager-item-left esh-pager-item--navigable @Model.Previous" <a class="esh-pager-item-left esh-pager-item--navigable @Model.Previous"
id="Previous" id="Previous"
asp-controller="Catalog" asp-route-pageid="@(Model.ActualPage - 1)"
asp-action="Index"
asp-route-page="@(Model.ActualPage - 1)"
aria-label="Previous"> aria-label="Previous">
Previous Previous
</a> </a>
@@ -24,9 +22,7 @@
<div class="col-md-2 col-xs-12"> <div class="col-md-2 col-xs-12">
<a class="esh-pager-item-right esh-pager-item--navigable @Model.Next" <a class="esh-pager-item-right esh-pager-item--navigable @Model.Next"
id="Next" id="Next"
asp-controller="Catalog" asp-route-pageid="@(Model.ActualPage + 1)"
asp-action="Index"
asp-route-page="@(Model.ActualPage + 1)"
aria-label="Next"> aria-label="Next">
Next Next
</a> </a>

View File

@@ -1,22 +1,14 @@
@model CatalogItemViewModel @model CatalogItemViewModel
<form asp-page="/Basket/Index" method="post">
<form asp-controller="Basket" asp-action="AddToBasket">
<img class="esh-catalog-thumbnail" src="@Model.PictureUri" /> <img class="esh-catalog-thumbnail" src="@Model.PictureUri" />
<input class="esh-catalog-button" type="submit" value="[ ADD TO BASKET ]" /> <input class="esh-catalog-button" type="submit" value="[ ADD TO BASKET ]" />
<div class="esh-catalog-name"> <div class="esh-catalog-name">
<span>@Model.Name</span> <span>@Model.Name</span>
</div> </div>
<div class="esh-catalog-price"> <div class="esh-catalog-price">
<span>@Model.Price.ToString("N2")</span> <span>@Model.Price.ToString("N2")</span>
</div> </div>
@*<input type="hidden" asp-for="@Model.CatalogBrand" name="brand" />
<input type="hidden" asp-for="@Model.CatalogBrandId" name="brandId" />
<input type="hidden" asp-for="@Model.CatalogType" name="type" />
<input type="hidden" asp-for="@Model.CatalogTypeId" name="typeId" />
<input type="hidden" asp-for="@Model.Description" name="description" />*@
<input type="hidden" asp-for="@Model.Id" name="id" /> <input type="hidden" asp-for="@Model.Id" name="id" />
<input type="hidden" asp-for="@Model.Name" name="name" /> <input type="hidden" asp-for="@Model.Name" name="name" />
<input type="hidden" asp-for="@Model.PictureUri" name="pictureUri" /> <input type="hidden" asp-for="@Model.PictureUri" name="pictureUri" />

View File

@@ -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

View File

@@ -0,0 +1,3 @@
@{
Layout = "_Layout";
}

View File

@@ -1,4 +1,4 @@
{ {
"iisSettings": { "iisSettings": {
"windowsAuthentication": false, "windowsAuthentication": false,
"anonymousAuthentication": true, "anonymousAuthentication": true,
@@ -15,12 +15,12 @@
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} }
}, },
"Web": { "Web - PROD": {
"commandName": "Project", "commandName": "Project",
"launchBrowser": true, "launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000", "applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Production"
} }
} }
} }

View File

@@ -1,9 +1,9 @@
using Microsoft.eShopWeb.ApplicationCore.Interfaces; using Microsoft.eShopWeb.ApplicationCore.Entities;
using Microsoft.eShopWeb.ApplicationCore.Specifications;
using Microsoft.eShopWeb.ApplicationCore.Entities;
using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate; 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.Interfaces;
using Microsoft.eShopWeb.Web.ViewModels; using Microsoft.eShopWeb.Web.Pages.Basket;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;

View File

@@ -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.Linq;
using System.Threading.Tasks; 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 namespace Microsoft.eShopWeb.Web.Services
{ {

View File

@@ -118,7 +118,13 @@ namespace Microsoft.eShopWeb.Web
options.Conventions.Add(new RouteTokenTransformerConvention( options.Conventions.Add(new RouteTokenTransformerConvention(
new SlugifyParameterTransformer())); new SlugifyParameterTransformer()));
} }
).SetCompatibilityVersion(CompatibilityVersion.Version_2_2); )
.AddRazorPagesOptions(options =>
{
options.Conventions.AuthorizePage("/Basket/Checkout");
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddHttpContextAccessor(); services.AddHttpContextAccessor();
services.AddSwaggerGen(c => services.AddSwaggerGen(c =>
{ {
@@ -184,7 +190,7 @@ namespace Microsoft.eShopWeb.Web
} }
else 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. // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts(); app.UseHsts();
} }

View File

@@ -1,8 +0,0 @@
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

View File

@@ -80,7 +80,7 @@
<article class="esh-orders_detail-items row"> <article class="esh-orders_detail-items row">
<section class="esh-orders_detail-item col-xs-9"></section> <section class="esh-orders_detail-item col-xs-9"></section>
<section class="esh-orders_detail-item esh-orders_detail-item--mark col-xs-2">$ @Model.Total</section> <section class="esh-orders_detail-item esh-orders_detail-item--mark col-xs-2">$ @Model.Total.ToString("N2")</section>
</article> </article>
</section> </section>
</div> </div>

View File

@@ -4,7 +4,6 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Microsoft.eShopOnWeb</title> <title>@ViewData["Title"] - Microsoft.eShopOnWeb</title>
<environment names="Development"> <environment names="Development">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" /> <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/app.css" /> <link rel="stylesheet" href="~/css/app.css" />
@@ -26,9 +25,8 @@
<header class="navbar navbar-light navbar-static-top"> <header class="navbar navbar-light navbar-static-top">
<div class="container"> <div class="container">
<article class="row"> <article class="row">
<section class="col-lg-7 col-md-6 col-xs-12"> <section class="col-lg-7 col-md-6 col-xs-12">
<a asp-area="" asp-controller="Catalog" asp-action="Index" class="navbar-brand"> <a asp-area="" asp-page="/Index" class="navbar-brand">
<img src="~/images/brand.png" alt="eShop On Web" /> <img src="~/images/brand.png" alt="eShop On Web" />
</a> </a>
</section> </section>
@@ -36,25 +34,17 @@
</article> </article>
</div> </div>
</header> </header>
@RenderBody() @RenderBody()
<footer class="esh-app-footer"> <footer class="esh-app-footer">
<div class="container"> <div class="container">
<article class="row"> <article class="row">
<section class="col-sm-6"></section>
<section class="col-sm-6">
</section>
<section class="col-sm-6"> <section class="col-sm-6">
<div class="esh-app-footer-text hidden-xs"> e-ShopOnWeb. All rights reserved </div> <div class="esh-app-footer-text hidden-xs"> e-ShopOnWeb. All rights reserved </div>
</section> </section>
</article> </article>
</div> </div>
</footer> </footer>
<environment names="Development"> <environment names="Development">
<script src="~/lib/jquery/dist/jquery.js"></script> <script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script> <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
@@ -71,7 +61,6 @@
</script> </script>
<script src="~/js/site.min.js" asp-append-version="true"></script> <script src="~/js/site.min.js" asp-append-version="true"></script>
</environment> </environment>
@RenderSection("scripts", required: false) @RenderSection("scripts", required: false)
</body> </body>
</html> </html>

View File

@@ -2,6 +2,8 @@
@using Microsoft.eShopWeb.Web.ViewModels @using Microsoft.eShopWeb.Web.ViewModels
@using Microsoft.eShopWeb.Web.ViewModels.Account @using Microsoft.eShopWeb.Web.ViewModels.Account
@using Microsoft.eShopWeb.Web.ViewModels.Manage @using Microsoft.eShopWeb.Web.ViewModels.Manage
@using Microsoft.eShopWeb.Web.Pages
@using Microsoft.AspNetCore.Identity @using Microsoft.AspNetCore.Identity
@using Microsoft.eShopWeb.Infrastructure.Identity @using Microsoft.eShopWeb.Infrastructure.Identity
@namespace Microsoft.eShopWeb.Web.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

View File

@@ -14,7 +14,6 @@
<PackageReference Include="Swashbuckle.AspNetCore" Version="4.0.1" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="4.0.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Views\Catalog\" />
<Folder Include="wwwroot\fonts\" /> <Folder Include="wwwroot\fonts\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -66,11 +65,6 @@
<_ContentIncludedByDefault Remove="Views\Account\LoginWith2fa.cshtml" /> <_ContentIncludedByDefault Remove="Views\Account\LoginWith2fa.cshtml" />
<_ContentIncludedByDefault Remove="Views\Account\Register.cshtml" /> <_ContentIncludedByDefault Remove="Views\Account\Register.cshtml" />
<_ContentIncludedByDefault Remove="Views\Account\Signin.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\ChangePassword.cshtml" />
<_ContentIncludedByDefault Remove="Views\Manage\Disable2fa.cshtml" /> <_ContentIncludedByDefault Remove="Views\Manage\Disable2fa.cshtml" />
<_ContentIncludedByDefault Remove="Views\Manage\EnableAuthenticator.cshtml" /> <_ContentIncludedByDefault Remove="Views\Manage\EnableAuthenticator.cshtml" />
@@ -95,21 +89,6 @@
<ItemGroup> <ItemGroup>
<UpToDateCheckInput Remove="Views\Account\Signin.cshtml" /> <UpToDateCheckInput Remove="Views\Account\Signin.cshtml" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Basket\Checkout.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Basket\Index.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Catalog\_pagination.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Catalog\_product.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Catalog\Index.cshtml" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<UpToDateCheckInput Remove="Views\Manage\_Layout.cshtml" /> <UpToDateCheckInput Remove="Views\Manage\_Layout.cshtml" />
</ItemGroup> </ItemGroup>

View File

@@ -1,7 +1,7 @@
using Microsoft.eShopWeb.ApplicationCore.Interfaces; using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.eShopWeb.ApplicationCore.Specifications;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.eShopWeb.ApplicationCore.Entities; using Microsoft.eShopWeb.ApplicationCore.Entities;
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
using Microsoft.eShopWeb.ApplicationCore.Specifications;
using Microsoft.eShopWeb.RazorPages.Interfaces; using Microsoft.eShopWeb.RazorPages.Interfaces;
using Microsoft.eShopWeb.RazorPages.ViewModels; using Microsoft.eShopWeb.RazorPages.ViewModels;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;

View File

@@ -22,11 +22,14 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\ApplicationCore\ApplicationCore.csproj" /> <ProjectReference Include="..\..\src\ApplicationCore\ApplicationCore.csproj" />
<ProjectReference Include="..\..\src\Web\Web.csproj" /> <ProjectReference Include="..\..\src\Web\Web.csproj" />
<ProjectReference Include="..\..\src\WebRazorPages\WebRazorPages.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" /> <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="WebRazorPages\" />
</ItemGroup>
</Project> </Project>

View File

@@ -22,7 +22,7 @@ namespace Microsoft.eShopWeb.FunctionalTests.Web.Controllers
[Fact] [Fact]
public async Task ReturnsRedirectGivenAnonymousUser() 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; var redirectLocation = response.Headers.Location.OriginalString;
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);

View File

@@ -1,13 +1,14 @@
using Microsoft.eShopWeb.RazorPages; using Microsoft.eShopWeb.FunctionalTests.Web.Controllers;
using Microsoft.eShopWeb.Web;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Xunit; using Xunit;
namespace Microsoft.eShopWeb.FunctionalTests.WebRazorPages namespace Microsoft.eShopWeb.FunctionalTests.WebRazorPages
{ {
public class HomePageOnGet : IClassFixture<CustomWebRazorPagesApplicationFactory<Startup>> public class HomePageOnGet : IClassFixture<CustomWebApplicationFactory<Startup>>
{ {
public HomePageOnGet(CustomWebRazorPagesApplicationFactory<Startup> factory) public HomePageOnGet(CustomWebApplicationFactory<Startup> factory)
{ {
Client = factory.CreateClient(); Client = factory.CreateClient();
} }

View File

@@ -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<TStartup>
: WebApplicationFactory<Startup>
{
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<CatalogContext>(options =>
{
options.UseInMemoryDatabase("InMemoryDbForTesting");
options.UseInternalServiceProvider(serviceProvider);
});
services.AddDbContext<AppIdentityDbContext>(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<CatalogContext>();
var loggerFactory = scopedServices.GetRequiredService<ILoggerFactory>();
var logger = scopedServices
.GetRequiredService<ILogger<CustomWebRazorPagesApplicationFactory<TStartup>>>();
// 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}");
}
}
});
}
}
}

View File

@@ -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<CustomWebRazorPagesApplicationFactory<Startup>>
{
public OrderIndexOnGet(CustomWebRazorPagesApplicationFactory<Startup> 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);
}
}
}