Upgrade to 2.2 (#171)

* Initial Web2 project working

* Initial WebRazorPages project working

* Adding additional sln files

* Removing old project

* Fixed integration tests

* Getting FunctionalTests working.

* Got Swagger working in Web

* Moved web2 to web
This commit is contained in:
Steve Smith
2018-12-28 10:04:35 -08:00
committed by GitHub
parent eb02750841
commit 6c41a1bab9
54 changed files with 2088 additions and 399 deletions

View File

@@ -7,8 +7,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{419A6ACE-041
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Infrastructure", "src\Infrastructure\Infrastructure.csproj", "{7C461394-ABDC-43CD-A798-71249C58BA67}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Infrastructure", "src\Infrastructure\Infrastructure.csproj", "{7C461394-ABDC-43CD-A798-71249C58BA67}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Web", "src\Web\Web.csproj", "{9CB6566E-E86A-4C07-BB8D-E0B95BCD4BD2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationCore", "src\ApplicationCore\ApplicationCore.csproj", "{7FED7440-2311-4D1E-958B-3E887C585CD2}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationCore", "src\ApplicationCore\ApplicationCore.csproj", "{7FED7440-2311-4D1E-958B-3E887C585CD2}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{15EA4737-125B-4E6E-A806-E13B7EBCDCCF}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{15EA4737-125B-4E6E-A806-E13B7EBCDCCF}"
@@ -19,13 +17,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationTests", "tests\I
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunctionalTests", "tests\FunctionalTests\FunctionalTests.csproj", "{7EFB5482-F942-4C3D-94B0-9B70596E6D0A}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunctionalTests", "tests\FunctionalTests\FunctionalTests.csproj", "{7EFB5482-F942-4C3D-94B0-9B70596E6D0A}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebRazorPages", "src\WebRazorPages\WebRazorPages.csproj", "{3CA62E98-218E-4A74-BF79-1098900BD421}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0BD72BEA-EF42-4B72-8B69-12A39EC76FBA}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0BD72BEA-EF42-4B72-8B69-12A39EC76FBA}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
docker-compose.yml = docker-compose.yml docker-compose.yml = docker-compose.yml
EndProjectSection EndProjectSection
EndProject 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 Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -36,10 +36,6 @@ Global
{7C461394-ABDC-43CD-A798-71249C58BA67}.Debug|Any CPU.Build.0 = Debug|Any CPU {7C461394-ABDC-43CD-A798-71249C58BA67}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C461394-ABDC-43CD-A798-71249C58BA67}.Release|Any CPU.ActiveCfg = Release|Any CPU {7C461394-ABDC-43CD-A798-71249C58BA67}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C461394-ABDC-43CD-A798-71249C58BA67}.Release|Any CPU.Build.0 = Release|Any CPU {7C461394-ABDC-43CD-A798-71249C58BA67}.Release|Any CPU.Build.0 = Release|Any CPU
{9CB6566E-E86A-4C07-BB8D-E0B95BCD4BD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9CB6566E-E86A-4C07-BB8D-E0B95BCD4BD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9CB6566E-E86A-4C07-BB8D-E0B95BCD4BD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9CB6566E-E86A-4C07-BB8D-E0B95BCD4BD2}.Release|Any CPU.Build.0 = Release|Any CPU
{7FED7440-2311-4D1E-958B-3E887C585CD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7FED7440-2311-4D1E-958B-3E887C585CD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7FED7440-2311-4D1E-958B-3E887C585CD2}.Debug|Any CPU.Build.0 = Debug|Any CPU {7FED7440-2311-4D1E-958B-3E887C585CD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7FED7440-2311-4D1E-958B-3E887C585CD2}.Release|Any CPU.ActiveCfg = Release|Any CPU {7FED7440-2311-4D1E-958B-3E887C585CD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -56,22 +52,26 @@ Global
{7EFB5482-F942-4C3D-94B0-9B70596E6D0A}.Debug|Any CPU.Build.0 = Debug|Any CPU {7EFB5482-F942-4C3D-94B0-9B70596E6D0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7EFB5482-F942-4C3D-94B0-9B70596E6D0A}.Release|Any CPU.ActiveCfg = Release|Any CPU {7EFB5482-F942-4C3D-94B0-9B70596E6D0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7EFB5482-F942-4C3D-94B0-9B70596E6D0A}.Release|Any CPU.Build.0 = Release|Any CPU {7EFB5482-F942-4C3D-94B0-9B70596E6D0A}.Release|Any CPU.Build.0 = Release|Any CPU
{3CA62E98-218E-4A74-BF79-1098900BD421}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {227CF035-29B0-448D-97E4-944F9EA850E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3CA62E98-218E-4A74-BF79-1098900BD421}.Debug|Any CPU.Build.0 = Debug|Any CPU {227CF035-29B0-448D-97E4-944F9EA850E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3CA62E98-218E-4A74-BF79-1098900BD421}.Release|Any CPU.ActiveCfg = Release|Any CPU {227CF035-29B0-448D-97E4-944F9EA850E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3CA62E98-218E-4A74-BF79-1098900BD421}.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
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{7C461394-ABDC-43CD-A798-71249C58BA67} = {419A6ACE-0419-4315-A6FB-B0E63D39432E} {7C461394-ABDC-43CD-A798-71249C58BA67} = {419A6ACE-0419-4315-A6FB-B0E63D39432E}
{9CB6566E-E86A-4C07-BB8D-E0B95BCD4BD2} = {419A6ACE-0419-4315-A6FB-B0E63D39432E}
{7FED7440-2311-4D1E-958B-3E887C585CD2} = {419A6ACE-0419-4315-A6FB-B0E63D39432E} {7FED7440-2311-4D1E-958B-3E887C585CD2} = {419A6ACE-0419-4315-A6FB-B0E63D39432E}
{EF6877E6-59CB-43A7-8C2C-E70DD70CC5B6} = {15EA4737-125B-4E6E-A806-E13B7EBCDCCF} {EF6877E6-59CB-43A7-8C2C-E70DD70CC5B6} = {15EA4737-125B-4E6E-A806-E13B7EBCDCCF}
{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}
{3CA62E98-218E-4A74-BF79-1098900BD421} = {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

@@ -0,0 +1,3 @@
@{
Layout = "/Views/Shared/_Layout.cshtml";
}

View File

@@ -1,15 +1,16 @@
using Microsoft.eShopWeb.ApplicationCore.Interfaces; using Microsoft.AspNetCore.Authentication;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.Web.ViewModels.Account; using Microsoft.eShopWeb.Web.ViewModels.Account;
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.eShopWeb.Web.Controllers namespace Microsoft.eShopWeb.Web.Controllers
{ {
[ApiExplorerSettings(IgnoreApi = true)]
[Route("[controller]/[action]")] [Route("[controller]/[action]")]
[Authorize] [Authorize]
public class AccountController : Controller public class AccountController : Controller
@@ -153,6 +154,7 @@ namespace Microsoft.eShopWeb.Web.Controllers
} }
[AllowAnonymous] [AllowAnonymous]
[HttpGet]
public IActionResult Register() public IActionResult Register()
{ {
return View(); return View();

View File

@@ -3,6 +3,7 @@
namespace Microsoft.eShopWeb.Web.Controllers.Api namespace Microsoft.eShopWeb.Web.Controllers.Api
{ {
[Route("api/[controller]/[action]")] [Route("api/[controller]/[action]")]
[ApiController]
public class BaseApiController : Controller public class BaseApiController : Controller
{ } { }
} }

View File

@@ -1,18 +1,19 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization;
using System.Threading.Tasks;
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.eShopWeb.Web.ViewModels;
using Microsoft.AspNetCore.Identity; 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.Infrastructure.Identity;
using Microsoft.eShopWeb.Web.Interfaces;
using Microsoft.eShopWeb.Web.ViewModels;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.eShopWeb.Web.Interfaces;
namespace Microsoft.eShopWeb.Web.Controllers namespace Microsoft.eShopWeb.Web.Controllers
{ {
[ApiExplorerSettings(IgnoreApi = true)]
[Route("[controller]/[action]")] [Route("[controller]/[action]")]
public class BasketController : Controller public class BasketController : Controller
{ {

View File

@@ -1,9 +1,10 @@
using Microsoft.eShopWeb.Web.Services; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc; using Microsoft.eShopWeb.Web.Services;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.eShopWeb.Web.Controllers namespace Microsoft.eShopWeb.Web.Controllers
{ {
[ApiExplorerSettings(IgnoreApi = true)]
[Route("")] [Route("")]
public class CatalogController : Controller public class CatalogController : Controller
{ {

View File

@@ -1,11 +1,11 @@
using Microsoft.eShopWeb.ApplicationCore.Interfaces; using Microsoft.AspNetCore.Authentication;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopWeb.Web.ViewModels.Manage; using Microsoft.eShopWeb.ApplicationCore.Interfaces;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.Web.Services; using Microsoft.eShopWeb.Web.Services;
using Microsoft.eShopWeb.Web.ViewModels.Manage;
using System; using System;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@@ -14,6 +14,7 @@ using System.Threading.Tasks;
namespace Microsoft.eShopWeb.Web.Controllers namespace Microsoft.eShopWeb.Web.Controllers
{ {
[ApiExplorerSettings(IgnoreApi = true)]
[Authorize] [Authorize]
[Route("[controller]/[action]")] [Route("[controller]/[action]")]
public class ManageController : Controller public class ManageController : Controller

View File

@@ -1,23 +1,26 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization;
using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.eShopWeb.Web.ViewModels;
using Microsoft.eShopWeb.ApplicationCore.Interfaces; using Microsoft.eShopWeb.ApplicationCore.Interfaces;
using System.Linq;
using Microsoft.eShopWeb.ApplicationCore.Specifications; using Microsoft.eShopWeb.ApplicationCore.Specifications;
using Microsoft.eShopWeb.Web.ViewModels;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopWeb.Web.Controllers namespace Microsoft.eShopWeb.Web.Controllers
{ {
[ApiExplorerSettings(IgnoreApi = true)]
[Authorize] [Authorize]
[Route("[controller]/[action]")] [Route("[controller]/[action]")]
public class OrderController : Controller public class OrderController : Controller
{ {
private readonly IOrderRepository _orderRepository; private readonly IOrderRepository _orderRepository;
public OrderController(IOrderRepository orderRepository) { public OrderController(IOrderRepository orderRepository)
{
_orderRepository = orderRepository; _orderRepository = orderRepository;
} }
[HttpGet]
public async Task<IActionResult> Index() public async Task<IActionResult> Index()
{ {
var orders = await _orderRepository.ListAsync(new CustomerOrdersWithItemsSpecification(User.Identity.Name)); var orders = await _orderRepository.ListAsync(new CustomerOrdersWithItemsSpecification(User.Identity.Name));

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace Web2.Data
{
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
}

View File

@@ -0,0 +1,236 @@
// <auto-generated />
using System;
using Web2.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Web2.Data.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("00000000000000_CreateIdentitySchema")]
partial class CreateIdentitySchema
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.2.0-preview1")
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Name")
.HasMaxLength(256);
b.Property<string>("NormalizedName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasName("RoleNameIndex")
.HasFilter("[NormalizedName] IS NOT NULL");
b.ToTable("AspNetRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("RoleId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AccessFailedCount");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Email")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed");
b.Property<bool>("LockoutEnabled");
b.Property<DateTimeOffset?>("LockoutEnd");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256);
b.Property<string>("NormalizedUserName")
.HasMaxLength(256);
b.Property<string>("PasswordHash");
b.Property<string>("PhoneNumber");
b.Property<bool>("PhoneNumberConfirmed");
b.Property<string>("SecurityStamp");
b.Property<bool>("TwoFactorEnabled");
b.Property<string>("UserName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasName("UserNameIndex")
.HasFilter("[NormalizedUserName] IS NOT NULL");
b.ToTable("AspNetUsers");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128);
b.Property<string>("ProviderKey")
.HasMaxLength(128);
b.Property<string>("ProviderDisplayName");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("RoleId");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("LoginProvider")
.HasMaxLength(128);
b.Property<string>("Name")
.HasMaxLength(128);
b.Property<string>("Value");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,220 @@
using System;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Web2.Data.Migrations
{
public partial class CreateIdentitySchema : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AspNetRoles",
columns: table => new
{
Id = table.Column<string>(nullable: false),
Name = table.Column<string>(maxLength: 256, nullable: true),
NormalizedName = table.Column<string>(maxLength: 256, nullable: true),
ConcurrencyStamp = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetUsers",
columns: table => new
{
Id = table.Column<string>(nullable: false),
UserName = table.Column<string>(maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(maxLength: 256, nullable: true),
Email = table.Column<string>(maxLength: 256, nullable: true),
NormalizedEmail = table.Column<string>(maxLength: 256, nullable: true),
EmailConfirmed = table.Column<bool>(nullable: false),
PasswordHash = table.Column<string>(nullable: true),
SecurityStamp = table.Column<string>(nullable: true),
ConcurrencyStamp = table.Column<string>(nullable: true),
PhoneNumber = table.Column<string>(nullable: true),
PhoneNumberConfirmed = table.Column<bool>(nullable: false),
TwoFactorEnabled = table.Column<bool>(nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(nullable: true),
LockoutEnabled = table.Column<bool>(nullable: false),
AccessFailedCount = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetRoleClaims",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
RoleId = table.Column<string>(nullable: false),
ClaimType = table.Column<string>(nullable: true),
ClaimValue = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
UserId = table.Column<string>(nullable: false),
ClaimType = table.Column<string>(nullable: true),
ClaimValue = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(maxLength: 128, nullable: false),
ProviderKey = table.Column<string>(maxLength: 128, nullable: false),
ProviderDisplayName = table.Column<string>(nullable: true),
UserId = table.Column<string>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
table.ForeignKey(
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserRoles",
columns: table => new
{
UserId = table.Column<string>(nullable: false),
RoleId = table.Column<string>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserTokens",
columns: table => new
{
UserId = table.Column<string>(nullable: false),
LoginProvider = table.Column<string>(maxLength: 128, nullable: false),
Name = table.Column<string>(maxLength: 128, nullable: false),
Value = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
table.ForeignKey(
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_AspNetRoleClaims_RoleId",
table: "AspNetRoleClaims",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "RoleNameIndex",
table: "AspNetRoles",
column: "NormalizedName",
unique: true,
filter: "[NormalizedName] IS NOT NULL");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserClaims_UserId",
table: "AspNetUserClaims",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserLogins_UserId",
table: "AspNetUserLogins",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserRoles_RoleId",
table: "AspNetUserRoles",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "AspNetUsers",
column: "NormalizedEmail");
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "AspNetUsers",
column: "NormalizedUserName",
unique: true,
filter: "[NormalizedUserName] IS NOT NULL");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AspNetRoleClaims");
migrationBuilder.DropTable(
name: "AspNetUserClaims");
migrationBuilder.DropTable(
name: "AspNetUserLogins");
migrationBuilder.DropTable(
name: "AspNetUserRoles");
migrationBuilder.DropTable(
name: "AspNetUserTokens");
migrationBuilder.DropTable(
name: "AspNetRoles");
migrationBuilder.DropTable(
name: "AspNetUsers");
}
}
}

View File

@@ -0,0 +1,234 @@
// <auto-generated />
using System;
using Web2.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace Web2.Data.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.2.0-preview1")
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Name")
.HasMaxLength(256);
b.Property<string>("NormalizedName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasName("RoleNameIndex")
.HasFilter("[NormalizedName] IS NOT NULL");
b.ToTable("AspNetRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("RoleId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AccessFailedCount");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Email")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed");
b.Property<bool>("LockoutEnabled");
b.Property<DateTimeOffset?>("LockoutEnd");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256);
b.Property<string>("NormalizedUserName")
.HasMaxLength(256);
b.Property<string>("PasswordHash");
b.Property<string>("PhoneNumber");
b.Property<bool>("PhoneNumberConfirmed");
b.Property<string>("SecurityStamp");
b.Property<bool>("TwoFactorEnabled");
b.Property<string>("UserName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasName("UserNameIndex")
.HasFilter("[NormalizedUserName] IS NOT NULL");
b.ToTable("AspNetUsers");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128);
b.Property<string>("ProviderKey")
.HasMaxLength(128);
b.Property<string>("ProviderDisplayName");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("RoleId");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("LoginProvider")
.HasMaxLength(128);
b.Property<string>("Name")
.HasMaxLength(128);
b.Property<string>("Value");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,11 @@
using System;
namespace Web2.Models
{
public class ErrorViewModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
}

View File

@@ -1,11 +1,11 @@
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore;
using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.eShopWeb.Infrastructure.Data;
using System;
using Microsoft.Extensions.Logging;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.eShopWeb.Infrastructure.Data;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
namespace Microsoft.eShopWeb.Web namespace Microsoft.eShopWeb.Web
{ {
@@ -41,7 +41,6 @@ namespace Microsoft.eShopWeb.Web
public static IWebHostBuilder CreateWebHostBuilder(string[] args) => public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args) WebHost.CreateDefaultBuilder(args)
.UseUrls("http://0.0.0.0:5106")
.UseStartup<Startup>(); .UseStartup<Startup>();
} }
} }

View File

@@ -1,10 +1,10 @@
{ {
"iisSettings": { "iisSettings": {
"windowsAuthentication": false, "windowsAuthentication": false,
"anonymousAuthentication": true, "anonymousAuthentication": true,
"iisExpress": { "iisExpress": {
"applicationUrl": "http://localhost:5106/", "applicationUrl": "http://localhost:17469",
"sslPort": 0 "sslPort": 44315
} }
}, },
"profiles": { "profiles": {
@@ -15,13 +15,13 @@
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} }
}, },
"eShopWeb": { "Web": {
"commandName": "Project", "commandName": "Project",
"launchBrowser": true, "launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}, }
"applicationUrl": "http://localhost:5106"
} }
} }
} }

View File

@@ -1,18 +1,21 @@
using Microsoft.eShopWeb.ApplicationCore.Interfaces; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
using Microsoft.eShopWeb.ApplicationCore.Services; using Microsoft.eShopWeb.ApplicationCore.Services;
using Microsoft.eShopWeb.Infrastructure.Data; using Microsoft.eShopWeb.Infrastructure.Data;
using Microsoft.eShopWeb.Infrastructure.Identity; using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.Infrastructure.Logging; using Microsoft.eShopWeb.Infrastructure.Logging;
using Microsoft.eShopWeb.Infrastructure.Services; using Microsoft.eShopWeb.Infrastructure.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.eShopWeb.Web.Interfaces; using Microsoft.eShopWeb.Web.Interfaces;
using Microsoft.eShopWeb.Web.Services; using Microsoft.eShopWeb.Web.Services;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Swashbuckle.AspNetCore.Swagger;
using System; using System;
using System.Text; using System.Text;
@@ -65,23 +68,17 @@ namespace Microsoft.eShopWeb.Web
ConfigureServices(services); ConfigureServices(services);
} }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.AddIdentity<ApplicationUser, IdentityRole>() ConfigureCookieSettings(services);
.AddEntityFrameworkStores<AppIdentityDbContext>()
.AddDefaultTokenProviders();
services.ConfigureApplicationCookie(options => services.AddIdentity<ApplicationUser, IdentityRole>()
{ .AddDefaultUI(UIFramework.Bootstrap4)
options.Cookie.HttpOnly = true; .AddEntityFrameworkStores<AppIdentityDbContext>()
options.ExpireTimeSpan = TimeSpan.FromHours(1); .AddDefaultTokenProviders();
options.LoginPath = "/Account/Signin";
options.LogoutPath = "/Account/Signout";
options.Cookie = new CookieBuilder
{
IsEssential = true // required for auth to work without explicit user consent; adjust to suit your privacy policy
};
});
services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>)); services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
services.AddScoped(typeof(IAsyncRepository<>), typeof(EfRepository<>)); services.AddScoped(typeof(IAsyncRepository<>), typeof(EfRepository<>));
@@ -101,15 +98,37 @@ namespace Microsoft.eShopWeb.Web
// Add memory cache services // Add memory cache services
services.AddMemoryCache(); services.AddMemoryCache();
services.AddMvc() services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
.SetCompatibilityVersion(AspNetCore.Mvc.CompatibilityVersion.Version_2_1); services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });
});
_services = services; // used to debug registered services
}
_services = services; private static void ConfigureCookieSettings(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.ConfigureApplicationCookie(options =>
{
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromHours(1);
options.LoginPath = "/Account/Signin";
options.LogoutPath = "/Account/Signout";
options.Cookie = new CookieBuilder
{
IsEssential = true // required for auth to work without explicit user consent; adjust to suit your privacy policy
};
});
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, public void Configure(IApplicationBuilder app, IHostingEnvironment env)
IHostingEnvironment env)
{ {
if (env.IsDevelopment()) if (env.IsDevelopment())
{ {
@@ -119,15 +138,33 @@ namespace Microsoft.eShopWeb.Web
} }
else else
{ {
app.UseExceptionHandler("/Catalog/Error"); app.UseExceptionHandler("/Home/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(); app.UseHsts();
} }
app.UseHttpsRedirection(); app.UseHttpsRedirection();
app.UseStaticFiles(); app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication(); app.UseAuthentication();
app.UseMvc(); // Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
} }
private void ListAllRegisteredServices(IApplicationBuilder app) private void ListAllRegisteredServices(IApplicationBuilder app)
@@ -151,5 +188,6 @@ namespace Microsoft.eShopWeb.Web
await context.Response.WriteAsync(sb.ToString()); await context.Response.WriteAsync(sb.ToString());
})); }));
} }
} }
} }

