Skip to content

Commit

Permalink
Fix Null Warnings (dotnet-architecture#874)
Browse files Browse the repository at this point in the history
* Fixing null warnings

* Fix null warnings
Fix other compiler warnings
ardalis authored Mar 20, 2023
1 parent a2ebd3f commit d2412a8
Showing 38 changed files with 385 additions and 270 deletions.
8 changes: 7 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
@@ -141,4 +141,10 @@ csharp_preserve_single_line_blocks = true
###############################
[*.vb]
# 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 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
92 changes: 92 additions & 0 deletions Everything.sln
Original file line number Diff line number Diff line change
@@ -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 changes: 2 additions & 2 deletions src/Infrastructure/Dependencies.cs
Original file line number Diff line number Diff line change
@@ -10,10 +10,10 @@ public static class Dependencies
{
public static void ConfigureServices(IConfiguration configuration, IServiceCollection services)
{
var useOnlyInMemoryDatabase = false;
bool useOnlyInMemoryDatabase = false;
if (configuration["UseOnlyInMemoryDatabase"] != null)
{
useOnlyInMemoryDatabase = bool.Parse(configuration["UseOnlyInMemoryDatabase"]);
useOnlyInMemoryDatabase = bool.Parse(configuration["UseOnlyInMemoryDatabase"]!);
}

if (useOnlyInMemoryDatabase)
5 changes: 4 additions & 1 deletion src/Infrastructure/Identity/AppIdentityDbContextSeed.cs
Original file line number Diff line number Diff line change
@@ -24,6 +24,9 @@ public static async Task SeedAsync(AppIdentityDbContext identityDbContext, UserM
var adminUser = new ApplicationUser { UserName = adminUserName, Email = adminUserName };
await userManager.CreateAsync(adminUser, AuthorizationConstants.DEFAULT_PASSWORD);
adminUser = await userManager.FindByNameAsync(adminUserName);
await userManager.AddToRoleAsync(adminUser, BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS);
if (adminUser != null)
{
await userManager.AddToRoleAsync(adminUser, BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS);
}
}
}
1 change: 1 addition & 0 deletions src/Infrastructure/Identity/IdentityTokenClaimService.cs
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ public async Task<string> GetTokenAsync(string userName)
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(AuthorizationConstants.JWT_SECRET_KEY);
var user = await _userManager.FindByNameAsync(userName);
if (user == null) throw new UserNotFoundException(userName);
var roles = await _userManager.GetRolesAsync(user);
var claims = new List<Claim> { new Claim(ClaimTypes.Name, userName) };

10 changes: 10 additions & 0 deletions src/Infrastructure/Identity/UserNotFoundException.cs
Original file line number Diff line number Diff line change
@@ -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 changes: 3 additions & 8 deletions src/PublicApi/AuthEndpoints/AuthenticateEndpoint.ClaimValue.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Microsoft.eShopWeb.PublicApi.AuthEndpoints;
namespace Microsoft.eShopWeb.PublicApi.AuthEndpoints;

public class ClaimValue
{
@@ -17,6 +12,6 @@ public ClaimValue(string type, string value)
Value = value;
}

public string Type { get; set; }
public string Value { get; set; }
public string Type { get; set; } = string.Empty;
public string Value { get; set; } = string.Empty;
}
11 changes: 4 additions & 7 deletions src/PublicApi/AuthEndpoints/AuthenticateEndpoint.UserInfo.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;

namespace Microsoft.eShopWeb.PublicApi.AuthEndpoints;

public class UserInfo
{
public static readonly UserInfo Anonymous = new UserInfo();
public bool IsAuthenticated { get; set; }
public string NameClaimType { get; set; }
public string RoleClaimType { get; set; }
public IEnumerable<ClaimValue> Claims { get; set; }
public string NameClaimType { get; set; } = string.Empty;
public string RoleClaimType { get; set; } = string.Empty;
public IEnumerable<ClaimValue> Claims { get; set; } = new List<ClaimValue>();
}
3 changes: 2 additions & 1 deletion src/PublicApi/AuthEndpoints/AuthenticateEndpoint.cs
Original file line number Diff line number Diff line change
@@ -33,7 +33,8 @@ public AuthenticateEndpoint(SignInManager<ApplicationUser> signInManager,
OperationId = "auth.authenticate",
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());

Original file line number Diff line number Diff line change
@@ -2,8 +2,8 @@

public class ListPagedCatalogItemRequest : BaseRequest
{
public int? PageSize { get; init; }
public int? PageIndex { get; init; }
public int PageSize { get; init; }
public int PageIndex { get; init; }
public int? CatalogBrandId { get; init; }
public int? CatalogTypeId { get; init; }

Original file line number Diff line number Diff line change
@@ -46,8 +46,8 @@ public async Task<IResult> HandleAsync(ListPagedCatalogItemRequest request, IRep
int totalItems = await itemRepository.CountAsync(filterSpec);

var pagedSpec = new CatalogFilterPaginatedSpecification(
skip: request.PageIndex.Value * request.PageSize.Value,
take: request.PageSize.Value,
skip: request.PageIndex * request.PageSize,
take: request.PageSize,
brandId: request.CatalogBrandId,
typeId: request.CatalogTypeId);

@@ -61,7 +61,7 @@ public async Task<IResult> HandleAsync(ListPagedCatalogItemRequest request, IRep

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
{
Original file line number Diff line number Diff line change
@@ -39,6 +39,10 @@ public async Task<IResult> HandleAsync(UpdateCatalogItemRequest request, IReposi
var response = new UpdateCatalogItemResponse(request.CorrelationId());

var existingItem = await itemRepository.GetByIdAsync(request.Id);
if (existingItem == null)
{
return Results.NotFound();
}

CatalogItem.CatalogItemDetails details = new(request.Name, request.Description, request.Price);
existingItem.UpdateDetails(details);
23 changes: 10 additions & 13 deletions src/PublicApi/Program.cs
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Text;
using BlazorShared;
using BlazorShared.Models;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
@@ -41,7 +40,8 @@
builder.Services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
builder.Services.AddScoped(typeof(IReadRepository<>), typeof(EfRepository<>));
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<ITokenClaimsService, IdentityTokenClaimService>();

@@ -73,12 +73,12 @@
builder.Services.AddCors(options =>
{
options.AddPolicy(name: CORS_POLICY,
corsPolicyBuilder =>
{
corsPolicyBuilder.WithOrigins(baseUrlConfig.WebBase.Replace("host.docker.internal", "localhost").TrimEnd('/'));
corsPolicyBuilder.AllowAnyMethod();
corsPolicyBuilder.AllowAnyHeader();
});
corsPolicyBuilder =>
{
corsPolicyBuilder.WithOrigins(baseUrlConfig!.WebBase.Replace("host.docker.internal", "localhost").TrimEnd('/'));
corsPolicyBuilder.AllowAnyMethod();
corsPolicyBuilder.AllowAnyHeader();
});
});

builder.Services.AddControllers();
@@ -172,12 +172,9 @@
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});

app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});

app.MapControllers();
app.MapEndpoints();

app.Logger.LogInformation("LAUNCHING PublicApi");
app.Run();

5 changes: 3 additions & 2 deletions src/Web/Areas/Identity/Pages/Account/Login.cshtml.cs
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ public LoginModel(SignInManager<ApplicationUser> signInManager, ILogger<LoginMod
}

[BindProperty]
public InputModel? Input { get; set; }
public required InputModel Input { get; set; }

public IList<AuthenticationScheme>? ExternalLogins { get; set; }

@@ -74,7 +74,8 @@ public async Task<IActionResult> OnPostAsync(string? returnUrl = null)
// This doesn't count login failures towards account lockout
// 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, false, true);
var result = await _signInManager.PasswordSignInAsync(Input!.Email!, Input!.Password!,
false, true);

if (result.Succeeded)
{
6 changes: 3 additions & 3 deletions src/Web/Areas/Identity/Pages/Account/Register.cshtml.cs
Original file line number Diff line number Diff line change
@@ -35,7 +35,7 @@ public RegisterModel(
}

[BindProperty]
public InputModel? Input { get; set; }
public required InputModel Input { get; set; }

public string? ReturnUrl { get; set; }

@@ -69,7 +69,7 @@ public async Task<IActionResult> OnPostAsync(string? returnUrl = null)
if (ModelState.IsValid)
{
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)
{
_logger.LogInformation("User created a new account with password.");
@@ -82,7 +82,7 @@ public async Task<IActionResult> OnPostAsync(string? returnUrl = null)
protocol: Request.Scheme);

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>.");

await _signInManager.SignInAsync(user, isPersistent: false);
7 changes: 4 additions & 3 deletions src/Web/Configuration/ConfigureCoreServices.cs
Original file line number Diff line number Diff line change
@@ -4,8 +4,6 @@
using Microsoft.eShopWeb.Infrastructure.Data.Queries;
using Microsoft.eShopWeb.Infrastructure.Logging;
using Microsoft.eShopWeb.Infrastructure.Services;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.eShopWeb.Web.Configuration;

@@ -20,7 +18,10 @@ public static IServiceCollection AddCoreServices(this IServiceCollection service
services.AddScoped<IBasketService, BasketService>();
services.AddScoped<IOrderService, OrderService>();
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.AddTransient<IEmailSender, EmailSender>();

Loading
Oops, something went wrong.

0 comments on commit d2412a8

Please sign in to comment.