From 5d92988095efbcfb8e3d63786b7a32c6596a4368 Mon Sep 17 00:00:00 2001 From: aicia-bot Date: Thu, 29 Oct 2026 18:10:58 +0100 Subject: [PATCH 01/14] =?UTF-8?q?=F0=9F=94=A5=20remove=20benchmark=20promp?= =?UTF-8?q?t=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Copilot benchmark prompt is no longer used by the repository and is removed to keep the workflow prompts current. --- .github/prompts/benchmark.prompt.md | 164 ---------------------------- 1 file changed, 164 deletions(-) delete mode 100644 .github/prompts/benchmark.prompt.md diff --git a/.github/prompts/benchmark.prompt.md b/.github/prompts/benchmark.prompt.md deleted file mode 100644 index 22d1c9d..0000000 --- a/.github/prompts/benchmark.prompt.md +++ /dev/null @@ -1,164 +0,0 @@ ---- -mode: agent -description: 'Writing Performance Benchmarks' ---- - -# Benchmark Fixture Prompt (Tuning Benchmarks) - -This prompt defines how to generate performance tests (“benchmarks”) for a project/solution using BenchmarkDotNet. -Benchmarks are *not* unit tests — they are micro- or component-level performance measurements that belong under the `tuning/` directory and follow strict conventions. - -Copilot must follow these guidelines when generating benchmark fixtures. - ---- - -## 1. Naming and Placement - -- All benchmark projects live under the `tuning/` folder. - Examples: - - `tuning/.Benchmarks/` - - `tuning/.Console.Benchmarks/` - -- **Namespaces must NOT end with `.Benchmarks`.** - They must mirror the production assembly’s namespace. - - Example: - If benchmarking a type inside `YourProject.Console`, then: - - ```csharp - namespace YourProject.Console - { - public class Sha512256Benchmark { … } - } - ``` - -* **Benchmark class names must end with `Benchmark`.** - Example: `DateSpanBenchmark`, `FowlerNollVoBenchmark`. - -* Benchmark files should be located in the matching benchmark project - (e.g., benchmarks for `YourProject.Console` go in `YourProject.Console.Benchmarks.csproj`). - -* In the `.csproj` for each benchmark project, set the root namespace to the production namespace, for example: - - ```xml - YourProject.Console - ``` - ---- - -## 2. Attributes and Configuration - -Each benchmark class should use: - -```csharp -[MemoryDiagnoser] -[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] -``` - -Optional but strongly recommended where meaningful: - -* `[Params(...)]` — define small, medium, large input sizes. -* `[GlobalSetup]` — deterministic initialization of benchmark data. -* `[Benchmark(Description = "...")]` — always add descriptions. -* `[Benchmark(Baseline = true)]` — when comparing two implementations. - -Avoid complex global configs; prefer explicit attributes inside the class. - ---- - -## 3. Structure and Best Practices - -A benchmark fixture must: - -* Measure a **single logical operation** per benchmark method. -* Avoid I/O, networking, disk access, logging, or side effects. -* Avoid expensive setup inside `[Benchmark]` methods. -* Use deterministic data (e.g., seeded RNG or predefined constants). -* Use `[GlobalSetup]` to allocate buffers, random payloads, or reusable test data only once. -* Avoid shared mutable state unless reset per iteration. - -Use representative input sizes such as: - -```csharp -[Params(8, 256, 4096)] -public int Count { get; set; } -``` - -BenchmarkDotNet will run each benchmark for each parameter value. - ---- - -## 4. Method Naming Conventions - -Use descriptive names that communicate intent: - -* `Parse_Short` -* `Parse_Long` -* `ComputeHash_Small` -* `ComputeHash_Large` -* `Serialize_Optimized` -* `Serialize_Baseline` - -When comparing approaches, always list them clearly and tag one as the baseline. - ---- - -## 5. Example Benchmark Fixture - -```csharp -using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Configs; - -namespace YourProject -{ - [MemoryDiagnoser] - [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] - public class SampleOperationBenchmark - { - [Params(8, 256, 4096)] - public int Count { get; set; } - - private byte[] _payload; - - [GlobalSetup] - public void Setup() - { - _payload = new byte[Count]; - // deterministic initialization - } - - [Benchmark(Baseline = true, Description = "Operation - baseline")] - public int Operation_Baseline() => SampleOperation.Process(_payload); - - [Benchmark(Description = "Operation - optimized")] - public int Operation_Optimized() => SampleOperation.ProcessOptimized(_payload); - } -} -``` - ---- - -## 6. Reporting and CI - -* Benchmark projects live exclusively under `tuning/`. They must not affect production builds. -* Heavy BenchmarkDotNet runs should *not* run in CI unless explicitly configured. -* Reports are produced by the benchmark runner and stored under the configured artifacts directory. - ---- - -## 7. Additional Guidelines - -* Keep benchmark fixtures focused and readable. -* Document non-obvious reasoning in short comments. -* Prefer realistic but deterministic data sets. -* When benchmarks reveal regressions or improvements, reference the associated PR or issue in a comment. -* Shared benchmark helpers belong in `tuning/` projects, not in production code. - ---- - -## Final Notes - -* Benchmarks are performance tests, not unit tests. -* Use `[Benchmark]` only for pure performance measurement. -* Avoid `MethodImplOptions.NoInlining` unless absolutely necessary. -* Use small sets of meaningful benchmark scenarios — avoid combinatorial explosion. From 489f5fd3c9366a9b07b9239c6b9133446a06b8a7 Mon Sep 17 00:00:00 2001 From: aicia-bot Date: Thu, 29 Oct 2026 18:10:59 +0100 Subject: [PATCH 02/14] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20upgrade=20target=20f?= =?UTF-8?q?rameworks=20and=20package=20versions=20to=20net11?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The solution moves from net9.0 and net10.0 to net10.0 and net11.0 and bumps the package baselines to match the new SDK. Consumers on net9.0 are no longer targeted. --- Directory.Build.props | 5 +-- Directory.Build.targets | 2 +- Directory.Packages.props | 33 ++++++++++--------- .../Codebelt.Bootstrapper.Console.App.csproj | 2 +- ...elt.Bootstrapper.MinimalConsole.App.csproj | 2 +- ...belt.Bootstrapper.MinimalWebApi.App.csproj | 2 +- .../Codebelt.Bootstrapper.Console.csproj | 2 +- .../Codebelt.Bootstrapper.Web.csproj | 2 +- .../Codebelt.Bootstrapper.csproj | 2 +- ...debelt.Bootstrapper.FunctionalTests.csproj | 2 +- 10 files changed, 28 insertions(+), 26 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index ceca187..68a1188 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,7 +14,7 @@ - net10.0;net9.0 + net11.0;net10.0 Copyright © Geekle 2021-2026. All rights reserved. gimlichael Geekle @@ -47,13 +47,14 @@ + Exe - net10.0;net9.0 + net11.0;net10.0 false false false diff --git a/Directory.Build.targets b/Directory.Build.targets index 00bb68a..f6a6a00 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,4 +1,4 @@ - + $([System.IO.File]::ReadAllText('$(PackageReleaseNotesFile)')) diff --git a/Directory.Packages.props b/Directory.Packages.props index 97631a9..c6772c7 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -3,30 +3,31 @@ true - + - - + + - + - - - - - - - + - - - - - + + + + + + + + + + + + diff --git a/app/Codebelt.Bootstrapper.Console.App/Codebelt.Bootstrapper.Console.App.csproj b/app/Codebelt.Bootstrapper.Console.App/Codebelt.Bootstrapper.Console.App.csproj index c4fd29a..c19fab9 100644 --- a/app/Codebelt.Bootstrapper.Console.App/Codebelt.Bootstrapper.Console.App.csproj +++ b/app/Codebelt.Bootstrapper.Console.App/Codebelt.Bootstrapper.Console.App.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/app/Codebelt.Bootstrapper.MinimalConsole.App/Codebelt.Bootstrapper.MinimalConsole.App.csproj b/app/Codebelt.Bootstrapper.MinimalConsole.App/Codebelt.Bootstrapper.MinimalConsole.App.csproj index 7c322c3..06e5cad 100644 --- a/app/Codebelt.Bootstrapper.MinimalConsole.App/Codebelt.Bootstrapper.MinimalConsole.App.csproj +++ b/app/Codebelt.Bootstrapper.MinimalConsole.App/Codebelt.Bootstrapper.MinimalConsole.App.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/app/Codebelt.Bootstrapper.MinimalWebApi.App/Codebelt.Bootstrapper.MinimalWebApi.App.csproj b/app/Codebelt.Bootstrapper.MinimalWebApi.App/Codebelt.Bootstrapper.MinimalWebApi.App.csproj index e53b0a2..b073392 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebApi.App/Codebelt.Bootstrapper.MinimalWebApi.App.csproj +++ b/app/Codebelt.Bootstrapper.MinimalWebApi.App/Codebelt.Bootstrapper.MinimalWebApi.App.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/src/Codebelt.Bootstrapper.Console/Codebelt.Bootstrapper.Console.csproj b/src/Codebelt.Bootstrapper.Console/Codebelt.Bootstrapper.Console.csproj index 590f824..35f7283 100644 --- a/src/Codebelt.Bootstrapper.Console/Codebelt.Bootstrapper.Console.csproj +++ b/src/Codebelt.Bootstrapper.Console/Codebelt.Bootstrapper.Console.csproj @@ -1,4 +1,4 @@ - + An implementation optimized for console applications that is managed by its host. diff --git a/src/Codebelt.Bootstrapper.Web/Codebelt.Bootstrapper.Web.csproj b/src/Codebelt.Bootstrapper.Web/Codebelt.Bootstrapper.Web.csproj index 158c083..530eb0d 100644 --- a/src/Codebelt.Bootstrapper.Web/Codebelt.Bootstrapper.Web.csproj +++ b/src/Codebelt.Bootstrapper.Web/Codebelt.Bootstrapper.Web.csproj @@ -1,4 +1,4 @@ - + An implementation optimized for web applications that is managed by its host. diff --git a/src/Codebelt.Bootstrapper/Codebelt.Bootstrapper.csproj b/src/Codebelt.Bootstrapper/Codebelt.Bootstrapper.csproj index bfa6f45..24d4fe6 100644 --- a/src/Codebelt.Bootstrapper/Codebelt.Bootstrapper.csproj +++ b/src/Codebelt.Bootstrapper/Codebelt.Bootstrapper.csproj @@ -1,4 +1,4 @@ - + The core types of this lightweight boostrapper framework optimized for console applicationss, providing a uniform and consistent implementation of console-, worker-, web-, mvc-, webapp- and webapi-project types. diff --git a/test/Codebelt.Bootstrapper.FunctionalTests/Codebelt.Bootstrapper.FunctionalTests.csproj b/test/Codebelt.Bootstrapper.FunctionalTests/Codebelt.Bootstrapper.FunctionalTests.csproj index e91ad88..06a6cd1 100644 --- a/test/Codebelt.Bootstrapper.FunctionalTests/Codebelt.Bootstrapper.FunctionalTests.csproj +++ b/test/Codebelt.Bootstrapper.FunctionalTests/Codebelt.Bootstrapper.FunctionalTests.csproj @@ -1,4 +1,4 @@ - + Codebelt.Bootstrapper From ce6f234fdb2683c97930d4470fa5235c6180a54f Mon Sep 17 00:00:00 2001 From: aicia-bot Date: Thu, 29 Oct 2026 18:11:00 +0100 Subject: [PATCH 03/14] =?UTF-8?q?=F0=9F=8E=A8=20remove=20byte=20order=20ma?= =?UTF-8?q?rks=20and=20use=20file-scoped=20namespaces?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Source, test and sample files are normalized to UTF-8 without BOM and file-scoped namespaces per the editorconfig rules. The bulk of the change is mechanical; a few Startup files also get small edits in the same pass. --- .../Program.cs | 19 +- .../Startup.cs | 75 ++-- .../Program.cs | 63 ++- .../Program.cs | 35 +- .../Properties/launchSettings.json | 2 +- .../Program.cs | 97 +++-- .../Properties/launchSettings.json | 2 +- .../WeatherForecast.cs | 15 +- .../Pages/Error.cshtml | 2 +- .../Pages/Error.cshtml.cs | 32 +- .../Pages/Index.cshtml | 2 +- .../Pages/Index.cshtml.cs | 21 +- .../Pages/Privacy.cshtml | 2 +- .../Pages/Privacy.cshtml.cs | 24 +- .../Pages/Shared/_Layout.cshtml.css | 2 +- .../Shared/_ValidationScriptsPartial.cshtml | 2 +- .../Pages/_ViewImports.cshtml | 2 +- .../Pages/_ViewStart.cshtml | 2 +- .../Program.cs | 49 ++- .../wwwroot/js/site.js | 2 +- .../Controllers/HomeController.cs | 41 +- .../Models/ErrorViewModel.cs | 11 +- .../Program.cs | 55 ++- .../Properties/launchSettings.json | 2 +- .../Views/Home/Index.cshtml | 2 +- .../Views/Home/Privacy.cshtml | 2 +- .../Views/Shared/Error.cshtml | 2 +- .../Views/Shared/_Layout.cshtml | 2 +- .../Views/Shared/_Layout.cshtml.css | 2 +- .../Shared/_ValidationScriptsPartial.cshtml | 2 +- .../Views/_ViewImports.cshtml | 2 +- .../Views/_ViewStart.cshtml | 2 +- .../wwwroot/js/site.js | 2 +- .../FakeHostedService.cs | 49 ++- .../Program.cs | 19 +- .../Properties/launchSettings.json | 2 +- app/Codebelt.Bootstrapper.Web.App/Program.cs | 15 +- .../Properties/launchSettings.json | 2 +- app/Codebelt.Bootstrapper.Web.App/Startup.cs | 39 +- .../Controllers/WeatherForecastController.cs | 49 ++- .../Program.cs | 17 +- .../Properties/launchSettings.json | 2 +- .../Startup.cs | 57 ++- .../WeatherForecast.cs | 15 +- .../Pages/Error.cshtml | 2 +- .../Pages/Error.cshtml.cs | 31 +- .../Pages/Index.cshtml | 2 +- .../Pages/Index.cshtml.cs | 23 +- .../Pages/Privacy.cshtml | 2 +- .../Pages/Privacy.cshtml.cs | 23 +- .../Pages/Shared/_Layout.cshtml | 2 +- .../Shared/_ValidationScriptsPartial.cshtml | 2 +- .../Pages/_ViewStart.cshtml | 2 +- .../Program.cs | 11 +- .../Properties/launchSettings.json | 2 +- .../Startup.cs | 63 ++- .../wwwroot/css/site.css | 2 +- .../wwwroot/js/site.js | 2 +- .../Controllers/HomeController.cs | 43 +- .../Models/ErrorViewModel.cs | 11 +- .../Program.cs | 11 +- .../Properties/launchSettings.json | 2 +- .../Startup.cs | 65 ++- .../Views/Home/Index.cshtml | 2 +- .../Views/Home/Privacy.cshtml | 2 +- .../Views/Shared/Error.cshtml | 2 +- .../Views/Shared/_Layout.cshtml | 2 +- .../Shared/_ValidationScriptsPartial.cshtml | 2 +- .../Views/_ViewImports.cshtml | 2 +- .../Views/_ViewStart.cshtml | 2 +- .../wwwroot/css/site.css | 2 +- .../wwwroot/js/site.js | 2 +- .../FakeHostedService.cs | 49 ++- .../Program.cs | 19 +- .../Startup.cs | 19 +- .../ConsoleHostedService.cs | 187 ++++---- .../ConsoleProgram.cs | 37 +- .../ConsoleStartup.cs | 53 ++- .../HostApplicationBuilderExtensions.cs | 49 ++- .../HostBuilderExtensions.cs | 31 +- .../IProgramFactory.cs | 19 +- .../MinimalConsoleHostedService.cs | 195 +++++---- .../MinimalConsoleProgram.cs | 77 ++-- .../ProgramFactory.cs | 39 +- .../Properties/AssemblyInfo.cs | 4 +- .../MinimalWebProgram.cs | 31 +- .../Properties/AssemblyInfo.cs | 4 +- src/Codebelt.Bootstrapper.Web/WebProgram.cs | 41 +- src/Codebelt.Bootstrapper.Web/WebStartup.cs | 49 ++- .../MinimalWorkerProgram.cs | 31 +- .../Properties/AssemblyInfo.cs | 4 +- .../WorkerProgram.cs | 35 +- .../WorkerStartup.cs | 25 +- .../BootstrapperLifetime.cs | 149 ++++--- .../BootstrapperLogMessages.cs | 117 +++-- .../CommandLineContext.cs | 2 +- .../GlobalSuppressions.cs | 2 +- .../HostApplicationBuilderExtensions.cs | 79 ++-- .../HostBuilderExtensions.cs | 91 ++-- .../HostEnvironmentExtensions.cs | 17 +- .../IHostLifetimeEvents.cs | 35 +- src/Codebelt.Bootstrapper/IStartupFactory.cs | 21 +- src/Codebelt.Bootstrapper/ProgramRoot.cs | 29 +- .../Properties/AssemblyInfo.cs | 4 +- src/Codebelt.Bootstrapper/StartupFactory.cs | 45 +- src/Codebelt.Bootstrapper/StartupRoot.cs | 59 ++- .../Assets/NullProgramFactory.cs | 19 +- .../Assets/NullStartupFactory.cs | 9 +- .../Assets/TestConsoleProgram.cs | 9 +- .../Assets/TestConsoleStartup.cs | 29 +- .../Assets/TestConsoleStartupWithException.cs | 65 ++- .../TestConsoleStartupWithPrematureEnd.cs | 69 ++- .../TestGenericMinimalConsoleProgram.cs | 15 +- .../Assets/TestHostFixture.cs | 47 +- .../Assets/TestMinimalConsoleProgram.cs | 21 +- .../TestMinimalConsoleProgramWithException.cs | 35 +- ...stMinimalConsoleProgramWithPrematureEnd.cs | 39 +- .../ConsoleHostedServiceTest.cs | 401 +++++++++--------- .../ConsoleProgramTest.cs | 31 +- .../ConsoleStartupTest.cs | 49 ++- .../MinimalConsoleHostedServiceTest.cs | 401 +++++++++--------- .../MinimalConsoleProgramBuilderTest.cs | 61 ++- .../Assets/TestBackgroundService.cs | 55 ++- .../Assets/TestHostFixture.cs | 47 +- .../Assets/TestStartup.cs | 17 +- .../BootstrapperLifetimeTest.cs | 107 +++-- .../BootstrapperLogMessagesTest.cs | 29 +- .../HostApplicationBuilderExtensionsTest.cs | 183 ++++---- .../HostBuilderExtensionsTest.cs | 131 +++--- .../HostedServiceExtensionsTest.cs | 73 ++-- .../Assets/StartupRootUnsafeAccessor.cs | 17 +- .../Assets/TestStartupRoot.cs | 21 +- .../CommandLineContextTest.cs | 157 ++++--- .../StartupRootTest.cs | 111 +++-- .../Assets/TestMinimalWebProgram.cs | 9 +- .../Assets/TestStartup.cs | 41 +- .../Assets/TestWebProgram.cs | 9 +- .../MinimalWebProgramBuilderTest.cs | 43 +- .../MinimalWebProgramTest.cs | 55 ++- .../WebProgramTest.cs | 41 +- .../WebStartupTest.cs | 45 +- .../Assets/FakeHostedService.cs | 71 ++-- .../Assets/TestMinimalWorkerProgram.cs | 9 +- .../Assets/TestStartup.cs | 19 +- .../Assets/TestWorkerProgram.cs | 9 +- .../MinimalWorkerProgramBuilderTest.cs | 23 +- .../MinimalWorkerProgramTest.cs | 63 ++- .../WorkerProgramTest.cs | 27 +- .../WorkerStartupTest.cs | 63 ++- 149 files changed, 2741 insertions(+), 2844 deletions(-) diff --git a/app/Codebelt.Bootstrapper.Console.App/Program.cs b/app/Codebelt.Bootstrapper.Console.App/Program.cs index 7efe4db..5bce538 100644 --- a/app/Codebelt.Bootstrapper.Console.App/Program.cs +++ b/app/Codebelt.Bootstrapper.Console.App/Program.cs @@ -1,18 +1,17 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Console.App +namespace Codebelt.Bootstrapper.Console.App; + +public class Program : ConsoleProgram { - public class Program : ConsoleProgram + static Task Main(string[] args) { - static Task Main(string[] args) - { - var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); // simulate cronjob that has exceeded a max. running time - var builder = CreateHostBuilder(args); - var host = builder.Build(); - return host.RunAsync(cts.Token); - } + var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); // simulate cronjob that has exceeded a max. running time + var builder = CreateHostBuilder(args); + var host = builder.Build(); + return host.RunAsync(cts.Token); } } diff --git a/app/Codebelt.Bootstrapper.Console.App/Startup.cs b/app/Codebelt.Bootstrapper.Console.App/Startup.cs index a727e2d..56b4afb 100644 --- a/app/Codebelt.Bootstrapper.Console.App/Startup.cs +++ b/app/Codebelt.Bootstrapper.Console.App/Startup.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using Cuemon; @@ -8,53 +8,52 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -namespace Codebelt.Bootstrapper.Console.App +namespace Codebelt.Bootstrapper.Console.App; + +public class Startup : ConsoleStartup { - public class Startup : ConsoleStartup + public Startup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) { - public Startup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) - { - } + } - public override void ConfigureServices(IServiceCollection services) - { - services.AddSingleton(new CorrelationToken()); - } + public override void ConfigureServices(IServiceCollection services) + { + services.AddSingleton(new CorrelationToken()); + } - public override void ConfigureConsole(IServiceProvider serviceProvider) + public override void ConfigureConsole(IServiceProvider serviceProvider) + { + var logger = serviceProvider.GetRequiredService>(); + var events = serviceProvider.GetRequiredService(); + + events.OnApplicationStartedCallback = () => { - var logger = serviceProvider.GetRequiredService>(); - var events = serviceProvider.GetRequiredService(); - - events.OnApplicationStartedCallback = () => - { - logger.LogWarning("Console started."); - }; - - events.OnApplicationStoppingCallback = () => - { - logger.LogWarning("Stopping and cleaning .."); - Thread.Sleep(TimeSpan.FromSeconds(5)); // simulate graceful shutdown - logger.LogWarning(".. done!"); - }; - - events.OnApplicationStoppedCallback = () => logger.LogCritical("Console stopped."); - } + logger.LogWarning("Console started."); + }; - public async override Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) + events.OnApplicationStoppingCallback = () => { - var logger = serviceProvider.GetRequiredService>(); + logger.LogWarning("Stopping and cleaning .."); + Thread.Sleep(TimeSpan.FromSeconds(5)); // simulate graceful shutdown + logger.LogWarning(".. done!"); + }; + + events.OnApplicationStoppedCallback = () => logger.LogCritical("Console stopped."); + } - logger.LogInformation("Guid: {Guid}", serviceProvider.GetRequiredService()); + public async override Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) + { + var logger = serviceProvider.GetRequiredService>(); - for (int dots = 0; dots <= 5; ++dots) - { - if (cancellationToken.IsCancellationRequested) { return; } - System.Console.Write($"\rFire and forget {Generate.FixedString('.', dots)}"); - await Task.Delay(500, cancellationToken).ConfigureAwait(false); - } + logger.LogInformation("Guid: {Guid}", serviceProvider.GetRequiredService()); - System.Console.WriteLine("\nDone and done!"); + for (int dots = 0; dots <= 5; ++dots) + { + if (cancellationToken.IsCancellationRequested) { return; } + System.Console.Write($"\rFire and forget {Generate.FixedString('.', dots)}"); + await Task.Delay(500, cancellationToken).ConfigureAwait(false); } + + System.Console.WriteLine("\nDone and done!"); } } diff --git a/app/Codebelt.Bootstrapper.MinimalConsole.App/Program.cs b/app/Codebelt.Bootstrapper.MinimalConsole.App/Program.cs index b37566a..4cf4679 100644 --- a/app/Codebelt.Bootstrapper.MinimalConsole.App/Program.cs +++ b/app/Codebelt.Bootstrapper.MinimalConsole.App/Program.cs @@ -1,51 +1,50 @@ -using Codebelt.Bootstrapper.Console; +using Codebelt.Bootstrapper.Console; using Cuemon.Messaging; using Cuemon; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -namespace Codebelt.Bootstrapper.MinimalConsole.App +namespace Codebelt.Bootstrapper.MinimalConsole.App; + +internal class Program : MinimalConsoleProgram { - internal class Program : MinimalConsoleProgram + static Task Main(string[] args) { - static Task Main(string[] args) - { - var builder = CreateHostBuilder(args); - - builder.Services.AddSingleton(new CorrelationToken()); + var builder = CreateHostBuilder(args); - var host = builder.Build(); + builder.Services.AddSingleton(new CorrelationToken()); - var logger = host.Services.GetRequiredService>(); - var events = host.Services.GetRequiredService(); + var host = builder.Build(); - events.OnApplicationStartedCallback = () => logger.LogWarning("Console started."); - events.OnApplicationStoppingCallback = () => - { - logger.LogWarning("Stopping and cleaning .."); - Thread.Sleep(TimeSpan.FromSeconds(5)); // simulate graceful shutdown - logger.LogWarning(".. done!"); - }; - events.OnApplicationStoppedCallback = () => logger.LogCritical("Console stopped."); - - return host.RunAsync(); - } + var logger = host.Services.GetRequiredService>(); + var events = host.Services.GetRequiredService(); - public async override Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) + events.OnApplicationStartedCallback = () => logger.LogWarning("Console started."); + events.OnApplicationStoppingCallback = () => { - var logger = serviceProvider.GetRequiredService>(); + logger.LogWarning("Stopping and cleaning .."); + Thread.Sleep(TimeSpan.FromSeconds(5)); // simulate graceful shutdown + logger.LogWarning(".. done!"); + }; + events.OnApplicationStoppedCallback = () => logger.LogCritical("Console stopped."); - logger.LogInformation("Guid: {Guid}", serviceProvider.GetRequiredService()); + return host.RunAsync(); + } + + public async override Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) + { + var logger = serviceProvider.GetRequiredService>(); - for (int dots = 0; dots <= 5; ++dots) - { - if (cancellationToken.IsCancellationRequested) { return; } - System.Console.Write($"\rFire and forget {Generate.FixedString('.', dots)}"); - await Task.Delay(500, cancellationToken).ConfigureAwait(false); - } + logger.LogInformation("Guid: {Guid}", serviceProvider.GetRequiredService()); - System.Console.WriteLine("\nDone and done!"); + for (int dots = 0; dots <= 5; ++dots) + { + if (cancellationToken.IsCancellationRequested) { return; } + System.Console.Write($"\rFire and forget {Generate.FixedString('.', dots)}"); + await Task.Delay(500, cancellationToken).ConfigureAwait(false); } + + System.Console.WriteLine("\nDone and done!"); } } diff --git a/app/Codebelt.Bootstrapper.MinimalWeb.App/Program.cs b/app/Codebelt.Bootstrapper.MinimalWeb.App/Program.cs index fd60d78..166013f 100644 --- a/app/Codebelt.Bootstrapper.MinimalWeb.App/Program.cs +++ b/app/Codebelt.Bootstrapper.MinimalWeb.App/Program.cs @@ -1,32 +1,31 @@ using Codebelt.Bootstrapper.Web; using Cuemon.Extensions.Hosting; -namespace Codebelt.Bootstrapper.MinimalWeb.App +namespace Codebelt.Bootstrapper.MinimalWeb.App; + +public class Program : MinimalWebProgram { - public class Program : MinimalWebProgram + static Task Main(string[] args) { - static Task Main(string[] args) - { - var builder = CreateHostBuilder(args); + var builder = CreateHostBuilder(args); - var app = builder.Build(); + var app = builder.Build(); - if (app.Environment.IsLocalDevelopment()) - { - app.UseDeveloperExceptionPage(); - } + if (app.Environment.IsLocalDevelopment()) + { + app.UseDeveloperExceptionPage(); + } - app.UseRouting(); + app.UseRouting(); - app.UseEndpoints(endpoints => + app.UseEndpoints(endpoints => + { + endpoints.MapGet("/", async context => { - endpoints.MapGet("/", async context => - { - await context.Response.WriteAsync("Hello World!"); - }); + await context.Response.WriteAsync("Hello World!"); }); + }); - return app.RunAsync(); - } + return app.RunAsync(); } } diff --git a/app/Codebelt.Bootstrapper.MinimalWeb.App/Properties/launchSettings.json b/app/Codebelt.Bootstrapper.MinimalWeb.App/Properties/launchSettings.json index 565ac8e..4cf4be5 100644 --- a/app/Codebelt.Bootstrapper.MinimalWeb.App/Properties/launchSettings.json +++ b/app/Codebelt.Bootstrapper.MinimalWeb.App/Properties/launchSettings.json @@ -1,4 +1,4 @@ -{ +{ "$schema": "http://json.schemastore.org/launchsettings.json", "iisSettings": { "windowsAuthentication": false, diff --git a/app/Codebelt.Bootstrapper.MinimalWebApi.App/Program.cs b/app/Codebelt.Bootstrapper.MinimalWebApi.App/Program.cs index d6a06cc..83502c6 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebApi.App/Program.cs +++ b/app/Codebelt.Bootstrapper.MinimalWebApi.App/Program.cs @@ -2,58 +2,57 @@ using Codebelt.Bootstrapper.Web; using Microsoft.OpenApi; -namespace Codebelt.Bootstrapper.MinimalWebApi.App +namespace Codebelt.Bootstrapper.MinimalWebApi.App; + +public class Program : MinimalWebProgram { - public class Program : MinimalWebProgram + static Task Main(string[] args) { - static Task Main(string[] args) + var builder = CreateHostBuilder(args); + + // Add services to the container. + builder.Services.AddAuthorization(); + + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + builder.Services.AddEndpointsApiExplorer(); + builder.Services.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new OpenApiInfo { Title = "Codebelt.Bootstrapper.MinimalWebApi.App", Version = "v1" }); + }); + + var app = builder.Build(); + + // Configure the HTTP request pipeline. + if (app.Environment.IsDevelopment()) { - var builder = CreateHostBuilder(args); - - // Add services to the container. - builder.Services.AddAuthorization(); - - // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle - builder.Services.AddEndpointsApiExplorer(); - builder.Services.AddSwaggerGen(c => - { - c.SwaggerDoc("v1", new OpenApiInfo { Title = "Codebelt.Bootstrapper.MinimalWebApi.App", Version = "v1" }); - }); - - var app = builder.Build(); - - // Configure the HTTP request pipeline. - if (app.Environment.IsDevelopment()) - { - app.UseSwagger(); - app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Codebelt.Bootstrapper.MinimalWebApi.App v1")); - } - - app.UseHttpsRedirection(); - - app.UseAuthorization(); - - var summaries = new[] - { - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" - }; - - app.MapGet("/weatherforecast", (HttpContext _) => - { - var forecast = Enumerable.Range(1, 5).Select(index => - new WeatherForecast - { - Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - TemperatureC = Random.Shared.Next(-20, 55), - Summary = summaries[Random.Shared.Next(summaries.Length)] - }) - .ToArray(); - return forecast; - }) - .WithName("GetWeatherForecast") - .WithOpenApi(); - - return app.RunAsync(); + app.UseSwagger(); + app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Codebelt.Bootstrapper.MinimalWebApi.App v1")); } + + app.UseHttpsRedirection(); + + app.UseAuthorization(); + + var summaries = new[] + { + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + }; + + app.MapGet("/weatherforecast", (HttpContext _) => + { + var forecast = Enumerable.Range(1, 5).Select(index => + new WeatherForecast + { + Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = summaries[Random.Shared.Next(summaries.Length)] + }) + .ToArray(); + return forecast; + }) + .WithName("GetWeatherForecast") + .WithOpenApi(); + + return app.RunAsync(); } } diff --git a/app/Codebelt.Bootstrapper.MinimalWebApi.App/Properties/launchSettings.json b/app/Codebelt.Bootstrapper.MinimalWebApi.App/Properties/launchSettings.json index b610958..32be5f4 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebApi.App/Properties/launchSettings.json +++ b/app/Codebelt.Bootstrapper.MinimalWebApi.App/Properties/launchSettings.json @@ -1,4 +1,4 @@ -{ +{ "$schema": "http://json.schemastore.org/launchsettings.json", "iisSettings": { "windowsAuthentication": false, diff --git a/app/Codebelt.Bootstrapper.MinimalWebApi.App/WeatherForecast.cs b/app/Codebelt.Bootstrapper.MinimalWebApi.App/WeatherForecast.cs index a859e9c..cc16022 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebApi.App/WeatherForecast.cs +++ b/app/Codebelt.Bootstrapper.MinimalWebApi.App/WeatherForecast.cs @@ -1,13 +1,12 @@ -namespace Codebelt.Bootstrapper.MinimalWebApi.App +namespace Codebelt.Bootstrapper.MinimalWebApi.App; + +public class WeatherForecast { - public class WeatherForecast - { - public DateOnly Date { get; set; } + public DateOnly Date { get; set; } - public int TemperatureC { get; set; } + public int TemperatureC { get; set; } - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); - public string? Summary { get; set; } - } + public string? Summary { get; set; } } diff --git a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Error.cshtml b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Error.cshtml index 6f92b95..3961204 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Error.cshtml +++ b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Error.cshtml @@ -1,4 +1,4 @@ -@page +@page @model ErrorModel @{ ViewData["Title"] = "Error"; diff --git a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Error.cshtml.cs b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Error.cshtml.cs index f74c66a..af3d451 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Error.cshtml.cs +++ b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Error.cshtml.cs @@ -2,27 +2,25 @@ using Microsoft.AspNetCore.Mvc.RazorPages; using System.Diagnostics; -namespace Codebelt.Bootstrapper.MinimalWebApp.App.Pages -{ - [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] - [IgnoreAntiforgeryToken] - public class ErrorModel : PageModel - { - public string? RequestId { get; set; } +namespace Codebelt.Bootstrapper.MinimalWebApp.App.Pages; - public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); +[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] +[IgnoreAntiforgeryToken] +public class ErrorModel : PageModel +{ + public string? RequestId { get; set; } - private readonly ILogger _logger; + public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); - public ErrorModel(ILogger logger) - { - _logger = logger; - } + private readonly ILogger _logger; - public void OnGet() - { - RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; - } + public ErrorModel(ILogger logger) + { + _logger = logger; } + public void OnGet() + { + RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; + } } diff --git a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Index.cshtml b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Index.cshtml index f9ff8d4..f761314 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Index.cshtml +++ b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Index.cshtml @@ -1,4 +1,4 @@ -@page +@page @model IndexModel @{ ViewData["Title"] = "Home page"; diff --git a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Index.cshtml.cs b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Index.cshtml.cs index e62f040..a81cef9 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Index.cshtml.cs +++ b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Index.cshtml.cs @@ -1,20 +1,19 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; -namespace Codebelt.Bootstrapper.MinimalWebApp.App.Pages +namespace Codebelt.Bootstrapper.MinimalWebApp.App.Pages; + +public class IndexModel : PageModel { - public class IndexModel : PageModel - { - private readonly ILogger _logger; + private readonly ILogger _logger; - public IndexModel(ILogger logger) - { - _logger = logger; - } + public IndexModel(ILogger logger) + { + _logger = logger; + } - public void OnGet() - { + public void OnGet() + { - } } } diff --git a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Privacy.cshtml b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Privacy.cshtml index 46ba966..8c3afc0 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Privacy.cshtml +++ b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Privacy.cshtml @@ -1,4 +1,4 @@ -@page +@page @model PrivacyModel @{ ViewData["Title"] = "Privacy Policy"; diff --git a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Privacy.cshtml.cs b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Privacy.cshtml.cs index 189a733..bbed87b 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Privacy.cshtml.cs +++ b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Privacy.cshtml.cs @@ -1,20 +1,18 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; -namespace Codebelt.Bootstrapper.MinimalWebApp.App.Pages -{ - public class PrivacyModel : PageModel - { - private readonly ILogger _logger; +namespace Codebelt.Bootstrapper.MinimalWebApp.App.Pages; - public PrivacyModel(ILogger logger) - { - _logger = logger; - } +public class PrivacyModel : PageModel +{ + private readonly ILogger _logger; - public void OnGet() - { - } + public PrivacyModel(ILogger logger) + { + _logger = logger; } + public void OnGet() + { + } } diff --git a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Shared/_Layout.cshtml.css b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Shared/_Layout.cshtml.css index c187c02..104c44c 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Shared/_Layout.cshtml.css +++ b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Shared/_Layout.cshtml.css @@ -1,4 +1,4 @@ -/* Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification +/* Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification for details on configuring this project to bundle and minify static web assets. */ a.navbar-brand { diff --git a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Shared/_ValidationScriptsPartial.cshtml b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Shared/_ValidationScriptsPartial.cshtml index 5a16d80..7d8dd3e 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Shared/_ValidationScriptsPartial.cshtml +++ b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/Shared/_ValidationScriptsPartial.cshtml @@ -1,2 +1,2 @@ - + diff --git a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/_ViewImports.cshtml b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/_ViewImports.cshtml index 0eb6384..a3c768d 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/_ViewImports.cshtml +++ b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/_ViewImports.cshtml @@ -1,3 +1,3 @@ -@using Codebelt.Bootstrapper.MinimalWebApp.App +@using Codebelt.Bootstrapper.MinimalWebApp.App @namespace Codebelt.Bootstrapper.MinimalWebApp.App.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/_ViewStart.cshtml b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/_ViewStart.cshtml index a5f1004..820a2f6 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/_ViewStart.cshtml +++ b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Pages/_ViewStart.cshtml @@ -1,3 +1,3 @@ -@{ +@{ Layout = "_Layout"; } diff --git a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Program.cs b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Program.cs index c7758ff..ca99b98 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebApp.App/Program.cs +++ b/app/Codebelt.Bootstrapper.MinimalWebApp.App/Program.cs @@ -1,40 +1,39 @@ using Codebelt.Bootstrapper.Web; using Cuemon.Extensions.Hosting; -namespace Codebelt.Bootstrapper.MinimalWebApp.App +namespace Codebelt.Bootstrapper.MinimalWebApp.App; + +public class Program : MinimalWebProgram { - public class Program : MinimalWebProgram + static Task Main(string[] args) { - static Task Main(string[] args) - { - var builder = CreateHostBuilder(args); + var builder = CreateHostBuilder(args); - // Add services to the container. - builder.Services.AddRazorPages(); + // Add services to the container. + builder.Services.AddRazorPages(); - var app = builder.Build(); + var app = builder.Build(); - if (app.Environment.IsLocalDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseExceptionHandler("/Error"); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); - } + if (app.Environment.IsLocalDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + app.UseExceptionHandler("/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } - app.UseHttpsRedirection(); - app.UseStaticFiles(); + app.UseHttpsRedirection(); + app.UseStaticFiles(); - app.UseRouting(); + app.UseRouting(); - app.UseAuthorization(); + app.UseAuthorization(); - app.MapRazorPages(); + app.MapRazorPages(); - return app.RunAsync(); - } + return app.RunAsync(); } } diff --git a/app/Codebelt.Bootstrapper.MinimalWebApp.App/wwwroot/js/site.js b/app/Codebelt.Bootstrapper.MinimalWebApp.App/wwwroot/js/site.js index 0937657..3b7cc5f 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebApp.App/wwwroot/js/site.js +++ b/app/Codebelt.Bootstrapper.MinimalWebApp.App/wwwroot/js/site.js @@ -1,4 +1,4 @@ -// Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification +// Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification // for details on configuring this project to bundle and minify static web assets. // Write your JavaScript code. diff --git a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Controllers/HomeController.cs b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Controllers/HomeController.cs index 6540461..780b256 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Controllers/HomeController.cs +++ b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Controllers/HomeController.cs @@ -2,31 +2,30 @@ using Microsoft.AspNetCore.Mvc; using System.Diagnostics; -namespace Codebelt.Bootstrapper.MinimalWebMvc.App.Controllers +namespace Codebelt.Bootstrapper.MinimalWebMvc.App.Controllers; + +public class HomeController : Controller { - public class HomeController : Controller - { - private readonly ILogger _logger; + private readonly ILogger _logger; - public HomeController(ILogger logger) - { - _logger = logger; - } + public HomeController(ILogger logger) + { + _logger = logger; + } - public IActionResult Index() - { - return View(); - } + public IActionResult Index() + { + return View(); + } - public IActionResult Privacy() - { - return View(); - } + public IActionResult Privacy() + { + return View(); + } - [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] - public IActionResult Error() - { - return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); - } + [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] + public IActionResult Error() + { + return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } } diff --git a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Models/ErrorViewModel.cs b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Models/ErrorViewModel.cs index 2905bbc..9ac02e4 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Models/ErrorViewModel.cs +++ b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Models/ErrorViewModel.cs @@ -1,9 +1,8 @@ -namespace Codebelt.Bootstrapper.MinimalWebMvc.App.Models +namespace Codebelt.Bootstrapper.MinimalWebMvc.App.Models; + +public class ErrorViewModel { - public class ErrorViewModel - { - public string? RequestId { get; set; } + public string? RequestId { get; set; } - public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); - } + public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); } diff --git a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Program.cs b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Program.cs index 167bf56..cdeaae0 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Program.cs +++ b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Program.cs @@ -1,43 +1,42 @@ using Codebelt.Bootstrapper.Web; using Cuemon.Extensions.Hosting; -namespace Codebelt.Bootstrapper.MinimalWebMvc.App +namespace Codebelt.Bootstrapper.MinimalWebMvc.App; + +public class Program : MinimalWebProgram { - public class Program : MinimalWebProgram + static Task Main(string[] args) { - static Task Main(string[] args) - { - var builder = CreateHostBuilder(args); + var builder = CreateHostBuilder(args); - // Add services to the container. - builder.Services.AddControllersWithViews(); + // Add services to the container. + builder.Services.AddControllersWithViews(); - var app = builder.Build(); + var app = builder.Build(); - // Configure the HTTP request pipeline. - if (app.Environment.IsLocalDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseExceptionHandler("/Home/Error"); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); - } + // Configure the HTTP request pipeline. + if (app.Environment.IsLocalDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + app.UseExceptionHandler("/Home/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } - app.UseHttpsRedirection(); - app.UseStaticFiles(); + app.UseHttpsRedirection(); + app.UseStaticFiles(); - app.UseRouting(); + app.UseRouting(); - app.UseAuthorization(); + app.UseAuthorization(); - app.MapControllerRoute( - name: "default", - pattern: "{controller=Home}/{action=Index}/{id?}"); + app.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); - return app.RunAsync(); - } + return app.RunAsync(); } } diff --git a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Properties/launchSettings.json b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Properties/launchSettings.json index 68e67b0..2645ffa 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Properties/launchSettings.json +++ b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Properties/launchSettings.json @@ -1,4 +1,4 @@ -{ +{ "$schema": "http://json.schemastore.org/launchsettings.json", "iisSettings": { "windowsAuthentication": false, diff --git a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Home/Index.cshtml b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Home/Index.cshtml index bcfd79a..19c8d3f 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Home/Index.cshtml +++ b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Home/Index.cshtml @@ -1,4 +1,4 @@ -@{ +@{ ViewData["Title"] = "Home Page"; } diff --git a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Home/Privacy.cshtml b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Home/Privacy.cshtml index af4fb19..d01477f 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Home/Privacy.cshtml +++ b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Home/Privacy.cshtml @@ -1,4 +1,4 @@ -@{ +@{ ViewData["Title"] = "Privacy Policy"; }