View File

@@ -0,0 +1,8 @@
@{
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

@@ -0,0 +1,6 @@
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>

View File

@@ -0,0 +1,25 @@
@using Microsoft.AspNetCore.Http.Features
@{
var consentFeature = Context.Features.Get<ITrackingConsentFeature>();
var showBanner = !consentFeature?.CanTrack ?? false;
var cookieString = consentFeature?.CreateConsentCookie();
}
@if (showBanner)
{
<div id="cookieConsent" class="alert alert-info alert-dismissible fade show" role="alert">
Use this space to summarize your privacy and cookie use policy. <a asp-area="" asp-controller="Home" asp-action="Privacy">Learn More</a>.
<button type="button" class="accept-policy close" data-dismiss="alert" aria-label="Close" data-cookie-string="@cookieString">
<span aria-hidden="true">Accept</span>
</button>
</div>
<script>
(function () {
var button = document.querySelector("#cookieConsent button[data-cookie-string]");
button.addEventListener("click", function (event) {
document.cookie = button.dataset.cookieString;
}, false);
})();
</script>
}

View File

@@ -1,42 +1,164 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework> <TargetFramework>netcoreapp2.2</TargetFramework>
<RootNamespace>Microsoft.eShopWeb.Web</RootNamespace> <RootNamespace>Microsoft.eShopWeb.Web</RootNamespace>
</PropertyGroup> <UserSecretsId>aspnet-Web2-1FA3F72E-E7E3-4360-9E49-1CCCD7FE85F7</UserSecretsId>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dapper" Version="1.50.5" /> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.3" /> <PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.1.2" PrivateAssets="All" /> <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.3" PrivateAssets="All" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="4.0.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Views\Catalog\" /> <Folder Include="Views\Catalog\" />
<Folder Include="wwwroot\fonts\" /> <Folder Include="wwwroot\fonts\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ApplicationCore\ApplicationCore.csproj" /> <ProjectReference Include="..\ApplicationCore\ApplicationCore.csproj" />
<ProjectReference Include="..\Infrastructure\Infrastructure.csproj" /> <ProjectReference Include="..\Infrastructure\Infrastructure.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="wwwroot\images\products\1.png" /> <None Include="wwwroot\images\products\1.png" />
<None Include="wwwroot\images\products\10.png" /> <None Include="wwwroot\images\products\10.png" />
<None Include="wwwroot\images\products\11.png" /> <None Include="wwwroot\images\products\11.png" />
<None Include="wwwroot\images\products\12.png" /> <None Include="wwwroot\images\products\12.png" />
<None Include="wwwroot\images\products\2.png" /> <None Include="wwwroot\images\products\2.png" />
<None Include="wwwroot\images\products\3.png" /> <None Include="wwwroot\images\products\3.png" />
<None Include="wwwroot\images\products\4.png" /> <None Include="wwwroot\images\products\4.png" />
<None Include="wwwroot\images\products\5.png" /> <None Include="wwwroot\images\products\5.png" />
<None Include="wwwroot\images\products\6.png" /> <None Include="wwwroot\images\products\6.png" />
<None Include="wwwroot\images\products\7.png" /> <None Include="wwwroot\images\products\7.png" />
<None Include="wwwroot\images\products\8.png" /> <None Include="wwwroot\images\products\8.png" />
<None Include="wwwroot\images\products\9.png" /> <None Include="wwwroot\images\products\9.png" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Update="appsettings.json"> <Content Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content> </Content>
</ItemGroup> <Content Update="Views\Shared\Error.cshtml">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="Views\Shared\_Layout.cshtml">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="Views\Shared\_LoginPartial.cshtml">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="Views\Shared\_ValidationScriptsPartial.cshtml">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="Views\_ViewImports.cshtml">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="Views\_ViewStart.cshtml">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Account\Lockout.cshtml" />
</ItemGroup>
<ItemGroup>
<_ContentIncludedByDefault Remove="Views\Account\Lockout.cshtml" />
<_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" />
<_ContentIncludedByDefault Remove="Views\Manage\ExternalLogins.cshtml" />
<_ContentIncludedByDefault Remove="Views\Manage\GenerateRecoveryCodes.cshtml" />
<_ContentIncludedByDefault Remove="Views\Manage\Index.cshtml" />
<_ContentIncludedByDefault Remove="Views\Manage\ResetAuthenticator.cshtml" />
<_ContentIncludedByDefault Remove="Views\Manage\SetPassword.cshtml" />
<_ContentIncludedByDefault Remove="Views\Manage\TwoFactorAuthentication.cshtml" />
<_ContentIncludedByDefault Remove="Views\Manage\_Layout.cshtml" />
<_ContentIncludedByDefault Remove="Views\Manage\_ManageNav.cshtml" />
<_ContentIncludedByDefault Remove="Views\Manage\_StatusMessage.cshtml" />
<_ContentIncludedByDefault Remove="Views\Manage\_ViewImports.cshtml" />
<_ContentIncludedByDefault Remove="Views\Order\Detail.cshtml" />
<_ContentIncludedByDefault Remove="Views\Order\Index.cshtml" />
<_ContentIncludedByDefault Remove="Views\Shared\Components\Basket\Default.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Account\LoginWith2fa.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Account\Register.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Account\Signin.cshtml" />
</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>
<UpToDateCheckInput Remove="Views\Manage\_Layout.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Manage\_ManageNav.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Manage\_StatusMessage.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Manage\_ViewImports.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Manage\ChangePassword.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Manage\Disable2fa.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Manage\EnableAuthenticator.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Manage\ExternalLogins.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Manage\GenerateRecoveryCodes.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Manage\Index.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Manage\ResetAuthenticator.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Manage\SetPassword.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Manage\TwoFactorAuthentication.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Order\Detail.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Order\Index.cshtml" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\Shared\Components\Basket\Default.cshtml" />
</ItemGroup>
</Project> </Project>

View File

@@ -1,6 +1,5 @@
{ {
"Logging": { "Logging": {
"IncludeScopes": false,
"LogLevel": { "LogLevel": {
"Default": "Debug", "Default": "Debug",
"System": "Information", "System": "Information",

View File

@@ -10,6 +10,7 @@
"Default": "Warning", "Default": "Warning",
"Microsoft": "Warning", "Microsoft": "Warning",
"System": "Warning" "System": "Warning"
} },
"AllowedHosts": "*"
} }
} }

View File

@@ -1,24 +0,0 @@
// Configure bundling and minification for the project.
// More info at https://go.microsoft.com/fwlink/?LinkId=808241
[
{
"outputFileName": "wwwroot/css/app.min.css",
// An array of relative input file paths. Globbing patterns supported
"inputFiles": [
"wwwroot/css/app.css"
]
},
{
"outputFileName": "wwwroot/js/site.min.js",
"inputFiles": [
"wwwroot/js/site.js"
],
// Optionally specify minification options
"minify": {
"enabled": true,
"renameLocals": true
},
// Optionally generate .map file
"sourceMap": false
}
]

View File

@@ -1,42 +0,0 @@
[
{
"outputFile": "wwwroot/css/orders/orders.component.css",
"inputFile": "wwwroot/css/orders/orders.component.scss"
},
//{
// "outputFile": "wwwroot/css/orders/orders-new/orders-new.component.css",
// "inputFile": "wwwroot/css/orders/orders-new/orders-new.component.scss"
//},
//{
// "outputFile": "wwwroot/css/orders/orders-detail/orders-detail.component.css",
// "inputFile": "wwwroot/css/orders/orders-detail/orders-detail.component.scss"
//},
{
"outputFile": "wwwroot/css/catalog/catalog.component.css",
"inputFile": "wwwroot/css/catalog/catalog.component.scss"
},
{
"outputFile": "wwwroot/css/basket/basket.component.css",
"inputFile": "wwwroot/css/basket/basket.component.scss"
},
{
"outputFile": "wwwroot/css/basket/basket-status/basket-status.component.css",
"inputFile": "wwwroot/css/basket/basket-status/basket-status.component.scss"
},
//{
// "outputFile": "wwwroot/css/shared/components/header/header.css",
// "inputFile": "wwwroot/css/shared/components/header/header.scss"
//},
//{
// "outputFile": "wwwroot/css/shared/components/identity/identity.css",
// "inputFile": "wwwroot/css/shared/components/identity/identity.scss"
//},
//{
// "outputFile": "wwwroot/css/shared/components/pager/pager.css",
// "inputFile": "wwwroot/css/shared/components/pager/pager.scss"
//},
{
"outputFile": "wwwroot/css/app.component.css",
"inputFile": "wwwroot/css/app.component.scss"
}
]

View File

@@ -0,0 +1,3 @@
@{
Layout = "/Pages/Shared/_Layout.cshtml";
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace WebRazorPages.Data
{
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
}

View File

@@ -0,0 +1,236 @@
// <auto-generated />
using System;
using WebRazorPages.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace WebRazorPages.Data.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("00000000000000_CreateIdentitySchema")]
partial class CreateIdentitySchema
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.2.0-preview1")
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Name")
.HasMaxLength(256);
b.Property<string>("NormalizedName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasName("RoleNameIndex")
.HasFilter("[NormalizedName] IS NOT NULL");
b.ToTable("AspNetRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("RoleId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AccessFailedCount");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Email")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed");
b.Property<bool>("LockoutEnabled");
b.Property<DateTimeOffset?>("LockoutEnd");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256);
b.Property<string>("NormalizedUserName")
.HasMaxLength(256);
b.Property<string>("PasswordHash");
b.Property<string>("PhoneNumber");
b.Property<bool>("PhoneNumberConfirmed");
b.Property<string>("SecurityStamp");
b.Property<bool>("TwoFactorEnabled");
b.Property<string>("UserName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasName("UserNameIndex")
.HasFilter("[NormalizedUserName] IS NOT NULL");
b.ToTable("AspNetUsers");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128);
b.Property<string>("ProviderKey")
.HasMaxLength(128);
b.Property<string>("ProviderDisplayName");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("RoleId");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("LoginProvider")
.HasMaxLength(128);
b.Property<string>("Name")
.HasMaxLength(128);
b.Property<string>("Value");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,220 @@
using System;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
namespace WebRazorPages.Data.Migrations
{
public partial class CreateIdentitySchema : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AspNetRoles",
columns: table => new
{
Id = table.Column<string>(nullable: false),
Name = table.Column<string>(maxLength: 256, nullable: true),
NormalizedName = table.Column<string>(maxLength: 256, nullable: true),
ConcurrencyStamp = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetUsers",
columns: table => new
{
Id = table.Column<string>(nullable: false),
UserName = table.Column<string>(maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(maxLength: 256, nullable: true),
Email = table.Column<string>(maxLength: 256, nullable: true),
NormalizedEmail = table.Column<string>(maxLength: 256, nullable: true),
EmailConfirmed = table.Column<bool>(nullable: false),
PasswordHash = table.Column<string>(nullable: true),
SecurityStamp = table.Column<string>(nullable: true),
ConcurrencyStamp = table.Column<string>(nullable: true),
PhoneNumber = table.Column<string>(nullable: true),
PhoneNumberConfirmed = table.Column<bool>(nullable: false),
TwoFactorEnabled = table.Column<bool>(nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(nullable: true),
LockoutEnabled = table.Column<bool>(nullable: false),
AccessFailedCount = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetRoleClaims",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
RoleId = table.Column<string>(nullable: false),
ClaimType = table.Column<string>(nullable: true),
ClaimValue = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
UserId = table.Column<string>(nullable: false),
ClaimType = table.Column<string>(nullable: true),
ClaimValue = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(maxLength: 128, nullable: false),
ProviderKey = table.Column<string>(maxLength: 128, nullable: false),
ProviderDisplayName = table.Column<string>(nullable: true),
UserId = table.Column<string>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
table.ForeignKey(
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserRoles",
columns: table => new
{
UserId = table.Column<string>(nullable: false),
RoleId = table.Column<string>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserTokens",
columns: table => new
{
UserId = table.Column<string>(nullable: false),
LoginProvider = table.Column<string>(maxLength: 128, nullable: false),
Name = table.Column<string>(maxLength: 128, nullable: false),
Value = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
table.ForeignKey(
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_AspNetRoleClaims_RoleId",
table: "AspNetRoleClaims",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "RoleNameIndex",
table: "AspNetRoles",
column: "NormalizedName",
unique: true,
filter: "[NormalizedName] IS NOT NULL");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserClaims_UserId",
table: "AspNetUserClaims",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserLogins_UserId",
table: "AspNetUserLogins",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserRoles_RoleId",
table: "AspNetUserRoles",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "AspNetUsers",
column: "NormalizedEmail");
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "AspNetUsers",
column: "NormalizedUserName",
unique: true,
filter: "[NormalizedUserName] IS NOT NULL");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AspNetRoleClaims");
migrationBuilder.DropTable(
name: "AspNetUserClaims");
migrationBuilder.DropTable(
name: "AspNetUserLogins");
migrationBuilder.DropTable(
name: "AspNetUserRoles");
migrationBuilder.DropTable(
name: "AspNetUserTokens");
migrationBuilder.DropTable(
name: "AspNetRoles");
migrationBuilder.DropTable(
name: "AspNetUsers");
}
}
}

View File

@@ -0,0 +1,234 @@
// <auto-generated />
using System;
using WebRazorPages.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace WebRazorPages.Data.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.2.0-preview1")
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Name")
.HasMaxLength(256);
b.Property<string>("NormalizedName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasName("RoleNameIndex")
.HasFilter("[NormalizedName] IS NOT NULL");
b.ToTable("AspNetRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("RoleId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AccessFailedCount");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Email")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed");
b.Property<bool>("LockoutEnabled");
b.Property<DateTimeOffset?>("LockoutEnd");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256);
b.Property<string>("NormalizedUserName")
.HasMaxLength(256);
b.Property<string>("PasswordHash");
b.Property<string>("PhoneNumber");
b.Property<bool>("PhoneNumberConfirmed");
b.Property<string>("SecurityStamp");
b.Property<bool>("TwoFactorEnabled");
b.Property<string>("UserName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasName("UserNameIndex")
.HasFilter("[NormalizedUserName] IS NOT NULL");
b.ToTable("AspNetUsers");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128);
b.Property<string>("ProviderKey")
.HasMaxLength(128);
b.Property<string>("ProviderDisplayName");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("RoleId");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("LoginProvider")
.HasMaxLength(128);
b.Property<string>("Name")
.HasMaxLength(128);
b.Property<string>("Value");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -1,14 +1,14 @@
using System.Threading.Tasks; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.eShopWeb.RazorPages.ViewModels;
using Microsoft.eShopWeb.RazorPages.Interfaces;
using Microsoft.eShopWeb.ApplicationCore.Interfaces; using Microsoft.eShopWeb.ApplicationCore.Interfaces;
using Microsoft.AspNetCore.Identity;
using Microsoft.eShopWeb.Infrastructure.Identity; using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.RazorPages.Interfaces;
using Microsoft.eShopWeb.RazorPages.ViewModels;
using System; using System;
using Microsoft.AspNetCore.Http;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks;
namespace Microsoft.eShopWeb.RazorPages.Pages.Basket namespace Microsoft.eShopWeb.RazorPages.Pages.Basket
{ {
@@ -54,7 +54,7 @@ namespace Microsoft.eShopWeb.RazorPages.Pages.Basket
return RedirectToPage(); return RedirectToPage();
} }
public async Task OnPostUpdate(Dictionary<string,int> items) public async Task OnPostUpdate(Dictionary<string, int> items)
{ {
await SetBasketModelAsync(); await SetBasketModelAsync();
await _basketService.SetQuantities(BasketModel.Id, items); await _basketService.SetQuantities(BasketModel.Id, items);

View File

@@ -16,8 +16,11 @@
<h3>Development Mode</h3> <h3>Development Mode</h3>
<p> <p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred. Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
</p> </p>
<p> <p>
<strong>Development environment should not be enabled in deployed applications</strong>, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>, and restarting the application. <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> </p>

View File

@@ -1,8 +1,10 @@
using System.Diagnostics; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Diagnostics;
namespace Microsoft.eShopWeb.RazorPages.Pages namespace Microsoft.eShopWeb.RazorPages.Pages
{ {
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class ErrorModel : PageModel public class ErrorModel : PageModel
{ {
public string RequestId { get; set; } public string RequestId { get; set; }

View File

@@ -0,0 +1,8 @@
@page
@model PrivacyModel
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>

View File

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

View File

@@ -0,0 +1,25 @@
@using Microsoft.AspNetCore.Http.Features
@{
var consentFeature = Context.Features.Get<ITrackingConsentFeature>();
var showBanner = !consentFeature?.CanTrack ?? false;
var cookieString = consentFeature?.CreateConsentCookie();
}
@if (showBanner)
{
<div id="cookieConsent" class="alert alert-info alert-dismissible fade show" role="alert">
Use this space to summarize your privacy and cookie use policy. <a asp-page="/Privacy">Learn More</a>.
<button type="button" class="accept-policy close" data-dismiss="alert" aria-label="Close" data-cookie-string="@cookieString">
<span aria-hidden="true">Accept</span>
</button>
</div>
<script>
(function () {
var button = document.querySelector("#cookieConsent button[data-cookie-string]");
button.addEventListener("click", function (event) {
document.cookie = button.dataset.cookieString;
}, false);
})();
</script>
}

View File

@@ -3,16 +3,17 @@
<head> <head>
<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"] - WebRazorPages</title>
<environment include="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" />
</environment> </environment>
<environment names="Staging,Production"> <environment exclude="Development">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.5/css/bootstrap.min.css" <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css" asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" /> asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute"
crossorigin="anonymous"
integrity="sha256-eSi1q2PG6J7g7ib17yAaWMcrr5GrtohYChqibrV7PBE=" />
<link rel="stylesheet" href="~/css/app.min.css" asp-append-version="true" /> <link rel="stylesheet" href="~/css/app.min.css" asp-append-version="true" />
</environment> </environment>
<link rel="stylesheet" href="~/css/app.component.css" /> <link rel="stylesheet" href="~/css/app.component.css" />
@@ -26,7 +27,6 @@
<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-page="/Index" class="navbar-brand"> <a asp-page="/Index" class="navbar-brand">
<img src="../images/brand.png" alt="eShop On Web" /> <img src="../images/brand.png" alt="eShop On Web" />
@@ -36,41 +36,44 @@
</article> </article>
</div> </div>
</header> </header>
<partial name="_CookieConsentPartial" />
@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 include="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.bundle.js"></script>*@
<script src="~/js/site.js" asp-append-version="true"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.bundle.min.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
crossorigin="anonymous"
integrity="sha256-E/V4cWE4qvAeO5MOhjtGtqDzPndRO1LBk8lJ/PR7CA4=">
</script>
</environment> </environment>
<environment names="Staging,Production"> <environment exclude="Development">
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js" <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"
asp-fallback-src="~/lib/jquery/dist/jquery.min.js" asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
asp-fallback-test="window.jQuery"> asp-fallback-test="window.jQuery"
crossorigin="anonymous"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=">
</script> </script>
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/bootstrap.min.js" <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.bundle.min.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js" asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"> asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
crossorigin="anonymous"
integrity="sha256-E/V4cWE4qvAeO5MOhjtGtqDzPndRO1LBk8lJ/PR7CA4=">
</script> </script>
<script src="~/js/site.min.js" asp-append-version="true"></script>
</environment> </environment>
<script src="~/js/site.js" asp-append-version="true"></script>
@RenderSection("scripts", required: false) @RenderSection("Scripts", required: false)
</body> </body>
</html> </html>

View File

@@ -1,61 +1,56 @@
@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager
@if (Context.User.Identity.IsAuthenticated) @if (Context.User.Identity.IsAuthenticated)
{ {
<section class="col-lg-4 col-md-5 col-xs-12"> <section class="col-lg-4 col-md-5 col-xs-12">
<div class="esh-identity"> <div class="esh-identity">
<form asp-controller="Account" asp-action="Logout" method="post" <form asp-controller="Account" asp-action="Logout" method="post"
id="logoutForm" class="navbar-right"> id="logoutForm" class="navbar-right">
<section class="esh-identity-section"> <section class="esh-identity-section">
@*<div class="esh-identity-name">@User.FindFirst(x => x.Type == "preferred_username").Value</div>*@ @*<div class="esh-identity-name">@User.FindFirst(x => x.Type == "preferred_username").Value</div>*@
<img class="esh-identity-image" src="~/images/arrow-down.png"> <img class="esh-identity-image" src="~/images/arrow-down.png">
</section> </section>
<section class="esh-identity-drop">
<a class="esh-identity-item"
asp-page="/Order/Index">
<div class="esh-identity-name esh-identity-name--upper">My orders</div>
<img class="esh-identity-image" src="~/images/my_orders.png">
</a>
<a class="esh-identity-item"
asp-page="/Account/Manage/Index">
<div class="esh-identity-name esh-identity-name--upper">My account</div>
<img class="esh-identity-image" src="~/images/my_orders.png">
</a>
<a class="esh-identity-item"
href="javascript:document.getElementById('logoutForm').submit()">
<div class="esh-identity-name esh-identity-name--upper">Log Out</div>
<img class="esh-identity-image" src="~/images/logout.png">
</a>
</section>
</form>
</div>
</section>
<section class="esh-identity-drop"> <section class="col-lg-1 col-xs-12">
<a class="esh-identity-item" @await Component.InvokeAsync("Basket")
asp-page="/Order/Index"> </section>
<div class="esh-identity-name esh-identity-name--upper">My orders</div>
<img class="esh-identity-image" src="~/images/my_orders.png">
</a>
<a class="esh-identity-item"
asp-page="/Account/Manage/Index">
<div class="esh-identity-name esh-identity-name--upper">My account</div>
<img class="esh-identity-image" src="~/images/my_orders.png">
</a>
<a class="esh-identity-item"
href="javascript:document.getElementById('logoutForm').submit()">
<div class="esh-identity-name esh-identity-name--upper">Log Out</div>
<img class="esh-identity-image" src="~/images/logout.png">
</a>
</section>
</form>
</div>
</section>
<section class="col-lg-1 col-xs-12">
@await Component.InvokeAsync("Basket")
</section>
} }
else else
{ {
<section class="col-lg-1 col-lg-offset-3 col-md-3 col-xs-6"> <section class="col-lg-1 col-lg-offset-3 col-md-3 col-xs-6">
<div class="esh-identity"> <div class="esh-identity">
<section class="esh-identity-section"> <section class="esh-identity-section">
<div class="esh-identity-item"> <div class="esh-identity-item">
<a asp-page="/Account/Signin" class="esh-identity-name esh-identity-name--upper">
Login
</a>
</div>
</section>
</div>
</section>
<a asp-page="/Account/Signin" class="esh-identity-name esh-identity-name--upper"> <section class="col-lg-1 col-xs-12">
Login @await Component.InvokeAsync("Basket")
</a> </section>
</div>
</section>
</div>
</section>
<section class="col-lg-1 col-xs-12">
@await Component.InvokeAsync("Basket")
</section>
} }

View File

@@ -3,16 +3,16 @@
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script> <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
</environment> </environment>
<environment exclude="Development"> <environment exclude="Development">
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.14.0/jquery.validate.min.js" <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js"
asp-fallback-src="~/lib/jquery-validation/dist/jquery.validate.min.js" asp-fallback-src="~/lib/jquery-validation/dist/jquery.validate.min.js"
asp-fallback-test="window.jQuery && window.jQuery.validator" asp-fallback-test="window.jQuery && window.jQuery.validator"
crossorigin="anonymous" crossorigin="anonymous"
integrity="sha384-Fnqn3nxp3506LP/7Y3j/25BlWeA3PXTyT1l78LjECcPaKCV12TsZP7yyMxOe/G/k"> integrity="sha256-F6h55Qw6sweK+t7SiOJX+2bpSAa3b/fnlrVCJvmEj1A=">
</script> </script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js" <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js"
asp-fallback-src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js" asp-fallback-src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive" asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive"
crossorigin="anonymous" crossorigin="anonymous"
integrity="sha384-JrXK+k53HACyavUKOsL+NkmSesD2P+73eDMrbTtTk0h4RmOF8hF8apPlkp26JlyH"> integrity="sha256-9GycpJnliUjJDVDqP0UEu/bsm9U+3dnQUH8+3W10vkY=">
</script> </script>
</environment> </environment>

View File

@@ -1,4 +1,4 @@
@using Microsoft.eShopWeb.RazorPages @using Microsoft.eShopWeb.RazorPages
@using Microsoft.eShopWeb.RazorPages.ViewModels @using Microsoft.eShopWeb.RazorPages.ViewModels
@using Microsoft.AspNetCore.Identity @using Microsoft.AspNetCore.Identity
@using Microsoft.eShopWeb.Infrastructure.Identity @using Microsoft.eShopWeb.Infrastructure.Identity

View File

@@ -1,11 +1,11 @@
using System; using Microsoft.AspNetCore;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.AspNetCore.Identity;
using Microsoft.eShopWeb.Infrastructure.Data; using Microsoft.eShopWeb.Infrastructure.Data;
using Microsoft.eShopWeb.Infrastructure.Identity; using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Logging;
using System;
namespace Microsoft.eShopWeb.RazorPages namespace Microsoft.eShopWeb.RazorPages
{ {
@@ -41,7 +41,6 @@ namespace Microsoft.eShopWeb.RazorPages
public static IWebHostBuilder CreateWebHostBuilder(string[] args) => public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args) WebHost.CreateDefaultBuilder(args)
.UseUrls("http://0.0.0.0:5107")
.UseStartup<Startup>(); .UseStartup<Startup>();
} }
} }

View File

@@ -1,10 +1,10 @@
{ {
"iisSettings": { "iisSettings": {
"windowsAuthentication": false, "windowsAuthentication": false,
"anonymousAuthentication": true, "anonymousAuthentication": true,
"iisExpress": { "iisExpress": {
"applicationUrl": "http://localhost:5107/", "applicationUrl": "http://localhost:17930",
"sslPort": 44305 "sslPort": 44394
} }
}, },
"profiles": { "profiles": {
@@ -18,15 +18,10 @@
"WebRazorPages": { "WebRazorPages": {
"commandName": "Project", "commandName": "Project",
"launchBrowser": true, "launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}, }
"applicationUrl": "http://localhost:5107/"
},
"Docker": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://localhost:{ServicePort}"
} }
} }
} }

View File

@@ -1,14 +1,16 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.eShopWeb.ApplicationCore.Interfaces; using Microsoft.eShopWeb.ApplicationCore.Interfaces;
using Microsoft.eShopWeb.ApplicationCore.Services; using Microsoft.eShopWeb.ApplicationCore.Services;
using Microsoft.eShopWeb.Infrastructure.Data; using Microsoft.eShopWeb.Infrastructure.Data;
using Microsoft.eShopWeb.Infrastructure.Identity; using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.Infrastructure.Logging; using Microsoft.eShopWeb.Infrastructure.Logging;
using Microsoft.eShopWeb.Infrastructure.Services; using Microsoft.eShopWeb.Infrastructure.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.eShopWeb.RazorPages.Interfaces; using Microsoft.eShopWeb.RazorPages.Interfaces;
using Microsoft.eShopWeb.RazorPages.Services; using Microsoft.eShopWeb.RazorPages.Services;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
@@ -74,20 +76,17 @@ namespace Microsoft.eShopWeb.RazorPages
ConfigureServices(services); ConfigureServices(services);
} }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
ConfigureCookieOptions(services);
services.AddIdentity<ApplicationUser, IdentityRole>() services.AddIdentity<ApplicationUser, IdentityRole>()
.AddDefaultUI(UIFramework.Bootstrap4)
.AddEntityFrameworkStores<AppIdentityDbContext>() .AddEntityFrameworkStores<AppIdentityDbContext>()
.AddDefaultTokenProviders(); .AddDefaultTokenProviders();
services.ConfigureApplicationCookie(options =>
{
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromHours(1);
options.LoginPath = "/Account/Signin";
options.LogoutPath = "/Account/Signout";
});
services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>)); services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
services.AddScoped(typeof(IAsyncRepository<>), typeof(EfRepository<>)); services.AddScoped(typeof(IAsyncRepository<>), typeof(EfRepository<>));
@@ -106,8 +105,9 @@ namespace Microsoft.eShopWeb.RazorPages
// Add memory cache services // Add memory cache services
services.AddMemoryCache(); services.AddMemoryCache();
services.AddMvc() services.AddMvc()
.SetCompatibilityVersion(AspNetCore.Mvc.CompatibilityVersion.Version_2_1) .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddRazorPagesOptions(options => .AddRazorPagesOptions(options =>
{ {
options.Conventions.AuthorizeFolder("/Order"); options.Conventions.AuthorizeFolder("/Order");
@@ -117,9 +117,25 @@ namespace Microsoft.eShopWeb.RazorPages
_services = services; _services = services;
} }
private static void ConfigureCookieOptions(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.ConfigureApplicationCookie(options =>
{
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromHours(1);
options.LoginPath = "/Account/Signin";
options.LogoutPath = "/Account/Signout";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, public void Configure(IApplicationBuilder app, IHostingEnvironment env)
IHostingEnvironment env)
{ {
if (env.IsDevelopment()) if (env.IsDevelopment())
{ {
@@ -129,12 +145,15 @@ namespace Microsoft.eShopWeb.RazorPages
} }
else else
{ {
app.UseExceptionHandler("/Catalog/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(); app.UseHsts();
} }
app.UseHttpsRedirection(); app.UseHttpsRedirection();
app.UseStaticFiles(); app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication(); app.UseAuthentication();
app.UseMvc(); app.UseMvc();
@@ -161,5 +180,6 @@ namespace Microsoft.eShopWeb.RazorPages
await context.Response.WriteAsync(sb.ToString()); await context.Response.WriteAsync(sb.ToString());
})); }));
} }
} }
} }

