diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index 54d859f..aa8d926 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -3,7 +3,8 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
-FROM mcr.microsoft.com/dotnet/sdk:6.0
+FROM mcr.microsoft.com/dotnet/sdk:7.0
+
# This Dockerfile adds a non-root user with sudo access. Use the "remoteUser"
# property in devcontainer.json to use it. On Linux, the container user's GID/UIDs
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 046068a..1606d8e 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -25,15 +25,22 @@
// Comment out to connect as root user. See https://aka.ms/vscode-remote/containers/non-root.
// make sure this is the same as USERNAME above
"remoteUser": "vscode",
+ "runArgs": [
+ "-v",
+ "/var/run/docker.sock:/var/run/docker.sock"
+ ],
+ // Set *default* container specific settings.json values on container create.
+ "settings": {
+ "terminal.integrated.profiles.linux": {
+ "bash": {
+ "path": "bash",
+ "icon": "terminal-bash"
+ }
+ }
+ },
- // Set *default* container specific settings.json values on container create.
- "settings": {
- "terminal.integrated.shell.linux": "/bin/bash"
- },
-
- // Add the IDs of extensions you want installed when the container is created.
- "extensions": [
- "ms-azuretools.azure-dev",
+ // Add the IDs of extensions you want installed when the container is created.
+ "extensions": [
"ms-dotnettools.csharp",
"formulahendry.dotnet-test-explorer",
"ms-vscode.vscode-node-azure-pack",
diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml
index 4fcc6d4..d5b7ee8 100644
--- a/.github/workflows/dotnetcore.yml
+++ b/.github/workflows/dotnetcore.yml
@@ -12,7 +12,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
- dotnet-version: '6.0.x'
+ dotnet-version: '7.0.x'
include-prerelease: true
- name: Build with dotnet
diff --git a/.github/workflows/richnav.yml b/.github/workflows/richnav.yml
index c21c216..977ee7c 100644
--- a/.github/workflows/richnav.yml
+++ b/.github/workflows/richnav.yml
@@ -12,7 +12,7 @@ jobs:
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
- dotnet-version: 3.1.x
+ dotnet-version: 7.0.x
- name: Build with dotnet
run: dotnet build ./eShopOnWeb.sln --configuration Release
diff --git a/.vscode/launch.json b/.vscode/launch.json
index d375cae..d6ed320 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -10,7 +10,7 @@
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
- "program": "${workspaceFolder}/src/Web/bin/Debug/net5.0/Web.dll",
+ "program": "${workspaceFolder}/src/Web/bin/Debug/net7.0/Web.dll",
"args": [],
"cwd": "${workspaceFolder}/src/Web",
"stopAtEntry": false,
diff --git a/Directory.Packages.props b/Directory.Packages.props
new file mode 100644
index 0000000..4573d60
--- /dev/null
+++ b/Directory.Packages.props
@@ -0,0 +1,68 @@
+
+
+ true
+ net7.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index d10d35b..9f8fa72 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@ The **eShopOnWeb** sample is related to the [eShopOnContainers](https://github.c
The goal for this sample is to demonstrate some of the principles and patterns described in the [eBook](https://aka.ms/webappebook). It is not meant to be an eCommerce reference application, and as such it does not implement many features that would be obvious and/or essential to a real eCommerce application.
> ### VERSIONS
-> #### The `main` branch is currently running ASP.NET Core 6.0.
+> #### The `main` branch is currently running ASP.NET Core 7.0.
> #### Older versions are tagged.
## Topics (eBook TOC)
@@ -47,7 +47,9 @@ The store's home page should look like this:

-Most of the site's functionality works with just the web application running. However, the site's Admin page relies on Blazor WebAssembly running in the browser, and it must communicate with the server using the site's PublicApi web application. You'll need to also run this project. You can configure Visual Studio to start multiple projects, or just go to the PublicApi folder in a terminal window and run `dotnet run` from there. After that from the Web folder you should run `dotnet run --launch-profile Web`. Now you should be able to browse to `https://localhost:5001/`. Note that if you use this approach, you'll need to stop the application manually in order to build the solution (otherwise you'll get file locking errors).
+Most of the site's functionality works with just the web application running. However, the site's Admin page relies on Blazor WebAssembly running in the browser, and it must communicate with the server using the site's PublicApi web application. You'll need to also run this project. You can configure Visual Studio to start multiple projects, or just go to the PublicApi folder in a terminal window and run `dotnet run` from there. After that from the Web folder you should run `dotnet run --launch-profile Web`. Now you should be able to browse to `https://localhost:5001/`. The admin part in Blazor is accessible to `https://localhost:5001/admin`
+
+Note that if you use this approach, you'll need to stop the application manually in order to build the solution (otherwise you'll get file locking errors).
After cloning or downloading the sample you must setup your database.
To use the sample with a persistent database, you will need to run its Entity Framework Core migrations before you will be able to run the app.
diff --git a/eShopOnWeb.sln b/eShopOnWeb.sln
index 2adaaf8..e878f9a 100755
--- a/eShopOnWeb.sln
+++ b/eShopOnWeb.sln
@@ -24,6 +24,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0BD72BEA-EF42-4B72-8B69-12A39EC76FBA}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
+ Directory.Packages.props = Directory.Packages.props
docker-compose.override.yml = docker-compose.override.yml
docker-compose.yml = docker-compose.yml
.github\workflows\dotnetcore.yml = .github\workflows\dotnetcore.yml
@@ -38,7 +39,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorAdmin", "src\BlazorAd
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorShared", "src\BlazorShared\BlazorShared.csproj", "{715CF7AF-A1EE-40A6-94A0-8DA3F3B2CAE9}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PublicApiIntegrationTests", "tests\PublicApiIntegrationTests\PublicApiIntegrationTests.csproj", "{D53EF010-8F8C-4337-A059-456E19D8AE63}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PublicApiIntegrationTests", "tests\PublicApiIntegrationTests\PublicApiIntegrationTests.csproj", "{D53EF010-8F8C-4337-A059-456E19D8AE63}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/global.json b/global.json
index 957199c..8ec4b2b 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "6.0.x",
+ "version": "7.0.x",
"rollForward": "latestFeature"
}
}
diff --git a/src/ApplicationCore/ApplicationCore.csproj b/src/ApplicationCore/ApplicationCore.csproj
index 2d2c5cd..a0a5bbe 100644
--- a/src/ApplicationCore/ApplicationCore.csproj
+++ b/src/ApplicationCore/ApplicationCore.csproj
@@ -1,18 +1,16 @@
-
- net6.0
+
Microsoft.eShopWeb.ApplicationCore
enable
-
-
-
-
-
-
+
+
+
+
+
diff --git a/src/BlazorAdmin/BlazorAdmin.csproj b/src/BlazorAdmin/BlazorAdmin.csproj
index 5eb9251..393b330 100644
--- a/src/BlazorAdmin/BlazorAdmin.csproj
+++ b/src/BlazorAdmin/BlazorAdmin.csproj
@@ -1,19 +1,14 @@
-
-
-
- net6.0
-
-
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/src/BlazorAdmin/CustomAuthStateProvider.cs b/src/BlazorAdmin/CustomAuthStateProvider.cs
index b12d232..30cf42c 100644
--- a/src/BlazorAdmin/CustomAuthStateProvider.cs
+++ b/src/BlazorAdmin/CustomAuthStateProvider.cs
@@ -63,7 +63,7 @@ public class CustomAuthStateProvider : AuthenticationStateProvider
if (user == null || !user.IsAuthenticated)
{
- return null;
+ return new ClaimsPrincipal(new ClaimsIdentity());
}
var identity = new ClaimsIdentity(
diff --git a/src/BlazorAdmin/Pages/Logout.razor b/src/BlazorAdmin/Pages/Logout.razor
index ddcd25a..ada679c 100644
--- a/src/BlazorAdmin/Pages/Logout.razor
+++ b/src/BlazorAdmin/Pages/Logout.razor
@@ -7,7 +7,7 @@
protected override async Task OnInitializedAsync()
{
- await HttpClient.PostAsync("Identity/Account/Logout", null);
+ await HttpClient.PostAsync("User/Logout", null);
await new Route(JSRuntime).RouteOutside("/Identity/Account/Login");
}
diff --git a/src/BlazorAdmin/Shared/RedirectToLogin.razor b/src/BlazorAdmin/Shared/RedirectToLogin.razor
index 810a66e..de9c49d 100644
--- a/src/BlazorAdmin/Shared/RedirectToLogin.razor
+++ b/src/BlazorAdmin/Shared/RedirectToLogin.razor
@@ -1,9 +1,12 @@
-@inject NavigationManager Navigation
+@using System.Web;
+
+@inject NavigationManager Navigation
+@inject IJSRuntime JsRuntime
@code {
protected override void OnInitialized()
- {
- Navigation.NavigateTo($"Identity/Account/Login?returnUrl=" +
- $"/{Uri.EscapeDataString(Navigation.ToBaseRelativePath(Navigation.Uri))}");
+ {
+ var returnUrl = HttpUtility.UrlEncode($"/{Uri.EscapeDataString(Navigation.ToBaseRelativePath(Navigation.Uri))}");
+ JsRuntime.InvokeVoidAsync("location.replace", $"Identity/Account/Login?returnUrl={returnUrl}");
}
}
\ No newline at end of file
diff --git a/src/BlazorShared/BlazorShared.csproj b/src/BlazorShared/BlazorShared.csproj
index c0aa99c..8cd1e29 100644
--- a/src/BlazorShared/BlazorShared.csproj
+++ b/src/BlazorShared/BlazorShared.csproj
@@ -1,14 +1,13 @@
-
- net6.0
+
BlazorShared
BlazorShared
-
-
+
+
diff --git a/src/Infrastructure/Infrastructure.csproj b/src/Infrastructure/Infrastructure.csproj
index a0be8bb..026a8ca 100644
--- a/src/Infrastructure/Infrastructure.csproj
+++ b/src/Infrastructure/Infrastructure.csproj
@@ -1,17 +1,16 @@
-
- net6.0
+
Microsoft.eShopWeb.Infrastructure
enable
-
-
-
-
-
+
+
+
+
+
diff --git a/src/PublicApi/CatalogBrandEndpoints/CatalogBrandListEndpoint.cs b/src/PublicApi/CatalogBrandEndpoints/CatalogBrandListEndpoint.cs
index dce823e..32b3d0b 100644
--- a/src/PublicApi/CatalogBrandEndpoints/CatalogBrandListEndpoint.cs
+++ b/src/PublicApi/CatalogBrandEndpoints/CatalogBrandListEndpoint.cs
@@ -13,9 +13,8 @@ namespace Microsoft.eShopWeb.PublicApi.CatalogBrandEndpoints;
///
/// List Catalog Brands
///
-public class CatalogBrandListEndpoint : IEndpoint
+public class CatalogBrandListEndpoint : IEndpoint>
{
- private IRepository _catalogBrandRepository;
private readonly IMapper _mapper;
public CatalogBrandListEndpoint(IMapper mapper)
@@ -28,18 +27,17 @@ public class CatalogBrandListEndpoint : IEndpoint
app.MapGet("api/catalog-brands",
async (IRepository catalogBrandRepository) =>
{
- _catalogBrandRepository = catalogBrandRepository;
- return await HandleAsync();
+ return await HandleAsync(catalogBrandRepository);
})
.Produces()
.WithTags("CatalogBrandEndpoints");
}
- public async Task HandleAsync()
+ public async Task HandleAsync(IRepository catalogBrandRepository)
{
var response = new ListCatalogBrandsResponse();
- var items = await _catalogBrandRepository.ListAsync();
+ var items = await catalogBrandRepository.ListAsync();
response.CatalogBrands.AddRange(items.Select(_mapper.Map));
diff --git a/src/PublicApi/CatalogItemEndpoints/CatalogItemGetByIdEndpoint.cs b/src/PublicApi/CatalogItemEndpoints/CatalogItemGetByIdEndpoint.cs
index a1f6011..9f15c72 100644
--- a/src/PublicApi/CatalogItemEndpoints/CatalogItemGetByIdEndpoint.cs
+++ b/src/PublicApi/CatalogItemEndpoints/CatalogItemGetByIdEndpoint.cs
@@ -11,9 +11,8 @@ namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints;
///
/// Get a Catalog Item by Id
///
-public class CatalogItemGetByIdEndpoint : IEndpoint
+public class CatalogItemGetByIdEndpoint : IEndpoint>
{
- private IRepository _itemRepository;
private readonly IUriComposer _uriComposer;
public CatalogItemGetByIdEndpoint(IUriComposer uriComposer)
@@ -26,18 +25,17 @@ public class CatalogItemGetByIdEndpoint : IEndpoint itemRepository) =>
{
- _itemRepository = itemRepository;
- return await HandleAsync(new GetByIdCatalogItemRequest(catalogItemId));
+ return await HandleAsync(new GetByIdCatalogItemRequest(catalogItemId), itemRepository);
})
.Produces()
.WithTags("CatalogItemEndpoints");
}
- public async Task HandleAsync(GetByIdCatalogItemRequest request)
+ public async Task HandleAsync(GetByIdCatalogItemRequest request, IRepository itemRepository)
{
var response = new GetByIdCatalogItemResponse(request.CorrelationId());
- var item = await _itemRepository.GetByIdAsync(request.CatalogItemId);
+ var item = await itemRepository.GetByIdAsync(request.CatalogItemId);
if (item is null)
return Results.NotFound();
diff --git a/src/PublicApi/CatalogItemEndpoints/CatalogItemListPagedEndpoint.cs b/src/PublicApi/CatalogItemEndpoints/CatalogItemListPagedEndpoint.cs
index 308d310..920fe4f 100644
--- a/src/PublicApi/CatalogItemEndpoints/CatalogItemListPagedEndpoint.cs
+++ b/src/PublicApi/CatalogItemEndpoints/CatalogItemListPagedEndpoint.cs
@@ -15,9 +15,8 @@ namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints;
///
/// List Catalog Items (paged)
///
-public class CatalogItemListPagedEndpoint : IEndpoint
+public class CatalogItemListPagedEndpoint : IEndpoint>
{
- private IRepository _itemRepository;
private readonly IUriComposer _uriComposer;
private readonly IMapper _mapper;
@@ -32,19 +31,19 @@ public class CatalogItemListPagedEndpoint : IEndpoint itemRepository) =>
{
- _itemRepository = itemRepository;
- return await HandleAsync(new ListPagedCatalogItemRequest(pageSize, pageIndex, catalogBrandId, catalogTypeId));
- })
+ return await HandleAsync(new ListPagedCatalogItemRequest(pageSize, pageIndex, catalogBrandId, catalogTypeId), itemRepository);
+ })
.Produces()
.WithTags("CatalogItemEndpoints");
}
- public async Task HandleAsync(ListPagedCatalogItemRequest request)
+ public async Task HandleAsync(ListPagedCatalogItemRequest request, IRepository itemRepository)
{
+ await Task.Delay(1000);
var response = new ListPagedCatalogItemResponse(request.CorrelationId());
var filterSpec = new CatalogFilterSpecification(request.CatalogBrandId, request.CatalogTypeId);
- int totalItems = await _itemRepository.CountAsync(filterSpec);
+ int totalItems = await itemRepository.CountAsync(filterSpec);
var pagedSpec = new CatalogFilterPaginatedSpecification(
skip: request.PageIndex.Value * request.PageSize.Value,
@@ -52,7 +51,7 @@ public class CatalogItemListPagedEndpoint : IEndpoint));
foreach (CatalogItemDto item in response.CatalogItems)
diff --git a/src/PublicApi/CatalogItemEndpoints/CreateCatalogItemEndpoint.cs b/src/PublicApi/CatalogItemEndpoints/CreateCatalogItemEndpoint.cs
index 25527f9..c15346f 100644
--- a/src/PublicApi/CatalogItemEndpoints/CreateCatalogItemEndpoint.cs
+++ b/src/PublicApi/CatalogItemEndpoints/CreateCatalogItemEndpoint.cs
@@ -15,9 +15,8 @@ namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints;
///
/// Creates a new Catalog Item
///
-public class CreateCatalogItemEndpoint : IEndpoint
+public class CreateCatalogItemEndpoint : IEndpoint>
{
- private IRepository _itemRepository;
private readonly IUriComposer _uriComposer;
public CreateCatalogItemEndpoint(IUriComposer uriComposer)
@@ -31,26 +30,25 @@ public class CreateCatalogItemEndpoint : IEndpoint itemRepository) =>
{
- _itemRepository = itemRepository;
- return await HandleAsync(request);
+ return await HandleAsync(request, itemRepository);
})
.Produces()
.WithTags("CatalogItemEndpoints");
}
- public async Task HandleAsync(CreateCatalogItemRequest request)
+ public async Task HandleAsync(CreateCatalogItemRequest request, IRepository itemRepository)
{
var response = new CreateCatalogItemResponse(request.CorrelationId());
var catalogItemNameSpecification = new CatalogItemNameSpecification(request.Name);
- var existingCataloogItem = await _itemRepository.CountAsync(catalogItemNameSpecification);
+ var existingCataloogItem = await itemRepository.CountAsync(catalogItemNameSpecification);
if (existingCataloogItem > 0)
{
throw new DuplicateException($"A catalogItem with name {request.Name} already exists");
}
var newItem = new CatalogItem(request.CatalogTypeId, request.CatalogBrandId, request.Description, request.Name, request.Price, request.PictureUri);
- newItem = await _itemRepository.AddAsync(newItem);
+ newItem = await itemRepository.AddAsync(newItem);
if (newItem.Id != 0)
{
@@ -59,7 +57,7 @@ public class CreateCatalogItemEndpoint : IEndpoint
/// Deletes a Catalog Item
///
-public class DeleteCatalogItemEndpoint : IEndpoint
+public class DeleteCatalogItemEndpoint : IEndpoint>
{
- private IRepository _itemRepository;
-
public void AddRoute(IEndpointRouteBuilder app)
{
app.MapDelete("api/catalog-items/{catalogItemId}",
[Authorize(Roles = BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS, AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] async
(int catalogItemId, IRepository itemRepository) =>
{
- _itemRepository = itemRepository;
- return await HandleAsync(new DeleteCatalogItemRequest(catalogItemId));
+ return await HandleAsync(new DeleteCatalogItemRequest(catalogItemId), itemRepository);
})
.Produces()
.WithTags("CatalogItemEndpoints");
}
- public async Task HandleAsync(DeleteCatalogItemRequest request)
+ public async Task HandleAsync(DeleteCatalogItemRequest request, IRepository itemRepository)
{
var response = new DeleteCatalogItemResponse(request.CorrelationId());
- var itemToDelete = await _itemRepository.GetByIdAsync(request.CatalogItemId);
+ var itemToDelete = await itemRepository.GetByIdAsync(request.CatalogItemId);
if (itemToDelete is null)
return Results.NotFound();
- await _itemRepository.DeleteAsync(itemToDelete);
+ await itemRepository.DeleteAsync(itemToDelete);
return Results.Ok(response);
}
diff --git a/src/PublicApi/CatalogItemEndpoints/UpdateCatalogItemEndpoint.cs b/src/PublicApi/CatalogItemEndpoints/UpdateCatalogItemEndpoint.cs
index 2ce0e6c..b923322 100644
--- a/src/PublicApi/CatalogItemEndpoints/UpdateCatalogItemEndpoint.cs
+++ b/src/PublicApi/CatalogItemEndpoints/UpdateCatalogItemEndpoint.cs
@@ -13,9 +13,8 @@ namespace Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints;
///
/// Updates a Catalog Item
///
-public class UpdateCatalogItemEndpoint : IEndpoint
-{
- private IRepository _itemRepository;
+public class UpdateCatalogItemEndpoint : IEndpoint>
+{
private readonly IUriComposer _uriComposer;
public UpdateCatalogItemEndpoint(IUriComposer uriComposer)
@@ -29,25 +28,24 @@ public class UpdateCatalogItemEndpoint : IEndpoint itemRepository) =>
{
- _itemRepository = itemRepository;
- return await HandleAsync(request);
+ return await HandleAsync(request, itemRepository);
})
.Produces()
.WithTags("CatalogItemEndpoints");
}
- public async Task HandleAsync(UpdateCatalogItemRequest request)
+ public async Task HandleAsync(UpdateCatalogItemRequest request, IRepository itemRepository)
{
var response = new UpdateCatalogItemResponse(request.CorrelationId());
- var existingItem = await _itemRepository.GetByIdAsync(request.Id);
-
+ var existingItem = await itemRepository.GetByIdAsync(request.Id);
+
CatalogItem.CatalogItemDetails details = new(request.Name, request.Description, request.Price);
existingItem.UpdateDetails(details);
existingItem.UpdateBrand(request.CatalogBrandId);
existingItem.UpdateType(request.CatalogTypeId);
- await _itemRepository.UpdateAsync(existingItem);
+ await itemRepository.UpdateAsync(existingItem);
var dto = new CatalogItemDto
{
diff --git a/src/PublicApi/CatalogTypeEndpoints/CatalogTypeListEndpoint.cs b/src/PublicApi/CatalogTypeEndpoints/CatalogTypeListEndpoint.cs
index 87aa035..3e36735 100644
--- a/src/PublicApi/CatalogTypeEndpoints/CatalogTypeListEndpoint.cs
+++ b/src/PublicApi/CatalogTypeEndpoints/CatalogTypeListEndpoint.cs
@@ -13,33 +13,31 @@ namespace Microsoft.eShopWeb.PublicApi.CatalogTypeEndpoints;
///
/// List Catalog Types
///
-public class CatalogTypeListEndpoint : IEndpoint
+public class CatalogTypeListEndpoint : IEndpoint>
{
- private IRepository _catalogTypeRepository;
private readonly IMapper _mapper;
public CatalogTypeListEndpoint(IMapper mapper)
- {
+ {
_mapper = mapper;
}
public void AddRoute(IEndpointRouteBuilder app)
{
- app.MapGet("api/catalog-types",
+ app.MapGet("api/catalog-types",
async (IRepository catalogTypeRepository) =>
{
- _catalogTypeRepository = catalogTypeRepository;
- return await HandleAsync();
+ return await HandleAsync(catalogTypeRepository);
})
.Produces()
.WithTags("CatalogTypeEndpoints");
}
- public async Task HandleAsync()
+ public async Task HandleAsync(IRepository catalogTypeRepository)
{
var response = new ListCatalogTypesResponse();
- var items = await _catalogTypeRepository.ListAsync();
+ var items = await catalogTypeRepository.ListAsync();
response.CatalogTypes.AddRange(items.Select(_mapper.Map));
diff --git a/src/PublicApi/Dockerfile b/src/PublicApi/Dockerfile
index f768db5..885a155 100644
--- a/src/PublicApi/Dockerfile
+++ b/src/PublicApi/Dockerfile
@@ -1,11 +1,11 @@
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
-FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
+FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
-FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
+FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /app
COPY . .
#COPY ["src/PublicApi/PublicApi.csproj", "./PublicApi/"]
diff --git a/src/PublicApi/Program.cs b/src/PublicApi/Program.cs
index 7356a62..2a16551 100644
--- a/src/PublicApi/Program.cs
+++ b/src/PublicApi/Program.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Text;
using BlazorShared;
using BlazorShared.Models;
-using MediatR;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
@@ -83,9 +82,8 @@ builder.Services.AddCors(options =>
});
builder.Services.AddControllers();
-
-builder.Services.AddMediatR(typeof(CatalogItem).Assembly);
builder.Services.AddAutoMapper(typeof(MappingProfile).Assembly);
+builder.Configuration.AddEnvironmentVariables();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
diff --git a/src/PublicApi/Properties/launchSettings.json b/src/PublicApi/Properties/launchSettings.json
index fbed524..c44d516 100644
--- a/src/PublicApi/Properties/launchSettings.json
+++ b/src/PublicApi/Properties/launchSettings.json
@@ -1,13 +1,4 @@
{
- "iisSettings": {
- "windowsAuthentication": false,
- "anonymousAuthentication": true,
- "iisExpress": {
- "applicationUrl": "http://localhost:52023",
- "sslPort": 44339
- }
- },
- "$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
@@ -25,6 +16,32 @@
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5099;http://localhost:5098"
+ },
+ "WSL": {
+ "commandName": "WSL2",
+ "launchBrowser": true,
+ "launchUrl": "https://localhost:5099/swagger",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "ASPNETCORE_URLS": "https://localhost:5099;http://localhost:5098"
+ },
+ "distributionName": ""
+ },
+ "Docker": {
+ "commandName": "Docker",
+ "launchBrowser": true,
+ "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
+ "publishAllPorts": true,
+ "useSSL": true
+ }
+ },
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:52023",
+ "sslPort": 44339
}
}
}
\ No newline at end of file
diff --git a/src/PublicApi/PublicApi.csproj b/src/PublicApi/PublicApi.csproj
index 4677879..965ea6d 100644
--- a/src/PublicApi/PublicApi.csproj
+++ b/src/PublicApi/PublicApi.csproj
@@ -1,7 +1,6 @@
-
- net6.0
+
Microsoft.eShopWeb.PublicApi
5b662463-1efd-4bae-bde4-befe0be3e8ff
Linux
@@ -10,28 +9,26 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
-
+
diff --git a/src/Web/.config/dotnet-tools.json b/src/Web/.config/dotnet-tools.json
index 5060fd6..f331fe5 100644
--- a/src/Web/.config/dotnet-tools.json
+++ b/src/Web/.config/dotnet-tools.json
@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"dotnet-ef": {
- "version": "6.0.4",
+ "version": "7.0.2",
"commands": [
"dotnet-ef"
]
diff --git a/src/Web/Areas/Identity/Pages/Account/Logout.cshtml.cs b/src/Web/Areas/Identity/Pages/Account/Logout.cshtml.cs
index 8af0afb..80bb467 100644
--- a/src/Web/Areas/Identity/Pages/Account/Logout.cshtml.cs
+++ b/src/Web/Areas/Identity/Pages/Account/Logout.cshtml.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Linq;
-using System.Security.Claims;
-using System.Threading.Tasks;
+using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Identity;
@@ -10,7 +7,6 @@ using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.Web.Configuration;
using Microsoft.Extensions.Caching.Memory;
-using Microsoft.Extensions.Logging;
namespace Microsoft.eShopWeb.Web.Areas.Identity.Pages.Account;
diff --git a/src/Web/Configuration/ConfigureWebServices.cs b/src/Web/Configuration/ConfigureWebServices.cs
index 478b89d..f89a99a 100644
--- a/src/Web/Configuration/ConfigureWebServices.cs
+++ b/src/Web/Configuration/ConfigureWebServices.cs
@@ -1,8 +1,6 @@
using MediatR;
using Microsoft.eShopWeb.Web.Interfaces;
using Microsoft.eShopWeb.Web.Services;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.eShopWeb.Web.Configuration;
diff --git a/src/Web/Controllers/UserController.cs b/src/Web/Controllers/UserController.cs
index 05d55c2..79968c1 100644
--- a/src/Web/Controllers/UserController.cs
+++ b/src/Web/Controllers/UserController.cs
@@ -1,11 +1,14 @@
-using System.Collections.Generic;
-using System.Linq;
-using System.Security.Claims;
-using System.Threading.Tasks;
+using System.Security.Claims;
using BlazorShared.Authorization;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Cookies;
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.Configuration;
+using Microsoft.Extensions.Caching.Memory;
namespace Microsoft.eShopWeb.Web.Controllers;
@@ -14,10 +17,19 @@ namespace Microsoft.eShopWeb.Web.Controllers;
public class UserController : ControllerBase
{
private readonly ITokenClaimsService _tokenClaimsService;
+ private readonly SignInManager _signInManager;
+ private readonly ILogger _logger;
+ private readonly IMemoryCache _cache;
- public UserController(ITokenClaimsService tokenClaimsService)
+ public UserController(ITokenClaimsService tokenClaimsService,
+ SignInManager signInManager,
+ ILogger logger,
+ IMemoryCache cache)
{
_tokenClaimsService = tokenClaimsService;
+ _signInManager = signInManager;
+ _logger = logger;
+ _cache = cache;
}
[HttpGet]
@@ -26,6 +38,25 @@ public class UserController : ControllerBase
public async Task GetCurrentUser() =>
Ok(await CreateUserInfo(User));
+ [Route("Logout")]
+ [HttpPost]
+ [Authorize]
+ [AllowAnonymous]
+ public async Task Logout()
+ {
+ await _signInManager.SignOutAsync();
+ await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
+ var userId = _signInManager.Context.User.Claims.First(c => c.Type == ClaimTypes.Name);
+ var identityKey = _signInManager.Context.Request.Cookies[ConfigureCookieSettings.IdentifierCookieName];
+ _cache.Set($"{userId.Value}:{identityKey}", identityKey, new MemoryCacheEntryOptions
+ {
+ AbsoluteExpiration = DateTime.Now.AddMinutes(ConfigureCookieSettings.ValidityMinutesPeriod)
+ });
+
+ _logger.LogInformation("User logged out.");
+ return Ok();
+ }
+
private async Task CreateUserInfo(ClaimsPrincipal claimsPrincipal)
{
if (claimsPrincipal.Identity == null || claimsPrincipal.Identity.Name == null || !claimsPrincipal.Identity.IsAuthenticated)
diff --git a/src/Web/Dockerfile b/src/Web/Dockerfile
index 9062398..9a5e23d 100644
--- a/src/Web/Dockerfile
+++ b/src/Web/Dockerfile
@@ -7,7 +7,7 @@
#
# RUN COMMAND
# docker run --name eshopweb --rm -it -p 5106:5106 web
-FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
+FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /app
COPY *.sln .
@@ -17,7 +17,7 @@ RUN dotnet restore
RUN dotnet publish -c Release -o out
-FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS runtime
+FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS runtime
WORKDIR /app
COPY --from=build /app/src/Web/out ./
diff --git a/src/Web/Features/MyOrders/GetMyOrdersHandler.cs b/src/Web/Features/MyOrders/GetMyOrdersHandler.cs
index 6cd64af..125f0a9 100644
--- a/src/Web/Features/MyOrders/GetMyOrdersHandler.cs
+++ b/src/Web/Features/MyOrders/GetMyOrdersHandler.cs
@@ -1,8 +1,4 @@
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediatR;
+using MediatR;
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate;
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
using Microsoft.eShopWeb.ApplicationCore.Specifications;
diff --git a/src/Web/Features/OrderDetails/GetOrderDetailsHandler.cs b/src/Web/Features/OrderDetails/GetOrderDetailsHandler.cs
index dab5050..be7b8dc 100644
--- a/src/Web/Features/OrderDetails/GetOrderDetailsHandler.cs
+++ b/src/Web/Features/OrderDetails/GetOrderDetailsHandler.cs
@@ -1,7 +1,4 @@
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediatR;
+using MediatR;
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate;
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
using Microsoft.eShopWeb.ApplicationCore.Specifications;
diff --git a/src/Web/Program.cs b/src/Web/Program.cs
index a998b28..593232c 100644
--- a/src/Web/Program.cs
+++ b/src/Web/Program.cs
@@ -53,7 +53,7 @@ builder.Services.AddIdentity()
.AddDefaultTokenProviders();
builder.Services.AddScoped();
-
+builder.Configuration.AddEnvironmentVariables();
builder.Services.AddCoreServices(builder.Configuration);
builder.Services.AddWebServices(builder.Configuration);
diff --git a/src/Web/Web.csproj b/src/Web/Web.csproj
index 6ec695d..35c6f0a 100644
--- a/src/Web/Web.csproj
+++ b/src/Web/Web.csproj
@@ -1,7 +1,6 @@
-
- net6.0
+
enable
enable
Microsoft.eShopWeb.Web
@@ -14,28 +13,28 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
diff --git a/src/Web/libman.json b/src/Web/libman.json
index ac8c0f9..d841fcf 100644
--- a/src/Web/libman.json
+++ b/src/Web/libman.json
@@ -3,11 +3,11 @@
"defaultProvider": "cdnjs",
"libraries": [
{
- "library": "jquery@3.3.1",
+ "library": "jquery@3.6.3",
"destination": "wwwroot/lib/jquery/"
},
{
- "library": "twitter-bootstrap@3.3.7",
+ "library": "twitter-bootstrap@5.2.3",
"files": [
"css/bootstrap.css",
"css/bootstrap.css.map",
@@ -19,11 +19,11 @@
"destination": "wwwroot/lib/bootstrap/dist/"
},
{
- "library": "jquery-validation-unobtrusive@3.2.10",
+ "library": "jquery-validation-unobtrusive@4.0.0",
"destination": "wwwroot/lib/jquery-validation-unobtrusive/"
},
{
- "library": "jquery-validate@1.17.0",
+ "library": "jquery-validate@1.19.5",
"destination": "wwwroot/lib/jquery-validate/",
"files": [
"jquery.validate.min.js",
@@ -35,7 +35,7 @@
"destination": "wwwroot/lib/toastr/"
},
{
- "library": "aspnet-signalr@1.0.3",
+ "library": "aspnet-signalr@1.0.27",
"files": [
"signalr.js",
"signalr.min.js"
@@ -43,4 +43,4 @@
"destination": "wwwroot/lib/@aspnet/signalr/dist/browser/"
}
]
-}
\ No newline at end of file
+}
diff --git a/tests/FunctionalTests/FunctionalTests.csproj b/tests/FunctionalTests/FunctionalTests.csproj
index ba3f67d..f484cf9 100644
--- a/tests/FunctionalTests/FunctionalTests.csproj
+++ b/tests/FunctionalTests/FunctionalTests.csproj
@@ -1,7 +1,6 @@
-
- net6.0
+
Microsoft.eShopWeb.FunctionalTests
false
enable
@@ -15,15 +14,12 @@
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers
-
-
-
+
+
+
+
+
+
diff --git a/tests/IntegrationTests/IntegrationTests.csproj b/tests/IntegrationTests/IntegrationTests.csproj
index 7473d83..5876dc3 100644
--- a/tests/IntegrationTests/IntegrationTests.csproj
+++ b/tests/IntegrationTests/IntegrationTests.csproj
@@ -1,17 +1,16 @@
-
- net6.0
+
Microsoft.eShopWeb.IntegrationTests
false
-
-
-
-
-
+
+
+
+
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/tests/PublicApiIntegrationTests/CatalogItemEndpoints/CatalogItemListPagedEndpoint.cs b/tests/PublicApiIntegrationTests/CatalogItemEndpoints/CatalogItemListPagedEndpoint.cs
index 1040463..5eb3036 100644
--- a/tests/PublicApiIntegrationTests/CatalogItemEndpoints/CatalogItemListPagedEndpoint.cs
+++ b/tests/PublicApiIntegrationTests/CatalogItemEndpoints/CatalogItemListPagedEndpoint.cs
@@ -2,7 +2,10 @@
using Microsoft.eShopWeb.PublicApi.CatalogItemEndpoints;
using Microsoft.eShopWeb.Web.ViewModels;
using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System.Collections.Generic;
using System.Linq;
+using System.Net.Http;
+using System.Net;
using System.Threading.Tasks;
namespace PublicApiIntegrationTests.CatalogItemEndpoints
@@ -45,5 +48,26 @@ namespace PublicApiIntegrationTests.CatalogItemEndpoints
Assert.AreEqual(totalExpected, model2.CatalogItems.Count());
}
+
+ [DataTestMethod]
+ [DataRow("catalog-items")]
+ [DataRow("catalog-brands")]
+ [DataRow("catalog-types")]
+ [DataRow("catalog-items/1")]
+ public async Task SuccessFullMutipleParallelCall(string endpointName)
+ {
+ var client = ProgramTest.NewClient;
+ var tasks = new List>();
+
+ for (int i = 0; i < 100; i++)
+ {
+ var task = client.GetAsync($"/api/{endpointName}");
+ tasks.Add(task);
+ }
+ await Task.WhenAll(tasks.ToList());
+ var totalKO = tasks.Count(t => t.Result.StatusCode != HttpStatusCode.OK);
+
+ Assert.AreEqual(0, totalKO);
+ }
}
}
diff --git a/tests/PublicApiIntegrationTests/PublicApiIntegrationTests.csproj b/tests/PublicApiIntegrationTests/PublicApiIntegrationTests.csproj
index d560cac..467bc1f 100644
--- a/tests/PublicApiIntegrationTests/PublicApiIntegrationTests.csproj
+++ b/tests/PublicApiIntegrationTests/PublicApiIntegrationTests.csproj
@@ -1,7 +1,6 @@
-
- net6.0
+
enable
false
@@ -20,11 +19,14 @@
-
-
-
-
-
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/tests/UnitTests/UnitTests.csproj b/tests/UnitTests/UnitTests.csproj
index 7381753..f8bbe01 100644
--- a/tests/UnitTests/UnitTests.csproj
+++ b/tests/UnitTests/UnitTests.csproj
@@ -1,7 +1,6 @@
-
- net6.0
+
enable
Microsoft.eShopWeb.UnitTests
false
@@ -10,18 +9,12 @@
-
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers
-
-
- all
- runtime; build; native; contentfiles; analyzers
-
+
+
+
+
+
+