diff --git a/Directory.Build.props b/Directory.Build.props
index 0e7e481..9b3a70f 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -2,25 +2,14 @@
2.0.0-beta4
- net8.0
-
- false
latest
enable
- enable
nullable
false
false
-
-
-
-
diff --git a/Passwordless.sln b/Passwordless.sln
index 7dd2580..dd09436 100644
--- a/Passwordless.sln
+++ b/Passwordless.sln
@@ -15,6 +15,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
README.md = README.md
LICENSE = LICENSE
favicon.png = favicon.png
+ global.json = global.json
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Passwordless.AspNetCore", "src\Passwordless.AspNetCore\Passwordless.AspNetCore.csproj", "{7AEFC619-81DC-45FD-B805-D31FC64AD566}"
diff --git a/examples/Passwordless.AspNetIdentity.Example/DataContext/DataContextBootstrap.cs b/examples/Passwordless.AspNetIdentity.Example/DataContext/DataContextBootstrap.cs
index 767b637..9c6cafd 100644
--- a/examples/Passwordless.AspNetIdentity.Example/DataContext/DataContextBootstrap.cs
+++ b/examples/Passwordless.AspNetIdentity.Example/DataContext/DataContextBootstrap.cs
@@ -1,3 +1,5 @@
+using Microsoft.Extensions.DependencyInjection;
+
namespace Passwordless.AspNetIdentity.Example.DataContext;
public static class DataContextBootstrap
diff --git a/examples/Passwordless.AspNetIdentity.Example/DataContext/Migrations/20230912095422_Initial.cs b/examples/Passwordless.AspNetIdentity.Example/DataContext/Migrations/20230912095422_Initial.cs
index 14f76a5..eea1eb2 100644
--- a/examples/Passwordless.AspNetIdentity.Example/DataContext/Migrations/20230912095422_Initial.cs
+++ b/examples/Passwordless.AspNetIdentity.Example/DataContext/Migrations/20230912095422_Initial.cs
@@ -1,4 +1,5 @@
-using Microsoft.EntityFrameworkCore.Migrations;
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
diff --git a/examples/Passwordless.AspNetIdentity.Example/Pages/Account/Login.cshtml.cs b/examples/Passwordless.AspNetIdentity.Example/Pages/Account/Login.cshtml.cs
index f9a580e..4e4e38b 100644
--- a/examples/Passwordless.AspNetIdentity.Example/Pages/Account/Login.cshtml.cs
+++ b/examples/Passwordless.AspNetIdentity.Example/Pages/Account/Login.cshtml.cs
@@ -1,6 +1,10 @@
-using System.ComponentModel.DataAnnotations;
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.Threading;
+using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
+using Microsoft.Extensions.Logging;
namespace Passwordless.AspNetIdentity.Example.Pages.Account;
diff --git a/examples/Passwordless.AspNetIdentity.Example/Pages/Account/Register.cshtml.cs b/examples/Passwordless.AspNetIdentity.Example/Pages/Account/Register.cshtml.cs
index b3d3055..026a3bd 100644
--- a/examples/Passwordless.AspNetIdentity.Example/Pages/Account/Register.cshtml.cs
+++ b/examples/Passwordless.AspNetIdentity.Example/Pages/Account/Register.cshtml.cs
@@ -1,6 +1,10 @@
-using System.ComponentModel.DataAnnotations;
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.Threading;
+using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
+using Microsoft.Extensions.Logging;
using Passwordless.AspNetIdentity.Example.Validation;
namespace Passwordless.AspNetIdentity.Example.Pages.Account;
diff --git a/examples/Passwordless.AspNetIdentity.Example/Pages/Authorized/HelloWorld.cshtml.cs b/examples/Passwordless.AspNetIdentity.Example/Pages/Authorized/HelloWorld.cshtml.cs
index 7a382e7..fed31c2 100644
--- a/examples/Passwordless.AspNetIdentity.Example/Pages/Authorized/HelloWorld.cshtml.cs
+++ b/examples/Passwordless.AspNetIdentity.Example/Pages/Authorized/HelloWorld.cshtml.cs
@@ -1,5 +1,7 @@
-using System.Security.Claims;
+using System;
+using System.Security.Claims;
using Microsoft.AspNetCore.Mvc.RazorPages;
+using Microsoft.Extensions.Logging;
namespace Passwordless.AspNetIdentity.Example.Pages.Authorized;
diff --git a/examples/Passwordless.AspNetIdentity.Example/Pages/Error.cshtml.cs b/examples/Passwordless.AspNetIdentity.Example/Pages/Error.cshtml.cs
index 18b9b8b..b3aa7fa 100644
--- a/examples/Passwordless.AspNetIdentity.Example/Pages/Error.cshtml.cs
+++ b/examples/Passwordless.AspNetIdentity.Example/Pages/Error.cshtml.cs
@@ -1,6 +1,7 @@
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
+using Microsoft.Extensions.Logging;
namespace Passwordless.AspNetIdentity.Example.Pages;
diff --git a/examples/Passwordless.AspNetIdentity.Example/Pages/Index.cshtml.cs b/examples/Passwordless.AspNetIdentity.Example/Pages/Index.cshtml.cs
index 80308de..98b580a 100644
--- a/examples/Passwordless.AspNetIdentity.Example/Pages/Index.cshtml.cs
+++ b/examples/Passwordless.AspNetIdentity.Example/Pages/Index.cshtml.cs
@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
+using Microsoft.Extensions.Logging;
namespace Passwordless.AspNetIdentity.Example.Pages;
diff --git a/examples/Passwordless.AspNetIdentity.Example/Pages/Privacy.cshtml.cs b/examples/Passwordless.AspNetIdentity.Example/Pages/Privacy.cshtml.cs
index ba61a7d..8cd3d3e 100644
--- a/examples/Passwordless.AspNetIdentity.Example/Pages/Privacy.cshtml.cs
+++ b/examples/Passwordless.AspNetIdentity.Example/Pages/Privacy.cshtml.cs
@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
+using Microsoft.Extensions.Logging;
namespace Passwordless.AspNetIdentity.Example.Pages;
diff --git a/examples/Passwordless.AspNetIdentity.Example/Program.cs b/examples/Passwordless.AspNetIdentity.Example/Program.cs
index b8e9a2e..2b58d59 100644
--- a/examples/Passwordless.AspNetIdentity.Example/Program.cs
+++ b/examples/Passwordless.AspNetIdentity.Example/Program.cs
@@ -1,5 +1,8 @@
+using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
using Passwordless.AspNetCore;
using Passwordless.AspNetIdentity.Example.DataContext;
diff --git a/examples/Passwordless.Example/PasswordlessController.cs b/examples/Passwordless.Example/PasswordlessController.cs
index 54c1278..54d101c 100644
--- a/examples/Passwordless.Example/PasswordlessController.cs
+++ b/examples/Passwordless.Example/PasswordlessController.cs
@@ -1,4 +1,7 @@
-using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
namespace Passwordless.Example;
diff --git a/examples/Passwordless.Example/Program.cs b/examples/Passwordless.Example/Program.cs
index 0386f09..2c7acd3 100644
--- a/examples/Passwordless.Example/Program.cs
+++ b/examples/Passwordless.Example/Program.cs
@@ -1,3 +1,6 @@
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Hosting;
+
namespace Passwordless.Example;
public class Program
diff --git a/examples/Passwordless.Example/Startup.cs b/examples/Passwordless.Example/Startup.cs
index 1be1ba7..fbcc369 100644
--- a/examples/Passwordless.Example/Startup.cs
+++ b/examples/Passwordless.Example/Startup.cs
@@ -1,3 +1,9 @@
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
namespace Passwordless.Example;
public class Startup
diff --git a/global.json b/global.json
new file mode 100644
index 0000000..989a69c
--- /dev/null
+++ b/global.json
@@ -0,0 +1,6 @@
+{
+ "sdk": {
+ "version": "8.0.100",
+ "rollForward": "latestMinor"
+ }
+}
\ No newline at end of file
diff --git a/src/Passwordless.AspNetCore/IdentityBuilderExtensions.cs b/src/Passwordless.AspNetCore/IdentityBuilderExtensions.cs
index 1db4142..55144ee 100644
--- a/src/Passwordless.AspNetCore/IdentityBuilderExtensions.cs
+++ b/src/Passwordless.AspNetCore/IdentityBuilderExtensions.cs
@@ -1,4 +1,5 @@
-using System.Diagnostics.CodeAnalysis;
+using System;
+using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
diff --git a/src/Passwordless.AspNetCore/PasswordlessApiEndpointRouteBuilderExtensions.cs b/src/Passwordless.AspNetCore/PasswordlessApiEndpointRouteBuilderExtensions.cs
index 1d42c84..ff470ed 100644
--- a/src/Passwordless.AspNetCore/PasswordlessApiEndpointRouteBuilderExtensions.cs
+++ b/src/Passwordless.AspNetCore/PasswordlessApiEndpointRouteBuilderExtensions.cs
@@ -1,4 +1,7 @@
+using System;
using System.Security.Claims;
+using System.Threading;
+using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
diff --git a/src/Passwordless.AspNetCore/PasswordlessRegisterOptions.cs b/src/Passwordless.AspNetCore/PasswordlessRegisterOptions.cs
index b23423a..fa3f7c6 100644
--- a/src/Passwordless.AspNetCore/PasswordlessRegisterOptions.cs
+++ b/src/Passwordless.AspNetCore/PasswordlessRegisterOptions.cs
@@ -1,3 +1,5 @@
+using System;
+
namespace Passwordless.AspNetCore;
///
diff --git a/src/Passwordless.AspNetCore/Services/ICustomizeRegisterOptions.cs b/src/Passwordless.AspNetCore/Services/ICustomizeRegisterOptions.cs
index fb438e1..ab09cc0 100644
--- a/src/Passwordless.AspNetCore/Services/ICustomizeRegisterOptions.cs
+++ b/src/Passwordless.AspNetCore/Services/ICustomizeRegisterOptions.cs
@@ -1,3 +1,6 @@
+using System.Threading;
+using System.Threading.Tasks;
+
namespace Passwordless.AspNetCore.Services;
public interface ICustomizeRegisterOptions
diff --git a/src/Passwordless.AspNetCore/Services/IPasswordlessService.cs b/src/Passwordless.AspNetCore/Services/IPasswordlessService.cs
index f985dc3..8e28c2c 100644
--- a/src/Passwordless.AspNetCore/Services/IPasswordlessService.cs
+++ b/src/Passwordless.AspNetCore/Services/IPasswordlessService.cs
@@ -1,4 +1,7 @@
+using System.Collections.Generic;
using System.Security.Claims;
+using System.Threading;
+using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
namespace Passwordless.AspNetCore.Services;
diff --git a/src/Passwordless.AspNetCore/Services/Implementations/NoopCustomizeRegisterOptions.cs b/src/Passwordless.AspNetCore/Services/Implementations/NoopCustomizeRegisterOptions.cs
index c6b1540..e672ece 100644
--- a/src/Passwordless.AspNetCore/Services/Implementations/NoopCustomizeRegisterOptions.cs
+++ b/src/Passwordless.AspNetCore/Services/Implementations/NoopCustomizeRegisterOptions.cs
@@ -1,3 +1,6 @@
+using System.Threading;
+using System.Threading.Tasks;
+
namespace Passwordless.AspNetCore.Services.Implementations;
internal sealed class NoopCustomizeRegisterOptions : ICustomizeRegisterOptions
diff --git a/src/Passwordless.AspNetCore/Services/Implementations/PasswordlessService.cs b/src/Passwordless.AspNetCore/Services/Implementations/PasswordlessService.cs
index b21f31f..570f39e 100644
--- a/src/Passwordless.AspNetCore/Services/Implementations/PasswordlessService.cs
+++ b/src/Passwordless.AspNetCore/Services/Implementations/PasswordlessService.cs
@@ -1,4 +1,9 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
using System.Security.Claims;
+using System.Threading;
+using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
diff --git a/src/Passwordless/Base64Url.cs b/src/Passwordless/Base64Url.cs
index 32f92ef..5f4dc76 100644
--- a/src/Passwordless/Base64Url.cs
+++ b/src/Passwordless/Base64Url.cs
@@ -1,4 +1,5 @@
-using System.Buffers;
+using System;
+using System.Buffers;
using System.Buffers.Text;
namespace Passwordless;
diff --git a/src/Passwordless/Helpers/Base64UrlConverter.cs b/src/Passwordless/Helpers/Base64UrlConverter.cs
index 8b68c8c..a990156 100644
--- a/src/Passwordless/Helpers/Base64UrlConverter.cs
+++ b/src/Passwordless/Helpers/Base64UrlConverter.cs
@@ -1,3 +1,4 @@
+using System;
using System.Text.Json;
using System.Text.Json.Serialization;
diff --git a/src/Passwordless/Helpers/Extensions/HttpExtensions.cs b/src/Passwordless/Helpers/Extensions/HttpExtensions.cs
index 8e93e93..b11ee26 100644
--- a/src/Passwordless/Helpers/Extensions/HttpExtensions.cs
+++ b/src/Passwordless/Helpers/Extensions/HttpExtensions.cs
@@ -1,4 +1,7 @@
+using System.IO;
using System.Net;
+using System.Net.Http;
+using System.Threading.Tasks;
namespace Passwordless.Helpers.Extensions;
diff --git a/src/Passwordless/Helpers/PasswordlessSerializerContext.cs b/src/Passwordless/Helpers/PasswordlessSerializerContext.cs
index 95353c1..03d077e 100644
--- a/src/Passwordless/Helpers/PasswordlessSerializerContext.cs
+++ b/src/Passwordless/Helpers/PasswordlessSerializerContext.cs
@@ -1,3 +1,4 @@
+using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using Passwordless.Models;
diff --git a/src/Passwordless/IPasswordlessClient.cs b/src/Passwordless/IPasswordlessClient.cs
index 73b7393..02315a5 100644
--- a/src/Passwordless/IPasswordlessClient.cs
+++ b/src/Passwordless/IPasswordlessClient.cs
@@ -1,4 +1,7 @@
-using Passwordless.Models;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Passwordless.Models;
namespace Passwordless;
diff --git a/src/Passwordless/Models/Credential.cs b/src/Passwordless/Models/Credential.cs
index fc85d25..6044cfa 100644
--- a/src/Passwordless/Models/Credential.cs
+++ b/src/Passwordless/Models/Credential.cs
@@ -1,4 +1,6 @@
-namespace Passwordless;
+using System;
+
+namespace Passwordless;
///
/// The passkey credential stored by Passwordless
diff --git a/src/Passwordless/Models/ListResponse.cs b/src/Passwordless/Models/ListResponse.cs
index 248f527..bed312f 100644
--- a/src/Passwordless/Models/ListResponse.cs
+++ b/src/Passwordless/Models/ListResponse.cs
@@ -1,3 +1,5 @@
+using System.Collections.Generic;
+
namespace Passwordless.Models;
internal class ListResponse
diff --git a/src/Passwordless/Models/PasswordlessUserSummary.cs b/src/Passwordless/Models/PasswordlessUserSummary.cs
index 1542211..06a871a 100644
--- a/src/Passwordless/Models/PasswordlessUserSummary.cs
+++ b/src/Passwordless/Models/PasswordlessUserSummary.cs
@@ -1,3 +1,6 @@
+using System;
+using System.Collections.Generic;
+
namespace Passwordless;
public class PasswordlessUserSummary
diff --git a/src/Passwordless/Models/RegisterOptions.cs b/src/Passwordless/Models/RegisterOptions.cs
index 06f1203..c939f98 100644
--- a/src/Passwordless/Models/RegisterOptions.cs
+++ b/src/Passwordless/Models/RegisterOptions.cs
@@ -1,4 +1,7 @@
-namespace Passwordless;
+using System;
+using System.Collections.Generic;
+
+namespace Passwordless;
///
///
diff --git a/src/Passwordless/Models/SetAliasRequest.cs b/src/Passwordless/Models/SetAliasRequest.cs
index 7d68e0f..14ad0ce 100644
--- a/src/Passwordless/Models/SetAliasRequest.cs
+++ b/src/Passwordless/Models/SetAliasRequest.cs
@@ -1,3 +1,7 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
namespace Passwordless.Models;
public class SetAliasRequest
diff --git a/src/Passwordless/Models/VerifiedUser.cs b/src/Passwordless/Models/VerifiedUser.cs
index a0428a7..c497fbf 100644
--- a/src/Passwordless/Models/VerifiedUser.cs
+++ b/src/Passwordless/Models/VerifiedUser.cs
@@ -1,4 +1,6 @@
-namespace Passwordless;
+using System;
+
+namespace Passwordless;
public class VerifiedUser
{
diff --git a/src/Passwordless/Passwordless.csproj b/src/Passwordless/Passwordless.csproj
index 24a033c..d58819d 100644
--- a/src/Passwordless/Passwordless.csproj
+++ b/src/Passwordless/Passwordless.csproj
@@ -2,9 +2,7 @@
net462;net6.0;net7.0;netstandard2.0
- $(TargetFrameworks);$(CurrentPreviewTfm)
true
- true
diff --git a/src/Passwordless/PasswordlessApiException.cs b/src/Passwordless/PasswordlessApiException.cs
index 91c1294..e1a8f39 100644
--- a/src/Passwordless/PasswordlessApiException.cs
+++ b/src/Passwordless/PasswordlessApiException.cs
@@ -1,3 +1,5 @@
+using System.Collections.Generic;
+using System.Net.Http;
using System.Text.Json;
using System.Text.Json.Serialization;
diff --git a/src/Passwordless/PasswordlessClient.cs b/src/Passwordless/PasswordlessClient.cs
index c008e12..38b5d42 100644
--- a/src/Passwordless/PasswordlessClient.cs
+++ b/src/Passwordless/PasswordlessClient.cs
@@ -1,6 +1,11 @@
+using System;
+using System.Collections.Generic;
using System.Diagnostics;
+using System.Net.Http;
using System.Net.Http.Json;
using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
using Passwordless.Helpers;
using Passwordless.Models;
using JsonContext = Passwordless.Helpers.PasswordlessSerializerContext;
diff --git a/src/Passwordless/PasswordlessHttpHandler.cs b/src/Passwordless/PasswordlessHttpHandler.cs
index d716038..3e6a3bd 100644
--- a/src/Passwordless/PasswordlessHttpHandler.cs
+++ b/src/Passwordless/PasswordlessHttpHandler.cs
@@ -1,4 +1,8 @@
+using System;
+using System.Net.Http;
using System.Net.Http.Json;
+using System.Threading;
+using System.Threading.Tasks;
using Passwordless.Helpers;
using Passwordless.Helpers.Extensions;
diff --git a/src/Passwordless/ServiceCollectionExtensions.cs b/src/Passwordless/ServiceCollectionExtensions.cs
index d1dd001..e8a49c7 100644
--- a/src/Passwordless/ServiceCollectionExtensions.cs
+++ b/src/Passwordless/ServiceCollectionExtensions.cs
@@ -1,3 +1,4 @@
+using System;
using Microsoft.Extensions.Options;
using Passwordless;
diff --git a/tests/Passwordless.AspNetCore.Tests/Passwordless.AspNetCore.Tests.csproj b/tests/Passwordless.AspNetCore.Tests/Passwordless.AspNetCore.Tests.csproj
index 5c7815b..e1f5746 100644
--- a/tests/Passwordless.AspNetCore.Tests/Passwordless.AspNetCore.Tests.csproj
+++ b/tests/Passwordless.AspNetCore.Tests/Passwordless.AspNetCore.Tests.csproj
@@ -1,7 +1,7 @@
- net7.0
+ net8.0
diff --git a/tests/Passwordless.AspNetCore.Tests/RegistrationTests.cs b/tests/Passwordless.AspNetCore.Tests/RegistrationTests.cs
index eebabd1..19311f8 100644
--- a/tests/Passwordless.AspNetCore.Tests/RegistrationTests.cs
+++ b/tests/Passwordless.AspNetCore.Tests/RegistrationTests.cs
@@ -1,9 +1,11 @@
+using System.Collections.Generic;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Passwordless.AspNetCore.Services;
+using Xunit;
namespace Passwordless.AspNetCore.Tests;
diff --git a/tests/Passwordless.AspNetCore.Tests/Services/PasswordlessServiceTests.cs b/tests/Passwordless.AspNetCore.Tests/Services/PasswordlessServiceTests.cs
index 9ecf034..740cfce 100644
--- a/tests/Passwordless.AspNetCore.Tests/Services/PasswordlessServiceTests.cs
+++ b/tests/Passwordless.AspNetCore.Tests/Services/PasswordlessServiceTests.cs
@@ -1,4 +1,9 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
using System.Security.Claims;
+using System.Threading;
+using System.Threading.Tasks;
using AutoFixture;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
@@ -10,6 +15,7 @@
using Passwordless.AspNetCore.Services;
using Passwordless.AspNetCore.Services.Implementations;
using Passwordless.Models;
+using Xunit;
namespace Passwordless.AspNetCore.Tests.Services;
diff --git a/tests/Passwordless.AspNetCore.Tests/Usings.cs b/tests/Passwordless.AspNetCore.Tests/Usings.cs
deleted file mode 100644
index 8c927eb..0000000
--- a/tests/Passwordless.AspNetCore.Tests/Usings.cs
+++ /dev/null
@@ -1 +0,0 @@
-global using Xunit;
\ No newline at end of file
diff --git a/tests/Passwordless.Tests/Fixtures/TestApiFixture.cs b/tests/Passwordless.Tests/Fixtures/TestApiFixture.cs
index e644eba..ad57bad 100644
--- a/tests/Passwordless.Tests/Fixtures/TestApiFixture.cs
+++ b/tests/Passwordless.Tests/Fixtures/TestApiFixture.cs
@@ -1,7 +1,12 @@
+using System;
+using System.IO;
using System.Net;
+using System.Net.Http;
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
+using System.Threading;
+using System.Threading.Tasks;
using DotNet.Testcontainers.Builders;
using DotNet.Testcontainers.Containers;
using DotNet.Testcontainers.Images;
@@ -14,6 +19,10 @@ namespace Passwordless.Tests.Fixtures;
public class TestApiFixture : IAsyncLifetime
{
+ private const string ManagementKey = "yourStrong(!)ManagementKey";
+ private const string DatabaseHost = "database";
+ private const ushort ApiPort = 8080;
+
private readonly HttpClient _http = new();
private readonly INetwork _network;
@@ -25,20 +34,17 @@ public class TestApiFixture : IAsyncLifetime
private readonly MemoryStream _apiContainerStdOut = new();
private readonly MemoryStream _apiContainerStdErr = new();
- private string PublicApiUrl => $"http://localhost:{_apiContainer.GetMappedPublicPort(80)}";
+ private string PublicApiUrl => $"http://{_apiContainer.Hostname}:{_apiContainer.GetMappedPublicPort(ApiPort)}";
public TestApiFixture()
{
- const string managementKey = "yourStrong(!)ManagementKey";
- const string databaseHost = "database";
-
_network = new NetworkBuilder()
.Build();
_databaseContainer = new MsSqlBuilder()
.WithImage("mcr.microsoft.com/mssql/server:2022-latest")
.WithNetwork(_network)
- .WithNetworkAliases(databaseHost)
+ .WithNetworkAliases(DatabaseHost)
.WithOutputConsumer(
Consume.RedirectStdoutAndStderrToStream(_databaseContainerStdOut, _databaseContainerStdErr)
)
@@ -53,22 +59,24 @@ public TestApiFixture()
.WithNetwork(_network)
// Run in development environment to execute migrations
.WithEnvironment("ASPNETCORE_ENVIRONMENT", "Development")
+ .WithEnvironment("ASPNETCORE_HTTP_PORTS", ApiPort.ToString())
.WithEnvironment("ConnectionStrings__sqlite:api", "")
.WithEnvironment("ConnectionStrings__mssql:api",
- $"Server={databaseHost},{MsSqlBuilder.MsSqlPort};" +
+ $"Server={DatabaseHost},{MsSqlBuilder.MsSqlPort};" +
"Database=Passwordless;" +
$"User Id={MsSqlBuilder.DefaultUsername};" +
$"Password={MsSqlBuilder.DefaultPassword};" +
"Trust Server Certificate=true;" +
"Trusted_Connection=false;"
)
- .WithEnvironment("PasswordlessManagement__ManagementKey", managementKey)
- .WithPortBinding(80, true)
+ .WithEnvironment("PasswordlessManagement__ManagementKey", ManagementKey)
+ .WithPortBinding(ApiPort, true)
// Wait until the API is launched, has performed migrations, and is ready to accept requests
.WithWaitStrategy(Wait
.ForUnixContainer()
.UntilHttpRequestIsSucceeded(r => r
.ForPath("/")
+ .ForPort(ApiPort)
.ForStatusCode(HttpStatusCode.OK)
)
)
@@ -77,14 +85,32 @@ public TestApiFixture()
)
.Build();
- _http.DefaultRequestHeaders.Add("ManagementKey", managementKey);
+ _http.DefaultRequestHeaders.Add("ManagementKey", ManagementKey);
}
public async Task InitializeAsync()
{
- await _network.CreateAsync();
- await _databaseContainer.StartAsync();
- await _apiContainer.StartAsync();
+ try
+ {
+ // Introduce a timeout to avoid waiting forever for the containers to start
+ // in case something goes wrong (e.g. wait strategy never succeeds).
+ using var timeoutCts = new CancellationTokenSource(TimeSpan.FromMinutes(5));
+
+ await _network.CreateAsync(timeoutCts.Token);
+ await _databaseContainer.StartAsync(timeoutCts.Token);
+ await _apiContainer.StartAsync(timeoutCts.Token);
+ }
+ catch (Exception ex) when (ex is OperationCanceledException or TimeoutException)
+ {
+ throw new OperationCanceledException(
+ "Failed to start the containers within the allotted timeout. " +
+ "This probably means that something went wrong during container initialization. " +
+ "See the logs for more info." +
+ Environment.NewLine + Environment.NewLine +
+ GetLogs(),
+ ex
+ );
+ }
}
public async Task CreateClientAsync()
diff --git a/tests/Passwordless.Tests/Infra/ApiTestBase.cs b/tests/Passwordless.Tests/Infra/ApiTestBase.cs
index 82701cf..d8a84c4 100644
--- a/tests/Passwordless.Tests/Infra/ApiTestBase.cs
+++ b/tests/Passwordless.Tests/Infra/ApiTestBase.cs
@@ -1,3 +1,4 @@
+using System;
using Passwordless.Tests.Fixtures;
using Xunit;
using Xunit.Abstractions;
diff --git a/tests/Passwordless.Tests/Passwordless.Tests.csproj b/tests/Passwordless.Tests/Passwordless.Tests.csproj
index 25dfad3..1513327 100644
--- a/tests/Passwordless.Tests/Passwordless.Tests.csproj
+++ b/tests/Passwordless.Tests/Passwordless.Tests.csproj
@@ -4,9 +4,8 @@
true
$([MSBuild]::IsOsPlatform('Windows'))
- $(TargetFrameworks);net6.0;net7.0
+ $(TargetFrameworks);net6.0;net8.0
$(TargetFrameworks);net462
- $(TargetFrameworks);$(CurrentPreviewTfm)
diff --git a/tests/Passwordless.Tests/TokenTests.cs b/tests/Passwordless.Tests/TokenTests.cs
index 5f06008..d4be8ec 100644
--- a/tests/Passwordless.Tests/TokenTests.cs
+++ b/tests/Passwordless.Tests/TokenTests.cs
@@ -1,3 +1,4 @@
+using System.Threading.Tasks;
using FluentAssertions;
using Passwordless.Tests.Fixtures;
using Passwordless.Tests.Infra;
diff --git a/tests/Passwordless.Tests/UserTests.cs b/tests/Passwordless.Tests/UserTests.cs
index ea2207b..fef3122 100644
--- a/tests/Passwordless.Tests/UserTests.cs
+++ b/tests/Passwordless.Tests/UserTests.cs
@@ -1,3 +1,4 @@
+using System.Threading.Tasks;
using FluentAssertions;
using Passwordless.Tests.Fixtures;
using Passwordless.Tests.Infra;