View File

@@ -1,16 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework> <PropertyGroup>
<RootNamespace>Microsoft.eShopWeb.RazorPages</RootNamespace> <TargetFramework>netcoreapp2.2</TargetFramework>
<AssemblyName>Microsoft.eShopWeb.RazorPages</AssemblyName> <RootNamespace>Microsoft.eShopWeb.RazorPages</RootNamespace>
<DockerTargetOS>Linux</DockerTargetOS> <AssemblyName>Microsoft.eShopWeb.RazorPages</AssemblyName>
<UserSecretsId>231ddc1b-6787-4704-a0c0-18df6a022660</UserSecretsId> <DockerTargetOS>Linux</DockerTargetOS>
</PropertyGroup> <UserSecretsId>aspnet-WebRazorPages-6B1EFE4D-B682-4543-93F5-69EE95000B1D</UserSecretsId>
<ItemGroup> <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.3" /> </PropertyGroup>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ApplicationCore\ApplicationCore.csproj" /> <ItemGroup>
<ProjectReference Include="..\Infrastructure\Infrastructure.csproj" /> <PackageReference Include="Microsoft.AspNetCore.App" />
</ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ApplicationCore\ApplicationCore.csproj" />
<ProjectReference Include="..\Infrastructure\Infrastructure.csproj" />
</ItemGroup>
<ItemGroup>
<Content Update="Pages\Shared\_LoginPartial.cshtml">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
</Project> </Project>

