Browse Source

Fix Null Warnings (#874)

* Fixing null warnings

* Fix null warnings
Fix other compiler warnings
main
Steve Smith 3 years ago
committed by GitHub
parent
commit
d2412a84a9
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      .editorconfig
  2. 1
      Directory.Packages.props
  3. 92
      Everything.sln
  4. 4
      src/Infrastructure/Dependencies.cs
  5. 3
      src/Infrastructure/Identity/AppIdentityDbContextSeed.cs
  6. 1
      src/Infrastructure/Identity/IdentityTokenClaimService.cs
  7. 10
      src/Infrastructure/Identity/UserNotFoundException.cs
  8. 11
      src/PublicApi/AuthEndpoints/AuthenticateEndpoint.ClaimValue.cs
  9. 11
      src/PublicApi/AuthEndpoints/AuthenticateEndpoint.UserInfo.cs
  10. 3
      src/PublicApi/AuthEndpoints/AuthenticateEndpoint.cs
  11. 4
      src/PublicApi/CatalogItemEndpoints/CatalogItemListPagedEndpoint.ListPagedCatalogItemRequest.cs
  12. 6
      src/PublicApi/CatalogItemEndpoints/CatalogItemListPagedEndpoint.cs
  13. 4
      src/PublicApi/CatalogItemEndpoints/UpdateCatalogItemEndpoint.cs
  14. 13
      src/PublicApi/Program.cs
  15. 5
      src/Web/Areas/Identity/Pages/Account/Login.cshtml.cs
  16. 6
      src/Web/Areas/Identity/Pages/Account/Register.cshtml.cs
  17. 7
      src/Web/Configuration/ConfigureCoreServices.cs
  18. 24
      src/Web/Controllers/ManageController.cs
  19. 2
      src/Web/Pages/Index.cshtml.cs
  20. 18
      src/Web/Program.cs
  21. 12
      src/Web/Services/CachedCatalogViewModelService.cs
  22. 9
      src/Web/ViewModels/CatalogIndexViewModel.cs
  23. 10
      src/Web/ViewModels/Manage/RemoveLoginViewModel.cs
  24. 6
      src/Web/ViewModels/OrderViewModel.cs
  25. 5
      src/Web/Views/Manage/ShowRecoverCodes.cshtml
  26. 6
      src/Web/Views/Order/Detail.cshtml
  27. 2
      src/Web/Views/Shared/_LoginPartial.cshtml
  28. 2
      tests/FunctionalTests/Web/Controllers/OrderControllerIndex.cs
  29. 2
      tests/FunctionalTests/Web/Pages/Basket/BasketPageCheckout.cs
  30. 2
      tests/FunctionalTests/Web/Pages/Basket/CheckoutTest.cs
  31. 4
      tests/FunctionalTests/Web/Pages/Basket/IndexTest.cs
  32. 2
      tests/FunctionalTests/Web/WebPageHelpers.cs
  33. 11
      tests/PublicApiIntegrationTests/AuthEndpoints/AuthenticateEndpointTest.cs
  34. 11
      tests/PublicApiIntegrationTests/CatalogItemEndpoints/CatalogItemGetByIdEndpointTest.cs
  35. 15
      tests/PublicApiIntegrationTests/CatalogItemEndpoints/CatalogItemListPagedEndpoint.cs
  36. 11
      tests/PublicApiIntegrationTests/CatalogItemEndpoints/CreateCatalogItemEndpointTest.cs
  37. 11
      tests/PublicApiIntegrationTests/CatalogItemEndpoints/DeleteCatalogItemEndpointTest.cs
  38. 11
      tests/PublicApiIntegrationTests/ProgramTest.cs

8
.editorconfig

@ -141,4 +141,10 @@ csharp_preserve_single_line_blocks = true
############################### ###############################
[*.vb] [*.vb]
# Modifier preferences # Modifier preferences
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion###############################
######################################
# Configure Nullable Reference Types #
######################################
[{**/*Dto.cs,**/*Request.cs,**/*Response.cs}]
# CS8618: Non-nullable field is uninitialized. Consider declaring as nullable.
dotnet_diagnostic.CS8618.severity = none

1
Directory.Packages.props

@ -1,6 +1,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally> <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<TargetFramework>net7.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

92
Everything.sln

@ -0,0 +1,92 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8FF16BDB-352E-42A2-A25F-0B5BC3A17FD7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApplicationCore", "src\ApplicationCore\ApplicationCore.csproj", "{1A5759FF-9990-4CF5-AD78-528452C5EFCC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlazorAdmin", "src\BlazorAdmin\BlazorAdmin.csproj", "{7D7D0B73-4153-4E9B-BBD1-C9D7C8AEE970}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlazorShared", "src\BlazorShared\BlazorShared.csproj", "{6FD75683-D186-4BE3-ABD0-2324650B46B5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure", "src\Infrastructure\Infrastructure.csproj", "{35457566-83CE-44FC-A650-265CC9C544DC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PublicApi", "src\PublicApi\PublicApi.csproj", "{7F226129-E8B0-4274-87A7-347AA4F7D374}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web", "src\Web\Web.csproj", "{7559FA9E-7CFC-4615-8D09-3CDEFC765455}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{BAA5312D-B54C-42D6-A3B9-504DD12F8250}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FunctionalTests", "tests\FunctionalTests\FunctionalTests.csproj", "{020545FF-D985-4274-9FDB-FD8B9B32D2ED}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IntegrationTests", "tests\IntegrationTests\IntegrationTests.csproj", "{D6829485-DD9C-42CE-BEDE-4EB0E81021AC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PublicApiIntegrationTests", "tests\PublicApiIntegrationTests\PublicApiIntegrationTests.csproj", "{698594AE-78D3-429F-B5CC-3A6F6BCE397A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "tests\UnitTests\UnitTests.csproj", "{EAD6CF0B-2979-462C-BBB9-AF723B1EB570}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1A5759FF-9990-4CF5-AD78-528452C5EFCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1A5759FF-9990-4CF5-AD78-528452C5EFCC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A5759FF-9990-4CF5-AD78-528452C5EFCC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1A5759FF-9990-4CF5-AD78-528452C5EFCC}.Release|Any CPU.Build.0 = Release|Any CPU
{7D7D0B73-4153-4E9B-BBD1-C9D7C8AEE970}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7D7D0B73-4153-4E9B-BBD1-C9D7C8AEE970}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7D7D0B73-4153-4E9B-BBD1-C9D7C8AEE970}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7D7D0B73-4153-4E9B-BBD1-C9D7C8AEE970}.Release|Any CPU.Build.0 = Release|Any CPU
{6FD75683-D186-4BE3-ABD0-2324650B46B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6FD75683-D186-4BE3-ABD0-2324650B46B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FD75683-D186-4BE3-ABD0-2324650B46B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6FD75683-D186-4BE3-ABD0-2324650B46B5}.Release|Any CPU.Build.0 = Release|Any CPU
{35457566-83CE-44FC-A650-265CC9C544DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{35457566-83CE-44FC-A650-265CC9C544DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{35457566-83CE-44FC-A650-265CC9C544DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{35457566-83CE-44FC-A650-265CC9C544DC}.Release|Any CPU.Build.0 = Release|Any CPU
{7F226129-E8B0-4274-87A7-347AA4F7D374}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7F226129-E8B0-4274-87A7-347AA4F7D374}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7F226129-E8B0-4274-87A7-347AA4F7D374}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7F226129-E8B0-4274-87A7-347AA4F7D374}.Release|Any CPU.Build.0 = Release|Any CPU
{7559FA9E-7CFC-4615-8D09-3CDEFC765455}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7559FA9E-7CFC-4615-8D09-3CDEFC765455}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7559FA9E-7CFC-4615-8D09-3CDEFC765455}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7559FA9E-7CFC-4615-8D09-3CDEFC765455}.Release|Any CPU.Build.0 = Release|Any CPU
{020545FF-D985-4274-9FDB-FD8B9B32D2ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{020545FF-D985-4274-9FDB-FD8B9B32D2ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{020545FF-D985-4274-9FDB-FD8B9B32D2ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{020545FF-D985-4274-9FDB-FD8B9B32D2ED}.Release|Any CPU.Build.0 = Release|Any CPU
{D6829485-DD9C-42CE-BEDE-4EB0E81021AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D6829485-DD9C-42CE-BEDE-4EB0E81021AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D6829485-DD9C-42CE-BEDE-4EB0E81021AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D6829485-DD9C-42CE-BEDE-4EB0E81021AC}.Release|Any CPU.Build.0 = Release|Any CPU
{698594AE-78D3-429F-B5CC-3A6F6BCE397A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{698594AE-78D3-429F-B5CC-3A6F6BCE397A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{698594AE-78D3-429F-B5CC-3A6F6BCE397A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{698594AE-78D3-429F-B5CC-3A6F6BCE397A}.Release|Any CPU.Build.0 = Release|Any CPU
{EAD6CF0B-2979-462C-BBB9-AF723B1EB570}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EAD6CF0B-2979-462C-BBB9-AF723B1EB570}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EAD6CF0B-2979-462C-BBB9-AF723B1EB570}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EAD6CF0B-2979-462C-BBB9-AF723B1EB570}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{1A5759FF-9990-4CF5-AD78-528452C5EFCC} = {8FF16BDB-352E-42A2-A25F-0B5BC3A17FD7}
{7D7D0B73-4153-4E9B-BBD1-C9D7C8AEE970} = {8FF16BDB-352E-42A2-A25F-0B5BC3A17FD7}
{6FD75683-D186-4BE3-ABD0-2324650B46B5} = {8FF16BDB-352E-42A2-A25F-0B5BC3A17FD7}
{35457566-83CE-44FC-A650-265CC9C544DC} = {8FF16BDB-352E-42A2-A25F-0B5BC3A17FD7}
{7F226129-E8B0-4274-87A7-347AA4F7D374} = {8FF16BDB-352E-42A2-A25F-0B5BC3A17FD7}
{7559FA9E-7CFC-4615-8D09-3CDEFC765455} = {8FF16BDB-352E-42A2-A25F-0B5BC3A17FD7}
{020545FF-D985-4274-9FDB-FD8B9B32D2ED} = {BAA5312D-B54C-42D6-A3B9-504DD12F8250}
{D6829485-DD9C-42CE-BEDE-4EB0E81021AC} = {BAA5312D-B54C-42D6-A3B9-504DD12F8250}
{698594AE-78D3-429F-B5CC-3A6F6BCE397A} = {BAA5312D-B54C-42D6-A3B9-504DD12F8250}
{EAD6CF0B-2979-462C-BBB9-AF723B1EB570} = {BAA5312D-B54C-42D6-A3B9-504DD12F8250}
EndGlobalSection
EndGlobal

4
src/Infrastructure/Dependencies.cs

@ -10,10 +10,10 @@ public static class Dependencies
{ {
public static void ConfigureServices(IConfiguration configuration, IServiceCollection services) public static void ConfigureServices(IConfiguration configuration, IServiceCollection services)
{ {
var useOnlyInMemoryDatabase = false; bool useOnlyInMemoryDatabase = false;
if (configuration["UseOnlyInMemoryDatabase"] != null) if (configuration["UseOnlyInMemoryDatabase"] != null)
{ {
useOnlyInMemoryDatabase = bool.Parse(configuration["UseOnlyInMemoryDatabase"]); useOnlyInMemoryDatabase = bool.Parse(configuration["UseOnlyInMemoryDatabase"]!);
} }
if (useOnlyInMemoryDatabase) if (useOnlyInMemoryDatabase)

3
src/Infrastructure/Identity/AppIdentityDbContextSeed.cs

@ -24,6 +24,9 @@ public class AppIdentityDbContextSeed
var adminUser = new ApplicationUser { UserName = adminUserName, Email = adminUserName }; var adminUser = new ApplicationUser { UserName = adminUserName, Email = adminUserName };
await userManager.CreateAsync(adminUser, AuthorizationConstants.DEFAULT_PASSWORD); await userManager.CreateAsync(adminUser, AuthorizationConstants.DEFAULT_PASSWORD);
adminUser = await userManager.FindByNameAsync(adminUserName); adminUser = await userManager.FindByNameAsync(adminUserName);
if (adminUser != null)
{
await userManager.AddToRoleAsync(adminUser, BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS); await userManager.AddToRoleAsync(adminUser, BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS);
} }
}
} }

1
src/Infrastructure/Identity/IdentityTokenClaimService.cs

@ -25,6 +25,7 @@ public class IdentityTokenClaimService : ITokenClaimsService
var tokenHandler = new JwtSecurityTokenHandler(); var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(AuthorizationConstants.JWT_SECRET_KEY); var key = Encoding.ASCII.GetBytes(AuthorizationConstants.JWT_SECRET_KEY);
var user = await _userManager.FindByNameAsync(userName); var user = await _userManager.FindByNameAsync(userName);
if (user == null) throw new UserNotFoundException(userName);
var roles = await _userManager.GetRolesAsync(user); var roles = await _userManager.GetRolesAsync(user);
var claims = new List<Claim> { new Claim(ClaimTypes.Name, userName) }; var claims = new List<Claim> { new Claim(ClaimTypes.Name, userName) };

10
src/Infrastructure/Identity/UserNotFoundException.cs

@ -0,0 +1,10 @@
using System;
namespace Microsoft.eShopWeb.Infrastructure.Identity;
public class UserNotFoundException : Exception
{
public UserNotFoundException(string userName) : base($"No user found with username: {userName}")
{
}
}

11
src/PublicApi/AuthEndpoints/AuthenticateEndpoint.ClaimValue.cs

@ -1,9 +1,4 @@
using System; namespace Microsoft.eShopWeb.PublicApi.AuthEndpoints;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopWeb.PublicApi.AuthEndpoints;
public class ClaimValue public class ClaimValue
{ {
@ -17,6 +12,6 @@ public class ClaimValue
Value = value; Value = value;
} }
public string Type { get; set; } public string Type { get; set; } = string.Empty;
public string Value { get; set; } public string Value { get; set; } = string.Empty;
} }

11
src/PublicApi/AuthEndpoints/AuthenticateEndpoint.UserInfo.cs

@ -1,7 +1,4 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopWeb.PublicApi.AuthEndpoints; namespace Microsoft.eShopWeb.PublicApi.AuthEndpoints;
@ -9,7 +6,7 @@ public class UserInfo
{ {
public static readonly UserInfo Anonymous = new UserInfo(); public static readonly UserInfo Anonymous = new UserInfo();
public bool IsAuthenticated { get; set; } public bool IsAuthenticated { get; set; }
public string NameClaimType { get; set; } public string NameClaimType { get; set; } = string.Empty;
public string RoleClaimType { get; set; } public string RoleClaimType { get; set; } = string.Empty;
public IEnumerable<ClaimValue> Claims { get; set; } public IEnumerable<ClaimValue> Claims { get; set; } = new List<ClaimValue>();
} }

3
src/PublicApi/AuthEndpoints/AuthenticateEndpoint.cs

@ -33,7 +33,8 @@ public class AuthenticateEndpoint : EndpointBaseAsync
OperationId = "auth.authenticate", OperationId = "auth.authenticate",
Tags = new[] { "AuthEndpoints" }) Tags = new[] { "AuthEndpoints" })
] ]
public override async Task<ActionResult<AuthenticateResponse>> HandleAsync(AuthenticateRequest request, CancellationToken cancellationToken = default) public override async Task<ActionResult<AuthenticateResponse>> HandleAsync(AuthenticateRequest request,
CancellationToken cancellationToken = default)
{ {
var response = new AuthenticateResponse(request.CorrelationId()); var response = new AuthenticateResponse(request.CorrelationId());

4
src/PublicApi/CatalogItemEndpoints/CatalogItemListPagedEndpoint.ListPagedCatalogItemRequest.cs

@ -2,8 +2,8 @@
public class ListPagedCatalogItemRequest : BaseRequest public class ListPagedCatalogItemRequest : BaseRequest
{ {
public int? PageSize { get; init; } public int PageSize { get; init; }
public int? PageIndex { get; init; } public int PageIndex { get; init; }
public int? CatalogBrandId { get; init; } public int? CatalogBrandId { get; init; }
public int? CatalogTypeId { get; init; } public int? CatalogTypeId { get; init; }

6
src/PublicApi/CatalogItemEndpoints/CatalogItemListPagedEndpoint.cs

@ -46,8 +46,8 @@ public class CatalogItemListPagedEndpoint : IEndpoint<IResult, ListPagedCatalogI
int totalItems = await itemRepository.CountAsync(filterSpec); int totalItems = await itemRepository.CountAsync(filterSpec);
var pagedSpec = new CatalogFilterPaginatedSpecification( var pagedSpec = new CatalogFilterPaginatedSpecification(
skip: request.PageIndex.Value * request.PageSize.Value, skip: request.PageIndex * request.PageSize,
take: request.PageSize.Value, take: request.PageSize,
brandId: request.CatalogBrandId, brandId: request.CatalogBrandId,
typeId: request.CatalogTypeId); typeId: request.CatalogTypeId);
@ -61,7 +61,7 @@ public class CatalogItemListPagedEndpoint : IEndpoint<IResult, ListPagedCatalogI
if (request.PageSize > 0) if (request.PageSize > 0)
{ {
response.PageCount = int.Parse(Math.Ceiling((decimal)totalItems / request.PageSize.Value).ToString()); response.PageCount = int.Parse(Math.Ceiling((decimal)totalItems / request.PageSize).ToString());
} }
else else
{ {

4
src/PublicApi/CatalogItemEndpoints/UpdateCatalogItemEndpoint.cs

@ -39,6 +39,10 @@ public class UpdateCatalogItemEndpoint : IEndpoint<IResult, UpdateCatalogItemReq
var response = new UpdateCatalogItemResponse(request.CorrelationId()); var response = new UpdateCatalogItemResponse(request.CorrelationId());
var existingItem = await itemRepository.GetByIdAsync(request.Id); var existingItem = await itemRepository.GetByIdAsync(request.Id);
if (existingItem == null)
{
return Results.NotFound();
}
CatalogItem.CatalogItemDetails details = new(request.Name, request.Description, request.Price); CatalogItem.CatalogItemDetails details = new(request.Name, request.Description, request.Price);
existingItem.UpdateDetails(details); existingItem.UpdateDetails(details);

13
src/PublicApi/Program.cs

@ -2,7 +2,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using BlazorShared; using BlazorShared;
using BlazorShared.Models;
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
@ -41,7 +40,8 @@ builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
builder.Services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>)); builder.Services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
builder.Services.AddScoped(typeof(IReadRepository<>), typeof(EfRepository<>)); builder.Services.AddScoped(typeof(IReadRepository<>), typeof(EfRepository<>));
builder.Services.Configure<CatalogSettings>(builder.Configuration); builder.Services.Configure<CatalogSettings>(builder.Configuration);
builder.Services.AddSingleton<IUriComposer>(new UriComposer(builder.Configuration.Get<CatalogSettings>())); var catalogSettings = builder.Configuration.Get<CatalogSettings>() ?? new CatalogSettings();
builder.Services.AddSingleton<IUriComposer>(new UriComposer(catalogSettings));
builder.Services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>)); builder.Services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>));
builder.Services.AddScoped<ITokenClaimsService, IdentityTokenClaimService>(); builder.Services.AddScoped<ITokenClaimsService, IdentityTokenClaimService>();
@ -75,7 +75,7 @@ builder.Services.AddCors(options =>
options.AddPolicy(name: CORS_POLICY, options.AddPolicy(name: CORS_POLICY,
corsPolicyBuilder => corsPolicyBuilder =>
{ {
corsPolicyBuilder.WithOrigins(baseUrlConfig.WebBase.Replace("host.docker.internal", "localhost").TrimEnd('/')); corsPolicyBuilder.WithOrigins(baseUrlConfig!.WebBase.Replace("host.docker.internal", "localhost").TrimEnd('/'));
corsPolicyBuilder.AllowAnyMethod(); corsPolicyBuilder.AllowAnyMethod();
corsPolicyBuilder.AllowAnyHeader(); corsPolicyBuilder.AllowAnyHeader();
}); });
@ -172,12 +172,9 @@ app.UseSwaggerUI(c =>
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
}); });
app.UseEndpoints(endpoints => app.MapControllers();
{
endpoints.MapControllers();
});
app.MapEndpoints(); app.MapEndpoints();
app.Logger.LogInformation("LAUNCHING PublicApi"); app.Logger.LogInformation("LAUNCHING PublicApi");
app.Run(); app.Run();

5
src/Web/Areas/Identity/Pages/Account/Login.cshtml.cs

@ -25,7 +25,7 @@ public class LoginModel : PageModel
} }
[BindProperty] [BindProperty]
public InputModel? Input { get; set; } public required InputModel Input { get; set; }
public IList<AuthenticationScheme>? ExternalLogins { get; set; } public IList<AuthenticationScheme>? ExternalLogins { get; set; }
@ -74,7 +74,8 @@ public class LoginModel : PageModel
// This doesn't count login failures towards account lockout // This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true // To enable password failures to trigger account lockout, set lockoutOnFailure: true
//var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: true); //var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: true);
var result = await _signInManager.PasswordSignInAsync(Input?.Email, Input?.Password, false, true); var result = await _signInManager.PasswordSignInAsync(Input!.Email!, Input!.Password!,
false, true);
if (result.Succeeded) if (result.Succeeded)
{ {

6
src/Web/Areas/Identity/Pages/Account/Register.cshtml.cs

@ -35,7 +35,7 @@ public class RegisterModel : PageModel
} }
[BindProperty] [BindProperty]
public InputModel? Input { get; set; } public required InputModel Input { get; set; }
public string? ReturnUrl { get; set; } public string? ReturnUrl { get; set; }
@ -69,7 +69,7 @@ public class RegisterModel : PageModel
if (ModelState.IsValid) if (ModelState.IsValid)
{ {
var user = new ApplicationUser { UserName = Input?.Email, Email = Input?.Email }; var user = new ApplicationUser { UserName = Input?.Email, Email = Input?.Email };
var result = await _userManager.CreateAsync(user, Input?.Password); var result = await _userManager.CreateAsync(user, Input?.Password!);
if (result.Succeeded) if (result.Succeeded)
{ {
_logger.LogInformation("User created a new account with password."); _logger.LogInformation("User created a new account with password.");
@ -82,7 +82,7 @@ public class RegisterModel : PageModel
protocol: Request.Scheme); protocol: Request.Scheme);
Guard.Against.Null(callbackUrl, nameof(callbackUrl)); Guard.Against.Null(callbackUrl, nameof(callbackUrl));
await _emailSender.SendEmailAsync(Input?.Email, "Confirm your email", await _emailSender.SendEmailAsync(Input!.Email!, "Confirm your email",
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>."); $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
await _signInManager.SignInAsync(user, isPersistent: false); await _signInManager.SignInAsync(user, isPersistent: false);

7
src/Web/Configuration/ConfigureCoreServices.cs

@ -4,8 +4,6 @@ using Microsoft.eShopWeb.Infrastructure.Data;
using Microsoft.eShopWeb.Infrastructure.Data.Queries; using Microsoft.eShopWeb.Infrastructure.Data.Queries;
using Microsoft.eShopWeb.Infrastructure.Logging; using Microsoft.eShopWeb.Infrastructure.Logging;
using Microsoft.eShopWeb.Infrastructure.Services; using Microsoft.eShopWeb.Infrastructure.Services;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.eShopWeb.Web.Configuration; namespace Microsoft.eShopWeb.Web.Configuration;
@ -20,7 +18,10 @@ public static class ConfigureCoreServices
services.AddScoped<IBasketService, BasketService>(); services.AddScoped<IBasketService, BasketService>();
services.AddScoped<IOrderService, OrderService>(); services.AddScoped<IOrderService, OrderService>();
services.AddScoped<IBasketQueryService, BasketQueryService>(); services.AddScoped<IBasketQueryService, BasketQueryService>();
services.AddSingleton<IUriComposer>(new UriComposer(configuration.Get<CatalogSettings>()));
var catalogSettings = configuration.Get<CatalogSettings>() ?? new CatalogSettings();
services.AddSingleton<IUriComposer>(new UriComposer(catalogSettings));
services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>)); services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>));
services.AddTransient<IEmailSender, EmailSender>(); services.AddTransient<IEmailSender, EmailSender>();

24
src/Web/Controllers/ManageController.cs

@ -122,6 +122,11 @@ public class ManageController : Controller
var callbackUrl = Url.EmailConfirmationLink(user.Id, code, Request.Scheme); var callbackUrl = Url.EmailConfirmationLink(user.Id, code, Request.Scheme);
Guard.Against.Null(callbackUrl, nameof(callbackUrl)); Guard.Against.Null(callbackUrl, nameof(callbackUrl));
var email = user.Email; var email = user.Email;
if (email == null)
{
throw new ApplicationException($"No email associated with user {user.UserName}'.");
}
await _emailSender.SendEmailConfirmationAsync(email, callbackUrl); await _emailSender.SendEmailConfirmationAsync(email, callbackUrl);
StatusMessage = "Verification email sent. Please check your email."; StatusMessage = "Verification email sent. Please check your email.";
@ -162,7 +167,8 @@ public class ManageController : Controller
throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
} }
var changePasswordResult = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword); var changePasswordResult = await _userManager
.ChangePasswordAsync(user, model.OldPassword!, model.NewPassword!);
if (!changePasswordResult.Succeeded) if (!changePasswordResult.Succeeded)
{ {
AddErrors(changePasswordResult); AddErrors(changePasswordResult);
@ -211,7 +217,7 @@ public class ManageController : Controller
throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
} }
var addPasswordResult = await _userManager.AddPasswordAsync(user, model.NewPassword); var addPasswordResult = await _userManager.AddPasswordAsync(user, model.NewPassword!);
if (!addPasswordResult.Succeeded) if (!addPasswordResult.Succeeded)
{ {
AddErrors(addPasswordResult); AddErrors(addPasswordResult);
@ -293,6 +299,10 @@ public class ManageController : Controller
{ {
throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
} }
if (!ModelState.IsValid)
{
return View(model);
}
var result = await _userManager.RemoveLoginAsync(user, model.LoginProvider, model.ProviderKey); var result = await _userManager.RemoveLoginAsync(user, model.LoginProvider, model.ProviderKey);
if (!result.Succeeded) if (!result.Succeeded)
@ -407,7 +417,7 @@ public class ManageController : Controller
} }
// Strip spaces and hypens // Strip spaces and hypens
var verificationCode = model.Code?.Replace(" ", string.Empty).Replace("-", string.Empty); string verificationCode = model.Code?.Replace(" ", string.Empty).Replace("-", string.Empty) ?? "";
var is2faTokenValid = await _userManager.VerifyTwoFactorTokenAsync( var is2faTokenValid = await _userManager.VerifyTwoFactorTokenAsync(
user, _userManager.Options.Tokens.AuthenticatorTokenProvider, verificationCode); user, _userManager.Options.Tokens.AuthenticatorTokenProvider, verificationCode);
@ -421,7 +431,7 @@ public class ManageController : Controller
await _userManager.SetTwoFactorEnabledAsync(user, true); await _userManager.SetTwoFactorEnabledAsync(user, true);
_logger.LogInformation("User with ID {UserId} has enabled 2FA with an authenticator app.", user.Id); _logger.LogInformation("User with ID {UserId} has enabled 2FA with an authenticator app.", user.Id);
var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10); var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10) ?? new List<string>();
TempData[RecoveryCodesKey] = recoveryCodes.ToArray(); TempData[RecoveryCodesKey] = recoveryCodes.ToArray();
return RedirectToAction(nameof(ShowRecoveryCodes)); return RedirectToAction(nameof(ShowRecoveryCodes));
@ -465,7 +475,7 @@ public class ManageController : Controller
throw new ApplicationException($"Cannot generate recovery codes for user with ID '{user.Id}' as they do not have 2FA enabled."); throw new ApplicationException($"Cannot generate recovery codes for user with ID '{user.Id}' as they do not have 2FA enabled.");
} }
var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10); var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10) ?? new List<string>();
_logger.LogInformation("User with ID {UserId} has generated new 2FA recovery codes.", user.Id); _logger.LogInformation("User with ID {UserId} has generated new 2FA recovery codes.", user.Id);
var model = new ShowRecoveryCodesViewModel { RecoveryCodes = recoveryCodes.ToArray() }; var model = new ShowRecoveryCodesViewModel { RecoveryCodes = recoveryCodes.ToArray() };
@ -533,8 +543,8 @@ public class ManageController : Controller
unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user); unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user);
} }
model.SharedKey = FormatKey(unformattedKey); model.SharedKey = FormatKey(unformattedKey!);
model.AuthenticatorUri = GenerateQrCodeUri(user.Email, unformattedKey); model.AuthenticatorUri = GenerateQrCodeUri(user.Email!, unformattedKey!);
} }
} }

2
src/Web/Pages/Index.cshtml.cs

@ -13,7 +13,7 @@ public class IndexModel : PageModel
_catalogViewModelService = catalogViewModelService; _catalogViewModelService = catalogViewModelService;
} }
public CatalogIndexViewModel CatalogModel { get; set; } = new CatalogIndexViewModel(); public required CatalogIndexViewModel CatalogModel { get; set; } = new CatalogIndexViewModel();
public async Task OnGet(CatalogIndexViewModel catalogModel, int? pageId) public async Task OnGet(CatalogIndexViewModel catalogModel, int? pageId)
{ {

18
src/Web/Program.cs

@ -82,7 +82,7 @@ var baseUrlConfig = configSection.Get<BaseUrlConfiguration>();
// Blazor Admin Required Services for Prerendering // Blazor Admin Required Services for Prerendering
builder.Services.AddScoped<HttpClient>(s => new HttpClient builder.Services.AddScoped<HttpClient>(s => new HttpClient
{ {
BaseAddress = new Uri(baseUrlConfig.WebBase) BaseAddress = new Uri(baseUrlConfig!.WebBase)
}); });
// add blazor services // add blazor services
@ -171,15 +171,13 @@ app.UseCookiePolicy();
app.UseAuthentication(); app.UseAuthentication();
app.UseAuthorization(); app.UseAuthorization();
app.UseEndpoints(endpoints =>
{ app.MapControllerRoute("default", "{controller:slugify=Home}/{action:slugify=Index}/{id?}");
endpoints.MapControllerRoute("default", "{controller:slugify=Home}/{action:slugify=Index}/{id?}"); app.MapRazorPages();
endpoints.MapRazorPages(); app.MapHealthChecks("home_page_health_check", new HealthCheckOptions { Predicate = check => check.Tags.Contains("homePageHealthCheck") });
endpoints.MapHealthChecks("home_page_health_check", new HealthCheckOptions { Predicate = check => check.Tags.Contains("homePageHealthCheck") }); app.MapHealthChecks("api_health_check", new HealthCheckOptions { Predicate = check => check.Tags.Contains("apiHealthCheck") });
endpoints.MapHealthChecks("api_health_check", new HealthCheckOptions { Predicate = check => check.Tags.Contains("apiHealthCheck") }); //endpoints.MapBlazorHub("/admin");
//endpoints.MapBlazorHub("/admin"); app.MapFallbackToFile("index.html");
endpoints.MapFallbackToFile("index.html");
});
app.Logger.LogInformation("LAUNCHING"); app.Logger.LogInformation("LAUNCHING");
app.Run(); app.Run();

12
src/Web/Services/CachedCatalogViewModelService.cs

@ -21,30 +21,30 @@ public class CachedCatalogViewModelService : ICatalogViewModelService
public async Task<IEnumerable<SelectListItem>> GetBrands() public async Task<IEnumerable<SelectListItem>> GetBrands()
{ {
return await _cache.GetOrCreateAsync(CacheHelpers.GenerateBrandsCacheKey(), async entry => return (await _cache.GetOrCreateAsync(CacheHelpers.GenerateBrandsCacheKey(), async entry =>
{ {
entry.SlidingExpiration = CacheHelpers.DefaultCacheDuration; entry.SlidingExpiration = CacheHelpers.DefaultCacheDuration;
return await _catalogViewModelService.GetBrands(); return await _catalogViewModelService.GetBrands();
}); })) ?? new List<SelectListItem>();
} }
public async Task<CatalogIndexViewModel> GetCatalogItems(int pageIndex, int itemsPage, int? brandId, int? typeId) public async Task<CatalogIndexViewModel> GetCatalogItems(int pageIndex, int itemsPage, int? brandId, int? typeId)
{ {
var cacheKey = CacheHelpers.GenerateCatalogItemCacheKey(pageIndex, Constants.ITEMS_PER_PAGE, brandId, typeId); var cacheKey = CacheHelpers.GenerateCatalogItemCacheKey(pageIndex, Constants.ITEMS_PER_PAGE, brandId, typeId);
return await _cache.GetOrCreateAsync(cacheKey, async entry => return (await _cache.GetOrCreateAsync(cacheKey, async entry =>
{ {
entry.SlidingExpiration = CacheHelpers.DefaultCacheDuration; entry.SlidingExpiration = CacheHelpers.DefaultCacheDuration;
return await _catalogViewModelService.GetCatalogItems(pageIndex, itemsPage, brandId, typeId); return await _catalogViewModelService.GetCatalogItems(pageIndex, itemsPage, brandId, typeId);
}); })) ?? new CatalogIndexViewModel();
} }
public async Task<IEnumerable<SelectListItem>> GetTypes() public async Task<IEnumerable<SelectListItem>> GetTypes()
{ {
return await _cache.GetOrCreateAsync(CacheHelpers.GenerateTypesCacheKey(), async entry => return (await _cache.GetOrCreateAsync(CacheHelpers.GenerateTypesCacheKey(), async entry =>
{ {
entry.SlidingExpiration = CacheHelpers.DefaultCacheDuration; entry.SlidingExpiration = CacheHelpers.DefaultCacheDuration;
return await _catalogViewModelService.GetTypes(); return await _catalogViewModelService.GetTypes();
}); })) ?? new List<SelectListItem>();
} }
} }

9
src/Web/ViewModels/CatalogIndexViewModel.cs

@ -1,13 +1,12 @@
using System.Collections.Generic; using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace Microsoft.eShopWeb.Web.ViewModels; namespace Microsoft.eShopWeb.Web.ViewModels;
public class CatalogIndexViewModel public class CatalogIndexViewModel
{ {
public List<CatalogItemViewModel>? CatalogItems { get; set; } public List<CatalogItemViewModel> CatalogItems { get; set; } = new List<CatalogItemViewModel>();
public List<SelectListItem>? Brands { get; set; } public List<SelectListItem>? Brands { get; set; } = new List<SelectListItem>();
public List<SelectListItem>? Types { get; set; } public List<SelectListItem>? Types { get; set; } = new List<SelectListItem>();
public int? BrandFilterApplied { get; set; } public int? BrandFilterApplied { get; set; }
public int? TypesFilterApplied { get; set; } public int? TypesFilterApplied { get; set; }
public PaginationInfoViewModel? PaginationInfo { get; set; } public PaginationInfoViewModel? PaginationInfo { get; set; }

10
src/Web/ViewModels/Manage/RemoveLoginViewModel.cs

@ -1,7 +1,11 @@
namespace Microsoft.eShopWeb.Web.ViewModels.Manage; using System.ComponentModel.DataAnnotations;
namespace Microsoft.eShopWeb.Web.ViewModels.Manage;
public class RemoveLoginViewModel public class RemoveLoginViewModel
{ {
public string? LoginProvider { get; set; } [Required]
public string? ProviderKey { get; set; } public string LoginProvider { get; set; } = string.Empty;
[Required]
public string ProviderKey { get; set; } = string.Empty;
} }

6
src/Web/ViewModels/OrderViewModel.cs

@ -1,6 +1,4 @@
using System; using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate;
using System.Collections.Generic;
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate;
namespace Microsoft.eShopWeb.Web.ViewModels; namespace Microsoft.eShopWeb.Web.ViewModels;
@ -13,5 +11,5 @@ public class OrderViewModel
public decimal Total { get; set; } public decimal Total { get; set; }
public string Status => DEFAULT_STATUS; public string Status => DEFAULT_STATUS;
public Address? ShippingAddress { get; set; } public Address? ShippingAddress { get; set; }
public List<OrderItemViewModel> OrderItems { get; set; } = new List<OrderItemViewModel>(); public List<OrderItemViewModel> OrderItems { get; set; } = new();
} }

5
src/Web/Views/Manage/ShowRecoverCodes.cshtml

@ -16,10 +16,13 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
@if (Model.RecoveryCodes != null)
{
@for (var row = 0; row < Model.RecoveryCodes.Length; row += 2) @for (var row = 0; row < Model.RecoveryCodes.Length; row += 2)
{ {
<code>@Model.RecoveryCodes[row]</code><text>&nbsp;</text><code>@Model.RecoveryCodes[row + 1]</code><br /> <code>@Model.RecoveryCodes[row]</code><text>&nbsp;</text><code>@Model.RecoveryCodes[row + 1]</code><br />
} }
}
</div> </div>
</div> </div>
© 2021 GitHub, Inc. © 2023 GitHub, Inc.

6
src/Web/Views/Order/Detail.cshtml

@ -30,15 +30,15 @@
</article> </article>
<article class="esh-orders-detail-items row"> <article class="esh-orders-detail-items row">
<section class="esh-orders-detail-item col-xs-12">@Model.ShippingAddress.Street</section> <section class="esh-orders-detail-item col-xs-12">@Model.ShippingAddress?.Street</section>
</article> </article>
<article class="esh-orders-detail-items row"> <article class="esh-orders-detail-items row">
<section class="esh-orders-detail-item col-xs-12">@Model.ShippingAddress.City</section> <section class="esh-orders-detail-item col-xs-12">@Model.ShippingAddress?.City</section>
</article> </article>
<article class="esh-orders-detail-items row"> <article class="esh-orders-detail-items row">
<section class="esh-orders-detail-item col-xs-12">@Model.ShippingAddress.Country</section> <section class="esh-orders-detail-item col-xs-12">@Model.ShippingAddress?.Country</section>
</article> </article>
</section> </section>

2
src/Web/Views/Shared/_LoginPartial.cshtml

@ -1,4 +1,4 @@
@if (Context.User.Identity.IsAuthenticated) @if (Context!.User!.Identity!.IsAuthenticated)
{ {
<section class="col-lg-4 col-md-5 col-xs-12"> <section class="col-lg-4 col-md-5 col-xs-12">
<div class="esh-identity"> <div class="esh-identity">

2
tests/FunctionalTests/Web/Controllers/OrderControllerIndex.cs

@ -23,7 +23,7 @@ public class OrderIndexOnGet : IClassFixture<TestApplication>
public async Task ReturnsRedirectGivenAnonymousUser() public async Task ReturnsRedirectGivenAnonymousUser()
{ {
var response = await Client.GetAsync("/order/my-orders"); var response = await Client.GetAsync("/order/my-orders");
var redirectLocation = response.Headers.Location.OriginalString; var redirectLocation = response!.Headers.Location!.OriginalString;
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
Assert.Contains("/Account/Login", redirectLocation); Assert.Contains("/Account/Login", redirectLocation);

2
tests/FunctionalTests/Web/Pages/Basket/BasketPageCheckout.cs

@ -45,6 +45,6 @@ public class BasketPageCheckout : IClassFixture<TestApplication>
formContent = new FormUrlEncodedContent(keyValues); formContent = new FormUrlEncodedContent(keyValues);
var postResponse2 = await Client.PostAsync("/Basket/Checkout", formContent); var postResponse2 = await Client.PostAsync("/Basket/Checkout", formContent);
Assert.Contains("/Identity/Account/Login", postResponse2.RequestMessage.RequestUri.ToString()); Assert.Contains("/Identity/Account/Login", postResponse2!.RequestMessage!.RequestUri!.ToString()!);
} }
} }

2
tests/FunctionalTests/Web/Pages/Basket/CheckoutTest.cs

@ -62,7 +62,7 @@ public class CheckoutTest : IClassFixture<TestApplication>
var checkOutResponse = await Client.PostAsync("/basket/checkout", checkOutContent); var checkOutResponse = await Client.PostAsync("/basket/checkout", checkOutContent);
var stringCheckOutResponse = await checkOutResponse.Content.ReadAsStringAsync(); var stringCheckOutResponse = await checkOutResponse.Content.ReadAsStringAsync();
Assert.Contains("/Basket/Success", checkOutResponse.RequestMessage.RequestUri.ToString()); Assert.Contains("/Basket/Success", checkOutResponse.RequestMessage!.RequestUri!.ToString());
Assert.Contains("Thanks for your Order!", stringCheckOutResponse); Assert.Contains("Thanks for your Order!", stringCheckOutResponse);
} }
} }

4
tests/FunctionalTests/Web/Pages/Basket/IndexTest.cs

@ -52,7 +52,7 @@ public class IndexTest : IClassFixture<TestApplication>
var stringUpdateResponse = await updateResponse.Content.ReadAsStringAsync(); var stringUpdateResponse = await updateResponse.Content.ReadAsStringAsync();
Assert.Contains("/basket/update", updateResponse.RequestMessage.RequestUri.ToString()); Assert.Contains("/basket/update", updateResponse!.RequestMessage!.RequestUri!.ToString()!);
decimal expectedTotalAmount = 416.50M; decimal expectedTotalAmount = 416.50M;
Assert.Contains(expectedTotalAmount.ToString("N2"), stringUpdateResponse); Assert.Contains(expectedTotalAmount.ToString("N2"), stringUpdateResponse);
} }
@ -92,7 +92,7 @@ public class IndexTest : IClassFixture<TestApplication>
var stringUpdateResponse = await updateResponse.Content.ReadAsStringAsync(); var stringUpdateResponse = await updateResponse.Content.ReadAsStringAsync();
Assert.Contains("/basket/update", updateResponse.RequestMessage.RequestUri.ToString()); Assert.Contains("/basket/update", updateResponse!.RequestMessage!.RequestUri!.ToString()!);
Assert.Contains("Basket is empty", stringUpdateResponse); Assert.Contains("Basket is empty", stringUpdateResponse);
} }
} }

2
tests/FunctionalTests/Web/WebPageHelpers.cs

@ -22,6 +22,6 @@ public static class WebPageHelpers
{ {
var regex = new Regex(regexpression); var regex = new Regex(regexpression);
var match = regex.Match(input); var match = regex.Match(input);
return match.Groups.Values.LastOrDefault().Value; return match!.Groups!.Values!.LastOrDefault()!.Value;
} }
} }

11
tests/PublicApiIntegrationTests/AuthEndpoints/AuthenticateEndpointTest.cs

@ -7,11 +7,11 @@ using Microsoft.eShopWeb.ApplicationCore.Constants;
using Microsoft.eShopWeb.PublicApi.AuthEndpoints; using Microsoft.eShopWeb.PublicApi.AuthEndpoints;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace PublicApiIntegrationTests.AuthEndpoints namespace PublicApiIntegrationTests.AuthEndpoints;
[TestClass]
public class AuthenticateEndpoint
{ {
[TestClass]
public class AuthenticateEndpoint
{
[TestMethod] [TestMethod]
[DataRow("demouser@microsoft.com", AuthorizationConstants.DEFAULT_PASSWORD, true)] [DataRow("demouser@microsoft.com", AuthorizationConstants.DEFAULT_PASSWORD, true)]
[DataRow("demouser@microsoft.com", "badpassword", false)] [DataRow("demouser@microsoft.com", "badpassword", false)]
@ -29,7 +29,6 @@ namespace PublicApiIntegrationTests.AuthEndpoints
var stringResponse = await response.Content.ReadAsStringAsync(); var stringResponse = await response.Content.ReadAsStringAsync();
var model = stringResponse.FromJson<AuthenticateResponse>(); var model = stringResponse.FromJson<AuthenticateResponse>();
Assert.AreEqual(expectedResult, model.Result); Assert.AreEqual(expectedResult, model!.Result);
}
} }
} }

11
tests/PublicApiIntegrationTests/CatalogItemEndpoints/CatalogItemGetByIdEndpointTest.cs

@ -4,11 +4,11 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace PublicApiIntegrationTests.CatalogItemEndpoints namespace PublicApiIntegrationTests.CatalogItemEndpoints;
[TestClass]
public class CatalogItemGetByIdEndpointTest
{ {
[TestClass]
public class CatalogItemGetByIdEndpointTest
{
[TestMethod] [TestMethod]
public async Task ReturnsItemGivenValidId() public async Task ReturnsItemGivenValidId()
{ {
@ -17,7 +17,7 @@ namespace PublicApiIntegrationTests.CatalogItemEndpoints
var stringResponse = await response.Content.ReadAsStringAsync(); var stringResponse = await response.Content.ReadAsStringAsync();
var model = stringResponse.FromJson<GetByIdCatalogItemResponse>(); var model = stringResponse.FromJson<GetByIdCatalogItemResponse>();
Assert.AreEqual(5, model.CatalogItem.Id); Assert.AreEqual(5, model!.CatalogItem.Id);
Assert.AreEqual("Roslyn Red Sheet", model.CatalogItem.Name); Assert.AreEqual("Roslyn Red Sheet", model.CatalogItem.Name);
} }
@ -28,5 +28,4 @@ namespace PublicApiIntegrationTests.CatalogItemEndpoints
Assert.AreEqual(HttpStatusCode.NotFound, response.StatusCode); Assert.AreEqual(HttpStatusCode.NotFound, response.StatusCode);
} }
}
} }

15
tests/PublicApiIntegrationTests/CatalogItemEndpoints/CatalogItemListPagedEndpoint.cs

@ -8,11 +8,11 @@ using System.Net.Http;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace PublicApiIntegrationTests.CatalogItemEndpoints namespace PublicApiIntegrationTests.CatalogItemEndpoints;
[TestClass]
public class CatalogItemListPagedEndpoint
{ {
[TestClass]
public class CatalogItemListPagedEndpoint
{
[TestMethod] [TestMethod]
public async Task ReturnsFirst10CatalogItems() public async Task ReturnsFirst10CatalogItems()
{ {
@ -22,7 +22,7 @@ namespace PublicApiIntegrationTests.CatalogItemEndpoints
var stringResponse = await response.Content.ReadAsStringAsync(); var stringResponse = await response.Content.ReadAsStringAsync();
var model = stringResponse.FromJson<CatalogIndexViewModel>(); var model = stringResponse.FromJson<CatalogIndexViewModel>();
Assert.AreEqual(10, model.CatalogItems.Count()); Assert.AreEqual(10, model!.CatalogItems.Count());
} }
[TestMethod] [TestMethod]
@ -37,7 +37,7 @@ namespace PublicApiIntegrationTests.CatalogItemEndpoints
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
var stringResponse = await response.Content.ReadAsStringAsync(); var stringResponse = await response.Content.ReadAsStringAsync();
var model = stringResponse.FromJson<ListPagedCatalogItemResponse>(); var model = stringResponse.FromJson<ListPagedCatalogItemResponse>();
var totalItem = model.CatalogItems.Count(); var totalItem = model!.CatalogItems.Count();
var response2 = await client.GetAsync($"/api/catalog-items?pageSize={pageSize}&pageIndex={pageIndex}"); var response2 = await client.GetAsync($"/api/catalog-items?pageSize={pageSize}&pageIndex={pageIndex}");
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
@ -46,7 +46,7 @@ namespace PublicApiIntegrationTests.CatalogItemEndpoints
var totalExpected = totalItem - (pageSize * pageIndex); var totalExpected = totalItem - (pageSize * pageIndex);
Assert.AreEqual(totalExpected, model2.CatalogItems.Count()); Assert.AreEqual(totalExpected, model2!.CatalogItems.Count());
} }
[DataTestMethod] [DataTestMethod]
@ -69,5 +69,4 @@ namespace PublicApiIntegrationTests.CatalogItemEndpoints
Assert.AreEqual(0, totalKO); Assert.AreEqual(0, totalKO);
} }
}
} }

11
tests/PublicApiIntegrationTests/CatalogItemEndpoints/CreateCatalogItemEndpointTest.cs

@ -8,11 +8,11 @@ using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace PublicApiIntegrationTests.AuthEndpoints namespace PublicApiIntegrationTests.AuthEndpoints;
[TestClass]
public class CreateCatalogItemEndpointTest
{ {
[TestClass]
public class CreateCatalogItemEndpointTest
{
private int _testBrandId = 1; private int _testBrandId = 1;
private int _testTypeId = 2; private int _testTypeId = 2;
private string _testDescription = "test description"; private string _testDescription = "test description";
@ -44,7 +44,7 @@ namespace PublicApiIntegrationTests.AuthEndpoints
var stringResponse = await response.Content.ReadAsStringAsync(); var stringResponse = await response.Content.ReadAsStringAsync();
var model = stringResponse.FromJson<CreateCatalogItemResponse>(); var model = stringResponse.FromJson<CreateCatalogItemResponse>();
Assert.AreEqual(_testBrandId, model.CatalogItem.CatalogBrandId); Assert.AreEqual(_testBrandId, model!.CatalogItem.CatalogBrandId);
Assert.AreEqual(_testTypeId, model.CatalogItem.CatalogTypeId); Assert.AreEqual(_testTypeId, model.CatalogItem.CatalogTypeId);
Assert.AreEqual(_testDescription, model.CatalogItem.Description); Assert.AreEqual(_testDescription, model.CatalogItem.Description);
Assert.AreEqual(_testName, model.CatalogItem.Name); Assert.AreEqual(_testName, model.CatalogItem.Name);
@ -65,5 +65,4 @@ namespace PublicApiIntegrationTests.AuthEndpoints
return jsonContent; return jsonContent;
} }
}
} }

11
tests/PublicApiIntegrationTests/CatalogItemEndpoints/DeleteCatalogItemEndpointTest.cs

@ -5,11 +5,11 @@ using System.Net;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace PublicApiIntegrationTests.CatalogItemEndpoints namespace PublicApiIntegrationTests.CatalogItemEndpoints;
[TestClass]
public class DeleteCatalogItemEndpointTest
{ {
[TestClass]
public class DeleteCatalogItemEndpointTest
{
[TestMethod] [TestMethod]
public async Task ReturnsSuccessGivenValidIdAndAdminUserToken() public async Task ReturnsSuccessGivenValidIdAndAdminUserToken()
{ {
@ -21,7 +21,7 @@ namespace PublicApiIntegrationTests.CatalogItemEndpoints
var stringResponse = await response.Content.ReadAsStringAsync(); var stringResponse = await response.Content.ReadAsStringAsync();
var model = stringResponse.FromJson<DeleteCatalogItemResponse>(); var model = stringResponse.FromJson<DeleteCatalogItemResponse>();
Assert.AreEqual("Deleted", model.Status); Assert.AreEqual("Deleted", model!.Status);
} }
[TestMethod] [TestMethod]
@ -34,5 +34,4 @@ namespace PublicApiIntegrationTests.CatalogItemEndpoints
Assert.AreEqual(HttpStatusCode.NotFound, response.StatusCode); Assert.AreEqual(HttpStatusCode.NotFound, response.StatusCode);
} }
}
} }

11
tests/PublicApiIntegrationTests/ProgramTest.cs

@ -2,12 +2,12 @@
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Net.Http; using System.Net.Http;
namespace PublicApiIntegrationTests namespace PublicApiIntegrationTests;
[TestClass]
public class ProgramTest
{ {
[TestClass] private static WebApplicationFactory<Program> _application = new();
public class ProgramTest
{
private static WebApplicationFactory<Program> _application;
public static HttpClient NewClient public static HttpClient NewClient
{ {
@ -23,5 +23,4 @@ namespace PublicApiIntegrationTests
_application = new WebApplicationFactory<Program>(); _application = new WebApplicationFactory<Program>();
} }
}
} }

Loading…
Cancel
Save