From 5cf5f888eb6db462d5679a043be94b22704df4ad Mon Sep 17 00:00:00 2001 From: Anatolii Grynchuk Date: Sat, 2 May 2026 00:24:54 +0300 Subject: [PATCH] feat: wire up Program.cs, DI extensions, Serilog, and appsettings - ServiceCollectionExtensions in DAL.EF: AddNotificationDataAccess (DbContext, UoW, repositories) - ServiceCollectionExtensions in Services: AddNotificationServices (MediatR + TransactionBehavior) - Api/Program.cs: Serilog, OpenAPI, controllers, DI wiring - Worker/Program.cs: Serilog, DI wiring - appsettings.json: Serilog config with Console + Seq sinks, connection string - appsettings.Development.json: Debug log level overrides Ref: IT-628 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Directory.Packages.props | 1 + HrynCo.NotificationService.Api/Program.cs | 47 +++++++------------ .../appsettings.Development.json | 14 ++++-- .../appsettings.json | 27 +++++++++-- .../Repositories/IEmailTemplateRepository.cs | 10 ++-- .../Repositories/EmailTemplateRepository.cs | 2 +- .../ServiceCollectionExtensions.cs | 26 ++++++++++ .../ServiceCollectionExtensions.cs | 19 ++++++++ .../HrynCo.NotificationService.Worker.csproj | 1 + HrynCo.NotificationService.Worker/Program.cs | 14 +++++- .../appsettings.Development.json | 14 ++++-- .../appsettings.json | 27 +++++++++-- 12 files changed, 144 insertions(+), 58 deletions(-) create mode 100644 HrynCo.NotificationService.DAL.EF/ServiceCollectionExtensions.cs create mode 100644 HrynCo.NotificationService.Services/ServiceCollectionExtensions.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index dbdf273..7430824 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -21,6 +21,7 @@ + diff --git a/HrynCo.NotificationService.Api/Program.cs b/HrynCo.NotificationService.Api/Program.cs index ee9d65d..2798628 100644 --- a/HrynCo.NotificationService.Api/Program.cs +++ b/HrynCo.NotificationService.Api/Program.cs @@ -1,41 +1,26 @@ +using HrynCo.NotificationService.DAL.EF; +using HrynCo.NotificationService.Services; +using Serilog; + var builder = WebApplication.CreateBuilder(args); -// Add services to the container. -// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi +builder.Host.UseSerilog((context, lc) => + lc.ReadFrom.Configuration(context.Configuration)); + builder.Services.AddOpenApi(); +builder.Services.AddControllers(); + +string connectionString = builder.Configuration.GetConnectionString("Default") + ?? throw new InvalidOperationException("Connection string 'Default' is not configured."); + +builder.Services.AddNotificationDataAccess(connectionString); +builder.Services.AddNotificationServices(); var app = builder.Build(); -// Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) -{ app.MapOpenApi(); -} app.UseHttpsRedirection(); - -var summaries = new[] -{ - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" -}; - -app.MapGet("/weatherforecast", () => -{ - var forecast = Enumerable.Range(1, 5).Select(index => - new WeatherForecast - ( - DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - Random.Shared.Next(-20, 55), - summaries[Random.Shared.Next(summaries.Length)] - )) - .ToArray(); - return forecast; -}) -.WithName("GetWeatherForecast"); - -app.Run(); - -record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) -{ - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); -} +app.MapControllers(); +app.Run(); \ No newline at end of file diff --git a/HrynCo.NotificationService.Api/appsettings.Development.json b/HrynCo.NotificationService.Api/appsettings.Development.json index 0c208ae..3ef00ad 100644 --- a/HrynCo.NotificationService.Api/appsettings.Development.json +++ b/HrynCo.NotificationService.Api/appsettings.Development.json @@ -1,8 +1,12 @@ { - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Serilog": { + "MinimumLevel": { + "Default": "Debug", + "Override": { + "Microsoft": "Information", + "Microsoft.EntityFrameworkCore": "Information", + "Microsoft.AspNetCore": "Information" + } } } -} +} \ No newline at end of file diff --git a/HrynCo.NotificationService.Api/appsettings.json b/HrynCo.NotificationService.Api/appsettings.json index 10f68b8..253cb2d 100644 --- a/HrynCo.NotificationService.Api/appsettings.json +++ b/HrynCo.NotificationService.Api/appsettings.json @@ -1,9 +1,26 @@ { - "Logging": { - "LogLevel": { + "ConnectionStrings": { + "Default": "Host=localhost;Port=5432;Database=notification_service;Username=postgres;Password=postgres" + }, + "Serilog": { + "MinimumLevel": { "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } + "Override": { + "Microsoft": "Warning", + "Microsoft.EntityFrameworkCore": "Warning", + "Microsoft.AspNetCore": "Warning" + } + }, + "WriteTo": [ + { "Name": "Console" }, + { + "Name": "Seq", + "Args": { + "serverUrl": "http://localhost:5341" + } + } + ], + "Enrich": [ "FromLogContext" ] }, "AllowedHosts": "*" -} +} \ No newline at end of file diff --git a/HrynCo.NotificationService.DAL.Abstract/Repositories/IEmailTemplateRepository.cs b/HrynCo.NotificationService.DAL.Abstract/Repositories/IEmailTemplateRepository.cs index 43bf89d..2375fe6 100644 --- a/HrynCo.NotificationService.DAL.Abstract/Repositories/IEmailTemplateRepository.cs +++ b/HrynCo.NotificationService.DAL.Abstract/Repositories/IEmailTemplateRepository.cs @@ -2,11 +2,11 @@ using HrynCo.NotificationService.DAL.Abstract.Templates; namespace HrynCo.NotificationService.DAL.Abstract.Repositories; -public interface IEmailEmailTemplateRepository +public interface IEmailTemplateRepository { Task> GetByServiceAsync(string serviceName, CancellationToken ct = default); Task GetAsync(string serviceName, string key, string languageCode, CancellationToken ct = default); - Task AddAsync(EmailTemplate EmailTemplate, CancellationToken ct = default); - Task UpdateAsync(EmailTemplate EmailTemplate, CancellationToken ct = default); - Task DeleteAsync(EmailTemplate EmailTemplate, CancellationToken ct = default); -} + Task AddAsync(EmailTemplate template, CancellationToken ct = default); + Task UpdateAsync(EmailTemplate template, CancellationToken ct = default); + Task DeleteAsync(EmailTemplate template, CancellationToken ct = default); +} \ No newline at end of file diff --git a/HrynCo.NotificationService.DAL.EF/Repositories/EmailTemplateRepository.cs b/HrynCo.NotificationService.DAL.EF/Repositories/EmailTemplateRepository.cs index 81199b7..d18afb8 100644 --- a/HrynCo.NotificationService.DAL.EF/Repositories/EmailTemplateRepository.cs +++ b/HrynCo.NotificationService.DAL.EF/Repositories/EmailTemplateRepository.cs @@ -6,7 +6,7 @@ using Microsoft.EntityFrameworkCore; namespace HrynCo.NotificationService.DAL.EF.Repositories; -internal sealed class EmailTemplateRepository : EfRepository, IEmailEmailTemplateRepository +internal sealed class EmailTemplateRepository : EfRepository, IEmailTemplateRepository { public EmailTemplateRepository(NotificationDbContext dbContext) : base(dbContext) { diff --git a/HrynCo.NotificationService.DAL.EF/ServiceCollectionExtensions.cs b/HrynCo.NotificationService.DAL.EF/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..16edbb7 --- /dev/null +++ b/HrynCo.NotificationService.DAL.EF/ServiceCollectionExtensions.cs @@ -0,0 +1,26 @@ +using HrynCo.NotificationService.DAL.Abstract; +using HrynCo.NotificationService.DAL.Abstract.Repositories; +using HrynCo.NotificationService.DAL.EF.Core; +using HrynCo.NotificationService.DAL.EF.Repositories; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; + +namespace HrynCo.NotificationService.DAL.EF; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddNotificationDataAccess( + this IServiceCollection services, + string connectionString) + { + services.AddDbContext(options => + options.UseNpgsql(connectionString)); + + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + return services; + } +} diff --git a/HrynCo.NotificationService.Services/ServiceCollectionExtensions.cs b/HrynCo.NotificationService.Services/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..a5ec603 --- /dev/null +++ b/HrynCo.NotificationService.Services/ServiceCollectionExtensions.cs @@ -0,0 +1,19 @@ +using HrynCo.NotificationService.Services.Behaviors; +using MediatR; +using Microsoft.Extensions.DependencyInjection; + +namespace HrynCo.NotificationService.Services; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddNotificationServices(this IServiceCollection services) + { + services.AddMediatR(cfg => + { + cfg.RegisterServicesFromAssembly(typeof(ServiceCollectionExtensions).Assembly); + cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(TransactionBehavior<,>)); + }); + + return services; + } +} diff --git a/HrynCo.NotificationService.Worker/HrynCo.NotificationService.Worker.csproj b/HrynCo.NotificationService.Worker/HrynCo.NotificationService.Worker.csproj index b63bd32..b47cd24 100644 --- a/HrynCo.NotificationService.Worker/HrynCo.NotificationService.Worker.csproj +++ b/HrynCo.NotificationService.Worker/HrynCo.NotificationService.Worker.csproj @@ -10,6 +10,7 @@ + diff --git a/HrynCo.NotificationService.Worker/Program.cs b/HrynCo.NotificationService.Worker/Program.cs index 1f917ba..bb7026a 100644 --- a/HrynCo.NotificationService.Worker/Program.cs +++ b/HrynCo.NotificationService.Worker/Program.cs @@ -1,7 +1,19 @@ +using HrynCo.NotificationService.DAL.EF; +using HrynCo.NotificationService.Services; using HrynCo.NotificationService.Worker; +using Serilog; var builder = Host.CreateApplicationBuilder(args); + +builder.Services.AddSerilog(lc => + lc.ReadFrom.Configuration(builder.Configuration)); + +string connectionString = builder.Configuration.GetConnectionString("Default") + ?? throw new InvalidOperationException("Connection string 'Default' is not configured."); + +builder.Services.AddNotificationDataAccess(connectionString); +builder.Services.AddNotificationServices(); builder.Services.AddHostedService(); var host = builder.Build(); -host.Run(); +host.Run(); \ No newline at end of file diff --git a/HrynCo.NotificationService.Worker/appsettings.Development.json b/HrynCo.NotificationService.Worker/appsettings.Development.json index b2dcdb6..3ef00ad 100644 --- a/HrynCo.NotificationService.Worker/appsettings.Development.json +++ b/HrynCo.NotificationService.Worker/appsettings.Development.json @@ -1,8 +1,12 @@ { - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.Hosting.Lifetime": "Information" + "Serilog": { + "MinimumLevel": { + "Default": "Debug", + "Override": { + "Microsoft": "Information", + "Microsoft.EntityFrameworkCore": "Information", + "Microsoft.AspNetCore": "Information" + } } } -} +} \ No newline at end of file diff --git a/HrynCo.NotificationService.Worker/appsettings.json b/HrynCo.NotificationService.Worker/appsettings.json index b2dcdb6..117dbc3 100644 --- a/HrynCo.NotificationService.Worker/appsettings.json +++ b/HrynCo.NotificationService.Worker/appsettings.json @@ -1,8 +1,25 @@ { - "Logging": { - "LogLevel": { + "ConnectionStrings": { + "Default": "Host=localhost;Port=5432;Database=notification_service;Username=postgres;Password=postgres" + }, + "Serilog": { + "MinimumLevel": { "Default": "Information", - "Microsoft.Hosting.Lifetime": "Information" - } + "Override": { + "Microsoft": "Warning", + "Microsoft.EntityFrameworkCore": "Warning", + "Microsoft.AspNetCore": "Warning" + } + }, + "WriteTo": [ + { "Name": "Console" }, + { + "Name": "Seq", + "Args": { + "serverUrl": "http://localhost:5341" + } + } + ], + "Enrich": [ "FromLogContext" ] } -} +} \ No newline at end of file