diff --git a/.github/workflows/pipelines.yml b/.github/workflows/pipelines.yml index 2e3e130..cf710ba 100644 --- a/.github/workflows/pipelines.yml +++ b/.github/workflows/pipelines.yml @@ -24,7 +24,7 @@ jobs: strategy: matrix: configuration: [Debug, Release] - framework: [net8.0, net6.0] + framework: [net9.0, net8.0] outputs: version: ${{ steps.minver-calculate.outputs.version }} steps: diff --git a/.nuget/Codebelt.Bootstrapper.Console/PackageReleaseNotes.txt b/.nuget/Codebelt.Bootstrapper.Console/PackageReleaseNotes.txt index 0309ab7..46a45e6 100644 --- a/.nuget/Codebelt.Bootstrapper.Console/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Bootstrapper.Console/PackageReleaseNotes.txt @@ -1,10 +1,34 @@ -Version: 2.0.0 +Version 3.0.0 +Availability: .NET 9 and .NET 8 +  +# ALM +- CHANGED Dependencies to latest and greatest with respect to TFMs +- REMOVED Support for TFM .NET 6 (LTS) +  +# Breaking Changes +- REMOVED Run (abstract method) from the ConsoleStartup class located in the Codebelt.Bootstrapper.Console namespace +- REMOVED ILogger{TStartup} argument from the ConsoleHostedService class in the Codebelt.Bootstrapper.Console namespace +  +# New Features +- ADDED RunAsync (abstract method) to the ConsoleHostedService class in the Codebelt.Bootstrapper.Console namespace +- ADDED UseServices (abstract method) to the ConsoleHostedService class in the Codebelt.Bootstrapper.Console namespace +  +# Improvements +- CHANGED ConsoleHostedService class in the Codebelt.Bootstrapper.Console namespace to provide a better developer experience +  +Version: 2.0.0 Availability: .NET 6.0 and .NET 8.0   # ALM - REMOVED TFM for net7.0 - CHANGED Dependencies to latest and greatest with respect to TFMs   +Version: 1.3.0 +Availability: .NET 6.0, .NET 7.0, .NET 8.0 +  +# ALM +- CHANGED Dependencies to latest and greatest +  Version: 1.2.0 Availability: .NET 6.0, .NET 7.0, .NET 8.0   diff --git a/.nuget/Codebelt.Bootstrapper.Console/README.md b/.nuget/Codebelt.Bootstrapper.Console/README.md index 1e8b7e8..2dce083 100644 --- a/.nuget/Codebelt.Bootstrapper.Console/README.md +++ b/.nuget/Codebelt.Bootstrapper.Console/README.md @@ -15,4 +15,64 @@ An implementation optimized for `console` applications. * [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/) 📦 + +### CSharp Example + +An example on how to use `Codebelt.Bootstrapper.Console` in C#: + +```csharp + +// --- Program.cs --- + +public class Program : ConsoleProgram +{ + static async Task Main(string[] args) + { + await CreateHostBuilder(args) + .Build() + .RunAsync() + .ConfigureAwait(false); + } +} + +// --- Startup.cs --- + +public class Startup : ConsoleStartup +{ + public Startup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) + { + } + + public override void ConfigureServices(IServiceCollection services) + { + } + + public override void UseServices(IServiceProvider serviceProvider) + { + var logger = serviceProvider.GetRequiredService>(); + + BootstrapperLifetime.OnApplicationStartedCallback = () => logger.LogInformation("Started"); + BootstrapperLifetime.OnApplicationStoppingCallback = () => + { + logger.LogWarning("Stopping and cleaning .."); + Thread.Sleep(TimeSpan.FromSeconds(5)); // simulate graceful shutdown + logger.LogWarning(".. done!"); + }; + BootstrapperLifetime.OnApplicationStoppedCallback = () => logger.LogCritical("Stopped"); + } + + public async override Task RunAsync(CancellationToken cancellationToken) + { + 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/.nuget/Codebelt.Bootstrapper.Web/PackageReleaseNotes.txt b/.nuget/Codebelt.Bootstrapper.Web/PackageReleaseNotes.txt index 26cc0ed..55f9c19 100644 --- a/.nuget/Codebelt.Bootstrapper.Web/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Bootstrapper.Web/PackageReleaseNotes.txt @@ -1,4 +1,11 @@ -Version: 2.0.0 +Version 3.0.0 +Availability: .NET 9 and .NET 8 +  +# ALM +- CHANGED Dependencies to latest and greatest with respect to TFMs +- REMOVED Support for TFM .NET 6 (LTS) +  +Version: 2.0.0 Availability: .NET 6.0 and .NET 8.0   # ALM @@ -8,6 +15,12 @@ Availability: .NET 6.0 and .NET 8.0 # Breaking Changes - CHANGED WebStartup class in the Codebelt.Bootstrapper.Web namespace to provide a new abstraction; ConfigurePipeline(IApplicationBuilder) and removed ILogger parameter from Configure method   +Version: 1.3.0 +Availability: .NET 6.0, .NET 7.0, .NET 8.0 +  +# ALM +- CHANGED Dependencies to latest and greatest +  Version: 1.2.0 Availability: .NET 6.0, .NET 7.0, .NET 8.0   diff --git a/.nuget/Codebelt.Bootstrapper.Web/README.md b/.nuget/Codebelt.Bootstrapper.Web/README.md index 3bdb68a..13a72cf 100644 --- a/.nuget/Codebelt.Bootstrapper.Web/README.md +++ b/.nuget/Codebelt.Bootstrapper.Web/README.md @@ -15,4 +15,56 @@ An implementation optimized for `web`, `webapi`, `webapp`, `razor`, `mvc` applic * [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/) 📦 + +### CSharp Example + +An example on how to use `Codebelt.Bootstrapper.Web` in C#: + +```csharp + +// --- Program.cs --- + +public class Program : WebProgram +{ + static async Task Main(string[] args) + { + await CreateHostBuilder(args) + .Build() + .RunAsync() + .ConfigureAwait(false); + } +} + +// --- Startup.cs --- + +public class Startup : WebStartup +{ + public Startup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) + { + } + + public override void ConfigureServices(IServiceCollection services) + { + } + + public override void ConfigurePipeline(IApplicationBuilder app) + { + if (Environment.IsLocalDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapGet("/", async context => + { + await context.Response.WriteAsync("Hello World!"); + }); + }); + } +} + +``` diff --git a/.nuget/Codebelt.Bootstrapper.Worker/PackageReleaseNotes.txt b/.nuget/Codebelt.Bootstrapper.Worker/PackageReleaseNotes.txt index 37f507c..bae01db 100644 --- a/.nuget/Codebelt.Bootstrapper.Worker/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Bootstrapper.Worker/PackageReleaseNotes.txt @@ -1,10 +1,23 @@ -Version: 2.0.0 +Version 3.0.0 +Availability: .NET 9 and .NET 8 +  +# ALM +- CHANGED Dependencies to latest and greatest with respect to TFMs +- REMOVED Support for TFM .NET 6 (LTS) +  +Version: 2.0.0 Availability: .NET 6.0 and .NET 8.0   # ALM - REMOVED TFM for net7.0 - CHANGED Dependencies to latest and greatest with respect to TFMs   +Version: 1.3.0 +Availability: .NET 6.0, .NET 7.0, .NET 8.0 +  +# ALM +- CHANGED Dependencies to latest and greatest +  Version: 1.2.0 Availability: .NET 6.0, .NET 7.0, .NET 8.0   diff --git a/.nuget/Codebelt.Bootstrapper.Worker/README.md b/.nuget/Codebelt.Bootstrapper.Worker/README.md index c6f10ff..cc44a7e 100644 --- a/.nuget/Codebelt.Bootstrapper.Worker/README.md +++ b/.nuget/Codebelt.Bootstrapper.Worker/README.md @@ -15,4 +15,72 @@ An implementation optimized for `worker` services. * [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/) 📦 + +### CSharp Example + +An example on how to use `Codebelt.Bootstrapper.Worker` in C#: + +```csharp + +// --- Program.cs --- + +public class Program : WorkerProgram +{ + static async Task Main(string[] args) + { + await CreateHostBuilder(args) + .Build() + .RunAsync() + .ConfigureAwait(false); + } +} + +// --- Startup.cs --- + +public class Startup : WorkerStartup +{ + public Startup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) + { + } + + public override void ConfigureServices(IServiceCollection services) + { + services.AddHostedService(); + } +} + +// --- FakeHostedService.cs --- + +public class FakeHostedService : BackgroundService +{ + private readonly ILogger _logger; + private bool _gracefulShutdown; + + public FakeHostedService(ILogger logger) + { + _logger = logger; + + BootstrapperLifetime.OnApplicationStartedCallback = () => logger.LogInformation("Started"); + BootstrapperLifetime.OnApplicationStoppingCallback = () => + { + _gracefulShutdown = true; + logger.LogWarning("Stopping and cleaning .."); + Thread.Sleep(TimeSpan.FromSeconds(5)); // simulate graceful shutdown + logger.LogWarning(".. done!"); + }; + BootstrapperLifetime.OnApplicationStoppedCallback = () => logger.LogCritical("Stopped"); + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) + { + if (_gracefulShutdown) { return; } + _logger.LogInformation("Worker running at: {time}", DateTimeOffset.UtcNow.ToString("O")); + await Task.Delay(TimeSpan.FromSeconds(2), stoppingToken); + } + } +} + +``` diff --git a/.nuget/Codebelt.Bootstrapper/PackageReleaseNotes.txt b/.nuget/Codebelt.Bootstrapper/PackageReleaseNotes.txt index 899fa70..bca4395 100644 --- a/.nuget/Codebelt.Bootstrapper/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Bootstrapper/PackageReleaseNotes.txt @@ -1,10 +1,23 @@ -Version: 2.0.0 +Version 3.0.0 +Availability: .NET 9 and .NET 8 +  +# ALM +- CHANGED Dependencies to latest and greatest with respect to TFMs +- REMOVED Support for TFM .NET 6 (LTS) +  +Version: 2.0.0 Availability: .NET 6.0 and .NET 8.0   # ALM - REMOVED TFM for net7.0 - CHANGED Dependencies to latest and greatest with respect to TFMs   +Version: 1.3.0 +Availability: .NET 6.0, .NET 7.0, .NET 8.0 +  +# ALM +- CHANGED Dependencies to latest and greatest +  Version: 1.2.0 Availability: .NET 6.0, .NET 7.0, .NET 8.0   diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..84662e2 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,102 @@ +# Changelog + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +For more details, please refer to `PackageReleaseNotes.txt` on a per assembly basis in the `.nuget` folder. + +## [3.0.0] - TBD + +This major release is first and foremost focused on ironing out any wrinkles that have been introduced with .NET 9 preview releases so the final release is production ready together with the official launch from Microsoft. + +### Added + +- RunAsync (abstract method) to the ConsoleHostedService class in the Codebelt.Bootstrapper.Console namespace +- UseServices (abstract method) to the ConsoleHostedService class in the Codebelt.Bootstrapper.Console namespace + +### Changed + +- Dependencies to latest and greatest with respect to TFM +- Run (abstract method) from the ConsoleStartup class located in the Codebelt.Bootstrapper.Console namespace (breaking change) +- ConsoleHostedService class in the Codebelt.Bootstrapper.Console namespace to provide a better developer experience + +### Removed + +- Support for TFM .NET 6 (LTS) +- ILogger{TStartup} argument from the ConsoleHostedService class in the Codebelt.Bootstrapper.Console namespace (breaking change) + +## [2.0.0] - 2024-09-08 + +### Changed + +- Dependencies to latest and greatest with respect to TFM +- WebStartup class in the Codebelt.Bootstrapper.Web namespace to provide a new abstraction; ConfigurePipeline(IApplicationBuilder) and removed ILogger parameter from Configure method (breaking change) + +### Removed + +- Support for TFM .NET 7 (STS) + + +## [1.3.0] - 2024-02-11 + +### Changed + +- Dependencies to latest and greatest with respect to TFM + +## [1.2.0] - 2023-12-15 + +### Added + +- Support for TFM .NET 8 (LTS) + +### Changed + +- Dependencies to latest and greatest with respect to TFM + +## [1.1.0] - 2022-11-09 + +### Added + +- Support for TFM .NET 7 (STS) + +### Changed + +- Dependencies to latest and greatest with respect to TFM + +### Removed + +- Support for TFM .NET 5 (STS) + +## [1.0.1] - 2021-12-29 + +### Added + +- Support for TFM .NET 6 (LTS) + +### Changed + +- Dependencies to latest and greatest with respect to TFM +- Namespace from Codebelt.Bootstrapper.Common to Codebelt.Bootstrapper.Console (breaking change) + +### Fixed + +- Non-critical bug in the ConsoleHostedService class located in the Codebelt.Bootstrapper.Console namespace + +## [1.0.0] - 2021-07-05 + +### Added + +- BootstrapperLifetime class in the Codebelt.Bootstrapper namespace that listens for Ctrl+C or SIGTERM and initiates shutdown +- HostBuilderExtensions class in the Codebelt.Bootstrapper namespace that consist of extension methods for the IHostBuilder interface: UseBootstrapperLifetime, UseBootstrapperStartup +- IStartupFactory interface in the Codebelt.Bootstrapper namespace that provides an interface for initializing services and middleware used by an application +- ProgramRoot class in the Codebelt.Bootstrapper namespace that is the base entry point of an application responsible for registering its StartupRoot partner +- StartupFactory class in the Codebelt.Bootstrapper namespace that is the default implementation of IStartupFactory +- StartupRoot class in the Codebelt.Bootstrapper namespace that provides the base class of a conventional based Startup class +- ConsoleHostedService class in the Codebelt.Bootstrapper.Common namespace that provides a console application that is managed by its host +- ConsoleProgram class in the Codebelt.Bootstrapper.Common namespace that is the base entry point of an application responsible for registering its ConsoleStartup partner +- ConsoleStartup interface in the Codebelt.Bootstrapper.Common namespace that provides the base class of a conventional based Startup class for a console application +- HostBuilderExtensions class in the Codebelt.Bootstrapper.Common namespace that consist of extension methods for the IHostBuilder interface: UseConsoleStartup +- WebProgram class in the Codebelt.Bootstrapper.Web namespace that is the entry point of an application responsible for registering its WebStartup partner +- WebStartup class in the Codebelt.Bootstrapper.Web namespace that provides the base class of a conventional based Startup class for web applications +- HostBuilderExtensions class in the Codebelt.Bootstrapper.Worker namespace that consist of extension methods for the IHostBuilder interface: UseWorkerStartup +- 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 \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props index 2cc2084..25ad0ab 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -13,7 +13,7 @@ - net8.0;net6.0 + net9.0;net8.0 Copyright © Geekle 2021-2024. All rights reserved. gimlichael Geekle @@ -46,7 +46,7 @@ - net8.0;net6.0 + net9.0;net8.0 false false false @@ -58,7 +58,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -74,6 +74,6 @@ - + diff --git a/Directory.Build.targets b/Directory.Build.targets index b719a7f..511f34d 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -14,8 +14,8 @@ - 00000 - $(MinVerMajor).$(MinVerMinor).$(MinVerPatch).$(BUILD_BUILDNUMBER) + 0 + $(MinVerMajor).$(MinVerMinor).$(MinVerPatch).$(GITHUB_RUN_NUMBER) diff --git a/README.md b/README.md index e8ea64b..58e69f5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +![Extensions for AWS Signature Version 4 API by Codebelt](.nuget/Codebelt.Bootstrapper/icon.png) # Bootstrapper Framework for Console Apps (>= .NET 6) ## Codebelt.Bootstrapper @@ -30,3 +31,11 @@ An implementation optimized for `worker` services. --- Code with passion; love your code; deliver with confidence 👨‍💻️🔥❤️🚀😎 + +### Contributing to `Bootstrapper Framework for Console Apps` +[Contributions](.github/CONTRIBUTING.md) are welcome and appreciated. + +Feel free to submit issues, feature requests, or pull requests to help improve this library. + +### License +This project is licensed under the MIT License - see the [LICENSE](LICENSE.md) file for details. diff --git a/app/Codebelt.Bootstrapper.Console.App/Startup.cs b/app/Codebelt.Bootstrapper.Console.App/Startup.cs index 9251b90..184139f 100644 --- a/app/Codebelt.Bootstrapper.Console.App/Startup.cs +++ b/app/Codebelt.Bootstrapper.Console.App/Startup.cs @@ -1,5 +1,6 @@ using System; using System.Threading; +using System.Threading.Tasks; using Cuemon; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -18,21 +19,27 @@ public override void ConfigureServices(IServiceCollection services) { } - public override void Run(IServiceProvider serviceProvider, ILogger logger) + public override void UseServices(IServiceProvider serviceProvider) { + var logger = serviceProvider.GetRequiredService>(); + BootstrapperLifetime.OnApplicationStartedCallback = () => logger.LogInformation("Started"); BootstrapperLifetime.OnApplicationStoppingCallback = () => { logger.LogWarning("Stopping and cleaning .."); - Thread.Sleep(TimeSpan.FromSeconds(1)); // simulate graceful shutdown + Thread.Sleep(TimeSpan.FromSeconds(5)); // simulate graceful shutdown logger.LogWarning(".. done!"); }; BootstrapperLifetime.OnApplicationStoppedCallback = () => logger.LogCritical("Stopped"); + } + public async override Task RunAsync(CancellationToken cancellationToken) + { for (int dots = 0; dots <= 5; ++dots) { + if (cancellationToken.IsCancellationRequested) { return; } System.Console.Write($"\rFire and forget {Generate.FixedString('.', dots)}"); - Thread.Sleep(500); + await Task.Delay(500, cancellationToken).ConfigureAwait(false); } System.Console.WriteLine("\nDone and done!"); diff --git a/app/Codebelt.Bootstrapper.Web.App/Properties/launchSettings.json b/app/Codebelt.Bootstrapper.Web.App/Properties/launchSettings.json index d0369ee..cbaae35 100644 --- a/app/Codebelt.Bootstrapper.Web.App/Properties/launchSettings.json +++ b/app/Codebelt.Bootstrapper.Web.App/Properties/launchSettings.json @@ -4,7 +4,7 @@ "commandName": "Project", "dotnetRunMessages": "true", "launchBrowser": true, - "applicationUrl": "https://localhost:5001;http://localhost:5000", + "applicationUrl": "https://localhost:35001;http://localhost:35000", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "LocalDevelopment" } diff --git a/app/Codebelt.Bootstrapper.Web.App/Startup.cs b/app/Codebelt.Bootstrapper.Web.App/Startup.cs index 9107cf9..ef8d627 100644 --- a/app/Codebelt.Bootstrapper.Web.App/Startup.cs +++ b/app/Codebelt.Bootstrapper.Web.App/Startup.cs @@ -4,7 +4,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; namespace Codebelt.Bootstrapper.Web.App { @@ -20,8 +19,6 @@ public override void ConfigureServices(IServiceCollection services) public override void ConfigurePipeline(IApplicationBuilder app) { - var logger = app.ApplicationServices.GetRequiredService>(); - if (Environment.IsLocalDevelopment()) { app.UseDeveloperExceptionPage(); diff --git a/app/Codebelt.Bootstrapper.WebApi.App/Codebelt.Bootstrapper.WebApi.App.csproj b/app/Codebelt.Bootstrapper.WebApi.App/Codebelt.Bootstrapper.WebApi.App.csproj index 741352e..66fc95b 100644 --- a/app/Codebelt.Bootstrapper.WebApi.App/Codebelt.Bootstrapper.WebApi.App.csproj +++ b/app/Codebelt.Bootstrapper.WebApi.App/Codebelt.Bootstrapper.WebApi.App.csproj @@ -1,7 +1,7 @@ - + diff --git a/app/Codebelt.Bootstrapper.WebApi.App/Program.cs b/app/Codebelt.Bootstrapper.WebApi.App/Program.cs index 10e345d..27d21bf 100644 --- a/app/Codebelt.Bootstrapper.WebApi.App/Program.cs +++ b/app/Codebelt.Bootstrapper.WebApi.App/Program.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using Codebelt.Bootstrapper.Web; using Microsoft.Extensions.Hosting; @@ -5,9 +6,12 @@ namespace Codebelt.Bootstrapper.WebApi.App { public class Program : WebProgram { - public static void Main(string[] args) + static async Task Main(string[] args) { - CreateHostBuilder(args).Build().Run(); + 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 0b2eccf..62969a3 100644 --- a/app/Codebelt.Bootstrapper.WebApi.App/Properties/launchSettings.json +++ b/app/Codebelt.Bootstrapper.WebApi.App/Properties/launchSettings.json @@ -2,14 +2,14 @@ "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "Codebelt.Bootstrapper.WebApi.App": { - "commandName": "Project", - "dotnetRunMessages": "true", - "launchBrowser": true, - "launchUrl": "swagger", - "applicationUrl": "https://localhost:5001;http://localhost:5000", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "LocalDevelopment" - } + "commandName": "Project", + "dotnetRunMessages": "true", + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:32451;http://localhost:32450", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "LocalDevelopment" + } } } } diff --git a/app/Codebelt.Bootstrapper.WebApp.App/Codebelt.Bootstrapper.WebApp.App.csproj b/app/Codebelt.Bootstrapper.WebApp.App/Codebelt.Bootstrapper.WebApp.App.csproj index 01cec98..46dbb32 100644 --- a/app/Codebelt.Bootstrapper.WebApp.App/Codebelt.Bootstrapper.WebApp.App.csproj +++ b/app/Codebelt.Bootstrapper.WebApp.App/Codebelt.Bootstrapper.WebApp.App.csproj @@ -4,12 +4,12 @@ false - - + + - - + + diff --git a/app/Codebelt.Bootstrapper.WebMvc.App/Codebelt.Bootstrapper.WebMvc.App.csproj b/app/Codebelt.Bootstrapper.WebMvc.App/Codebelt.Bootstrapper.WebMvc.App.csproj index 01cec98..46dbb32 100644 --- a/app/Codebelt.Bootstrapper.WebMvc.App/Codebelt.Bootstrapper.WebMvc.App.csproj +++ b/app/Codebelt.Bootstrapper.WebMvc.App/Codebelt.Bootstrapper.WebMvc.App.csproj @@ -4,12 +4,12 @@ false - - + + - - + + diff --git a/app/Codebelt.Bootstrapper.Worker.App/Program.cs b/app/Codebelt.Bootstrapper.Worker.App/Program.cs index e178071..220d8e6 100644 --- a/app/Codebelt.Bootstrapper.Worker.App/Program.cs +++ b/app/Codebelt.Bootstrapper.Worker.App/Program.cs @@ -1,14 +1,15 @@ -using Microsoft.Extensions.Hosting; +using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; namespace Codebelt.Bootstrapper.Worker.App { public class Program : WorkerProgram { - static void Main(string[] args) + static async Task Main(string[] args) { - CreateHostBuilder(args) + await CreateHostBuilder(args) .Build() - .Run(); + .RunAsync().ConfigureAwait(false); } } } diff --git a/src/Codebelt.Bootstrapper.Console/ConsoleHostedService.cs b/src/Codebelt.Bootstrapper.Console/ConsoleHostedService.cs index b37e58e..44a3204 100644 --- a/src/Codebelt.Bootstrapper.Console/ConsoleHostedService.cs +++ b/src/Codebelt.Bootstrapper.Console/ConsoleHostedService.cs @@ -16,20 +16,19 @@ public class ConsoleHostedService : IHostedService where TStartup : Co { private readonly IStartupFactory _factory; private readonly IHostApplicationLifetime _applicationLifetime; - private readonly ILogger _logger; + private ILogger _logger = null; private bool _ranToCompletion = false; + private Task _runAsyncTask = null; /// /// Initializes a new instance of the class. /// /// The dependency injected . /// The dependency injected . - /// The dependency injected . - public ConsoleHostedService(IStartupFactory factory, IHostApplicationLifetime applicationLifetime, ILogger logger) + public ConsoleHostedService(IStartupFactory factory, IHostApplicationLifetime applicationLifetime) { _factory = factory; _applicationLifetime = applicationLifetime; - _logger = logger; } /// @@ -39,33 +38,43 @@ public ConsoleHostedService(IStartupFactory factory, IHostApplicationLifetime ap /// A that represents the asynchronous operation. public Task StartAsync(CancellationToken cancellationToken) { - return Task.Run(() => + var startup = _factory.CreateInstance(out var services); + var provider = services.BuildServiceProvider(); + + _logger = provider.GetRequiredService>(); + + _runAsyncTask = Task.Run(async () => { try { - var startup = _factory.CreateInstance(out var services); if (startup != null) { - startup.Run(services.BuildServiceProvider(), _logger); - - _logger.LogInformation("Run completed successfully."); + await Task.Delay(TimeSpan.FromMilliseconds(250), cancellationToken).ConfigureAwait(false); // give time for the host to start and present informational message + startup.UseServices(provider); + _logger.LogInformation("RunAsync started."); + await startup.RunAsync(cancellationToken).ConfigureAwait(false); _ranToCompletion = true; } else { - _logger.LogWarning($"Unable to activate an instance of {typeof(TStartup).FullName}."); + _logger.LogWarning("Unable to activate an instance of {TypeFullName}.", typeof(TStartup).FullName); } } catch (Exception e) { - _logger.LogCritical(e, $"Fatal error occurred while activating {typeof(TStartup).FullName}."); - } - finally - { - _applicationLifetime.StopApplication(); + _logger.LogCritical(e, "Fatal error occurred while activating {TypeFullName}.", typeof(TStartup).FullName); } - }, cancellationToken); + + StartWaitForCompletionOfRunAsync().ConfigureAwait(false); + + return Task.CompletedTask; + } + + private async Task StartWaitForCompletionOfRunAsync() + { + await _runAsyncTask.ConfigureAwait(false); + _applicationLifetime.StopApplication(); } /// @@ -75,7 +84,15 @@ public Task StartAsync(CancellationToken cancellationToken) /// A that represents the asynchronous operation. public Task StopAsync(CancellationToken cancellationToken) { - if (!_ranToCompletion) { _logger.LogInformation("Run ended prematurely."); } + if (!_ranToCompletion) + { + _logger?.LogInformation("RunAsync ended prematurely."); + } + else + { + _logger?.LogInformation("RunAsync completed successfully."); + } + return Task.CompletedTask; } } diff --git a/src/Codebelt.Bootstrapper.Console/ConsoleProgram.cs b/src/Codebelt.Bootstrapper.Console/ConsoleProgram.cs index 47d9392..916ce47 100644 --- a/src/Codebelt.Bootstrapper.Console/ConsoleProgram.cs +++ b/src/Codebelt.Bootstrapper.Console/ConsoleProgram.cs @@ -1,5 +1,4 @@ -using System.Threading; -using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Hosting; namespace Codebelt.Bootstrapper.Console { @@ -23,7 +22,7 @@ static ConsoleProgram() /// /// The command line arguments. /// The initialized . - protected static IHostBuilder CreateHostBuilder(string[] args) + protected new static IHostBuilder CreateHostBuilder(string[] args) { return ProgramRoot.CreateHostBuilder(args); } diff --git a/src/Codebelt.Bootstrapper.Console/ConsoleStartup.cs b/src/Codebelt.Bootstrapper.Console/ConsoleStartup.cs index 5f25f66..85ee7f5 100644 --- a/src/Codebelt.Bootstrapper.Console/ConsoleStartup.cs +++ b/src/Codebelt.Bootstrapper.Console/ConsoleStartup.cs @@ -1,7 +1,8 @@ using System; +using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; namespace Codebelt.Bootstrapper.Console { @@ -14,17 +15,22 @@ public abstract class ConsoleStartup : StartupRoot /// /// Initializes a new instance of the class. /// - /// The dependency injected . - /// The dependency injected . + /// The dependency injected . + /// The dependency injected . protected ConsoleStartup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) { } /// - /// A convenient method for executing code. + /// Provides access to previously registered services. /// /// The to retrieve services from. - /// The to write to. - public abstract void Run(IServiceProvider serviceProvider, ILogger logger); + public abstract void UseServices(IServiceProvider serviceProvider); + + /// + /// A convenient method for executing fire-and-forget code. + /// + /// Indicates that the run has been aborted. + public abstract Task RunAsync(CancellationToken cancellationToken); } } diff --git a/src/Codebelt.Bootstrapper.Web/Codebelt.Bootstrapper.Web.csproj b/src/Codebelt.Bootstrapper.Web/Codebelt.Bootstrapper.Web.csproj index 85eb5da..22c67cf 100644 --- a/src/Codebelt.Bootstrapper.Web/Codebelt.Bootstrapper.Web.csproj +++ b/src/Codebelt.Bootstrapper.Web/Codebelt.Bootstrapper.Web.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/Codebelt.Bootstrapper.Worker/WorkerStartup.cs b/src/Codebelt.Bootstrapper.Worker/WorkerStartup.cs index 11294e7..f5ea733 100644 --- a/src/Codebelt.Bootstrapper.Worker/WorkerStartup.cs +++ b/src/Codebelt.Bootstrapper.Worker/WorkerStartup.cs @@ -12,8 +12,8 @@ public abstract class WorkerStartup : StartupRoot /// /// Initializes a new instance of the class. /// - /// The dependency injected . - /// The dependency injected . + /// The dependency injected . + /// The dependency injected . protected WorkerStartup(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) { } diff --git a/src/Codebelt.Bootstrapper/Codebelt.Bootstrapper.csproj b/src/Codebelt.Bootstrapper/Codebelt.Bootstrapper.csproj index aed97bf..610d94a 100644 --- a/src/Codebelt.Bootstrapper/Codebelt.Bootstrapper.csproj +++ b/src/Codebelt.Bootstrapper/Codebelt.Bootstrapper.csproj @@ -5,11 +5,20 @@ bootstrap bootstrapper host host-builder program startup create-host-builder configure configure-services - - + + + + + + + + + + + diff --git a/src/Codebelt.Bootstrapper/StartupFactory.cs b/src/Codebelt.Bootstrapper/StartupFactory.cs index c4e4462..9218cbb 100644 --- a/src/Codebelt.Bootstrapper/StartupFactory.cs +++ b/src/Codebelt.Bootstrapper/StartupFactory.cs @@ -36,7 +36,7 @@ public StartupFactory(IServiceCollection services, IConfiguration configuration, /// A reference to the newly created object of type . public TStartup CreateInstance(out IServiceCollection services) where TStartup : StartupRoot { - var startup = (TStartup) Activator.CreateInstance(typeof(TStartup), _configuration, _environment); + var startup = (TStartup)Activator.CreateInstance(typeof(TStartup), _configuration, _environment); startup?.ConfigureServices(_services); services = _services; return startup;