Merge branch 'master' into pr/119
This commit is contained in:
@@ -56,9 +56,9 @@ You can also run the samples in Docker (see below).
|
||||
}
|
||||
```
|
||||
|
||||
1. Ensure your connection strings in `appsettings.json` point to a local SQL Server instance.
|
||||
2. Ensure your connection strings in `appsettings.json` point to a local SQL Server instance.
|
||||
|
||||
2. Open a command prompt in the Web folder and execute the following commands:
|
||||
3. Open a command prompt in the Web folder and execute the following commands:
|
||||
|
||||
```
|
||||
dotnet restore
|
||||
@@ -68,7 +68,7 @@ dotnet ef database update -c appidentitydbcontext -p ../Infrastructure/Infrastru
|
||||
|
||||
These commands will create two separate databases, one for the store's catalog data and shopping cart information, and one for the app's user credentials and identity data.
|
||||
|
||||
3. Run the application.
|
||||
4. Run the application.
|
||||
The first time you run the application, it will seed both databases with data such that you should see products in the store, and you should be able to log in using the demouser@microsoft.com account.
|
||||
|
||||
Note: If you need to create migrations, you can use these commands:
|
||||
|
||||
@@ -9,7 +9,7 @@ services:
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
ports:
|
||||
- "5107:5107"
|
||||
- "5107:80"
|
||||
|
||||
eshopwebmvc:
|
||||
image: eshopwebmvc
|
||||
@@ -19,7 +19,7 @@ services:
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
ports:
|
||||
- "5106:5106"
|
||||
- "5106:80"
|
||||
|
||||
networks:
|
||||
default:
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -7,8 +7,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{419A6ACE-041
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Infrastructure", "src\Infrastructure\Infrastructure.csproj", "{7C461394-ABDC-43CD-A798-71249C58BA67}"
|
||||
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}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{15EA4737-125B-4E6E-A806-E13B7EBCDCCF}"
|
||||
@@ -19,13 +17,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationTests", "tests\I
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunctionalTests", "tests\FunctionalTests\FunctionalTests.csproj", "{7EFB5482-F942-4C3D-94B0-9B70596E6D0A}"
|
||||
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}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
docker-compose.yml = docker-compose.yml
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Web", "src\Web\Web.csproj", "{227CF035-29B0-448D-97E4-944F9EA850E5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -36,10 +34,6 @@ Global
|
||||
{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.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.Build.0 = Debug|Any CPU
|
||||
{7FED7440-2311-4D1E-958B-3E887C585CD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -56,22 +50,21 @@ Global
|
||||
{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.Build.0 = Release|Any CPU
|
||||
{3CA62E98-218E-4A74-BF79-1098900BD421}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3CA62E98-218E-4A74-BF79-1098900BD421}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3CA62E98-218E-4A74-BF79-1098900BD421}.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}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{227CF035-29B0-448D-97E4-944F9EA850E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{227CF035-29B0-448D-97E4-944F9EA850E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{227CF035-29B0-448D-97E4-944F9EA850E5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{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}
|
||||
{EF6877E6-59CB-43A7-8C2C-E70DD70CC5B6} = {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}
|
||||
{3CA62E98-218E-4A74-BF79-1098900BD421} = {419A6ACE-0419-4315-A6FB-B0E63D39432E}
|
||||
{227CF035-29B0-448D-97E4-944F9EA850E5} = {419A6ACE-0419-4315-A6FB-B0E63D39432E}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {49813262-5DA3-4D61-ABD3-493C74CE8C2B}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RootNamespace>Microsoft.eShopWeb.ApplicationCore</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RootNamespace>Microsoft.eShopWeb.ApplicationCore</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Ardalis.GuardClauses" Version="1.2.3" />
|
||||
<PackageReference Include="System.Security.Claims" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Ardalis.GuardClauses" Version="1.2.3" />
|
||||
<PackageReference Include="System.Security.Claims" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,6 +1,5 @@
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using Ardalis.GuardClauses;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Entities.BuyerAggregate
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Entities.BuyerAggregate
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Entities.BuyerAggregate
|
||||
{
|
||||
public class PaymentMethod : BaseEntity
|
||||
{
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Entities
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Entities
|
||||
{
|
||||
public class CatalogBrand : BaseEntity
|
||||
{
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using Ardalis.GuardClauses;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate
|
||||
{
|
||||
|
||||
public class OrderItem : BaseEntity
|
||||
|
||||
@@ -7,10 +7,11 @@ namespace Microsoft.eShopWeb.ApplicationCore.Interfaces
|
||||
public interface IAsyncRepository<T> where T : BaseEntity
|
||||
{
|
||||
Task<T> GetByIdAsync(int id);
|
||||
Task<List<T>> ListAllAsync();
|
||||
Task<List<T>> ListAsync(ISpecification<T> spec);
|
||||
Task<IReadOnlyList<T>> ListAllAsync();
|
||||
Task<IReadOnlyList<T>> ListAsync(ISpecification<T> spec);
|
||||
Task<T> AddAsync(T entity);
|
||||
Task UpdateAsync(T entity);
|
||||
Task DeleteAsync(T entity);
|
||||
Task<int> CountAsync(ISpecification<T> spec);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,8 @@ using System.Threading.Tasks;
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces
|
||||
{
|
||||
|
||||
public interface IOrderRepository : IRepository<Order>, IAsyncRepository<Order>
|
||||
public interface IOrderRepository : IAsyncRepository<Order>
|
||||
{
|
||||
Order GetByIdWithItems(int id);
|
||||
Task<Order> GetByIdWithItemsAsync(int id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,5 +12,6 @@ namespace Microsoft.eShopWeb.ApplicationCore.Interfaces
|
||||
T Add(T entity);
|
||||
void Update(T entity);
|
||||
void Delete(T entity);
|
||||
int Count(ISpecification<T> spec);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,11 @@ namespace Microsoft.eShopWeb.ApplicationCore.Interfaces
|
||||
Expression<Func<T, bool>> Criteria { get; }
|
||||
List<Expression<Func<T, object>>> Includes { get; }
|
||||
List<string> IncludeStrings { get; }
|
||||
Expression<Func<T, object>> OrderBy { get; }
|
||||
Expression<Func<T, object>> OrderByDescending { get; }
|
||||
|
||||
int Take { get; }
|
||||
int Skip { get; }
|
||||
bool isPagingEnabled { get;}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Microsoft.eShopWeb.ApplicationCore.Services
|
||||
public class BasketService : IBasketService
|
||||
{
|
||||
private readonly IAsyncRepository<Basket> _basketRepository;
|
||||
private readonly IAsyncRepository<BasketItem> _basketItemRepository;
|
||||
private readonly IUriComposer _uriComposer;
|
||||
private readonly IAppLogger<BasketService> _logger;
|
||||
private readonly IRepository<CatalogItem> _itemRepository;
|
||||
@@ -19,12 +20,14 @@ namespace Microsoft.eShopWeb.ApplicationCore.Services
|
||||
public BasketService(IAsyncRepository<Basket> basketRepository,
|
||||
IRepository<CatalogItem> itemRepository,
|
||||
IUriComposer uriComposer,
|
||||
IAppLogger<BasketService> logger)
|
||||
IAppLogger<BasketService> logger,
|
||||
IAsyncRepository<BasketItem> basketItemRepository)
|
||||
{
|
||||
_basketRepository = basketRepository;
|
||||
_uriComposer = uriComposer;
|
||||
this._logger = logger;
|
||||
_logger = logger;
|
||||
_itemRepository = itemRepository;
|
||||
_basketItemRepository = basketItemRepository;
|
||||
}
|
||||
|
||||
public async Task AddItemToBasket(int basketId, int catalogItemId, decimal price, int quantity)
|
||||
@@ -40,6 +43,11 @@ namespace Microsoft.eShopWeb.ApplicationCore.Services
|
||||
{
|
||||
var basket = await _basketRepository.GetByIdAsync(basketId);
|
||||
|
||||
foreach (var item in basket.Items.ToList())
|
||||
{
|
||||
await _basketItemRepository.DeleteAsync(item);
|
||||
}
|
||||
|
||||
await _basketRepository.DeleteAsync(basket);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using Microsoft.eShopWeb;
|
||||
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Services
|
||||
{
|
||||
|
||||
@@ -14,6 +14,12 @@ namespace Microsoft.eShopWeb.ApplicationCore.Specifications
|
||||
public Expression<Func<T, bool>> Criteria { get; }
|
||||
public List<Expression<Func<T, object>>> Includes { get; } = new List<Expression<Func<T, object>>>();
|
||||
public List<string> IncludeStrings { get; } = new List<string>();
|
||||
public Expression<Func<T, object>> OrderBy { get; private set; }
|
||||
public Expression<Func<T, object>> OrderByDescending { get; private set; }
|
||||
|
||||
public int Take { get; private set; }
|
||||
public int Skip { get; private set; }
|
||||
public bool isPagingEnabled { get; private set; } = false;
|
||||
|
||||
protected virtual void AddInclude(Expression<Func<T, object>> includeExpression)
|
||||
{
|
||||
@@ -23,5 +29,19 @@ namespace Microsoft.eShopWeb.ApplicationCore.Specifications
|
||||
{
|
||||
IncludeStrings.Add(includeString);
|
||||
}
|
||||
protected virtual void ApplyPaging(int skip, int take)
|
||||
{
|
||||
Skip = skip;
|
||||
Take = take;
|
||||
isPagingEnabled = true;
|
||||
}
|
||||
protected virtual void ApplyOrderBy(Expression<Func<T, object>> orderByExpression)
|
||||
{
|
||||
OrderBy = orderByExpression;
|
||||
}
|
||||
protected virtual void ApplyOrderByDescending(Expression<Func<T, object>> orderByDescendingExpression)
|
||||
{
|
||||
OrderByDescending = orderByDescendingExpression;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Specifications
|
||||
{
|
||||
public class CatalogFilterPaginatedSpecification : BaseSpecification<CatalogItem>
|
||||
{
|
||||
public CatalogFilterPaginatedSpecification(int skip, int take, int? brandId, int? typeId)
|
||||
: base(i => (!brandId.HasValue || i.CatalogBrandId == brandId) &&
|
||||
(!typeId.HasValue || i.CatalogTypeId == typeId))
|
||||
{
|
||||
ApplyPaging(skip, take);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -31,7 +31,6 @@ namespace Microsoft.eShopWeb.Infrastructure.Data
|
||||
return List(spec).FirstOrDefault();
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task<T> GetByIdAsync(int id)
|
||||
{
|
||||
return await _dbContext.Set<T>().FindAsync(id);
|
||||
@@ -42,44 +41,28 @@ namespace Microsoft.eShopWeb.Infrastructure.Data
|
||||
return _dbContext.Set<T>().AsEnumerable();
|
||||
}
|
||||
|
||||
public async Task<List<T>> ListAllAsync()
|
||||
public async Task<IReadOnlyList<T>> ListAllAsync()
|
||||
{
|
||||
return await _dbContext.Set<T>().ToListAsync();
|
||||
}
|
||||
|
||||
public IEnumerable<T> List(ISpecification<T> spec)
|
||||
{
|
||||
// fetch a Queryable that includes all expression-based includes
|
||||
var queryableResultWithIncludes = spec.Includes
|
||||
.Aggregate(_dbContext.Set<T>().AsQueryable(),
|
||||
(current, include) => current.Include(include));
|
||||
|
||||
// modify the IQueryable to include any string-based include statements
|
||||
var secondaryResult = spec.IncludeStrings
|
||||
.Aggregate(queryableResultWithIncludes,
|
||||
(current, include) => current.Include(include));
|
||||
|
||||
// return the result of the query using the specification's criteria expression
|
||||
return secondaryResult
|
||||
.Where(spec.Criteria)
|
||||
.AsEnumerable();
|
||||
return ApplySpecification(spec).AsEnumerable();
|
||||
}
|
||||
public async Task<List<T>> ListAsync(ISpecification<T> spec)
|
||||
public async Task<IReadOnlyList<T>> ListAsync(ISpecification<T> spec)
|
||||
{
|
||||
// fetch a Queryable that includes all expression-based includes
|
||||
var queryableResultWithIncludes = spec.Includes
|
||||
.Aggregate(_dbContext.Set<T>().AsQueryable(),
|
||||
(current, include) => current.Include(include));
|
||||
|
||||
// modify the IQueryable to include any string-based include statements
|
||||
var secondaryResult = spec.IncludeStrings
|
||||
.Aggregate(queryableResultWithIncludes,
|
||||
(current, include) => current.Include(include));
|
||||
|
||||
// return the result of the query using the specification's criteria expression
|
||||
return await secondaryResult
|
||||
.Where(spec.Criteria)
|
||||
.ToListAsync();
|
||||
return await ApplySpecification(spec).ToListAsync();
|
||||
}
|
||||
|
||||
public int Count(ISpecification<T> spec)
|
||||
{
|
||||
return ApplySpecification(spec).Count();
|
||||
}
|
||||
|
||||
public async Task<int> CountAsync(ISpecification<T> spec)
|
||||
{
|
||||
return await ApplySpecification(spec).CountAsync();
|
||||
}
|
||||
|
||||
public T Add(T entity)
|
||||
@@ -103,6 +86,7 @@ namespace Microsoft.eShopWeb.Infrastructure.Data
|
||||
_dbContext.Entry(entity).State = EntityState.Modified;
|
||||
_dbContext.SaveChanges();
|
||||
}
|
||||
|
||||
public async Task UpdateAsync(T entity)
|
||||
{
|
||||
_dbContext.Entry(entity).State = EntityState.Modified;
|
||||
@@ -114,10 +98,16 @@ namespace Microsoft.eShopWeb.Infrastructure.Data
|
||||
_dbContext.Set<T>().Remove(entity);
|
||||
_dbContext.SaveChanges();
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(T entity)
|
||||
{
|
||||
_dbContext.Set<T>().Remove(entity);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private IQueryable<T> ApplySpecification(ISpecification<T> spec)
|
||||
{
|
||||
return SpecificationEvaluator<T>.GetQuery(_dbContext.Set<T>().AsQueryable(), spec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.eShopWeb.Infrastructure.Data.Migrations
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopWeb.Infrastructure.Data
|
||||
@@ -12,20 +11,12 @@ namespace Microsoft.eShopWeb.Infrastructure.Data
|
||||
{
|
||||
}
|
||||
|
||||
public Order GetByIdWithItems(int id)
|
||||
{
|
||||
return _dbContext.Orders
|
||||
.Include(o => o.OrderItems)
|
||||
.Include($"{nameof(Order.OrderItems)}.{nameof(OrderItem.ItemOrdered)}")
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
public Task<Order> GetByIdWithItemsAsync(int id)
|
||||
{
|
||||
return _dbContext.Orders
|
||||
.Include(o => o.OrderItems)
|
||||
.Include($"{nameof(Order.OrderItems)}.{nameof(OrderItem.ItemOrdered)}")
|
||||
.FirstOrDefaultAsync();
|
||||
.FirstOrDefaultAsync(x => x.Id == id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
50
src/Infrastructure/Data/SpecificationEvaluator.cs
Normal file
50
src/Infrastructure/Data/SpecificationEvaluator.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.eShopWeb.Infrastructure.Data
|
||||
{
|
||||
public class SpecificationEvaluator<T> where T : BaseEntity
|
||||
{
|
||||
public static IQueryable<T> GetQuery(IQueryable<T> inputQuery, ISpecification<T> specification)
|
||||
{
|
||||
var query = inputQuery;
|
||||
|
||||
// modify the IQueryable using the specification's criteria expression
|
||||
if (specification.Criteria != null)
|
||||
{
|
||||
query = query.Where(specification.Criteria);
|
||||
}
|
||||
|
||||
// Includes all expression-based includes
|
||||
query = specification.Includes.Aggregate(query,
|
||||
(current, include) => current.Include(include));
|
||||
|
||||
// Include any string-based include statements
|
||||
query = specification.IncludeStrings.Aggregate(query,
|
||||
(current, include) => current.Include(include));
|
||||
|
||||
// Apply ordering if expressions are set
|
||||
if (specification.OrderBy != null)
|
||||
{
|
||||
query = query.OrderBy(specification.OrderBy);
|
||||
}
|
||||
else if (specification.OrderByDescending != null)
|
||||
{
|
||||
query = query.OrderByDescending(specification.OrderByDescending);
|
||||
}
|
||||
|
||||
// Apply paging if enabled
|
||||
if (specification.isPagingEnabled)
|
||||
{
|
||||
query = query.Skip(specification.Skip)
|
||||
.Take(specification.Take);
|
||||
}
|
||||
return query;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.eShopWeb.Infrastructure.Identity;
|
||||
|
||||
namespace Microsoft.eShopWeb.Infrastructure.Identity.Migrations
|
||||
{
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RootNamespace>Microsoft.eShopWeb.Infrastructure</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RootNamespace>Microsoft.eShopWeb.Infrastructure</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.1.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ApplicationCore\ApplicationCore.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Data\Migrations\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.1.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="2.1.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.1.2" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ApplicationCore\ApplicationCore.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Data\Migrations\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"directory": "wwwroot/lib"
|
||||
}
|
||||
3
src/Web/Areas/Identity/Pages/_ViewStart.cshtml
Normal file
3
src/Web/Areas/Identity/Pages/_ViewStart.cshtml
Normal file
@@ -0,0 +1,3 @@
|
||||
@{
|
||||
Layout = "/Views/Shared/_Layout.cshtml";
|
||||
}
|
||||
@@ -3,5 +3,7 @@
|
||||
public static class Constants
|
||||
{
|
||||
public const string BASKET_COOKIENAME = "eShop";
|
||||
public const int ITEMS_PER_PAGE = 10;
|
||||
public const string DEFAULT_USERNAME = "Guest";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using Microsoft.eShopWeb.Infrastructure.Identity;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using Microsoft.eShopWeb.Infrastructure.Identity;
|
||||
using Microsoft.eShopWeb.Web.ViewModels.Account;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.Controllers
|
||||
{
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
[Route("[controller]/[action]")]
|
||||
[Authorize]
|
||||
[Authorize] // Controllers that mainly require Authorization still use Controller/View; other pages use Pages
|
||||
public class AccountController : Controller
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
@@ -149,10 +150,11 @@ namespace Microsoft.eShopWeb.Web.Controllers
|
||||
{
|
||||
await _signInManager.SignOutAsync();
|
||||
|
||||
return RedirectToAction(nameof(CatalogController.Index), "Catalog");
|
||||
return RedirectToPage("/Index");
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpGet]
|
||||
public IActionResult Register()
|
||||
{
|
||||
return View();
|
||||
@@ -184,7 +186,7 @@ namespace Microsoft.eShopWeb.Web.Controllers
|
||||
{
|
||||
if (userId == null || code == null)
|
||||
{
|
||||
return RedirectToAction(nameof(CatalogController.Index), "Catalog");
|
||||
return RedirectToPage("/Index");
|
||||
}
|
||||
var user = await _userManager.FindByIdAsync(userId);
|
||||
if (user == null)
|
||||
@@ -215,7 +217,7 @@ namespace Microsoft.eShopWeb.Web.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
return RedirectToAction(nameof(CatalogController.Index), "Catalog");
|
||||
return RedirectToPage("/Index");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
using Microsoft.eShopWeb.Web.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.Controllers.Api
|
||||
{
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class BaseApiController : Controller
|
||||
{ }
|
||||
}
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.eShopWeb.Web.ViewModels;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.eShopWeb.Infrastructure.Identity;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.eShopWeb.Web.Interfaces;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.Controllers
|
||||
{
|
||||
[Route("[controller]/[action]")]
|
||||
public class BasketController : Controller
|
||||
{
|
||||
private readonly IBasketService _basketService;
|
||||
private readonly IUriComposer _uriComposer;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
private readonly IAppLogger<BasketController> _logger;
|
||||
private readonly IOrderService _orderService;
|
||||
private readonly IBasketViewModelService _basketViewModelService;
|
||||
|
||||
public BasketController(IBasketService basketService,
|
||||
IBasketViewModelService basketViewModelService,
|
||||
IOrderService orderService,
|
||||
IUriComposer uriComposer,
|
||||
SignInManager<ApplicationUser> signInManager,
|
||||
IAppLogger<BasketController> logger)
|
||||
{
|
||||
_basketService = basketService;
|
||||
_uriComposer = uriComposer;
|
||||
_signInManager = signInManager;
|
||||
_logger = logger;
|
||||
_orderService = orderService;
|
||||
_basketViewModelService = basketViewModelService;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Index()
|
||||
{
|
||||
var basketModel = await GetBasketViewModelAsync();
|
||||
|
||||
return View(basketModel);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Index(Dictionary<string, int> items)
|
||||
{
|
||||
var basketViewModel = await GetBasketViewModelAsync();
|
||||
await _basketService.SetQuantities(basketViewModel.Id, items);
|
||||
|
||||
return View(await GetBasketViewModelAsync());
|
||||
}
|
||||
|
||||
|
||||
// POST: /Basket/AddToBasket
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> AddToBasket(CatalogItemViewModel productDetails)
|
||||
{
|
||||
if (productDetails?.Id == null)
|
||||
{
|
||||
return RedirectToAction("Index", "Catalog");
|
||||
}
|
||||
var basketViewModel = await GetBasketViewModelAsync();
|
||||
|
||||
await _basketService.AddItemToBasket(basketViewModel.Id, productDetails.Id, productDetails.Price, 1);
|
||||
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> Checkout(Dictionary<string, int> items)
|
||||
{
|
||||
var basketViewModel = await GetBasketViewModelAsync();
|
||||
await _basketService.SetQuantities(basketViewModel.Id, items);
|
||||
|
||||
await _orderService.CreateOrderAsync(basketViewModel.Id, new Address("123 Main St.", "Kent", "OH", "United States", "44240"));
|
||||
|
||||
await _basketService.DeleteBasketAsync(basketViewModel.Id);
|
||||
|
||||
return View("Checkout");
|
||||
}
|
||||
|
||||
private async Task<BasketViewModel> GetBasketViewModelAsync()
|
||||
{
|
||||
if (_signInManager.IsSignedIn(HttpContext.User))
|
||||
{
|
||||
return await _basketViewModelService.GetOrCreateBasketForUser(User.Identity.Name);
|
||||
}
|
||||
string anonymousId = GetOrSetBasketCookie();
|
||||
return await _basketViewModelService.GetOrCreateBasketForUser(anonymousId);
|
||||
}
|
||||
|
||||
private string GetOrSetBasketCookie()
|
||||
{
|
||||
if (Request.Cookies.ContainsKey(Constants.BASKET_COOKIENAME))
|
||||
{
|
||||
return Request.Cookies[Constants.BASKET_COOKIENAME];
|
||||
}
|
||||
string anonymousId = Guid.NewGuid().ToString();
|
||||
var cookieOptions = new CookieOptions();
|
||||
cookieOptions.Expires = DateTime.Today.AddYears(10);
|
||||
Response.Cookies.Append(Constants.BASKET_COOKIENAME, anonymousId, cookieOptions);
|
||||
return anonymousId;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using Microsoft.eShopWeb.Web.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.Controllers
|
||||
{
|
||||
[Route("")]
|
||||
public class CatalogController : Controller
|
||||
{
|
||||
private readonly ICatalogService _catalogService;
|
||||
|
||||
public CatalogController(ICatalogService catalogService) => _catalogService = catalogService;
|
||||
|
||||
[HttpGet]
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Index(int? brandFilterApplied, int? typesFilterApplied, int? page)
|
||||
{
|
||||
var itemsPage = 10;
|
||||
var catalogModel = await _catalogService.GetCatalogItems(page ?? 0, itemsPage, brandFilterApplied, typesFilterApplied);
|
||||
return View(catalogModel);
|
||||
}
|
||||
|
||||
[HttpGet("Error")]
|
||||
public IActionResult Error()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using Microsoft.eShopWeb.Infrastructure.Identity;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
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.ViewModels.Manage;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -14,7 +14,8 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
[Authorize] // Controllers that mainly require Authorization still use Controller/View; other pages use Pages
|
||||
[Route("[controller]/[action]")]
|
||||
public class ManageController : Controller
|
||||
{
|
||||
@@ -44,7 +45,7 @@ namespace Microsoft.eShopWeb.Web.Controllers
|
||||
public string StatusMessage { get; set; }
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Index()
|
||||
public async Task<IActionResult> MyAccount()
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
if (user == null)
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.eShopWeb.Web.ViewModels;
|
||||
using System;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using System.Linq;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Specifications;
|
||||
using Microsoft.eShopWeb.Web.ViewModels;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
[Authorize] // Controllers that mainly require Authorization still use Controller/View; other pages use Pages
|
||||
[Route("[controller]/[action]")]
|
||||
public class OrderController : Controller
|
||||
{
|
||||
private readonly IOrderRepository _orderRepository;
|
||||
|
||||
public OrderController(IOrderRepository orderRepository) {
|
||||
public OrderController(IOrderRepository orderRepository)
|
||||
{
|
||||
_orderRepository = orderRepository;
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Index()
|
||||
|
||||
[HttpGet()]
|
||||
public async Task<IActionResult> MyOrders()
|
||||
{
|
||||
var orders = await _orderRepository.ListAsync(new CustomerOrdersWithItemsSpecification(User.Identity.Name));
|
||||
|
||||
|
||||
16
src/Web/Data/ApplicationDbContext.cs
Normal file
16
src/Web/Data/ApplicationDbContext.cs
Normal 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
236
src/Web/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs
generated
Normal file
236
src/Web/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs
generated
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
220
src/Web/Data/Migrations/00000000000000_CreateIdentitySchema.cs
Normal file
220
src/Web/Data/Migrations/00000000000000_CreateIdentitySchema.cs
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
234
src/Web/Data/Migrations/ApplicationDbContextModelSnapshot.cs
Normal file
234
src/Web/Data/Migrations/ApplicationDbContextModelSnapshot.cs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
# RUN COMMAND
|
||||
# docker run --name eshopweb --rm -it -p 8000:5106 web
|
||||
FROM microsoft/dotnet:2.1-sdk AS build
|
||||
FROM microsoft/dotnet:2.2-sdk AS build
|
||||
WORKDIR /app
|
||||
|
||||
COPY *.sln .
|
||||
@@ -17,7 +17,7 @@ RUN dotnet restore
|
||||
|
||||
RUN dotnet publish -c Release -o out
|
||||
|
||||
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS runtime
|
||||
FROM microsoft/dotnet:2.2-aspnetcore-runtime AS runtime
|
||||
WORKDIR /app
|
||||
COPY --from=build /app/src/Web/out ./
|
||||
|
||||
|
||||
40
src/Web/HealthChecks/ApiHealthCheck.cs
Normal file
40
src/Web/HealthChecks/ApiHealthCheck.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.HealthChecks
|
||||
{
|
||||
public class ApiHealthCheck : IHealthCheck
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly LinkGenerator _linkGenerator;
|
||||
|
||||
public ApiHealthCheck(IHttpContextAccessor httpContextAccessor, LinkGenerator linkGenerator)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_linkGenerator = linkGenerator;
|
||||
}
|
||||
|
||||
public async Task<HealthCheckResult> CheckHealthAsync(
|
||||
HealthCheckContext context,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var request = _httpContextAccessor.HttpContext.Request;
|
||||
|
||||
string apiLink = _linkGenerator.GetPathByAction("List", "Catalog");
|
||||
string myUrl = request.Scheme + "://" + request.Host.ToString() + apiLink;
|
||||
var client = new HttpClient();
|
||||
var response = await client.GetAsync(myUrl);
|
||||
var pageContents = await response.Content.ReadAsStringAsync();
|
||||
if (pageContents.Contains(".NET Bot Black Sweatshirt"))
|
||||
{
|
||||
return HealthCheckResult.Healthy("The check indicates a healthy result.");
|
||||
}
|
||||
|
||||
return HealthCheckResult.Unhealthy("The check indicates an unhealthy result.");
|
||||
}
|
||||
}
|
||||
}
|
||||
36
src/Web/HealthChecks/HomePageHealthCheck.cs
Normal file
36
src/Web/HealthChecks/HomePageHealthCheck.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.HealthChecks
|
||||
{
|
||||
public class HomePageHealthCheck : IHealthCheck
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public HomePageHealthCheck(IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public async Task<HealthCheckResult> CheckHealthAsync(
|
||||
HealthCheckContext context,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var request = _httpContextAccessor.HttpContext.Request;
|
||||
string myUrl = request.Scheme + "://" + request.Host.ToString();
|
||||
|
||||
var client = new HttpClient();
|
||||
var response = await client.GetAsync(myUrl);
|
||||
var pageContents = await response.Content.ReadAsStringAsync();
|
||||
if (pageContents.Contains(".NET Bot Black Sweatshirt"))
|
||||
{
|
||||
return HealthCheckResult.Healthy("The check indicates a healthy result.");
|
||||
}
|
||||
|
||||
return HealthCheckResult.Unhealthy("The check indicates an unhealthy result.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using Microsoft.eShopWeb.Web.ViewModels;
|
||||
using Microsoft.eShopWeb.Web.Pages.Basket;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.Interfaces
|
||||
11
src/Web/Models/ErrorViewModel.cs
Normal file
11
src/Web/Models/ErrorViewModel.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace Web2.Models
|
||||
{
|
||||
public class ErrorViewModel
|
||||
{
|
||||
public string RequestId { get; set; }
|
||||
|
||||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Microsoft.eShopWeb.Web.ViewModels
|
||||
namespace Microsoft.eShopWeb.Web.Pages.Basket
|
||||
{
|
||||
public class BasketItemViewModel
|
||||
{
|
||||
@@ -2,7 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.ViewModels
|
||||
namespace Microsoft.eShopWeb.Web.Pages.Basket
|
||||
{
|
||||
public class BasketViewModel
|
||||
{
|
||||
16
src/Web/Pages/Basket/Checkout.cshtml
Normal file
16
src/Web/Pages/Basket/Checkout.cshtml
Normal file
@@ -0,0 +1,16 @@
|
||||
@page
|
||||
@model CheckoutModel
|
||||
@{
|
||||
ViewData["Title"] = "Checkout Complete";
|
||||
}
|
||||
<section class="esh-catalog-hero">
|
||||
<div class="container">
|
||||
<img class="esh-catalog-title" src="~/images/main_banner_text.png" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="container">
|
||||
<h1>Thanks for your Order!</h1>
|
||||
|
||||
<a asp-page="/Index">Continue Shopping...</a>
|
||||
</div>
|
||||
83
src/Web/Pages/Basket/Checkout.cshtml.cs
Normal file
83
src/Web/Pages/Basket/Checkout.cshtml.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using Microsoft.eShopWeb.Infrastructure.Identity;
|
||||
using Microsoft.eShopWeb.Web.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.Pages.Basket
|
||||
{
|
||||
public class CheckoutModel : PageModel
|
||||
{
|
||||
private readonly IBasketService _basketService;
|
||||
private readonly IUriComposer _uriComposer;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
private readonly IOrderService _orderService;
|
||||
private string _username = null;
|
||||
private readonly IBasketViewModelService _basketViewModelService;
|
||||
|
||||
public CheckoutModel(IBasketService basketService,
|
||||
IBasketViewModelService basketViewModelService,
|
||||
IUriComposer uriComposer,
|
||||
SignInManager<ApplicationUser> signInManager,
|
||||
IOrderService orderService)
|
||||
{
|
||||
_basketService = basketService;
|
||||
_uriComposer = uriComposer;
|
||||
_signInManager = signInManager;
|
||||
_orderService = orderService;
|
||||
_basketViewModelService = basketViewModelService;
|
||||
}
|
||||
|
||||
public BasketViewModel BasketModel { get; set; } = new BasketViewModel();
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnPost(Dictionary<string, int> items)
|
||||
{
|
||||
await SetBasketModelAsync();
|
||||
|
||||
await _basketService.SetQuantities(BasketModel.Id, items);
|
||||
|
||||
await _orderService.CreateOrderAsync(BasketModel.Id, new Address("123 Main St.", "Kent", "OH", "United States", "44240"));
|
||||
|
||||
await _basketService.DeleteBasketAsync(BasketModel.Id);
|
||||
|
||||
return RedirectToPage();
|
||||
}
|
||||
|
||||
private async Task SetBasketModelAsync()
|
||||
{
|
||||
if (_signInManager.IsSignedIn(HttpContext.User))
|
||||
{
|
||||
BasketModel = await _basketViewModelService.GetOrCreateBasketForUser(User.Identity.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetOrSetBasketCookieAndUserName();
|
||||
BasketModel = await _basketViewModelService.GetOrCreateBasketForUser(_username);
|
||||
}
|
||||
}
|
||||
|
||||
private void GetOrSetBasketCookieAndUserName()
|
||||
{
|
||||
if (Request.Cookies.ContainsKey(Constants.BASKET_COOKIENAME))
|
||||
{
|
||||
_username = Request.Cookies[Constants.BASKET_COOKIENAME];
|
||||
}
|
||||
if (_username != null) return;
|
||||
|
||||
_username = Guid.NewGuid().ToString();
|
||||
var cookieOptions = new CookieOptions();
|
||||
cookieOptions.Expires = DateTime.Today.AddYears(10);
|
||||
Response.Cookies.Append(Constants.BASKET_COOKIENAME, _username, cookieOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
@using Microsoft.eShopWeb.Web.ViewModels
|
||||
@model BasketViewModel
|
||||
@page "{handler?}"
|
||||
@model IndexModel
|
||||
@{
|
||||
ViewData["Title"] = "Basket";
|
||||
}
|
||||
<section class="esh-catalog-hero">
|
||||
<div class="container">
|
||||
<img class="esh-catalog-title" src="../images/main_banner_text.png" />
|
||||
<img class="esh-catalog-title" src="~/images/main_banner_text.png" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="container">
|
||||
|
||||
@if (Model.Items.Any())
|
||||
@if (Model.BasketModel.Items.Any())
|
||||
{
|
||||
<form method="post">
|
||||
<article class="esh-basket-titles row">
|
||||
@@ -23,9 +23,9 @@
|
||||
<section class="esh-basket-title col-xs-2">Cost</section>
|
||||
</article>
|
||||
<div class="esh-catalog-items row">
|
||||
@for (int i=0; i< Model.Items.Count; i++)
|
||||
@for (int i = 0; i < Model.BasketModel.Items.Count; i++)
|
||||
{
|
||||
var item = Model.Items[i];
|
||||
var item = Model.BasketModel.Items[i];
|
||||
<article class="esh-basket-items row">
|
||||
<div>
|
||||
<section class="esh-basket-item esh-basket-item--middle col-lg-3 hidden-lg-down">
|
||||
@@ -44,32 +44,36 @@
|
||||
</div>
|
||||
</article>
|
||||
@*<div class="esh-catalog-item col-md-4">
|
||||
@item.ProductId
|
||||
</div>*@
|
||||
@item.ProductId
|
||||
</div>*@
|
||||
|
||||
<div class="container">
|
||||
<article class="esh-basket-titles esh-basket-titles--clean row">
|
||||
<section class="esh-basket-title col-xs-10"></section>
|
||||
<section class="esh-basket-title col-xs-2">Total</section>
|
||||
</article>
|
||||
|
||||
<article class="esh-basket-items row">
|
||||
<section class="esh-basket-item col-xs-10"></section>
|
||||
<section class="esh-basket-item esh-basket-item--mark col-xs-2">$ @Model.Total()</section>
|
||||
</article>
|
||||
|
||||
<article class="esh-basket-items row">
|
||||
<section class="esh-basket-item col-xs-7"></section>
|
||||
<section class="esh-basket-item col-xs-2">
|
||||
@*<button class="btn esh-basket-checkout" name="name" value="" type="submit">[ Update ]</button>*@
|
||||
</section>
|
||||
</article>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="container">
|
||||
<article class="esh-basket-titles esh-basket-titles--clean row">
|
||||
<section class="esh-basket-title col-xs-10"></section>
|
||||
<section class="esh-basket-title col-xs-2">Total</section>
|
||||
</article>
|
||||
|
||||
<article class="esh-basket-items row">
|
||||
<section class="esh-basket-item col-xs-10"></section>
|
||||
<section class="esh-basket-item esh-basket-item--mark col-xs-2">$ @Model.BasketModel.Total().ToString("N2")</section>
|
||||
</article>
|
||||
|
||||
<article class="esh-basket-items row">
|
||||
<section class="esh-basket-item col-xs-7"></section>
|
||||
<section class="esh-basket-item col-xs-2">
|
||||
@*<button class="btn esh-basket-checkout" name="name" value="" type="submit">[ Update ]</button>*@
|
||||
</section>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<section class="esh-basket-item col-xs-push-8 col-xs-4">
|
||||
<button class="btn esh-basket-checkout" name="updatebutton" value="" type="submit"
|
||||
asp-action="Index">[ Update ]</button>
|
||||
<input type="submit" asp-action="Checkout"
|
||||
asp-page-handler="Update">
|
||||
[ Update ]
|
||||
</button>
|
||||
<input type="submit" asp-page="Checkout"
|
||||
class="btn esh-basket-checkout"
|
||||
value="[ Checkout ]" name="action" />
|
||||
</section>
|
||||
92
src/Web/Pages/Basket/Index.cshtml.cs
Normal file
92
src/Web/Pages/Basket/Index.cshtml.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using Microsoft.eShopWeb.Infrastructure.Identity;
|
||||
using Microsoft.eShopWeb.Web.Interfaces;
|
||||
using Microsoft.eShopWeb.Web.ViewModels;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.Pages.Basket
|
||||
{
|
||||
public class IndexModel : PageModel
|
||||
{
|
||||
private readonly IBasketService _basketService;
|
||||
private const string _basketSessionKey = "basketId";
|
||||
private readonly IUriComposer _uriComposer;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
private string _username = null;
|
||||
private readonly IBasketViewModelService _basketViewModelService;
|
||||
|
||||
public IndexModel(IBasketService basketService,
|
||||
IBasketViewModelService basketViewModelService,
|
||||
IUriComposer uriComposer,
|
||||
SignInManager<ApplicationUser> signInManager)
|
||||
{
|
||||
_basketService = basketService;
|
||||
_uriComposer = uriComposer;
|
||||
_signInManager = signInManager;
|
||||
_basketViewModelService = basketViewModelService;
|
||||
}
|
||||
|
||||
public BasketViewModel BasketModel { get; set; } = new BasketViewModel();
|
||||
|
||||
public async Task OnGet()
|
||||
{
|
||||
await SetBasketModelAsync();
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnPost(CatalogItemViewModel productDetails)
|
||||
{
|
||||
if (productDetails?.Id == null)
|
||||
{
|
||||
return RedirectToPage("/Index");
|
||||
}
|
||||
await SetBasketModelAsync();
|
||||
|
||||
await _basketService.AddItemToBasket(BasketModel.Id, productDetails.Id, productDetails.Price, 1);
|
||||
|
||||
await SetBasketModelAsync();
|
||||
|
||||
return RedirectToPage();
|
||||
}
|
||||
|
||||
public async Task OnPostUpdate(Dictionary<string, int> items)
|
||||
{
|
||||
await SetBasketModelAsync();
|
||||
await _basketService.SetQuantities(BasketModel.Id, items);
|
||||
|
||||
await SetBasketModelAsync();
|
||||
}
|
||||
|
||||
private async Task SetBasketModelAsync()
|
||||
{
|
||||
if (_signInManager.IsSignedIn(HttpContext.User))
|
||||
{
|
||||
BasketModel = await _basketViewModelService.GetOrCreateBasketForUser(User.Identity.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetOrSetBasketCookieAndUserName();
|
||||
BasketModel = await _basketViewModelService.GetOrCreateBasketForUser(_username);
|
||||
}
|
||||
}
|
||||
|
||||
private void GetOrSetBasketCookieAndUserName()
|
||||
{
|
||||
if (Request.Cookies.ContainsKey(Constants.BASKET_COOKIENAME))
|
||||
{
|
||||
_username = Request.Cookies[Constants.BASKET_COOKIENAME];
|
||||
}
|
||||
if (_username != null) return;
|
||||
|
||||
_username = Guid.NewGuid().ToString();
|
||||
var cookieOptions = new CookieOptions { IsEssential = true };
|
||||
cookieOptions.Expires = DateTime.Today.AddYears(10);
|
||||
Response.Cookies.Append(Constants.BASKET_COOKIENAME, _username, cookieOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/Web/Pages/Error.cshtml
Normal file
26
src/Web/Pages/Error.cshtml
Normal file
@@ -0,0 +1,26 @@
|
||||
@page
|
||||
@model ErrorModel
|
||||
@{
|
||||
ViewData["Title"] = "Error";
|
||||
}
|
||||
|
||||
<h1 class="text-danger">Error.</h1>
|
||||
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||
|
||||
@if (Model.ShowRequestId)
|
||||
{
|
||||
<p>
|
||||
<strong>Request ID:</strong> <code>@Model.RequestId</code>
|
||||
</p>
|
||||
}
|
||||
|
||||
<h3>Development Mode</h3>
|
||||
<p>
|
||||
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
|
||||
</p>
|
||||
<p>
|
||||
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
|
||||
It can result in displaying sensitive information from exceptions to end users.
|
||||
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
|
||||
and restarting the app.
|
||||
</p>
|
||||
19
src/Web/Pages/Error.cshtml.cs
Normal file
19
src/Web/Pages/Error.cshtml.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.Pages
|
||||
{
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public class ErrorModel : PageModel
|
||||
{
|
||||
public string RequestId { get; set; }
|
||||
|
||||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +1,40 @@
|
||||
@{
|
||||
@page
|
||||
@{
|
||||
ViewData["Title"] = "Catalog";
|
||||
@model CatalogIndexViewModel
|
||||
@model IndexModel
|
||||
}
|
||||
<section class="esh-catalog-hero">
|
||||
<div class="container">
|
||||
<img class="esh-catalog-title" src="../images/main_banner_text.png" />
|
||||
<img class="esh-catalog-title" src="~/images/main_banner_text.png" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="esh-catalog-filters">
|
||||
<div class="container">
|
||||
<form asp-action="Index" asp-controller="Catalog" method="post">
|
||||
<form method="get">
|
||||
<label class="esh-catalog-label" data-title="brand">
|
||||
<select asp-for="@Model.BrandFilterApplied" asp-items="@Model.Brands" class="esh-catalog-filter"></select>
|
||||
<select asp-for="@Model.CatalogModel.BrandFilterApplied" asp-items="@Model.CatalogModel.Brands" class="esh-catalog-filter"></select>
|
||||
</label>
|
||||
<label class="esh-catalog-label" data-title="type">
|
||||
<select asp-for="@Model.TypesFilterApplied" asp-items="@Model.Types" class="esh-catalog-filter"></select>
|
||||
<select asp-for="@Model.CatalogModel.TypesFilterApplied" asp-items="@Model.CatalogModel.Types" class="esh-catalog-filter"></select>
|
||||
</label>
|
||||
<input class="esh-catalog-send" type="image" src="images/arrow-right.svg" />
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="container">
|
||||
|
||||
@if (Model.CatalogItems.Any())
|
||||
@if (Model.CatalogModel.CatalogItems.Any())
|
||||
{
|
||||
<partial name="_pagination" for="PaginationInfo" />
|
||||
<partial name="_pagination" for="CatalogModel.PaginationInfo" />
|
||||
|
||||
<div class="esh-catalog-items row">
|
||||
@foreach (var catalogItem in Model.CatalogItems)
|
||||
@foreach (var catalogItem in Model.CatalogModel.CatalogItems)
|
||||
{
|
||||
<div class="esh-catalog-item col-md-4">
|
||||
<partial name="_product" model="catalogItem" />
|
||||
<partial name="_product" for="@catalogItem" />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<partial name="_pagination" for="PaginationInfo" />
|
||||
<partial name="_pagination" for="CatalogModel.PaginationInfo" />
|
||||
}
|
||||
else
|
||||
{
|
||||
26
src/Web/Pages/Index.cshtml.cs
Normal file
26
src/Web/Pages/Index.cshtml.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.eShopWeb.Web.Services;
|
||||
using Microsoft.eShopWeb.Web.ViewModels;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.Pages
|
||||
{
|
||||
public class IndexModel : PageModel
|
||||
{
|
||||
private readonly ICatalogService _catalogService;
|
||||
|
||||
public IndexModel(ICatalogService catalogService)
|
||||
{
|
||||
_catalogService = catalogService;
|
||||
}
|
||||
|
||||
public CatalogIndexViewModel CatalogModel { get; set; } = new CatalogIndexViewModel();
|
||||
|
||||
public async Task OnGet(CatalogIndexViewModel catalogModel, int? pageId)
|
||||
{
|
||||
CatalogModel = await _catalogService.GetCatalogItems(pageId ?? 0, Constants.ITEMS_PER_PAGE, catalogModel.BrandFilterApplied, catalogModel.TypesFilterApplied);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
8
src/Web/Pages/Privacy.cshtml
Normal file
8
src/Web/Pages/Privacy.cshtml
Normal 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>
|
||||
11
src/Web/Pages/Privacy.cshtml.cs
Normal file
11
src/Web/Pages/Privacy.cshtml.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.Pages
|
||||
{
|
||||
public class PrivacyModel : PageModel
|
||||
{
|
||||
public void OnGet()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
using Microsoft.eShopWeb.Infrastructure.Identity;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.eShopWeb;
|
||||
using Microsoft.eShopWeb.Infrastructure.Identity;
|
||||
using Microsoft.eShopWeb.Web.Interfaces;
|
||||
using Microsoft.eShopWeb.Web.Pages.Basket;
|
||||
using Microsoft.eShopWeb.Web.ViewModels;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.ViewComponents
|
||||
namespace Microsoft.eShopWeb.Web.Pages.Shared.Components.BasketComponent
|
||||
{
|
||||
public class Basket : ViewComponent
|
||||
{
|
||||
@@ -0,0 +1,13 @@
|
||||
@model BasketComponentViewModel
|
||||
@{
|
||||
ViewData["Title"] = "My Basket";
|
||||
}
|
||||
<a class="esh-basketstatus "
|
||||
asp-page="/Basket/Index">
|
||||
<div class="esh-basketstatus-image">
|
||||
<img src="~/images/cart.png" />
|
||||
</div>
|
||||
<div class="esh-basketstatus-badge">
|
||||
@Model.ItemsCount
|
||||
</div>
|
||||
</a>
|
||||
@@ -7,9 +7,7 @@
|
||||
<div class="col-md-2 col-xs-12">
|
||||
<a class="esh-pager-item-left esh-pager-item--navigable @Model.Previous"
|
||||
id="Previous"
|
||||
asp-controller="Catalog"
|
||||
asp-action="Index"
|
||||
asp-route-page="@(Model.ActualPage - 1)"
|
||||
asp-route-pageid="@(Model.ActualPage - 1)"
|
||||
aria-label="Previous">
|
||||
Previous
|
||||
</a>
|
||||
@@ -24,9 +22,7 @@
|
||||
<div class="col-md-2 col-xs-12">
|
||||
<a class="esh-pager-item-right esh-pager-item--navigable @Model.Next"
|
||||
id="Next"
|
||||
asp-controller="Catalog"
|
||||
asp-action="Index"
|
||||
asp-route-page="@(Model.ActualPage + 1)"
|
||||
asp-route-pageid="@(Model.ActualPage + 1)"
|
||||
aria-label="Next">
|
||||
Next
|
||||
</a>
|
||||
@@ -1,22 +1,14 @@
|
||||
@model CatalogItemViewModel
|
||||
|
||||
|
||||
<form asp-controller="Basket" asp-action="AddToBasket">
|
||||
|
||||
<form asp-page="/Basket/Index" method="post">
|
||||
<img class="esh-catalog-thumbnail" src="@Model.PictureUri" />
|
||||
<input class="esh-catalog-button" type="submit" value="[ ADD TO BASKET ]" />
|
||||
|
||||
<div class="esh-catalog-name">
|
||||
<span>@Model.Name</span>
|
||||
</div>
|
||||
<div class="esh-catalog-price">
|
||||
<span>@Model.Price.ToString("N2")</span>
|
||||
</div>
|
||||
@*<input type="hidden" asp-for="@Model.CatalogBrand" name="brand" />
|
||||
<input type="hidden" asp-for="@Model.CatalogBrandId" name="brandId" />
|
||||
<input type="hidden" asp-for="@Model.CatalogType" name="type" />
|
||||
<input type="hidden" asp-for="@Model.CatalogTypeId" name="typeId" />
|
||||
<input type="hidden" asp-for="@Model.Description" name="description" />*@
|
||||
<input type="hidden" asp-for="@Model.Id" name="id" />
|
||||
<input type="hidden" asp-for="@Model.Name" name="name" />
|
||||
<input type="hidden" asp-for="@Model.PictureUri" name="pictureUri" />
|
||||
9
src/Web/Pages/_ViewImports.cshtml
Normal file
9
src/Web/Pages/_ViewImports.cshtml
Normal file
@@ -0,0 +1,9 @@
|
||||
@using Microsoft.eShopWeb.Web
|
||||
@using Microsoft.eShopWeb.Web.ViewModels
|
||||
@using Microsoft.eShopWeb.Web.ViewModels.Account
|
||||
@using Microsoft.eShopWeb.Web.ViewModels.Manage
|
||||
@using Microsoft.eShopWeb.Web.Pages
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
@using Microsoft.eShopWeb.Infrastructure.Identity
|
||||
@namespace Microsoft.eShopWeb.Web.Pages
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
3
src/Web/Pages/_ViewStart.cshtml
Normal file
3
src/Web/Pages/_ViewStart.cshtml
Normal file
@@ -0,0 +1,3 @@
|
||||
@{
|
||||
Layout = "_Layout";
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.eShopWeb.Infrastructure.Data;
|
||||
using System;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.eShopWeb.Infrastructure.Identity;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
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
|
||||
{
|
||||
@@ -41,7 +41,6 @@ namespace Microsoft.eShopWeb.Web
|
||||
|
||||
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
|
||||
WebHost.CreateDefaultBuilder(args)
|
||||
.UseUrls("http://0.0.0.0:5106")
|
||||
.UseStartup<Startup>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:5106/",
|
||||
"sslPort": 0
|
||||
"applicationUrl": "http://localhost:17469",
|
||||
"sslPort": 44315
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
@@ -15,13 +15,13 @@
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"eShopWeb": {
|
||||
"Web - PROD": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "http://localhost:5106"
|
||||
"ASPNETCORE_ENVIRONMENT": "Production"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Specifications;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Specifications;
|
||||
using Microsoft.eShopWeb.Web.Interfaces;
|
||||
using Microsoft.eShopWeb.Web.ViewModels;
|
||||
using Microsoft.eShopWeb.Web.Pages.Basket;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
@@ -30,7 +30,7 @@ namespace Microsoft.eShopWeb.Web.Services
|
||||
var basketSpec = new BasketWithItemsSpecification(userName);
|
||||
var basket = (await _basketRepository.ListAsync(basketSpec)).FirstOrDefault();
|
||||
|
||||
if(basket == null)
|
||||
if (basket == null)
|
||||
{
|
||||
return await CreateBasketForUser(userName);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Specifications;
|
||||
using Microsoft.eShopWeb.Web.ViewModels;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.eShopWeb.Web.ViewModels;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using System;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Specifications;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.Services
|
||||
{
|
||||
@@ -42,14 +42,12 @@ namespace Microsoft.eShopWeb.Web.Services
|
||||
_logger.LogInformation("GetCatalogItems called.");
|
||||
|
||||
var filterSpecification = new CatalogFilterSpecification(brandId, typeId);
|
||||
var root = _itemRepository.List(filterSpecification);
|
||||
var filterPaginatedSpecification =
|
||||
new CatalogFilterPaginatedSpecification(itemsPage * pageIndex, itemsPage, brandId, typeId);
|
||||
|
||||
var totalItems = root.Count();
|
||||
|
||||
var itemsOnPage = root
|
||||
.Skip(itemsPage * pageIndex)
|
||||
.Take(itemsPage)
|
||||
.ToList();
|
||||
// the implementation below using ForEach and Count. We need a List.
|
||||
var itemsOnPage = _itemRepository.List(filterPaginatedSpecification).ToList();
|
||||
var totalItems = _itemRepository.Count(filterSpecification);
|
||||
|
||||
itemsOnPage.ForEach(x =>
|
||||
{
|
||||
|
||||
17
src/Web/SlugifyParameterTransformer.cs
Normal file
17
src/Web/SlugifyParameterTransformer.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web
|
||||
{
|
||||
|
||||
public class SlugifyParameterTransformer : IOutboundParameterTransformer
|
||||
{
|
||||
public string TransformOutbound(object value)
|
||||
{
|
||||
if (value == null) { return null; }
|
||||
|
||||
// Slugify value
|
||||
return Regex.Replace(value.ToString(), "([a-z])([A-Z])", "$1-$2").ToLower();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,30 @@
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.UI;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Services;
|
||||
using Microsoft.eShopWeb.Infrastructure.Data;
|
||||
using Microsoft.eShopWeb.Infrastructure.Identity;
|
||||
using Microsoft.eShopWeb.Infrastructure.Logging;
|
||||
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.HealthChecks;
|
||||
using Microsoft.eShopWeb.Web.Interfaces;
|
||||
using Microsoft.eShopWeb.Web.Services;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
using Newtonsoft.Json;
|
||||
using Swashbuckle.AspNetCore.Swagger;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web
|
||||
@@ -65,23 +76,17 @@ namespace Microsoft.eShopWeb.Web
|
||||
ConfigureServices(services);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddIdentity<ApplicationUser, IdentityRole>()
|
||||
.AddEntityFrameworkStores<AppIdentityDbContext>()
|
||||
.AddDefaultTokenProviders();
|
||||
ConfigureCookieSettings(services);
|
||||
|
||||
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
|
||||
};
|
||||
});
|
||||
services.AddIdentity<ApplicationUser, IdentityRole>()
|
||||
.AddDefaultUI(UIFramework.Bootstrap4)
|
||||
.AddEntityFrameworkStores<AppIdentityDbContext>()
|
||||
.AddDefaultTokenProviders();
|
||||
|
||||
services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
|
||||
services.AddScoped(typeof(IAsyncRepository<>), typeof(EfRepository<>));
|
||||
@@ -101,40 +106,132 @@ namespace Microsoft.eShopWeb.Web
|
||||
// Add memory cache services
|
||||
services.AddMemoryCache();
|
||||
|
||||
services.AddMvc()
|
||||
.SetCompatibilityVersion(AspNetCore.Mvc.CompatibilityVersion.Version_2_1);
|
||||
services.AddRouting(options =>
|
||||
{
|
||||
// Replace the type and the name used to refer to it with your own
|
||||
// IOutboundParameterTransformer implementation
|
||||
options.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer);
|
||||
});
|
||||
|
||||
_services = services;
|
||||
services.AddMvc(options =>
|
||||
{
|
||||
options.Conventions.Add(new RouteTokenTransformerConvention(
|
||||
new SlugifyParameterTransformer()));
|
||||
}
|
||||
)
|
||||
.AddRazorPagesOptions(options =>
|
||||
{
|
||||
options.Conventions.AuthorizePage("/Basket/Checkout");
|
||||
})
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
|
||||
|
||||
services.AddHttpContextAccessor();
|
||||
services.AddSwaggerGen(c =>
|
||||
{
|
||||
c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });
|
||||
});
|
||||
|
||||
services.AddHealthChecks()
|
||||
.AddCheck<HomePageHealthCheck>("home_page_health_check")
|
||||
.AddCheck<ApiHealthCheck>("api_health_check");
|
||||
|
||||
_services = services; // used to debug registered 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.
|
||||
public void Configure(IApplicationBuilder app,
|
||||
IHostingEnvironment env)
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, LinkGenerator linkGenerator)
|
||||
{
|
||||
//app.UseDeveloperExceptionPage();
|
||||
app.UseHealthChecks("/health",
|
||||
new HealthCheckOptions
|
||||
{
|
||||
ResponseWriter = async (context, report) =>
|
||||
{
|
||||
var result = JsonConvert.SerializeObject(
|
||||
new
|
||||
{
|
||||
status = report.Status.ToString(),
|
||||
errors = report.Entries.Select(e => new
|
||||
{
|
||||
key = e.Key,
|
||||
value = Enum.GetName(typeof(HealthStatus), e.Value.Status)
|
||||
})
|
||||
});
|
||||
context.Response.ContentType = MediaTypeNames.Application.Json;
|
||||
await context.Response.WriteAsync(result);
|
||||
}
|
||||
});
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
ListAllRegisteredServices(app);
|
||||
ListAllRegisteredServices(app, linkGenerator);
|
||||
app.UseDatabaseErrorPage();
|
||||
}
|
||||
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.UseHttpsRedirection();
|
||||
app.UseStaticFiles();
|
||||
app.UseCookiePolicy();
|
||||
|
||||
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:slugify=Home}/{action:slugify=Index}/{id?}");
|
||||
});
|
||||
}
|
||||
|
||||
private void ListAllRegisteredServices(IApplicationBuilder app)
|
||||
private void ListAllRegisteredServices(IApplicationBuilder app, LinkGenerator linkGenerator)
|
||||
{
|
||||
var homePageLink = linkGenerator.GetPathByAction("Index", "Catalog");
|
||||
var loginLink = linkGenerator.GetPathByAction("SignIn", "Account");
|
||||
app.Map("/allservices", builder => builder.Run(async context =>
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append("<a href=\"");
|
||||
sb.Append(homePageLink);
|
||||
sb.AppendLine("\">Return to site</a> | ");
|
||||
sb.Append("<a href=\"");
|
||||
sb.Append(loginLink);
|
||||
sb.AppendLine("\">Login to site</a>");
|
||||
sb.Append("<h1>All Services</h1>");
|
||||
sb.Append("<table><thead>");
|
||||
sb.Append("<tr><th>Type</th><th>Lifetime</th><th>Instance</th></tr>");
|
||||
@@ -151,5 +248,6 @@ namespace Microsoft.eShopWeb.Web
|
||||
await context.Response.WriteAsync(sb.ToString());
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.ViewModels.Account
|
||||
{
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.ViewModels.Manage
|
||||
namespace Microsoft.eShopWeb.Web.ViewModels.Manage
|
||||
{
|
||||
public class TwoFactorAuthenticationViewModel
|
||||
{
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Microsoft.eShopWeb.Web.ViewModels
|
||||
namespace Microsoft.eShopWeb.Web.ViewModels
|
||||
{
|
||||
public class OrderItemViewModel
|
||||
{
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
@using Microsoft.eShopWeb.Web.ViewModels.Account
|
||||
@model LoginWith2faViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Two-factor authentication";
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
@using System.Collections.Generic
|
||||
@using Microsoft.AspNetCore.Http
|
||||
@using Microsoft.AspNetCore.Http.Authentication
|
||||
@using Microsoft.eShopWeb.Web.ViewModels.Account
|
||||
@model RegisterViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Register";
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
@using Microsoft.eShopWeb.Web.ViewModels.Account
|
||||
@model LoginViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Log in";
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
@using Microsoft.eShopWeb.Web.ViewModels
|
||||
@{
|
||||
ViewData["Title"] = "Checkout Complete";
|
||||
@model BasketViewModel
|
||||
}
|
||||
<section class="esh-catalog-hero">
|
||||
<div class="container">
|
||||
<img class="esh-catalog-title" src="../images/main_banner_text.png" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="container">
|
||||
<h1>Thanks for your Order!</h1>
|
||||
|
||||
<a asp-controller="Catalog" asp-action="Index">Continue Shopping...</a>
|
||||
</div>
|
||||
@@ -18,15 +18,15 @@
|
||||
<label asp-for="Email"></label>
|
||||
@if (Model.IsEmailConfirmed)
|
||||
{
|
||||
<div class="input-group">
|
||||
<input asp-for="Email" class="form-control" />
|
||||
<span class="input-group-addon" aria-hidden="true"><span class="glyphicon glyphicon-ok text-success"></span></span>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input asp-for="Email" class="form-control" />
|
||||
<span class="input-group-addon" aria-hidden="true"><span class="glyphicon glyphicon-ok text-success"></span></span>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<input asp-for="Email" class="form-control" />
|
||||
<button asp-action="SendVerificationEmail" class="btn btn-link">Send verification email</button>
|
||||
<input asp-for="Email" class="form-control" />
|
||||
<button asp-action="SendVerificationEmail" class="btn btn-link">Send verification email</button>
|
||||
}
|
||||
<span asp-validation-for="Email" class="text-danger"></span>
|
||||
</div>
|
||||
@@ -1,5 +1,4 @@
|
||||
@using Microsoft.eShopWeb.Web.ViewModels
|
||||
@model OrderViewModel
|
||||
@model OrderViewModel
|
||||
@{
|
||||
ViewData["Title"] = "My Order History";
|
||||
}
|
||||
@@ -26,14 +25,14 @@
|
||||
</section>
|
||||
|
||||
@*<section class="esh-orders_detail-section">
|
||||
<article class="esh-orders_detail-titles row">
|
||||
<section class="esh-orders_detail-title col-xs-12">Description</section>
|
||||
</article>
|
||||
<article class="esh-orders_detail-titles row">
|
||||
<section class="esh-orders_detail-title col-xs-12">Description</section>
|
||||
</article>
|
||||
|
||||
<article class="esh-orders_detail-items row">
|
||||
<section class="esh-orders_detail-item col-xs-12">@Model.Description</section>
|
||||
</article>
|
||||
</section>*@
|
||||
<article class="esh-orders_detail-items row">
|
||||
<section class="esh-orders_detail-item col-xs-12">@Model.Description</section>
|
||||
</article>
|
||||
</section>*@
|
||||
|
||||
<section class="esh-orders_detail-section">
|
||||
<article class="esh-orders_detail-titles row">
|
||||
@@ -81,7 +80,7 @@
|
||||
|
||||
<article class="esh-orders_detail-items row">
|
||||
<section class="esh-orders_detail-item col-xs-9"></section>
|
||||
<section class="esh-orders_detail-item esh-orders_detail-item--mark col-xs-2">$ @Model.Total</section>
|
||||
<section class="esh-orders_detail-item esh-orders_detail-item--mark col-xs-2">$ @Model.Total.ToString("N2")</section>
|
||||
</article>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
@using Microsoft.eShopWeb.Web.ViewModels
|
||||
@model IEnumerable<OrderViewModel>
|
||||
@model IEnumerable<OrderViewModel>
|
||||
@{
|
||||
ViewData["Title"] = "My Order History";
|
||||
}
|
||||
25
src/Web/Views/Shared/_CookieConsentPartial.cshtml
Normal file
25
src/Web/Views/Shared/_CookieConsentPartial.cshtml
Normal 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>
|
||||
}
|
||||
@@ -1,77 +1,66 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - Microsoft.eShopOnWeb</title>
|
||||
|
||||
<environment names="Development">
|
||||
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
|
||||
<link rel="stylesheet" href="~/css/app.css" />
|
||||
</environment>
|
||||
<environment names="Staging,Production">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.5/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" />
|
||||
<link rel="stylesheet" href="~/css/app.min.css" asp-append-version="true" />
|
||||
</environment>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - Microsoft.eShopOnWeb</title>
|
||||
<environment names="Development">
|
||||
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
|
||||
<link rel="stylesheet" href="~/css/app.css" />
|
||||
</environment>
|
||||
<environment names="Staging,Production">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.5/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" />
|
||||
<link rel="stylesheet" href="~/css/app.min.css" asp-append-version="true" />
|
||||
</environment>
|
||||
<link rel="stylesheet" href="~/css/app.component.css" />
|
||||
<link rel="stylesheet" href="~/css/basket/basket.component.css" />
|
||||
<link rel="stylesheet" href="~/css/catalog/pager.css" />
|
||||
<link rel="stylesheet" href="~/css/catalog/catalog.component.css" />
|
||||
<link rel="stylesheet" href="~/css/catalog/catalog.component.css" />
|
||||
<link rel="stylesheet" href="~/css/basket/basket-status/basket-status.component.css" />
|
||||
<link rel="stylesheet" href="~/css/orders/orders.component.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header class="navbar navbar-light navbar-static-top">
|
||||
<div class="container">
|
||||
<article class="row">
|
||||
|
||||
<section class="col-lg-7 col-md-6 col-xs-12">
|
||||
<a asp-area="" asp-controller="Catalog" asp-action="Index" class="navbar-brand">
|
||||
<img src="../images/brand.png" alt="eShop On Web"/>
|
||||
</a>
|
||||
</section>
|
||||
<header class="navbar navbar-light navbar-static-top">
|
||||
<div class="container">
|
||||
<article class="row">
|
||||
<section class="col-lg-7 col-md-6 col-xs-12">
|
||||
<a asp-area="" asp-page="/Index" class="navbar-brand">
|
||||
<img src="~/images/brand.png" alt="eShop On Web" />
|
||||
</a>
|
||||
</section>
|
||||
<partial name="_LoginPartial" />
|
||||
</article>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@RenderBody()
|
||||
|
||||
|
||||
<footer class="esh-app-footer">
|
||||
<div class="container">
|
||||
<article class="row">
|
||||
|
||||
<section class="col-sm-6">
|
||||
</section>
|
||||
|
||||
<section class="col-sm-6">
|
||||
<div class="esh-app-footer-text hidden-xs"> e-ShopOnWeb. All rights reserved </div>
|
||||
</section>
|
||||
|
||||
</article>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<environment names="Development">
|
||||
<script src="~/lib/jquery/dist/jquery.js"></script>
|
||||
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
|
||||
<script src="~/js/site.js" asp-append-version="true"></script>
|
||||
</environment>
|
||||
<environment names="Staging,Production">
|
||||
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"
|
||||
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
|
||||
asp-fallback-test="window.jQuery">
|
||||
</script>
|
||||
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/bootstrap.min.js"
|
||||
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
|
||||
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal">
|
||||
</script>
|
||||
<script src="~/js/site.min.js" asp-append-version="true"></script>
|
||||
</environment>
|
||||
|
||||
@RenderSection("scripts", required: false)
|
||||
</article>
|
||||
</div>
|
||||
</header>
|
||||
@RenderBody()
|
||||
<footer class="esh-app-footer">
|
||||
<div class="container">
|
||||
<article class="row">
|
||||
<section class="col-sm-6"></section>
|
||||
<section class="col-sm-6">
|
||||
<div class="esh-app-footer-text hidden-xs"> e-ShopOnWeb. All rights reserved </div>
|
||||
</section>
|
||||
</article>
|
||||
</div>
|
||||
</footer>
|
||||
<environment names="Development">
|
||||
<script src="~/lib/jquery/dist/jquery.js"></script>
|
||||
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
|
||||
<script src="~/js/site.js" asp-append-version="true"></script>
|
||||
</environment>
|
||||
<environment names="Staging,Production">
|
||||
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"
|
||||
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
|
||||
asp-fallback-test="window.jQuery">
|
||||
</script>
|
||||
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/bootstrap.min.js"
|
||||
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
|
||||
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal">
|
||||
</script>
|
||||
<script src="~/js/site.min.js" asp-append-version="true"></script>
|
||||
</environment>
|
||||
@RenderSection("scripts", required: false)
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,66 +1,55 @@
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
|
||||
@if (Context.User.Identity.IsAuthenticated)
|
||||
@if (Context.User.Identity.IsAuthenticated)
|
||||
{
|
||||
<section class="col-lg-4 col-md-5 col-xs-12">
|
||||
<div class="esh-identity">
|
||||
<form asp-area="" asp-controller="Account" asp-action="SignOut" method="post" id="logoutForm" class="navbar-right">
|
||||
<section class="esh-identity-section">
|
||||
<section class="col-lg-4 col-md-5 col-xs-12">
|
||||
<div class="esh-identity">
|
||||
<form asp-area="" asp-controller="Account" asp-action="SignOut" method="post" id="logoutForm" class="navbar-right">
|
||||
<section class="esh-identity-section">
|
||||
@*<div class="esh-identity-name">@User.FindFirst(x => x.Type == "preferred_username").Value</div>*@
|
||||
<img class="esh-identity-image" src="~/images/arrow-down.png">
|
||||
</section>
|
||||
<section class="esh-identity-drop">
|
||||
<a class="esh-identity-item"
|
||||
asp-controller="Order"
|
||||
asp-action="MyOrders">
|
||||
<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-controller="Manage"
|
||||
asp-action="MyAccount">
|
||||
<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>
|
||||
|
||||
@*<div class="esh-identity-name">@User.FindFirst(x => x.Type == "preferred_username").Value</div>*@
|
||||
<img class="esh-identity-image" src="~/images/arrow-down.png">
|
||||
</section>
|
||||
|
||||
<section class="esh-identity-drop">
|
||||
|
||||
<a class="esh-identity-item"
|
||||
asp-controller="Order"
|
||||
asp-action="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-controller="Manage"
|
||||
asp-action="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", User.Identity.Name)
|
||||
</section>
|
||||
<section class="col-lg-1 col-xs-12">
|
||||
@await Component.InvokeAsync("Basket", User.Identity.Name)
|
||||
</section>
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
<section class="col-lg-1 col-lg-offset-3 col-md-3 col-xs-6">
|
||||
<div class="esh-identity">
|
||||
<section class="esh-identity-section">
|
||||
<div class="esh-identity-item">
|
||||
<section class="col-lg-1 col-lg-offset-3 col-md-3 col-xs-6">
|
||||
<div class="esh-identity">
|
||||
<section class="esh-identity-section">
|
||||
<div class="esh-identity-item">
|
||||
<a asp-area="" asp-controller="Account" asp-action="SignIn" class="esh-identity-name esh-identity-name--upper">
|
||||
Login
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<a asp-area="" asp-controller="Account" asp-action="SignIn" class="esh-identity-name esh-identity-name--upper">
|
||||
Login
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="col-lg-1 col-xs-12">
|
||||
@await Component.InvokeAsync("Basket")
|
||||
</section>
|
||||
<section class="col-lg-1 col-xs-12">
|
||||
@await Component.InvokeAsync("Basket")
|
||||
</section>
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
@using Microsoft.eShopWeb.Web.ViewModels
|
||||
@using Microsoft.eShopWeb.Web.ViewModels.Account
|
||||
@using Microsoft.eShopWeb.Web.ViewModels.Manage
|
||||
@using Microsoft.eShopWeb.Web.Pages
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
@using Microsoft.eShopWeb.Infrastructure.Identity
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@namespace Microsoft.eShopWeb.Web.Pages
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
<RootNamespace>Microsoft.eShopWeb.Web</RootNamespace>
|
||||
<UserSecretsId>aspnet-Web2-1FA3F72E-E7E3-4360-9E49-1CCCD7FE85F7</UserSecretsId>
|
||||
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dapper" Version="1.50.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.1.0" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="4.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Views\Catalog\" />
|
||||
<Folder Include="wwwroot\fonts\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -37,6 +38,98 @@
|
||||
<Content Update="appsettings.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<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\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\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\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\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\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\Shared\Components\Basket\Default.cshtml" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
{
|
||||
"Logging": {
|
||||
"IncludeScopes": false,
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"System": "Information",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"Default": "Warning",
|
||||
"Microsoft": "Warning",
|
||||
"System": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"name": "asp.net",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"bootstrap": "3.3.7",
|
||||
"jquery": "2.2.0",
|
||||
"jquery-validation": "1.14.0",
|
||||
"jquery-validation-unobtrusive": "3.2.6"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"name": "jquery-validation",
|
||||
"homepage": "http://jqueryvalidation.org/",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/jzaefferer/jquery-validation.git"
|
||||
},
|
||||
"authors": [
|
||||
"Jörn Zaefferer <joern.zaefferer@gmail.com>"
|
||||
],
|
||||
"description": "Form validation made easy",
|
||||
"main": "dist/jquery.validate.js",
|
||||
"keywords": [
|
||||
"forms",
|
||||
"validation",
|
||||
"validate"
|
||||
],
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"demo",
|
||||
"lib"
|
||||
],
|
||||
"dependencies": {
|
||||
"jquery": ">= 1.7.2"
|
||||
},
|
||||
"version": "1.14.0",
|
||||
"_release": "1.14.0",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "1.14.0",
|
||||
"commit": "c1343fb9823392aa9acbe1c3ffd337b8c92fed48"
|
||||
},
|
||||
"_source": "git://github.com/jzaefferer/jquery-validation.git",
|
||||
"_target": ">=1.8",
|
||||
"_originalSource": "jquery-validation"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"directory": "wwwroot/lib"
|
||||
}
|
||||
3
src/WebRazorPages/Areas/Identity/Pages/_ViewStart.cshtml
Normal file
3
src/WebRazorPages/Areas/Identity/Pages/_ViewStart.cshtml
Normal file
@@ -0,0 +1,3 @@
|
||||
@{
|
||||
Layout = "/Pages/Shared/_Layout.cshtml";
|
||||
}
|
||||
16
src/WebRazorPages/Data/ApplicationDbContext.cs
Normal file
16
src/WebRazorPages/Data/ApplicationDbContext.cs
Normal 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
236
src/WebRazorPages/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs
generated
Normal file
236
src/WebRazorPages/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs
generated
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
# RUN COMMAND
|
||||
# docker run --name eshopweb --rm -it -p 5107:5107 webrazor
|
||||
FROM microsoft/dotnet:2.1-sdk AS build
|
||||
FROM microsoft/dotnet:2.2-sdk AS build
|
||||
WORKDIR /app
|
||||
|
||||
COPY *.sln .
|
||||
@@ -17,7 +17,7 @@ RUN dotnet restore
|
||||
|
||||
RUN dotnet publish -c Release -o out
|
||||
|
||||
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS runtime
|
||||
FROM microsoft/dotnet:2.2-aspnetcore-runtime AS runtime
|
||||
WORKDIR /app
|
||||
COPY --from=build /app/src/WebRazorPages/out ./
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user