using System.Runtime.CompilerServices; using Femto.Common.Infrastructure; using Femto.Common.Infrastructure.DbConnection; using Femto.Common.Infrastructure.Outbox; using Femto.Common.Integration; using Femto.Modules.Auth.Contracts.Events; using Femto.Modules.Blog.Handlers; using Femto.Modules.Blog.Infrastructure; using MediatR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Quartz; namespace Femto.Modules.Blog.Application; public static class BlogStartup { public static void InitializeBlogModule( this IServiceCollection rootContainer, string connectionString, IEventBus bus ) { var hostBuilder = Host.CreateDefaultBuilder(); hostBuilder.ConfigureServices(services => ConfigureServices(services, connectionString, bus) ); var host = hostBuilder.Build(); rootContainer.AddHostedService(services => new BlogApplication(host)); rootContainer.AddScoped(_ => new BlogModule(host)); bus.Subscribe( (evt, cancellationToken) => EventSubscriber(evt, host.Services, cancellationToken) ); } private static void ConfigureServices( this IServiceCollection services, string connectionString, IEventPublisher publisher ) { services.AddTransient(_ => new DbConnectionFactory(connectionString)); services.AddDbContext(builder => { builder.UseNpgsql( connectionString, o => { o.MapEnum("outbox_status"); } ); builder.UseSnakeCaseNamingConvention(); var loggerFactory = LoggerFactory.Create(b => { }); builder.UseLoggerFactory(loggerFactory); }); services.AddOutbox(); services.AddMediatR(c => { c.RegisterServicesFromAssembly(typeof(BlogStartup).Assembly); }); services.ConfigureDomainServices(); services.AddSingleton(publisher); } private static async Task EventSubscriber( IEvent evt, IServiceProvider provider, CancellationToken cancellationToken ) { using var scope = provider.CreateScope(); var context = scope.ServiceProvider.GetRequiredService(); var loggerFactory = scope.ServiceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger(); var publisher = scope.ServiceProvider.GetRequiredService(); // todo inject these IEventHandler? handler = evt switch { UserWasCreatedIntegrationEvent => new UserCreatedEventHandler( context, loggerFactory.CreateLogger() ), _ => null, }; if (handler is null) return; await handler.Handle(evt, cancellationToken); if (context.ChangeTracker.HasChanges()) { await context.EmitDomainEvents(logger, publisher, cancellationToken); await context.SaveChangesAsync(cancellationToken); } } }