View File

@@ -1,6 +1,5 @@
{ {
"Logging": { "Logging": {
"IncludeScopes": false,
"LogLevel": { "LogLevel": {
"Default": "Debug", "Default": "Debug",
"System": "Information", "System": "Information",

View File

@@ -1,8 +1,11 @@
{ {
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-WebRazorPages-53bc9b9d-9d6a-45d4-8429-2a2761773502;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": { "Logging": {
"IncludeScopes": false,
"LogLevel": { "LogLevel": {
"Default": "Warning" "Default": "Warning"
} }
} },
"AllowedHosts": "*"
} }

View File

@@ -1,26 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework> <TargetFramework>netcoreapp2.2</TargetFramework>
<RootNamespace>Microsoft.eShopWeb.FunctionalTests</RootNamespace> <RootNamespace>Microsoft.eShopWeb.FunctionalTests</RootNamespace>
</PropertyGroup> <IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="2.1.2" /> <PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="2.2.0" />
<PackageReference Include="xunit" Version="2.3.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" /> <PackageReference Include="xunit" Version="2.4.1" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
</ItemGroup> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="2.2.0" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\ApplicationCore\ApplicationCore.csproj" /> <ProjectReference Include="..\..\src\ApplicationCore\ApplicationCore.csproj" />
<ProjectReference Include="..\..\src\WebRazorPages\WebRazorPages.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>
</Project> </Project>

View File

@@ -1,12 +1,12 @@
using Microsoft.eShopWeb.Infrastructure.Data; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.eShopWeb.Infrastructure.Data;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.Web; using Microsoft.eShopWeb.Web;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System; using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.eShopWeb.Infrastructure.Identity;
namespace Microsoft.eShopWeb.FunctionalTests.Web.Controllers namespace Microsoft.eShopWeb.FunctionalTests.Web.Controllers
{ {

View File

@@ -26,7 +26,7 @@ namespace Microsoft.eShopWeb.FunctionalTests.Web.Controllers
var redirectLocation = response.Headers.Location.OriginalString; var redirectLocation = response.Headers.Location.OriginalString;
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
Assert.Contains("Account/Signin", redirectLocation); Assert.Contains("Account/Login", redirectLocation);
} }
} }
} }

