Refactor solution structure and add RabbitMQ config

Reorganized the solution structure to align with a layered architecture:
- Replaced `src` folder with `core`, `infrastructure`, and `presentation`.
- Moved projects to their respective folders.
- Added `DigitalData.MessagingService.Publisher.Abstraction` project.
- Removed `DigitalData.MessagingService.Client` project.

Updated project configurations and nesting in the solution file.

Added `appsettings.Secrets.json` with RabbitMQ and email account settings:
- RabbitMQ configuration includes hostname, port, credentials, and queue/exchange details.
- Email configuration includes SMTP server details and credentials.
This commit is contained in:
2026-07-28 10:26:15 +02:00
parent 2ad2dc6b4d
commit 78c82bf129
40 changed files with 67 additions and 40 deletions

View File

@@ -0,0 +1,28 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace DigitalData.MessagingService.RabbitMQ
{
/// <summary>
/// Dependency injection configuration for Infrastructure layer
/// </summary>
public static class DependencyInjection
{
/// <summary>
/// Adds Infrastructure layer services to the DI container
/// </summary>
public static IServiceCollection AddRabbitMqConnectionFactory(
this IServiceCollection services,
IConfiguration configuration)
{
services.AddSingleton<RabbitMqConnectionFactory>();
// --- RabbitMQ Configuration ---
services.Configure<RabbitMqConfiguration>(
configuration.GetSection(RabbitMqConfiguration.SectionName));
return services;
}
}
}

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net462;net8.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.10" />
<PackageReference Include="RabbitMQ.Client" Version="7.2.1" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.10" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,55 @@
namespace DigitalData.MessagingService.RabbitMQ
{
/// <summary>
/// Configuration for RabbitMQ connection
/// </summary>
public class RabbitMqConfiguration
{
/// <summary>
/// Configuration section name in appsettings.json
/// </summary>
public const string SectionName = "RabbitMQ";
/// <summary>
/// RabbitMQ server hostname
/// </summary>
public string HostName { get; set; } = "localhost";
/// <summary>
/// RabbitMQ AMQP port (default: 5672)
/// </summary>
public int Port { get; set; } = 5672;
/// <summary>
/// RabbitMQ username
/// </summary>
public string UserName { get; set; } = "guest";
/// <summary>
/// RabbitMQ password
/// </summary>
public string Password { get; set; } = "guest";
/// <summary>
/// Virtual host (default: /)
/// </summary>
public string VirtualHost { get; set; } = "/";
/// <summary>
/// Enable automatic recovery on connection failure
/// </summary>
public bool AutomaticRecoveryEnabled { get; set; } = true;
/// <summary>
/// Network recovery interval in seconds
/// </summary>
public int NetworkRecoveryIntervalSeconds { get; set; } = 10;
public string QueueName { get; set; }
public string ExchangeName { get; set; }
public string RoutingKey { get; set; }
public string DlqQueueName { get; set; }
public string DlqExchangeName { get; set; }
public string DlqRoutingKey { get; set; }
}
}

View File

@@ -0,0 +1,80 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace DigitalData.MessagingService.RabbitMQ
{
public sealed class RabbitMqConnectionFactory : IAsyncDisposable
{
private readonly CancellationTokenSource _consumerCts = new CancellationTokenSource();
private readonly RabbitMqConfiguration _config;
private readonly ILogger<RabbitMqConnectionFactory>
#if nullable
?
#endif
_logger;
private readonly Lazy<Task<IConnection>> _lazyConnectionProvider;
public CancellationToken CancellationToken => _consumerCts.Token;
public Task<IConnection> GetDefaultConnectionAsync()
{
return _lazyConnectionProvider.Value;
}
public async Task<IChannel> CreateChannelAsync()
{
var cnn = await GetDefaultConnectionAsync();
return await cnn.CreateChannelAsync(cancellationToken: CancellationToken);
}
public async Task<AsyncEventingBasicConsumer> CreateConsumerAsync()
{
var channel = await CreateChannelAsync();
return new AsyncEventingBasicConsumer(channel);
}
public RabbitMqConnectionFactory(IOptions<RabbitMqConfiguration> config)
{
_config = config.Value;
_lazyConnectionProvider = new Lazy<Task<IConnection>>(async () =>
{
var factory = new ConnectionFactory
{
HostName = _config.HostName,
Port = _config.Port,
UserName = _config.UserName,
Password = _config.Password,
VirtualHost = _config.VirtualHost,
AutomaticRecoveryEnabled = _config.AutomaticRecoveryEnabled,
NetworkRecoveryInterval = TimeSpan.FromSeconds(_config.NetworkRecoveryIntervalSeconds),
};
return await factory.CreateConnectionAsync(CancellationToken);
});
}
public async ValueTask DisposeAsync()
{
#if NET
await _consumerCts.CancelAsync();
#else
_consumerCts.Cancel();
#endif
var connection = await _lazyConnectionProvider.Value;
if (connection != null)
{
await connection.CloseAsync();
await connection.DisposeAsync();
}
}
}
}