@ViewData["Title"]

diff --git a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Shared/Error.cshtml b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Shared/Error.cshtml index a1e0478..0c47bb0 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Shared/Error.cshtml +++ b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Shared/Error.cshtml @@ -1,4 +1,4 @@ -@model ErrorViewModel +@model ErrorViewModel @{ ViewData["Title"] = "Error"; } diff --git a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Shared/_Layout.cshtml b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Shared/_Layout.cshtml index dfc14f3..93f7670 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Shared/_Layout.cshtml +++ b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Shared/_Layout.cshtml @@ -1,4 +1,4 @@ - + diff --git a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Shared/_Layout.cshtml.css b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Shared/_Layout.cshtml.css index c187c02..104c44c 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Shared/_Layout.cshtml.css +++ b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Shared/_Layout.cshtml.css @@ -1,4 +1,4 @@ -/* Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification +/* Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification for details on configuring this project to bundle and minify static web assets. */ a.navbar-brand { diff --git a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Shared/_ValidationScriptsPartial.cshtml b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Shared/_ValidationScriptsPartial.cshtml index 5a16d80..7d8dd3e 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Shared/_ValidationScriptsPartial.cshtml +++ b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/Shared/_ValidationScriptsPartial.cshtml @@ -1,2 +1,2 @@ - + diff --git a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/_ViewImports.cshtml b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/_ViewImports.cshtml index 060f436..e353c12 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/_ViewImports.cshtml +++ b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/_ViewImports.cshtml @@ -1,3 +1,3 @@ -@using Codebelt.Bootstrapper.MinimalWebMvc.App +@using Codebelt.Bootstrapper.MinimalWebMvc.App @using Codebelt.Bootstrapper.MinimalWebMvc.App.Models @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/_ViewStart.cshtml b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/_ViewStart.cshtml index a5f1004..820a2f6 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/_ViewStart.cshtml +++ b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/Views/_ViewStart.cshtml @@ -1,3 +1,3 @@ -@{ +@{ Layout = "_Layout"; } diff --git a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/wwwroot/js/site.js b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/wwwroot/js/site.js index 0937657..3b7cc5f 100644 --- a/app/Codebelt.Bootstrapper.MinimalWebMvc.App/wwwroot/js/site.js +++ b/app/Codebelt.Bootstrapper.MinimalWebMvc.App/wwwroot/js/site.js @@ -1,4 +1,4 @@ -// Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification +// Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification // for details on configuring this project to bundle and minify static web assets. // Write your JavaScript code. diff --git a/app/Codebelt.Bootstrapper.MinimalWorker.App/FakeHostedService.cs b/app/Codebelt.Bootstrapper.MinimalWorker.App/FakeHostedService.cs index 9ff8335..1d03caa 100644 --- a/app/Codebelt.Bootstrapper.MinimalWorker.App/FakeHostedService.cs +++ b/app/Codebelt.Bootstrapper.MinimalWorker.App/FakeHostedService.cs @@ -1,34 +1,33 @@ -namespace Codebelt.Bootstrapper.MinimalWorker.App +namespace Codebelt.Bootstrapper.MinimalWorker.App; + +public class FakeHostedService : BackgroundService { - public class FakeHostedService : BackgroundService - { - private readonly ILogger _logger; - private bool _gracefulShutdown; + private readonly ILogger _logger; + private bool _gracefulShutdown; - public FakeHostedService(ILogger logger, IHostLifetimeEvents events) - { - _logger = logger; + public FakeHostedService(ILogger logger, IHostLifetimeEvents events) + { + _logger = logger; - events.OnApplicationStartedCallback = () => logger.LogInformation("Started"); - events.OnApplicationStoppingCallback = () => - { - _gracefulShutdown = true; - logger.LogWarning("Stopping and cleaning .."); - Thread.Sleep(TimeSpan.FromSeconds(5)); // simulate graceful shutdown - logger.LogWarning(".. done!"); - }; - events.OnApplicationStoppedCallback = () => logger.LogCritical("Stopped"); - } + events.OnApplicationStartedCallback = () => logger.LogInformation("Started"); + events.OnApplicationStoppingCallback = () => + { + _gracefulShutdown = true; + logger.LogWarning("Stopping and cleaning .."); + Thread.Sleep(TimeSpan.FromSeconds(5)); // simulate graceful shutdown + logger.LogWarning(".. done!"); + }; + events.OnApplicationStoppedCallback = () => logger.LogCritical("Stopped"); + } - protected override async Task ExecuteAsync(CancellationToken stoppingToken) + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) { - while (!stoppingToken.IsCancellationRequested) - { - if (_gracefulShutdown) { return; } - _logger.LogInformation("Worker running at: {time}", DateTimeOffset.UtcNow.ToString("O")); - await Task.Delay(TimeSpan.FromSeconds(2), stoppingToken); - } + if (_gracefulShutdown) { return; } + _logger.LogInformation("Worker running at: {time}", DateTimeOffset.UtcNow.ToString("O")); + await Task.Delay(TimeSpan.FromSeconds(2), stoppingToken); } } } diff --git a/app/Codebelt.Bootstrapper.MinimalWorker.App/Program.cs b/app/Codebelt.Bootstrapper.MinimalWorker.App/Program.cs index b2ef700..3eaa8fc 100644 --- a/app/Codebelt.Bootstrapper.MinimalWorker.App/Program.cs +++ b/app/Codebelt.Bootstrapper.MinimalWorker.App/Program.cs @@ -1,16 +1,15 @@ using Codebelt.Bootstrapper.Worker; -namespace Codebelt.Bootstrapper.MinimalWorker.App +namespace Codebelt.Bootstrapper.MinimalWorker.App; + +public class Program : MinimalWorkerProgram { - public class Program : MinimalWorkerProgram + static Task Main(string[] args) { - static Task Main(string[] args) - { - var builder = CreateHostBuilder(args); - builder.Services.AddHostedService(); + var builder = CreateHostBuilder(args); + builder.Services.AddHostedService(); - var host = builder.Build(); - return host.RunAsync(); - } + var host = builder.Build(); + return host.RunAsync(); } -} \ No newline at end of file +} diff --git a/app/Codebelt.Bootstrapper.MinimalWorker.App/Properties/launchSettings.json b/app/Codebelt.Bootstrapper.MinimalWorker.App/Properties/launchSettings.json index 18c72f8..0aa3908 100644 --- a/app/Codebelt.Bootstrapper.MinimalWorker.App/Properties/launchSettings.json +++ b/app/Codebelt.Bootstrapper.MinimalWorker.App/Properties/launchSettings.json @@ -1,4 +1,4 @@ -{ +{ "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "Codebelt.Bootstrapper.MinimalWorker.App": { diff --git a/app/Codebelt.Bootstrapper.Web.App/Program.cs b/app/Codebelt.Bootstrapper.Web.App/Program.cs index 025d391..3aec13f 100644 --- a/app/Codebelt.Bootstrapper.Web.App/Program.cs +++ b/app/Codebelt.Bootstrapper.Web.App/Program.cs @@ -1,14 +1,13 @@ using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Web.App +namespace Codebelt.Bootstrapper.Web.App; + +public class Program : WebProgram { - public class Program : WebProgram + static void Main(string[] args) { - static void Main(string[] args) - { - CreateHostBuilder(args) - .Build() - .Run(); - } + CreateHostBuilder(args) + .Build() + .Run(); } } diff --git a/app/Codebelt.Bootstrapper.Web.App/Properties/launchSettings.json b/app/Codebelt.Bootstrapper.Web.App/Properties/launchSettings.json index cbaae35..ed490ee 100644 --- a/app/Codebelt.Bootstrapper.Web.App/Properties/launchSettings.json +++ b/app/Codebelt.Bootstrapper.Web.App/Properties/launchSettings.json @@ -1,4 +1,4 @@ -{ +{ "profiles": { "Codebelt.Bootstrapper.Web.App": { "commandName": "Project", diff --git a/app/Codebelt.Bootstrapper.Web.App/Startup.cs b/app/Codebelt.Bootstrapper.Web.App/Startup.cs index ef8d627..34ae1b9 100644 --- a/app/Codebelt.Bootstrapper.Web.App/Startup.cs +++ b/app/Codebelt.Bootstrapper.Web.App/Startup.cs @@ -5,34 +5,33 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Configuration; -namespace Codebelt.Bootstrapper.Web.App +namespace Codebelt.Bootstrapper.Web.App; + +public class Startup : WebStartup { - public class Startup : WebStartup + public Startup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) { - public Startup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) - { - } + } - public override void ConfigureServices(IServiceCollection services) - { - } + public override void ConfigureServices(IServiceCollection services) + { + } - public override void ConfigurePipeline(IApplicationBuilder app) + public override void ConfigurePipeline(IApplicationBuilder app) + { + if (Environment.IsLocalDevelopment()) { - if (Environment.IsLocalDevelopment()) - { - app.UseDeveloperExceptionPage(); - } + app.UseDeveloperExceptionPage(); + } - app.UseRouting(); + app.UseRouting(); - app.UseEndpoints(endpoints => + app.UseEndpoints(endpoints => + { + endpoints.MapGet("/", async context => { - endpoints.MapGet("/", async context => - { - await context.Response.WriteAsync("Hello World!"); - }); + await context.Response.WriteAsync("Hello World!"); }); - } + }); } } diff --git a/app/Codebelt.Bootstrapper.WebApi.App/Controllers/WeatherForecastController.cs b/app/Codebelt.Bootstrapper.WebApi.App/Controllers/WeatherForecastController.cs index 1d89d73..275235b 100644 --- a/app/Codebelt.Bootstrapper.WebApi.App/Controllers/WeatherForecastController.cs +++ b/app/Codebelt.Bootstrapper.WebApi.App/Controllers/WeatherForecastController.cs @@ -1,38 +1,37 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; -namespace Codebelt.Bootstrapper.WebApi.App.Controllers +namespace Codebelt.Bootstrapper.WebApi.App.Controllers; + +[ApiController] +[Route("[controller]")] +public class WeatherForecastController : ControllerBase { - [ApiController] - [Route("[controller]")] - public class WeatherForecastController : ControllerBase + private static readonly string[] Summaries = new[] { - private static readonly string[] Summaries = new[] - { - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" - }; + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + }; - private readonly ILogger _logger; + private readonly ILogger _logger; - public WeatherForecastController(ILogger logger) - { - _logger = logger; - } + public WeatherForecastController(ILogger logger) + { + _logger = logger; + } - [HttpGet] - public IEnumerable Get() + [HttpGet] + public IEnumerable Get() + { + var rng = new Random(); + return Enumerable.Range(1, 5).Select(index => new WeatherForecast { - var rng = new Random(); - return Enumerable.Range(1, 5).Select(index => new WeatherForecast - { - Date = DateTime.Now.AddDays(index), - TemperatureC = rng.Next(-20, 55), - Summary = Summaries[rng.Next(Summaries.Length)] - }) - .ToArray(); - } + Date = DateTime.Now.AddDays(index), + TemperatureC = rng.Next(-20, 55), + Summary = Summaries[rng.Next(Summaries.Length)] + }) + .ToArray(); } } diff --git a/app/Codebelt.Bootstrapper.WebApi.App/Program.cs b/app/Codebelt.Bootstrapper.WebApi.App/Program.cs index 27d21bf..70e77d4 100644 --- a/app/Codebelt.Bootstrapper.WebApi.App/Program.cs +++ b/app/Codebelt.Bootstrapper.WebApi.App/Program.cs @@ -2,16 +2,15 @@ using Codebelt.Bootstrapper.Web; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.WebApi.App +namespace Codebelt.Bootstrapper.WebApi.App; + +public class Program : WebProgram { - public class Program : WebProgram + static async Task Main(string[] args) { - static async Task Main(string[] args) - { - await CreateHostBuilder(args) - .Build() - .RunAsync() - .ConfigureAwait(false); - } + await CreateHostBuilder(args) + .Build() + .RunAsync() + .ConfigureAwait(false); } } diff --git a/app/Codebelt.Bootstrapper.WebApi.App/Properties/launchSettings.json b/app/Codebelt.Bootstrapper.WebApi.App/Properties/launchSettings.json index 62969a3..2a3abb6 100644 --- a/app/Codebelt.Bootstrapper.WebApi.App/Properties/launchSettings.json +++ b/app/Codebelt.Bootstrapper.WebApi.App/Properties/launchSettings.json @@ -1,4 +1,4 @@ -{ +{ "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "Codebelt.Bootstrapper.WebApi.App": { diff --git a/app/Codebelt.Bootstrapper.WebApi.App/Startup.cs b/app/Codebelt.Bootstrapper.WebApi.App/Startup.cs index 03a605a..f844f3f 100644 --- a/app/Codebelt.Bootstrapper.WebApi.App/Startup.cs +++ b/app/Codebelt.Bootstrapper.WebApi.App/Startup.cs @@ -7,44 +7,43 @@ using Cuemon.Extensions.Hosting; using Microsoft.OpenApi; -namespace Codebelt.Bootstrapper.WebApi.App +namespace Codebelt.Bootstrapper.WebApi.App; + +public class Startup : WebStartup { - public class Startup : WebStartup + public Startup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) { - public Startup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) - { - } + } - public override void ConfigureServices(IServiceCollection services) + public override void ConfigureServices(IServiceCollection services) + { + services.AddControllers(); + services.AddSwaggerGen(c => { - services.AddControllers(); - services.AddSwaggerGen(c => - { - c.SwaggerDoc("v1", new OpenApiInfo { Title = "Codebelt.Bootstrapper.WebApi.App", Version = "v1" }); - }); - } + c.SwaggerDoc("v1", new OpenApiInfo { Title = "Codebelt.Bootstrapper.WebApi.App", Version = "v1" }); + }); + } - public override void ConfigurePipeline(IApplicationBuilder app) - { - var logger = app.ApplicationServices.GetRequiredService>(); + public override void ConfigurePipeline(IApplicationBuilder app) + { + var logger = app.ApplicationServices.GetRequiredService>(); - if (Environment.IsLocalDevelopment()) - { - app.UseDeveloperExceptionPage(); - app.UseSwagger(); - app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Codebelt.Bootstrapper.WebApi.App v1")); - } + if (Environment.IsLocalDevelopment()) + { + app.UseDeveloperExceptionPage(); + app.UseSwagger(); + app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Codebelt.Bootstrapper.WebApi.App v1")); + } - app.UseHttpsRedirection(); + app.UseHttpsRedirection(); - app.UseRouting(); + app.UseRouting(); - app.UseAuthorization(); + app.UseAuthorization(); - app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - }); - } + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); } } diff --git a/app/Codebelt.Bootstrapper.WebApi.App/WeatherForecast.cs b/app/Codebelt.Bootstrapper.WebApi.App/WeatherForecast.cs index e7aee76..4858f86 100644 --- a/app/Codebelt.Bootstrapper.WebApi.App/WeatherForecast.cs +++ b/app/Codebelt.Bootstrapper.WebApi.App/WeatherForecast.cs @@ -1,15 +1,14 @@ using System; -namespace Codebelt.Bootstrapper.WebApi.App +namespace Codebelt.Bootstrapper.WebApi.App; + +public class WeatherForecast { - public class WeatherForecast - { - public DateTime Date { get; set; } + public DateTime Date { get; set; } - public int TemperatureC { get; set; } + public int TemperatureC { get; set; } - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); - public string Summary { get; set; } - } + public string Summary { get; set; } } diff --git a/app/Codebelt.Bootstrapper.WebApp.App/Pages/Error.cshtml b/app/Codebelt.Bootstrapper.WebApp.App/Pages/Error.cshtml index 6f92b95..3961204 100644 --- a/app/Codebelt.Bootstrapper.WebApp.App/Pages/Error.cshtml +++ b/app/Codebelt.Bootstrapper.WebApp.App/Pages/Error.cshtml @@ -1,4 +1,4 @@ -@page +@page @model ErrorModel @{ ViewData["Title"] = "Error"; diff --git a/app/Codebelt.Bootstrapper.WebApp.App/Pages/Error.cshtml.cs b/app/Codebelt.Bootstrapper.WebApp.App/Pages/Error.cshtml.cs index 34a7307..ddc1e10 100644 --- a/app/Codebelt.Bootstrapper.WebApp.App/Pages/Error.cshtml.cs +++ b/app/Codebelt.Bootstrapper.WebApp.App/Pages/Error.cshtml.cs @@ -3,26 +3,25 @@ using Microsoft.Extensions.Logging; using System.Diagnostics; -namespace Codebelt.Bootstrapper.WebApp.App.Pages +namespace Codebelt.Bootstrapper.WebApp.App.Pages; + +[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] +[IgnoreAntiforgeryToken] +public class ErrorModel : PageModel { - [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] - [IgnoreAntiforgeryToken] - public class ErrorModel : PageModel - { - public string RequestId { get; set; } + public string RequestId { get; set; } - public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); - private readonly ILogger _logger; + private readonly ILogger _logger; - public ErrorModel(ILogger logger) - { - _logger = logger; - } + public ErrorModel(ILogger logger) + { + _logger = logger; + } - public void OnGet() - { - RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; - } + public void OnGet() + { + RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; } } diff --git a/app/Codebelt.Bootstrapper.WebApp.App/Pages/Index.cshtml b/app/Codebelt.Bootstrapper.WebApp.App/Pages/Index.cshtml index b5f0c15..6fb28a2 100644 --- a/app/Codebelt.Bootstrapper.WebApp.App/Pages/Index.cshtml +++ b/app/Codebelt.Bootstrapper.WebApp.App/Pages/Index.cshtml @@ -1,4 +1,4 @@ -@page +@page @model IndexModel @{ ViewData["Title"] = "Home page"; diff --git a/app/Codebelt.Bootstrapper.WebApp.App/Pages/Index.cshtml.cs b/app/Codebelt.Bootstrapper.WebApp.App/Pages/Index.cshtml.cs index af0410b..6b783a8 100644 --- a/app/Codebelt.Bootstrapper.WebApp.App/Pages/Index.cshtml.cs +++ b/app/Codebelt.Bootstrapper.WebApp.App/Pages/Index.cshtml.cs @@ -1,20 +1,19 @@ -using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.Logging; -namespace Codebelt.Bootstrapper.WebApp.App.Pages +namespace Codebelt.Bootstrapper.WebApp.App.Pages; + +public class IndexModel : PageModel { - public class IndexModel : PageModel - { - private readonly ILogger _logger; + private readonly ILogger _logger; - public IndexModel(ILogger logger) - { - _logger = logger; - } + public IndexModel(ILogger logger) + { + _logger = logger; + } - public void OnGet() - { + public void OnGet() + { - } } } diff --git a/app/Codebelt.Bootstrapper.WebApp.App/Pages/Privacy.cshtml b/app/Codebelt.Bootstrapper.WebApp.App/Pages/Privacy.cshtml index 46ba966..8c3afc0 100644 --- a/app/Codebelt.Bootstrapper.WebApp.App/Pages/Privacy.cshtml +++ b/app/Codebelt.Bootstrapper.WebApp.App/Pages/Privacy.cshtml @@ -1,4 +1,4 @@ -@page +@page @model PrivacyModel @{ ViewData["Title"] = "Privacy Policy"; diff --git a/app/Codebelt.Bootstrapper.WebApp.App/Pages/Privacy.cshtml.cs b/app/Codebelt.Bootstrapper.WebApp.App/Pages/Privacy.cshtml.cs index 2e3c8bd..2c7ca5e 100644 --- a/app/Codebelt.Bootstrapper.WebApp.App/Pages/Privacy.cshtml.cs +++ b/app/Codebelt.Bootstrapper.WebApp.App/Pages/Privacy.cshtml.cs @@ -1,19 +1,18 @@ -using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.Logging; -namespace Codebelt.Bootstrapper.WebApp.App.Pages +namespace Codebelt.Bootstrapper.WebApp.App.Pages; + +public class PrivacyModel : PageModel { - public class PrivacyModel : PageModel - { - private readonly ILogger _logger; + private readonly ILogger _logger; - public PrivacyModel(ILogger logger) - { - _logger = logger; - } + public PrivacyModel(ILogger logger) + { + _logger = logger; + } - public void OnGet() - { - } + public void OnGet() + { } } diff --git a/app/Codebelt.Bootstrapper.WebApp.App/Pages/Shared/_Layout.cshtml b/app/Codebelt.Bootstrapper.WebApp.App/Pages/Shared/_Layout.cshtml index a8dcbcc..9828b6f 100644 --- a/app/Codebelt.Bootstrapper.WebApp.App/Pages/Shared/_Layout.cshtml +++ b/app/Codebelt.Bootstrapper.WebApp.App/Pages/Shared/_Layout.cshtml @@ -1,4 +1,4 @@ - + diff --git a/app/Codebelt.Bootstrapper.WebApp.App/Pages/Shared/_ValidationScriptsPartial.cshtml b/app/Codebelt.Bootstrapper.WebApp.App/Pages/Shared/_ValidationScriptsPartial.cshtml index 5a16d80..7d8dd3e 100644 --- a/app/Codebelt.Bootstrapper.WebApp.App/Pages/Shared/_ValidationScriptsPartial.cshtml +++ b/app/Codebelt.Bootstrapper.WebApp.App/Pages/Shared/_ValidationScriptsPartial.cshtml @@ -1,2 +1,2 @@ - + diff --git a/app/Codebelt.Bootstrapper.WebApp.App/Pages/_ViewStart.cshtml b/app/Codebelt.Bootstrapper.WebApp.App/Pages/_ViewStart.cshtml index a5f1004..820a2f6 100644 --- a/app/Codebelt.Bootstrapper.WebApp.App/Pages/_ViewStart.cshtml +++ b/app/Codebelt.Bootstrapper.WebApp.App/Pages/_ViewStart.cshtml @@ -1,3 +1,3 @@ -@{ +@{ Layout = "_Layout"; } diff --git a/app/Codebelt.Bootstrapper.WebApp.App/Program.cs b/app/Codebelt.Bootstrapper.WebApp.App/Program.cs index 83ac30f..4e7ae74 100644 --- a/app/Codebelt.Bootstrapper.WebApp.App/Program.cs +++ b/app/Codebelt.Bootstrapper.WebApp.App/Program.cs @@ -1,13 +1,12 @@ using Codebelt.Bootstrapper.Web; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.WebApp.App +namespace Codebelt.Bootstrapper.WebApp.App; + +public class Program : WebProgram { - public class Program : WebProgram + public static void Main(string[] args) { - public static void Main(string[] args) - { - CreateHostBuilder(args).Build().Run(); - } + CreateHostBuilder(args).Build().Run(); } } diff --git a/app/Codebelt.Bootstrapper.WebApp.App/Properties/launchSettings.json b/app/Codebelt.Bootstrapper.WebApp.App/Properties/launchSettings.json index f8cb865..a96d2ac 100644 --- a/app/Codebelt.Bootstrapper.WebApp.App/Properties/launchSettings.json +++ b/app/Codebelt.Bootstrapper.WebApp.App/Properties/launchSettings.json @@ -1,4 +1,4 @@ -{ +{ "profiles": { "Codebelt.Bootstrapper.WebApp.App": { "commandName": "Project", diff --git a/app/Codebelt.Bootstrapper.WebApp.App/Startup.cs b/app/Codebelt.Bootstrapper.WebApp.App/Startup.cs index f182645..0da88ee 100644 --- a/app/Codebelt.Bootstrapper.WebApp.App/Startup.cs +++ b/app/Codebelt.Bootstrapper.WebApp.App/Startup.cs @@ -6,45 +6,44 @@ using Cuemon.Extensions.Hosting; using Microsoft.Extensions.Logging; -namespace Codebelt.Bootstrapper.WebApp.App +namespace Codebelt.Bootstrapper.WebApp.App; + +public class Startup : WebStartup { - public class Startup : WebStartup + public Startup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) + { + } + + public override void ConfigureServices(IServiceCollection services) + { + services.AddRazorPages(); + } + + public override void ConfigurePipeline(IApplicationBuilder app) { - public Startup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) + var logger = app.ApplicationServices.GetRequiredService>(); + + if (Environment.IsLocalDevelopment()) { + app.UseDeveloperExceptionPage(); } - - public override void ConfigureServices(IServiceCollection services) + else { - services.AddRazorPages(); + app.UseExceptionHandler("/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); } - public override void ConfigurePipeline(IApplicationBuilder app) + app.UseHttpsRedirection(); + app.UseStaticFiles(); + + app.UseRouting(); + + app.UseAuthorization(); + + app.UseEndpoints(endpoints => { - var logger = app.ApplicationServices.GetRequiredService>(); - - if (Environment.IsLocalDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseExceptionHandler("/Error"); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); - } - - app.UseHttpsRedirection(); - app.UseStaticFiles(); - - app.UseRouting(); - - app.UseAuthorization(); - - app.UseEndpoints(endpoints => - { - endpoints.MapRazorPages(); - }); - } + endpoints.MapRazorPages(); + }); } } diff --git a/app/Codebelt.Bootstrapper.WebApp.App/wwwroot/css/site.css b/app/Codebelt.Bootstrapper.WebApp.App/wwwroot/css/site.css index e679a8e..f541d8f 100644 --- a/app/Codebelt.Bootstrapper.WebApp.App/wwwroot/css/site.css +++ b/app/Codebelt.Bootstrapper.WebApp.App/wwwroot/css/site.css @@ -1,4 +1,4 @@ -/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification +/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification for details on configuring this project to bundle and minify static web assets. */ a.navbar-brand { diff --git a/app/Codebelt.Bootstrapper.WebApp.App/wwwroot/js/site.js b/app/Codebelt.Bootstrapper.WebApp.App/wwwroot/js/site.js index ac49c18..f5d74f4 100644 --- a/app/Codebelt.Bootstrapper.WebApp.App/wwwroot/js/site.js +++ b/app/Codebelt.Bootstrapper.WebApp.App/wwwroot/js/site.js @@ -1,4 +1,4 @@ -// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification +// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification // for details on configuring this project to bundle and minify static web assets. // Write your JavaScript code. diff --git a/app/Codebelt.Bootstrapper.WebMvc.App/Controllers/HomeController.cs b/app/Codebelt.Bootstrapper.WebMvc.App/Controllers/HomeController.cs index 2e4d13e..57009ef 100644 --- a/app/Codebelt.Bootstrapper.WebMvc.App/Controllers/HomeController.cs +++ b/app/Codebelt.Bootstrapper.WebMvc.App/Controllers/HomeController.cs @@ -1,33 +1,32 @@ -using Codebelt.Bootstrapper.WebMvc.App.Models; +using Codebelt.Bootstrapper.WebMvc.App.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using System.Diagnostics; -namespace Codebelt.Bootstrapper.WebMvc.App.Controllers +namespace Codebelt.Bootstrapper.WebMvc.App.Controllers; + +public class HomeController : Controller { - public class HomeController : Controller - { - private readonly ILogger _logger; + private readonly ILogger _logger; - public HomeController(ILogger logger) - { - _logger = logger; - } + public HomeController(ILogger logger) + { + _logger = logger; + } - public IActionResult Index() - { - return View(); - } + public IActionResult Index() + { + return View(); + } - public IActionResult Privacy() - { - return View(); - } + public IActionResult Privacy() + { + return View(); + } - [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] - public IActionResult Error() - { - return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); - } + [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] + public IActionResult Error() + { + return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } } diff --git a/app/Codebelt.Bootstrapper.WebMvc.App/Models/ErrorViewModel.cs b/app/Codebelt.Bootstrapper.WebMvc.App/Models/ErrorViewModel.cs index a0fac3a..ab33b4c 100644 --- a/app/Codebelt.Bootstrapper.WebMvc.App/Models/ErrorViewModel.cs +++ b/app/Codebelt.Bootstrapper.WebMvc.App/Models/ErrorViewModel.cs @@ -1,9 +1,8 @@ -namespace Codebelt.Bootstrapper.WebMvc.App.Models +namespace Codebelt.Bootstrapper.WebMvc.App.Models; + +public class ErrorViewModel { - public class ErrorViewModel - { - public string RequestId { get; set; } + public string RequestId { get; set; } - public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); - } + public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); } diff --git a/app/Codebelt.Bootstrapper.WebMvc.App/Program.cs b/app/Codebelt.Bootstrapper.WebMvc.App/Program.cs index 13acfbf..becfa23 100644 --- a/app/Codebelt.Bootstrapper.WebMvc.App/Program.cs +++ b/app/Codebelt.Bootstrapper.WebMvc.App/Program.cs @@ -1,13 +1,12 @@ using Codebelt.Bootstrapper.Web; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.WebMvc.App +namespace Codebelt.Bootstrapper.WebMvc.App; + +public class Program : WebProgram { - public class Program : WebProgram + public static void Main(string[] args) { - public static void Main(string[] args) - { - CreateHostBuilder(args).Build().Run(); - } + CreateHostBuilder(args).Build().Run(); } } diff --git a/app/Codebelt.Bootstrapper.WebMvc.App/Properties/launchSettings.json b/app/Codebelt.Bootstrapper.WebMvc.App/Properties/launchSettings.json index fa94b70..2b6c9a7 100644 --- a/app/Codebelt.Bootstrapper.WebMvc.App/Properties/launchSettings.json +++ b/app/Codebelt.Bootstrapper.WebMvc.App/Properties/launchSettings.json @@ -1,4 +1,4 @@ -{ +{ "profiles": { "Codebelt.Bootstrapper.WebMvc.App": { "commandName": "Project", diff --git a/app/Codebelt.Bootstrapper.WebMvc.App/Startup.cs b/app/Codebelt.Bootstrapper.WebMvc.App/Startup.cs index f74d2a5..e9c6410 100644 --- a/app/Codebelt.Bootstrapper.WebMvc.App/Startup.cs +++ b/app/Codebelt.Bootstrapper.WebMvc.App/Startup.cs @@ -6,46 +6,45 @@ using Cuemon.Extensions.Hosting; using Microsoft.Extensions.Logging; -namespace Codebelt.Bootstrapper.WebMvc.App +namespace Codebelt.Bootstrapper.WebMvc.App; + +public class Startup : WebStartup { - public class Startup : WebStartup + public Startup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) + { + } + + public override void ConfigureServices(IServiceCollection services) + { + services.AddControllersWithViews(); + } + + public override void ConfigurePipeline(IApplicationBuilder app) { - public Startup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) + var logger = app.ApplicationServices.GetRequiredService>(); + + if (Environment.IsLocalDevelopment()) { + app.UseDeveloperExceptionPage(); } - - public override void ConfigureServices(IServiceCollection services) + else { - services.AddControllersWithViews(); + app.UseExceptionHandler("/Home/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); } + app.UseHttpsRedirection(); + app.UseStaticFiles(); - public override void ConfigurePipeline(IApplicationBuilder app) + app.UseRouting(); + + app.UseAuthorization(); + + app.UseEndpoints(endpoints => { - var logger = app.ApplicationServices.GetRequiredService>(); - - if (Environment.IsLocalDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseExceptionHandler("/Home/Error"); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); - } - app.UseHttpsRedirection(); - app.UseStaticFiles(); - - app.UseRouting(); - - app.UseAuthorization(); - - app.UseEndpoints(endpoints => - { - endpoints.MapControllerRoute( - name: "default", - pattern: "{controller=Home}/{action=Index}/{id?}"); - }); - } + endpoints.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); + }); } } diff --git a/app/Codebelt.Bootstrapper.WebMvc.App/Views/Home/Index.cshtml b/app/Codebelt.Bootstrapper.WebMvc.App/Views/Home/Index.cshtml index d2d19bd..52ffe01 100644 --- a/app/Codebelt.Bootstrapper.WebMvc.App/Views/Home/Index.cshtml +++ b/app/Codebelt.Bootstrapper.WebMvc.App/Views/Home/Index.cshtml @@ -1,4 +1,4 @@ -@{ +@{ ViewData["Title"] = "Home Page"; } diff --git a/app/Codebelt.Bootstrapper.WebMvc.App/Views/Home/Privacy.cshtml b/app/Codebelt.Bootstrapper.WebMvc.App/Views/Home/Privacy.cshtml index af4fb19..d01477f 100644 --- a/app/Codebelt.Bootstrapper.WebMvc.App/Views/Home/Privacy.cshtml +++ b/app/Codebelt.Bootstrapper.WebMvc.App/Views/Home/Privacy.cshtml @@ -1,4 +1,4 @@ -@{ +@{ ViewData["Title"] = "Privacy Policy"; }

@ViewData["Title"]

diff --git a/app/Codebelt.Bootstrapper.WebMvc.App/Views/Shared/Error.cshtml b/app/Codebelt.Bootstrapper.WebMvc.App/Views/Shared/Error.cshtml index a1e0478..0c47bb0 100644 --- a/app/Codebelt.Bootstrapper.WebMvc.App/Views/Shared/Error.cshtml +++ b/app/Codebelt.Bootstrapper.WebMvc.App/Views/Shared/Error.cshtml @@ -1,4 +1,4 @@ -@model ErrorViewModel +@model ErrorViewModel @{ ViewData["Title"] = "Error"; } diff --git a/app/Codebelt.Bootstrapper.WebMvc.App/Views/Shared/_Layout.cshtml b/app/Codebelt.Bootstrapper.WebMvc.App/Views/Shared/_Layout.cshtml index 0ab7647..38e3437 100644 --- a/app/Codebelt.Bootstrapper.WebMvc.App/Views/Shared/_Layout.cshtml +++ b/app/Codebelt.Bootstrapper.WebMvc.App/Views/Shared/_Layout.cshtml @@ -1,4 +1,4 @@ - + diff --git a/app/Codebelt.Bootstrapper.WebMvc.App/Views/Shared/_ValidationScriptsPartial.cshtml b/app/Codebelt.Bootstrapper.WebMvc.App/Views/Shared/_ValidationScriptsPartial.cshtml index 5a16d80..7d8dd3e 100644 --- a/app/Codebelt.Bootstrapper.WebMvc.App/Views/Shared/_ValidationScriptsPartial.cshtml +++ b/app/Codebelt.Bootstrapper.WebMvc.App/Views/Shared/_ValidationScriptsPartial.cshtml @@ -1,2 +1,2 @@ - + diff --git a/app/Codebelt.Bootstrapper.WebMvc.App/Views/_ViewImports.cshtml b/app/Codebelt.Bootstrapper.WebMvc.App/Views/_ViewImports.cshtml index d9f25bd..75a833e 100644 --- a/app/Codebelt.Bootstrapper.WebMvc.App/Views/_ViewImports.cshtml +++ b/app/Codebelt.Bootstrapper.WebMvc.App/Views/_ViewImports.cshtml @@ -1,3 +1,3 @@ -@using Codebelt.Bootstrapper.WebMvc.App +@using Codebelt.Bootstrapper.WebMvc.App @using Codebelt.Bootstrapper.WebMvc.App.Models @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/app/Codebelt.Bootstrapper.WebMvc.App/Views/_ViewStart.cshtml b/app/Codebelt.Bootstrapper.WebMvc.App/Views/_ViewStart.cshtml index a5f1004..820a2f6 100644 --- a/app/Codebelt.Bootstrapper.WebMvc.App/Views/_ViewStart.cshtml +++ b/app/Codebelt.Bootstrapper.WebMvc.App/Views/_ViewStart.cshtml @@ -1,3 +1,3 @@ -@{ +@{ Layout = "_Layout"; } diff --git a/app/Codebelt.Bootstrapper.WebMvc.App/wwwroot/css/site.css b/app/Codebelt.Bootstrapper.WebMvc.App/wwwroot/css/site.css index e679a8e..f541d8f 100644 --- a/app/Codebelt.Bootstrapper.WebMvc.App/wwwroot/css/site.css +++ b/app/Codebelt.Bootstrapper.WebMvc.App/wwwroot/css/site.css @@ -1,4 +1,4 @@ -/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification +/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification for details on configuring this project to bundle and minify static web assets. */ a.navbar-brand { diff --git a/app/Codebelt.Bootstrapper.WebMvc.App/wwwroot/js/site.js b/app/Codebelt.Bootstrapper.WebMvc.App/wwwroot/js/site.js index ac49c18..f5d74f4 100644 --- a/app/Codebelt.Bootstrapper.WebMvc.App/wwwroot/js/site.js +++ b/app/Codebelt.Bootstrapper.WebMvc.App/wwwroot/js/site.js @@ -1,4 +1,4 @@ -// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification +// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification // for details on configuring this project to bundle and minify static web assets. // Write your JavaScript code. diff --git a/app/Codebelt.Bootstrapper.Worker.App/FakeHostedService.cs b/app/Codebelt.Bootstrapper.Worker.App/FakeHostedService.cs index 7dd9c9c..f5a9de4 100644 --- a/app/Codebelt.Bootstrapper.Worker.App/FakeHostedService.cs +++ b/app/Codebelt.Bootstrapper.Worker.App/FakeHostedService.cs @@ -1,39 +1,38 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -namespace Codebelt.Bootstrapper.Worker.App +namespace Codebelt.Bootstrapper.Worker.App; + +public class FakeHostedService : BackgroundService { - public class FakeHostedService : BackgroundService + private readonly ILogger _logger; + private bool _gracefulShutdown; + + public FakeHostedService(ILogger logger, IHostLifetimeEvents events) { - private readonly ILogger _logger; - private bool _gracefulShutdown; + _logger = logger; - public FakeHostedService(ILogger logger, IHostLifetimeEvents events) + events.OnApplicationStartedCallback = () => logger.LogInformation("Started"); + events.OnApplicationStoppingCallback = () => { - _logger = logger; - - events.OnApplicationStartedCallback = () => logger.LogInformation("Started"); - events.OnApplicationStoppingCallback = () => - { - _gracefulShutdown = true; - logger.LogWarning("Stopping and cleaning .."); - Thread.Sleep(TimeSpan.FromSeconds(5)); // simulate graceful shutdown - logger.LogWarning(".. done!"); - }; - events.OnApplicationStoppedCallback = () => logger.LogCritical("Stopped"); - } + _gracefulShutdown = true; + logger.LogWarning("Stopping and cleaning .."); + Thread.Sleep(TimeSpan.FromSeconds(5)); // simulate graceful shutdown + logger.LogWarning(".. done!"); + }; + events.OnApplicationStoppedCallback = () => logger.LogCritical("Stopped"); + } - protected override async Task ExecuteAsync(CancellationToken stoppingToken) + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) { - while (!stoppingToken.IsCancellationRequested) - { - if (_gracefulShutdown) { return; } - _logger.LogInformation("Worker running at: {time}", DateTimeOffset.UtcNow.ToString("O")); - await Task.Delay(TimeSpan.FromSeconds(2), stoppingToken); - } + if (_gracefulShutdown) { return; } + _logger.LogInformation("Worker running at: {time}", DateTimeOffset.UtcNow.ToString("O")); + await Task.Delay(TimeSpan.FromSeconds(2), stoppingToken); } } } diff --git a/app/Codebelt.Bootstrapper.Worker.App/Program.cs b/app/Codebelt.Bootstrapper.Worker.App/Program.cs index 9860bbc..15657e9 100644 --- a/app/Codebelt.Bootstrapper.Worker.App/Program.cs +++ b/app/Codebelt.Bootstrapper.Worker.App/Program.cs @@ -1,16 +1,15 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Worker.App +namespace Codebelt.Bootstrapper.Worker.App; + +public class Program : WorkerProgram { - public class Program : WorkerProgram + static async Task Main(string[] args) { - static async Task Main(string[] args) - { - await CreateHostBuilder(args) - .Build() - .RunAsync() - .ConfigureAwait(false); - } + await CreateHostBuilder(args) + .Build() + .RunAsync() + .ConfigureAwait(false); } } diff --git a/app/Codebelt.Bootstrapper.Worker.App/Startup.cs b/app/Codebelt.Bootstrapper.Worker.App/Startup.cs index b03bbe0..3d36120 100644 --- a/app/Codebelt.Bootstrapper.Worker.App/Startup.cs +++ b/app/Codebelt.Bootstrapper.Worker.App/Startup.cs @@ -1,18 +1,17 @@ -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Worker.App +namespace Codebelt.Bootstrapper.Worker.App; + +public class Startup : WorkerStartup { - public class Startup : WorkerStartup + public Startup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) { - public Startup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) - { - } + } - public override void ConfigureServices(IServiceCollection services) - { - services.AddHostedService(); - } + public override void ConfigureServices(IServiceCollection services) + { + services.AddHostedService(); } } diff --git a/src/Codebelt.Bootstrapper.Console/ConsoleHostedService.cs b/src/Codebelt.Bootstrapper.Console/ConsoleHostedService.cs index 277c3d3..325f989 100644 --- a/src/Codebelt.Bootstrapper.Console/ConsoleHostedService.cs +++ b/src/Codebelt.Bootstrapper.Console/ConsoleHostedService.cs @@ -1,4 +1,4 @@ -using Cuemon; +using Cuemon; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; @@ -7,120 +7,119 @@ using System.Threading.Tasks; using Microsoft.Extensions.Options; -namespace Codebelt.Bootstrapper.Console +namespace Codebelt.Bootstrapper.Console; + +/// +/// Provides a console application that is managed by its host. +/// +/// The type containing the startup methods for the application. +/// +public class ConsoleHostedService : IHostedService where TStartup : ConsoleStartup { + private readonly IStartupFactory _factory; + private readonly IHostApplicationLifetime _applicationLifetime; + private readonly IServiceProvider _provider; + private ILogger _logger; + private bool _ranToCompletion; + private Task _runAsyncTask; + private readonly IHostLifetimeEvents _events; + private readonly bool _suppressStatusMessages; + /// - /// Provides a console application that is managed by its host. + /// Initializes a new instance of the class. /// - /// The type containing the startup methods for the application. - /// - public class ConsoleHostedService : IHostedService where TStartup : ConsoleStartup + /// The dependency injected . + /// The dependency injected . + /// The dependency injected . + /// The dependency injected . + public ConsoleHostedService(IStartupFactory factory, IHostApplicationLifetime applicationLifetime, IServiceProvider provider, IHostLifetimeEvents events) { - private readonly IStartupFactory _factory; - private readonly IHostApplicationLifetime _applicationLifetime; - private readonly IServiceProvider _provider; - private ILogger _logger; - private bool _ranToCompletion; - private Task _runAsyncTask; - private readonly IHostLifetimeEvents _events; - private readonly bool _suppressStatusMessages; + _factory = factory; + _applicationLifetime = applicationLifetime; + _provider = provider; + _events = events; + _suppressStatusMessages = provider.GetService>()?.Value.SuppressStatusMessages ?? false; + } - /// - /// Initializes a new instance of the class. - /// - /// The dependency injected . - /// The dependency injected . - /// The dependency injected . - /// The dependency injected . - public ConsoleHostedService(IStartupFactory factory, IHostApplicationLifetime applicationLifetime, IServiceProvider provider, IHostLifetimeEvents events) + /// + /// Triggered when the application host is ready to start the service. + /// + /// Indicates that the start process has been aborted. + /// A that represents the asynchronous operation. + public Task StartAsync(CancellationToken cancellationToken) + { + _logger = _provider.GetRequiredService>(); + TStartup startup = _factory.Instance; + if (startup != null) { - _factory = factory; - _applicationLifetime = applicationLifetime; - _provider = provider; - _events = events; - _suppressStatusMessages = provider.GetService>()?.Value.SuppressStatusMessages ?? false; + startup.ConfigureConsole(_provider); + _events.OnApplicationStartedCallback += () => StartRunAsync(startup, cancellationToken); } - - /// - /// Triggered when the application host is ready to start the service. - /// - /// Indicates that the start process has been aborted. - /// A that represents the asynchronous operation. - public Task StartAsync(CancellationToken cancellationToken) + else { - _logger = _provider.GetRequiredService>(); - TStartup startup = _factory.Instance; - if (startup != null) - { - startup.ConfigureConsole(_provider); - _events.OnApplicationStartedCallback += () => StartRunAsync(startup, cancellationToken); - } - else - { - LogUnableToActivate(typeof(TStartup).FullName); - } - - return Task.CompletedTask; + LogUnableToActivate(typeof(TStartup).FullName); } - private void StartRunAsync(TStartup startup, CancellationToken cancellationToken) - { - _runAsyncTask = Task.Run(() => RunAsync(startup, cancellationToken), cancellationToken); - _ = StartWaitForCompletionOfRunAsync(); - } + return Task.CompletedTask; + } - private async Task RunAsync(TStartup startup, CancellationToken cancellationToken) - { - try - { - LogRunAsyncStarted(); - await startup.RunAsync(_provider, cancellationToken).ConfigureAwait(false); - _ranToCompletion = true; - } - catch (Exception e) - { - LogFatalError(typeof(TStartup).FullName, e); - } - } + private void StartRunAsync(TStartup startup, CancellationToken cancellationToken) + { + _runAsyncTask = Task.Run(() => RunAsync(startup, cancellationToken), cancellationToken); + _ = StartWaitForCompletionOfRunAsync(); + } - private void LogRunAsyncStarted() + private async Task RunAsync(TStartup startup, CancellationToken cancellationToken) + { + try { - if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false).RunAsyncStarted(); } + LogRunAsyncStarted(); + await startup.RunAsync(_provider, cancellationToken).ConfigureAwait(false); + _ranToCompletion = true; } - - private void LogUnableToActivate(string typeFullName) + catch (Exception e) { - if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false).UnableToActivateInstance(typeFullName); } + LogFatalError(typeof(TStartup).FullName, e); } + } - private void LogFatalError(string typeFullName, Exception exception) - { - if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false).FatalErrorActivating(typeFullName, exception); } - } + private void LogRunAsyncStarted() + { + if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false).RunAsyncStarted(); } + } + + private void LogUnableToActivate(string typeFullName) + { + if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false).UnableToActivateInstance(typeFullName); } + } + + private void LogFatalError(string typeFullName, Exception exception) + { + if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false).FatalErrorActivating(typeFullName, exception); } + } - private async Task StartWaitForCompletionOfRunAsync() + private async Task StartWaitForCompletionOfRunAsync() + { + await _runAsyncTask.ConfigureAwait(false); + _applicationLifetime.StopApplication(); + } + + /// + /// Triggered when the application host is performing a graceful shutdown. + /// + /// Indicates that the shutdown process should no longer be graceful. + /// A that represents the asynchronous operation. + public Task StopAsync(CancellationToken cancellationToken) + { + if (!_ranToCompletion) { - await _runAsyncTask.ConfigureAwait(false); - _applicationLifetime.StopApplication(); + if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false)?.RunAsyncPrematureEnd(); } } - - /// - /// Triggered when the application host is performing a graceful shutdown. - /// - /// Indicates that the shutdown process should no longer be graceful. - /// A that represents the asynchronous operation. - public Task StopAsync(CancellationToken cancellationToken) + else { - if (!_ranToCompletion) - { - if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false)?.RunAsyncPrematureEnd(); } - } - else - { - if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false)?.RunAsyncCompleted(); } - } - - return Task.CompletedTask; + if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false)?.RunAsyncCompleted(); } } + + return Task.CompletedTask; } } diff --git a/src/Codebelt.Bootstrapper.Console/ConsoleProgram.cs b/src/Codebelt.Bootstrapper.Console/ConsoleProgram.cs index 2883c33..a1aae35 100644 --- a/src/Codebelt.Bootstrapper.Console/ConsoleProgram.cs +++ b/src/Codebelt.Bootstrapper.Console/ConsoleProgram.cs @@ -1,26 +1,25 @@ -using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Console +namespace Codebelt.Bootstrapper.Console; + +/// +/// The base entry point of an application responsible for registering its partner. +/// +/// The type containing the startup methods for the application. +/// +public abstract class ConsoleProgram : ProgramRoot where TStartup : ConsoleStartup { /// - /// The base entry point of an application responsible for registering its partner. + /// Creates an used to set up the host. /// - /// The type containing the startup methods for the application. - /// - public abstract class ConsoleProgram : ProgramRoot where TStartup : ConsoleStartup + /// The command line arguments. + /// The initialized . + protected static IHostBuilder CreateHostBuilder(string[] args) { - /// - /// Creates an used to set up the host. - /// - /// The command line arguments. - /// The initialized . - protected static IHostBuilder CreateHostBuilder(string[] args) - { - return Host.CreateDefaultBuilder(args) - .UseBootstrapperLifetime() - .UseBootstrapperStartup() - .UseBootstrapperEnvironmentDefaults() - .UseConsoleStartup(); - } + return Host.CreateDefaultBuilder(args) + .UseBootstrapperLifetime() + .UseBootstrapperStartup() + .UseBootstrapperEnvironmentDefaults() + .UseConsoleStartup(); } } diff --git a/src/Codebelt.Bootstrapper.Console/ConsoleStartup.cs b/src/Codebelt.Bootstrapper.Console/ConsoleStartup.cs index 72c9fe2..f09534b 100644 --- a/src/Codebelt.Bootstrapper.Console/ConsoleStartup.cs +++ b/src/Codebelt.Bootstrapper.Console/ConsoleStartup.cs @@ -1,39 +1,38 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Console +namespace Codebelt.Bootstrapper.Console; + +/// +/// Provides the base class of a conventional based Startup class for a console application. +/// +/// +public abstract class ConsoleStartup : StartupRoot { /// - /// Provides the base class of a conventional based Startup class for a console application. + /// Initializes a new instance of the class. /// - /// - public abstract class ConsoleStartup : StartupRoot + /// The dependency injected . + /// The dependency injected . + protected ConsoleStartup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) { - /// - /// Initializes a new instance of the class. - /// - /// The dependency injected . - /// The dependency injected . - protected ConsoleStartup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) - { - } - - /// - /// Provides access to previously registered services. - /// - /// The to retrieve services from. - public virtual void ConfigureConsole(IServiceProvider serviceProvider) - { - } + } - /// - /// A convenient method for executing fire-and-forget code. - /// - /// The to retrieve services from. - /// Indicates that the run has been aborted. - public abstract Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken); + /// + /// Provides access to previously registered services. + /// + /// The to retrieve services from. + public virtual void ConfigureConsole(IServiceProvider serviceProvider) + { } + + /// + /// A convenient method for executing fire-and-forget code. + /// + /// The to retrieve services from. + /// Indicates that the run has been aborted. + public abstract Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken); } diff --git a/src/Codebelt.Bootstrapper.Console/HostApplicationBuilderExtensions.cs b/src/Codebelt.Bootstrapper.Console/HostApplicationBuilderExtensions.cs index d3ce6b8..773c468 100644 --- a/src/Codebelt.Bootstrapper.Console/HostApplicationBuilderExtensions.cs +++ b/src/Codebelt.Bootstrapper.Console/HostApplicationBuilderExtensions.cs @@ -1,35 +1,34 @@ -using System; +using System; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Console +namespace Codebelt.Bootstrapper.Console; + +/// +/// Extension methods for the . +/// +public static class HostApplicationBuilderExtensions { /// - /// Extension methods for the . + /// Provides an implementation of a conventional based . /// - public static class HostApplicationBuilderExtensions + /// The to configure. + /// The that must be assignable from . + /// The same instance of the for chaining. + public static IHostApplicationBuilder UseBootstrapperProgram(this IHostApplicationBuilder hostBuilder, Type minimalConsoleProgramType) { - /// - /// Provides an implementation of a conventional based . - /// - /// The to configure. - /// The that must be assignable from . - /// The same instance of the for chaining. - public static IHostApplicationBuilder UseBootstrapperProgram(this IHostApplicationBuilder hostBuilder, Type minimalConsoleProgramType) - { - hostBuilder.Services.AddSingleton(new ProgramFactory(minimalConsoleProgramType)); - return hostBuilder; - } + hostBuilder.Services.AddSingleton(new ProgramFactory(minimalConsoleProgramType)); + return hostBuilder; + } - /// - /// Provides an implementation of that has the role of a console application. - /// - /// The to configure. - /// The same instance of the for chaining. - public static IHostApplicationBuilder UseMinimalConsoleProgram(this IHostApplicationBuilder hostBuilder) - { - hostBuilder.Services.AddHostedService(); - return hostBuilder; - } + /// + /// Provides an implementation of that has the role of a console application. + /// + /// The to configure. + /// The same instance of the for chaining. + public static IHostApplicationBuilder UseMinimalConsoleProgram(this IHostApplicationBuilder hostBuilder) + { + hostBuilder.Services.AddHostedService(); + return hostBuilder; } } diff --git a/src/Codebelt.Bootstrapper.Console/HostBuilderExtensions.cs b/src/Codebelt.Bootstrapper.Console/HostBuilderExtensions.cs index aa58ffd..50fc242 100644 --- a/src/Codebelt.Bootstrapper.Console/HostBuilderExtensions.cs +++ b/src/Codebelt.Bootstrapper.Console/HostBuilderExtensions.cs @@ -1,25 +1,24 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Console +namespace Codebelt.Bootstrapper.Console; + +/// +/// Extension methods for the . +/// +public static class HostBuilderExtensions { /// - /// Extension methods for the . + /// Provides an implementation of that has the role of a console application. /// - public static class HostBuilderExtensions + /// The type containing the startup methods for the application. + /// The to configure. + /// The same instance of the for chaining. + public static IHostBuilder UseConsoleStartup(this IHostBuilder hostBuilder) where TStartup : ConsoleStartup { - /// - /// Provides an implementation of that has the role of a console application. - /// - /// The type containing the startup methods for the application. - /// The to configure. - /// The same instance of the for chaining. - public static IHostBuilder UseConsoleStartup(this IHostBuilder hostBuilder) where TStartup : ConsoleStartup + return hostBuilder.ConfigureServices(services => { - return hostBuilder.ConfigureServices(services => - { - services.AddHostedService>(); - }); - } + services.AddHostedService>(); + }); } } diff --git a/src/Codebelt.Bootstrapper.Console/IProgramFactory.cs b/src/Codebelt.Bootstrapper.Console/IProgramFactory.cs index e17db9b..04283a8 100644 --- a/src/Codebelt.Bootstrapper.Console/IProgramFactory.cs +++ b/src/Codebelt.Bootstrapper.Console/IProgramFactory.cs @@ -1,14 +1,13 @@ -namespace Codebelt.Bootstrapper.Console +namespace Codebelt.Bootstrapper.Console; + +/// +/// Provides an interface for initializing services and middleware used by an application. +/// +public interface IProgramFactory { /// - /// Provides an interface for initializing services and middleware used by an application. + /// Provides access to an instance inheriting from . /// - public interface IProgramFactory - { - /// - /// Provides access to an instance inheriting from . - /// - /// A reference to the object of type . - MinimalConsoleProgram Instance { get; } - } + /// A reference to the object of type . + MinimalConsoleProgram Instance { get; } } diff --git a/src/Codebelt.Bootstrapper.Console/MinimalConsoleHostedService.cs b/src/Codebelt.Bootstrapper.Console/MinimalConsoleHostedService.cs index aa42d6a..ec93291 100644 --- a/src/Codebelt.Bootstrapper.Console/MinimalConsoleHostedService.cs +++ b/src/Codebelt.Bootstrapper.Console/MinimalConsoleHostedService.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using System; @@ -7,125 +7,124 @@ using Cuemon; using Microsoft.Extensions.Options; -namespace Codebelt.Bootstrapper.Console +namespace Codebelt.Bootstrapper.Console; + +/// +/// Provides a console application that is managed by its host. +/// +/// +public class MinimalConsoleHostedService : IHostedService { + private readonly IProgramFactory _factory; + private readonly IHostApplicationLifetime _applicationLifetime; + private readonly IServiceProvider _provider; + private ILogger _logger; + private bool _ranToCompletion; + private Task _runAsyncTask; + private readonly IHostLifetimeEvents _events; + private readonly bool _suppressStatusMessages; + /// - /// Provides a console application that is managed by its host. + /// Initializes a new instance of the class. /// - /// - public class MinimalConsoleHostedService : IHostedService + /// The dependency injected . + /// The dependency injected . + /// The dependency injected . + /// The dependency injected . + public MinimalConsoleHostedService(IProgramFactory factory, IHostApplicationLifetime applicationLifetime, IServiceProvider provider, IHostLifetimeEvents events) { - private readonly IProgramFactory _factory; - private readonly IHostApplicationLifetime _applicationLifetime; - private readonly IServiceProvider _provider; - private ILogger _logger; - private bool _ranToCompletion; - private Task _runAsyncTask; - private readonly IHostLifetimeEvents _events; - private readonly bool _suppressStatusMessages; - - /// - /// Initializes a new instance of the class. - /// - /// The dependency injected . - /// The dependency injected . - /// The dependency injected . - /// The dependency injected . - public MinimalConsoleHostedService(IProgramFactory factory, IHostApplicationLifetime applicationLifetime, IServiceProvider provider, IHostLifetimeEvents events) - { - _factory = factory; - _applicationLifetime = applicationLifetime; - _provider = provider; - _events = events; - _suppressStatusMessages = provider.GetService>()?.Value.SuppressStatusMessages ?? false; - } + _factory = factory; + _applicationLifetime = applicationLifetime; + _provider = provider; + _events = events; + _suppressStatusMessages = provider.GetService>()?.Value.SuppressStatusMessages ?? false; + } - /// - /// Triggered when the application host is ready to start the service. - /// - /// Indicates that the start process has been aborted. - /// A that represents the asynchronous operation. - public Task StartAsync(CancellationToken cancellationToken) - { - _events.OnApplicationStartedCallback += () => StartRunAsync(cancellationToken); + /// + /// Triggered when the application host is ready to start the service. + /// + /// Indicates that the start process has been aborted. + /// A that represents the asynchronous operation. + public Task StartAsync(CancellationToken cancellationToken) + { + _events.OnApplicationStartedCallback += () => StartRunAsync(cancellationToken); - return Task.CompletedTask; - } + return Task.CompletedTask; + } - private void StartRunAsync(CancellationToken cancellationToken) - { - MinimalConsoleProgram program = _factory.Instance; - Type programType = program?.GetType() ?? typeof(MinimalConsoleProgram); + private void StartRunAsync(CancellationToken cancellationToken) + { + MinimalConsoleProgram program = _factory.Instance; + Type programType = program?.GetType() ?? typeof(MinimalConsoleProgram); - _logger = ResolveLogger(programType); - _runAsyncTask = Task.Run(() => RunAsync(program, programType, cancellationToken), cancellationToken); - _ = StartWaitForCompletionOfRunAsync(); - } + _logger = ResolveLogger(programType); + _runAsyncTask = Task.Run(() => RunAsync(program, programType, cancellationToken), cancellationToken); + _ = StartWaitForCompletionOfRunAsync(); + } - private ILogger ResolveLogger(Type programType) - { - Type loggerType = typeof(ILogger<>).MakeGenericType(programType); - return _provider.GetRequiredService(loggerType) as ILogger; - } + private ILogger ResolveLogger(Type programType) + { + Type loggerType = typeof(ILogger<>).MakeGenericType(programType); + return _provider.GetRequiredService(loggerType) as ILogger; + } - private async Task RunAsync(MinimalConsoleProgram program, Type programType, CancellationToken cancellationToken) + private async Task RunAsync(MinimalConsoleProgram program, Type programType, CancellationToken cancellationToken) + { + try { - try - { - if (program == null) - { - LogUnableToActivate(programType.FullName); - return; - } - - LogRunAsyncStarted(); - await program.RunAsync(_provider, cancellationToken).ConfigureAwait(false); - _ranToCompletion = true; - } - catch (Exception e) + if (program == null) { - LogFatalError(programType.FullName, e); + LogUnableToActivate(programType.FullName); + return; } - } - private void LogRunAsyncStarted() - { - if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false).RunAsyncStarted(); } + LogRunAsyncStarted(); + await program.RunAsync(_provider, cancellationToken).ConfigureAwait(false); + _ranToCompletion = true; } - - private void LogUnableToActivate(string typeFullName) + catch (Exception e) { - if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false).UnableToActivateInstance(typeFullName); } + LogFatalError(programType.FullName, e); } + } - private void LogFatalError(string typeFullName, Exception exception) - { - if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false).FatalErrorActivating(typeFullName, exception); } - } + private void LogRunAsyncStarted() + { + if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false).RunAsyncStarted(); } + } + + private void LogUnableToActivate(string typeFullName) + { + if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false).UnableToActivateInstance(typeFullName); } + } + + private void LogFatalError(string typeFullName, Exception exception) + { + if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false).FatalErrorActivating(typeFullName, exception); } + } + + private async Task StartWaitForCompletionOfRunAsync() + { + await _runAsyncTask.ConfigureAwait(false); + _applicationLifetime.StopApplication(); + } - private async Task StartWaitForCompletionOfRunAsync() + /// + /// Triggered when the application host is performing a graceful shutdown. + /// + /// Indicates that the shutdown process should no longer be graceful. + /// A that represents the asynchronous operation. + public Task StopAsync(CancellationToken cancellationToken) + { + if (!_ranToCompletion) { - await _runAsyncTask.ConfigureAwait(false); - _applicationLifetime.StopApplication(); + if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false)?.RunAsyncPrematureEnd(); } } - - /// - /// Triggered when the application host is performing a graceful shutdown. - /// - /// Indicates that the shutdown process should no longer be graceful. - /// A that represents the asynchronous operation. - public Task StopAsync(CancellationToken cancellationToken) + else { - if (!_ranToCompletion) - { - if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false)?.RunAsyncPrematureEnd(); } - } - else - { - if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false)?.RunAsyncCompleted(); } - } - - return Task.CompletedTask; + if (!_suppressStatusMessages) { Decorator.EncloseToExpose(_logger, false)?.RunAsyncCompleted(); } } + + return Task.CompletedTask; } } diff --git a/src/Codebelt.Bootstrapper.Console/MinimalConsoleProgram.cs b/src/Codebelt.Bootstrapper.Console/MinimalConsoleProgram.cs index 5f7c506..50b47f2 100644 --- a/src/Codebelt.Bootstrapper.Console/MinimalConsoleProgram.cs +++ b/src/Codebelt.Bootstrapper.Console/MinimalConsoleProgram.cs @@ -1,53 +1,52 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Console +namespace Codebelt.Bootstrapper.Console; + +/// +/// The base entry point of an application optimized for console applications. +/// +public abstract class MinimalConsoleProgram : ProgramRoot { /// - /// The base entry point of an application optimized for console applications. + /// Creates an used to set up the host. /// - public abstract class MinimalConsoleProgram : ProgramRoot - { - /// - /// Creates an used to set up the host. - /// - /// The command line arguments. - /// The initialized . - protected static HostApplicationBuilder CreateHostBuilder(string[] args) => CreateHostBuilder(args, typeof(MinimalConsoleProgram)); + /// The command line arguments. + /// The initialized . + protected static HostApplicationBuilder CreateHostBuilder(string[] args) => CreateHostBuilder(args, typeof(MinimalConsoleProgram)); - /// - /// A convenient method for executing fire-and-forget code. - /// - /// The to retrieve services from. - /// Indicates that the run has been aborted. - /// A that completes when the execution is finished. - public abstract Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken); + /// + /// A convenient method for executing fire-and-forget code. + /// + /// The to retrieve services from. + /// Indicates that the run has been aborted. + /// A that completes when the execution is finished. + public abstract Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken); - internal static HostApplicationBuilder CreateHostBuilder(string[] args, Type programType) - { - var hb = Host.CreateApplicationBuilder(args); - hb.UseBootstrapperLifetime(); - hb.UseBootstrapperEnvironmentDefaults(); - hb.UseBootstrapperProgram(programType); - hb.UseMinimalConsoleProgram(); - return hb; - } + internal static HostApplicationBuilder CreateHostBuilder(string[] args, Type programType) + { + var hb = Host.CreateApplicationBuilder(args); + hb.UseBootstrapperLifetime(); + hb.UseBootstrapperEnvironmentDefaults(); + hb.UseBootstrapperProgram(programType); + hb.UseMinimalConsoleProgram(); + return hb; } +} +/// +/// The base entry point of an application optimized for console applications with a specific bootstrap type. +/// +/// The type responsible for the application bootstrap. +/// +public abstract class MinimalConsoleProgram : MinimalConsoleProgram where TProgram : ProgramRoot +{ /// - /// The base entry point of an application optimized for console applications with a specific bootstrap type. + /// Creates an used to set up the host. /// - /// The type responsible for the application bootstrap. - /// - public abstract class MinimalConsoleProgram : MinimalConsoleProgram where TProgram : ProgramRoot - { - /// - /// Creates an used to set up the host. - /// - /// The command line arguments. - /// The initialized . - protected new static HostApplicationBuilder CreateHostBuilder(string[] args) => CreateHostBuilder(args, typeof(TProgram)); - } + /// The command line arguments. + /// The initialized . + protected new static HostApplicationBuilder CreateHostBuilder(string[] args) => CreateHostBuilder(args, typeof(TProgram)); } diff --git a/src/Codebelt.Bootstrapper.Console/ProgramFactory.cs b/src/Codebelt.Bootstrapper.Console/ProgramFactory.cs index 20e3a37..f4a0579 100644 --- a/src/Codebelt.Bootstrapper.Console/ProgramFactory.cs +++ b/src/Codebelt.Bootstrapper.Console/ProgramFactory.cs @@ -1,31 +1,30 @@ -using System; +using System; using System.Linq; using System.Reflection; using Cuemon; using Cuemon.Collections.Generic; -namespace Codebelt.Bootstrapper.Console +namespace Codebelt.Bootstrapper.Console; + +/// +/// The default implementation of . +/// +public class ProgramFactory : IProgramFactory { /// - /// The default implementation of . + /// Initializes a new instance of the class. /// - public class ProgramFactory : IProgramFactory + /// + public ProgramFactory(Type minimalConsoleProgramType) { - /// - /// Initializes a new instance of the class. - /// - /// - public ProgramFactory(Type minimalConsoleProgramType) - { - Validator.ThrowIfNotContainsType(minimalConsoleProgramType, Arguments.ToArrayOf(typeof(MinimalConsoleProgram)), $"{nameof(minimalConsoleProgramType)} is not assignable from MinimalConsoleProgram."); - var candidate = Decorator.Enclose(minimalConsoleProgramType).GetDerivedTypes(Assembly.GetEntryAssembly()).FirstOrDefault(); - Instance = Activator.CreateInstance(candidate, true) as MinimalConsoleProgram; - } - - /// - /// Provides access to an instance inheriting from . - /// - /// A reference to the object of type . - public MinimalConsoleProgram Instance { get; } + Validator.ThrowIfNotContainsType(minimalConsoleProgramType, Arguments.ToArrayOf(typeof(MinimalConsoleProgram)), $"{nameof(minimalConsoleProgramType)} is not assignable from MinimalConsoleProgram."); + var candidate = Decorator.Enclose(minimalConsoleProgramType).GetDerivedTypes(Assembly.GetEntryAssembly()).FirstOrDefault(); + Instance = Activator.CreateInstance(candidate, true) as MinimalConsoleProgram; } + + /// + /// Provides access to an instance inheriting from . + /// + /// A reference to the object of type . + public MinimalConsoleProgram Instance { get; } } diff --git a/src/Codebelt.Bootstrapper.Console/Properties/AssemblyInfo.cs b/src/Codebelt.Bootstrapper.Console/Properties/AssemblyInfo.cs index cadbee7..6a9d591 100644 --- a/src/Codebelt.Bootstrapper.Console/Properties/AssemblyInfo.cs +++ b/src/Codebelt.Bootstrapper.Console/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; [assembly: ComVisible(false)] -[assembly: Guid("86e2ac39-79b4-42f0-9dcd-f88ea40adba6")] \ No newline at end of file +[assembly: Guid("86e2ac39-79b4-42f0-9dcd-f88ea40adba6")] diff --git a/src/Codebelt.Bootstrapper.Web/MinimalWebProgram.cs b/src/Codebelt.Bootstrapper.Web/MinimalWebProgram.cs index 63a8d68..8265caa 100644 --- a/src/Codebelt.Bootstrapper.Web/MinimalWebProgram.cs +++ b/src/Codebelt.Bootstrapper.Web/MinimalWebProgram.cs @@ -1,24 +1,23 @@ -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Web +namespace Codebelt.Bootstrapper.Web; + +/// +/// The base entry point of an application optimized for web applications. +/// +public abstract class MinimalWebProgram : ProgramRoot { /// - /// The base entry point of an application optimized for web applications. + /// Creates an used to set up the host. /// - public abstract class MinimalWebProgram : ProgramRoot + /// The command line arguments. + /// The initialized . + protected static WebApplicationBuilder CreateHostBuilder(string[] args) { - /// - /// Creates an used to set up the host. - /// - /// The command line arguments. - /// The initialized . - protected static WebApplicationBuilder CreateHostBuilder(string[] args) - { - var hb = WebApplication.CreateBuilder(args); - hb.UseBootstrapperLifetime(); - hb.UseBootstrapperEnvironmentDefaults(); - return hb; - } + var hb = WebApplication.CreateBuilder(args); + hb.UseBootstrapperLifetime(); + hb.UseBootstrapperEnvironmentDefaults(); + return hb; } } diff --git a/src/Codebelt.Bootstrapper.Web/Properties/AssemblyInfo.cs b/src/Codebelt.Bootstrapper.Web/Properties/AssemblyInfo.cs index 6dc0c12..fd65898 100644 --- a/src/Codebelt.Bootstrapper.Web/Properties/AssemblyInfo.cs +++ b/src/Codebelt.Bootstrapper.Web/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; [assembly: ComVisible(false)] -[assembly: Guid("6620ad70-7371-42e2-a857-f88ea40adba6")] \ No newline at end of file +[assembly: Guid("6620ad70-7371-42e2-a857-f88ea40adba6")] diff --git a/src/Codebelt.Bootstrapper.Web/WebProgram.cs b/src/Codebelt.Bootstrapper.Web/WebProgram.cs index 8a17252..eb9aea6 100644 --- a/src/Codebelt.Bootstrapper.Web/WebProgram.cs +++ b/src/Codebelt.Bootstrapper.Web/WebProgram.cs @@ -1,29 +1,28 @@ -using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Web +namespace Codebelt.Bootstrapper.Web; + +/// +/// The entry point of an application responsible for registering its partner. +/// +/// The type containing the startup methods for the application. +/// +public class WebProgram : ProgramRoot where TStartup : WebStartup { /// - /// The entry point of an application responsible for registering its partner. + /// Creates an used to set up the host. /// - /// The type containing the startup methods for the application. - /// - public class WebProgram : ProgramRoot where TStartup : WebStartup + /// The command line arguments. + /// The initialized . + protected static IHostBuilder CreateHostBuilder(string[] args) { - /// - /// Creates an used to set up the host. - /// - /// The command line arguments. - /// The initialized . - protected static IHostBuilder CreateHostBuilder(string[] args) - { - return Host.CreateDefaultBuilder(args) - .UseBootstrapperLifetime() - .UseBootstrapperEnvironmentDefaults() - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }); - } + return Host.CreateDefaultBuilder(args) + .UseBootstrapperLifetime() + .UseBootstrapperEnvironmentDefaults() + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); } } diff --git a/src/Codebelt.Bootstrapper.Web/WebStartup.cs b/src/Codebelt.Bootstrapper.Web/WebStartup.cs index c13b4c5..fc2c26e 100644 --- a/src/Codebelt.Bootstrapper.Web/WebStartup.cs +++ b/src/Codebelt.Bootstrapper.Web/WebStartup.cs @@ -1,36 +1,35 @@ -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Web +namespace Codebelt.Bootstrapper.Web; + +/// +/// Provides the base class of a conventional based Startup class for web applications. +/// +/// +public abstract class WebStartup : StartupRoot { /// - /// Provides the base class of a conventional based Startup class for web applications. + /// Initializes a new instance of the class. /// - /// - public abstract class WebStartup : StartupRoot + /// The dependency injected . + /// The dependency injected . + protected WebStartup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) { - /// - /// Initializes a new instance of the class. - /// - /// The dependency injected . - /// The dependency injected . - protected WebStartup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) - { - } + } - /// - /// Configures the application pipeline. - /// - /// The for the application to configure. - public abstract void ConfigurePipeline(IApplicationBuilder app); + /// + /// Configures the application pipeline. + /// + /// The for the application to configure. + public abstract void ConfigurePipeline(IApplicationBuilder app); - /// - /// Delegates the application pipeline configuration to . - /// - /// The for the application to configure. - /// This method is necessary as we rely on built-in convention based bootstrapping (>). - public void Configure(IApplicationBuilder app) => ConfigurePipeline(app); - } + /// + /// Delegates the application pipeline configuration to . + /// + /// The for the application to configure. + /// This method is necessary as we rely on built-in convention based bootstrapping (>). + public void Configure(IApplicationBuilder app) => ConfigurePipeline(app); } diff --git a/src/Codebelt.Bootstrapper.Worker/MinimalWorkerProgram.cs b/src/Codebelt.Bootstrapper.Worker/MinimalWorkerProgram.cs index f5fadd7..29749f6 100644 --- a/src/Codebelt.Bootstrapper.Worker/MinimalWorkerProgram.cs +++ b/src/Codebelt.Bootstrapper.Worker/MinimalWorkerProgram.cs @@ -1,23 +1,22 @@ -using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Worker +namespace Codebelt.Bootstrapper.Worker; + +/// +/// The base entry point of an application optimized for worker applications. +/// +public abstract class MinimalWorkerProgram : ProgramRoot { /// - /// The base entry point of an application optimized for worker applications. + /// Creates an used to set up the host. /// - public abstract class MinimalWorkerProgram : ProgramRoot + /// The command line arguments. + /// The initialized . + protected static HostApplicationBuilder CreateHostBuilder(string[] args) { - /// - /// Creates an used to set up the host. - /// - /// The command line arguments. - /// The initialized . - protected static HostApplicationBuilder CreateHostBuilder(string[] args) - { - var hb = Host.CreateApplicationBuilder(args); - hb.UseBootstrapperLifetime(); - hb.UseBootstrapperEnvironmentDefaults(); - return hb; - } + var hb = Host.CreateApplicationBuilder(args); + hb.UseBootstrapperLifetime(); + hb.UseBootstrapperEnvironmentDefaults(); + return hb; } } diff --git a/src/Codebelt.Bootstrapper.Worker/Properties/AssemblyInfo.cs b/src/Codebelt.Bootstrapper.Worker/Properties/AssemblyInfo.cs index 035b23e..5c9f46c 100644 --- a/src/Codebelt.Bootstrapper.Worker/Properties/AssemblyInfo.cs +++ b/src/Codebelt.Bootstrapper.Worker/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; [assembly: ComVisible(false)] -[assembly: Guid("b94e8352-1808-4cfe-a7b4-f88ea40adba6")] \ No newline at end of file +[assembly: Guid("b94e8352-1808-4cfe-a7b4-f88ea40adba6")] diff --git a/src/Codebelt.Bootstrapper.Worker/WorkerProgram.cs b/src/Codebelt.Bootstrapper.Worker/WorkerProgram.cs index 11548e5..07727d8 100644 --- a/src/Codebelt.Bootstrapper.Worker/WorkerProgram.cs +++ b/src/Codebelt.Bootstrapper.Worker/WorkerProgram.cs @@ -1,25 +1,24 @@ -using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Worker +namespace Codebelt.Bootstrapper.Worker; + +/// +/// The entry point of an application responsible for registering its partner. +/// +/// The type containing the startup methods for the application. +/// +public class WorkerProgram : ProgramRoot where TStartup : WorkerStartup { /// - /// The entry point of an application responsible for registering its partner. + /// Creates an used to set up the host. /// - /// The type containing the startup methods for the application. - /// - public class WorkerProgram : ProgramRoot where TStartup : WorkerStartup + /// The command line arguments. + /// The initialized . + protected static IHostBuilder CreateHostBuilder(string[] args) { - /// - /// Creates an used to set up the host. - /// - /// The command line arguments. - /// The initialized . - protected static IHostBuilder CreateHostBuilder(string[] args) - { - return Host.CreateDefaultBuilder(args) - .UseBootstrapperLifetime() - .UseBootstrapperEnvironmentDefaults() - .UseBootstrapperStartup(); - } + return Host.CreateDefaultBuilder(args) + .UseBootstrapperLifetime() + .UseBootstrapperEnvironmentDefaults() + .UseBootstrapperStartup(); } } diff --git a/src/Codebelt.Bootstrapper.Worker/WorkerStartup.cs b/src/Codebelt.Bootstrapper.Worker/WorkerStartup.cs index f5ea733..873ca78 100644 --- a/src/Codebelt.Bootstrapper.Worker/WorkerStartup.cs +++ b/src/Codebelt.Bootstrapper.Worker/WorkerStartup.cs @@ -1,21 +1,20 @@ -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Worker +namespace Codebelt.Bootstrapper.Worker; + +/// +/// Provides the base class of a conventional based Startup class for a worker service. +/// +/// +public abstract class WorkerStartup : StartupRoot { /// - /// Provides the base class of a conventional based Startup class for a worker service. + /// Initializes a new instance of the class. /// - /// - public abstract class WorkerStartup : StartupRoot + /// The dependency injected . + /// The dependency injected . + protected WorkerStartup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) { - /// - /// Initializes a new instance of the class. - /// - /// The dependency injected . - /// The dependency injected . - protected WorkerStartup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) - { - } } } diff --git a/src/Codebelt.Bootstrapper/BootstrapperLifetime.cs b/src/Codebelt.Bootstrapper/BootstrapperLifetime.cs index 31be448..602b81f 100644 --- a/src/Codebelt.Bootstrapper/BootstrapperLifetime.cs +++ b/src/Codebelt.Bootstrapper/BootstrapperLifetime.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using Cuemon; @@ -7,91 +7,90 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -namespace Codebelt.Bootstrapper +namespace Codebelt.Bootstrapper; + +/// +/// Listens for Ctrl+C or SIGTERM and initiates shutdown. +/// +/// +/// +public class BootstrapperLifetime : Disposable, IHostLifetime, IHostLifetimeEvents { + private readonly ConsoleLifetime _hostLifetime; + private readonly IHostApplicationLifetime _applicationLifetime; + /// - /// Listens for Ctrl+C or SIGTERM and initiates shutdown. + /// Triggered when the application host has fully started. /// - /// - /// - public class BootstrapperLifetime : Disposable, IHostLifetime, IHostLifetimeEvents - { - private readonly ConsoleLifetime _hostLifetime; - private readonly IHostApplicationLifetime _applicationLifetime; - - /// - /// Triggered when the application host has fully started. - /// - public Action OnApplicationStartedCallback { get; set; } + public Action OnApplicationStartedCallback { get; set; } - /// - /// Triggered when the application host is starting a graceful shutdown. - /// - public Action OnApplicationStoppingCallback { get; set; } + /// + /// Triggered when the application host is starting a graceful shutdown. + /// + public Action OnApplicationStoppingCallback { get; set; } - /// - /// Triggered when the application host has completed a graceful shutdown./// - public Action OnApplicationStoppedCallback { get; set; } + /// + /// Triggered when the application host has completed a graceful shutdown./// + public Action OnApplicationStoppedCallback { get; set; } - /// - /// Initializes a new instance of the class. - /// - /// The dependency injected . - /// The dependency injected . - /// The dependency injected . - /// The dependency injected . - /// The dependency injected . - public BootstrapperLifetime(IOptions options, IHostEnvironment environment, IHostApplicationLifetime applicationLifetime, IOptions hostOptions, ILoggerFactory loggerFactory) - { - _hostLifetime = new ConsoleLifetime(options, environment, applicationLifetime, hostOptions, loggerFactory); - _applicationLifetime = applicationLifetime; - } + /// + /// Initializes a new instance of the class. + /// + /// The dependency injected . + /// The dependency injected . + /// The dependency injected . + /// The dependency injected . + /// The dependency injected . + public BootstrapperLifetime(IOptions options, IHostEnvironment environment, IHostApplicationLifetime applicationLifetime, IOptions hostOptions, ILoggerFactory loggerFactory) + { + _hostLifetime = new ConsoleLifetime(options, environment, applicationLifetime, hostOptions, loggerFactory); + _applicationLifetime = applicationLifetime; + } - /// - /// Called from to indicate that the host is stopping and it's time to shut down. - /// - /// Used to indicate when stop should no longer be graceful. - /// A that represents the asynchronous operation. - public Task StopAsync(CancellationToken cancellationToken) - { - return _hostLifetime.StopAsync(cancellationToken); - } + /// + /// Called from to indicate that the host is stopping and it's time to shut down. + /// + /// Used to indicate when stop should no longer be graceful. + /// A that represents the asynchronous operation. + public Task StopAsync(CancellationToken cancellationToken) + { + return _hostLifetime.StopAsync(cancellationToken); + } - /// - /// Called at the start of which will wait until it's complete before - /// continuing. This can be used to delay startup until signaled by an external event. - /// - /// Used to abort program start. - /// A that represents the asynchronous operation. - public Task WaitForStartAsync(CancellationToken cancellationToken) - { - _applicationLifetime.ApplicationStarted.Register(OnApplicationStarted); - _applicationLifetime.ApplicationStopped.Register(OnApplicationStopped); - _applicationLifetime.ApplicationStopping.Register(OnApplicationStopping); - return _hostLifetime.WaitForStartAsync(cancellationToken); - } + /// + /// Called at the start of which will wait until it's complete before + /// continuing. This can be used to delay startup until signaled by an external event. + /// + /// Used to abort program start. + /// A that represents the asynchronous operation. + public Task WaitForStartAsync(CancellationToken cancellationToken) + { + _applicationLifetime.ApplicationStarted.Register(OnApplicationStarted); + _applicationLifetime.ApplicationStopped.Register(OnApplicationStopped); + _applicationLifetime.ApplicationStopping.Register(OnApplicationStopping); + return _hostLifetime.WaitForStartAsync(cancellationToken); + } - private void OnApplicationStarted() - { - OnApplicationStartedCallback?.Invoke(); - } + private void OnApplicationStarted() + { + OnApplicationStartedCallback?.Invoke(); + } - private void OnApplicationStopped() - { - OnApplicationStoppedCallback?.Invoke(); - } + private void OnApplicationStopped() + { + OnApplicationStoppedCallback?.Invoke(); + } - private void OnApplicationStopping() - { - OnApplicationStoppingCallback?.Invoke(); - } + private void OnApplicationStopping() + { + OnApplicationStoppingCallback?.Invoke(); + } - /// - /// Called when this object is being disposed by either or having disposing set to true and is false. - /// - protected override void OnDisposeManagedResources() - { - _hostLifetime.Dispose(); - } + /// + /// Called when this object is being disposed by either or having disposing set to true and is false. + /// + protected override void OnDisposeManagedResources() + { + _hostLifetime.Dispose(); } } diff --git a/src/Codebelt.Bootstrapper/BootstrapperLogMessages.cs b/src/Codebelt.Bootstrapper/BootstrapperLogMessages.cs index 92eb249..e8a6379 100644 --- a/src/Codebelt.Bootstrapper/BootstrapperLogMessages.cs +++ b/src/Codebelt.Bootstrapper/BootstrapperLogMessages.cs @@ -2,72 +2,71 @@ using Cuemon; using Microsoft.Extensions.Logging; -namespace Codebelt.Bootstrapper +namespace Codebelt.Bootstrapper; + +/// +/// Provides centralized logging messages for the Bootstrapper SDK using the LoggerMessage pattern. +/// This API supports the product infrastructure and is not intended to be used directly from your code. +/// +/// https://learn.microsoft.com/en-us/dotnet/core/extensions/high-performance-logging +public static class BootstrapperLogMessages { - /// - /// Provides centralized logging messages for the Bootstrapper SDK using the LoggerMessage pattern. - /// This API supports the product infrastructure and is not intended to be used directly from your code. - /// - /// https://learn.microsoft.com/en-us/dotnet/core/extensions/high-performance-logging - public static class BootstrapperLogMessages - { - // Information messages - private static readonly Action RunAsyncStartedDefinition = LoggerMessage.Define(LogLevel.Information, new EventId(1000, nameof(RunAsyncStarted)), "RunAsync started."); - private static readonly Action RunAsyncPrematureEndDefinition = LoggerMessage.Define(LogLevel.Information, new EventId(1001, nameof(RunAsyncPrematureEnd)), "RunAsync ended prematurely."); - private static readonly Action RunAsyncCompletedDefinition = LoggerMessage.Define(LogLevel.Information, new EventId(1002, nameof(RunAsyncCompleted)), "RunAsync completed successfully."); + // Information messages + private static readonly Action RunAsyncStartedDefinition = LoggerMessage.Define(LogLevel.Information, new EventId(1000, nameof(RunAsyncStarted)), "RunAsync started."); + private static readonly Action RunAsyncPrematureEndDefinition = LoggerMessage.Define(LogLevel.Information, new EventId(1001, nameof(RunAsyncPrematureEnd)), "RunAsync ended prematurely."); + private static readonly Action RunAsyncCompletedDefinition = LoggerMessage.Define(LogLevel.Information, new EventId(1002, nameof(RunAsyncCompleted)), "RunAsync completed successfully."); - // Warning messages - private static readonly Action UnableToActivateInstanceDefinition = LoggerMessage.Define(LogLevel.Warning, new EventId(2000, nameof(UnableToActivateInstance)), "Unable to activate an instance of {TypeFullName}."); + // Warning messages + private static readonly Action UnableToActivateInstanceDefinition = LoggerMessage.Define(LogLevel.Warning, new EventId(2000, nameof(UnableToActivateInstance)), "Unable to activate an instance of {TypeFullName}."); - // Critical messages - private static readonly Action FatalErrorActivatingDefinition = LoggerMessage.Define(LogLevel.Critical, new EventId(3000, nameof(FatalErrorActivating)), "Fatal error occurred while activating {TypeFullName}."); + // Critical messages + private static readonly Action FatalErrorActivatingDefinition = LoggerMessage.Define(LogLevel.Critical, new EventId(3000, nameof(FatalErrorActivating)), "Fatal error occurred while activating {TypeFullName}."); - /// - /// Logs that RunAsync has started. - /// - /// The logger instance. - public static void RunAsyncStarted(this IDecorator logger) - { - RunAsyncStartedDefinition(logger.Inner, null); - } + /// + /// Logs that RunAsync has started. + /// + /// The logger instance. + public static void RunAsyncStarted(this IDecorator logger) + { + RunAsyncStartedDefinition(logger.Inner, null); + } - /// - /// Logs that RunAsync ended prematurely. - /// - /// The logger instance. - public static void RunAsyncPrematureEnd(this IDecorator logger) - { - RunAsyncPrematureEndDefinition(logger.Inner, null); - } + /// + /// Logs that RunAsync ended prematurely. + /// + /// The logger instance. + public static void RunAsyncPrematureEnd(this IDecorator logger) + { + RunAsyncPrematureEndDefinition(logger.Inner, null); + } - /// - /// Logs that RunAsync completed successfully. - /// - /// The logger instance. - public static void RunAsyncCompleted(this IDecorator logger) - { - RunAsyncCompletedDefinition(logger.Inner, null); - } + /// + /// Logs that RunAsync completed successfully. + /// + /// The logger instance. + public static void RunAsyncCompleted(this IDecorator logger) + { + RunAsyncCompletedDefinition(logger.Inner, null); + } - /// - /// Logs an inability to activate the specified type. - /// - /// The logger instance. - /// The full name of the type that couldn't be activated. - public static void UnableToActivateInstance(this IDecorator logger, string typeFullName) - { - UnableToActivateInstanceDefinition(logger.Inner, typeFullName, null); - } + /// + /// Logs an inability to activate the specified type. + /// + /// The logger instance. + /// The full name of the type that couldn't be activated. + public static void UnableToActivateInstance(this IDecorator logger, string typeFullName) + { + UnableToActivateInstanceDefinition(logger.Inner, typeFullName, null); + } - /// - /// Logs a fatal error that occurred while activating a type. - /// - /// The logger instance. - /// The full name of the type being activated. - /// The exception that occurred. - public static void FatalErrorActivating(this IDecorator logger, string typeFullName, Exception exception) - { - FatalErrorActivatingDefinition(logger.Inner, typeFullName, exception); - } + /// + /// Logs a fatal error that occurred while activating a type. + /// + /// The logger instance. + /// The full name of the type being activated. + /// The exception that occurred. + public static void FatalErrorActivating(this IDecorator logger, string typeFullName, Exception exception) + { + FatalErrorActivatingDefinition(logger.Inner, typeFullName, exception); } } diff --git a/src/Codebelt.Bootstrapper/CommandLineContext.cs b/src/Codebelt.Bootstrapper/CommandLineContext.cs index 52057d0..06a0118 100644 --- a/src/Codebelt.Bootstrapper/CommandLineContext.cs +++ b/src/Codebelt.Bootstrapper/CommandLineContext.cs @@ -1,4 +1,4 @@ -namespace Codebelt.Bootstrapper; +namespace Codebelt.Bootstrapper; /// /// Represents the command-line arguments available to a bootstrapper. diff --git a/src/Codebelt.Bootstrapper/GlobalSuppressions.cs b/src/Codebelt.Bootstrapper/GlobalSuppressions.cs index 92def2e..0a10850 100644 --- a/src/Codebelt.Bootstrapper/GlobalSuppressions.cs +++ b/src/Codebelt.Bootstrapper/GlobalSuppressions.cs @@ -1,4 +1,4 @@ -// This file is used by Code Analysis to maintain SuppressMessage +// This file is used by Code Analysis to maintain SuppressMessage // attributes that are applied to this project. // Project-level suppressions either have no target or are given // a specific target and scoped to a namespace, type, member, etc. diff --git a/src/Codebelt.Bootstrapper/HostApplicationBuilderExtensions.cs b/src/Codebelt.Bootstrapper/HostApplicationBuilderExtensions.cs index 943dab5..e9c47bf 100644 --- a/src/Codebelt.Bootstrapper/HostApplicationBuilderExtensions.cs +++ b/src/Codebelt.Bootstrapper/HostApplicationBuilderExtensions.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting.Internal; @@ -6,52 +6,51 @@ using System.Reflection; using Microsoft.Extensions.Configuration; -namespace Codebelt.Bootstrapper +namespace Codebelt.Bootstrapper; + +/// +/// Extension methods for the . +/// +public static class HostApplicationBuilderExtensions { /// - /// Extension methods for the . + /// Listens for Ctrl+C or SIGTERM and calls to start the shutdown process. + /// + /// The to configure. + /// The same instance of the for chaining. + /// Complements the default implementation of . + public static IHostApplicationBuilder UseBootstrapperLifetime(this IHostApplicationBuilder hostBuilder) + { + hostBuilder.Services.Replace(ServiceDescriptor.Singleton()); + hostBuilder.Services.AddSingleton(provider => provider.GetRequiredService() as BootstrapperLifetime); + return hostBuilder; + } + + /// + /// Adds conventional environment defaults for local development. /// - public static class HostApplicationBuilderExtensions + /// The to configure. + /// The same instance of the for chaining. + /// + /// When the current environment is local development, this method attempts to resolve the application assembly from + /// and adds user secrets to . If the application assembly cannot be resolved, the operation is ignored. + /// + public static IHostApplicationBuilder UseBootstrapperEnvironmentDefaults(this IHostApplicationBuilder hostBuilder) { - /// - /// Listens for Ctrl+C or SIGTERM and calls to start the shutdown process. - /// - /// The to configure. - /// The same instance of the for chaining. - /// Complements the default implementation of . - public static IHostApplicationBuilder UseBootstrapperLifetime(this IHostApplicationBuilder hostBuilder) + if (!hostBuilder.Environment.IsLocalDevelopment()) { return hostBuilder; } + if (hostBuilder.Environment.ApplicationName is not { Length: > 0 } applicationName) { return hostBuilder; } + var reloadOnChange = hostBuilder.Configuration.GetValue("hostBuilder:reloadConfigOnChange", defaultValue: true); + + try { - hostBuilder.Services.Replace(ServiceDescriptor.Singleton()); - hostBuilder.Services.AddSingleton(provider => provider.GetRequiredService() as BootstrapperLifetime); - return hostBuilder; + var appAssembly = Assembly.Load(new AssemblyName(applicationName)); + hostBuilder.Configuration.AddUserSecrets(appAssembly, optional: true, reloadOnChange: reloadOnChange); } - - /// - /// Adds conventional environment defaults for local development. - /// - /// The to configure. - /// The same instance of the for chaining. - /// - /// When the current environment is local development, this method attempts to resolve the application assembly from - /// and adds user secrets to . If the application assembly cannot be resolved, the operation is ignored. - /// - public static IHostApplicationBuilder UseBootstrapperEnvironmentDefaults(this IHostApplicationBuilder hostBuilder) + catch (FileNotFoundException) { - if (!hostBuilder.Environment.IsLocalDevelopment()) { return hostBuilder; } - if (hostBuilder.Environment.ApplicationName is not { Length: > 0 } applicationName) { return hostBuilder; } - var reloadOnChange = hostBuilder.Configuration.GetValue("hostBuilder:reloadConfigOnChange", defaultValue: true); - - try - { - var appAssembly = Assembly.Load(new AssemblyName(applicationName)); - hostBuilder.Configuration.AddUserSecrets(appAssembly, optional: true, reloadOnChange: reloadOnChange); - } - catch (FileNotFoundException) - { - // The assembly cannot be found, so just skip it. - } - - return hostBuilder; + // The assembly cannot be found, so just skip it. } + + return hostBuilder; } } diff --git a/src/Codebelt.Bootstrapper/HostBuilderExtensions.cs b/src/Codebelt.Bootstrapper/HostBuilderExtensions.cs index 4440eea..af1aae7 100644 --- a/src/Codebelt.Bootstrapper/HostBuilderExtensions.cs +++ b/src/Codebelt.Bootstrapper/HostBuilderExtensions.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; @@ -6,59 +6,58 @@ using System.IO; using System.Reflection; -namespace Codebelt.Bootstrapper +namespace Codebelt.Bootstrapper; + +/// +/// Extension methods for the . +/// +public static class HostBuilderExtensions { /// - /// Extension methods for the . + /// Listens for Ctrl+C or SIGTERM and calls to start the shutdown process. /// - public static class HostBuilderExtensions + /// The to configure. + /// The same instance of the for chaining. + /// Complements the default implementation of . + public static IHostBuilder UseBootstrapperLifetime(this IHostBuilder hostBuilder) { - /// - /// Listens for Ctrl+C or SIGTERM and calls to start the shutdown process. - /// - /// The to configure. - /// The same instance of the for chaining. - /// Complements the default implementation of . - public static IHostBuilder UseBootstrapperLifetime(this IHostBuilder hostBuilder) + return hostBuilder.ConfigureServices(services => { - return hostBuilder.ConfigureServices(services => - { - services.Replace(ServiceDescriptor.Singleton()); - services.AddSingleton(provider => provider.GetRequiredService() as BootstrapperLifetime); - }); - } + services.Replace(ServiceDescriptor.Singleton()); + services.AddSingleton(provider => provider.GetRequiredService() as BootstrapperLifetime); + }); + } - /// - /// Provides an implementation of a conventional based . - /// - /// The to configure. - /// The same instance of the for chaining. - public static IHostBuilder UseBootstrapperStartup(this IHostBuilder hostBuilder) where TStartup : StartupRoot + /// + /// Provides an implementation of a conventional based . + /// + /// The to configure. + /// The same instance of the for chaining. + public static IHostBuilder UseBootstrapperStartup(this IHostBuilder hostBuilder) where TStartup : StartupRoot + { + return hostBuilder.ConfigureServices((context, services) => { - return hostBuilder.ConfigureServices((context, services) => - { - services.AddSingleton>(new StartupFactory(services, context.Configuration, context.HostingEnvironment)); - }); - } + services.AddSingleton>(new StartupFactory(services, context.Configuration, context.HostingEnvironment)); + }); + } - /// - /// Adds conventional environment defaults for local development. - /// - /// The type of the startup class used to resolve user secrets. - /// The to configure. - /// The same instance of the for chaining. - /// - /// When the current environment is local development, this method adds user secrets for to the application configuration. - /// - public static IHostBuilder UseBootstrapperEnvironmentDefaults(this IHostBuilder hostBuilder) where TStartup : StartupRoot + /// + /// Adds conventional environment defaults for local development. + /// + /// The type of the startup class used to resolve user secrets. + /// The to configure. + /// The same instance of the for chaining. + /// + /// When the current environment is local development, this method adds user secrets for to the application configuration. + /// + public static IHostBuilder UseBootstrapperEnvironmentDefaults(this IHostBuilder hostBuilder) where TStartup : StartupRoot + { + return hostBuilder.ConfigureAppConfiguration((context, builder) => { - return hostBuilder.ConfigureAppConfiguration((context, builder) => - { - var environment = context.HostingEnvironment; - if (!environment.IsLocalDevelopment()) { return; } - var reloadOnChange = context.Configuration.GetValue("hostBuilder:reloadConfigOnChange", defaultValue: true); - builder.AddUserSecrets(optional: true, reloadOnChange: reloadOnChange); - }); - } + var environment = context.HostingEnvironment; + if (!environment.IsLocalDevelopment()) { return; } + var reloadOnChange = context.Configuration.GetValue("hostBuilder:reloadConfigOnChange", defaultValue: true); + builder.AddUserSecrets(optional: true, reloadOnChange: reloadOnChange); + }); } } diff --git a/src/Codebelt.Bootstrapper/HostEnvironmentExtensions.cs b/src/Codebelt.Bootstrapper/HostEnvironmentExtensions.cs index 1d0bdf0..8d98cff 100644 --- a/src/Codebelt.Bootstrapper/HostEnvironmentExtensions.cs +++ b/src/Codebelt.Bootstrapper/HostEnvironmentExtensions.cs @@ -1,14 +1,13 @@ -using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper +namespace Codebelt.Bootstrapper; + +internal static class HostEnvironmentExtensions { - internal static class HostEnvironmentExtensions - { - private const string LocalDevelopment = "LocalDevelopment"; + private const string LocalDevelopment = "LocalDevelopment"; - internal static bool IsLocalDevelopment(this IHostEnvironment environment) - { - return environment.IsEnvironment(LocalDevelopment); - } + internal static bool IsLocalDevelopment(this IHostEnvironment environment) + { + return environment.IsEnvironment(LocalDevelopment); } } diff --git a/src/Codebelt.Bootstrapper/IHostLifetimeEvents.cs b/src/Codebelt.Bootstrapper/IHostLifetimeEvents.cs index e79ace0..fd4b235 100644 --- a/src/Codebelt.Bootstrapper/IHostLifetimeEvents.cs +++ b/src/Codebelt.Bootstrapper/IHostLifetimeEvents.cs @@ -1,25 +1,24 @@ -using System; +using System; -namespace Codebelt.Bootstrapper +namespace Codebelt.Bootstrapper; + +/// +/// Provides a convenient way to be notified of host lifetime events. +/// +public interface IHostLifetimeEvents { /// - /// Provides a convenient way to be notified of host lifetime events. + /// Triggered when the application host has fully started. /// - public interface IHostLifetimeEvents - { - /// - /// Triggered when the application host has fully started. - /// - Action OnApplicationStartedCallback { get; set; } + Action OnApplicationStartedCallback { get; set; } - /// - /// Triggered when the application host is starting a graceful shutdown. - /// - Action OnApplicationStoppingCallback { get; set; } + /// + /// Triggered when the application host is starting a graceful shutdown. + /// + Action OnApplicationStoppingCallback { get; set; } - /// - /// Triggered when the application host has completed a graceful shutdown. - /// - Action OnApplicationStoppedCallback { get; set; } - } + /// + /// Triggered when the application host has completed a graceful shutdown. + /// + Action OnApplicationStoppedCallback { get; set; } } diff --git a/src/Codebelt.Bootstrapper/IStartupFactory.cs b/src/Codebelt.Bootstrapper/IStartupFactory.cs index 158e9a6..6285af3 100644 --- a/src/Codebelt.Bootstrapper/IStartupFactory.cs +++ b/src/Codebelt.Bootstrapper/IStartupFactory.cs @@ -1,15 +1,14 @@ -namespace Codebelt.Bootstrapper +namespace Codebelt.Bootstrapper; + +/// +/// Provides an interface for initializing services and middleware used by an application. +/// +/// The type to create. +public interface IStartupFactory where TStartup : StartupRoot { /// - /// Provides an interface for initializing services and middleware used by an application. + /// Provides access to an instance of the specified . /// - /// The type to create. - public interface IStartupFactory where TStartup : StartupRoot - { - /// - /// Provides access to an instance of the specified . - /// - /// A reference to the object of type . - TStartup Instance { get; } - } + /// A reference to the object of type . + TStartup Instance { get; } } diff --git a/src/Codebelt.Bootstrapper/ProgramRoot.cs b/src/Codebelt.Bootstrapper/ProgramRoot.cs index 772b8fd..639d542 100644 --- a/src/Codebelt.Bootstrapper/ProgramRoot.cs +++ b/src/Codebelt.Bootstrapper/ProgramRoot.cs @@ -1,18 +1,17 @@ -namespace Codebelt.Bootstrapper +namespace Codebelt.Bootstrapper; + +/// +/// The base entry point of an application responsible for registering its partner. +/// +/// The type containing the startup methods for the application. +/// +public abstract class ProgramRoot : ProgramRoot where TStartup : StartupRoot { - /// - /// The base entry point of an application responsible for registering its partner. - /// - /// The type containing the startup methods for the application. - /// - public abstract class ProgramRoot : ProgramRoot where TStartup : StartupRoot - { - } +} - /// - /// The base entry point of an application. - /// - public abstract class ProgramRoot - { - } +/// +/// The base entry point of an application. +/// +public abstract class ProgramRoot +{ } diff --git a/src/Codebelt.Bootstrapper/Properties/AssemblyInfo.cs b/src/Codebelt.Bootstrapper/Properties/AssemblyInfo.cs index 33d2f51..bcc726c 100644 --- a/src/Codebelt.Bootstrapper/Properties/AssemblyInfo.cs +++ b/src/Codebelt.Bootstrapper/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; [assembly: ComVisible(false)] -[assembly: Guid("5f17df4c-b610-467d-b211-f88ea40adba6")] \ No newline at end of file +[assembly: Guid("5f17df4c-b610-467d-b211-f88ea40adba6")] diff --git a/src/Codebelt.Bootstrapper/StartupFactory.cs b/src/Codebelt.Bootstrapper/StartupFactory.cs index bd31b3f..e2b216c 100644 --- a/src/Codebelt.Bootstrapper/StartupFactory.cs +++ b/src/Codebelt.Bootstrapper/StartupFactory.cs @@ -1,34 +1,33 @@ -using System; +using System; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper +namespace Codebelt.Bootstrapper; + +/// +/// The default implementation of . +/// +/// +public class StartupFactory : IStartupFactory where TStartup : StartupRoot { /// - /// The default implementation of . + /// Initializes a new instance of the class. /// - /// - public class StartupFactory : IStartupFactory where TStartup : StartupRoot + /// The dependency injected . + /// The dependency injected . + /// The dependency injected . + public StartupFactory(IServiceCollection services, IConfiguration configuration, IHostEnvironment environment) { - /// - /// Initializes a new instance of the class. - /// - /// The dependency injected . - /// The dependency injected . - /// The dependency injected . - public StartupFactory(IServiceCollection services, IConfiguration configuration, IHostEnvironment environment) - { - var startup = (TStartup)Activator.CreateInstance(typeof(TStartup), configuration, environment); - startup?.ConfigureServices(services); - Instance = startup; - - } + var startup = (TStartup)Activator.CreateInstance(typeof(TStartup), configuration, environment); + startup?.ConfigureServices(services); + Instance = startup; - /// - /// Provides access to an instance of the specified . - /// - /// A reference to the object of type . - public TStartup Instance { get; } } + + /// + /// Provides access to an instance of the specified . + /// + /// A reference to the object of type . + public TStartup Instance { get; } } diff --git a/src/Codebelt.Bootstrapper/StartupRoot.cs b/src/Codebelt.Bootstrapper/StartupRoot.cs index 7f6af9d..f8f786b 100644 --- a/src/Codebelt.Bootstrapper/StartupRoot.cs +++ b/src/Codebelt.Bootstrapper/StartupRoot.cs @@ -1,41 +1,40 @@ -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper +namespace Codebelt.Bootstrapper; + +/// +/// Provides the base class of a conventional based Startup class. +/// +public abstract class StartupRoot { /// - /// Provides the base class of a conventional based Startup class. + /// Initializes a new instance of the class. /// - public abstract class StartupRoot + /// The dependency injected . + /// The dependency injected . + protected StartupRoot(IConfiguration configuration, IHostEnvironment environment) { - /// - /// Initializes a new instance of the class. - /// - /// The dependency injected . - /// The dependency injected . - protected StartupRoot(IConfiguration configuration, IHostEnvironment environment) - { - Configuration = configuration; - Environment = environment; - } + Configuration = configuration; + Environment = environment; + } - /// - /// Gets the of this instance. - /// - /// The of this instance. - protected IConfiguration Configuration { get; } + /// + /// Gets the of this instance. + /// + /// The of this instance. + protected IConfiguration Configuration { get; } - /// - /// Gets the of this instance. - /// - /// The of this instance. - protected IHostEnvironment Environment { get; } + /// + /// Gets the of this instance. + /// + /// The of this instance. + protected IHostEnvironment Environment { get; } - /// - /// Register services into the . - /// - /// The to add the services to. - public abstract void ConfigureServices(IServiceCollection services); - } + /// + /// Register services into the . + /// + /// The to add the services to. + public abstract void ConfigureServices(IServiceCollection services); } diff --git a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/NullProgramFactory.cs b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/NullProgramFactory.cs index 3379a3c..a26b578 100644 --- a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/NullProgramFactory.cs +++ b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/NullProgramFactory.cs @@ -1,14 +1,13 @@ -namespace Codebelt.Bootstrapper.Console.Assets +namespace Codebelt.Bootstrapper.Console.Assets; + +/// +/// A test implementation of that returns null to simulate program activation failure. +/// +public class NullProgramFactory : IProgramFactory { /// - /// A test implementation of that returns null to simulate program activation failure. + /// Gets the instance of the program, which is always null for testing purposes. /// - public class NullProgramFactory : IProgramFactory - { - /// - /// Gets the instance of the program, which is always null for testing purposes. - /// - /// Always returns null. - public MinimalConsoleProgram Instance => null; - } + /// Always returns null. + public MinimalConsoleProgram Instance => null; } diff --git a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/NullStartupFactory.cs b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/NullStartupFactory.cs index d0b2bbb..93ccf56 100644 --- a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/NullStartupFactory.cs +++ b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/NullStartupFactory.cs @@ -1,7 +1,6 @@ -namespace Codebelt.Bootstrapper.Console.Assets +namespace Codebelt.Bootstrapper.Console.Assets; + +public class NullStartupFactory : global::Codebelt.Bootstrapper.IStartupFactory where TStartup : global::Codebelt.Bootstrapper.StartupRoot { - public class NullStartupFactory : global::Codebelt.Bootstrapper.IStartupFactory where TStartup : global::Codebelt.Bootstrapper.StartupRoot - { - public TStartup Instance => null; - } + public TStartup Instance => null; } diff --git a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestConsoleProgram.cs b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestConsoleProgram.cs index 2c5e19b..e22320a 100644 --- a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestConsoleProgram.cs +++ b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestConsoleProgram.cs @@ -1,9 +1,8 @@ using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Console.Assets +namespace Codebelt.Bootstrapper.Console.Assets; + +public class TestConsoleProgram : ConsoleProgram { - public class TestConsoleProgram : ConsoleProgram - { - public static IHostBuilder CreateHostBuilderAccessor(string[] args) => CreateHostBuilder(args); - } + public static IHostBuilder CreateHostBuilderAccessor(string[] args) => CreateHostBuilder(args); } diff --git a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestConsoleStartup.cs b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestConsoleStartup.cs index df3c4df..4e92a97 100644 --- a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestConsoleStartup.cs +++ b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestConsoleStartup.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Configuration; @@ -6,23 +6,22 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -namespace Codebelt.Bootstrapper.Console.Assets +namespace Codebelt.Bootstrapper.Console.Assets; + +public class TestConsoleStartup : ConsoleStartup { - public class TestConsoleStartup : ConsoleStartup + public TestConsoleStartup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) { - public TestConsoleStartup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) - { - } + } - public override void ConfigureServices(IServiceCollection services) - { - } + public override void ConfigureServices(IServiceCollection services) + { + } - public override Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) - { - var logger = serviceProvider.GetRequiredService>(); - logger.LogTrace($"Inside {nameof(RunAsync)} of {nameof(TestConsoleStartup)}."); - return Task.CompletedTask; - } + public override Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) + { + var logger = serviceProvider.GetRequiredService>(); + logger.LogTrace($"Inside {nameof(RunAsync)} of {nameof(TestConsoleStartup)}."); + return Task.CompletedTask; } } diff --git a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestConsoleStartupWithException.cs b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestConsoleStartupWithException.cs index 7f6df95..e5575c6 100644 --- a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestConsoleStartupWithException.cs +++ b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestConsoleStartupWithException.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Configuration; @@ -6,44 +6,43 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -namespace Codebelt.Bootstrapper.Console.Assets +namespace Codebelt.Bootstrapper.Console.Assets; + +/// +/// Test console startup class that simulates an exception scenario during RunAsync execution. +/// +public class TestConsoleStartupWithException : ConsoleStartup { /// - /// Test console startup class that simulates an exception scenario during RunAsync execution. + /// Initializes a new instance of the class. /// - public class TestConsoleStartupWithException : ConsoleStartup + /// The dependency injected . + /// The dependency injected . + public TestConsoleStartupWithException(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) { - /// - /// Initializes a new instance of the class. - /// - /// The dependency injected . - /// The dependency injected . - public TestConsoleStartupWithException(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) - { - } + } - /// - /// Configures services for the console application. - /// - /// The to add services to. - public override void ConfigureServices(IServiceCollection services) - { - } + /// + /// Configures services for the console application. + /// + /// The to add services to. + public override void ConfigureServices(IServiceCollection services) + { + } - /// - /// Executes the console application logic and throws an exception to simulate an error scenario. - /// - /// The to retrieve services from. - /// Indicates that the run has been aborted. - /// A that represents the asynchronous operation. - /// Thrown intentionally to simulate an error during execution. - public override Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) - { - var logger = serviceProvider.GetRequiredService>(); - logger.LogTrace($"Inside {nameof(RunAsync)} of {nameof(TestConsoleStartupWithException)}."); + /// + /// Executes the console application logic and throws an exception to simulate an error scenario. + /// + /// The to retrieve services from. + /// Indicates that the run has been aborted. + /// A that represents the asynchronous operation. + /// Thrown intentionally to simulate an error during execution. + public override Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) + { + var logger = serviceProvider.GetRequiredService>(); + logger.LogTrace($"Inside {nameof(RunAsync)} of {nameof(TestConsoleStartupWithException)}."); - // Throw exception to simulate fatal error during execution - throw new InvalidOperationException("Simulated exception in RunAsync for testing purposes."); - } + // Throw exception to simulate fatal error during execution + throw new InvalidOperationException("Simulated exception in RunAsync for testing purposes."); } } diff --git a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestConsoleStartupWithPrematureEnd.cs b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestConsoleStartupWithPrematureEnd.cs index 17a4edb..caf3304 100644 --- a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestConsoleStartupWithPrematureEnd.cs +++ b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestConsoleStartupWithPrematureEnd.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Configuration; @@ -6,48 +6,47 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -namespace Codebelt.Bootstrapper.Console.Assets +namespace Codebelt.Bootstrapper.Console.Assets; + +/// +/// Test console startup class that simulates a premature end scenario by stopping the application before RunAsync completes. +/// +public class TestConsoleStartupWithPrematureEnd : ConsoleStartup { /// - /// Test console startup class that simulates a premature end scenario by stopping the application before RunAsync completes. + /// Initializes a new instance of the class. /// - public class TestConsoleStartupWithPrematureEnd : ConsoleStartup + /// The dependency injected . + /// The dependency injected . + public TestConsoleStartupWithPrematureEnd(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) { - /// - /// Initializes a new instance of the class. - /// - /// The dependency injected . - /// The dependency injected . - public TestConsoleStartupWithPrematureEnd(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) - { - } + } - /// - /// Configures services for the console application. - /// - /// The to add services to. - public override void ConfigureServices(IServiceCollection services) - { - } + /// + /// Configures services for the console application. + /// + /// The to add services to. + public override void ConfigureServices(IServiceCollection services) + { + } - /// - /// Executes the console application logic with a premature end by requesting application stop. - /// - /// The to retrieve services from. - /// Indicates that the run has been aborted. - /// A that represents the asynchronous operation. - public override async Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) - { - var logger = serviceProvider.GetRequiredService>(); - var lifetime = serviceProvider.GetRequiredService(); + /// + /// Executes the console application logic with a premature end by requesting application stop. + /// + /// The to retrieve services from. + /// Indicates that the run has been aborted. + /// A that represents the asynchronous operation. + public override async Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) + { + var logger = serviceProvider.GetRequiredService>(); + var lifetime = serviceProvider.GetRequiredService(); - logger.LogTrace($"Inside {nameof(RunAsync)} of {nameof(TestConsoleStartupWithPrematureEnd)}."); + logger.LogTrace($"Inside {nameof(RunAsync)} of {nameof(TestConsoleStartupWithPrematureEnd)}."); - // Simulate premature end by stopping the application immediately - lifetime.StopApplication(); + // Simulate premature end by stopping the application immediately + lifetime.StopApplication(); - // This delay will never complete because the application stops - await Task.Delay(Timeout.Infinite, cancellationToken); - } + // This delay will never complete because the application stops + await Task.Delay(Timeout.Infinite, cancellationToken); } } diff --git a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestGenericMinimalConsoleProgram.cs b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestGenericMinimalConsoleProgram.cs index 3d4f000..d5e9956 100644 --- a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestGenericMinimalConsoleProgram.cs +++ b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestGenericMinimalConsoleProgram.cs @@ -3,15 +3,14 @@ using System.Threading.Tasks; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Console.Assets +namespace Codebelt.Bootstrapper.Console.Assets; + +public class TestGenericMinimalConsoleProgram : MinimalConsoleProgram { - public class TestGenericMinimalConsoleProgram : MinimalConsoleProgram - { - public static HostApplicationBuilder CreateHostBuilderAccessor(string[] args) => CreateHostBuilder(args); + public static HostApplicationBuilder CreateHostBuilderAccessor(string[] args) => CreateHostBuilder(args); - public override Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) - { - return Task.CompletedTask; - } + public override Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) + { + return Task.CompletedTask; } } diff --git a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestHostFixture.cs b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestHostFixture.cs index e7571fb..d6f2963 100644 --- a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestHostFixture.cs +++ b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestHostFixture.cs @@ -1,35 +1,34 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Codebelt.Extensions.Xunit; using Codebelt.Extensions.Xunit.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Console.Assets +namespace Codebelt.Bootstrapper.Console.Assets; + +public class TestHostFixture : ManagedHostFixture { - public class TestHostFixture : ManagedHostFixture + public override void ConfigureHost(Test hostTest) { - public override void ConfigureHost(Test hostTest) - { - var hb = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder() - .ConfigureAppConfiguration((context, config) => - { - ConfigureCallback(config.Build(), context.HostingEnvironment); - }) - .ConfigureServices((context, services) => - { - Configuration = context.Configuration; - Environment = context.HostingEnvironment; - ConfigureServicesCallback(services); - }) - .ConfigureHostConfiguration(builder => + var hb = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder() + .ConfigureAppConfiguration((context, config) => + { + ConfigureCallback(config.Build(), context.HostingEnvironment); + }) + .ConfigureServices((context, services) => + { + Configuration = context.Configuration; + Environment = context.HostingEnvironment; + ConfigureServicesCallback(services); + }) + .ConfigureHostConfiguration(builder => + { + builder.AddInMemoryCollection(new Dictionary { - builder.AddInMemoryCollection(new Dictionary - { - { HostDefaults.ApplicationKey, hostTest.CallerType.Assembly.GetName().Name } - }); + { HostDefaults.ApplicationKey, hostTest.CallerType.Assembly.GetName().Name } }); - ConfigureHostCallback(hb); - Host = hb.Build(); - } + }); + ConfigureHostCallback(hb); + Host = hb.Build(); } } diff --git a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestMinimalConsoleProgram.cs b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestMinimalConsoleProgram.cs index f1b209a..0d89048 100644 --- a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestMinimalConsoleProgram.cs +++ b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestMinimalConsoleProgram.cs @@ -1,21 +1,20 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Console.Assets +namespace Codebelt.Bootstrapper.Console.Assets; + +public class TestMinimalConsoleProgram : MinimalConsoleProgram { - public class TestMinimalConsoleProgram : MinimalConsoleProgram - { - public static HostApplicationBuilder CreateHostBuilderAccessor(string[] args) => CreateHostBuilder(args); + public static HostApplicationBuilder CreateHostBuilderAccessor(string[] args) => CreateHostBuilder(args); - public override Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) - { - var logger = serviceProvider.GetRequiredService>(); - logger.LogTrace($"Inside {nameof(RunAsync)} of {nameof(TestMinimalConsoleProgram)}."); - return Task.CompletedTask; - } + public override Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) + { + var logger = serviceProvider.GetRequiredService>(); + logger.LogTrace($"Inside {nameof(RunAsync)} of {nameof(TestMinimalConsoleProgram)}."); + return Task.CompletedTask; } } diff --git a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestMinimalConsoleProgramWithException.cs b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestMinimalConsoleProgramWithException.cs index 835181a..116f6d4 100644 --- a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestMinimalConsoleProgramWithException.cs +++ b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestMinimalConsoleProgramWithException.cs @@ -1,30 +1,29 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -namespace Codebelt.Bootstrapper.Console.Assets +namespace Codebelt.Bootstrapper.Console.Assets; + +/// +/// Test minimal console program that simulates an exception scenario during RunAsync execution. +/// +public class TestMinimalConsoleProgramWithException : MinimalConsoleProgram { /// - /// Test minimal console program that simulates an exception scenario during RunAsync execution. + /// Executes the console application logic and throws an exception to simulate an error scenario. /// - public class TestMinimalConsoleProgramWithException : MinimalConsoleProgram + /// The to retrieve services from. + /// Indicates that the run has been aborted. + /// A that represents the asynchronous operation. + /// Thrown intentionally to simulate an error during execution. + public override Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) { - /// - /// Executes the console application logic and throws an exception to simulate an error scenario. - /// - /// The to retrieve services from. - /// Indicates that the run has been aborted. - /// A that represents the asynchronous operation. - /// Thrown intentionally to simulate an error during execution. - public override Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) - { - var logger = serviceProvider.GetRequiredService>(); - logger.LogTrace($"Inside {nameof(RunAsync)} of {nameof(TestMinimalConsoleProgramWithException)}."); + var logger = serviceProvider.GetRequiredService>(); + logger.LogTrace($"Inside {nameof(RunAsync)} of {nameof(TestMinimalConsoleProgramWithException)}."); - // Throw exception to simulate fatal error during execution - throw new InvalidOperationException("Simulated exception in RunAsync for testing purposes."); - } + // Throw exception to simulate fatal error during execution + throw new InvalidOperationException("Simulated exception in RunAsync for testing purposes."); } } diff --git a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestMinimalConsoleProgramWithPrematureEnd.cs b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestMinimalConsoleProgramWithPrematureEnd.cs index 2078644..93f6aeb 100644 --- a/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestMinimalConsoleProgramWithPrematureEnd.cs +++ b/test/Codebelt.Bootstrapper.Console.FunctionalTests/Assets/TestMinimalConsoleProgramWithPrematureEnd.cs @@ -1,35 +1,34 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -namespace Codebelt.Bootstrapper.Console.Assets +namespace Codebelt.Bootstrapper.Console.Assets; + +/// +/// Test minimal console program that simulates a premature end scenario by stopping the application before RunAsync completes. +/// +public class TestMinimalConsoleProgramWithPrematureEnd : MinimalConsoleProgram { /// - /// Test minimal console program that simulates a premature end scenario by stopping the application before RunAsync completes. + /// Executes the console application logic with a premature end by requesting application stop. /// - public class TestMinimalConsoleProgramWithPrematureEnd : MinimalConsoleProgram + /// The to retrieve services from. + /// Indicates that the run has been aborted. + /// A that represents the asynchronous operation. + public override async Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) { - /// - /// Executes the console application logic with a premature end by requesting application stop. - /// - /// The to retrieve services from. - /// Indicates that the run has been aborted. - /// A that represents the asynchronous operation. - public override async Task RunAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) - { - var logger = serviceProvider.GetRequiredService>(); - var lifetime = serviceProvider.GetRequiredService(); + var logger = serviceProvider.GetRequiredService>(); + var lifetime = serviceProvider.GetRequiredService(); - logger.LogTrace($"Inside {nameof(RunAsync)} of {nameof(TestMinimalConsoleProgramWithPrematureEnd)}."); + logger.LogTrace($"Inside {nameof(RunAsync)} of {nameof(TestMinimalConsoleProgramWithPrematureEnd)}."); - // Simulate premature end by stopping the application immediately - lifetime.StopApplication(); + // Simulate premature end by stopping the application immediately + lifetime.StopApplication(); - // This delay will never complete because the application stops - await Task.Delay(Timeout.Infinite, cancellationToken); - } + // This delay will never complete because the application stops + await Task.Delay(Timeout.Infinite, cancellationToken); } } diff --git a/test/Codebelt.Bootstrapper.Console.FunctionalTests/ConsoleHostedServiceTest.cs b/test/Codebelt.Bootstrapper.Console.FunctionalTests/ConsoleHostedServiceTest.cs index 2621c32..dfe32f5 100644 --- a/test/Codebelt.Bootstrapper.Console.FunctionalTests/ConsoleHostedServiceTest.cs +++ b/test/Codebelt.Bootstrapper.Console.FunctionalTests/ConsoleHostedServiceTest.cs @@ -1,4 +1,4 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Codebelt.Bootstrapper.Console.Assets; using Codebelt.Extensions.Xunit; using Codebelt.Extensions.Xunit.Hosting; @@ -7,269 +7,268 @@ using Microsoft.Extensions.Logging; using Xunit; -namespace Codebelt.Bootstrapper.Console +namespace Codebelt.Bootstrapper.Console; + +public class ConsoleHostedServiceTest : Test { - public class ConsoleHostedServiceTest : Test + public ConsoleHostedServiceTest(ITestOutputHelper output) : base(output) { - public ConsoleHostedServiceTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public async Task StartAsync_ShouldInvokeRunAsyncInTestConsoleStartup() + [Fact] + public async Task StartAsync_ShouldInvokeRunAsyncInTestConsoleStartup() + { + await using var test = HostTestFactory.Create(services => { - await using var test = HostTestFactory.Create(services => - { - services.AddXunitTestLogging(TestOutput); - }, hb => - { - hb.UseBootstrapperLifetime() - .UseBootstrapperStartup() - .UseConsoleStartup(); - }); - - await test.Host.WaitForShutdownAsync(); - - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.Collection(loggerStore.Query(), - entry => Assert.Equal("Information: RunAsync started.", entry.Message), - entry => Assert.Equal("Trace: Inside RunAsync of TestConsoleStartup.", entry.Message), - entry => Assert.Equal("Information: RunAsync completed successfully.", entry.Message) - ); - } + services.AddXunitTestLogging(TestOutput); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseBootstrapperStartup() + .UseConsoleStartup(); + }); + + await test.Host.WaitForShutdownAsync(); + + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.Collection(loggerStore.Query(), + entry => Assert.Equal("Information: RunAsync started.", entry.Message), + entry => Assert.Equal("Trace: Inside RunAsync of TestConsoleStartup.", entry.Message), + entry => Assert.Equal("Information: RunAsync completed successfully.", entry.Message) + ); + } - [Fact] - public async Task StartAsync_ShouldSuppressStatusMessages_WhenSuppressStatusMessagesIsTrue() + [Fact] + public async Task StartAsync_ShouldSuppressStatusMessages_WhenSuppressStatusMessagesIsTrue() + { + await using var test = HostTestFactory.Create(services => { - await using var test = HostTestFactory.Create(services => - { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = true; - }); - }, hb => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - hb.UseBootstrapperLifetime() - .UseBootstrapperStartup() - .UseConsoleStartup(); + options.SuppressStatusMessages = true; }); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseBootstrapperStartup() + .UseConsoleStartup(); + }); - await test.Host.WaitForShutdownAsync(); + await test.Host.WaitForShutdownAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.Collection(loggerStore.Query(), - entry => Assert.Equal("Trace: Inside RunAsync of TestConsoleStartup.", entry.Message) - ); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.Collection(loggerStore.Query(), + entry => Assert.Equal("Trace: Inside RunAsync of TestConsoleStartup.", entry.Message) + ); + } - [Fact] - public async Task StartAsync_ShouldLogRunAsyncStarted_WhenSuppressStatusMessagesIsFalse() + [Fact] + public async Task StartAsync_ShouldLogRunAsyncStarted_WhenSuppressStatusMessagesIsFalse() + { + await using var test = HostTestFactory.Create(services => { - await using var test = HostTestFactory.Create(services => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = false; - }); - }, hb => - { - hb.UseBootstrapperLifetime() - .UseBootstrapperStartup() - .UseConsoleStartup(); + options.SuppressStatusMessages = false; }); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseBootstrapperStartup() + .UseConsoleStartup(); + }); - await test.Host.WaitForShutdownAsync(); + await test.Host.WaitForShutdownAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.Contains(loggerStore.Query(), entry => entry.Message == "Information: RunAsync started."); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.Contains(loggerStore.Query(), entry => entry.Message == "Information: RunAsync started."); + } - [Fact] - public async Task StopAsync_ShouldLogRunAsyncCompleted_WhenRanToCompletionAndSuppressStatusMessagesIsFalse() + [Fact] + public async Task StopAsync_ShouldLogRunAsyncCompleted_WhenRanToCompletionAndSuppressStatusMessagesIsFalse() + { + await using var test = HostTestFactory.Create(services => { - await using var test = HostTestFactory.Create(services => - { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = false; - }); - }, hb => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - hb.UseBootstrapperLifetime() - .UseBootstrapperStartup() - .UseConsoleStartup(); + options.SuppressStatusMessages = false; }); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseBootstrapperStartup() + .UseConsoleStartup(); + }); - await test.Host.WaitForShutdownAsync(); + await test.Host.WaitForShutdownAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.Contains(loggerStore.Query(), entry => entry.Message == "Information: RunAsync completed successfully."); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.Contains(loggerStore.Query(), entry => entry.Message == "Information: RunAsync completed successfully."); + } - [Fact] - public async Task StopAsync_ShouldNotLogRunAsyncCompleted_WhenSuppressStatusMessagesIsTrue() + [Fact] + public async Task StopAsync_ShouldNotLogRunAsyncCompleted_WhenSuppressStatusMessagesIsTrue() + { + await using var test = HostTestFactory.Create(services => { - await using var test = HostTestFactory.Create(services => - { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = true; - }); - }, hb => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - hb.UseBootstrapperLifetime() - .UseBootstrapperStartup() - .UseConsoleStartup(); + options.SuppressStatusMessages = true; }); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseBootstrapperStartup() + .UseConsoleStartup(); + }); - await test.Host.WaitForShutdownAsync(); + await test.Host.WaitForShutdownAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.DoesNotContain(loggerStore.Query(), entry => entry.Message == "Information: RunAsync completed successfully."); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.DoesNotContain(loggerStore.Query(), entry => entry.Message == "Information: RunAsync completed successfully."); + } - [Fact] - public async Task StopAsync_ShouldLogRunAsyncPrematureEnd_WhenNotRanToCompletionAndSuppressStatusMessagesIsFalse() + [Fact] + public async Task StopAsync_ShouldLogRunAsyncPrematureEnd_WhenNotRanToCompletionAndSuppressStatusMessagesIsFalse() + { + await using var test = HostTestFactory.Create(services => { - await using var test = HostTestFactory.Create(services => - { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = false; - }); - }, hb => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - hb.UseBootstrapperLifetime() - .UseBootstrapperStartup() - .UseConsoleStartup(); + options.SuppressStatusMessages = false; }); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseBootstrapperStartup() + .UseConsoleStartup(); + }); - await test.Host.WaitForShutdownAsync(); + await test.Host.WaitForShutdownAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.Contains(loggerStore.Query(), entry => entry.Message.Contains("RunAsync ended prematurely")); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.Contains(loggerStore.Query(), entry => entry.Message.Contains("RunAsync ended prematurely")); + } - [Fact] - public async Task StopAsync_ShouldNotLogRunAsyncPrematureEnd_WhenSuppressStatusMessagesIsTrue() + [Fact] + public async Task StopAsync_ShouldNotLogRunAsyncPrematureEnd_WhenSuppressStatusMessagesIsTrue() + { + await using var test = HostTestFactory.Create(services => { - await using var test = HostTestFactory.Create(services => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = true; - }); - }, hb => - { - hb.UseBootstrapperLifetime() - .UseBootstrapperStartup() - .UseConsoleStartup(); + options.SuppressStatusMessages = true; }); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseBootstrapperStartup() + .UseConsoleStartup(); + }); - await test.Host.WaitForShutdownAsync(); + await test.Host.WaitForShutdownAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.DoesNotContain(loggerStore.Query(), entry => entry.Message.Contains("RunAsync ended prematurely")); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.DoesNotContain(loggerStore.Query(), entry => entry.Message.Contains("RunAsync ended prematurely")); + } - [Fact] - public async Task StartAsync_ShouldLogFatalError_WhenExceptionOccursAndSuppressStatusMessagesIsFalse() + [Fact] + public async Task StartAsync_ShouldLogFatalError_WhenExceptionOccursAndSuppressStatusMessagesIsFalse() + { + await using var test = HostTestFactory.Create(services => { - await using var test = HostTestFactory.Create(services => - { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = false; - }); - }, hb => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - hb.UseBootstrapperLifetime() - .UseBootstrapperStartup() - .UseConsoleStartup(); + options.SuppressStatusMessages = false; }); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseBootstrapperStartup() + .UseConsoleStartup(); + }); - await test.Host.WaitForShutdownAsync(); + await test.Host.WaitForShutdownAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.Contains(loggerStore.Query(), entry => entry.Message.Contains("Fatal error") || entry.Message.Contains("Error")); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.Contains(loggerStore.Query(), entry => entry.Message.Contains("Fatal error") || entry.Message.Contains("Error")); + } - [Fact] - public async Task StartAsync_ShouldNotLogFatalError_WhenExceptionOccursAndSuppressStatusMessagesIsTrue() + [Fact] + public async Task StartAsync_ShouldNotLogFatalError_WhenExceptionOccursAndSuppressStatusMessagesIsTrue() + { + await using var test = HostTestFactory.Create(services => { - await using var test = HostTestFactory.Create(services => - { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = true; - }); - }, hb => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - hb.UseBootstrapperLifetime() - .UseBootstrapperStartup() - .UseConsoleStartup(); + options.SuppressStatusMessages = true; }); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseBootstrapperStartup() + .UseConsoleStartup(); + }); - await test.Host.WaitForShutdownAsync(); + await test.Host.WaitForShutdownAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.DoesNotContain(loggerStore.Query(), entry => entry.Message.Contains("Fatal error") && entry.Message.Contains("activating")); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.DoesNotContain(loggerStore.Query(), entry => entry.Message.Contains("Fatal error") && entry.Message.Contains("activating")); + } - [Fact] - public async Task StartAsync_ShouldLogUnableToActivateInstance_WhenStartupIsNullAndSuppressStatusMessagesIsFalse() + [Fact] + public async Task StartAsync_ShouldLogUnableToActivateInstance_WhenStartupIsNullAndSuppressStatusMessagesIsFalse() + { + await using var test = HostTestFactory.Create(services => { - await using var test = HostTestFactory.Create(services => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = false; - }); - services.AddSingleton>(new NullStartupFactory()); - }, hb => - { - hb.UseBootstrapperLifetime() - .UseConsoleStartup(); + options.SuppressStatusMessages = false; }); + services.AddSingleton>(new NullStartupFactory()); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseConsoleStartup(); + }); - await test.Host.StartAsync(); - await test.Host.StopAsync(); + await test.Host.StartAsync(); + await test.Host.StopAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.Contains(loggerStore.Query(), entry => entry.Message.Contains("Unable to activate")); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.Contains(loggerStore.Query(), entry => entry.Message.Contains("Unable to activate")); + } - [Fact] - public async Task StartAsync_ShouldNotLogUnableToActivateInstance_WhenStartupIsNullAndSuppressStatusMessagesIsTrue() + [Fact] + public async Task StartAsync_ShouldNotLogUnableToActivateInstance_WhenStartupIsNullAndSuppressStatusMessagesIsTrue() + { + await using var test = HostTestFactory.Create(services => { - await using var test = HostTestFactory.Create(services => - { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = true; - }); - services.AddSingleton>(new NullStartupFactory()); - }, hb => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - hb.UseBootstrapperLifetime() - .UseConsoleStartup(); + options.SuppressStatusMessages = true; }); + services.AddSingleton>(new NullStartupFactory()); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseConsoleStartup(); + }); - await test.Host.StartAsync(); - await test.Host.StopAsync(); + await test.Host.StartAsync(); + await test.Host.StopAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.DoesNotContain(loggerStore.Query(), entry => entry.Message.Contains("Unable to activate")); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.DoesNotContain(loggerStore.Query(), entry => entry.Message.Contains("Unable to activate")); } } diff --git a/test/Codebelt.Bootstrapper.Console.FunctionalTests/ConsoleProgramTest.cs b/test/Codebelt.Bootstrapper.Console.FunctionalTests/ConsoleProgramTest.cs index 448690b..ddc7906 100644 --- a/test/Codebelt.Bootstrapper.Console.FunctionalTests/ConsoleProgramTest.cs +++ b/test/Codebelt.Bootstrapper.Console.FunctionalTests/ConsoleProgramTest.cs @@ -5,26 +5,25 @@ using Microsoft.Extensions.Hosting; using Xunit; -namespace Codebelt.Bootstrapper.Console +namespace Codebelt.Bootstrapper.Console; + +public class ConsoleProgramTest : Test { - public class ConsoleProgramTest : Test + public ConsoleProgramTest(ITestOutputHelper output) : base(output) { - public ConsoleProgramTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public void CreateHostBuilder_ShouldRegisterBootstrapperServices() - { - using var host = TestConsoleProgram.CreateHostBuilderAccessor([]).Build(); + [Fact] + public void CreateHostBuilder_ShouldRegisterBootstrapperServices() + { + using var host = TestConsoleProgram.CreateHostBuilderAccessor([]).Build(); - var lifetime = host.Services.GetRequiredService(); - var startupFactory = host.Services.GetRequiredService>(); - var hostedServices = host.Services.GetServices().ToList(); + var lifetime = host.Services.GetRequiredService(); + var startupFactory = host.Services.GetRequiredService>(); + var hostedServices = host.Services.GetServices().ToList(); - Assert.IsType(lifetime); - Assert.IsType>(startupFactory); - Assert.Contains(hostedServices, hostedService => hostedService is ConsoleHostedService); - } + Assert.IsType(lifetime); + Assert.IsType>(startupFactory); + Assert.Contains(hostedServices, hostedService => hostedService is ConsoleHostedService); } } diff --git a/test/Codebelt.Bootstrapper.Console.FunctionalTests/ConsoleStartupTest.cs b/test/Codebelt.Bootstrapper.Console.FunctionalTests/ConsoleStartupTest.cs index 7233e2e..47c3549 100644 --- a/test/Codebelt.Bootstrapper.Console.FunctionalTests/ConsoleStartupTest.cs +++ b/test/Codebelt.Bootstrapper.Console.FunctionalTests/ConsoleStartupTest.cs @@ -8,37 +8,36 @@ using Microsoft.Extensions.Hosting.Internal; using Xunit; -namespace Codebelt.Bootstrapper.Console +namespace Codebelt.Bootstrapper.Console; + +public class ConsoleStartupTest : Test { - public class ConsoleStartupTest : Test + public ConsoleStartupTest(ITestOutputHelper output) : base(output) { - public ConsoleStartupTest(ITestOutputHelper output) : base(output) - { - } - - [Fact] - public void ConfigureConsole_ShouldAllowDefaultNoOpImplementation() - { - var configuration = new ConfigurationBuilder() - .AddInMemoryCollection(new Dictionary - { - { "TestKey", "TestValue" } - }) - .Build(); + } - var environment = new HostingEnvironment + [Fact] + public void ConfigureConsole_ShouldAllowDefaultNoOpImplementation() + { + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary { - EnvironmentName = Environments.Development, - ApplicationName = "TestApp", - ContentRootPath = Directory.GetCurrentDirectory() - }; + { "TestKey", "TestValue" } + }) + .Build(); + + var environment = new HostingEnvironment + { + EnvironmentName = Environments.Development, + ApplicationName = "TestApp", + ContentRootPath = Directory.GetCurrentDirectory() + }; - var startup = new TestConsoleStartup(configuration, environment); - var serviceProvider = new ServiceCollection().BuildServiceProvider(); + var startup = new TestConsoleStartup(configuration, environment); + var serviceProvider = new ServiceCollection().BuildServiceProvider(); - var exception = Record.Exception(() => startup.ConfigureConsole(serviceProvider)); + var exception = Record.Exception(() => startup.ConfigureConsole(serviceProvider)); - Assert.Null(exception); - } + Assert.Null(exception); } } diff --git a/test/Codebelt.Bootstrapper.Console.FunctionalTests/MinimalConsoleHostedServiceTest.cs b/test/Codebelt.Bootstrapper.Console.FunctionalTests/MinimalConsoleHostedServiceTest.cs index 853efed..9382a69 100644 --- a/test/Codebelt.Bootstrapper.Console.FunctionalTests/MinimalConsoleHostedServiceTest.cs +++ b/test/Codebelt.Bootstrapper.Console.FunctionalTests/MinimalConsoleHostedServiceTest.cs @@ -1,4 +1,4 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Codebelt.Bootstrapper.Console.Assets; using Codebelt.Extensions.Xunit; using Codebelt.Extensions.Xunit.Hosting; @@ -7,269 +7,268 @@ using Microsoft.Extensions.Logging; using Xunit; -namespace Codebelt.Bootstrapper.Console +namespace Codebelt.Bootstrapper.Console; + +public class MinimalConsoleHostedServiceTest : Test { - public class MinimalConsoleHostedServiceTest : Test + public MinimalConsoleHostedServiceTest(ITestOutputHelper output) : base(output) { - public MinimalConsoleHostedServiceTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public async Task StartAsync_ShouldInvokeRunAsyncInTestConsoleStartup() + [Fact] + public async Task StartAsync_ShouldInvokeRunAsyncInTestConsoleStartup() + { + await using var test = MinimalHostTestFactory.Create(services => { - await using var test = MinimalHostTestFactory.Create(services => - { - services.AddXunitTestLogging(TestOutput); - }, hb => - { - hb.UseBootstrapperLifetime() - .UseBootstrapperProgram(typeof(TestMinimalConsoleProgram)) - .UseMinimalConsoleProgram(); - }); - - await test.Host.WaitForShutdownAsync(); - - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.Collection(loggerStore.Query(), - entry => Assert.Equal("Information: RunAsync started.", entry.Message), - entry => Assert.Equal("Trace: Inside RunAsync of TestMinimalConsoleProgram.", entry.Message), - entry => Assert.Equal("Information: RunAsync completed successfully.", entry.Message) - ); - } + services.AddXunitTestLogging(TestOutput); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseBootstrapperProgram(typeof(TestMinimalConsoleProgram)) + .UseMinimalConsoleProgram(); + }); + + await test.Host.WaitForShutdownAsync(); + + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.Collection(loggerStore.Query(), + entry => Assert.Equal("Information: RunAsync started.", entry.Message), + entry => Assert.Equal("Trace: Inside RunAsync of TestMinimalConsoleProgram.", entry.Message), + entry => Assert.Equal("Information: RunAsync completed successfully.", entry.Message) + ); + } - [Fact] - public async Task StartAsync_ShouldSuppressStatusMessages_WhenSuppressStatusMessagesIsTrue() + [Fact] + public async Task StartAsync_ShouldSuppressStatusMessages_WhenSuppressStatusMessagesIsTrue() + { + await using var test = MinimalHostTestFactory.Create(services => { - await using var test = MinimalHostTestFactory.Create(services => - { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = true; - }); - }, hb => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - hb.UseBootstrapperLifetime() - .UseBootstrapperProgram(typeof(TestMinimalConsoleProgram)) - .UseMinimalConsoleProgram(); + options.SuppressStatusMessages = true; }); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseBootstrapperProgram(typeof(TestMinimalConsoleProgram)) + .UseMinimalConsoleProgram(); + }); - await test.Host.WaitForShutdownAsync(); + await test.Host.WaitForShutdownAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.Collection(loggerStore.Query(), - entry => Assert.Equal("Trace: Inside RunAsync of TestMinimalConsoleProgram.", entry.Message) - ); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.Collection(loggerStore.Query(), + entry => Assert.Equal("Trace: Inside RunAsync of TestMinimalConsoleProgram.", entry.Message) + ); + } - [Fact] - public async Task StartAsync_ShouldLogRunAsyncStarted_WhenSuppressStatusMessagesIsFalse() + [Fact] + public async Task StartAsync_ShouldLogRunAsyncStarted_WhenSuppressStatusMessagesIsFalse() + { + await using var test = MinimalHostTestFactory.Create(services => { - await using var test = MinimalHostTestFactory.Create(services => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = false; - }); - }, hb => - { - hb.UseBootstrapperLifetime() - .UseBootstrapperProgram(typeof(TestMinimalConsoleProgram)) - .UseMinimalConsoleProgram(); + options.SuppressStatusMessages = false; }); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseBootstrapperProgram(typeof(TestMinimalConsoleProgram)) + .UseMinimalConsoleProgram(); + }); - await test.Host.WaitForShutdownAsync(); + await test.Host.WaitForShutdownAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.Contains(loggerStore.Query(), entry => entry.Message == "Information: RunAsync started."); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.Contains(loggerStore.Query(), entry => entry.Message == "Information: RunAsync started."); + } - [Fact] - public async Task StopAsync_ShouldLogRunAsyncCompleted_WhenRanToCompletionAndSuppressStatusMessagesIsFalse() + [Fact] + public async Task StopAsync_ShouldLogRunAsyncCompleted_WhenRanToCompletionAndSuppressStatusMessagesIsFalse() + { + await using var test = MinimalHostTestFactory.Create(services => { - await using var test = MinimalHostTestFactory.Create(services => - { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = false; - }); - }, hb => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - hb.UseBootstrapperLifetime() - .UseBootstrapperProgram(typeof(TestMinimalConsoleProgram)) - .UseMinimalConsoleProgram(); + options.SuppressStatusMessages = false; }); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseBootstrapperProgram(typeof(TestMinimalConsoleProgram)) + .UseMinimalConsoleProgram(); + }); - await test.Host.WaitForShutdownAsync(); + await test.Host.WaitForShutdownAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.Contains(loggerStore.Query(), entry => entry.Message == "Information: RunAsync completed successfully."); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.Contains(loggerStore.Query(), entry => entry.Message == "Information: RunAsync completed successfully."); + } - [Fact] - public async Task StopAsync_ShouldNotLogRunAsyncCompleted_WhenSuppressStatusMessagesIsTrue() + [Fact] + public async Task StopAsync_ShouldNotLogRunAsyncCompleted_WhenSuppressStatusMessagesIsTrue() + { + await using var test = MinimalHostTestFactory.Create(services => { - await using var test = MinimalHostTestFactory.Create(services => - { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = true; - }); - }, hb => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - hb.UseBootstrapperLifetime() - .UseBootstrapperProgram(typeof(TestMinimalConsoleProgram)) - .UseMinimalConsoleProgram(); + options.SuppressStatusMessages = true; }); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseBootstrapperProgram(typeof(TestMinimalConsoleProgram)) + .UseMinimalConsoleProgram(); + }); - await test.Host.WaitForShutdownAsync(); + await test.Host.WaitForShutdownAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.DoesNotContain(loggerStore.Query(), entry => entry.Message == "Information: RunAsync completed successfully."); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.DoesNotContain(loggerStore.Query(), entry => entry.Message == "Information: RunAsync completed successfully."); + } - [Fact] - public async Task StopAsync_ShouldLogRunAsyncPrematureEnd_WhenNotRanToCompletionAndSuppressStatusMessagesIsFalse() + [Fact] + public async Task StopAsync_ShouldLogRunAsyncPrematureEnd_WhenNotRanToCompletionAndSuppressStatusMessagesIsFalse() + { + await using var test = MinimalHostTestFactory.Create(services => { - await using var test = MinimalHostTestFactory.Create(services => - { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = false; - }); - }, hb => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - hb.UseBootstrapperLifetime() - .UseBootstrapperProgram(typeof(TestMinimalConsoleProgramWithPrematureEnd)) - .UseMinimalConsoleProgram(); + options.SuppressStatusMessages = false; }); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseBootstrapperProgram(typeof(TestMinimalConsoleProgramWithPrematureEnd)) + .UseMinimalConsoleProgram(); + }); - await test.Host.WaitForShutdownAsync(); + await test.Host.WaitForShutdownAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.Contains(loggerStore.Query(), entry => entry.Message.Contains("RunAsync ended prematurely")); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.Contains(loggerStore.Query(), entry => entry.Message.Contains("RunAsync ended prematurely")); + } - [Fact] - public async Task StopAsync_ShouldNotLogRunAsyncPrematureEnd_WhenSuppressStatusMessagesIsTrue() + [Fact] + public async Task StopAsync_ShouldNotLogRunAsyncPrematureEnd_WhenSuppressStatusMessagesIsTrue() + { + await using var test = MinimalHostTestFactory.Create(services => { - await using var test = MinimalHostTestFactory.Create(services => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = true; - }); - }, hb => - { - hb.UseBootstrapperLifetime() - .UseBootstrapperProgram(typeof(TestMinimalConsoleProgramWithPrematureEnd)) - .UseMinimalConsoleProgram(); + options.SuppressStatusMessages = true; }); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseBootstrapperProgram(typeof(TestMinimalConsoleProgramWithPrematureEnd)) + .UseMinimalConsoleProgram(); + }); - await test.Host.WaitForShutdownAsync(); + await test.Host.WaitForShutdownAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.DoesNotContain(loggerStore.Query(), entry => entry.Message.Contains("RunAsync ended prematurely")); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.DoesNotContain(loggerStore.Query(), entry => entry.Message.Contains("RunAsync ended prematurely")); + } - [Fact] - public async Task StartAsync_ShouldLogFatalError_WhenExceptionOccursAndSuppressStatusMessagesIsFalse() + [Fact] + public async Task StartAsync_ShouldLogFatalError_WhenExceptionOccursAndSuppressStatusMessagesIsFalse() + { + await using var test = MinimalHostTestFactory.Create(services => { - await using var test = MinimalHostTestFactory.Create(services => - { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = false; - }); - }, hb => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - hb.UseBootstrapperLifetime() - .UseBootstrapperProgram(typeof(TestMinimalConsoleProgramWithException)) - .UseMinimalConsoleProgram(); + options.SuppressStatusMessages = false; }); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseBootstrapperProgram(typeof(TestMinimalConsoleProgramWithException)) + .UseMinimalConsoleProgram(); + }); - await test.Host.WaitForShutdownAsync(); + await test.Host.WaitForShutdownAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.Contains(loggerStore.Query(), entry => entry.Message.Contains("Fatal error") || entry.Message.Contains("Error")); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.Contains(loggerStore.Query(), entry => entry.Message.Contains("Fatal error") || entry.Message.Contains("Error")); + } - [Fact] - public async Task StartAsync_ShouldNotLogFatalError_WhenExceptionOccursAndSuppressStatusMessagesIsTrue() + [Fact] + public async Task StartAsync_ShouldNotLogFatalError_WhenExceptionOccursAndSuppressStatusMessagesIsTrue() + { + await using var test = MinimalHostTestFactory.Create(services => { - await using var test = MinimalHostTestFactory.Create(services => - { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = true; - }); - }, hb => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - hb.UseBootstrapperLifetime() - .UseBootstrapperProgram(typeof(TestMinimalConsoleProgramWithException)) - .UseMinimalConsoleProgram(); + options.SuppressStatusMessages = true; }); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseBootstrapperProgram(typeof(TestMinimalConsoleProgramWithException)) + .UseMinimalConsoleProgram(); + }); - await test.Host.WaitForShutdownAsync(); + await test.Host.WaitForShutdownAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.DoesNotContain(loggerStore.Query(), entry => entry.Message.Contains("Fatal error") && entry.Message.Contains("activating")); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.DoesNotContain(loggerStore.Query(), entry => entry.Message.Contains("Fatal error") && entry.Message.Contains("activating")); + } - [Fact] - public async Task StartAsync_ShouldLogUnableToActivateInstance_WhenProgramIsNullAndSuppressStatusMessagesIsFalse() + [Fact] + public async Task StartAsync_ShouldLogUnableToActivateInstance_WhenProgramIsNullAndSuppressStatusMessagesIsFalse() + { + await using var test = MinimalHostTestFactory.Create(services => { - await using var test = MinimalHostTestFactory.Create(services => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = false; - }); - // Register null factory to simulate program not being created - services.AddSingleton(new NullProgramFactory()); - }, hb => - { - hb.UseBootstrapperLifetime() - .UseMinimalConsoleProgram(); + options.SuppressStatusMessages = false; }); + // Register null factory to simulate program not being created + services.AddSingleton(new NullProgramFactory()); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseMinimalConsoleProgram(); + }); - await test.Host.WaitForShutdownAsync(); + await test.Host.WaitForShutdownAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.Contains(loggerStore.Query(), entry => entry.Message.Contains("Unable to activate")); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.Contains(loggerStore.Query(), entry => entry.Message.Contains("Unable to activate")); + } - [Fact] - public async Task StartAsync_ShouldNotLogUnableToActivateInstance_WhenProgramIsNullAndSuppressStatusMessagesIsTrue() + [Fact] + public async Task StartAsync_ShouldNotLogUnableToActivateInstance_WhenProgramIsNullAndSuppressStatusMessagesIsTrue() + { + await using var test = MinimalHostTestFactory.Create(services => { - await using var test = MinimalHostTestFactory.Create(services => - { - services.AddXunitTestLogging(TestOutput); - services.Configure(options => - { - options.SuppressStatusMessages = true; - }); - // Register null factory to simulate program not being created - services.AddSingleton(new NullProgramFactory()); - }, hb => + services.AddXunitTestLogging(TestOutput); + services.Configure(options => { - hb.UseBootstrapperLifetime() - .UseMinimalConsoleProgram(); + options.SuppressStatusMessages = true; }); + // Register null factory to simulate program not being created + services.AddSingleton(new NullProgramFactory()); + }, hb => + { + hb.UseBootstrapperLifetime() + .UseMinimalConsoleProgram(); + }); - await test.Host.WaitForShutdownAsync(); + await test.Host.WaitForShutdownAsync(); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.DoesNotContain(loggerStore.Query(), entry => entry.Message.Contains("Unable to activate")); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.DoesNotContain(loggerStore.Query(), entry => entry.Message.Contains("Unable to activate")); } } diff --git a/test/Codebelt.Bootstrapper.Console.FunctionalTests/MinimalConsoleProgramBuilderTest.cs b/test/Codebelt.Bootstrapper.Console.FunctionalTests/MinimalConsoleProgramBuilderTest.cs index eb00750..01ce1d5 100644 --- a/test/Codebelt.Bootstrapper.Console.FunctionalTests/MinimalConsoleProgramBuilderTest.cs +++ b/test/Codebelt.Bootstrapper.Console.FunctionalTests/MinimalConsoleProgramBuilderTest.cs @@ -5,38 +5,37 @@ using Microsoft.Extensions.Hosting; using Xunit; -namespace Codebelt.Bootstrapper.Console +namespace Codebelt.Bootstrapper.Console; + +public class MinimalConsoleProgramBuilderTest : Test { - public class MinimalConsoleProgramBuilderTest : Test + public MinimalConsoleProgramBuilderTest(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public void CreateHostBuilder_ShouldRegisterMinimalConsoleServices() { - public MinimalConsoleProgramBuilderTest(ITestOutputHelper output) : base(output) - { - } - - [Fact] - public void CreateHostBuilder_ShouldRegisterMinimalConsoleServices() - { - using var host = TestMinimalConsoleProgram.CreateHostBuilderAccessor([]).Build(); - - var lifetime = host.Services.GetRequiredService(); - var programFactory = host.Services.GetRequiredService(); - var hostedServices = host.Services.GetServices().ToList(); - - Assert.IsType(lifetime); - Assert.NotNull(programFactory); - Assert.Contains(hostedServices, hostedService => hostedService is MinimalConsoleHostedService); - } - - [Fact] - public void CreateHostBuilderOfTProgram_ShouldRegisterMinimalConsoleServices() - { - using var host = TestGenericMinimalConsoleProgram.CreateHostBuilderAccessor([]).Build(); - - var programFactory = host.Services.GetRequiredService(); - var hostedServices = host.Services.GetServices().ToList(); - - Assert.NotNull(programFactory); - Assert.Contains(hostedServices, hostedService => hostedService is MinimalConsoleHostedService); - } + using var host = TestMinimalConsoleProgram.CreateHostBuilderAccessor([]).Build(); + + var lifetime = host.Services.GetRequiredService(); + var programFactory = host.Services.GetRequiredService(); + var hostedServices = host.Services.GetServices().ToList(); + + Assert.IsType(lifetime); + Assert.NotNull(programFactory); + Assert.Contains(hostedServices, hostedService => hostedService is MinimalConsoleHostedService); + } + + [Fact] + public void CreateHostBuilderOfTProgram_ShouldRegisterMinimalConsoleServices() + { + using var host = TestGenericMinimalConsoleProgram.CreateHostBuilderAccessor([]).Build(); + + var programFactory = host.Services.GetRequiredService(); + var hostedServices = host.Services.GetServices().ToList(); + + Assert.NotNull(programFactory); + Assert.Contains(hostedServices, hostedService => hostedService is MinimalConsoleHostedService); } } diff --git a/test/Codebelt.Bootstrapper.FunctionalTests/Assets/TestBackgroundService.cs b/test/Codebelt.Bootstrapper.FunctionalTests/Assets/TestBackgroundService.cs index 12d8bb5..f8d3316 100644 --- a/test/Codebelt.Bootstrapper.FunctionalTests/Assets/TestBackgroundService.cs +++ b/test/Codebelt.Bootstrapper.FunctionalTests/Assets/TestBackgroundService.cs @@ -1,46 +1,45 @@ -using System; +using System; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -namespace Codebelt.Bootstrapper.Assets +namespace Codebelt.Bootstrapper.Assets; + +public class TestBackgroundService : BackgroundService { - public class TestBackgroundService : BackgroundService + private readonly ILogger _logger; + private readonly IHostLifetimeEvents _events; + private readonly Stopwatch _stopwatch; + + public TestBackgroundService(ILogger logger, IHostLifetimeEvents events, IHostApplicationLifetime applicationLifetime) { - private readonly ILogger _logger; - private readonly IHostLifetimeEvents _events; - private readonly Stopwatch _stopwatch; + _logger = logger; + _events = events; + _stopwatch = Stopwatch.StartNew(); - public TestBackgroundService(ILogger logger, IHostLifetimeEvents events, IHostApplicationLifetime applicationLifetime) + _events.OnApplicationStartedCallback += () => { - _logger = logger; - _events = events; - _stopwatch = Stopwatch.StartNew(); - - _events.OnApplicationStartedCallback += () => - { - _logger.LogInformation("TestBackgroundService started after {Elapsed}", Elapsed); - applicationLifetime.StopApplication(); - }; - } + _logger.LogInformation("TestBackgroundService started after {Elapsed}", Elapsed); + applicationLifetime.StopApplication(); + }; + } - public TimeSpan Elapsed { get; private set; } = TimeSpan.Zero; + public TimeSpan Elapsed { get; private set; } = TimeSpan.Zero; - protected override async Task ExecuteAsync(CancellationToken stoppingToken) + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) { - while (!stoppingToken.IsCancellationRequested) + try + { + await Task.Delay(TimeSpan.FromMilliseconds(1), stoppingToken).ConfigureAwait(false); + } + finally { - try - { - await Task.Delay(TimeSpan.FromMilliseconds(1), stoppingToken).ConfigureAwait(false); - } - finally - { - Elapsed = _stopwatch.Elapsed; - } + Elapsed = _stopwatch.Elapsed; } } } diff --git a/test/Codebelt.Bootstrapper.FunctionalTests/Assets/TestHostFixture.cs b/test/Codebelt.Bootstrapper.FunctionalTests/Assets/TestHostFixture.cs index 55750dc..d56594f 100644 --- a/test/Codebelt.Bootstrapper.FunctionalTests/Assets/TestHostFixture.cs +++ b/test/Codebelt.Bootstrapper.FunctionalTests/Assets/TestHostFixture.cs @@ -1,35 +1,34 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Codebelt.Extensions.Xunit.Hosting; using Codebelt.Extensions.Xunit; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Assets +namespace Codebelt.Bootstrapper.Assets; + +public class TestHostFixture : ManagedHostFixture { - public class TestHostFixture : ManagedHostFixture + public override void ConfigureHost(Test hostTest) { - public override void ConfigureHost(Test hostTest) - { - var hb = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder() - .ConfigureAppConfiguration((context, config) => - { - ConfigureCallback(config.Build(), context.HostingEnvironment); - }) - .ConfigureServices((context, services) => - { - Configuration = context.Configuration; - Environment = context.HostingEnvironment; - ConfigureServicesCallback(services); - }) - .ConfigureHostConfiguration(builder => + var hb = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder() + .ConfigureAppConfiguration((context, config) => + { + ConfigureCallback(config.Build(), context.HostingEnvironment); + }) + .ConfigureServices((context, services) => + { + Configuration = context.Configuration; + Environment = context.HostingEnvironment; + ConfigureServicesCallback(services); + }) + .ConfigureHostConfiguration(builder => + { + builder.AddInMemoryCollection(new Dictionary { - builder.AddInMemoryCollection(new Dictionary - { - { HostDefaults.ApplicationKey, hostTest.CallerType.Assembly.GetName().Name } - }); + { HostDefaults.ApplicationKey, hostTest.CallerType.Assembly.GetName().Name } }); - ConfigureHostCallback(hb); - Host = hb.Build(); - } + }); + ConfigureHostCallback(hb); + Host = hb.Build(); } } diff --git a/test/Codebelt.Bootstrapper.FunctionalTests/Assets/TestStartup.cs b/test/Codebelt.Bootstrapper.FunctionalTests/Assets/TestStartup.cs index d8461ab..499ed03 100644 --- a/test/Codebelt.Bootstrapper.FunctionalTests/Assets/TestStartup.cs +++ b/test/Codebelt.Bootstrapper.FunctionalTests/Assets/TestStartup.cs @@ -1,17 +1,16 @@ -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Assets +namespace Codebelt.Bootstrapper.Assets; + +public class TestStartup : StartupRoot { - public class TestStartup : StartupRoot + public TestStartup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) { - public TestStartup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) - { - } + } - public override void ConfigureServices(IServiceCollection services) - { - } + public override void ConfigureServices(IServiceCollection services) + { } } diff --git a/test/Codebelt.Bootstrapper.FunctionalTests/BootstrapperLifetimeTest.cs b/test/Codebelt.Bootstrapper.FunctionalTests/BootstrapperLifetimeTest.cs index bdfed31..320d372 100644 --- a/test/Codebelt.Bootstrapper.FunctionalTests/BootstrapperLifetimeTest.cs +++ b/test/Codebelt.Bootstrapper.FunctionalTests/BootstrapperLifetimeTest.cs @@ -1,78 +1,77 @@ -using Codebelt.Bootstrapper.Assets; +using Codebelt.Bootstrapper.Assets; using Codebelt.Extensions.Xunit; using Codebelt.Extensions.Xunit.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Xunit; -namespace Codebelt.Bootstrapper +namespace Codebelt.Bootstrapper; + +public class BootstrapperLifetimeTest : Test { - public class BootstrapperLifetimeTest : Test + public BootstrapperLifetimeTest(ITestOutputHelper output) : base(output) { - public BootstrapperLifetimeTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public void OnApplicationStartedCallback_ShouldBeInvokedWhenStartingHost() + [Fact] + public void OnApplicationStartedCallback_ShouldBeInvokedWhenStartingHost() + { + var started = false; + using var test = HostTestFactory.Create(services => + { + services.AddXunitTestLoggingOutputHelperAccessor(); + services.AddXunitTestLogging(TestOutput); + }, hb => { - var started = false; - using var test = HostTestFactory.Create(services => - { - services.AddXunitTestLoggingOutputHelperAccessor(); - services.AddXunitTestLogging(TestOutput); - }, hb => - { - hb.UseBootstrapperLifetime(); - hb.UseBootstrapperStartup(); - }, new TestHostFixture()); + hb.UseBootstrapperLifetime(); + hb.UseBootstrapperStartup(); + }, new TestHostFixture()); - test.Host.Services.GetRequiredService().OnApplicationStartedCallback = () => { started = true; }; + test.Host.Services.GetRequiredService().OnApplicationStartedCallback = () => { started = true; }; - test.Host.Start(); + test.Host.Start(); - Assert.True(started); - } + Assert.True(started); + } - [Fact] - public void OnApplicationStoppingCallback_OnApplicationStoppedCallback_ShouldBeInvokedWhenStoppingHost() + [Fact] + public void OnApplicationStoppingCallback_OnApplicationStoppedCallback_ShouldBeInvokedWhenStoppingHost() + { + var stopping = false; + var stopped = false; + using var test = HostTestFactory.Create(services => + { + services.AddXunitTestLoggingOutputHelperAccessor(); + services.AddXunitTestLogging(TestOutput); + }, hb => { - var stopping = false; - var stopped = false; - using var test = HostTestFactory.Create(services => - { - services.AddXunitTestLoggingOutputHelperAccessor(); - services.AddXunitTestLogging(TestOutput); - }, hb => - { - hb.UseBootstrapperLifetime(); - hb.UseBootstrapperStartup(); - }, new TestHostFixture()); + hb.UseBootstrapperLifetime(); + hb.UseBootstrapperStartup(); + }, new TestHostFixture()); - test.Host.Services.GetRequiredService().OnApplicationStoppingCallback = () => { stopping = true; }; - test.Host.Services.GetRequiredService().OnApplicationStoppedCallback = () => { stopped = true; }; + test.Host.Services.GetRequiredService().OnApplicationStoppingCallback = () => { stopping = true; }; + test.Host.Services.GetRequiredService().OnApplicationStoppedCallback = () => { stopped = true; }; - test.Host.Start(); - test.Host.StopAsync().GetAwaiter().GetResult(); + test.Host.Start(); + test.Host.StopAsync().GetAwaiter().GetResult(); - Assert.True(stopping && stopped); - } + Assert.True(stopping && stopped); + } - [Fact] - public void Dispose_ShouldDisposeWrappedHostLifetime() + [Fact] + public void Dispose_ShouldDisposeWrappedHostLifetime() + { + using var test = HostTestFactory.Create(services => + { + services.AddXunitTestLoggingOutputHelperAccessor(); + services.AddXunitTestLogging(TestOutput); + }, hb => { - using var test = HostTestFactory.Create(services => - { - services.AddXunitTestLoggingOutputHelperAccessor(); - services.AddXunitTestLogging(TestOutput); - }, hb => - { - hb.UseBootstrapperLifetime(); - }, new TestHostFixture()); + hb.UseBootstrapperLifetime(); + }, new TestHostFixture()); - var bootstrapperLifetime = Assert.IsType(test.Host.Services.GetRequiredService()); + var bootstrapperLifetime = Assert.IsType(test.Host.Services.GetRequiredService()); - bootstrapperLifetime.Dispose(); - } + bootstrapperLifetime.Dispose(); } } diff --git a/test/Codebelt.Bootstrapper.FunctionalTests/BootstrapperLogMessagesTest.cs b/test/Codebelt.Bootstrapper.FunctionalTests/BootstrapperLogMessagesTest.cs index 8d02feb..f6bfd95 100644 --- a/test/Codebelt.Bootstrapper.FunctionalTests/BootstrapperLogMessagesTest.cs +++ b/test/Codebelt.Bootstrapper.FunctionalTests/BootstrapperLogMessagesTest.cs @@ -6,26 +6,25 @@ using Microsoft.Extensions.Logging; using Xunit; -namespace Codebelt.Bootstrapper +namespace Codebelt.Bootstrapper; + +public class BootstrapperLogMessagesTest : Test { - public class BootstrapperLogMessagesTest : Test + public BootstrapperLogMessagesTest(ITestOutputHelper output) : base(output) { - public BootstrapperLogMessagesTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public void FatalErrorActivating_ShouldWriteCriticalEntry() - { - using var services = new ServiceCollection() - .AddXunitTestLogging(TestOutput) - .BuildServiceProvider(); + [Fact] + public void FatalErrorActivating_ShouldWriteCriticalEntry() + { + using var services = new ServiceCollection() + .AddXunitTestLogging(TestOutput) + .BuildServiceProvider(); - var logger = services.GetRequiredService>(); + var logger = services.GetRequiredService>(); - Decorator.EncloseToExpose(logger, false).FatalErrorActivating("Test.Type", new InvalidOperationException("Boom")); + Decorator.EncloseToExpose(logger, false).FatalErrorActivating("Test.Type", new InvalidOperationException("Boom")); - Assert.Contains(logger.GetTestStore().Query(), entry => entry.Message.Contains("Fatal error occurred while activating Test.Type.")); - } + Assert.Contains(logger.GetTestStore().Query(), entry => entry.Message.Contains("Fatal error occurred while activating Test.Type.")); } } diff --git a/test/Codebelt.Bootstrapper.FunctionalTests/HostApplicationBuilderExtensionsTest.cs b/test/Codebelt.Bootstrapper.FunctionalTests/HostApplicationBuilderExtensionsTest.cs index feae8ea..4519bb0 100644 --- a/test/Codebelt.Bootstrapper.FunctionalTests/HostApplicationBuilderExtensionsTest.cs +++ b/test/Codebelt.Bootstrapper.FunctionalTests/HostApplicationBuilderExtensionsTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -10,120 +10,119 @@ using Microsoft.Extensions.Hosting.Internal; using Xunit; -namespace Codebelt.Bootstrapper +namespace Codebelt.Bootstrapper; + +public class HostApplicationBuilderExtensionsTest : Test { - public class HostApplicationBuilderExtensionsTest : Test - { - private static readonly string TestAssemblyName = typeof(TestStartup).Assembly.GetName().Name!; + private static readonly string TestAssemblyName = typeof(TestStartup).Assembly.GetName().Name!; - public HostApplicationBuilderExtensionsTest(ITestOutputHelper output) : base(output) - { - } + public HostApplicationBuilderExtensionsTest(ITestOutputHelper output) : base(output) + { + } - [Fact] - public void UseBootstrapperLifetime_ShouldRegisterBootstrapperLifetime() - { - var hb = Host.CreateApplicationBuilder(); - hb.UseBootstrapperLifetime(); - var host = hb.Build(); + [Fact] + public void UseBootstrapperLifetime_ShouldRegisterBootstrapperLifetime() + { + var hb = Host.CreateApplicationBuilder(); + hb.UseBootstrapperLifetime(); + var host = hb.Build(); - var bootstrapperLifetime = host.Services.GetService(); + var bootstrapperLifetime = host.Services.GetService(); - Assert.NotNull(bootstrapperLifetime); - Assert.IsType(bootstrapperLifetime); - } + Assert.NotNull(bootstrapperLifetime); + Assert.IsType(bootstrapperLifetime); + } - [Fact] - public void UseBootstrapperEnvironmentDefaults_ShouldAddUserSecretsSource_WhenEnvironmentIsLocalDevelopment() + [Fact] + public void UseBootstrapperEnvironmentDefaults_ShouldAddUserSecretsSource_WhenEnvironmentIsLocalDevelopment() + { + var hb = CreateHostApplicationBuilder("LocalDevelopment", TestAssemblyName, new Dictionary { - var hb = CreateHostApplicationBuilder("LocalDevelopment", TestAssemblyName, new Dictionary - { - ["hostBuilder:reloadConfigOnChange"] = "false" - }); - var initialSecretsSourceCount = CountUserSecretsSources(hb.Configuration.Sources); - - var result = hb.UseBootstrapperEnvironmentDefaults(); - - Assert.Same(hb, result); - var userSecretsSource = Assert.Single(hb.Configuration.Sources.OfType().Where(IsUserSecretsSource)); - Assert.Equal(initialSecretsSourceCount + 1, CountUserSecretsSources(hb.Configuration.Sources)); - Assert.False(userSecretsSource.ReloadOnChange); - } + ["hostBuilder:reloadConfigOnChange"] = "false" + }); + var initialSecretsSourceCount = CountUserSecretsSources(hb.Configuration.Sources); - [Fact] - public void UseBootstrapperEnvironmentDefaults_ShouldIgnoreMissingApplicationAssembly_WhenEnvironmentIsLocalDevelopment() - { - var hb = CreateHostApplicationBuilder("LocalDevelopment", "Codebelt.Bootstrapper.Missing.Assembly", null); - var initialSecretsSourceCount = CountUserSecretsSources(hb.Configuration.Sources); + var result = hb.UseBootstrapperEnvironmentDefaults(); - var exception = Record.Exception(() => hb.UseBootstrapperEnvironmentDefaults()); + Assert.Same(hb, result); + var userSecretsSource = Assert.Single(hb.Configuration.Sources.OfType().Where(IsUserSecretsSource)); + Assert.Equal(initialSecretsSourceCount + 1, CountUserSecretsSources(hb.Configuration.Sources)); + Assert.False(userSecretsSource.ReloadOnChange); + } - Assert.Null(exception); - Assert.Equal(initialSecretsSourceCount, CountUserSecretsSources(hb.Configuration.Sources)); - } + [Fact] + public void UseBootstrapperEnvironmentDefaults_ShouldIgnoreMissingApplicationAssembly_WhenEnvironmentIsLocalDevelopment() + { + var hb = CreateHostApplicationBuilder("LocalDevelopment", "Codebelt.Bootstrapper.Missing.Assembly", null); + var initialSecretsSourceCount = CountUserSecretsSources(hb.Configuration.Sources); - [Fact] - public void UseBootstrapperEnvironmentDefaults_ShouldReturnWithoutAddingUserSecrets_WhenApplicationNameIsEmpty() - { - var hb = CreateHostApplicationBuilder("LocalDevelopment", TestAssemblyName, null); - ((HostingEnvironment)hb.Environment).ApplicationName = string.Empty; - var initialSecretsSourceCount = CountUserSecretsSources(hb.Configuration.Sources); + var exception = Record.Exception(() => hb.UseBootstrapperEnvironmentDefaults()); - var result = hb.UseBootstrapperEnvironmentDefaults(); + Assert.Null(exception); + Assert.Equal(initialSecretsSourceCount, CountUserSecretsSources(hb.Configuration.Sources)); + } - Assert.Same(hb, result); - Assert.Equal(initialSecretsSourceCount, CountUserSecretsSources(hb.Configuration.Sources)); - } + [Fact] + public void UseBootstrapperEnvironmentDefaults_ShouldReturnWithoutAddingUserSecrets_WhenApplicationNameIsEmpty() + { + var hb = CreateHostApplicationBuilder("LocalDevelopment", TestAssemblyName, null); + ((HostingEnvironment)hb.Environment).ApplicationName = string.Empty; + var initialSecretsSourceCount = CountUserSecretsSources(hb.Configuration.Sources); - [Fact] - public void UseBootstrapperEnvironmentDefaults_ShouldReturnWithoutAddingUserSecrets_WhenApplicationNameIsNull() - { - var hb = CreateHostApplicationBuilder("LocalDevelopment", TestAssemblyName, null); - ((HostingEnvironment)hb.Environment).ApplicationName = null!; - var initialSecretsSourceCount = CountUserSecretsSources(hb.Configuration.Sources); + var result = hb.UseBootstrapperEnvironmentDefaults(); - var result = hb.UseBootstrapperEnvironmentDefaults(); + Assert.Same(hb, result); + Assert.Equal(initialSecretsSourceCount, CountUserSecretsSources(hb.Configuration.Sources)); + } - Assert.Same(hb, result); - Assert.Equal(initialSecretsSourceCount, CountUserSecretsSources(hb.Configuration.Sources)); - } + [Fact] + public void UseBootstrapperEnvironmentDefaults_ShouldReturnWithoutAddingUserSecrets_WhenApplicationNameIsNull() + { + var hb = CreateHostApplicationBuilder("LocalDevelopment", TestAssemblyName, null); + ((HostingEnvironment)hb.Environment).ApplicationName = null!; + var initialSecretsSourceCount = CountUserSecretsSources(hb.Configuration.Sources); - [Fact] - public void UseBootstrapperEnvironmentDefaults_ShouldReturnWithoutAddingUserSecrets_WhenEnvironmentIsNotLocalDevelopment() - { - var hb = CreateHostApplicationBuilder(Environments.Development, TestAssemblyName, null); - var initialSecretsSourceCount = CountUserSecretsSources(hb.Configuration.Sources); + var result = hb.UseBootstrapperEnvironmentDefaults(); - var result = hb.UseBootstrapperEnvironmentDefaults(); + Assert.Same(hb, result); + Assert.Equal(initialSecretsSourceCount, CountUserSecretsSources(hb.Configuration.Sources)); + } - Assert.Same(hb, result); - Assert.Equal(initialSecretsSourceCount, CountUserSecretsSources(hb.Configuration.Sources)); - } + [Fact] + public void UseBootstrapperEnvironmentDefaults_ShouldReturnWithoutAddingUserSecrets_WhenEnvironmentIsNotLocalDevelopment() + { + var hb = CreateHostApplicationBuilder(Environments.Development, TestAssemblyName, null); + var initialSecretsSourceCount = CountUserSecretsSources(hb.Configuration.Sources); - private static HostApplicationBuilder CreateHostApplicationBuilder(string environmentName, string applicationName, Dictionary? configuration) - { - var settings = new HostApplicationBuilderSettings - { - EnvironmentName = environmentName, - ApplicationName = applicationName - }; - var hostBuilder = Host.CreateApplicationBuilder(settings); - if (configuration is not null) - { - hostBuilder.Configuration.AddInMemoryCollection(configuration); - } - - return hostBuilder; - } + var result = hb.UseBootstrapperEnvironmentDefaults(); - private static int CountUserSecretsSources(IEnumerable sources) - { - return sources.OfType().Count(IsUserSecretsSource); - } + Assert.Same(hb, result); + Assert.Equal(initialSecretsSourceCount, CountUserSecretsSources(hb.Configuration.Sources)); + } - private static bool IsUserSecretsSource(FileConfigurationSource source) + private static HostApplicationBuilder CreateHostApplicationBuilder(string environmentName, string applicationName, Dictionary? configuration) + { + var settings = new HostApplicationBuilderSettings + { + EnvironmentName = environmentName, + ApplicationName = applicationName + }; + var hostBuilder = Host.CreateApplicationBuilder(settings); + if (configuration is not null) { - return string.Equals(Path.GetFileName(source.Path), "secrets.json", StringComparison.OrdinalIgnoreCase); + hostBuilder.Configuration.AddInMemoryCollection(configuration); } + + return hostBuilder; + } + + private static int CountUserSecretsSources(IEnumerable sources) + { + return sources.OfType().Count(IsUserSecretsSource); + } + + private static bool IsUserSecretsSource(FileConfigurationSource source) + { + return string.Equals(Path.GetFileName(source.Path), "secrets.json", StringComparison.OrdinalIgnoreCase); } } diff --git a/test/Codebelt.Bootstrapper.FunctionalTests/HostBuilderExtensionsTest.cs b/test/Codebelt.Bootstrapper.FunctionalTests/HostBuilderExtensionsTest.cs index b3fcec2..dbf7286 100644 --- a/test/Codebelt.Bootstrapper.FunctionalTests/HostBuilderExtensionsTest.cs +++ b/test/Codebelt.Bootstrapper.FunctionalTests/HostBuilderExtensionsTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -10,92 +10,91 @@ using Microsoft.Extensions.Hosting; using Xunit; -namespace Codebelt.Bootstrapper +namespace Codebelt.Bootstrapper; + +public class HostBuilderExtensionsTest : Test { - public class HostBuilderExtensionsTest : Test + public HostBuilderExtensionsTest(ITestOutputHelper output) : base(output) { - public HostBuilderExtensionsTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public void UseBootstrapperLifetime_ShouldRegisterBootstrapperLifetime() + [Fact] + public void UseBootstrapperLifetime_ShouldRegisterBootstrapperLifetime() + { + using var test = HostTestFactory.Create(services => { - using var test = HostTestFactory.Create(services => - { - }, hb => - { - hb.UseBootstrapperLifetime(); - }); + }, hb => + { + hb.UseBootstrapperLifetime(); + }); - var bootstrapperLifetime = test.Host.Services.GetService(); + var bootstrapperLifetime = test.Host.Services.GetService(); - Assert.NotNull(bootstrapperLifetime); - Assert.IsType(bootstrapperLifetime); - } + Assert.NotNull(bootstrapperLifetime); + Assert.IsType(bootstrapperLifetime); + } - [Fact] - public void UseBootstrapperStartup_ShouldRegisterStartupFactory() + [Fact] + public void UseBootstrapperStartup_ShouldRegisterStartupFactory() + { + using var test = HostTestFactory.Create(services => { - using var test = HostTestFactory.Create(services => - { - }, hb => - { - hb.UseBootstrapperStartup(); - }); + }, hb => + { + hb.UseBootstrapperStartup(); + }); - var startupFactory = test.Host.Services.GetService>(); + var startupFactory = test.Host.Services.GetService>(); - Assert.NotNull(startupFactory); - Assert.IsType>(startupFactory); - } + Assert.NotNull(startupFactory); + Assert.IsType>(startupFactory); + } - [Fact] - public void UseBootstrapperEnvironmentDefaults_ShouldAddUserSecretsProvider_WhenEnvironmentIsLocalDevelopment() + [Fact] + public void UseBootstrapperEnvironmentDefaults_ShouldAddUserSecretsProvider_WhenEnvironmentIsLocalDevelopment() + { + using var host = CreateHost("LocalDevelopment", configureHostBuilder: hb => hb.UseBootstrapperEnvironmentDefaults(), hostConfiguration: new Dictionary { - using var host = CreateHost("LocalDevelopment", configureHostBuilder: hb => hb.UseBootstrapperEnvironmentDefaults(), hostConfiguration: new Dictionary - { - ["hostBuilder:reloadConfigOnChange"] = "false" - }); + ["hostBuilder:reloadConfigOnChange"] = "false" + }); - var userSecretsProvider = Assert.Single(GetConfigurationRoot(host).Providers.OfType().Where(IsUserSecretsProvider)); + var userSecretsProvider = Assert.Single(GetConfigurationRoot(host).Providers.OfType().Where(IsUserSecretsProvider)); - Assert.False(userSecretsProvider.Source.ReloadOnChange); - } + Assert.False(userSecretsProvider.Source.ReloadOnChange); + } - [Fact] - public void UseBootstrapperEnvironmentDefaults_ShouldNotAddUserSecretsProvider_WhenEnvironmentIsNotLocalDevelopment() - { - using var host = CreateHost(Environments.Development, configureHostBuilder: hb => hb.UseBootstrapperEnvironmentDefaults()); + [Fact] + public void UseBootstrapperEnvironmentDefaults_ShouldNotAddUserSecretsProvider_WhenEnvironmentIsNotLocalDevelopment() + { + using var host = CreateHost(Environments.Development, configureHostBuilder: hb => hb.UseBootstrapperEnvironmentDefaults()); - Assert.Empty(GetConfigurationRoot(host).Providers.OfType().Where(IsUserSecretsProvider)); - } + Assert.Empty(GetConfigurationRoot(host).Providers.OfType().Where(IsUserSecretsProvider)); + } - private static IHost CreateHost(string environmentName, Action? configureHostBuilder = null, Dictionary? hostConfiguration = null) - { - var hostBuilder = new HostBuilder() - .UseEnvironment(environmentName) - .ConfigureHostConfiguration(builder => + private static IHost CreateHost(string environmentName, Action? configureHostBuilder = null, Dictionary? hostConfiguration = null) + { + var hostBuilder = new HostBuilder() + .UseEnvironment(environmentName) + .ConfigureHostConfiguration(builder => + { + if (hostConfiguration is not null) { - if (hostConfiguration is not null) - { - builder.AddInMemoryCollection(hostConfiguration); - } - }); + builder.AddInMemoryCollection(hostConfiguration); + } + }); - configureHostBuilder?.Invoke(hostBuilder); + configureHostBuilder?.Invoke(hostBuilder); - return hostBuilder.Build(); - } + return hostBuilder.Build(); + } - private static IConfigurationRoot GetConfigurationRoot(IHost host) - { - return Assert.IsAssignableFrom(host.Services.GetRequiredService()); - } + private static IConfigurationRoot GetConfigurationRoot(IHost host) + { + return Assert.IsAssignableFrom(host.Services.GetRequiredService()); + } - private static bool IsUserSecretsProvider(FileConfigurationProvider provider) - { - return string.Equals(Path.GetFileName(provider.Source.Path), "secrets.json", StringComparison.OrdinalIgnoreCase); - } + private static bool IsUserSecretsProvider(FileConfigurationProvider provider) + { + return string.Equals(Path.GetFileName(provider.Source.Path), "secrets.json", StringComparison.OrdinalIgnoreCase); } } diff --git a/test/Codebelt.Bootstrapper.FunctionalTests/HostedServiceExtensionsTest.cs b/test/Codebelt.Bootstrapper.FunctionalTests/HostedServiceExtensionsTest.cs index d4ebd4f..80214ae 100644 --- a/test/Codebelt.Bootstrapper.FunctionalTests/HostedServiceExtensionsTest.cs +++ b/test/Codebelt.Bootstrapper.FunctionalTests/HostedServiceExtensionsTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using Codebelt.Bootstrapper.Assets; @@ -11,53 +11,52 @@ using Microsoft.Extensions.Hosting; using Xunit; -namespace Codebelt.Bootstrapper +namespace Codebelt.Bootstrapper; + +public class HostedServiceExtensionsTest : Test { - public class HostedServiceExtensionsTest : Test + public HostedServiceExtensionsTest(ITestOutputHelper output) : base(output) { - public HostedServiceExtensionsTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public async Task WaitForApplicationStartedAnnouncementAsync_MustWaitForApplicationStarted() - { - var timeToWait = TimeSpan.FromMilliseconds(500); + [Fact] + public async Task WaitForApplicationStartedAnnouncementAsync_MustWaitForApplicationStarted() + { + var timeToWait = TimeSpan.FromMilliseconds(500); - using var test = HostTestFactory.Create(services => - { - services.AddXunitTestLogging(TestOutput); - services.AddHostedService(); - services.Configure(o => o.ShutdownTimeout = TimeSpan.FromSeconds(5)); - }, hb => - { - hb.UseBootstrapperLifetime(); - }, new TestHostFixture()); + using var test = HostTestFactory.Create(services => + { + services.AddXunitTestLogging(TestOutput); + services.AddHostedService(); + services.Configure(o => o.ShutdownTimeout = TimeSpan.FromSeconds(5)); + }, hb => + { + hb.UseBootstrapperLifetime(); + }, new TestHostFixture()); - var lifetimeEvents = test.Host.Services.GetRequiredService(); + var lifetimeEvents = test.Host.Services.GetRequiredService(); - lifetimeEvents.OnApplicationStartedCallback += () => - { - Thread.Sleep(timeToWait); - }; + lifetimeEvents.OnApplicationStartedCallback += () => + { + Thread.Sleep(timeToWait); + }; - var reset = false; - lifetimeEvents.OnApplicationStoppingCallback += () => - { - reset = true; - }; + var reset = false; + lifetimeEvents.OnApplicationStoppingCallback += () => + { + reset = true; + }; - var bgs = (TestBackgroundService)test.Host.Services.GetRequiredService(); + var bgs = (TestBackgroundService)test.Host.Services.GetRequiredService(); - await test.Host.StartAsync().ConfigureAwait(false); + await test.Host.StartAsync().ConfigureAwait(false); - await Awaiter.RunUntilSuccessfulOrTimeoutAsync(() => reset - ? Task.FromResult(new SuccessfulValue()) - : Task.FromResult(new UnsuccessfulValue())).ConfigureAwait(false); + await Awaiter.RunUntilSuccessfulOrTimeoutAsync(() => reset + ? Task.FromResult(new SuccessfulValue()) + : Task.FromResult(new UnsuccessfulValue())).ConfigureAwait(false); - TestOutput.WriteLine($"{bgs.Elapsed} >= {timeToWait}"); + TestOutput.WriteLine($"{bgs.Elapsed} >= {timeToWait}"); - Assert.True(bgs.Elapsed >= timeToWait, $"{bgs.Elapsed} >= {timeToWait}"); - } + Assert.True(bgs.Elapsed >= timeToWait, $"{bgs.Elapsed} >= {timeToWait}"); } } diff --git a/test/Codebelt.Bootstrapper.Tests/Assets/StartupRootUnsafeAccessor.cs b/test/Codebelt.Bootstrapper.Tests/Assets/StartupRootUnsafeAccessor.cs index fca1272..ec16781 100644 --- a/test/Codebelt.Bootstrapper.Tests/Assets/StartupRootUnsafeAccessor.cs +++ b/test/Codebelt.Bootstrapper.Tests/Assets/StartupRootUnsafeAccessor.cs @@ -1,15 +1,14 @@ -using System.Runtime.CompilerServices; +using System.Runtime.CompilerServices; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Assets +namespace Codebelt.Bootstrapper.Assets; + +public static class StartupRootUnsafeAccessor { - public static class StartupRootUnsafeAccessor - { - [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Configuration")] - public static extern IConfiguration GetConfiguration(StartupRoot startup); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Configuration")] + public static extern IConfiguration GetConfiguration(StartupRoot startup); - [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Environment")] - public static extern IHostEnvironment GetEnvironment(StartupRoot startup); - } + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Environment")] + public static extern IHostEnvironment GetEnvironment(StartupRoot startup); } diff --git a/test/Codebelt.Bootstrapper.Tests/Assets/TestStartupRoot.cs b/test/Codebelt.Bootstrapper.Tests/Assets/TestStartupRoot.cs index 34df4c4..72956b9 100644 --- a/test/Codebelt.Bootstrapper.Tests/Assets/TestStartupRoot.cs +++ b/test/Codebelt.Bootstrapper.Tests/Assets/TestStartupRoot.cs @@ -2,19 +2,18 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Assets +namespace Codebelt.Bootstrapper.Assets; + +public class TestStartupRoot : StartupRoot { - public class TestStartupRoot : StartupRoot + public TestStartupRoot(IConfiguration configuration, IHostEnvironment environment) + : base(configuration, environment) { - public TestStartupRoot(IConfiguration configuration, IHostEnvironment environment) - : base(configuration, environment) - { - } + } - public override void ConfigureServices(IServiceCollection services) - { - // Add test services here - services.AddSingleton("TestService"); - } + public override void ConfigureServices(IServiceCollection services) + { + // Add test services here + services.AddSingleton("TestService"); } } diff --git a/test/Codebelt.Bootstrapper.Tests/CommandLineContextTest.cs b/test/Codebelt.Bootstrapper.Tests/CommandLineContextTest.cs index 3be7d03..809a81a 100644 --- a/test/Codebelt.Bootstrapper.Tests/CommandLineContextTest.cs +++ b/test/Codebelt.Bootstrapper.Tests/CommandLineContextTest.cs @@ -1,86 +1,85 @@ using Codebelt.Extensions.Xunit; using Xunit; -namespace Codebelt.Bootstrapper +namespace Codebelt.Bootstrapper; + +public class CommandLineContextTest : Test { - public class CommandLineContextTest : Test + public CommandLineContextTest(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public void Constructor_ShouldInitializeWithEmptyArray_WhenArgsIsNull() + { + // Act + var context = new CommandLineContext(null); + + // Assert + Assert.NotNull(context.Args); + Assert.Empty(context.Args); + } + + [Fact] + public void Constructor_ShouldInitializeWithProvidedArray_WhenArgsIsEmpty() + { + // Arrange + var args = new string[] { }; + + // Act + var context = new CommandLineContext(args); + + // Assert + Assert.NotNull(context.Args); + Assert.Empty(context.Args); + Assert.Same(args, context.Args); + } + + [Fact] + public void Constructor_ShouldInitializeWithProvidedArray_WhenArgsContainsValues() { - public CommandLineContextTest(ITestOutputHelper output) : base(output) - { - } - - [Fact] - public void Constructor_ShouldInitializeWithEmptyArray_WhenArgsIsNull() - { - // Act - var context = new CommandLineContext(null); - - // Assert - Assert.NotNull(context.Args); - Assert.Empty(context.Args); - } - - [Fact] - public void Constructor_ShouldInitializeWithProvidedArray_WhenArgsIsEmpty() - { - // Arrange - var args = new string[] { }; - - // Act - var context = new CommandLineContext(args); - - // Assert - Assert.NotNull(context.Args); - Assert.Empty(context.Args); - Assert.Same(args, context.Args); - } - - [Fact] - public void Constructor_ShouldInitializeWithProvidedArray_WhenArgsContainsValues() - { - // Arrange - var args = new[] { "arg1", "arg2", "arg3" }; - - // Act - var context = new CommandLineContext(args); - - // Assert - Assert.NotNull(context.Args); - Assert.Equal(3, context.Args.Length); - Assert.Equal("arg1", context.Args[0]); - Assert.Equal("arg2", context.Args[1]); - Assert.Equal("arg3", context.Args[2]); - Assert.Same(args, context.Args); - } - - [Fact] - public void ArgsProperty_ShouldReturnActualReference_WhenMultipleAccessesOccur() - { - // Arrange - var args = new[] { "value1", "value2" }; - var context = new CommandLineContext(args); - - // Act - var firstAccess = context.Args; - var secondAccess = context.Args; - - // Assert - Assert.Same(firstAccess, secondAccess); - Assert.Same(args, firstAccess); - } - - [Fact] - public void Constructor_ShouldPreserveSingleArgument_WhenArgsProvidesOne() - { - // Arrange - var args = new[] { "--debug" }; - - // Act - var context = new CommandLineContext(args); - - // Assert - Assert.Single(context.Args); - Assert.Equal("--debug", context.Args[0]); - } + // Arrange + var args = new[] { "arg1", "arg2", "arg3" }; + + // Act + var context = new CommandLineContext(args); + + // Assert + Assert.NotNull(context.Args); + Assert.Equal(3, context.Args.Length); + Assert.Equal("arg1", context.Args[0]); + Assert.Equal("arg2", context.Args[1]); + Assert.Equal("arg3", context.Args[2]); + Assert.Same(args, context.Args); + } + + [Fact] + public void ArgsProperty_ShouldReturnActualReference_WhenMultipleAccessesOccur() + { + // Arrange + var args = new[] { "value1", "value2" }; + var context = new CommandLineContext(args); + + // Act + var firstAccess = context.Args; + var secondAccess = context.Args; + + // Assert + Assert.Same(firstAccess, secondAccess); + Assert.Same(args, firstAccess); + } + + [Fact] + public void Constructor_ShouldPreserveSingleArgument_WhenArgsProvidesOne() + { + // Arrange + var args = new[] { "--debug" }; + + // Act + var context = new CommandLineContext(args); + + // Assert + Assert.Single(context.Args); + Assert.Equal("--debug", context.Args[0]); } } diff --git a/test/Codebelt.Bootstrapper.Tests/StartupRootTest.cs b/test/Codebelt.Bootstrapper.Tests/StartupRootTest.cs index 7a0dfb6..6a85869 100644 --- a/test/Codebelt.Bootstrapper.Tests/StartupRootTest.cs +++ b/test/Codebelt.Bootstrapper.Tests/StartupRootTest.cs @@ -8,73 +8,72 @@ using Microsoft.Extensions.Hosting.Internal; using Xunit; -namespace Codebelt.Bootstrapper +namespace Codebelt.Bootstrapper; + +public class StartupRootTest : Test { - public class StartupRootTest : Test + private readonly IConfiguration _configuration; + private readonly IHostEnvironment _environment; + + public StartupRootTest(ITestOutputHelper output) : base(output) { - private readonly IConfiguration _configuration; - private readonly IHostEnvironment _environment; + var inMemorySettings = new Dictionary { + {"TestKey", "TestValue"} + }; - public StartupRootTest(ITestOutputHelper output) : base(output) - { - var inMemorySettings = new Dictionary { - {"TestKey", "TestValue"} - }; - - _configuration = new ConfigurationBuilder() - .AddInMemoryCollection(inMemorySettings) - .Build(); - - _environment = new HostingEnvironment() - { - EnvironmentName = Environments.Development, - ApplicationName = "TestApp", - ContentRootPath = Directory.GetCurrentDirectory() - }; - } - - [Fact] - public void ConfigurationProperty_ShouldReturnInjectedConfiguration() + _configuration = new ConfigurationBuilder() + .AddInMemoryCollection(inMemorySettings) + .Build(); + + _environment = new HostingEnvironment() { - // Arrange - var startup = new TestStartupRoot(_configuration, _environment); + EnvironmentName = Environments.Development, + ApplicationName = "TestApp", + ContentRootPath = Directory.GetCurrentDirectory() + }; + } - // Act - var configuration = StartupRootUnsafeAccessor.GetConfiguration(startup); + [Fact] + public void ConfigurationProperty_ShouldReturnInjectedConfiguration() + { + // Arrange + var startup = new TestStartupRoot(_configuration, _environment); - // Assert - Assert.Equal(_configuration, configuration); - } + // Act + var configuration = StartupRootUnsafeAccessor.GetConfiguration(startup); + // Assert + Assert.Equal(_configuration, configuration); + } - [Fact] - public void EnvironmentProperty_ShouldReturnInjectedEnvironment() - { - // Arrange - var startup = new TestStartupRoot(_configuration, _environment); - // Act - var environment = StartupRootUnsafeAccessor.GetEnvironment(startup); + [Fact] + public void EnvironmentProperty_ShouldReturnInjectedEnvironment() + { + // Arrange + var startup = new TestStartupRoot(_configuration, _environment); - // Assert - Assert.Equal(_environment, environment); - } + // Act + var environment = StartupRootUnsafeAccessor.GetEnvironment(startup); - [Fact] - public void ConfigureServices_ShouldAddServicesToServiceCollection() - { - // Arrange - var services = new ServiceCollection(); - var startup = new TestStartupRoot(_configuration, _environment); - - // Act - startup.ConfigureServices(services); - var serviceProvider = services.BuildServiceProvider(); - var testService = serviceProvider.GetService(); - - // Assert - Assert.Equal("TestService", testService); - } + // Assert + Assert.Equal(_environment, environment); + } + + [Fact] + public void ConfigureServices_ShouldAddServicesToServiceCollection() + { + // Arrange + var services = new ServiceCollection(); + var startup = new TestStartupRoot(_configuration, _environment); + + // Act + startup.ConfigureServices(services); + var serviceProvider = services.BuildServiceProvider(); + var testService = serviceProvider.GetService(); + + // Assert + Assert.Equal("TestService", testService); } } diff --git a/test/Codebelt.Bootstrapper.Web.FunctionalTests/Assets/TestMinimalWebProgram.cs b/test/Codebelt.Bootstrapper.Web.FunctionalTests/Assets/TestMinimalWebProgram.cs index be07474..93b730c 100644 --- a/test/Codebelt.Bootstrapper.Web.FunctionalTests/Assets/TestMinimalWebProgram.cs +++ b/test/Codebelt.Bootstrapper.Web.FunctionalTests/Assets/TestMinimalWebProgram.cs @@ -1,9 +1,8 @@ using Microsoft.AspNetCore.Builder; -namespace Codebelt.Bootstrapper.Web.Assets +namespace Codebelt.Bootstrapper.Web.Assets; + +internal class TestMinimalWebProgram : MinimalWebProgram { - internal class TestMinimalWebProgram : MinimalWebProgram - { - public static WebApplicationBuilder CreateHostBuilderAccessor(string[] args) => CreateHostBuilder(args); - } + public static WebApplicationBuilder CreateHostBuilderAccessor(string[] args) => CreateHostBuilder(args); } diff --git a/test/Codebelt.Bootstrapper.Web.FunctionalTests/Assets/TestStartup.cs b/test/Codebelt.Bootstrapper.Web.FunctionalTests/Assets/TestStartup.cs index ca5d316..d808b04 100644 --- a/test/Codebelt.Bootstrapper.Web.FunctionalTests/Assets/TestStartup.cs +++ b/test/Codebelt.Bootstrapper.Web.FunctionalTests/Assets/TestStartup.cs @@ -1,38 +1,37 @@ -using Cuemon.Extensions.Hosting; +using Cuemon.Extensions.Hosting; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Web.Assets +namespace Codebelt.Bootstrapper.Web.Assets; + +public class TestStartup : WebStartup { - public class TestStartup : WebStartup + public TestStartup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) { - public TestStartup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) - { - } + } - public override void ConfigureServices(IServiceCollection services) - { - } + public override void ConfigureServices(IServiceCollection services) + { + } - public override void ConfigurePipeline(IApplicationBuilder app) + public override void ConfigurePipeline(IApplicationBuilder app) + { + if (Environment.IsLocalDevelopment()) { - if (Environment.IsLocalDevelopment()) - { - app.UseDeveloperExceptionPage(); - } + app.UseDeveloperExceptionPage(); + } - app.UseRouting(); + app.UseRouting(); - app.UseEndpoints(endpoints => + app.UseEndpoints(endpoints => + { + endpoints.MapGet("/", async context => { - endpoints.MapGet("/", async context => - { - await context.Response.WriteAsync("Hello World!"); - }); + await context.Response.WriteAsync("Hello World!"); }); - } + }); } } diff --git a/test/Codebelt.Bootstrapper.Web.FunctionalTests/Assets/TestWebProgram.cs b/test/Codebelt.Bootstrapper.Web.FunctionalTests/Assets/TestWebProgram.cs index 491049a..ad5833e 100644 --- a/test/Codebelt.Bootstrapper.Web.FunctionalTests/Assets/TestWebProgram.cs +++ b/test/Codebelt.Bootstrapper.Web.FunctionalTests/Assets/TestWebProgram.cs @@ -1,9 +1,8 @@ using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Web.Assets +namespace Codebelt.Bootstrapper.Web.Assets; + +internal class TestWebProgram : WebProgram { - internal class TestWebProgram : WebProgram - { - public static IHostBuilder CreateHostBuilderAccessor(string[] args) => CreateHostBuilder(args); - } + public static IHostBuilder CreateHostBuilderAccessor(string[] args) => CreateHostBuilder(args); } diff --git a/test/Codebelt.Bootstrapper.Web.FunctionalTests/MinimalWebProgramBuilderTest.cs b/test/Codebelt.Bootstrapper.Web.FunctionalTests/MinimalWebProgramBuilderTest.cs index 58f16bd..e6535ff 100644 --- a/test/Codebelt.Bootstrapper.Web.FunctionalTests/MinimalWebProgramBuilderTest.cs +++ b/test/Codebelt.Bootstrapper.Web.FunctionalTests/MinimalWebProgramBuilderTest.cs @@ -7,34 +7,33 @@ using Microsoft.Extensions.Hosting; using Xunit; -namespace Codebelt.Bootstrapper.Web +namespace Codebelt.Bootstrapper.Web; + +public class MinimalWebProgramBuilderTest : Test { - public class MinimalWebProgramBuilderTest : Test + public MinimalWebProgramBuilderTest(ITestOutputHelper output) : base(output) { - public MinimalWebProgramBuilderTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public async Task CreateHostBuilder_ShouldRegisterBootstrapperLifetime() - { - var builder = TestMinimalWebProgram.CreateHostBuilderAccessor([]); - builder.WebHost.UseTestServer(); + [Fact] + public async Task CreateHostBuilder_ShouldRegisterBootstrapperLifetime() + { + var builder = TestMinimalWebProgram.CreateHostBuilderAccessor([]); + builder.WebHost.UseTestServer(); - await using var app = builder.Build(); - app.MapGet("/", () => "Hello World!"); + await using var app = builder.Build(); + app.MapGet("/", () => "Hello World!"); - await app.StartAsync(); - try - { - var client = app.GetTestClient(); + await app.StartAsync(); + try + { + var client = app.GetTestClient(); - Assert.Equal("Hello World!", await client.GetStringAsync("/")); - } - finally - { - await app.StopAsync(); - } + Assert.Equal("Hello World!", await client.GetStringAsync("/")); + } + finally + { + await app.StopAsync(); } } } diff --git a/test/Codebelt.Bootstrapper.Web.FunctionalTests/MinimalWebProgramTest.cs b/test/Codebelt.Bootstrapper.Web.FunctionalTests/MinimalWebProgramTest.cs index af47395..f851930 100644 --- a/test/Codebelt.Bootstrapper.Web.FunctionalTests/MinimalWebProgramTest.cs +++ b/test/Codebelt.Bootstrapper.Web.FunctionalTests/MinimalWebProgramTest.cs @@ -1,4 +1,4 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Codebelt.Extensions.Xunit; using Codebelt.Extensions.Xunit.Hosting; using Codebelt.Extensions.Xunit.Hosting.AspNetCore; @@ -7,44 +7,43 @@ using Microsoft.AspNetCore.Http; using Xunit; -namespace Codebelt.Bootstrapper.Web +namespace Codebelt.Bootstrapper.Web; + +public class MinimalWebProgramTest : Test { - public class MinimalWebProgramTest : Test + public MinimalWebProgramTest(ITestOutputHelper output) : base(output) { - public MinimalWebProgramTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public async Task ExecuteAsync_ShouldSimulateAMinimalWebApplication() + [Fact] + public async Task ExecuteAsync_ShouldSimulateAMinimalWebApplication() + { + using var test = await MinimalWebHostTestFactory.RunWithHostBuilderContextAsync((context, services) => { - using var test = await MinimalWebHostTestFactory.RunWithHostBuilderContextAsync((context, services) => - { - services.AddXunitTestLogging(TestOutput); - }, (context, app) => + services.AddXunitTestLogging(TestOutput); + }, (context, app) => + { + if (context.HostingEnvironment.IsLocalDevelopment()) { - if (context.HostingEnvironment.IsLocalDevelopment()) - { - app.UseDeveloperExceptionPage(); - } + app.UseDeveloperExceptionPage(); + } - app.UseRouting(); + app.UseRouting(); - app.UseEndpoints(endpoints => + app.UseEndpoints(endpoints => + { + endpoints.MapGet("/", async context => { - endpoints.MapGet("/", async context => - { - await context.Response.WriteAsync("Hello World!"); - }); + await context.Response.WriteAsync("Hello World!"); }); - }, hb => - { - hb.UseBootstrapperLifetime(); }); + }, hb => + { + hb.UseBootstrapperLifetime(); + }); - var helloWorld = await test.Content.ReadAsStringAsync(); + var helloWorld = await test.Content.ReadAsStringAsync(); - Assert.Equal("Hello World!", helloWorld); - } + Assert.Equal("Hello World!", helloWorld); } } diff --git a/test/Codebelt.Bootstrapper.Web.FunctionalTests/WebProgramTest.cs b/test/Codebelt.Bootstrapper.Web.FunctionalTests/WebProgramTest.cs index 0ee69d3..ac4d692 100644 --- a/test/Codebelt.Bootstrapper.Web.FunctionalTests/WebProgramTest.cs +++ b/test/Codebelt.Bootstrapper.Web.FunctionalTests/WebProgramTest.cs @@ -6,32 +6,31 @@ using Microsoft.Extensions.Hosting; using Xunit; -namespace Codebelt.Bootstrapper.Web +namespace Codebelt.Bootstrapper.Web; + +public class WebProgramTest : Test { - public class WebProgramTest : Test + public WebProgramTest(ITestOutputHelper output) : base(output) { - public WebProgramTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public async Task CreateHostBuilder_ShouldRegisterBootstrapperLifetimeAndStartup() - { - var builder = TestWebProgram.CreateHostBuilderAccessor([]); - builder.ConfigureWebHost(webBuilder => webBuilder.UseTestServer()); + [Fact] + public async Task CreateHostBuilder_ShouldRegisterBootstrapperLifetimeAndStartup() + { + var builder = TestWebProgram.CreateHostBuilderAccessor([]); + builder.ConfigureWebHost(webBuilder => webBuilder.UseTestServer()); - using var host = builder.Build(); - await host.StartAsync(); - try - { - var client = host.GetTestClient(); + using var host = builder.Build(); + await host.StartAsync(); + try + { + var client = host.GetTestClient(); - Assert.Equal("Hello World!", await client.GetStringAsync("/")); - } - finally - { - await host.StopAsync(); - } + Assert.Equal("Hello World!", await client.GetStringAsync("/")); + } + finally + { + await host.StopAsync(); } } } diff --git a/test/Codebelt.Bootstrapper.Web.FunctionalTests/WebStartupTest.cs b/test/Codebelt.Bootstrapper.Web.FunctionalTests/WebStartupTest.cs index 00632db..a7cfab1 100644 --- a/test/Codebelt.Bootstrapper.Web.FunctionalTests/WebStartupTest.cs +++ b/test/Codebelt.Bootstrapper.Web.FunctionalTests/WebStartupTest.cs @@ -1,4 +1,4 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Codebelt.Bootstrapper.Web.Assets; using Codebelt.Extensions.Xunit; using Codebelt.Extensions.Xunit.Hosting; @@ -8,33 +8,32 @@ using Microsoft.Extensions.Hosting; using Xunit; -namespace Codebelt.Bootstrapper.Web +namespace Codebelt.Bootstrapper.Web; + +public class WebStartupTest : Test { - public class WebStartupTest : Test + public WebStartupTest(ITestOutputHelper output) : base(output) { - public WebStartupTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public async Task ConfigurePipeline_ShouldSimulateAWebApplication() + [Fact] + public async Task ConfigurePipeline_ShouldSimulateAWebApplication() + { + using var test = await WebHostTestFactory.RunWithHostBuilderContextAsync((context, services) => + { + services.AddXunitTestLogging(TestOutput); + }, hostSetup: hb => { - using var test = await WebHostTestFactory.RunWithHostBuilderContextAsync((context, services) => - { - services.AddXunitTestLogging(TestOutput); - }, hostSetup: hb => - { - hb.UseBootstrapperLifetime() - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseTestServer(o => o.PreserveExecutionContext = true); - webBuilder.UseStartup(); - }); - }); + hb.UseBootstrapperLifetime() + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseTestServer(o => o.PreserveExecutionContext = true); + webBuilder.UseStartup(); + }); + }); - var helloWorld = await test.Content.ReadAsStringAsync(); + var helloWorld = await test.Content.ReadAsStringAsync(); - Assert.Equal("Hello World!", helloWorld); - } + Assert.Equal("Hello World!", helloWorld); } } diff --git a/test/Codebelt.Bootstrapper.Worker.FunctionalTests/Assets/FakeHostedService.cs b/test/Codebelt.Bootstrapper.Worker.FunctionalTests/Assets/FakeHostedService.cs index 8052d87..16ebdfa 100644 --- a/test/Codebelt.Bootstrapper.Worker.FunctionalTests/Assets/FakeHostedService.cs +++ b/test/Codebelt.Bootstrapper.Worker.FunctionalTests/Assets/FakeHostedService.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -7,48 +7,47 @@ using System.Threading; using System.Threading.Tasks; -namespace Codebelt.Bootstrapper.Worker.Assets +namespace Codebelt.Bootstrapper.Worker.Assets; + +public class FakeHostedService : BackgroundService { - public class FakeHostedService : BackgroundService + private readonly TaskCompletionSource _tsc = new(); + private readonly ILogger _logger; + private readonly IHostLifetimeEvents _events; + private bool _gracefulShutdown; + + public FakeHostedService(ILogger logger, IHostLifetimeEvents events) { - private readonly TaskCompletionSource _tsc = new(); - private readonly ILogger _logger; - private readonly IHostLifetimeEvents _events; - private bool _gracefulShutdown; + _logger = logger; - public FakeHostedService(ILogger logger, IHostLifetimeEvents events) + events.OnApplicationStartedCallback = () => + { + logger.LogInformation("Started"); + _tsc.SetResult(); + }; + events.OnApplicationStoppingCallback = () => { - _logger = logger; + _gracefulShutdown = true; + logger.LogWarning("Stopping and cleaning .."); + Thread.Sleep(TimeSpan.FromMilliseconds(125)); // simulate graceful shutdown + logger.LogWarning(".. done!"); + }; + events.OnApplicationStoppedCallback = () => logger.LogCritical("Stopped"); - events.OnApplicationStartedCallback = () => - { - logger.LogInformation("Started"); - _tsc.SetResult(); - }; - events.OnApplicationStoppingCallback = () => - { - _gracefulShutdown = true; - logger.LogWarning("Stopping and cleaning .."); - Thread.Sleep(TimeSpan.FromMilliseconds(125)); // simulate graceful shutdown - logger.LogWarning(".. done!"); - }; - events.OnApplicationStoppedCallback = () => logger.LogCritical("Stopped"); - - _events = events; - } + _events = events; + } - protected override async Task ExecuteAsync(CancellationToken stoppingToken) + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + await _tsc.Task.ConfigureAwait(false); + var i = 1; + while (!stoppingToken.IsCancellationRequested) { - await _tsc.Task.ConfigureAwait(false); - var i = 1; - while (!stoppingToken.IsCancellationRequested) - { - if (_gracefulShutdown) { return; } - _logger.LogInformation("Worker running in iterations: {iteration}", i); - i++; - await Task.Delay(TimeSpan.FromMilliseconds(500), stoppingToken); - if (i == 6) { break; } - } + if (_gracefulShutdown) { return; } + _logger.LogInformation("Worker running in iterations: {iteration}", i); + i++; + await Task.Delay(TimeSpan.FromMilliseconds(500), stoppingToken); + if (i == 6) { break; } } } } diff --git a/test/Codebelt.Bootstrapper.Worker.FunctionalTests/Assets/TestMinimalWorkerProgram.cs b/test/Codebelt.Bootstrapper.Worker.FunctionalTests/Assets/TestMinimalWorkerProgram.cs index c30f100..773aafd 100644 --- a/test/Codebelt.Bootstrapper.Worker.FunctionalTests/Assets/TestMinimalWorkerProgram.cs +++ b/test/Codebelt.Bootstrapper.Worker.FunctionalTests/Assets/TestMinimalWorkerProgram.cs @@ -1,9 +1,8 @@ using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Worker.Assets +namespace Codebelt.Bootstrapper.Worker.Assets; + +internal class TestMinimalWorkerProgram : MinimalWorkerProgram { - internal class TestMinimalWorkerProgram : MinimalWorkerProgram - { - public static HostApplicationBuilder CreateHostBuilderAccessor(string[] args) => CreateHostBuilder(args); - } + public static HostApplicationBuilder CreateHostBuilderAccessor(string[] args) => CreateHostBuilder(args); } diff --git a/test/Codebelt.Bootstrapper.Worker.FunctionalTests/Assets/TestStartup.cs b/test/Codebelt.Bootstrapper.Worker.FunctionalTests/Assets/TestStartup.cs index 8ac50cb..ef3d50d 100644 --- a/test/Codebelt.Bootstrapper.Worker.FunctionalTests/Assets/TestStartup.cs +++ b/test/Codebelt.Bootstrapper.Worker.FunctionalTests/Assets/TestStartup.cs @@ -1,18 +1,17 @@ -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Worker.Assets +namespace Codebelt.Bootstrapper.Worker.Assets; + +public class TestStartup : WorkerStartup { - public class TestStartup : WorkerStartup + public TestStartup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) { - public TestStartup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) - { - } + } - public override void ConfigureServices(IServiceCollection services) - { - services.AddHostedService(); - } + public override void ConfigureServices(IServiceCollection services) + { + services.AddHostedService(); } } diff --git a/test/Codebelt.Bootstrapper.Worker.FunctionalTests/Assets/TestWorkerProgram.cs b/test/Codebelt.Bootstrapper.Worker.FunctionalTests/Assets/TestWorkerProgram.cs index f4e4d1a..7b6c71b 100644 --- a/test/Codebelt.Bootstrapper.Worker.FunctionalTests/Assets/TestWorkerProgram.cs +++ b/test/Codebelt.Bootstrapper.Worker.FunctionalTests/Assets/TestWorkerProgram.cs @@ -1,9 +1,8 @@ using Microsoft.Extensions.Hosting; -namespace Codebelt.Bootstrapper.Worker.Assets +namespace Codebelt.Bootstrapper.Worker.Assets; + +internal class TestWorkerProgram : WorkerProgram { - internal class TestWorkerProgram : WorkerProgram - { - public static IHostBuilder CreateHostBuilderAccessor(string[] args) => CreateHostBuilder(args); - } + public static IHostBuilder CreateHostBuilderAccessor(string[] args) => CreateHostBuilder(args); } diff --git a/test/Codebelt.Bootstrapper.Worker.FunctionalTests/MinimalWorkerProgramBuilderTest.cs b/test/Codebelt.Bootstrapper.Worker.FunctionalTests/MinimalWorkerProgramBuilderTest.cs index 2933724..600ec40 100644 --- a/test/Codebelt.Bootstrapper.Worker.FunctionalTests/MinimalWorkerProgramBuilderTest.cs +++ b/test/Codebelt.Bootstrapper.Worker.FunctionalTests/MinimalWorkerProgramBuilderTest.cs @@ -4,22 +4,21 @@ using Microsoft.Extensions.Hosting; using Xunit; -namespace Codebelt.Bootstrapper.Worker +namespace Codebelt.Bootstrapper.Worker; + +public class MinimalWorkerProgramBuilderTest : Test { - public class MinimalWorkerProgramBuilderTest : Test + public MinimalWorkerProgramBuilderTest(ITestOutputHelper output) : base(output) { - public MinimalWorkerProgramBuilderTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public void CreateHostBuilder_ShouldRegisterBootstrapperLifetime() - { - using var host = TestMinimalWorkerProgram.CreateHostBuilderAccessor([]).Build(); + [Fact] + public void CreateHostBuilder_ShouldRegisterBootstrapperLifetime() + { + using var host = TestMinimalWorkerProgram.CreateHostBuilderAccessor([]).Build(); - var lifetime = host.Services.GetRequiredService(); + var lifetime = host.Services.GetRequiredService(); - Assert.IsType(lifetime); - } + Assert.IsType(lifetime); } } diff --git a/test/Codebelt.Bootstrapper.Worker.FunctionalTests/MinimalWorkerProgramTest.cs b/test/Codebelt.Bootstrapper.Worker.FunctionalTests/MinimalWorkerProgramTest.cs index a4bf1bb..10c29db 100644 --- a/test/Codebelt.Bootstrapper.Worker.FunctionalTests/MinimalWorkerProgramTest.cs +++ b/test/Codebelt.Bootstrapper.Worker.FunctionalTests/MinimalWorkerProgramTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading; using Codebelt.Extensions.Xunit; using System.Threading.Tasks; @@ -9,43 +9,42 @@ using Microsoft.Extensions.Logging; using Xunit; -namespace Codebelt.Bootstrapper.Worker +namespace Codebelt.Bootstrapper.Worker; + +public class MinimalWorkerProgramTest : Test { - public class MinimalWorkerProgramTest : Test + public MinimalWorkerProgramTest(ITestOutputHelper output) : base(output) { - public MinimalWorkerProgramTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public async Task ExecuteAsync_ShouldSimulateAMinimalWorkerService() + [Fact] + public async Task ExecuteAsync_ShouldSimulateAMinimalWorkerService() + { + await using var test = MinimalHostTestFactory.Create(services => + { + services.AddXunitTestLogging(TestOutput); + services.AddHostedService(); + }, hb => { - await using var test = MinimalHostTestFactory.Create(services => - { - services.AddXunitTestLogging(TestOutput); - services.AddHostedService(); - }, hb => - { - hb.UseBootstrapperLifetime(); - }, new SelfManagedMinimalHostFixture()); + hb.UseBootstrapperLifetime(); + }, new SelfManagedMinimalHostFixture()); - var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); + var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); - await test.Host.StartAsync(cts.Token); - await test.Host.WaitForShutdownAsync(cts.Token); + await test.Host.StartAsync(cts.Token); + await test.Host.WaitForShutdownAsync(cts.Token); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.Collection(loggerStore.Query(), - entry => Assert.Equal("Information: Started", entry.Message), - entry => Assert.Equal("Information: Worker running in iterations: 1", entry.Message), - entry => Assert.Equal("Information: Worker running in iterations: 2", entry.Message), - entry => Assert.Equal("Information: Worker running in iterations: 3", entry.Message), - entry => Assert.Equal("Information: Worker running in iterations: 4", entry.Message), - entry => Assert.Equal("Information: Worker running in iterations: 5", entry.Message), - entry => Assert.Equal("Warning: Stopping and cleaning ..", entry.Message), - entry => Assert.Equal("Warning: .. done!", entry.Message), - entry => Assert.Equal("Critical: Stopped", entry.Message) - ); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.Collection(loggerStore.Query(), + entry => Assert.Equal("Information: Started", entry.Message), + entry => Assert.Equal("Information: Worker running in iterations: 1", entry.Message), + entry => Assert.Equal("Information: Worker running in iterations: 2", entry.Message), + entry => Assert.Equal("Information: Worker running in iterations: 3", entry.Message), + entry => Assert.Equal("Information: Worker running in iterations: 4", entry.Message), + entry => Assert.Equal("Information: Worker running in iterations: 5", entry.Message), + entry => Assert.Equal("Warning: Stopping and cleaning ..", entry.Message), + entry => Assert.Equal("Warning: .. done!", entry.Message), + entry => Assert.Equal("Critical: Stopped", entry.Message) + ); } } diff --git a/test/Codebelt.Bootstrapper.Worker.FunctionalTests/WorkerProgramTest.cs b/test/Codebelt.Bootstrapper.Worker.FunctionalTests/WorkerProgramTest.cs index a461ffe..86491db 100644 --- a/test/Codebelt.Bootstrapper.Worker.FunctionalTests/WorkerProgramTest.cs +++ b/test/Codebelt.Bootstrapper.Worker.FunctionalTests/WorkerProgramTest.cs @@ -4,24 +4,23 @@ using Microsoft.Extensions.Hosting; using Xunit; -namespace Codebelt.Bootstrapper.Worker +namespace Codebelt.Bootstrapper.Worker; + +public class WorkerProgramTest : Test { - public class WorkerProgramTest : Test + public WorkerProgramTest(ITestOutputHelper output) : base(output) { - public WorkerProgramTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public void CreateHostBuilder_ShouldRegisterBootstrapperLifetimeAndStartup() - { - using var host = TestWorkerProgram.CreateHostBuilderAccessor([]).Build(); + [Fact] + public void CreateHostBuilder_ShouldRegisterBootstrapperLifetimeAndStartup() + { + using var host = TestWorkerProgram.CreateHostBuilderAccessor([]).Build(); - var lifetime = host.Services.GetRequiredService(); - var startupFactory = host.Services.GetRequiredService>(); + var lifetime = host.Services.GetRequiredService(); + var startupFactory = host.Services.GetRequiredService>(); - Assert.IsType(lifetime); - Assert.IsType>(startupFactory); - } + Assert.IsType(lifetime); + Assert.IsType>(startupFactory); } } diff --git a/test/Codebelt.Bootstrapper.Worker.FunctionalTests/WorkerStartupTest.cs b/test/Codebelt.Bootstrapper.Worker.FunctionalTests/WorkerStartupTest.cs index 5ec6c90..cb0313d 100644 --- a/test/Codebelt.Bootstrapper.Worker.FunctionalTests/WorkerStartupTest.cs +++ b/test/Codebelt.Bootstrapper.Worker.FunctionalTests/WorkerStartupTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using Codebelt.Bootstrapper.Worker.Assets; @@ -9,43 +9,42 @@ using Microsoft.Extensions.Logging; using Xunit; -namespace Codebelt.Bootstrapper.Worker +namespace Codebelt.Bootstrapper.Worker; + +public class WorkerStartupTest : Test { - public class WorkerStartupTest : Test + public WorkerStartupTest(ITestOutputHelper output) : base(output) { - public WorkerStartupTest(ITestOutputHelper output) : base(output) - { - } + } - [Fact] - public async Task ExecuteAsync_ShouldSimulateAWorkerService() + [Fact] + public async Task ExecuteAsync_ShouldSimulateAWorkerService() + { + await using var test = HostTestFactory.Create(services => + { + services.AddXunitTestLogging(TestOutput); + }, hb => { - await using var test = HostTestFactory.Create(services => - { - services.AddXunitTestLogging(TestOutput); - }, hb => - { - hb.UseBootstrapperLifetime() - .UseBootstrapperStartup(); - }, new SelfManagedHostFixture()); + hb.UseBootstrapperLifetime() + .UseBootstrapperStartup(); + }, new SelfManagedHostFixture()); - var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); + var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); - await test.Host.StartAsync(cts.Token); - await test.Host.WaitForShutdownAsync(cts.Token); + await test.Host.StartAsync(cts.Token); + await test.Host.WaitForShutdownAsync(cts.Token); - var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); - Assert.Collection(loggerStore.Query(), - entry => Assert.Equal("Information: Started", entry.Message), - entry => Assert.Equal("Information: Worker running in iterations: 1", entry.Message), - entry => Assert.Equal("Information: Worker running in iterations: 2", entry.Message), - entry => Assert.Equal("Information: Worker running in iterations: 3", entry.Message), - entry => Assert.Equal("Information: Worker running in iterations: 4", entry.Message), - entry => Assert.Equal("Information: Worker running in iterations: 5", entry.Message), - entry => Assert.Equal("Warning: Stopping and cleaning ..", entry.Message), - entry => Assert.Equal("Warning: .. done!", entry.Message), - entry => Assert.Equal("Critical: Stopped", entry.Message) - ); - } + var loggerStore = test.Host.Services.GetRequiredService>().GetTestStore(); + Assert.Collection(loggerStore.Query(), + entry => Assert.Equal("Information: Started", entry.Message), + entry => Assert.Equal("Information: Worker running in iterations: 1", entry.Message), + entry => Assert.Equal("Information: Worker running in iterations: 2", entry.Message), + entry => Assert.Equal("Information: Worker running in iterations: 3", entry.Message), + entry => Assert.Equal("Information: Worker running in iterations: 4", entry.Message), + entry => Assert.Equal("Information: Worker running in iterations: 5", entry.Message), + entry => Assert.Equal("Warning: Stopping and cleaning ..", entry.Message), + entry => Assert.Equal("Warning: .. done!", entry.Message), + entry => Assert.Equal("Critical: Stopped", entry.Message) + ); } } From 9ca627c967dc84d386df5cc9b63bda812ea2ed81 Mon Sep 17 00:00:00 2001 From: aicia-bot Date: Thu, 29 Oct 2026 18:11:01 +0100 Subject: [PATCH 04/14] =?UTF-8?q?=F0=9F=94=A7=20update=20ci=20workflows,?= =?UTF-8?q?=20dependabot=20and=20editor=20settings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keeps CI, dependency updates and the editor and test environment configuration aligned with the net11 baseline. --- .editorconfig | 7 ++--- .gitattributes | 8 +++--- .github/workflows/ci-pipeline.yml | 38 ++++++++++++++++++++++++---- .github/workflows/service-update.yml | 2 +- testenvironments.json | 31 +++++++++++++---------- 5 files changed, 60 insertions(+), 26 deletions(-) diff --git a/.editorconfig b/.editorconfig index a083db5..886ea15 100644 --- a/.editorconfig +++ b/.editorconfig @@ -37,7 +37,7 @@ dotnet_diagnostic.IDE0063.severity = none dotnet_diagnostic.IDE0071.severity = none # S3267: Loops should be simplified with "LINQ" expressions -# https://rules.sonarsource.com/csharp/RSPEC-3267 +# https://sonarcloud.io/organizations/sonarcloud/rules?open=csharpsquid:S3267&rule_key=csharpsquid:S3267 dotnet_diagnostic.S3267.severity = none # CA1859: Use concrete types when possible for improved performance @@ -57,9 +57,10 @@ indent_size = 4 # IDE0161: Namespace declaration preferences # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0161 -# Prefer file-scoped namespaces for new files; existing block-scoped files should not be converted unless explicitly asked +# File-scoped namespaces are mandatory for new and existing C# files. [*.cs] -csharp_style_namespace_declarations = file_scoped:suggestion +csharp_style_namespace_declarations = file_scoped:error +dotnet_diagnostic.IDE0161.severity = error # Top-level statements: DO NOT USE # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0210-ide0211 diff --git a/.gitattributes b/.gitattributes index 1ff0c42..0ea8d1b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,7 +1,7 @@ ############################################################################### # Set default behavior to automatically normalize line endings. ############################################################################### -* text=auto +* text=auto eol=lf ############################################################################### # Set default behavior for command prompt diff. @@ -17,7 +17,7 @@ # # Merging from the command prompt will add diff markers to the files if there # are conflicts (Merging from VS is not affected by the settings below, in VS -# the diff markers are never inserted). Diff markers may cause the following +# the diff markers are never inserted). Diff markers may cause the following # file extensions to fail to load in VS. An alternative would be to treat # these files as binary and thus will always conflict and require user # intervention with every merge. To do so, just uncomment the entries below @@ -46,9 +46,9 @@ ############################################################################### # diff behavior for common document formats -# +# # Convert binary document formats to text before diffing them. This feature -# is only available from the command line. Turn it on by uncommenting the +# is only available from the command line. Turn it on by uncommenting the # entries below. ############################################################################### #*.doc diff=astextplain diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 111bea9..f774402 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -23,7 +23,7 @@ permissions: jobs: init: name: initialize - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 outputs: run-mac-tests: ${{ steps.vars.outputs.run-mac-tests }} run-privileged-jobs: ${{ steps.vars.outputs.run-privileged-jobs }} @@ -63,7 +63,7 @@ jobs: configuration: ${{ matrix.configuration }} strong-name-key-filename: ${{ needs.init.outputs.strong-name-key-filename }} build-switches: ${{ needs.init.outputs.build-switches }} - runs-on: ${{ matrix.arch == 'ARM64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }} + runs-on: ${{ matrix.arch == 'ARM64' && 'ubuntu-26.04-arm' || 'ubuntu-26.04' }} upload-build-artifact-name: build-${{ matrix.configuration }}-${{ matrix.arch }} secrets: GCP_TOKEN: ${{ secrets.GCP_TOKEN }} @@ -91,7 +91,7 @@ jobs: configuration: [Debug, Release] uses: codebeltnet/jobs-dotnet-test/.github/workflows/default.yml@v3 with: - runs-on: ${{ matrix.arch == 'ARM64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }} + runs-on: ${{ matrix.arch == 'ARM64' && 'ubuntu-26.04-arm' || 'ubuntu-26.04' }} projects: test/**/*.csproj configuration: ${{ matrix.configuration }} verbosity-level: normal @@ -100,6 +100,32 @@ jobs: build: true download-pattern: build-${{ matrix.configuration }}-${{ matrix.arch }} + test_frameworks: + name: test-${{ matrix.framework }} + runs-on: ubuntu-26.04 + strategy: + fail-fast: false + matrix: + framework: [net10.0, net11.0] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-dotnet@v6 + with: + dotnet-version: | + 10.0.x + 11.0.x + - name: Test each project on ${{ matrix.framework }} + shell: bash + run: | + mapfile -d '' projects < <(find test -name '*Tests.csproj' -print0) + if [[ ${#projects[@]} -eq 0 ]]; then + echo '::error::No test projects were found.' + exit 1 + fi + for project in "${projects[@]}"; do + dotnet test --project "$project" --framework "${{ matrix.framework }}" --configuration Release -p:SkipSignAssembly=true --minimum-expected-tests 1 + done + test_windows: name: call-test-windows needs: [build] @@ -142,8 +168,8 @@ jobs: test_qualitygate: if: ${{ always() }} name: test-qualitygate - needs: [init, test_linux, test_windows, test_mac] - runs-on: ubuntu-24.04 + needs: [init, test_linux, test_windows, test_mac, test_frameworks] + runs-on: ubuntu-26.04 steps: - name: Evaluate test results shell: bash @@ -152,6 +178,7 @@ jobs: TEST_LINUX_RESULT: ${{ needs.test_linux.result }} TEST_WINDOWS_RESULT: ${{ needs.test_windows.result }} TEST_MAC_RESULT: ${{ needs.test_mac.result }} + TEST_FRAMEWORKS_RESULT: ${{ needs.test_frameworks.result }} run: | require_success() { local job_name="$1" @@ -181,6 +208,7 @@ jobs: require_success "test_linux" "$TEST_LINUX_RESULT" require_success "test_windows" "$TEST_WINDOWS_RESULT" + require_success "test_frameworks" "$TEST_FRAMEWORKS_RESULT" require_success_or_skip "test_mac" "$RUN_MAC_TESTS" "$TEST_MAC_RESULT" sonarcloud: diff --git a/.github/workflows/service-update.yml b/.github/workflows/service-update.yml index 1f69586..05713e7 100644 --- a/.github/workflows/service-update.yml +++ b/.github/workflows/service-update.yml @@ -125,7 +125,7 @@ jobs: NEW="${{ steps.newver.outputs.new }}" for f in .nuget/*/PackageReleaseNotes.txt; do [ -f "$f" ] || continue - TFM=$(grep -m1 "^Availability:" "$f" | sed 's/Availability: //' || echo ".NET 10, .NET 9 and .NET Standard 2.0") + TFM=".NET 10 and .NET 11" ENTRY="Version: ${NEW}\nAvailability: ${TFM}\n\n# ALM\n- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)\n\n" { printf "$ENTRY"; cat "$f"; } > "$f.tmp" && mv "$f.tmp" "$f" done diff --git a/testenvironments.json b/testenvironments.json index cf8b99c..0651f28 100644 --- a/testenvironments.json +++ b/testenvironments.json @@ -1,15 +1,20 @@ { - "version": "1", - "environments": [ - { - "name": "WSL-Ubuntu", - "type": "wsl", - "wslDistribution": "Ubuntu-24.04" - }, - { - "name": "Docker-Ubuntu", - "type": "docker", - "dockerImage": "codebeltnet/ubuntu-testrunner:8-9-10-11" - } - ] + "version": "1", + "environments": [ + { + "name": "WSL-Ubuntu", + "type": "wsl", + "wslDistribution": "Ubuntu-26.04" + }, + { + "name": "Docker-Ubuntu (net10.0)", + "type": "docker", + "dockerImage": "codebeltnet/ubuntu-testrunner:10" + }, + { + "name": "Docker-Ubuntu (net11.0)", + "type": "docker", + "dockerImage": "codebeltnet/ubuntu-testrunner:11" + } + ] } From 8274b5e034ff8bc526918f415b8481351ebc0167 Mon Sep 17 00:00:00 2001 From: aicia-bot Date: Thu, 29 Oct 2026 18:11:01 +0100 Subject: [PATCH 05/14] =?UTF-8?q?=F0=9F=93=A6=20update=20nuget=20package?= =?UTF-8?q?=20release=20notes=20and=20readmes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Package release notes and NuGet readmes describe the net11 target and the 6.0.0 changes for each published package. --- .nuget/Codebelt.Bootstrapper.Console/README.md | 2 +- .nuget/Codebelt.Bootstrapper.Web/README.md | 2 +- .nuget/Codebelt.Bootstrapper.Worker/README.md | 2 +- .nuget/Codebelt.Bootstrapper/README.md | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.nuget/Codebelt.Bootstrapper.Console/README.md b/.nuget/Codebelt.Bootstrapper.Console/README.md index f2e22c6..0896bd7 100644 --- a/.nuget/Codebelt.Bootstrapper.Console/README.md +++ b/.nuget/Codebelt.Bootstrapper.Console/README.md @@ -4,7 +4,7 @@ An open-source family of assemblies (MIT license) that provide a uniform and con Also, common for all, is the implementation of the `IHostedService` interface; this means that all project types, including the traditional `console`, now have option for graceful shutdown should your application require this (cronjob scenarios or similar). -Your versatile Bootstrapper companion for modern development with `.NET 9` and `.NET 10`. +Your versatile Bootstrapper companion for modern development with `.NET 10` and `.NET 11`. It is, by heart, free, flexible and built to extend and boost your agile codebelt. diff --git a/.nuget/Codebelt.Bootstrapper.Web/README.md b/.nuget/Codebelt.Bootstrapper.Web/README.md index 192dc03..5c338af 100644 --- a/.nuget/Codebelt.Bootstrapper.Web/README.md +++ b/.nuget/Codebelt.Bootstrapper.Web/README.md @@ -4,7 +4,7 @@ An open-source family of assemblies (MIT license) that provide a uniform and con Also, common for all, is the implementation of the `IHostedService` interface; this means that all project types, including the traditional `console`, now have option for graceful shutdown should your application require this (cronjob scenarios or similar). -Your versatile Bootstrapper companion for modern development with `.NET 9` and `.NET 10`. +Your versatile Bootstrapper companion for modern development with `.NET 10` and `.NET 11`. It is, by heart, free, flexible and built to extend and boost your agile codebelt. diff --git a/.nuget/Codebelt.Bootstrapper.Worker/README.md b/.nuget/Codebelt.Bootstrapper.Worker/README.md index a642b53..d4826e1 100644 --- a/.nuget/Codebelt.Bootstrapper.Worker/README.md +++ b/.nuget/Codebelt.Bootstrapper.Worker/README.md @@ -4,7 +4,7 @@ An open-source family of assemblies (MIT license) that provide a uniform and con Also, common for all, is the implementation of the `IHostedService` interface; this means that all project types, including the traditional `console`, now have option for graceful shutdown should your application require this (cronjob scenarios or similar). -Your versatile Bootstrapper companion for modern development with `.NET 9` and `.NET 10`. +Your versatile Bootstrapper companion for modern development with `.NET 10` and `.NET 11`. It is, by heart, free, flexible and built to extend and boost your agile codebelt. diff --git a/.nuget/Codebelt.Bootstrapper/README.md b/.nuget/Codebelt.Bootstrapper/README.md index 1c4facc..78e3ae2 100644 --- a/.nuget/Codebelt.Bootstrapper/README.md +++ b/.nuget/Codebelt.Bootstrapper/README.md @@ -4,7 +4,7 @@ An open-source family of assemblies (MIT license) that provide a uniform and con Also, common for all, is the implementation of the `IHostedService` interface; this means that all project types, including the traditional `console`, now have option for graceful shutdown should your application require this (cronjob scenarios or similar). -Your versatile Bootstrapper companion for modern development with `.NET 9` and `.NET 10`. +Your versatile Bootstrapper companion for modern development with `.NET 10` and `.NET 11`. It is, by heart, free, flexible and built to extend and boost your agile codebelt. @@ -26,4 +26,4 @@ The core types of this lightweight boostrapper framework optimized for console a * [Codebelt.Bootstrapper](https://www.nuget.org/packages/Codebelt.Bootstrapper/) 📦 * [Codebelt.Bootstrapper.Console](https://www.nuget.org/packages/Codebelt.Bootstrapper.Console/) 📦 * [Codebelt.Bootstrapper.Web](https://www.nuget.org/packages/Codebelt.Bootstrapper.Web/) 📦 -* [Codebelt.Bootstrapper.Worker](https://www.nuget.org/packages/Codebelt.Bootstrapper.Worker/) 📦 \ No newline at end of file +* [Codebelt.Bootstrapper.Worker](https://www.nuget.org/packages/Codebelt.Bootstrapper.Worker/) 📦 From dbd7fdbf42a461bac8355306cc569fa4a13997e8 Mon Sep 17 00:00:00 2001 From: aicia-bot Date: Thu, 29 Oct 2026 18:11:02 +0100 Subject: [PATCH 06/14] =?UTF-8?q?=F0=9F=93=9A=20update=20docfx=20publishin?= =?UTF-8?q?g=20and=20api=20overview=20pages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refreshes the DocFX configuration, publishing images and API overview pages so the published documentation matches the current public API. --- .docfx/BuildDocfxImage.ps1 | 2 +- .docfx/api/namespaces/Codebelt.Bootstrapper.Console.md | 2 +- .docfx/api/namespaces/Codebelt.Bootstrapper.Web.md | 2 +- .docfx/api/namespaces/Codebelt.Bootstrapper.Worker.md | 2 +- .docfx/api/namespaces/Codebelt.Bootstrapper.md | 2 +- .docfx/includes/availability-default.md | 2 +- .docfx/includes/availability-modern.md | 2 +- .docfx/nginx.conf | 8 +------- 8 files changed, 8 insertions(+), 14 deletions(-) diff --git a/.docfx/BuildDocfxImage.ps1 b/.docfx/BuildDocfxImage.ps1 index 7f1d39e..075789c 100644 --- a/.docfx/BuildDocfxImage.ps1 +++ b/.docfx/BuildDocfxImage.ps1 @@ -1,4 +1,4 @@ -$version = minver -i -t v -v w +$version = minver -i -t v -v w docfx metadata docfx.json docker buildx build -t jcr.codebelt.net/geekle/bootstrapper-docfx:$version --platform linux/arm64,linux/amd64 --load -f Dockerfile.docfx . get-childItem -recurse -path api -include *.yml, .manifest | remove-item diff --git a/.docfx/api/namespaces/Codebelt.Bootstrapper.Console.md b/.docfx/api/namespaces/Codebelt.Bootstrapper.Console.md index c654c2d..cf1d04b 100644 --- a/.docfx/api/namespaces/Codebelt.Bootstrapper.Console.md +++ b/.docfx/api/namespaces/Codebelt.Bootstrapper.Console.md @@ -1,4 +1,4 @@ ---- +--- uid: Codebelt.Bootstrapper.Console summary: *content --- diff --git a/.docfx/api/namespaces/Codebelt.Bootstrapper.Web.md b/.docfx/api/namespaces/Codebelt.Bootstrapper.Web.md index 1310dea..71a6a68 100644 --- a/.docfx/api/namespaces/Codebelt.Bootstrapper.Web.md +++ b/.docfx/api/namespaces/Codebelt.Bootstrapper.Web.md @@ -1,4 +1,4 @@ ---- +--- uid: Codebelt.Bootstrapper.Web summary: *content --- diff --git a/.docfx/api/namespaces/Codebelt.Bootstrapper.Worker.md b/.docfx/api/namespaces/Codebelt.Bootstrapper.Worker.md index 763bca9..86c3a17 100644 --- a/.docfx/api/namespaces/Codebelt.Bootstrapper.Worker.md +++ b/.docfx/api/namespaces/Codebelt.Bootstrapper.Worker.md @@ -1,4 +1,4 @@ ---- +--- uid: Codebelt.Bootstrapper.Worker summary: *content --- diff --git a/.docfx/api/namespaces/Codebelt.Bootstrapper.md b/.docfx/api/namespaces/Codebelt.Bootstrapper.md index 0190073..2726aa2 100644 --- a/.docfx/api/namespaces/Codebelt.Bootstrapper.md +++ b/.docfx/api/namespaces/Codebelt.Bootstrapper.md @@ -1,4 +1,4 @@ ---- +--- uid: Codebelt.Bootstrapper summary: *content --- diff --git a/.docfx/includes/availability-default.md b/.docfx/includes/availability-default.md index fa28d0e..22cf496 100644 --- a/.docfx/includes/availability-default.md +++ b/.docfx/includes/availability-default.md @@ -1 +1 @@ -Availability: .NET 10, .NET 9 and .NET Standard 2.0 \ No newline at end of file +Availability: .NET 10 and .NET 11 diff --git a/.docfx/includes/availability-modern.md b/.docfx/includes/availability-modern.md index af5cf4b..22cf496 100644 --- a/.docfx/includes/availability-modern.md +++ b/.docfx/includes/availability-modern.md @@ -1 +1 @@ -Availability: .NET 10 and .NET 9 \ No newline at end of file +Availability: .NET 10 and .NET 11 diff --git a/.docfx/nginx.conf b/.docfx/nginx.conf index 67c9e06..c95d1b1 100644 --- a/.docfx/nginx.conf +++ b/.docfx/nginx.conf @@ -10,17 +10,11 @@ server { # DocFX fingerprints these generated dependencies in their filenames. They can be # cached permanently because changed content is published under a different URL. location ~ "^/public/.+-[A-Z0-9]{8}(?:-[A-Z0-9]{8})?(?:\.min)?\.(?:(?:css|js)(?:\.map)?|woff2?)$" { - error_page 404 = @not_found; try_files $uri =404; - add_header Cache-Control "public, max-age=31536000, immutable"; + add_header Cache-Control "public, max-age=31536000, immutable" always; add_header Vary "Accept-Encoding" always; } - location @not_found { - add_header Cache-Control "no-store" always; - return 404; - } - # Pages, navigation data, images, and DocFX entry assets keep stable URLs. Do not # retain them across deployments, and ignore validators cached under an old policy. location / { From cb2483de8bfe4ba75022b0382926af7ed32cf911 Mon Sep 17 00:00:00 2001 From: aicia-bot Date: Thu, 29 Oct 2026 18:11:03 +0100 Subject: [PATCH 07/14] =?UTF-8?q?=F0=9F=92=AC=20add=206.0.0=20changelog=20?= =?UTF-8?q?entry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Records the major 6.0.0 release, including the dropped net9.0 target and the net11.0 addition, for consumers reading release status. --- CHANGELOG.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e19e2e..f21c9cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,27 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), For more details, please refer to `PackageReleaseNotes.txt` on a per assembly basis in the `.nuget` folder. +## [6.0.0] - 2026-11-10 + +This is a major release that drops the `net9.0` target framework and adds `net11.0`, with updated package versions, the SonarAnalyzer.CSharp analyzer, and removal of the benchmark prompt file. + +### Added + +- SonarAnalyzer.CSharp 10.35.0.4138 as an analyzer package reference with `PrivateAssets="all"`, +- `net11.0` target framework in the project files, with Microsoft.AspNetCore.OpenApi, Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation, Microsoft.Extensions.Configuration, Microsoft.Extensions.DependencyInjection.Abstractions, and Microsoft.Extensions.Hosting + +### Changed + +- Project target frameworks from `net10.0;net9.0` to `net11.0;net10.0`, +- Cuemon.Core and Cuemon.Extensions.Hosting from 10.8.1 to 10.8.2, Codebelt.Coverlet.MTP from 10.1.0 to 10.1.1, and Microsoft.Testing.Extensions.HangDump from 2.5.1 to 2.5.2, +- Microsoft.AspNetCore.OpenApi, Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation, Microsoft.Extensions.Configuration, Microsoft.Extensions.DependencyInjection.Abstractions, and Microsoft.Extensions.Hosting from 10.0.13 to 10.0.14 for `net10.0`, +- Package README descriptions now mention `.NET 10` and `.NET 11`. + +### Removed + +- `net9.0` target framework and its Microsoft.AspNetCore and Microsoft.Extensions package versions from the central package versions, +- `.github/prompts/benchmark.prompt.md`. + ## [5.2.3] - 2026-10-18 This patch release updates dependencies, aligns MTP coverage and hang diagnostics with the shared CI workflow, and refreshes documentation hosting and contributor guidance. @@ -332,6 +353,7 @@ Highlighted features included in this release: - WorkerProgram class in the Codebelt.Bootstrapper.Worker namespace that is the base entry point of an application responsible for registering its WorkerStartup partner, - WorkerStartup interface in the Codebelt.Bootstrapper.Worker namespace that provides the base class of a conventional based Startup class for a console application. +[6.0.0]: https://github.com/codebeltnet/bootstrapper/compare/v5.2.3...v6.0.0 [5.2.3]: https://github.com/codebeltnet/bootstrapper/compare/v5.2.2...v5.2.3 [5.2.2]: https://github.com/codebeltnet/bootstrapper/compare/v5.2.1...v5.2.2 [5.2.1]: https://github.com/codebeltnet/bootstrapper/compare/v5.2.0...v5.2.1 From 8bdbf0ff097027e5c141bb6674bd378e515d9f66 Mon Sep 17 00:00:00 2001 From: aicia-bot Date: Thu, 29 Oct 2026 18:11:03 +0100 Subject: [PATCH 08/14] =?UTF-8?q?=F0=9F=93=9D=20update=20agents,=20readme?= =?UTF-8?q?=20and=20contributing=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Brings the agent instructions, repository readme, contributing guide and Context7 metadata in line with the 6.0.0 baseline. --- .github/CONTRIBUTING.md | 9 +++++---- AGENTS.md | 2 +- README.md | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index ae37602..04c2eca 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -5,7 +5,7 @@ This repository is part of the Codebelt .NET library estate. The instructions be ## Before you start - Read the repository `README.md` and open an issue before starting a non-trivial feature or behavioral change. -- Use an installed .NET SDK that can build the target frameworks listed below. This repository currently targets: **net10.0, net9.0**. +- Use an installed .NET SDK that can build the target frameworks listed below. The libraries and tests target **net10.0 and net11.0**; the sample applications target **net10.0**. - The solution is `Codebelt.Bootstrapper.slnx`. Central package versions are maintained in `Directory.Packages.props`. - The shared build behavior is in `Directory.Build.props` and `Directory.Build.targets`; repository-specific TFMs, package references and metadata remain local to this library. @@ -39,12 +39,13 @@ foreach ($project in $testProjects) { } ``` -The CI test plan currently runs **6** project(s) and excludes **0** project(s). The workflow also has an optional macOS test job. +The CI test plan currently runs **6** test projects. The release gate requires successful tests for both target frameworks, along with the Linux and Windows matrices. The workflow also has an optional macOS test job. ## Integration and infrastructure -- `WSL-Ubuntu` — WSL distribution `Ubuntu-24.04`. -- `Docker-Ubuntu` — Docker image `codebeltnet/ubuntu-testrunner:8-9-10-11`. +- `WSL-Ubuntu` — WSL distribution `Ubuntu-26.04`. +- `Docker-Ubuntu (net10.0)` — Docker image `codebeltnet/ubuntu-testrunner:10`. +- `Docker-Ubuntu (net11.0)` — Docker image `codebeltnet/ubuntu-testrunner:11`. This repository has no repository-local `docker-compose.yml` service dependency in the current checkout. Use the environments declared in `testenvironments.json` when you need the estate test runner. diff --git a/AGENTS.md b/AGENTS.md index 50153bd..316cd7b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,7 +4,7 @@ This document provides guidance for AI agents working in this repository. ## Project Overview -Codebelt.Bootstrapper is an open-source family of assemblies (MIT license) that provide a uniform and consistent way of bootstrapping .NET code with `Program.cs` paired with `Startup.cs` — or using the new `Minimal` equivalent for all project types. The solution targets .NET 10.0, .NET 9.0, and later. It includes: +Codebelt.Bootstrapper is an open-source family of assemblies (MIT license) that provide a uniform and consistent way of bootstrapping .NET code with `Program.cs` paired with `Startup.cs` — or using the new `Minimal` equivalent for all project types. The libraries and tests target .NET 10.0 and .NET 11.0; sample applications target .NET 10.0. It includes: - **Codebelt.Bootstrapper** — Core types and interfaces for all project types. - **Codebelt.Bootstrapper.Console** — Implementation optimized for console applications. diff --git a/README.md b/README.md index 164a610..7bd6a26 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ An open-source family of assemblies (MIT license) that provide a uniform and consistent way of bootstraping your code with Program.cs paired with Startup.cs -OR- using the new `Minimal` equivalent for all project types. -Your versatile Bootstrapper companion for modern development with `.NET 9` and `.NET 10`. +Your versatile Bootstrapper companion for modern development with `.NET 10` and `.NET 11`. It is, by heart, free, flexible and built to extend and boost your agile codebelt. From e4cbe04b12823e2d19d36ff53b24e0bbffbacb91 Mon Sep 17 00:00:00 2001 From: gimlichael Date: Thu, 29 Oct 2026 18:15:48 +0100 Subject: [PATCH 09/14] release notes --- .../Codebelt.Bootstrapper.Console/PackageReleaseNotes.txt | 6 ++++++ .nuget/Codebelt.Bootstrapper.Web/PackageReleaseNotes.txt | 6 ++++++ .nuget/Codebelt.Bootstrapper.Worker/PackageReleaseNotes.txt | 6 ++++++ .nuget/Codebelt.Bootstrapper/PackageReleaseNotes.txt | 6 ++++++ 4 files changed, 24 insertions(+) diff --git a/.nuget/Codebelt.Bootstrapper.Console/PackageReleaseNotes.txt b/.nuget/Codebelt.Bootstrapper.Console/PackageReleaseNotes.txt index cc72351..806a07b 100644 --- a/.nuget/Codebelt.Bootstrapper.Console/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Bootstrapper.Console/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 6.0.0 +Availability: .NET 11 and .NET 10 + +# ALM +- CHANGED Target frameworks by adding .NET 11 (net11.0) and removing .NET 9 (net9.0), so the package now targets .NET 11 and .NET 10 + Version: 5.2.3 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Codebelt.Bootstrapper.Web/PackageReleaseNotes.txt b/.nuget/Codebelt.Bootstrapper.Web/PackageReleaseNotes.txt index 1305c4f..537b3ec 100644 --- a/.nuget/Codebelt.Bootstrapper.Web/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Bootstrapper.Web/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 6.0.0 +Availability: .NET 11 and .NET 10 + +# ALM +- CHANGED Target frameworks by adding .NET 11 (net11.0) and removing .NET 9 (net9.0), so the package now targets .NET 11 and .NET 10 + Version: 5.2.3 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Codebelt.Bootstrapper.Worker/PackageReleaseNotes.txt b/.nuget/Codebelt.Bootstrapper.Worker/PackageReleaseNotes.txt index 1f2dcd9..a7bf27d 100644 --- a/.nuget/Codebelt.Bootstrapper.Worker/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Bootstrapper.Worker/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 6.0.0 +Availability: .NET 11 and .NET 10 + +# ALM +- CHANGED Target frameworks by adding .NET 11 (net11.0) and removing .NET 9 (net9.0), so the package now targets .NET 11 and .NET 10 + Version: 5.2.3 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Codebelt.Bootstrapper/PackageReleaseNotes.txt b/.nuget/Codebelt.Bootstrapper/PackageReleaseNotes.txt index dbf32e3..8e3e299 100644 --- a/.nuget/Codebelt.Bootstrapper/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Bootstrapper/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 6.0.0 +Availability: .NET 11 and .NET 10 + +# ALM +- CHANGED Target frameworks by adding .NET 11 (net11.0) and removing .NET 9 (net9.0), so the package now targets .NET 11 and .NET 10 + Version: 5.2.3 Availability: .NET 10 and .NET 9 From a01e2259270b44c25ff1874fc6137beb3609de7e Mon Sep 17 00:00:00 2001 From: gimlichael Date: Sun, 1 Nov 2026 17:21:20 +0100 Subject: [PATCH 10/14] =?UTF-8?q?=F0=9F=93=9D=20update=20contributing=20an?= =?UTF-8?q?d=20ci=20pipeline=20for=20clarity=20and=20preview=20inclusion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/CONTRIBUTING.md | 2 +- .github/workflows/ci-pipeline.yml | 38 +++++++--------------------- .github/workflows/service-update.yml | 37 +++++++++++++++++---------- 3 files changed, 34 insertions(+), 43 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 04c2eca..c9d78f8 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -39,7 +39,7 @@ foreach ($project in $testProjects) { } ``` -The CI test plan currently runs **6** test projects. The release gate requires successful tests for both target frameworks, along with the Linux and Windows matrices. The workflow also has an optional macOS test job. +The CI test plan currently runs **6** test projects on both target frameworks in the Linux and Windows matrices. The workflow also has an optional macOS test job. ## Integration and infrastructure diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index f774402..ba27e73 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -61,6 +61,7 @@ jobs: with: projects: src/**/*.csproj configuration: ${{ matrix.configuration }} + include-preview: true strong-name-key-filename: ${{ needs.init.outputs.strong-name-key-filename }} build-switches: ${{ needs.init.outputs.build-switches }} runs-on: ${{ matrix.arch == 'ARM64' && 'ubuntu-26.04-arm' || 'ubuntu-26.04' }} @@ -78,6 +79,7 @@ jobs: uses: codebeltnet/jobs-dotnet-pack/.github/workflows/default.yml@v3 with: configuration: ${{ matrix.configuration }} + include-preview: true version: ${{ needs.build.outputs.version }} download-build-artifact-pattern: build-${{ matrix.configuration }}-X64 @@ -94,38 +96,13 @@ jobs: runs-on: ${{ matrix.arch == 'ARM64' && 'ubuntu-26.04-arm' || 'ubuntu-26.04' }} projects: test/**/*.csproj configuration: ${{ matrix.configuration }} + include-preview: true verbosity-level: normal build-switches: -p:SkipSignAssembly=true restore: true build: true download-pattern: build-${{ matrix.configuration }}-${{ matrix.arch }} - test_frameworks: - name: test-${{ matrix.framework }} - runs-on: ubuntu-26.04 - strategy: - fail-fast: false - matrix: - framework: [net10.0, net11.0] - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-dotnet@v6 - with: - dotnet-version: | - 10.0.x - 11.0.x - - name: Test each project on ${{ matrix.framework }} - shell: bash - run: | - mapfile -d '' projects < <(find test -name '*Tests.csproj' -print0) - if [[ ${#projects[@]} -eq 0 ]]; then - echo '::error::No test projects were found.' - exit 1 - fi - for project in "${projects[@]}"; do - dotnet test --project "$project" --framework "${{ matrix.framework }}" --configuration Release -p:SkipSignAssembly=true --minimum-expected-tests 1 - done - test_windows: name: call-test-windows needs: [build] @@ -139,6 +116,7 @@ jobs: runs-on: ${{ matrix.arch == 'ARM64' && 'windows-11-arm' || 'windows-2025' }} projects: test/**/*.csproj configuration: ${{ matrix.configuration }} + include-preview: true verbosity-level: normal build-switches: -p:SkipSignAssembly=true restore: true @@ -159,6 +137,7 @@ jobs: runs-on: ${{ matrix.arch == 'ARM64' && 'macos-26' || 'macos-26-intel' }} projects: test/**/*.csproj configuration: ${{ matrix.configuration }} + include-preview: true verbosity-level: normal build-switches: -p:SkipSignAssembly=true restore: true @@ -168,7 +147,7 @@ jobs: test_qualitygate: if: ${{ always() }} name: test-qualitygate - needs: [init, test_linux, test_windows, test_mac, test_frameworks] + needs: [init, test_linux, test_windows, test_mac] runs-on: ubuntu-26.04 steps: - name: Evaluate test results @@ -178,7 +157,6 @@ jobs: TEST_LINUX_RESULT: ${{ needs.test_linux.result }} TEST_WINDOWS_RESULT: ${{ needs.test_windows.result }} TEST_MAC_RESULT: ${{ needs.test_mac.result }} - TEST_FRAMEWORKS_RESULT: ${{ needs.test_frameworks.result }} run: | require_success() { local job_name="$1" @@ -208,7 +186,6 @@ jobs: require_success "test_linux" "$TEST_LINUX_RESULT" require_success "test_windows" "$TEST_WINDOWS_RESULT" - require_success "test_frameworks" "$TEST_FRAMEWORKS_RESULT" require_success_or_skip "test_mac" "$RUN_MAC_TESTS" "$TEST_MAC_RESULT" sonarcloud: @@ -217,6 +194,7 @@ jobs: needs: [init, build, test_qualitygate] uses: codebeltnet/jobs-sonarcloud/.github/workflows/default.yml@v3 with: + include-preview: true organization: geekle projectKey: bootstrapper version: ${{ needs.build.outputs.version }} @@ -236,6 +214,8 @@ jobs: name: call-codeql needs: [init, build, test_qualitygate] uses: codebeltnet/jobs-codeql/.github/workflows/default.yml@v3 + with: + include-preview: true permissions: security-events: write diff --git a/.github/workflows/service-update.yml b/.github/workflows/service-update.yml index 05713e7..da42c0d 100644 --- a/.github/workflows/service-update.yml +++ b/.github/workflows/service-update.yml @@ -50,6 +50,7 @@ jobs: import re import subprocess import sys + from datetime import date tag_pattern = re.compile(r"^v(\d+)\.(\d+)\.(\d+)$") tags = subprocess.check_output(["git", "tag", "--list"], text=True).splitlines() @@ -72,28 +73,37 @@ jobs: with open("CHANGELOG.md", encoding="utf-8") as changelog_file: changelog = changelog_file.read() - heading = re.search(r"(?m)^## \[(\d+\.\d+\.\d+)\] - ([^\r\n]+)[ \t]*$", changelog) + heading = re.search(r"(?m)^## \[(\d+\.\d+\.\d+)\]([^\r\n]*)$", changelog) if not heading: print("::error::CHANGELOG.md has no versioned heading to compare with Git tags.") sys.exit(1) - current_version, current_status = heading.groups() - current_status = current_status.strip() - if current_status.upper() != "TBD" and not re.fullmatch(r"\d{4}-\d{2}-\d{2}", current_status): - print(f"::error::Unsupported CHANGELOG.md version status: {current_status}") + current_version = heading.group(1) + status_match = re.fullmatch(r" - (TBD|\d{4}-\d{2}-\d{2})[ \t]*", heading.group(2), re.IGNORECASE) + if not status_match: + print(f"::error::Unsupported or missing CHANGELOG.md version status: {heading.group(2).strip()}") sys.exit(1) - - if current_version == next_version and current_status.upper() == "TBD": - # Reuse an already pending next release, such as [5.0.13] - TBD. - new_version = next_version - elif current_version == latest_version and current_status.upper() != "TBD": + current_status = status_match.group(1) + if current_status.upper() != "TBD": + try: + date.fromisoformat(current_status) + except ValueError: + print(f"::error::Invalid CHANGELOG.md release date: {current_status}") + sys.exit(1) + + pending_version = tuple(int(part) for part in current_version.split(".")) + released_version = (major, minor, patch) + if pending_version > released_version: + # Preserve an explicitly planned patch, minor, or major release. + new_version = current_version + elif pending_version == released_version and current_status.upper() != "TBD": # The changelog is at the latest released tag; start the next patch release. new_version = next_version else: print( f"::error::CHANGELOG.md starts at {current_version} ({current_status}), " f"but the latest stable Git tag is {latest_tag}. Expected either " - f"[{latest_version}] with a release date or [{next_version}] - TBD." + f"[{latest_version}] with a release date or a newer version with a date or TBD." ) sys.exit(1) @@ -105,6 +115,7 @@ jobs: output.write(f"current={current_version}\n") output.write(f"new={new_version}\n") output.write(f"branch={branch}\n") + PY - name: Generate codebelt-aicia token id: app-token @@ -140,9 +151,9 @@ jobs: service_note = "This release also includes a service update focused on package dependencies." with open("CHANGELOG.md", encoding="utf-8") as f: content = f.read() - heading = re.search(r"(?m)^## \[(\d+\.\d+\.\d+)\] - (TBD|\d{4}-\d{2}-\d{2})[ \t]*$", content) + heading = re.search(r"(?m)^## \[(\d+\.\d+\.\d+)\] - (TBD|\d{4}-\d{2}-\d{2})[ \t]*$", content, re.IGNORECASE) if heading and heading.group(1) == new_ver: - if heading.group(2) == "TBD": + if heading.group(2).upper() == "TBD": content = content[:heading.start(2)] + today + content[heading.end(2):] heading = re.search(r"(?m)^## \[(\d+\.\d+\.\d+)\] - \d{4}-\d{2}-\d{2}[ \t]*$", content) section_end = re.search(r"(?m)^## \[", content[heading.end():]) From 12f008ec7770f94338dbd4c2b1a2f1266e3620f8 Mon Sep 17 00:00:00 2001 From: aicia-bot Date: Sun, 1 Nov 2026 17:32:29 +0100 Subject: [PATCH 11/14] =?UTF-8?q?=F0=9F=94=A7=20cache=20fingerprinted=20do?= =?UTF-8?q?cfx=20assets=20in=20nginx?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DocFX fingerprints generated CSS and JavaScript, so successful responses for those assets can be cached permanently. Other responses keep the no-store policy, and range requests are disabled so cached assets are always complete. --- .docfx/nginx.conf | 61 +++++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/.docfx/nginx.conf b/.docfx/nginx.conf index c95d1b1..dfabe96 100644 --- a/.docfx/nginx.conf +++ b/.docfx/nginx.conf @@ -1,31 +1,40 @@ +# Only successful asset responses and revalidation responses may be cached. +map $status $fingerprinted_asset_cache_control { + default "no-store"; + ~^2 "public, max-age=31536000, immutable"; + 304 "public, max-age=31536000, immutable"; +} + server { - listen 8080; - server_name _; - # The ingress terminates TLS; keep redirects from exposing this container port. - absolute_redirect off; + listen 8080; + server_name _; + # The ingress terminates TLS; keep redirects from exposing this container port. + absolute_redirect off; - root /usr/share/nginx/html; - index index.html; + root /usr/share/nginx/html; + index index.html; - # DocFX fingerprints these generated dependencies in their filenames. They can be - # cached permanently because changed content is published under a different URL. - location ~ "^/public/.+-[A-Z0-9]{8}(?:-[A-Z0-9]{8})?(?:\.min)?\.(?:(?:css|js)(?:\.map)?|woff2?)$" { - try_files $uri =404; - add_header Cache-Control "public, max-age=31536000, immutable" always; - add_header Vary "Accept-Encoding" always; - } + # DocFX fingerprints these generated dependencies in their filenames. They can be + # cached permanently because changed content is published under a different URL. + location ~ "^/public/.+-[A-Z0-9]{8}(?:-[A-Z0-9]{8})?(?:\.min)?\.(?:(?:css|js)(?:\.map)?|woff2?)$" { + try_files $uri =404; + # Range errors are generated after headers are set, so serve complete assets. + max_ranges 0; + add_header Cache-Control $fingerprinted_asset_cache_control always; + add_header Vary "Accept-Encoding" always; + } - # Pages, navigation data, images, and DocFX entry assets keep stable URLs. Do not - # retain them across deployments, and ignore validators cached under an old policy. - location / { - # Nginx derives ETags from modification time and file size. Those values can be - # reused by files copied from different image layers, producing a false 304. - etag off; - if_modified_since off; - try_files $uri $uri/ =404; - add_header Cache-Control "no-store, no-cache, must-revalidate, max-age=0" always; - add_header Expires "0" always; - add_header Pragma "no-cache" always; - add_header Vary "Accept-Encoding" always; - } + # Pages, navigation data, images, and DocFX entry assets keep stable URLs. Do not + # retain them across deployments, and ignore validators cached under an old policy. + location / { + # Nginx derives ETags from modification time and file size. Those values can be + # reused by files copied from different image layers, producing a false 304. + etag off; + if_modified_since off; + try_files $uri $uri/ =404; + add_header Cache-Control "no-store, no-cache, must-revalidate, max-age=0" always; + add_header Expires "0" always; + add_header Pragma "no-cache" always; + add_header Vary "Accept-Encoding" always; + } } From 14c91d44624be43eee71ea619216225d947604a7 Mon Sep 17 00:00:00 2001 From: aicia-bot Date: Sun, 1 Nov 2026 17:32:29 +0100 Subject: [PATCH 12/14] =?UTF-8?q?=F0=9F=93=9D=20track=20bot=20readme=20whi?= =?UTF-8?q?le=20ignoring=20other=20bot=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .bot/README.md file documents the folder's policy and needs to be shared, while the rest of the .bot/ working material stays local-only. --- .bot/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bot/README.md b/.bot/README.md index f7e13f0..9f9afda 100644 --- a/.bot/README.md +++ b/.bot/README.md @@ -7,4 +7,4 @@ This folder is reserved for local-only AI working material such as: - design alternatives - temporary agent state -Keep this folder out of source control. Move only finalized, non-confidential guidance into `AGENTS.md`. +The `.bot/README.md` file itself is intentionally tracked in source control. All other `.bot/` working material remains local-only and excluded from source control. Move only finalized, non-confidential guidance into `AGENTS.md`. From 12e2f60d21b06198e844b699b2c3a26f0f4117d3 Mon Sep 17 00:00:00 2001 From: aicia-bot Date: Sun, 1 Nov 2026 17:32:29 +0100 Subject: [PATCH 13/14] =?UTF-8?q?=F0=9F=93=A6=20record=20net9=20removal=20?= =?UTF-8?q?in=20package=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Packages no longer target .NET 9, so the release notes for each package record this as a breaking change that consumers must account for by targeting .NET 10 or later. --- .nuget/Codebelt.Bootstrapper.Console/PackageReleaseNotes.txt | 3 +++ .nuget/Codebelt.Bootstrapper.Web/PackageReleaseNotes.txt | 3 +++ .nuget/Codebelt.Bootstrapper.Worker/PackageReleaseNotes.txt | 3 +++ .nuget/Codebelt.Bootstrapper/PackageReleaseNotes.txt | 3 +++ 4 files changed, 12 insertions(+) diff --git a/.nuget/Codebelt.Bootstrapper.Console/PackageReleaseNotes.txt b/.nuget/Codebelt.Bootstrapper.Console/PackageReleaseNotes.txt index 806a07b..379fda2 100644 --- a/.nuget/Codebelt.Bootstrapper.Console/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Bootstrapper.Console/PackageReleaseNotes.txt @@ -4,6 +4,9 @@ Availability: .NET 11 and .NET 10 # ALM - CHANGED Target frameworks by adding .NET 11 (net11.0) and removing .NET 9 (net9.0), so the package now targets .NET 11 and .NET 10 +# Breaking Changes +- REMOVED .NET 9 support; consumers must target .NET 10 or later + Version: 5.2.3 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Codebelt.Bootstrapper.Web/PackageReleaseNotes.txt b/.nuget/Codebelt.Bootstrapper.Web/PackageReleaseNotes.txt index 537b3ec..9c7ed0c 100644 --- a/.nuget/Codebelt.Bootstrapper.Web/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Bootstrapper.Web/PackageReleaseNotes.txt @@ -4,6 +4,9 @@ Availability: .NET 11 and .NET 10 # ALM - CHANGED Target frameworks by adding .NET 11 (net11.0) and removing .NET 9 (net9.0), so the package now targets .NET 11 and .NET 10 +# Breaking Changes +- REMOVED .NET 9 support; consumers must target .NET 10 or later + Version: 5.2.3 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Codebelt.Bootstrapper.Worker/PackageReleaseNotes.txt b/.nuget/Codebelt.Bootstrapper.Worker/PackageReleaseNotes.txt index a7bf27d..bc3e704 100644 --- a/.nuget/Codebelt.Bootstrapper.Worker/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Bootstrapper.Worker/PackageReleaseNotes.txt @@ -4,6 +4,9 @@ Availability: .NET 11 and .NET 10 # ALM - CHANGED Target frameworks by adding .NET 11 (net11.0) and removing .NET 9 (net9.0), so the package now targets .NET 11 and .NET 10 +# Breaking Changes +- REMOVED .NET 9 support; consumers must target .NET 10 or later + Version: 5.2.3 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Codebelt.Bootstrapper/PackageReleaseNotes.txt b/.nuget/Codebelt.Bootstrapper/PackageReleaseNotes.txt index 8e3e299..58eee0f 100644 --- a/.nuget/Codebelt.Bootstrapper/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Bootstrapper/PackageReleaseNotes.txt @@ -4,6 +4,9 @@ Availability: .NET 11 and .NET 10 # ALM - CHANGED Target frameworks by adding .NET 11 (net11.0) and removing .NET 9 (net9.0), so the package now targets .NET 11 and .NET 10 +# Breaking Changes +- REMOVED .NET 9 support; consumers must target .NET 10 or later + Version: 5.2.3 Availability: .NET 10 and .NET 9 From ba59d9238c1fbba5709c0913a805fba3b81653c6 Mon Sep 17 00:00:00 2001 From: aicia-bot Date: Sun, 1 Nov 2026 17:32:29 +0100 Subject: [PATCH 14/14] =?UTF-8?q?=F0=9F=92=AC=20refine=206.0.0=20changelog?= =?UTF-8?q?=20entry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 6.0.0 entry now describes the .NET 11 addition and .NET 9 removal more accurately, and lists the build, CI, and DocFX infrastructure changes that shipped with it. --- CHANGELOG.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f21c9cc..74178ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,23 +6,28 @@ For more details, please refer to `PackageReleaseNotes.txt` on a per assembly ba ## [6.0.0] - 2026-11-10 -This is a major release that drops the `net9.0` target framework and adds `net11.0`, with updated package versions, the SonarAnalyzer.CSharp analyzer, and removal of the benchmark prompt file. +This is a major release that adds .NET 11 support and removes .NET 9 support, updates dependencies, and refreshes build and test infrastructure. ### Added -- SonarAnalyzer.CSharp 10.35.0.4138 as an analyzer package reference with `PrivateAssets="all"`, -- `net11.0` target framework in the project files, with Microsoft.AspNetCore.OpenApi, Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation, Microsoft.Extensions.Configuration, Microsoft.Extensions.DependencyInjection.Abstractions, and Microsoft.Extensions.Hosting +- SonarAnalyzer.CSharp 10.35.0.4138 as a private analyzer for non-test projects, +- `net11.0` targets for libraries and tests, with corresponding preview Microsoft.AspNetCore and Microsoft.Extensions package declarations. ### Changed -- Project target frameworks from `net10.0;net9.0` to `net11.0;net10.0`, +- Library and test target frameworks from `net10.0;net9.0` to `net11.0;net10.0`, - Cuemon.Core and Cuemon.Extensions.Hosting from 10.8.1 to 10.8.2, Codebelt.Coverlet.MTP from 10.1.0 to 10.1.1, and Microsoft.Testing.Extensions.HangDump from 2.5.1 to 2.5.2, - Microsoft.AspNetCore.OpenApi, Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation, Microsoft.Extensions.Configuration, Microsoft.Extensions.DependencyInjection.Abstractions, and Microsoft.Extensions.Hosting from 10.0.13 to 10.0.14 for `net10.0`, -- Package README descriptions now mention `.NET 10` and `.NET 11`. +- Source, test, and sample C# namespaces to file-scoped declarations, and updated EditorConfig to require that style, +- Linux CI jobs to Ubuntu 26.04 and enabled preview SDKs in the build, pack, test, SonarCloud, and CodeQL workflows, +- Test environments to separate .NET 10 and .NET 11 Docker runners and Ubuntu 26.04 for WSL, +- Service-update version selection to retain a newer planned release and validate its date, +- DocFX nginx caching so successful fingerprinted assets can be cached while unsuccessful responses are not, +- Package availability notes, contributor guidance, and the tracked `.bot/README.md` to reflect the current repository setup. ### Removed -- `net9.0` target framework and its Microsoft.AspNetCore and Microsoft.Extensions package versions from the central package versions, +- `net9.0` support and the corresponding conditional Microsoft.AspNetCore and Microsoft.Extensions package version declarations, - `.github/prompts/benchmark.prompt.md`. ## [5.2.3] - 2026-10-18