View File

@@ -1,12 +1,12 @@
using Microsoft.eShopWeb.Infrastructure.Data; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.eShopWeb.Web; using Microsoft.EntityFrameworkCore;
using Microsoft.eShopWeb.Infrastructure.Data;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.RazorPages;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System; using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.eShopWeb.Infrastructure.Identity;
namespace Microsoft.eShopWeb.FunctionalTests.WebRazorPages namespace Microsoft.eShopWeb.FunctionalTests.WebRazorPages
{ {

View File

@@ -1,5 +1,5 @@
using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.eShopWeb.Web; using Microsoft.eShopWeb.RazorPages;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -26,7 +26,7 @@ namespace Microsoft.eShopWeb.FunctionalTests.WebRazorPages
var redirectLocation = response.Headers.Location.OriginalString; var redirectLocation = response.Headers.Location.OriginalString;
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
Assert.Contains("Account/Signin", redirectLocation); Assert.Contains("Account/Login", redirectLocation);
} }
} }
} }

View File

@@ -1,25 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework> <TargetFramework>netcoreapp2.2</TargetFramework>
<RootNamespace>Microsoft.eShopWeb.IntegrationTests</RootNamespace> <RootNamespace>Microsoft.eShopWeb.IntegrationTests</RootNamespace>
</PropertyGroup> <IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="2.2.0" />
<PackageReference Include="xunit" Version="2.3.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" /> <PackageReference Include="Moq" Version="4.10.1" />
<PackageReference Include="Moq" Version="4.8.2" /> <PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
</ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Infrastructure\Infrastructure.csproj" />
<ProjectReference Include="..\UnitTests\UnitTests.csproj" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Web\Web.csproj" /> <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
<ProjectReference Include="..\UnitTests\UnitTests.csproj" /> </ItemGroup>
</ItemGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
</Project> </Project>

View File

@@ -1,26 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework> <TargetFramework>netcoreapp2.2</TargetFramework>
<RootNamespace>Microsoft.eShopWeb.UnitTests</RootNamespace> <RootNamespace>Microsoft.eShopWeb.UnitTests</RootNamespace>
</PropertyGroup> <IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.2" /> <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="Moq" Version="4.8.2" /> <PackageReference Include="Moq" Version="4.10.1" />
<PackageReference Include="xunit" Version="2.3.1" /> <PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.console" Version="2.3.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" /> <PrivateAssets>all</PrivateAssets>
</ItemGroup> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit.runner.console" Version="2.4.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\ApplicationCore\ApplicationCore.csproj" /> <ProjectReference Include="..\..\src\ApplicationCore\ApplicationCore.csproj" />
<ProjectReference Include="..\..\src\Web\Web.csproj" /> </ItemGroup>
</ItemGroup>
<ItemGroup> <ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" /> <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -0,0 +1,14 @@
using System;
using Xunit;
namespace XUnitTestProject1
{
public class UnitTest1
{
[Fact]
public void Test1()
{
}
}
}

View File

@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
</ItemGroup>
</Project>