From 14185b99773a61bd61a5fcbe6f938d9b7e52fa21 Mon Sep 17 00:00:00 2001 From: fraliv13 <5892139+fraliv13@users.noreply.github.com> Date: Wed, 18 Sep 2024 17:06:07 +0300 Subject: [PATCH 1/5] Connection string parts validation --- .../TenantConfigurationExtensions.cs | 14 ++++++ .../TenantConfigurationTests.cs | 50 ++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/MultiTenancy/NBB.MultiTenancy.Abstractions/Configuration/TenantConfigurationExtensions.cs b/src/MultiTenancy/NBB.MultiTenancy.Abstractions/Configuration/TenantConfigurationExtensions.cs index 7866b3aa..0cbc52a2 100644 --- a/src/MultiTenancy/NBB.MultiTenancy.Abstractions/Configuration/TenantConfigurationExtensions.cs +++ b/src/MultiTenancy/NBB.MultiTenancy.Abstractions/Configuration/TenantConfigurationExtensions.cs @@ -2,6 +2,7 @@ // This source code is licensed under the MIT license. using Microsoft.Extensions.Configuration; +using System; using System.Linq; namespace NBB.MultiTenancy.Abstractions.Configuration; @@ -46,6 +47,11 @@ public static string GetConnectionString(this ITenantConfiguration config, strin var splitted = config.GetValue($"ConnectionStrings:{name}"); if (splitted != null) { + CheckMandatoryField(splitted.Server, nameof(splitted.Server)); + CheckMandatoryField(splitted.Database, nameof(splitted.Database)); + CheckMandatoryField(splitted.UserName, nameof(splitted.UserName)); + CheckMandatoryField(splitted.Password, nameof(splitted.Password)); + return $"Server={splitted.Server};Database={splitted.Database};User Id={splitted.UserName};Password={splitted.Password};{splitted.OtherParams}"; } @@ -53,6 +59,14 @@ public static string GetConnectionString(this ITenantConfiguration config, strin return config.GetValue($"ConnectionStrings:{name}"); } + private static void CheckMandatoryField(string fieldValue, string fieldName) { + if (string.IsNullOrWhiteSpace(fieldValue)) + { + throw new ArgumentException($"Connection string part {fieldName} is not provided!"); + } + } + + private class ConnectionStringDetails { public string Server { get; set; } diff --git a/test/UnitTests/MultiTenancy/NBB.MultiTenancy.Configuration.Tests/TenantConfigurationTests.cs b/test/UnitTests/MultiTenancy/NBB.MultiTenancy.Configuration.Tests/TenantConfigurationTests.cs index 85f76873..eebe9943 100644 --- a/test/UnitTests/MultiTenancy/NBB.MultiTenancy.Configuration.Tests/TenantConfigurationTests.cs +++ b/test/UnitTests/MultiTenancy/NBB.MultiTenancy.Configuration.Tests/TenantConfigurationTests.cs @@ -476,6 +476,54 @@ public void load_connectionString_concatenated_with_splitted_defaults() tenantConfig.GetValue("TenantId").Should().Be("68a448a2-e7d8-4875-8127-f18668217eb6"); } - + [Fact] + public void load_connectionString_splitted_tenant1_missing_database() + { + // Arrange + var myConfiguration = @"{ + ""MultiTenancy"": { + ""Tenants"": { + ""MBFS"": { + ""TenantId"": ""68a448a2-e7d8-4875-8127-f18668217eb6"", + ""ConnectionStrings"": { + ""Leasing_Database"": { + ""Server"": ""server1"", + ""Database"": """", + ""UserName"": ""web"", + ""OtherParams"": ""MultipleActiveResultSets=true"" + } + } + }, + ""BCR"": { + ""TenantId"": ""ef8d5362-9969-4e02-8794-0d1af56816f6"", + ""Code"": ""BCR"" + }, + ""DEV"": { + ""TenantId"": ""da84628a-2925-4b69-9116-a90dd5a72b1f"", + ""Code"": ""DEV"" + } + } + } + }"; + + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection() + .AddJsonStream(new MemoryStream(Encoding.UTF8.GetBytes(myConfiguration))) + .Build(); + + var tid = Guid.Parse("68a448a2-e7d8-4875-8127-f18668217eb6"); + var tca = new TenantContextAccessor(); + + tca.TenantContext = new TenantContext(new Tenant(tid, "MBFS")); + var tenantConfig = new TenantConfiguration(configuration, + new OptionsWrapper(new TenancyHostingOptions() + { TenancyType = TenancyType.MultiTenant }), tca); + + // Act + Action act = () => tenantConfig.GetConnectionString("Leasing_Database"); + + // Assert + act.Should().Throw().WithMessage("Connection string part Database is not provided!"); + } } } From e6371d6e8af3480e02e5345ea1c86211e0c70699 Mon Sep 17 00:00:00 2001 From: fraliv13 <5892139+fraliv13@users.noreply.github.com> Date: Wed, 18 Sep 2024 17:21:11 +0300 Subject: [PATCH 2/5] Fixed tests --- .../TenantConfigurationTests.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/test/UnitTests/MultiTenancy/NBB.MultiTenancy.Configuration.Tests/TenantConfigurationTests.cs b/test/UnitTests/MultiTenancy/NBB.MultiTenancy.Configuration.Tests/TenantConfigurationTests.cs index eebe9943..fdec0057 100644 --- a/test/UnitTests/MultiTenancy/NBB.MultiTenancy.Configuration.Tests/TenantConfigurationTests.cs +++ b/test/UnitTests/MultiTenancy/NBB.MultiTenancy.Configuration.Tests/TenantConfigurationTests.cs @@ -209,6 +209,7 @@ public void load_connectionString_splitted_without_defaults() ""Server"": ""server1"", ""Database"": ""db1"", ""UserName"": ""web"", + ""Password"": ""pass"", ""OtherParams"": ""MultipleActiveResultSets=true"" } } @@ -242,7 +243,7 @@ public void load_connectionString_splitted_without_defaults() // Assert tenantConfig.GetConnectionString("ConnectionString_").Should().BeNull(); - tenantConfig.GetConnectionString("Leasing_Database").Should().Be("Server=server1;Database=db1;User Id=web;Password=;MultipleActiveResultSets=true"); + tenantConfig.GetConnectionString("Leasing_Database").Should().Be("Server=server1;Database=db1;User Id=web;Password=pass;MultipleActiveResultSets=true"); tenantConfig.GetValue("TenantId").Should().Be("68a448a2-e7d8-4875-8127-f18668217eb6"); } @@ -258,7 +259,8 @@ public void load_connectionString_splitted_from_default() ""Leasing_Database"": { ""Server"": ""cf-erp17\\mama"", ""Database"": ""db1"", - ""UserName"": ""web"" + ""UserName"": ""web"", + ""Password"": ""pass"" } } }, @@ -303,7 +305,7 @@ public void load_connectionString_splitted_from_default() // Assert tenantConfig.GetConnectionString("ConnectionString_").Should().BeNull(); - tenantConfig.GetConnectionString("Leasing_Database").Should().Be("Server=cf-erp17\\mama;Database=db1;User Id=web;Password=;"); + tenantConfig.GetConnectionString("Leasing_Database").Should().Be("Server=cf-erp17\\mama;Database=db1;User Id=web;Password=pass;"); tenantConfig.GetValue("TenantId").Should().Be("ef8d5362-9969-4e02-8794-0d1af56816f6"); } @@ -383,6 +385,7 @@ public void load_connectionString_with_concatenated_defaults() ""Server"": ""server1"", ""Database"": ""db1"", ""UserName"": ""web"", + ""Password"": ""pass"", ""OtherParams"": ""MultipleActiveResultSets=true"" } } @@ -416,7 +419,7 @@ public void load_connectionString_with_concatenated_defaults() // Assert tenantConfig.GetConnectionString("ConnectionString_").Should().BeNull(); - tenantConfig.GetConnectionString("Leasing_Database").Should().Be("Server=server1;Database=db1;User Id=web;Password=;MultipleActiveResultSets=true"); + tenantConfig.GetConnectionString("Leasing_Database").Should().Be("Server=server1;Database=db1;User Id=web;Password=pass;MultipleActiveResultSets=true"); tenantConfig.GetValue("TenantId").Should().Be("68a448a2-e7d8-4875-8127-f18668217eb6"); } From b9c36106cf7f45b75e03921f8f54fd3254923d73 Mon Sep 17 00:00:00 2001 From: fraliv13 <5892139+fraliv13@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:27:37 +0300 Subject: [PATCH 3/5] Refactor --- .../TenantConfigurationExtensions.cs | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/src/MultiTenancy/NBB.MultiTenancy.Abstractions/Configuration/TenantConfigurationExtensions.cs b/src/MultiTenancy/NBB.MultiTenancy.Abstractions/Configuration/TenantConfigurationExtensions.cs index 0cbc52a2..999ae64e 100644 --- a/src/MultiTenancy/NBB.MultiTenancy.Abstractions/Configuration/TenantConfigurationExtensions.cs +++ b/src/MultiTenancy/NBB.MultiTenancy.Abstractions/Configuration/TenantConfigurationExtensions.cs @@ -44,35 +44,51 @@ private static T getValueOrComplexObject(IConfiguration config, string key) /// public static string GetConnectionString(this ITenantConfiguration config, string name) { - var splitted = config.GetValue($"ConnectionStrings:{name}"); - if (splitted != null) + var connStrBuilder = config.GetValue($"ConnectionStrings:{name}"); + if (connStrBuilder != null) { - CheckMandatoryField(splitted.Server, nameof(splitted.Server)); - CheckMandatoryField(splitted.Database, nameof(splitted.Database)); - CheckMandatoryField(splitted.UserName, nameof(splitted.UserName)); - CheckMandatoryField(splitted.Password, nameof(splitted.Password)); - - return - $"Server={splitted.Server};Database={splitted.Database};User Id={splitted.UserName};Password={splitted.Password};{splitted.OtherParams}"; + return connStrBuilder.Build(); } return config.GetValue($"ConnectionStrings:{name}"); } - private static void CheckMandatoryField(string fieldValue, string fieldName) { - if (string.IsNullOrWhiteSpace(fieldValue)) + public class TenantConnectionStringBuilderException : Exception + { + public TenantConnectionStringBuilderException(string message) : base(message) { - throw new ArgumentException($"Connection string part {fieldName} is not provided!"); } } - - private class ConnectionStringDetails + private class TenantConnectionStringBuilder { public string Server { get; set; } public string Database { get; set; } public string UserName { get; set; } public string Password { get; set; } public string OtherParams { get; set; } + + public string Build() + { + Validate(); + + return $"Server={Server};Database={Database};User Id={UserName};Password={Password};{OtherParams}"; + } + + private static void CheckMandatoryField(string fieldValue, string fieldName) + { + if (string.IsNullOrWhiteSpace(fieldValue)) + { + throw new TenantConnectionStringBuilderException($"Connection string part {fieldName} is not provided!"); + } + } + + private void Validate() + { + CheckMandatoryField(Server, nameof(Server)); + CheckMandatoryField(Database, nameof(Database)); + CheckMandatoryField(UserName, nameof(UserName)); + CheckMandatoryField(Password, nameof(Password)); + } } } From ac3f3611c91deca4d7ae908ad37ab59ce6cfe651 Mon Sep 17 00:00:00 2001 From: fraliv13 <5892139+fraliv13@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:28:15 +0300 Subject: [PATCH 4/5] Documentation --- .../Configuration/TenantConfigurationExtensions.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/MultiTenancy/NBB.MultiTenancy.Abstractions/Configuration/TenantConfigurationExtensions.cs b/src/MultiTenancy/NBB.MultiTenancy.Abstractions/Configuration/TenantConfigurationExtensions.cs index 999ae64e..8a2ad1c5 100644 --- a/src/MultiTenancy/NBB.MultiTenancy.Abstractions/Configuration/TenantConfigurationExtensions.cs +++ b/src/MultiTenancy/NBB.MultiTenancy.Abstractions/Configuration/TenantConfigurationExtensions.cs @@ -53,6 +53,9 @@ public static string GetConnectionString(this ITenantConfiguration config, strin return config.GetValue($"ConnectionStrings:{name}"); } + /// + /// Exception thrown when connection string builder is not properly configured + /// public class TenantConnectionStringBuilderException : Exception { public TenantConnectionStringBuilderException(string message) : base(message) From 0f078b6bd369a10448fce44c01285f7d2b466a82 Mon Sep 17 00:00:00 2001 From: fraliv13 <5892139+fraliv13@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:31:31 +0300 Subject: [PATCH 5/5] Tests update --- .../TenantConfigurationTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/UnitTests/MultiTenancy/NBB.MultiTenancy.Configuration.Tests/TenantConfigurationTests.cs b/test/UnitTests/MultiTenancy/NBB.MultiTenancy.Configuration.Tests/TenantConfigurationTests.cs index fdec0057..5c17a6ca 100644 --- a/test/UnitTests/MultiTenancy/NBB.MultiTenancy.Configuration.Tests/TenantConfigurationTests.cs +++ b/test/UnitTests/MultiTenancy/NBB.MultiTenancy.Configuration.Tests/TenantConfigurationTests.cs @@ -12,6 +12,7 @@ using System.IO; using System.Text; using Xunit; +using static NBB.MultiTenancy.Abstractions.Configuration.TenantConfigurationExtensions; namespace NBB.MultiTenancy.Abstractions.Tests { @@ -526,7 +527,7 @@ public void load_connectionString_splitted_tenant1_missing_database() Action act = () => tenantConfig.GetConnectionString("Leasing_Database"); // Assert - act.Should().Throw().WithMessage("Connection string part Database is not provided!"); + act.Should().Throw().WithMessage("Connection string part Database is not provided!"); } } }