using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using YaeBlog.Core.Models; namespace YaeBlog.Core.Services; public class WebApplicationHostedService : IHostedService { private readonly WebApplicationBuilder _websiteBuilder = WebApplication.CreateBuilder(); private readonly List> _webApplicationConfigurations; private Website? _currentWebsite; public WebApplicationHostedService(List> webApplicationBuilderConfigurations, List> webApplicationConfigurations, IServiceProvider hostServiceProvider) { _webApplicationConfigurations = webApplicationConfigurations; foreach (Action configure in webApplicationBuilderConfigurations) { configure(_websiteBuilder); } AddHostServices(hostServiceProvider); } public async Task BuildWebsite() { if (_currentWebsite is not null) { await _currentWebsite.ShutdownAsync(new CancellationToken()); } WebApplication application = _websiteBuilder.Build(); foreach (Action configure in _webApplicationConfigurations) { configure(application); } IHostLifetime websiteLifetime = application.Services.GetRequiredService(); _currentWebsite = new Website(application, websiteLifetime); } public Task RunAsync() { if (_currentWebsite is not null) { return _currentWebsite.RunAsync(); } throw new InvalidOperationException("Website has not been built."); } public Task ShutdownAsync() { if (_currentWebsite is { Running: true }) { return _currentWebsite.ShutdownAsync(new CancellationToken()); } throw new InvalidOperationException("Website is not running."); } public async Task StartAsync(CancellationToken cancellationToken) { await BuildWebsite(); _ = RunAsync(); } public Task StopAsync(CancellationToken cancellationToken) { if (_currentWebsite is { Running: true }) { return _currentWebsite.ShutdownAsync(cancellationToken); } return Task.CompletedTask; } private void AddHostServices(IServiceProvider provider) { _websiteBuilder.Services.AddSingleton(_ => provider.GetRequiredService()); _websiteBuilder.Services.AddTransient(_ => provider.GetRequiredService>().Value); } private class Website(WebApplication application, IHostLifetime websiteLifetime) { public bool Running { get; private set; } public Task RunAsync() { Running = true; return application.RunAsync(); } public async Task ShutdownAsync(CancellationToken cancellationToken) { if (!Running) { await websiteLifetime.StopAsync(cancellationToken); } Running = false; } } }