From 16387d9044b5222d80e969c1c90d562f67facb25 Mon Sep 17 00:00:00 2001 From: Filip Bekic Date: Tue, 29 Oct 2024 15:58:43 +0100 Subject: [PATCH] Add connection provider --- .../ResQueue/Endpoints/AuthEndpoints.cs | 11 +- .../ResQueue/Endpoints/QueuesEndpoints.cs | 27 ++-- .../Factories/DatabaseConnectionFactory.cs | 14 +-- .../DeleteMessages/DeleteMessagesFeature.cs | 9 +- .../GetMessages/GetMessagesFeature.cs | 19 +-- .../Messages/PurgeQueue/PurgeQueueFeature.cs | 9 +- .../RequeueMessages/RequeueMessagesFeature.cs | 9 +- .../RequeueSpecificMessagesFeature.cs | 9 +- .../ResQueue/Migrations/SqlMigrations.cs | 16 +-- .../DbConnectionProvider.cs | 117 ++++++++++++++++++ .../IDbConnectionProvider.cs | 15 +++ .../ResQueue/ResQueue/ResQueueExtensions.cs | 2 + backend/ResQueue/ResQueue/ResQueueOptions.cs | 36 ++---- backend/ResQueue/WebSample/Program.cs | 62 +++------- 14 files changed, 222 insertions(+), 133 deletions(-) create mode 100644 backend/ResQueue/ResQueue/Providers/DbConnectionProvider/DbConnectionProvider.cs create mode 100644 backend/ResQueue/ResQueue/Providers/DbConnectionProvider/IDbConnectionProvider.cs diff --git a/backend/ResQueue/ResQueue/Endpoints/AuthEndpoints.cs b/backend/ResQueue/ResQueue/Endpoints/AuthEndpoints.cs index 35f826c..80e01bb 100644 --- a/backend/ResQueue/ResQueue/Endpoints/AuthEndpoints.cs +++ b/backend/ResQueue/ResQueue/Endpoints/AuthEndpoints.cs @@ -1,6 +1,3 @@ -using Microsoft.Extensions.Options; -using ResQueue.Dtos; - namespace ResQueue.Endpoints; public static class AuthEndpoints @@ -9,12 +6,6 @@ public static void MapAuthEndpoints(this IEndpointRouteBuilder routes) { RouteGroupBuilder group = routes.MapGroup("auth"); - group.MapGet("", (IOptions options) => Results.Ok(new AuthDto( - SqlEngine: options.Value.SqlEngine, - Username: options.Value.Username, - Database: options.Value.Database, - Schema: options.Value.Schema, - Port: options.Value.Port - ))); + group.MapGet("", () => Results.Ok()); } } \ No newline at end of file diff --git a/backend/ResQueue/ResQueue/Endpoints/QueuesEndpoints.cs b/backend/ResQueue/ResQueue/Endpoints/QueuesEndpoints.cs index ea9c419..2696c37 100644 --- a/backend/ResQueue/ResQueue/Endpoints/QueuesEndpoints.cs +++ b/backend/ResQueue/ResQueue/Endpoints/QueuesEndpoints.cs @@ -6,6 +6,7 @@ using ResQueue.Enums; using ResQueue.Factories; using ResQueue.Features.Messages.PurgeQueue; +using ResQueue.Providers.DbConnectionProvider; namespace ResQueue.Endpoints; @@ -15,9 +16,9 @@ public static void MapQueueEndpoints(this IEndpointRouteBuilder routes) { RouteGroupBuilder group = routes.MapGroup("queues"); - group.MapGet("view", async (IDatabaseConnectionFactory connectionFactory, IOptions options) => + group.MapGet("view", async (IDatabaseConnectionFactory connectionFactory, IDbConnectionProvider conn) => { - var sql = options.Value.SqlEngine switch + var sql = conn.SqlEngine switch { ResQueueSqlEngine.Postgres => $""" SELECT @@ -33,7 +34,7 @@ public static void MapQueueEndpoints(this IEndpointRouteBuilder routes) dead_letter_count AS DeadLetterCount, '' AS CountStartTime, count_duration AS CountDuration - FROM {options.Value.Schema}.queues; + FROM {conn.Schema}.queues; """, ResQueueSqlEngine.SqlServer => $""" SELECT @@ -49,7 +50,7 @@ count_duration AS CountDuration DeadLetterCount, CountStartTime, CountDuration - FROM {options.Value.Schema}.Queues; + FROM {conn.Schema}.Queues; """, _ => throw new NotSupportedException("Unsupported SQL engine") }; @@ -62,9 +63,9 @@ count_duration AS CountDuration }); group.MapGet("view/{queueName}", async (IDatabaseConnectionFactory connectionFactory, - IOptions options, string queueName) => + IDbConnectionProvider conn, string queueName) => { - var sql = options.Value.SqlEngine switch + var sql = conn.SqlEngine switch { ResQueueSqlEngine.Postgres => $""" SELECT @@ -80,7 +81,7 @@ count_duration AS CountDuration dead_letter_count AS DeadLetterCount, '' AS CountStartTime, count_duration AS CountDuration - FROM {options.Value.Schema}.queues + FROM {conn.Schema}.queues WHERE queue_name = @QueueName; """, ResQueueSqlEngine.SqlServer => $""" @@ -97,7 +98,7 @@ count_duration AS CountDuration DeadLetterCount, CountStartTime, CountDuration - FROM {options.Value.Schema}.Queues + FROM {conn.Schema}.Queues WHERE QueueName = @QueueName; """, _ => throw new NotSupportedException("Unsupported SQL engine") @@ -112,9 +113,9 @@ count_duration AS CountDuration group.MapGet("", async ([FromQuery] string queueName, IDatabaseConnectionFactory connectionFactory, - IOptions options) => + IDbConnectionProvider conn) => { - var sql = options.Value.SqlEngine switch + var sql = conn.SqlEngine switch { ResQueueSqlEngine.Postgres => $""" SELECT @@ -123,7 +124,7 @@ count_duration AS CountDuration name AS Name, type AS Type, auto_delete AS AutoDelete - FROM {options.Value.Schema}.queue + FROM {conn.Schema}.queue WHERE name = @QueueName; """, ResQueueSqlEngine.SqlServer => $""" @@ -133,7 +134,7 @@ auto_delete AS AutoDelete Name, CAST(type AS INT) AS Type, AutoDelete - FROM {options.Value.Schema}.Queue + FROM {conn.Schema}.Queue WHERE Name = @QueueName; """, _ => throw new NotSupportedException("Unsupported SQL engine") @@ -147,7 +148,7 @@ auto_delete AS AutoDelete }); group.MapPost("purge", - async (IPurgeQueueFeature feature, IOptions options, [FromBody] PurgeQueueDto dto) => + async (IPurgeQueueFeature feature, IDbConnectionProvider conn, [FromBody] PurgeQueueDto dto) => { var result = await feature.ExecuteAsync(new PurgeQueueRequest(dto)); diff --git a/backend/ResQueue/ResQueue/Factories/DatabaseConnectionFactory.cs b/backend/ResQueue/ResQueue/Factories/DatabaseConnectionFactory.cs index eff9f3f..80aa85b 100644 --- a/backend/ResQueue/ResQueue/Factories/DatabaseConnectionFactory.cs +++ b/backend/ResQueue/ResQueue/Factories/DatabaseConnectionFactory.cs @@ -1,22 +1,20 @@ using System.Data.Common; using Microsoft.Data.SqlClient; -using Microsoft.Extensions.Options; using Npgsql; using ResQueue.Enums; +using ResQueue.Providers.DbConnectionProvider; namespace ResQueue.Factories; public class DatabaseConnectionFactory( - IOptions options + IDbConnectionProvider conn ) : IDatabaseConnectionFactory { - private readonly ResQueueOptions _options = options.Value; - - public DbConnection CreateConnection() => _options.SqlEngine switch + public DbConnection CreateConnection() => conn.SqlEngine switch { - ResQueueSqlEngine.Postgres => new NpgsqlConnection(_options.ConnectionString), - ResQueueSqlEngine.SqlServer => new SqlConnection(_options.ConnectionString), - _ => throw new NotSupportedException($"The SQL engine '{_options.SqlEngine}' is not supported.") + ResQueueSqlEngine.Postgres => new NpgsqlConnection(conn.ConnectionString), + ResQueueSqlEngine.SqlServer => new SqlConnection(conn.ConnectionString), + _ => throw new NotSupportedException() }; public DbCommand CreateCommand(string commandText, DbConnection connection) diff --git a/backend/ResQueue/ResQueue/Features/Messages/DeleteMessages/DeleteMessagesFeature.cs b/backend/ResQueue/ResQueue/Features/Messages/DeleteMessages/DeleteMessagesFeature.cs index e395ae0..e1f9811 100644 --- a/backend/ResQueue/ResQueue/Features/Messages/DeleteMessages/DeleteMessagesFeature.cs +++ b/backend/ResQueue/ResQueue/Features/Messages/DeleteMessages/DeleteMessagesFeature.cs @@ -4,6 +4,7 @@ using ResQueue.Dtos.Messages; using ResQueue.Enums; using ResQueue.Factories; +using ResQueue.Providers.DbConnectionProvider; namespace ResQueue.Features.Messages.DeleteMessages; @@ -15,7 +16,7 @@ public record DeleteMessagesResponse(); public class DeleteMessagesFeature( IDatabaseConnectionFactory connectionFactory, - IOptions options + IDbConnectionProvider conn ) : IDeleteMessagesFeature { public async Task> ExecuteAsync(DeleteMessagesRequest request) @@ -51,15 +52,15 @@ private async Task CallRoutineAsync(long messageDeliveryId, DbConnection connect var parameters = new DynamicParameters(); string commandText; - switch (options.Value.SqlEngine) + switch (conn.SqlEngine) { case ResQueueSqlEngine.Postgres: - commandText = $"SELECT {options.Value.Schema}._resqueue_delete_message(@message_delivery_id)"; + commandText = $"SELECT {conn.Schema}._resqueue_delete_message(@message_delivery_id)"; parameters.Add("message_delivery_id", messageDeliveryId); break; case ResQueueSqlEngine.SqlServer: - commandText = $"EXEC {options.Value.Schema}._ResQueue_DeleteMessage @messageDeliveryId"; + commandText = $"EXEC {conn.Schema}._ResQueue_DeleteMessage @messageDeliveryId"; parameters.Add("messageDeliveryId", messageDeliveryId); break; diff --git a/backend/ResQueue/ResQueue/Features/Messages/GetMessages/GetMessagesFeature.cs b/backend/ResQueue/ResQueue/Features/Messages/GetMessages/GetMessagesFeature.cs index d3de727..c0b6196 100644 --- a/backend/ResQueue/ResQueue/Features/Messages/GetMessages/GetMessagesFeature.cs +++ b/backend/ResQueue/ResQueue/Features/Messages/GetMessages/GetMessagesFeature.cs @@ -3,6 +3,7 @@ using ResQueue.Dtos.Messages; using ResQueue.Enums; using ResQueue.Factories; +using ResQueue.Providers.DbConnectionProvider; namespace ResQueue.Features.Messages.GetMessages; @@ -17,7 +18,7 @@ PaginatedResult Messages public class GetMessagesFeature( IDatabaseConnectionFactory connectionFactory, - IOptions options + IDbConnectionProvider conn ) : IGetMessagesFeature { public async Task> ExecuteAsync(GetMessagesRequest request) @@ -60,19 +61,19 @@ public async Task> ExecuteAsync(GetMessages private string GetSqlQueryCountText() { - return options.Value.SqlEngine switch + return conn.SqlEngine switch { ResQueueSqlEngine.Postgres => - $"SELECT COUNT(*) FROM {options.Value.Schema}.message_delivery WHERE queue_id = @QueueId", + $"SELECT COUNT(*) FROM {conn.Schema}.message_delivery WHERE queue_id = @QueueId", ResQueueSqlEngine.SqlServer => - $"SELECT COUNT(*) FROM {options.Value.Schema}.MessageDelivery WHERE QueueId = @QueueId", + $"SELECT COUNT(*) FROM {conn.Schema}.MessageDelivery WHERE QueueId = @QueueId", _ => throw new NotSupportedException("Unsupported SQL Engine") }; } private string GetSqlQueryText() { - return options.Value.SqlEngine switch + return conn.SqlEngine switch { ResQueueSqlEngine.Postgres => $""" SELECT @@ -108,8 +109,8 @@ private string GetSqlQueryText() md.max_delivery_count AS MaxDeliveryCount, md.last_delivered AS LastDelivered, md.transport_headers AS TransportHeaders - FROM {options.Value.Schema}.message_delivery md - LEFT JOIN {options.Value.Schema}.message m ON m.transport_message_id = md.transport_message_id + FROM {conn.Schema}.message_delivery md + LEFT JOIN {conn.Schema}.message m ON m.transport_message_id = md.transport_message_id WHERE md.queue_id = @QueueId ORDER BY md.message_delivery_id LIMIT @PageSize OFFSET @Offset @@ -148,8 +149,8 @@ LIMIT @PageSize OFFSET @Offset md.MaxDeliveryCount, md.LastDelivered, md.TransportHeaders - FROM {options.Value.Schema}.MessageDelivery md - LEFT JOIN {options.Value.Schema}.Message m ON m.TransportMessageId = md.TransportMessageId + FROM {conn.Schema}.MessageDelivery md + LEFT JOIN {conn.Schema}.Message m ON m.TransportMessageId = md.TransportMessageId WHERE md.QueueId = @QueueId ORDER BY md.MessageDeliveryId OFFSET @Offset ROWS FETCH NEXT @PageSize ROWS ONLY; diff --git a/backend/ResQueue/ResQueue/Features/Messages/PurgeQueue/PurgeQueueFeature.cs b/backend/ResQueue/ResQueue/Features/Messages/PurgeQueue/PurgeQueueFeature.cs index 90288ba..4062419 100644 --- a/backend/ResQueue/ResQueue/Features/Messages/PurgeQueue/PurgeQueueFeature.cs +++ b/backend/ResQueue/ResQueue/Features/Messages/PurgeQueue/PurgeQueueFeature.cs @@ -4,6 +4,7 @@ using ResQueue.Dtos.Messages; using ResQueue.Enums; using ResQueue.Factories; +using ResQueue.Providers.DbConnectionProvider; namespace ResQueue.Features.Messages.PurgeQueue; @@ -15,7 +16,7 @@ public record PurgeQueueResponse(); public class PurgeQueueFeature( IDatabaseConnectionFactory connectionFactory, - IOptions options + IDbConnectionProvider conn ) : IPurgeQueueFeature { public async Task> ExecuteAsync(PurgeQueueRequest request) @@ -34,15 +35,15 @@ private async Task CallRoutineAsync(PurgeQueueRequest request, DbConnection conn var parameters = new DynamicParameters(); string commandText; - switch (options.Value.SqlEngine) + switch (conn.SqlEngine) { case ResQueueSqlEngine.Postgres: - commandText = $"SELECT {options.Value.Schema}._resqueue_purge_queue_by_id(@queue_id)"; + commandText = $"SELECT {conn.Schema}._resqueue_purge_queue_by_id(@queue_id)"; parameters.Add("queue_id", request.Dto.QueueId); break; case ResQueueSqlEngine.SqlServer: - commandText = $"EXEC {options.Value.Schema}._ResQueue_PurgeQueueById @queueId"; + commandText = $"EXEC {conn.Schema}._ResQueue_PurgeQueueById @queueId"; parameters.Add("queueId", request.Dto.QueueId); break; diff --git a/backend/ResQueue/ResQueue/Features/Messages/RequeueMessages/RequeueMessagesFeature.cs b/backend/ResQueue/ResQueue/Features/Messages/RequeueMessages/RequeueMessagesFeature.cs index cb6ea59..a96b3b1 100644 --- a/backend/ResQueue/ResQueue/Features/Messages/RequeueMessages/RequeueMessagesFeature.cs +++ b/backend/ResQueue/ResQueue/Features/Messages/RequeueMessages/RequeueMessagesFeature.cs @@ -6,6 +6,7 @@ using ResQueue.Dtos.Messages; using ResQueue.Enums; using ResQueue.Factories; +using ResQueue.Providers.DbConnectionProvider; namespace ResQueue.Features.Messages.RequeueMessages; @@ -17,7 +18,7 @@ public record RequeueMessagesResponse(); public class RequeueMessagesFeature( IDatabaseConnectionFactory connectionFactory, - IOptions options + IDbConnectionProvider conn ) : IRequeueMessagesFeature { public async Task> ExecuteAsync(RequeueMessagesRequest request) @@ -36,11 +37,11 @@ private async Task CallRoutineAsync(RequeueMessagesRequest request, DbConnection var parameters = new DynamicParameters(); string commandText; - switch (options.Value.SqlEngine) + switch (conn.SqlEngine) { case ResQueueSqlEngine.Postgres: commandText = - $"SELECT {options.Value.Schema}.requeue_messages(@queue_name, @source_queue_type, @target_queue_type, @message_count, @delay::text::interval, @redelivery_count)"; + $"SELECT {conn.Schema}.requeue_messages(@queue_name, @source_queue_type, @target_queue_type, @message_count, @delay::text::interval, @redelivery_count)"; parameters.Add("queue_name", request.Dto.QueueName); parameters.Add("source_queue_type", request.Dto.SourceQueueType); parameters.Add("target_queue_type", request.Dto.TargetQueueType); @@ -51,7 +52,7 @@ private async Task CallRoutineAsync(RequeueMessagesRequest request, DbConnection case ResQueueSqlEngine.SqlServer: commandText = - $"EXEC {options.Value.Schema}.RequeueMessages @queueName, @sourceQueueType, @targetQueueType, @messageCount, @delay, @redeliveryCount"; + $"EXEC {conn.Schema}.RequeueMessages @queueName, @sourceQueueType, @targetQueueType, @messageCount, @delay, @redeliveryCount"; parameters.Add("queueName", request.Dto.QueueName); parameters.Add("sourceQueueType", request.Dto.SourceQueueType); parameters.Add("targetQueueType", request.Dto.TargetQueueType); diff --git a/backend/ResQueue/ResQueue/Features/Messages/RequeueSpecificMessages/RequeueSpecificMessagesFeature.cs b/backend/ResQueue/ResQueue/Features/Messages/RequeueSpecificMessages/RequeueSpecificMessagesFeature.cs index df346ca..3e124fe 100644 --- a/backend/ResQueue/ResQueue/Features/Messages/RequeueSpecificMessages/RequeueSpecificMessagesFeature.cs +++ b/backend/ResQueue/ResQueue/Features/Messages/RequeueSpecificMessages/RequeueSpecificMessagesFeature.cs @@ -6,6 +6,7 @@ using ResQueue.Dtos.Messages; using ResQueue.Enums; using ResQueue.Factories; +using ResQueue.Providers.DbConnectionProvider; namespace ResQueue.Features.Messages.RequeueSpecificMessages; @@ -17,7 +18,7 @@ public record RequeueSpecificMessagesResponse(); public class RequeueSpecificMessagesFeature( IDatabaseConnectionFactory connectionFactory, - IOptions options + IDbConnectionProvider conn ) : IRequeueSpecificMessagesFeature { public async Task> ExecuteAsync( @@ -57,11 +58,11 @@ private async Task CallRoutineAsync(RequeueSpecificMessagesRequest request, long var parameters = new DynamicParameters(); string commandText; - switch (options.Value.SqlEngine) + switch (conn.SqlEngine) { case ResQueueSqlEngine.Postgres: commandText = - $"SELECT {options.Value.Schema}.requeue_message(@message_delivery_id, @target_queue_type, @delay::text::interval, @redelivery_count)"; + $"SELECT {conn.Schema}.requeue_message(@message_delivery_id, @target_queue_type, @delay::text::interval, @redelivery_count)"; parameters.Add("message_delivery_id", deliveryMessageId); parameters.Add("target_queue_type", request.Dto.TargetQueueType); parameters.Add("delay", request.Dto.Delay); @@ -70,7 +71,7 @@ private async Task CallRoutineAsync(RequeueSpecificMessagesRequest request, long case ResQueueSqlEngine.SqlServer: commandText = - $"EXEC {options.Value.Schema}.RequeueMessage @messageDeliveryId, @targetQueueType, @delay, @redeliveryCount"; + $"EXEC {conn.Schema}.RequeueMessage @messageDeliveryId, @targetQueueType, @delay, @redeliveryCount"; parameters.Add("messageDeliveryId", deliveryMessageId); parameters.Add("targetQueueType", request.Dto.TargetQueueType); parameters.Add("delay", request.Dto.Delay); diff --git a/backend/ResQueue/ResQueue/Migrations/SqlMigrations.cs b/backend/ResQueue/ResQueue/Migrations/SqlMigrations.cs index 135c1a6..3342785 100644 --- a/backend/ResQueue/ResQueue/Migrations/SqlMigrations.cs +++ b/backend/ResQueue/ResQueue/Migrations/SqlMigrations.cs @@ -1,12 +1,12 @@ -using Microsoft.Extensions.Options; using ResQueue.Enums; using ResQueue.Factories; +using ResQueue.Providers.DbConnectionProvider; namespace ResQueue.Migrations; public class SqlMigrations( IDatabaseConnectionFactory connectionFactory, - IOptions options + IDbConnectionProvider conn ) : IHostedService { public async Task StartAsync(CancellationToken cancellationToken) @@ -27,7 +27,7 @@ public Task StopAsync(CancellationToken cancellationToken) } private string GetPurgeQueueByIdCommand() => - options.Value.SqlEngine switch + conn.SqlEngine switch { ResQueueSqlEngine.Postgres => string.Format(""" @@ -54,7 +54,7 @@ AND NOT EXISTS(SELECT WHERE md.transport_message_id = m.transport_message_id); END; $$; - """, options.Value.Schema), + """, conn.Schema), ResQueueSqlEngine.SqlServer => string.Format(""" CREATE OR ALTER PROCEDURE {0}._ResQueue_PurgeQueueById @@ -77,12 +77,12 @@ SELECT 1 WHERE md.TransportMessageId = {0}.message.TransportMessageId ); END; - """, options.Value.Schema), + """, conn.Schema), _ => throw new ArgumentOutOfRangeException() }; private string GetDeleteMessageCommand() => - options.Value.SqlEngine switch + conn.SqlEngine switch { ResQueueSqlEngine.Postgres => string.Format(""" @@ -107,7 +107,7 @@ DELETE FROM {0}.message m END IF; END; $$; - """, options.Value.Schema), + """, conn.Schema), ResQueueSqlEngine.SqlServer => string.Format(""" CREATE OR ALTER PROCEDURE {0}._ResQueue_DeleteMessage @@ -142,7 +142,7 @@ DELETE m AND NOT EXISTS (SELECT 1 FROM {0}.MessageDelivery md WHERE md.TransportMessageId = @outTransportMessageId); END; END; - """, options.Value.Schema), + """, conn.Schema), _ => throw new ArgumentOutOfRangeException() }; } \ No newline at end of file diff --git a/backend/ResQueue/ResQueue/Providers/DbConnectionProvider/DbConnectionProvider.cs b/backend/ResQueue/ResQueue/Providers/DbConnectionProvider/DbConnectionProvider.cs new file mode 100644 index 0000000..be3db13 --- /dev/null +++ b/backend/ResQueue/ResQueue/Providers/DbConnectionProvider/DbConnectionProvider.cs @@ -0,0 +1,117 @@ +using System.Data.Common; +using Microsoft.Data.SqlClient; +using Microsoft.Extensions.Options; +using Npgsql; +using ResQueue.Enums; + +namespace ResQueue.Providers.DbConnectionProvider +{ + public class DbConnectionProvider : IDbConnectionProvider + { + public string? Host { get; private set; } + public int? Port { get; private set; } + public string? Database { get; private set; } + public string? Schema { get; private set; } + public string? Username { get; private set; } + public string? Password { get; private set; } + public string? ConnectionString { get; private set; } + public ResQueueSqlEngine SqlEngine { get; private set; } + + public DbConnectionProvider(IOptions options) + { + SqlEngine = options.Value.SqlEngine; + Host = options.Value.Host; + Port = options.Value.Port; + Database = options.Value.Database; + Schema = string.IsNullOrEmpty(options.Value.Schema) + ? "transport" + : options.Value.Schema; + Username = options.Value.Username; + Password = options.Value.Password; + ConnectionString = options.Value.ConnectionString; + + if (!string.IsNullOrEmpty(options.Value.ConnectionString)) + { + ParseConnectionString(options.Value.ConnectionString); + } + else + { + ConnectionString = GenerateConnectionString(); + } + } + + private void ParseConnectionString(string connectionString) + { + DbConnectionStringBuilder builder; + + switch (SqlEngine) + { + case ResQueueSqlEngine.SqlServer: + builder = new SqlConnectionStringBuilder(connectionString); + Host = builder.TryGetValue("Data Source", out var sqlHost) ? sqlHost.ToString() : null; + Database = builder.TryGetValue("Initial Catalog", out var sqlDatabase) + ? sqlDatabase.ToString() + : null; + Username = builder.TryGetValue("User ID", out var sqlUser) ? sqlUser.ToString() : null; + Password = builder.TryGetValue("Password", out var sqlPassword) ? sqlPassword.ToString() : null; + break; + + case ResQueueSqlEngine.Postgres: + builder = new NpgsqlConnectionStringBuilder(connectionString); + Host = builder.TryGetValue("Host", out var pgHost) ? pgHost.ToString() : null; + Port = builder.TryGetValue("Port", out var pgPort) + ? int.TryParse(pgPort.ToString(), out var port) ? port : (int?)null + : null; + Database = builder.TryGetValue("Database", out var pgDatabase) ? pgDatabase.ToString() : null; + Username = builder.TryGetValue("Username", out var pgUser) ? pgUser.ToString() : null; + Password = builder.TryGetValue("Password", out var pgPassword) ? pgPassword.ToString() : null; + break; + + default: + throw new NotSupportedException(); + } + } + + private string GenerateConnectionString() + { + switch (SqlEngine) + { + case ResQueueSqlEngine.SqlServer: + var sqlBuilder = new SqlConnectionStringBuilder + { + DataSource = Host, + InitialCatalog = Database, + IntegratedSecurity = false, + TrustServerCertificate = true + }; + + if (!string.IsNullOrEmpty(Username)) + { + sqlBuilder.UserID = Username; + } + + if (!string.IsNullOrEmpty(Password)) + { + sqlBuilder.Password = Password; + } + + return sqlBuilder.ConnectionString; + + case ResQueueSqlEngine.Postgres: + var pgBuilder = new NpgsqlConnectionStringBuilder + { + Host = Host, + Port = Port ?? 5432, + Database = Database, + Username = Username, + Password = Password + }; + + return pgBuilder.ConnectionString; + + default: + throw new NotSupportedException(); + } + } + } +} \ No newline at end of file diff --git a/backend/ResQueue/ResQueue/Providers/DbConnectionProvider/IDbConnectionProvider.cs b/backend/ResQueue/ResQueue/Providers/DbConnectionProvider/IDbConnectionProvider.cs new file mode 100644 index 0000000..014f53c --- /dev/null +++ b/backend/ResQueue/ResQueue/Providers/DbConnectionProvider/IDbConnectionProvider.cs @@ -0,0 +1,15 @@ +using ResQueue.Enums; + +namespace ResQueue.Providers.DbConnectionProvider; + +public interface IDbConnectionProvider +{ + string? Host { get; } + int? Port { get; } + string? Database { get; } + string? Schema { get; } + string? Username { get; } + string? Password { get; } + string? ConnectionString { get; } + ResQueueSqlEngine SqlEngine { get; } +} \ No newline at end of file diff --git a/backend/ResQueue/ResQueue/ResQueueExtensions.cs b/backend/ResQueue/ResQueue/ResQueueExtensions.cs index b157055..ae4aaf2 100644 --- a/backend/ResQueue/ResQueue/ResQueueExtensions.cs +++ b/backend/ResQueue/ResQueue/ResQueueExtensions.cs @@ -10,6 +10,7 @@ using ResQueue.Features.Messages.RequeueMessages; using ResQueue.Features.Messages.RequeueSpecificMessages; using ResQueue.Migrations; +using ResQueue.Providers.DbConnectionProvider; namespace ResQueue; @@ -21,6 +22,7 @@ public static WebApplicationBuilder AddResQueue(this WebApplicationBuilder build builder.Services.Configure(configureOptions); builder.Services.AddSingleton(); + builder.Services.AddSingleton(); builder.Services.AddTransient(); builder.Services.AddTransient(); diff --git a/backend/ResQueue/ResQueue/ResQueueOptions.cs b/backend/ResQueue/ResQueue/ResQueueOptions.cs index 8ebda8b..d35888f 100644 --- a/backend/ResQueue/ResQueue/ResQueueOptions.cs +++ b/backend/ResQueue/ResQueue/ResQueueOptions.cs @@ -1,28 +1,16 @@ using ResQueue.Enums; -namespace ResQueue; - -public class ResQueueOptions +namespace ResQueue { - public ResQueueSqlEngine SqlEngine { get; set; } = ResQueueSqlEngine.Postgres; - public string? Host { get; set; } - public int? Port { get; set; } - public string? Database { get; set; } - public string? Schema { get; set; } - public string? Username { get; set; } - public string? Password { get; set; } - // public bool UseTls { get; set; } = false; - - internal string ConnectionString => - SqlEngine switch - { - ResQueueSqlEngine.Postgres => - $"Host={Host};Port={Port ?? 5432};Database={Database};Username={Username};Password={Password};" + - $"SearchPath={Schema};", - - ResQueueSqlEngine.SqlServer => - $"Server={Host},{Port ?? 1433};Database={Database};User Id={Username};Password={Password};TrustServerCertificate=True", - - _ => throw new NotSupportedException($"The SQL engine '{SqlEngine}' is not supported.") - }; + public class ResQueueOptions + { + public string? Host { get; set; } + public int? Port { get; set; } + public string? Database { get; set; } + public string? Schema { get; set; } + public string? Username { get; set; } + public string? Password { get; set; } + public string? ConnectionString { get; set; } + public ResQueueSqlEngine SqlEngine { get; set; } = ResQueueSqlEngine.Postgres; + } } \ No newline at end of file diff --git a/backend/ResQueue/WebSample/Program.cs b/backend/ResQueue/WebSample/Program.cs index 944fe04..b923da8 100644 --- a/backend/ResQueue/WebSample/Program.cs +++ b/backend/ResQueue/WebSample/Program.cs @@ -1,8 +1,5 @@ -using System.Reflection; using Marten; using MassTransit; -using Microsoft.AspNetCore.Rewrite; -using Microsoft.Extensions.FileProviders; using ResQueue; using ResQueue.Enums; @@ -25,52 +22,27 @@ public static void Main(string[] args) }); }); + // Server=localhost,1433;Database=sandbox201;User Id=sa;Password=YourStrong!Passw0rd;TrustServerCertificate=True + // Host=localhost;Database=sandbox201;Username=postgres;Password=postgres; builder.AddResQueue(opt => { - // // postgres - // opt.Host = "localhost"; - // opt.Database = "sandbox201"; - // opt.Schema = "transport"; - // opt.Username = "postgres"; - // opt.Password = "postgres"; - // opt.Port = 5432; - - // sqlserver - opt.Host = "localhost"; - opt.Database = "sandbox201"; - opt.Schema = "transport"; - opt.Username = "sa"; - opt.Password = "YourStrong!Passw0rd"; - opt.Port = 1433; - opt.SqlEngine = ResQueueSqlEngine.SqlServer; + opt.SqlEngine = ResQueueSqlEngine.Postgres; + opt.ConnectionString = + "Host=localhost;Database=sandbox201;Username=postgres;Password=postgres;"; }); - builder.Services.AddOptions().Configure(options => { - // // postgres - // options.Host = "localhost"; - // options.Database = "sandbox201"; - // options.Schema = "transport"; - // options.Role = "transport"; - // options.Username = "postgres"; - // options.Password = "postgres"; - - // sqlserver - options.Host = "localhost"; - options.Database = "sandbox201"; - options.Schema = "transport"; - options.Role = "transport"; - options.Username = "sa"; - options.Password = "YourStrong!Passw0rd"; + options.ConnectionString = + "Host=localhost;Database=sandbox201;Username=postgres;Password=postgres;"; }); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); - // Order is important because MassTransit will create database on boot, if missing. - // builder.Services.AddPostgresMigrationHostedService(); - builder.Services.AddSqlServerMigrationHostedService(); + builder.Services.AddPostgresMigrationHostedService(); + // builder.Services.AddSqlServerMigrationHostedService(); + // Must go after MassTransit migrations builder.Services.AddResQueueMigrationsHostedService(); builder.Services.AddMarten(x => @@ -91,17 +63,17 @@ public static void Main(string[] args) mt.AddJobSagaStateMachines(); - // mt.UsingPostgres((context, config) => - // { - // config.UseSqlMessageScheduler(); - // config.ConfigureEndpoints(context); - // }); - - mt.UsingSqlServer((context, config) => + mt.UsingPostgres((context, config) => { config.UseSqlMessageScheduler(); config.ConfigureEndpoints(context); }); + + // mt.UsingSqlServer((context, config) => + // { + // config.UseSqlMessageScheduler(); + // config.ConfigureEndpoints(context); + // }); }); var app = builder.Build();