diff --git a/src/Sitko.Core.App/ApplicationLifecycle.cs b/src/Sitko.Core.App/ApplicationLifecycle.cs new file mode 100644 index 000000000..e5a75e1d6 --- /dev/null +++ b/src/Sitko.Core.App/ApplicationLifecycle.cs @@ -0,0 +1,131 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Serilog; + +namespace Sitko.Core.App; + +public class ApplicationLifecycle( + IApplicationContext context, + IServiceProvider provider, + IEnumerable applicationModuleRegistrations, + ILogger logger) + : IApplicationLifecycle +{ + private readonly IReadOnlyList enabledModules = + ModulesHelper.GetEnabledModuleRegistrations(context, applicationModuleRegistrations); + + public async Task StartingAsync(CancellationToken cancellationToken) + { + await using var scope = provider.CreateAsyncScope(); + + foreach (var enabledModule in enabledModules) + { + var shouldContinue = await enabledModule.GetInstance() + .OnBeforeRunAsync(context, scope.ServiceProvider); + if (!shouldContinue) + { + Environment.Exit(0); + return; + } + } + + logger.LogInformation("Check required modules"); + var modulesCheckSuccess = true; + foreach (var registration in enabledModules) + { + var result = + registration.CheckRequiredModules(context, + enabledModules.Select(r => r.Type).ToArray()); + if (!result.isSuccess) + { + foreach (var missingModule in result.missingModules) + { + Log.Information("Required module {MissingModule} for module {Type} is not registered", + missingModule, registration.Type); + } + + modulesCheckSuccess = false; + } + } + + if (!modulesCheckSuccess) + { + throw new InvalidOperationException("Check required modules failed"); + } + + logger.LogInformation("Init modules"); + + foreach (var configurationModule in enabledModules.Select(module => module.GetInstance()) + .OfType()) + { + configurationModule.CheckConfiguration(context, scope.ServiceProvider); + } + + foreach (var registration in enabledModules) + { + logger.LogInformation("Init module {Module}", registration.Type); + await registration.InitAsync(context, scope.ServiceProvider); + } + + foreach (var enabledModule in enabledModules) + { + var shouldContinue = + await enabledModule.GetInstance().OnAfterRunAsync(context, scope.ServiceProvider); + if (!shouldContinue) + { + Environment.Exit(0); + } + } + } + + public async Task StartedAsync(CancellationToken cancellationToken) + { + foreach (var moduleRegistration in enabledModules) + { + try + { + await moduleRegistration.ApplicationStarted(context, provider); + } + catch (Exception ex) + { + logger.LogError(ex, "Error on application started hook in module {Module}: {ErrorText}", + moduleRegistration.Type, + ex.ToString()); + } + } + } + + public async Task StoppingAsync(CancellationToken cancellationToken) + { + foreach (var moduleRegistration in enabledModules) + { + try + { + await moduleRegistration.ApplicationStopping(context, provider); + } + catch (Exception ex) + { + logger.LogError(ex, "Error on application stopping hook in module {Module}: {ErrorText}", + moduleRegistration.Type, + ex.ToString()); + } + } + } + + public async Task StoppedAsync(CancellationToken cancellationToken) + { + foreach (var moduleRegistration in enabledModules) + { + try + { + await moduleRegistration.ApplicationStopped(context, provider); + } + catch (Exception ex) + { + logger.LogError(ex, "Error on application stopped hook in module {Module}: {ErrorText}", + moduleRegistration.Type, + ex.ToString()); + } + } + } +} diff --git a/src/Sitko.Core.App/HostedLifecycleService.cs b/src/Sitko.Core.App/HostedLifecycleService.cs index 2445f5aee..d35721b23 100644 --- a/src/Sitko.Core.App/HostedLifecycleService.cs +++ b/src/Sitko.Core.App/HostedLifecycleService.cs @@ -1,146 +1,22 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Serilog; -using Sitko.Core.App.Logging; +using Microsoft.Extensions.Hosting; namespace Sitko.Core.App; -internal class HostedLifecycleService : IHostedLifecycleService +internal class HostedLifecycleService(IApplicationLifecycle lifecycle) : IHostedLifecycleService { - private readonly ILogger logger; - private readonly IApplicationContext applicationContext; - private readonly IServiceProvider serviceProvider; - - - private readonly IReadOnlyList enabledModules; - - public HostedLifecycleService(ILogger logger, IApplicationContext applicationContext, - IServiceProvider serviceProvider, IEnumerable applicationModuleRegistrations) - { - this.logger = logger; - this.applicationContext = applicationContext; - this.serviceProvider = serviceProvider; - enabledModules = - ModulesHelper.GetEnabledModuleRegistrations(applicationContext, applicationModuleRegistrations); - } - public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask; public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; - public async Task StartingAsync(CancellationToken cancellationToken) - { - await using var scope = serviceProvider.CreateAsyncScope(); - - foreach (var enabledModule in enabledModules) - { - var shouldContinue = await enabledModule.GetInstance() - .OnBeforeRunAsync(applicationContext, scope.ServiceProvider); - if (!shouldContinue) - { - Environment.Exit(0); - return; - } - } - - logger.LogInformation("Check required modules"); - var modulesCheckSuccess = true; - foreach (var registration in enabledModules) - { - var result = - registration.CheckRequiredModules(applicationContext, - enabledModules.Select(r => r.Type).ToArray()); - if (!result.isSuccess) - { - foreach (var missingModule in result.missingModules) - { - Log.Information( - $"Required module {missingModule} for module {registration.Type} is not registered"); - } - - modulesCheckSuccess = false; - } - } - - if (!modulesCheckSuccess) - { - throw new InvalidOperationException("Check required modules failed"); - } - - logger.LogInformation("Init modules"); - - foreach (var configurationModule in enabledModules.Select(module => module.GetInstance()) - .OfType()) - { - configurationModule.CheckConfiguration(applicationContext, scope.ServiceProvider); - } - - foreach (var registration in enabledModules) - { - logger.LogInformation("Init module {Module}", registration.Type); - await registration.InitAsync(applicationContext, scope.ServiceProvider); - } - - foreach (var enabledModule in enabledModules) - { - var shouldContinue = - await enabledModule.GetInstance().OnAfterRunAsync(applicationContext, scope.ServiceProvider); - if (!shouldContinue) - { - Environment.Exit(0); - } - } - } + public Task StartingAsync(CancellationToken cancellationToken) => + lifecycle.StartingAsync(cancellationToken); - public async Task StartedAsync(CancellationToken cancellationToken) - { - foreach (var moduleRegistration in enabledModules) - { - try - { - await moduleRegistration.ApplicationStarted(applicationContext, serviceProvider); - } - catch (Exception ex) - { - logger.LogError(ex, "Error on application started hook in module {Module}: {ErrorText}", - moduleRegistration.Type, - ex.ToString()); - } - } - } + public Task StartedAsync(CancellationToken cancellationToken) => + lifecycle.StartedAsync(cancellationToken); - public async Task StoppingAsync(CancellationToken cancellationToken) - { - foreach (var moduleRegistration in enabledModules) - { - try - { - await moduleRegistration.ApplicationStopping(applicationContext, serviceProvider); - } - catch (Exception ex) - { - logger.LogError(ex, "Error on application stopping hook in module {Module}: {ErrorText}", - moduleRegistration.Type, - ex.ToString()); - } - } - } + public Task StoppingAsync(CancellationToken cancellationToken) => + lifecycle.StoppingAsync(cancellationToken); - public async Task StoppedAsync(CancellationToken cancellationToken) - { - foreach (var moduleRegistration in enabledModules) - { - try - { - await moduleRegistration.ApplicationStopped(applicationContext, serviceProvider); - } - catch (Exception ex) - { - logger.LogError(ex, "Error on application stopped hook in module {Module}: {ErrorText}", - moduleRegistration.Type, - ex.ToString()); - } - } - } + public Task StoppedAsync(CancellationToken cancellationToken) => + lifecycle.StoppedAsync(cancellationToken); } diff --git a/src/Sitko.Core.App/IApplicationLifecycle.cs b/src/Sitko.Core.App/IApplicationLifecycle.cs new file mode 100644 index 000000000..535e73ea6 --- /dev/null +++ b/src/Sitko.Core.App/IApplicationLifecycle.cs @@ -0,0 +1,12 @@ +namespace Sitko.Core.App; + +public interface IApplicationLifecycle +{ + Task StartingAsync(CancellationToken cancellationToken); + + Task StartedAsync(CancellationToken cancellationToken); + + Task StoppingAsync(CancellationToken cancellationToken); + + Task StoppedAsync(CancellationToken cancellationToken); +} diff --git a/src/Sitko.Core.App/SitkoCoreBaseApplicationBuilder.cs b/src/Sitko.Core.App/SitkoCoreBaseApplicationBuilder.cs index 531ed9504..d2178dc47 100644 --- a/src/Sitko.Core.App/SitkoCoreBaseApplicationBuilder.cs +++ b/src/Sitko.Core.App/SitkoCoreBaseApplicationBuilder.cs @@ -117,6 +117,7 @@ private void Init() Services.AddTransient(); Services.AddFluentValidationExtensions(); Services.AddTransient(typeof(ILocalizationProvider<>), typeof(LocalizationProvider<>)); + Services.AddSingleton(); // только Hosted? Проверить для Wasm Services.AddHostedService(); // только Hosted? Проверить для Wasm }