From cdf41d2135cb0f9b295e8719e5dbbd9a62a299fe Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Mon, 12 Aug 2024 14:02:20 +0500 Subject: [PATCH 01/32] Extensions: Configuration reading from new IConfigurationSections *Microsoft.Extensions.Configuration.IConfigurationSection --- .../TestCommon/ModernConfigurationTestBase.cs | 53 +++ Extensions/TestCommon/TestCommon.csproj | 6 + .../LocalizationSettings.config | 135 ++++++ .../ModernConfigurationTests.cs | 312 +++++++++++++ .../Xtensive.Orm.Localization.Tests.csproj | 22 + .../localizationsettings.json | 80 ++++ .../Elements/ConfigurationSection.cs | 1 + .../LocalizationConfiguration.cs | 106 ++++- .../Xtensive.Orm.Localization.csproj | 13 + .../App.config | 2 +- .../ReprocessingSettings.config | 136 ++++++ .../Tests/ModernConfugurationTests.cs | 307 +++++++++++++ .../Xtensive.Orm.Reprocessing.Tests.csproj | 18 + .../reprocessingsettings.json | 72 +++ .../ReprocessingConfiguration.cs | 56 ++- .../Xtensive.Orm.Reprocessing.csproj | 4 + .../Xtensive.Orm.Security.Tests/App.config | 9 +- .../SecuritySettings.config | 225 +++++++++ .../Tests/ConfigurationTests.cs | 29 +- .../Tests/ModernConfigurationTests.cs | 430 ++++++++++++++++++ .../Xtensive.Orm.Security.Tests.csproj | 18 + .../securitysettings.json | 147 ++++++ .../Elements/ConfigurationSection.cs | 18 +- .../Configuration/SecurityConfiguration.cs | 241 +++++++++- .../Xtensive.Orm.Security.csproj | 4 + 25 files changed, 2404 insertions(+), 40 deletions(-) create mode 100644 Extensions/TestCommon/ModernConfigurationTestBase.cs create mode 100644 Extensions/Xtensive.Orm.Localization.Tests/LocalizationSettings.config create mode 100644 Extensions/Xtensive.Orm.Localization.Tests/ModernConfigurationTests.cs create mode 100644 Extensions/Xtensive.Orm.Localization.Tests/localizationsettings.json create mode 100644 Extensions/Xtensive.Orm.Reprocessing.Tests/ReprocessingSettings.config create mode 100644 Extensions/Xtensive.Orm.Reprocessing.Tests/Tests/ModernConfugurationTests.cs create mode 100644 Extensions/Xtensive.Orm.Reprocessing.Tests/reprocessingsettings.json create mode 100644 Extensions/Xtensive.Orm.Security.Tests/SecuritySettings.config create mode 100644 Extensions/Xtensive.Orm.Security.Tests/Tests/ModernConfigurationTests.cs create mode 100644 Extensions/Xtensive.Orm.Security.Tests/securitysettings.json diff --git a/Extensions/TestCommon/ModernConfigurationTestBase.cs b/Extensions/TestCommon/ModernConfigurationTestBase.cs new file mode 100644 index 0000000000..3a263ef80c --- /dev/null +++ b/Extensions/TestCommon/ModernConfigurationTestBase.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; +using NUnit.Framework; + +namespace TestCommon +{ + public abstract class ModernConfigurationTestBase + { + protected enum ConfigTypes + { + Json, + Xml, + } + + protected IConfiguration configuration; + + protected abstract ConfigTypes ConfigFormat { get; } + + protected abstract void AddConfigurationFile(IConfigurationBuilder configurationBuilder); + + [OneTimeSetUp] + public virtual void BeforeAllTestsSetUp() + { + var configurationBuilder = new ConfigurationBuilder(); + configurationBuilder.SetBasePath(Directory.GetCurrentDirectory()); + AddConfigurationFile(configurationBuilder); + configuration = (ConfigurationRoot) configurationBuilder.Build(); + } + + protected void IgnoreIfXml() + { + if (ConfigFormat == ConfigTypes.Xml) + throw new IgnoreException("Not valid for Xml format"); + } + protected void IgnoreIfJson() + { + if (ConfigFormat == ConfigTypes.Json) + throw new IgnoreException("Not valid for JSON format"); + } + + protected IConfigurationSection GetAndCheckConfigurationSection(string sectionName) + { + var section = configuration.GetSection(sectionName); + Assert.That(section, Is.Not.Null); + return section; + } + } +} diff --git a/Extensions/TestCommon/TestCommon.csproj b/Extensions/TestCommon/TestCommon.csproj index e23f0c4aef..5b01dd3730 100644 --- a/Extensions/TestCommon/TestCommon.csproj +++ b/Extensions/TestCommon/TestCommon.csproj @@ -10,9 +10,15 @@ + + + + + + diff --git a/Extensions/Xtensive.Orm.Localization.Tests/LocalizationSettings.config b/Extensions/Xtensive.Orm.Localization.Tests/LocalizationSettings.config new file mode 100644 index 0000000000..8f439a9e13 --- /dev/null +++ b/Extensions/Xtensive.Orm.Localization.Tests/LocalizationSettings.config @@ -0,0 +1,135 @@ + + + + + + + + + + + + + es-ES + + + + ololo + + + + + + + + + es-ES + + + + es-ES + + + + es-ES + + + + es-ES + + + + + + + + + es-ES + + + + es-ES + + + + es-ES + + + + es-ES + + + + + + + + + + + + es-ES + + + + + + ololo + + + + + + es-ES + + + + + + es-ES + + + + + + es-ES + + + + + + es-ES + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Extensions/Xtensive.Orm.Localization.Tests/ModernConfigurationTests.cs b/Extensions/Xtensive.Orm.Localization.Tests/ModernConfigurationTests.cs new file mode 100644 index 0000000000..40e861d528 --- /dev/null +++ b/Extensions/Xtensive.Orm.Localization.Tests/ModernConfigurationTests.cs @@ -0,0 +1,312 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System.Globalization; +using System.Threading; +using Microsoft.Extensions.Configuration; +using NUnit.Framework; +using Xtensive.Orm.Localization.Configuration; + +namespace Xtensive.Orm.Localization.Tests.Configuration +{ + public sealed class JsonConfigurationTest : ModernConfigurationTest + { + protected override ConfigTypes ConfigFormat => ConfigTypes.Json; + + protected override void AddConfigurationFile(IConfigurationBuilder configurationBuilder) + { + _ = configurationBuilder.AddJsonFile("localizationsettings.json"); + } + } + + public sealed class XmlConfigurationTest : ModernConfigurationTest + { + protected override ConfigTypes ConfigFormat => ConfigTypes.Xml; + + protected override void AddConfigurationFile(IConfigurationBuilder configurationBuilder) + { + _ = configurationBuilder.AddXmlFile("LocalizationSettings.config"); + } + + [Test] + public void NameAttributeEmptyNameTest() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Localization.NameAttribute.NameEmpty"); + var locConfig = LocalizationConfiguration.Load(section); + CheckConfigurationIsDefault(locConfig); + } + + [Test] + public void NameAttributeAbsentTest() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Localization.NameAttribute.None"); + var locConfig = LocalizationConfiguration.Load(section); + CheckConfigurationIsDefault(locConfig); + } + + + [Test] + public void NameAttributeDefinedTest() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Localization.NameAttribute.Defined"); + var locConfig = LocalizationConfiguration.Load(section); + Assert.That(locConfig, Is.Not.Null); + Assert.That(locConfig.DefaultCulture, Is.EqualTo(expectedCulture)); + } + + [Test] + public void NameAttributeFaultyValueTest() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Localization.NameAttribute.FaultyValue"); + var locConfig = LocalizationConfiguration.Load(section); + CheckConfigurationIsDefault(locConfig); + } + + [Test] + public void NameAttributeLowCase() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Localization.NameAttribute.LC"); + var locConfig = LocalizationConfiguration.Load(section); + Assert.That(locConfig, Is.Not.Null); + Assert.That(locConfig.DefaultCulture, Is.EqualTo(expectedCulture)); + } + + [Test] + public void NameAttributeUpperCase() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Localization.NameAttribute.UC"); + var locConfig = LocalizationConfiguration.Load(section); + Assert.That(locConfig, Is.Not.Null); + Assert.That(locConfig.DefaultCulture, Is.EqualTo(expectedCulture)); + } + + [Test] + public void NameAttributePascalCase() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Localization.NameAttribute.PC"); + var locConfig = LocalizationConfiguration.Load(section); + Assert.That(locConfig, Is.Not.Null); + Assert.That(locConfig.DefaultCulture, Is.EqualTo(expectedCulture)); + } + } + + [TestFixture] + public abstract class ModernConfigurationTest : TestCommon.ModernConfigurationTestBase + { + protected readonly CultureInfo defaultCulture = new CultureInfo("en-US"); + protected readonly CultureInfo expectedCulture = new CultureInfo("es-ES"); + + private CultureInfo resetCulture; + + public override void BeforeAllTestsSetUp() + { + base.BeforeAllTestsSetUp(); + + } + + [SetUp] + public void SetUp() + { + resetCulture = Thread.CurrentThread.CurrentCulture; + Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); + } + + [TearDown] + public void TearDown() + { + Thread.CurrentThread.CurrentCulture = resetCulture; + } + + [Test] + public void EmptySectionCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.Empty"); + var locConfig = LocalizationConfiguration.Load(section); + CheckConfigurationIsDefault(locConfig); + } + + [Test] + public void EmptyName() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameEmpty"); + var locConfig = LocalizationConfiguration.Load(section); + CheckConfigurationIsDefault(locConfig); + } + + [Test] + public void NameDefined() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameDefined"); + var locConfig = LocalizationConfiguration.Load(section); + Assert.That(locConfig, Is.Not.Null); + Assert.That(locConfig.DefaultCulture, Is.EqualTo(expectedCulture)); + } + + [Test] + public void FaultyValue() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.FaultyValue"); + var locConfig = LocalizationConfiguration.Load(section); + CheckConfigurationIsDefault(locConfig); + } + + + #region Naming + [Test] + public void NamingInLowCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.Naming.LC"); + var locConfig = LocalizationConfiguration.Load(section); + ValidateNamingConfigurationResults(locConfig); + } + + [Test] + public void NamingInUpperCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.Naming.UC"); + var locConfig = LocalizationConfiguration.Load(section); + ValidateNamingConfigurationResults(locConfig); + } + + [Test] + public void NamingInCamelCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.Naming.CC"); + var locConfig = LocalizationConfiguration.Load(section); + ValidateNamingConfigurationResults(locConfig); + } + + [Test] + public void NamingInPascalCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.Naming.PC"); + var locConfig = LocalizationConfiguration.Load(section); + ValidateNamingConfigurationResults(locConfig); + } + + private void ValidateNamingConfigurationResults(LocalizationConfiguration locConfig) + { + Assert.That(locConfig, Is.Not.Null); + Assert.That(locConfig.DefaultCulture, Is.EqualTo(expectedCulture)); + } + #endregion + + #region mistype cases + [Test] + public void MistypeInLowCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.Mistype.LC"); + var locConfig = LocalizationConfiguration.Load(section); + ValidateMistypeConfigurationResults(locConfig); + } + + [Test] + public void MistypeInUpperCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.Mistype.UC"); + var locConfig = LocalizationConfiguration.Load(section); + ValidateMistypeConfigurationResults(locConfig); + } + + [Test] + public void MistypeInCamelCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.Mistype.CC"); + var locConfig = LocalizationConfiguration.Load(section); + ValidateMistypeConfigurationResults(locConfig); + } + + [Test] + public void MistypeInPascalCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.Mistype.PC"); + var locConfig = LocalizationConfiguration.Load(section); + ValidateMistypeConfigurationResults(locConfig); + } + + private void ValidateMistypeConfigurationResults(LocalizationConfiguration locConfig) + { + CheckConfigurationIsDefault(locConfig); + } + + #endregion + + #region Name as node + + [Test] + public void NoNameNodes() + { + IgnoreIfXml(); + + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Empty"); + var locConfig = LocalizationConfiguration.Load(section); + CheckConfigurationIsDefault(locConfig); + } + + [Test] + public void NameNodeIsEmpty() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.NameEmpty"); + var locConfig = LocalizationConfiguration.Load(section); + CheckConfigurationIsDefault(locConfig); + } + + [Test] + public void DefinedNameNode() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Espaniol"); + var locConfig = LocalizationConfiguration.Load(section); + Assert.That(locConfig, Is.Not.Null); + Assert.That(locConfig.DefaultCulture, Is.EqualTo(expectedCulture)); + } + + [Test] + public void FaultyNameNodeValue() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.FaultyValue"); + var locConfig = LocalizationConfiguration.Load(section); + CheckConfigurationIsDefault(locConfig); + } + + [Test] + public void NameNodeInLowCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.LC"); + var locConfig = LocalizationConfiguration.Load(section); + ValidateNamingConfigurationResults(locConfig); + } + + [Test] + public void NameNodeInUpperCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.UC"); + var locConfig = LocalizationConfiguration.Load(section); + ValidateNamingConfigurationResults(locConfig); + } + + [Test] + public void NameNodeInCamelCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.CC"); + var locConfig = LocalizationConfiguration.Load(section); + ValidateNamingConfigurationResults(locConfig); + } + + [Test] + public void NameNodeInPascalCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.PC"); + var locConfig = LocalizationConfiguration.Load(section); + ValidateNamingConfigurationResults(locConfig); + } + + #endregion + + protected void CheckConfigurationIsDefault(LocalizationConfiguration locConfig) + { + Assert.That(locConfig, Is.Not.Null); + Assert.That(locConfig.DefaultCulture, Is.EqualTo(defaultCulture)); + } + } +} diff --git a/Extensions/Xtensive.Orm.Localization.Tests/Xtensive.Orm.Localization.Tests.csproj b/Extensions/Xtensive.Orm.Localization.Tests/Xtensive.Orm.Localization.Tests.csproj index e0eba70610..ab65999ee8 100644 --- a/Extensions/Xtensive.Orm.Localization.Tests/Xtensive.Orm.Localization.Tests.csproj +++ b/Extensions/Xtensive.Orm.Localization.Tests/Xtensive.Orm.Localization.Tests.csproj @@ -9,6 +9,16 @@ + + + + + + + + + + @@ -20,4 +30,16 @@ + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + \ No newline at end of file diff --git a/Extensions/Xtensive.Orm.Localization.Tests/localizationsettings.json b/Extensions/Xtensive.Orm.Localization.Tests/localizationsettings.json new file mode 100644 index 0000000000..9fe0bc835b --- /dev/null +++ b/Extensions/Xtensive.Orm.Localization.Tests/localizationsettings.json @@ -0,0 +1,80 @@ +{ + "Xtensive.Orm.Localization.Json.Empty": { + + }, + + "Xtensive.Orm.Localization.Json.NameEmpty": { + "DefaultCulture": "" + }, + + "Xtensive.Orm.Localization.Json.NameDefined": { + "DefaultCulture": "es-ES" + }, + + "Xtensive.Orm.Localization.Json.FaultyValue": { + "DefaultCulture": "ololo" + }, + + "Xtensive.Orm.Localization.Json.Naming.LC": { + "defaultculture": "es-ES" + }, + "Xtensive.Orm.Localization.Json.Naming.UC": { + "DEFAULTCULTURE": "es-ES" + }, + "Xtensive.Orm.Localization.Json.Naming.CC": { + "defaultCulture": "es-ES" + }, + "Xtensive.Orm.Localization.Json.Naming.PC": { + "DefaultCulture": "es-ES" + }, + + "Xtensive.Orm.Localization.Json.Mistype.LC": { + "defailtculture": "es-ES" + }, + "Xtensive.Orm.Localization.Json.Mistype.UC": { + "DEFAILTCULTURE": "es-ES" + }, + "Xtensive.Orm.Localization.Json.Mistype.CC": { + "defailtCulture": "es-ES" + }, + "Xtensive.Orm.Localization.Json.Mistype.PC": { + "DefailtCulture": "es-ES" + }, + + + "Xtensive.Orm.Localization.Json.NameNode.Empty": { + "DefaultCulture": { + } + }, + + "Xtensive.Orm.Localization.Json.NameNode.NameEmpty": { + "DefaultCulture": { + "Name": "" + } + }, + + "Xtensive.Orm.Localization.Json.NameNode.Espaniol": { + "DefaultCulture": { + "Name": "es-ES" + } + }, + + "Xtensive.Orm.Localization.Json.NameNode.FaultyValue": { + "DefaultCulture": { + "Name": "ololo" + } + }, + + "Xtensive.Orm.Localization.Json.NameNode.Naming.LC": { + "DefaultCulture": { "name": "es-ES" } + }, + "Xtensive.Orm.Localization.Json.NameNode.Naming.UC": { + "DefaultCulture": { "NAME": "es-ES" } + }, + "Xtensive.Orm.Localization.Json.NameNode.Naming.CC": { + "DefaultCulture": { "naMe": "es-ES" } + }, + "Xtensive.Orm.Localization.Json.NameNode.Naming.PC": { + "DefaultCulture": { "NaMe": "es-ES" } + } +} diff --git a/Extensions/Xtensive.Orm.Localization/Configuration/Elements/ConfigurationSection.cs b/Extensions/Xtensive.Orm.Localization/Configuration/Elements/ConfigurationSection.cs index c13ec91716..8349378aed 100644 --- a/Extensions/Xtensive.Orm.Localization/Configuration/Elements/ConfigurationSection.cs +++ b/Extensions/Xtensive.Orm.Localization/Configuration/Elements/ConfigurationSection.cs @@ -18,6 +18,7 @@ public class ConfigurationSection : System.Configuration.ConfigurationSection /// Gets default section name for security configuration. /// Value is "Xtensive.Orm.Localization". /// + [Obsolete("Use Localization.DefaultSectionName instead.")] public static readonly string DefaultSectionName = "Xtensive.Orm.Localization"; private const string DefaultCultureElementName = "defaultCulture"; diff --git a/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfiguration.cs b/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfiguration.cs index aab701d997..72a90d34d3 100644 --- a/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfiguration.cs +++ b/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfiguration.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2011 Xtensive LLC. +// Copyright (C) 2011-2024 Xtensive LLC. // All rights reserved. // For conditions of distribution and use, see license. // Created by: Dmitri Maximov @@ -7,7 +7,10 @@ using System; using System.Configuration; using System.Globalization; +using System.Linq; using System.Threading; +using Microsoft.Extensions.Configuration; +using Xtensive.Core; namespace Xtensive.Orm.Localization.Configuration { @@ -17,12 +20,20 @@ namespace Xtensive.Orm.Localization.Configuration [Serializable] public class LocalizationConfiguration { + private class LocalizationOptions + { + public string DefaultCulture { get; set; } = null; + } + /// /// Default SectionName value: /// "". /// public const string DefaultSectionName = "Xtensive.Orm.Localization"; + private const string DefaultCultureElementName = "DefaultCulture"; + private const string CultureNameAttributeName = "name"; + /// /// Gets or sets the default culture. /// @@ -88,8 +99,8 @@ private static LocalizationConfiguration GetConfigurationFromSection(Configurati var result = new LocalizationConfiguration(); result.DefaultCulture = Thread.CurrentThread.CurrentCulture; - string cultureName = configurationSection==null - ? string.Empty + string cultureName = configurationSection == null + ? string.Empty : configurationSection.DefaultCulture.Name; if (string.IsNullOrEmpty(cultureName)) return result; @@ -98,10 +109,95 @@ private static LocalizationConfiguration GetConfigurationFromSection(Configurati var culture = new CultureInfo(cultureName); result.DefaultCulture = culture; } - catch (CultureNotFoundException) - { + catch (CultureNotFoundException) { } return result; } + + public static LocalizationConfiguration Load(IConfigurationSection configurationSection) + { + ArgumentValidator.EnsureArgumentNotNull(configurationSection, nameof(configurationSection)); + + if (TryReadAsOptions(configurationSection, out var localizationConfiguration)) + return localizationConfiguration; + + // if failed then try to handle unusual formats or xml with name attribute + return TryReadUnusualOrOldFormats(configurationSection, out var fallbackConfiguration) + ? fallbackConfiguration + : new LocalizationConfiguration { + DefaultCulture = Thread.CurrentThread.CurrentCulture + }; + } + + private static bool TryReadAsOptions(IConfigurationSection rootSection, out LocalizationConfiguration localizationConfiguration) + { + LocalizationOptions localizationOptions; + try { + localizationOptions = rootSection.Get(); + } + catch { + localizationConfiguration = null; + return false; + } + + if (localizationOptions != null) { + if (!string.IsNullOrEmpty(localizationOptions.DefaultCulture)) { + try { + var culture = new CultureInfo(localizationOptions.DefaultCulture); + localizationConfiguration = new LocalizationConfiguration() { DefaultCulture = culture }; + return true; + } + catch (CultureNotFoundException) { + } + } + } + localizationConfiguration = null; + return false; + } + + /// + /// Tries to read configuration of old format that supported by + /// old + /// or configuration where name of service is element, not attribute. + /// + /// A configuration section that contains data to read. + /// Read configuration or null if reading was not successful. + /// if reading is successful, otherwise . + private static bool TryReadUnusualOrOldFormats(IConfigurationSection rootSection, + out LocalizationConfiguration localizationConfiguration) + { + var defaultCultureSection = rootSection.GetSection(DefaultCultureElementName); + + if (defaultCultureSection == null) { + localizationConfiguration = null; + return false; + } + + var cultureName = defaultCultureSection.GetSection(CultureNameAttributeName)?.Value; + if (cultureName == null) { + var children = defaultCultureSection.GetChildren().ToList(); + if (children.Count > 0) { + cultureName = children[0].GetSection(CultureNameAttributeName).Value; + } + } + + if (cultureName != null && ! string.IsNullOrEmpty(cultureName)) { + try { + var culture = new CultureInfo(cultureName); + localizationConfiguration = new LocalizationConfiguration() { + DefaultCulture = culture + }; + return true; + } + catch (CultureNotFoundException) { + localizationConfiguration = new LocalizationConfiguration() { + DefaultCulture = Thread.CurrentThread.CurrentCulture + }; + return true; + } + } + localizationConfiguration = null; + return false; + } } } \ No newline at end of file diff --git a/Extensions/Xtensive.Orm.Localization/Xtensive.Orm.Localization.csproj b/Extensions/Xtensive.Orm.Localization/Xtensive.Orm.Localization.csproj index 404de113d2..e39ae0b162 100644 --- a/Extensions/Xtensive.Orm.Localization/Xtensive.Orm.Localization.csproj +++ b/Extensions/Xtensive.Orm.Localization/Xtensive.Orm.Localization.csproj @@ -27,4 +27,17 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/Extensions/Xtensive.Orm.Reprocessing.Tests/App.config b/Extensions/Xtensive.Orm.Reprocessing.Tests/App.config index cfe235c4cc..b088293b47 100644 --- a/Extensions/Xtensive.Orm.Reprocessing.Tests/App.config +++ b/Extensions/Xtensive.Orm.Reprocessing.Tests/App.config @@ -1,4 +1,4 @@ - +
diff --git a/Extensions/Xtensive.Orm.Reprocessing.Tests/ReprocessingSettings.config b/Extensions/Xtensive.Orm.Reprocessing.Tests/ReprocessingSettings.config new file mode 100644 index 0000000000..25567e878d --- /dev/null +++ b/Extensions/Xtensive.Orm.Reprocessing.Tests/ReprocessingSettings.config @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + Auto + + + New + + + Default + + + + + + + + Xtensive.Orm.Reprocessing.HandleReprocessableExceptionStrategy, Xtensive.Orm.Reprocessing + + + + Xtensive.Orm.Reprocessing.HandleUniqueConstraintViolationStrategy, Xtensive.Orm.Reprocessing + + + + Xtensive.Orm.Reprocessing.DummyStrategy, Xtensive.Orm.Reprocessing + + + + + + + + + + Auto + Xtensive.Orm.Reprocessing.HandleUniqueConstraintViolationStrategy, Xtensive.Orm.Reprocessing + + + + Auto + Xtensive.Orm.Reprocessing.HandleUniqueConstraintViolationStrategy, Xtensive.Orm.Reprocessing + + + + Auto + Xtensive.Orm.Reprocessing.HandleUniqueConstraintViolationStrategy, Xtensive.Orm.Reprocessing + + + + Auto + Xtensive.Orm.Reprocessing.HandleUniqueConstraintViolationStrategy, Xtensive.Orm.Reprocessing + + + + + + + + + Auto + Xtensive.Orm.Reprocessing.HandleUniqueConstraintViolationStrategy, Xtensive.Orm.Reprocessing + + + + Auto + Xtensive.Orm.Reprocessing.HandleUniqueConstraintViolationStrategy, Xtensive.Orm.Reprocessing + + + + Auto + Xtensive.Orm.Reprocessing.HandleUniqueConstraintViolationStrategy, Xtensive.Orm.Reprocessing + + + + Auto + Xtensive.Orm.Reprocessing.HandleUniqueConstraintViolationStrategy, Xtensive.Orm.Reprocessing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Extensions/Xtensive.Orm.Reprocessing.Tests/Tests/ModernConfugurationTests.cs b/Extensions/Xtensive.Orm.Reprocessing.Tests/Tests/ModernConfugurationTests.cs new file mode 100644 index 0000000000..dd545ae3ed --- /dev/null +++ b/Extensions/Xtensive.Orm.Reprocessing.Tests/Tests/ModernConfugurationTests.cs @@ -0,0 +1,307 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System; +using Microsoft.Extensions.Configuration; +using NUnit.Framework; +using Xtensive.Orm.Reprocessing.Configuration; + +namespace Xtensive.Orm.Reprocessing.Tests.Configuration +{ + public sealed class JsonConfigurationTest : ModernConfigurationTest + { + protected override ConfigTypes ConfigFormat => ConfigTypes.Json; + + protected override void AddConfigurationFile(IConfigurationBuilder configurationBuilder) + { + _ = configurationBuilder.AddJsonFile("reprocessingsettings.json"); + } + } + + public sealed class XmlConfigurationTest : ModernConfigurationTest + { + protected override ConfigTypes ConfigFormat => ConfigTypes.Xml; + + protected override void AddConfigurationFile(IConfigurationBuilder configurationBuilder) + { + _ = configurationBuilder.AddXmlFile("ReprocessingSettings.config"); + } + + [Test] + public void EmptyNodesTest() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Xml.EmptyNodes"); + var repConfig = ReprocessingConfiguration.Load(section); + CheckConfigIsDefault(repConfig); + } + + [Test] + public void EmptyValuesTest() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Attributes.EmptyValues"); + var repConfig = ReprocessingConfiguration.Load(section); + CheckConfigIsDefault(repConfig); + } + + [Test] + public void EmptyTransactionModeOnlyTest() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Attributes.EmptyTMOnly"); + var repConfig = ReprocessingConfiguration.Load(section); + CheckConfigIsDefault(repConfig); + } + + [Test] + public void EmptyStrategyOnlyTest() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Attributes.EmptyStrategyOnly"); + var repConfig = ReprocessingConfiguration.Load(section); + CheckConfigIsDefault(repConfig); + } + + [Test] + public void AllAttributesHasValuesTest() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Attributes.All"); + var repConfig = ReprocessingConfiguration.Load(section); + Assert.That(repConfig, Is.Not.Null); + Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.Auto)); + Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleUniqueConstraintViolationStrategy))); + } + + [Test] + public void OnlyTMAttributeHasValueTest() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Attributes.OnlyTM"); + var repConfig = ReprocessingConfiguration.Load(section); + Assert.That(repConfig, Is.Not.Null); + Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.Auto)); + Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleReprocessableExceptionStrategy))); + } + + [Test] + public void OnlyStrategyAttributeHasValueTest() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Attributes.OnlyStrategy"); + var repConfig = ReprocessingConfiguration.Load(section); + Assert.That(repConfig, Is.Not.Null); + Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.New)); + Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleUniqueConstraintViolationStrategy))); + } + + [Test] + public void AttributesInLowCase() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Attributes.LC"); + var repConfig = ReprocessingConfiguration.Load(section); + Assert.That(repConfig, Is.Not.Null); + Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.Auto)); + Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleUniqueConstraintViolationStrategy))); + } + + [Test] + public void AttributesInUpperCase() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Attributes.UC"); + var repConfig = ReprocessingConfiguration.Load(section); + Assert.That(repConfig, Is.Not.Null); + Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.Auto)); + Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleUniqueConstraintViolationStrategy))); + } + + [Test] + public void AttributesInPascalCase() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Attributes.PC"); + var repConfig = ReprocessingConfiguration.Load(section); + Assert.That(repConfig, Is.Not.Null); + Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.Auto)); + Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleUniqueConstraintViolationStrategy))); + } + } + + public abstract class ModernConfigurationTest : TestCommon.ModernConfigurationTestBase + { + [Test] + public void EmptySectionCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Empty"); + var repConfig = ReprocessingConfiguration.Load(section); + CheckConfigIsDefault(repConfig); + } + + [Test] + public void EmptyNames() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.AllEmpty"); + var repConfig = ReprocessingConfiguration.Load(section); + CheckConfigIsDefault(repConfig); + } + + [Test] + public void OnlyTransactionOpenModeAndEmpty() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyTM.Empty"); + var repConfig = ReprocessingConfiguration.Load(section); + CheckConfigIsDefault(repConfig); + } + + [Test] + public void OnlyTransactionOpenModeAuto() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyTM.Auto"); + var repConfig = ReprocessingConfiguration.Load(section); + Assert.That(repConfig, Is.Not.Null); + Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.Auto)); + Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleReprocessableExceptionStrategy))); + } + + [Test] + public void OnlyTransactionOpenModeNew() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyTM.New"); + var repConfig = ReprocessingConfiguration.Load(section); + Assert.That(repConfig, Is.Not.Null); + Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.New)); + Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleReprocessableExceptionStrategy))); + } + + [Test] + public void OnlyTransactionOpenModeDefault() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyTM.Default"); + var repConfig = ReprocessingConfiguration.Load(section); + Assert.That(repConfig, Is.Not.Null); + Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.Default)); + Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleReprocessableExceptionStrategy))); + } + + [Test] + public void OnlyStrategyAndEmpty() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyStrategy.Empty"); + var repConfig = ReprocessingConfiguration.Load(section); + CheckConfigIsDefault(repConfig); + Assert.That(repConfig, Is.Not.Null); + Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.New)); + Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleReprocessableExceptionStrategy))); + } + + [Test] + public void OnlyStrategyHandleReprocessible() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyStrategy.HandleReprocessible"); + var repConfig = ReprocessingConfiguration.Load(section); + Assert.That(repConfig, Is.Not.Null); + Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.New)); + Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleReprocessableExceptionStrategy))); + } + + [Test] + public void OnlyStrategyHandleUnique() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyStrategy.HandleUnique"); + var repConfig = ReprocessingConfiguration.Load(section); + Assert.That(repConfig, Is.Not.Null); + Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.New)); + Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleUniqueConstraintViolationStrategy))); + } + + [Test] + public void OnlyStrategyNonExistent() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyStrategy.NonExistent"); + _ = Assert.Throws(() => ReprocessingConfiguration.Load(section)); + } + + + #region Naming + [Test] + public void NamingInLowCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Naming.LC"); + var repConfig = ReprocessingConfiguration.Load(section); + ValidateNamingConfigurationResults(repConfig); + } + + [Test] + public void NamingInUpperCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Naming.UC"); + var repConfig = ReprocessingConfiguration.Load(section); + ValidateNamingConfigurationResults(repConfig); + } + + [Test] + public void NamingInCamelCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Naming.CC"); + var repConfig = ReprocessingConfiguration.Load(section); + ValidateNamingConfigurationResults(repConfig); + } + + [Test] + public void NamingInPascalCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Naming.PC"); + var repConfig = ReprocessingConfiguration.Load(section); + ValidateNamingConfigurationResults(repConfig); + } + + private static void ValidateNamingConfigurationResults(ReprocessingConfiguration repConfig) + { + Assert.That(repConfig, Is.Not.Null); + Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.Auto)); + Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleUniqueConstraintViolationStrategy))); + } + #endregion + + #region mistype cases + [Test] + public void MistypeInLowCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Mistype.LC"); + var repConfig = ReprocessingConfiguration.Load(section); + ValidateMistypeConfigurationResults(repConfig); + } + + [Test] + public void MistypeInUpperCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Mistype.UC"); + var repConfig = ReprocessingConfiguration.Load(section); + ValidateMistypeConfigurationResults(repConfig); + } + + [Test] + public void MistypeInCamelCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Mistype.CC"); + var repConfig = ReprocessingConfiguration.Load(section); + ValidateMistypeConfigurationResults(repConfig); + } + + [Test] + public void MistypeInPascalCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Mistype.PC"); + var repConfig = ReprocessingConfiguration.Load(section); + ValidateMistypeConfigurationResults(repConfig); + } + + private static void ValidateMistypeConfigurationResults(ReprocessingConfiguration repConfig) + { + CheckConfigIsDefault(repConfig); + } + + #endregion + + protected static void CheckConfigIsDefault(ReprocessingConfiguration configuration) + { + Assert.That(configuration, Is.Not.Null); + Assert.That(configuration.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.New)); + Assert.That(configuration.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleReprocessableExceptionStrategy))); + } + } +} diff --git a/Extensions/Xtensive.Orm.Reprocessing.Tests/Xtensive.Orm.Reprocessing.Tests.csproj b/Extensions/Xtensive.Orm.Reprocessing.Tests/Xtensive.Orm.Reprocessing.Tests.csproj index 29421c8206..e620d91ca5 100644 --- a/Extensions/Xtensive.Orm.Reprocessing.Tests/Xtensive.Orm.Reprocessing.Tests.csproj +++ b/Extensions/Xtensive.Orm.Reprocessing.Tests/Xtensive.Orm.Reprocessing.Tests.csproj @@ -9,6 +9,16 @@ + + + + + + + + + + @@ -20,4 +30,12 @@ + + + PreserveNewest + + + PreserveNewest + + \ No newline at end of file diff --git a/Extensions/Xtensive.Orm.Reprocessing.Tests/reprocessingsettings.json b/Extensions/Xtensive.Orm.Reprocessing.Tests/reprocessingsettings.json new file mode 100644 index 0000000000..9aa57971ef --- /dev/null +++ b/Extensions/Xtensive.Orm.Reprocessing.Tests/reprocessingsettings.json @@ -0,0 +1,72 @@ +{ + "Xtensive.Orm.Reprocessing.Json.Empty": { + + }, + + "Xtensive.Orm.Reprocessing.Json.AllEmpty": { + "DefaultTransactionOpenMode": "", + "DefaultExecuteStrategy": "" + }, + + + "Xtensive.Orm.Reprocessing.Json.OnlyTM.Empty": { + "DefaultTransactionOpenMode": "" + }, + "Xtensive.Orm.Reprocessing.Json.OnlyTM.Auto": { + "DefaultTransactionOpenMode": "Auto" + }, + "Xtensive.Orm.Reprocessing.Json.OnlyTM.New": { + "DefaultTransactionOpenMode": "New" + }, + "Xtensive.Orm.Reprocessing.Json.OnlyTM.Default": { + "DefaultTransactionOpenMode": "Default" + }, + + "Xtensive.Orm.Reprocessing.Json.OnlyStrategy.Empty": { + "DefaultExecuteStrategy": "" + }, + "Xtensive.Orm.Reprocessing.Json.OnlyStrategy.HandleReprocessible": { + "DefaultExecuteStrategy": "Xtensive.Orm.Reprocessing.HandleReprocessableExceptionStrategy, Xtensive.Orm.Reprocessing" + }, + "Xtensive.Orm.Reprocessing.Json.OnlyStrategy.HandleUnique": { + "DefaultExecuteStrategy": "Xtensive.Orm.Reprocessing.HandleUniqueConstraintViolationStrategy, Xtensive.Orm.Reprocessing" + }, + "Xtensive.Orm.Reprocessing.Json.OnlyStrategy.NonExistent": { + "DefaultExecuteStrategy": "Xtensive.Orm.Reprocessing.DummyStrategy, Xtensive.Orm.Reprocessing" + }, + + + "Xtensive.Orm.Reprocessing.Json.Naming.LC": { + "defaulttransactionopenmode": "Auto", + "defaultexecutestrategy": "Xtensive.Orm.Reprocessing.HandleUniqueConstraintViolationStrategy, Xtensive.Orm.Reprocessing" + }, + "Xtensive.Orm.Reprocessing.Json.Naming.UC": { + "DEFAULTTRANSACTIONOPENMODE": "Auto", + "DEFAULTEXECUTESTRATEGY": "Xtensive.Orm.Reprocessing.HandleUniqueConstraintViolationStrategy, Xtensive.Orm.Reprocessing" + }, + "Xtensive.Orm.Reprocessing.Json.Naming.CC": { + "defaultTransactionOpenMode": "Auto", + "defaultExecuteStrategy": "Xtensive.Orm.Reprocessing.HandleUniqueConstraintViolationStrategy, Xtensive.Orm.Reprocessing" + }, + "Xtensive.Orm.Reprocessing.Json.Naming.PC": { + "DefaultTransactionOpenMode": "Auto", + "DefaultExecuteStrategy": "Xtensive.Orm.Reprocessing.HandleUniqueConstraintViolationStrategy, Xtensive.Orm.Reprocessing" + }, + + "Xtensive.Orm.Reprocessing.Json.Mistype.LC": { + "defaultttransactionopenmode": "Auto", + "defaulttexecutestrategy": "Xtensive.Orm.Reprocessing.HandleUniqueConstraintViolationStrategy, Xtensive.Orm.Reprocessing" + }, + "Xtensive.Orm.Reprocessing.Json.Mistype.UC": { + "DEFAULTTTRANSACTIONOPENMODE": "Auto", + "DEFAULTTEXECUTESTRATEGY": "Xtensive.Orm.Reprocessing.HandleUniqueConstraintViolationStrategy, Xtensive.Orm.Reprocessing" + }, + "Xtensive.Orm.Reprocessing.Json.Mistype.CC": { + "defaultTtransactionOpenMode": "Auto", + "defaulttExecuteStrategy": "Xtensive.Orm.Reprocessing.HandleUniqueConstraintViolationStrategy, Xtensive.Orm.Reprocessing" + }, + "Xtensive.Orm.Reprocessing.Json.Mistype.PC": { + "DefaultTtransactionOpenMode": "Auto", + "DefaulttExecuteStrategy": "Xtensive.Orm.Reprocessing.HandleUniqueConstraintViolationStrategy, Xtensive.Orm.Reprocessing" + } +} diff --git a/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfiguration.cs b/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfiguration.cs index 12b6ec5612..7dc4fac9ee 100644 --- a/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfiguration.cs +++ b/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfiguration.cs @@ -1,5 +1,6 @@ -using System; +using System; using System.Configuration; +using Microsoft.Extensions.Configuration; using Xtensive.Core; namespace Xtensive.Orm.Reprocessing.Configuration @@ -9,6 +10,14 @@ namespace Xtensive.Orm.Reprocessing.Configuration /// public class ReprocessingConfiguration { + // intermediate class for reading section + private class ReprocessingOptions + { + public string DefaultTransactionOpenMode { get; set; } + + public string DefaultExecuteStrategy { get; set; } + } + /// /// Gets default value of the property. /// @@ -81,6 +90,51 @@ private static ReprocessingConfiguration GetConfigurationFromSection(Configurati }; } + /// + /// Loads the from given configuration section. + /// + /// to load from. + /// Loaded configuration or configuration with default settings. + public static ReprocessingConfiguration Load(IConfigurationSection configurationSection) + { + ArgumentValidator.EnsureArgumentNotNull(configurationSection, nameof(configurationSection)); + + return TryReadAsOptions(configurationSection, out var reprocessingConfiguration) + ? reprocessingConfiguration + : new ReprocessingConfiguration(); + } + + private static bool TryReadAsOptions(IConfigurationSection configuration, out ReprocessingConfiguration reprocessingConfiguration) + { + var reprocessingOptions = configuration.Get(); + + if (reprocessingOptions == default) { + reprocessingConfiguration = null; + return false; + } + + if (reprocessingOptions.DefaultTransactionOpenMode == default + && reprocessingOptions.DefaultExecuteStrategy == default) { + // that means instance is default. probably invalid + reprocessingConfiguration = null; + return false; + } + + var result = new ReprocessingConfiguration(); + if (reprocessingOptions.DefaultTransactionOpenMode != default + && Enum.TryParse(reprocessingOptions.DefaultTransactionOpenMode, out var enumValue)) { + result.DefaultTransactionOpenMode = enumValue; + } + if (!string.IsNullOrEmpty(reprocessingOptions.DefaultExecuteStrategy)) { + var type = Type.GetType(reprocessingOptions.DefaultExecuteStrategy, false); + if (type == null) + throw new InvalidOperationException($"Can't resolve type '{reprocessingOptions.DefaultExecuteStrategy}'. Note that DefaultExecuteStrategy value should be in form of Assembly Qualified Name"); + result.DefaultExecuteStrategy = type; + } + reprocessingConfiguration = result; + return true; + } + /// /// Initializes a new instance of the class. /// diff --git a/Extensions/Xtensive.Orm.Reprocessing/Xtensive.Orm.Reprocessing.csproj b/Extensions/Xtensive.Orm.Reprocessing/Xtensive.Orm.Reprocessing.csproj index 99a2631fc2..a578eae546 100644 --- a/Extensions/Xtensive.Orm.Reprocessing/Xtensive.Orm.Reprocessing.csproj +++ b/Extensions/Xtensive.Orm.Reprocessing/Xtensive.Orm.Reprocessing.csproj @@ -17,9 +17,13 @@ + + + + diff --git a/Extensions/Xtensive.Orm.Security.Tests/App.config b/Extensions/Xtensive.Orm.Security.Tests/App.config index 5d3d3d31f0..8e2061897b 100644 --- a/Extensions/Xtensive.Orm.Security.Tests/App.config +++ b/Extensions/Xtensive.Orm.Security.Tests/App.config @@ -1,9 +1,10 @@ - +
+
@@ -16,7 +17,13 @@ + + + + + + \ No newline at end of file diff --git a/Extensions/Xtensive.Orm.Security.Tests/SecuritySettings.config b/Extensions/Xtensive.Orm.Security.Tests/SecuritySettings.config new file mode 100644 index 0000000000..e5ec7efdad --- /dev/null +++ b/Extensions/Xtensive.Orm.Security.Tests/SecuritySettings.config @@ -0,0 +1,225 @@ + + + + + + + + + + + + + + + sha1 + + + sha256 + + + sha384 + + + sha512 + + + md5 + + + + + + + + NotDefault + + + + + + + + + + + + + + sha1 + NotDefault + + + + sha1 + NotDefault + + + + sha1 + NotDefault + + + + sha1 + NotDefault + + + + + + + + + sha1 + NotDefault + + + + sha1 + NotDefault + + + + sha1 + NotDefault + + + + sha1 + NotDefault + + + + + + + + + + + + + + + sha1 + + + + + sha256 + + + + + sha384 + + + + + sha512 + + + + + md5 + + + + + + + + + + + NotDefault + + + + + + + + + + + sha1 + + + NotDefault + + + + + + sha1 + + + NotDefault + + + + + + sha1 + + + NotDefault + + + + + + sha1 + + + NotDefault + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Extensions/Xtensive.Orm.Security.Tests/Tests/ConfigurationTests.cs b/Extensions/Xtensive.Orm.Security.Tests/Tests/ConfigurationTests.cs index 885724895a..acb56731ae 100644 --- a/Extensions/Xtensive.Orm.Security.Tests/Tests/ConfigurationTests.cs +++ b/Extensions/Xtensive.Orm.Security.Tests/Tests/ConfigurationTests.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2011-2021 Xtensive LLC. +// Copyright (C) 2011-2024 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Dmitri Maximov @@ -17,7 +17,7 @@ public class ConfigurationTests : HasConfigurationAccessTest [Test] public void HashingServiceNameTest() { - var section = (Configuration.ConfigurationSection) Configuration.GetSection("Xtensive.Orm.Security.WithName"); + var section = (ConfigurationSection) Configuration.GetSection("Xtensive.Orm.Security.WithName"); Assert.That(section, Is.Not.Null); Assert.That(section.HashingService, Is.Not.Null); Assert.That(section.HashingService.Name, Is.Not.Null); @@ -28,10 +28,27 @@ public void HashingServiceNameTest() Assert.That(config.HashingServiceName, Is.EqualTo("md5")); } + [Test] + public void HashingServiceAndAuthenticationServiceNameTest() + { + var section = (ConfigurationSection) Configuration.GetSection("Xtensive.Orm.Security.AllDeclared"); + Assert.That(section, Is.Not.Null); + Assert.That(section.HashingService, Is.Not.Null); + Assert.That(section.HashingService.Name, Is.Not.Null); + Assert.That(section.HashingService.Name, Is.EqualTo("sha1")); + Assert.That(section.AuthenticationService.Name, Is.Not.Null); + Assert.That(section.AuthenticationService.Name, Is.EqualTo("notdefault")); + + var config = SecurityConfiguration.Load(Configuration, "Xtensive.Orm.Security.AllDeclared"); + Assert.That(config, Is.Not.Null); + Assert.That(config.HashingServiceName, Is.EqualTo("sha1")); + Assert.That(config.AuthenticationServiceName, Is.EqualTo("notdefault")); + } + [Test] public void HashingServiceEmptyTest() { - var section = (Configuration.ConfigurationSection) Configuration.GetSection("Xtensive.Orm.Security.WithoutName"); + var section = (ConfigurationSection) Configuration.GetSection("Xtensive.Orm.Security.WithoutName"); Assert.That(section, Is.Not.Null); Assert.That(section.HashingService, Is.Not.Null); Assert.That(section.HashingService.Name, Is.Null.Or.Empty); @@ -44,7 +61,7 @@ public void HashingServiceEmptyTest() [Test] public void HashingServiceAbsentTest() { - var section = (Configuration.ConfigurationSection) Configuration.GetSection("Xtensive.Orm.Security.Empty"); + var section = (ConfigurationSection) Configuration.GetSection("Xtensive.Orm.Security.Empty"); Assert.That(section, Is.Not.Null); Assert.That(section.HashingService, Is.Not.Null); Assert.That(section.HashingService.Name, Is.Null.Or.Empty); @@ -57,7 +74,7 @@ public void HashingServiceAbsentTest() [Test] public void HashingServiceNoConfigTest() { - var section = (Configuration.ConfigurationSection) Configuration.GetSection("Xtensive.Orm.Security.XXX"); + var section = (ConfigurationSection) Configuration.GetSection("Xtensive.Orm.Security.XXX"); Assert.That(section, Is.Null); var config = SecurityConfiguration.Load(Configuration, "Xtensive.Orm.Security.XXX"); @@ -68,7 +85,7 @@ public void HashingServiceNoConfigTest() [Test] public void HashingServiceDefaultTest() { - var section = (Configuration.ConfigurationSection) Configuration.GetSection("Xtensive.Orm.Security"); + var section = (ConfigurationSection) Configuration.GetSection("Xtensive.Orm.Security"); Assert.That(section, Is.Not.Null); Assert.That(section.HashingService, Is.Not.Null); Assert.That(section.HashingService.Name, Is.Not.Null.Or.Empty); diff --git a/Extensions/Xtensive.Orm.Security.Tests/Tests/ModernConfigurationTests.cs b/Extensions/Xtensive.Orm.Security.Tests/Tests/ModernConfigurationTests.cs new file mode 100644 index 0000000000..257fefa286 --- /dev/null +++ b/Extensions/Xtensive.Orm.Security.Tests/Tests/ModernConfigurationTests.cs @@ -0,0 +1,430 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using NUnit.Framework; +using Microsoft.Extensions.Configuration; +using Xtensive.Orm.Security.Configuration; + +namespace Xtensive.Orm.Security.Tests.Configuration +{ + public sealed class JsonConfigurationTests : ModernConfigurationTests + { + protected override ConfigTypes ConfigFormat => ConfigTypes.Json; + + protected override void AddConfigurationFile(IConfigurationBuilder configurationBuilder) + { + _ = configurationBuilder.AddJsonFile("securitysettings.json"); + } + } + + public sealed class XmlConfigurationTests : ModernConfigurationTests + { + protected override ConfigTypes ConfigFormat => ConfigTypes.Xml; + + protected override void AddConfigurationFile(IConfigurationBuilder configurationBuilder) + { + _ = configurationBuilder.AddXmlFile("SecuritySettings.config"); + } + + [Test] + public void NameAttributeEmptyNamesTest() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Security.NameAttribute.NamesEmpty"); + var secConfig = SecurityConfiguration.Load(section); + CheckConfigurationIsDefault(secConfig); + } + + [Test] + public void NameAttributeEmptyAndNonExistentNameTest1() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Security.NameAttribute.NameExistPartially1"); + var secConfig = SecurityConfiguration.Load(section); + CheckConfigurationIsDefault(secConfig); + } + + [Test] + public void NameAttributeEmptyAndNonExistentNameTest2() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Security.NameAttribute.NameExistPartially2"); + var secConfig = SecurityConfiguration.Load(section); + CheckConfigurationIsDefault(secConfig); + } + + [Test] + public void NameAttributeAllNamesTest() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Security.NameAttribute.AllNames"); + var secConfig = SecurityConfiguration.Load(section); + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha1")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("notdefault")); + } + + [Test] + public void NameAttributeOnlyHashingServiceTest() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Security.NameAttribute.OnlyHashing"); + var secConfig = SecurityConfiguration.Load(section); + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha1")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); + } + + [Test] + public void NameAttributeOnlyAuthServiceTest() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Security.NameAttribute.OnlyAuth"); + var secConfig = SecurityConfiguration.Load(section); + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("plain")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("notdefault")); + } + + [Test] + public void NameAttributeLowCase() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Security.NameAttribute.LC"); + var secConfig = SecurityConfiguration.Load(section); + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha1")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("notdefault")); + } + + [Test] + public void NameAttributeUpperCase() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Security.NameAttribute.UC"); + var secConfig = SecurityConfiguration.Load(section); + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha1")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("notdefault")); + } + + [Test] + public void NameAttributePascalCase() + { + var section = GetAndCheckConfigurationSection("Xtensive.Orm.Security.NameAttribute.PC"); + var secConfig = SecurityConfiguration.Load(section); + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha1")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("notdefault")); + } + } + + + [TestFixture] + public abstract class ModernConfigurationTests : TestCommon.ModernConfigurationTestBase + { + [Test] + public void EmptySectionCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.Empty"); + var secConfig = SecurityConfiguration.Load(section); + CheckConfigurationIsDefault(secConfig); + } + + [Test] + public void EmptyNames() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.AllEmpty"); + var secConfig = SecurityConfiguration.Load(section); + CheckConfigurationIsDefault(secConfig); + } + + [Test] + public void OnlyHashingServiceEmpty() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.OnlyHashing.Empty"); + var secConfig = SecurityConfiguration.Load(section); + CheckConfigurationIsDefault(secConfig); + } + + [Test] + public void OnlyHashingServiceMd5() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.OnlyHashing.Md5"); + var secConfig = SecurityConfiguration.Load(section); + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("md5")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); + } + + [Test] + public void OnlyHashingServiceSha1() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.OnlyHashing.Sha1"); + var secConfig = SecurityConfiguration.Load(section); + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha1")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); + } + + [Test] + public void OnlyHashingServiceSha256() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.OnlyHashing.Sha256"); + var secConfig = SecurityConfiguration.Load(section); + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha256")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); + } + + [Test] + public void OnlyHashingServiceSha384() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.OnlyHashing.Sha384"); + var secConfig = SecurityConfiguration.Load(section); + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha384")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); + } + + [Test] + public void OnlyHashingServiceSha512() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.OnlyHashing.Sha512"); + var secConfig = SecurityConfiguration.Load(section); + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha512")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); + } + + [Test] + public void OnlyAuthenticationServiceEmptyName() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.OnlyAuth.Empty"); + var secConfig = SecurityConfiguration.Load(section); + CheckConfigurationIsDefault(secConfig); + } + + [Test] + public void OnlyAuthenticationServiceNotDefault() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.OnlyAuth"); + var secConfig = SecurityConfiguration.Load(section); + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("plain")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("notdefault")); + } + + + #region Naming + [Test] + public void NamingInLowCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.Naming.LC"); + var secConfig = SecurityConfiguration.Load(section); + ValidateNamingConfigurationResults(secConfig); + } + + [Test] + public void NamingInUpperCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.Naming.UC"); + var secConfig = SecurityConfiguration.Load(section); + ValidateNamingConfigurationResults(secConfig); + } + + [Test] + public void NamingInCamelCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.Naming.CC"); + var secConfig = SecurityConfiguration.Load(section); + ValidateNamingConfigurationResults(secConfig); + } + + [Test] + public void NamingInPascalCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.Naming.PC"); + var secConfig = SecurityConfiguration.Load(section); + ValidateNamingConfigurationResults(secConfig); + } + + private static void ValidateNamingConfigurationResults(SecurityConfiguration secConfig) + { + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha1")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("notdefault")); + } + #endregion + + #region mistype cases + [Test] + public void MistypeInLowCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.Mistype.LC"); + var secConfig = SecurityConfiguration.Load(section); + ValidateMistypeConfigurationResults(secConfig); + } + + [Test] + public void MistypeInUpperCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.Mistype.UC"); + var secConfig = SecurityConfiguration.Load(section); + ValidateMistypeConfigurationResults(secConfig); + } + + [Test] + public void MistypeInCamelCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.Mistype.CC"); + var secConfig = SecurityConfiguration.Load(section); + ValidateMistypeConfigurationResults(secConfig); + } + + [Test] + public void MistypeInPascalCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.Mistype.PC"); + var secConfig = SecurityConfiguration.Load(section); + ValidateMistypeConfigurationResults(secConfig); + } + + private static void ValidateMistypeConfigurationResults(SecurityConfiguration secConfig) + { + CheckConfigurationIsDefault(secConfig); + } + + #endregion + + #region Name as node + + [Test] + public void NoNameNodes() + { + IgnoreIfXml(); + + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.Json.NameNode.AllEmpty"); + var secConfig = SecurityConfiguration.Load(section); + CheckConfigurationIsDefault(secConfig); + } + + [Test] + public void NameNodesAreEmpty() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.Json.NameNode.NamesEmpty"); + var secConfig = SecurityConfiguration.Load(section); + CheckConfigurationIsDefault(secConfig); + } + + [Test] + public void OnlyHashingServiceNameIsEmpty() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyHashing.Empty"); + var secConfig = SecurityConfiguration.Load(section); + CheckConfigurationIsDefault(secConfig); + } + + [Test] + public void OnlyHashingServiceWithNameNodeMd5() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyHashing.Md5"); + var secConfig = SecurityConfiguration.Load(section); + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("md5")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); + } + + [Test] + public void OnlyHashingServiceWithNameNodeSha1() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyHashing.Sha1"); + var secConfig = SecurityConfiguration.Load(section); + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha1")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); + } + + [Test] + public void OnlyHashingServiceWithNameNodeSha256() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyHashing.Sha256"); + var secConfig = SecurityConfiguration.Load(section); + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha256")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); + } + + [Test] + public void OnlyHashingServiceWithNameNodeSha384() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyHashing.Sha384"); + var secConfig = SecurityConfiguration.Load(section); + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha384")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); + } + + [Test] + public void OnlyHashingServiceWithNameNodeSha512() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyHashing.Sha512"); + var secConfig = SecurityConfiguration.Load(section); + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha512")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); + } + + [Test] + public void OnlyAuthenticationServiceWithNameNodeEmptyName() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyAuth.Empty"); + var secConfig = SecurityConfiguration.Load(section); + CheckConfigurationIsDefault(secConfig); + } + + [Test] + public void OnlyAuthenticationServiceWithNameNodeNotDefault() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyAuth"); + var secConfig = SecurityConfiguration.Load(section); + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("plain")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("notdefault")); + } + + [Test] + public void NameNodeInLowCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.LC"); + var secConfig = SecurityConfiguration.Load(section); + ValidateNamingConfigurationResults(secConfig); + } + + [Test] + public void NameNodeInUpperCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.UC"); + var secConfig = SecurityConfiguration.Load(section); + ValidateNamingConfigurationResults(secConfig); + } + + [Test] + public void NameNodeInCamelCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.CC"); + var secConfig = SecurityConfiguration.Load(section); + ValidateNamingConfigurationResults(secConfig); + } + + [Test] + public void NameNodeInPascalCase() + { + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.PC"); + var secConfig = SecurityConfiguration.Load(section); + ValidateNamingConfigurationResults(secConfig); + } + + #endregion + + protected static void CheckConfigurationIsDefault(SecurityConfiguration secConfig) + { + Assert.That(secConfig, Is.Not.Null); + Assert.That(secConfig.HashingServiceName, Is.EqualTo("plain")); + Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); + } + } +} diff --git a/Extensions/Xtensive.Orm.Security.Tests/Xtensive.Orm.Security.Tests.csproj b/Extensions/Xtensive.Orm.Security.Tests/Xtensive.Orm.Security.Tests.csproj index 2d10b5ce07..8cc858fa2d 100644 --- a/Extensions/Xtensive.Orm.Security.Tests/Xtensive.Orm.Security.Tests.csproj +++ b/Extensions/Xtensive.Orm.Security.Tests/Xtensive.Orm.Security.Tests.csproj @@ -9,6 +9,16 @@ + + + + + + + + + + @@ -20,4 +30,12 @@ + + + PreserveNewest + + + PreserveNewest + + \ No newline at end of file diff --git a/Extensions/Xtensive.Orm.Security.Tests/securitysettings.json b/Extensions/Xtensive.Orm.Security.Tests/securitysettings.json new file mode 100644 index 0000000000..a7f9eff766 --- /dev/null +++ b/Extensions/Xtensive.Orm.Security.Tests/securitysettings.json @@ -0,0 +1,147 @@ +{ + "Xtensive.Orm.Security.Json.Empty": { + + }, + + "Xtensive.Orm.Security.Json.AllEmpty": { + "HashingService": "", + "AuthenticationService": "" + }, + + "Xtensive.Orm.Security.Json.OnlyHashing.Sha1": { + "HashingService": "sha1" + }, + "Xtensive.Orm.Security.Json.OnlyHashing.Sha256": { + "HashingService": "sha256" + }, + "Xtensive.Orm.Security.Json.OnlyHashing.Sha384": { + "HashingService": "sha384" + }, + "Xtensive.Orm.Security.Json.OnlyHashing.Sha512": { + "HashingService": "sha512" + }, + "Xtensive.Orm.Security.Json.OnlyHashing.Md5": { + "HashingService": "md5" + }, + "Xtensive.Orm.Security.Json.OnlyHashing.Empty": { + "HashingService": "" + }, + + "Xtensive.Orm.Security.Json.OnlyAuth": { + "AuthenticationService": "NotDefault" + }, + "Xtensive.Orm.Security.Json.OnlyAuth.Empty": { + "AuthenticationService": "" + }, + + "Xtensive.Orm.Security.Json.Naming.LC": { + "hashingservice": "sha1", + "authenticationservice": "NotDefault" + }, + "Xtensive.Orm.Security.Json.Naming.UC": { + "HASHINGSERVICE": "sha1", + "AUTHENTICATIONSERVICE": "NotDefault" + }, + "Xtensive.Orm.Security.Json.Naming.CC": { + "hashingService": "sha1", + "authenticationService": "NotDefault" + }, + "Xtensive.Orm.Security.Json.Naming.PC": { + "HashingService": "sha1", + "AuthenticationService": "NotDefault" + }, + + "Xtensive.Orm.Security.Json.Mistype.LC": { + "hashiingservice": "sha1", + "authentticationservice": "NotDefault" + }, + "Xtensive.Orm.Security.Json.Mistype.UC": { + "HASHIINGSERVICE": "sha1", + "AUTHENTTICATIONSERVICE": "NotDefault" + }, + "Xtensive.Orm.Security.Json.Mistype.CC": { + "hashiingService": "sha1", + "authentticationService": "NotDefault" + }, + "Xtensive.Orm.Security.Json.Mistype.PC": { + "HashiingSeervice": "sha1", + "AuthentticationService": "NotDefault" + }, + + + "Xtensive.Orm.Security.Json.NameNode.AllEmpty": { + "HashingService": { + }, + "AuthenticationService": { + } + }, + + "Xtensive.Orm.Security.Json.NameNode.NamesEmpty": { + "HashingService": { + "Name": "" + }, + "AuthenticationService": { + "Name": "" + } + }, + + "Xtensive.Orm.Security.Json.NameNode.OnlyHashing.Sha1": { + "HashingService": { + "Name": "sha1" + } + }, + "Xtensive.Orm.Security.Json.NameNode.OnlyHashing.Sha256": { + "HashingService": { + "Name": "sha256" + } + }, + "Xtensive.Orm.Security.Json.NameNode.OnlyHashing.Sha384": { + "HashingService": { + "Name": "sha384" + } + }, + "Xtensive.Orm.Security.Json.NameNode.OnlyHashing.Sha512": { + "HashingService": { + "Name": "sha512" + } + }, + "Xtensive.Orm.Security.Json.NameNode.OnlyHashing.Md5": { + "HashingService": { + "Name": "md5" + } + }, + "Xtensive.Orm.Security.Json.NameNode.OnlyHashing.Empty": { + "HashingService": { + "Name": "" + } + }, + + "Xtensive.Orm.Security.Json.NameNode.OnlyAuth": { + "AuthenticationService": { + "Name": "NotDefault" + } + }, + "Xtensive.Orm.Security.Json.NameNode.OnlyAuth.Empty": { + "AuthenticationService": { + "Name": "" + } + }, + + + "Xtensive.Orm.Security.Json.NameNode.Naming.LC": { + "HashingService": { "name": "sha1" }, + "AuthenticationService": { "name": "NotDefault" } + }, + "Xtensive.Orm.Security.Json.NameNode.Naming.UC": { + "HashingService": { "NAME": "sha1" }, + "AuthenticationService": { "NAME": "NotDefault" } + }, + "Xtensive.Orm.Security.Json.NameNode.Naming.CC": { + "HashingService": { "naMe": "sha1" }, + "AuthenticationService": { "naMe": "NotDefault" } + }, + "Xtensive.Orm.Security.Json.NameNode.Naming.PC": { + "HashingService": { "NaMe": "sha1" }, + "AuthenticationService": { "NaMe": "NotDefault" } + } +} diff --git a/Extensions/Xtensive.Orm.Security/Configuration/Elements/ConfigurationSection.cs b/Extensions/Xtensive.Orm.Security/Configuration/Elements/ConfigurationSection.cs index ca3fe8cf06..24956db0b8 100644 --- a/Extensions/Xtensive.Orm.Security/Configuration/Elements/ConfigurationSection.cs +++ b/Extensions/Xtensive.Orm.Security/Configuration/Elements/ConfigurationSection.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2011 Xtensive LLC. +// Copyright (C) 2011-2024 Xtensive LLC. // All rights reserved. // For conditions of distribution and use, see license. // Created by: Dmitri Maximov @@ -18,31 +18,29 @@ public class ConfigurationSection : System.Configuration.ConfigurationSection /// Gets default section name for security configuration. /// Value is "Xtensive.Orm.Security". /// + [Obsolete("Use SecurityConfiguration.DefaultSectionName instead")] public static readonly string DefaultSectionName = "Xtensive.Orm.Security"; - private const string HashingServiceElementName = "hashingService"; - private const string AuthenticationServiceElementName = "authenticationService"; - /// /// Gets or sets the hashing service. /// /// The hashing service. - [ConfigurationProperty(HashingServiceElementName, IsRequired = false)] + [ConfigurationProperty(SecurityConfiguration.HashingServiceElementName, IsRequired = false)] public HashingServiceConfigurationElement HashingService { - get { return (HashingServiceConfigurationElement) this[HashingServiceElementName]; } - set { this[HashingServiceElementName] = value; } + get { return (HashingServiceConfigurationElement) this[SecurityConfiguration.HashingServiceElementName]; } + set { this[SecurityConfiguration.HashingServiceElementName] = value; } } /// /// Gets or sets the authentication service. /// /// The authentication service. - [ConfigurationProperty(AuthenticationServiceElementName, IsRequired = false)] + [ConfigurationProperty(SecurityConfiguration.AuthenticationServiceElementName, IsRequired = false)] public AuthenticationServiceConfigurationElement AuthenticationService { - get { return (AuthenticationServiceConfigurationElement) this[AuthenticationServiceElementName]; } - set { this[AuthenticationServiceElementName] = value; } + get { return (AuthenticationServiceConfigurationElement) this[SecurityConfiguration.AuthenticationServiceElementName]; } + set { this[SecurityConfiguration.AuthenticationServiceElementName] = value; } } } } \ No newline at end of file diff --git a/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfiguration.cs b/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfiguration.cs index 8346a6497c..679d762549 100644 --- a/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfiguration.cs +++ b/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfiguration.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2011 Xtensive LLC. +// Copyright (C) 2011-2024 Xtensive LLC. // All rights reserved. // For conditions of distribution and use, see license. // Created by: Dmitri Maximov @@ -6,6 +6,10 @@ using System; using System.Configuration; +using System.Linq; +using System.Threading; +using Microsoft.Extensions.Configuration; +using Xtensive.Core; namespace Xtensive.Orm.Security.Configuration { @@ -15,23 +19,83 @@ namespace Xtensive.Orm.Security.Configuration [Serializable] public class SecurityConfiguration { + #region nested types +#pragma warning disable CS0661, CS0659 // Type defines operator == or operator != but does not override Object.GetHashCode() +#if !NET6_0_OR_GREATER + /// + /// Represents Json and XML without neither name attributes nor name as child element; + /// + private struct SecurityOptions + { + public string HashingService { get; set; } + + public string AuthenticationService { get; set; } + + public static bool operator ==(SecurityOptions r1, SecurityOptions r2) + { + return (r1.HashingService, r1.AuthenticationService) == (r2.HashingService, r2.AuthenticationService); + } + + public static bool operator !=(SecurityOptions r1, SecurityOptions r2) + { + return (r1.HashingService, r1.AuthenticationService) != (r2.HashingService, r2.AuthenticationService); + } + + public override bool Equals(object obj) + { + if (obj is null) + return false; + if (obj is SecurityOptions objRep) + return (HashingService, AuthenticationService) == (objRep.HashingService, objRep.AuthenticationService); + return false; + } + } + +#endif +#pragma warning restore CS0661, CS0659 // Type defines operator == or operator != but does not override Object.GetHashCode() + +#endregion + /// /// Default SectionName value: /// "". /// public const string DefaultSectionName = "Xtensive.Orm.Security"; + internal const string HashingServiceElementName = "HashingService"; + internal const string AuthenticationServiceElementName = "AuthenticationService"; + + private const string DefaultHashingServiceName = "plain"; + private const string DefaultAuthenticationServiceName = "default"; + private const string ServiceNameAttributeName = "name"; + +#if NET6_0_OR_GREATER /// /// Gets or sets the name of the hashing service. /// /// The name of the hashing service. - public string HashingServiceName { get; private set; } + [ConfigurationKeyName(HashingServiceElementName)] + public string HashingServiceName { get; set; } /// /// Gets or sets the name of the authentication service. /// /// The name of the authentication service. - public string AuthenticationServiceName { get; private set; } + [ConfigurationKeyName(AuthenticationServiceElementName)] + public string AuthenticationServiceName { get; set; } +#else + /// + /// Gets or sets the name of the hashing service. + /// + /// The name of the hashing service. + public string HashingServiceName { get; set; } + + /// + /// Gets or sets the name of the authentication service. + /// + /// The name of the authentication service. + public string AuthenticationServiceName { get; set; } +#endif /// /// Loads the @@ -79,29 +143,174 @@ public static SecurityConfiguration Load(System.Configuration.Configuration conf /// The . public static SecurityConfiguration Load(System.Configuration.Configuration configuration, string sectionName) { - var configurationSection = (ConfigurationSection)configuration.GetSection(sectionName); + var configurationSection = (ConfigurationSection) configuration.GetSection(sectionName); return GetConfigurationFromSection(configurationSection); } private static SecurityConfiguration GetConfigurationFromSection(ConfigurationSection configurationSection) { - var result = new SecurityConfiguration(); + var result = new SecurityConfiguration(true); - string hashingService = configurationSection==null - ? string.Empty + var hashingService = configurationSection == null + ? string.Empty : configurationSection.HashingService.Name; - if (string.IsNullOrEmpty(hashingService)) - hashingService = "plain"; - result.HashingServiceName = hashingService.ToLowerInvariant(); + if (!string.IsNullOrEmpty(hashingService)) + result.HashingServiceName = hashingService.ToLowerInvariant(); - string authenticationService = configurationSection==null - ? string.Empty + var authenticationService = configurationSection == null + ? string.Empty : configurationSection.AuthenticationService.Name; - if (string.IsNullOrEmpty(authenticationService)) - authenticationService = "default"; - result.AuthenticationServiceName = authenticationService.ToLowerInvariant(); + if (!string.IsNullOrEmpty(authenticationService)) + result.AuthenticationServiceName = authenticationService.ToLowerInvariant(); return result; } + + /// + /// Loads the from given configuration section. + /// + /// to load from. + /// Loaded configuration or configuration with default settings. + public static SecurityConfiguration Load(IConfigurationSection configurationSection) + { + ArgumentValidator.EnsureArgumentNotNull(configurationSection, nameof(configurationSection)); + + // First attempt is to read modern xml or json + if (TryReadConfigurationAsTypeInstance(configurationSection, out var fromModerntStyle)) + return fromModerntStyle; + + // if failed then try to handle unusual formats or xml with name attribute + return TryReadUnusualOrOldFormats(configurationSection, out var fallbackConfiguration) + ? fallbackConfiguration + : new SecurityConfiguration(true); + } + + /// + /// Tries to read configuration of most relevant format where service names declared as child nodes. + /// + /// A configuration section that contains data to read. + /// + /// if reading is successful, otherwise + private static bool TryReadConfigurationAsTypeInstance(IConfigurationSection configuration, out SecurityConfiguration securityConfiguration) + { + // + // sha1 + // SomeServiceName + // + // or + // "Xtensive.Orm.Security" : { + // "hashingService" :"sha1", + // "authenticationService" : "SomeServiceName" + // } + +#if NET6_0_OR_GREATER + try { + + var configAsIs = configuration.Get(); + if (configAsIs != null && (configAsIs.AuthenticationServiceName ?? configAsIs.HashingServiceName) != null) { + configAsIs.HashingServiceName = string.IsNullOrEmpty(configAsIs.HashingServiceName) + ? DefaultHashingServiceName + : configAsIs.HashingServiceName.ToLowerInvariant(); + configAsIs.AuthenticationServiceName = string.IsNullOrEmpty(configAsIs.AuthenticationServiceName) + ? DefaultAuthenticationServiceName + : (configAsIs.AuthenticationServiceName?.ToLowerInvariant()); + securityConfiguration = configAsIs; + return true; + } + } + catch { + securityConfiguration = null; + return false; + } +#else + try { + var securityOptions = configuration.Get(); + if (securityOptions != default) { + securityConfiguration = new SecurityConfiguration(true); + if (!string.IsNullOrEmpty(securityOptions.HashingService)) + securityConfiguration.HashingServiceName = securityOptions.HashingService.ToLowerInvariant(); + if(!string.IsNullOrEmpty(securityOptions.AuthenticationService)) + securityConfiguration.AuthenticationServiceName = securityOptions.AuthenticationService.ToLowerInvariant(); ; + + return true; + } + } + catch { + securityConfiguration = null; + return false; + } +#endif + var children = configuration.GetChildren().ToList(); + if (!children.Any()) { + securityConfiguration = new SecurityConfiguration(true); + return true; + } + else { + securityConfiguration = null; + return false; + } + } + + /// + /// Tries to read configuration of old format that supported by + /// old + /// or configuration where name of service is element, not attribute. + /// + /// A configuration section that contains data to read. + /// Read configuration or null if reading was not successful. + /// if reading is successful, otherwise . + private static bool TryReadUnusualOrOldFormats(IConfigurationSection configuration, + out SecurityConfiguration securityConfiguration) + { + var hashingServiceSection = configuration.GetSection(HashingServiceElementName); + var authenticationServiceSection = configuration.GetSection(AuthenticationServiceElementName); + + if (hashingServiceSection == null && authenticationServiceSection == null) { + securityConfiguration = null; + return false; + } + + var hashingServiceName = hashingServiceSection.GetSection(ServiceNameAttributeName)?.Value; + if (hashingServiceName == null) { + var children = hashingServiceSection.GetChildren().ToList(); + if (children.Count > 0) { + hashingServiceName = children[0].GetSection(ServiceNameAttributeName).Value; + } + } + + var authenticationServiceName = authenticationServiceSection.GetSection(ServiceNameAttributeName)?.Value; + if (authenticationServiceName == null) { + var children = authenticationServiceSection.GetChildren().ToList(); + if (children.Count > 0) { + authenticationServiceName = children[0].GetSection(ServiceNameAttributeName).Value; + } + } + if ((hashingServiceName ?? authenticationServiceName) != null) { + securityConfiguration = new SecurityConfiguration(true); + if (!string.IsNullOrEmpty(hashingServiceName)) + securityConfiguration.HashingServiceName = hashingServiceName.ToLowerInvariant(); + if (!string.IsNullOrEmpty(authenticationServiceName)) + securityConfiguration.AuthenticationServiceName = authenticationServiceName.ToLowerInvariant(); + + return true; + } + securityConfiguration = null; + return false; + } + + /// + /// Creates instance of with no properties initialized. + /// + public SecurityConfiguration() + { + } + + private SecurityConfiguration(bool initWithDefaults) + { + if (initWithDefaults) { + HashingServiceName = DefaultHashingServiceName; + AuthenticationServiceName = DefaultAuthenticationServiceName; + } + } } -} \ No newline at end of file +} diff --git a/Extensions/Xtensive.Orm.Security/Xtensive.Orm.Security.csproj b/Extensions/Xtensive.Orm.Security/Xtensive.Orm.Security.csproj index 91e131059a..bde5c3aff8 100644 --- a/Extensions/Xtensive.Orm.Security/Xtensive.Orm.Security.csproj +++ b/Extensions/Xtensive.Orm.Security/Xtensive.Orm.Security.csproj @@ -18,9 +18,13 @@ + + + + From eb381bf0d384322f702cb1a879a429ad299858b2 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Tue, 27 Aug 2024 17:07:02 +0500 Subject: [PATCH 02/32] Improved session and domain configuration elements - added validators for some fields - used default value from constant instead of literal - fixed type of collection --- .../Orm/Configuration/Elements/DomainConfigurationElement.cs | 5 +++-- .../Configuration/Elements/SessionConfigurationElement.cs | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Elements/DomainConfigurationElement.cs b/Orm/Xtensive.Orm/Orm/Configuration/Elements/DomainConfigurationElement.cs index d81753afa0..592699aed7 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Elements/DomainConfigurationElement.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Elements/DomainConfigurationElement.cs @@ -245,7 +245,7 @@ public ConfigurationCollection Databases /// /// [ConfigurationProperty(KeyGeneratorsElementName, IsDefaultCollection = false)] - [ConfigurationCollection(typeof (ConfigurationCollection), AddItemName = "keyGenerator")] + [ConfigurationCollection(typeof (ConfigurationCollection), AddItemName = "keyGenerator")] public ConfigurationCollection KeyGenerators { get { return (ConfigurationCollection) this[KeyGeneratorsElementName]; } @@ -295,7 +295,8 @@ public bool IncludeSqlInExceptions /// /// /// - [ConfigurationProperty(AllowCyclicDatabaseDependenciesElementName, DefaultValue = false)] + [ConfigurationProperty(AllowCyclicDatabaseDependenciesElementName, + DefaultValue = DomainConfiguration.DefaultAllowCyclicDatabaseDependencies)] public bool AllowCyclicDatabaseDependencies { get { return (bool) this[AllowCyclicDatabaseDependenciesElementName]; } diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Elements/SessionConfigurationElement.cs b/Orm/Xtensive.Orm/Orm/Configuration/Elements/SessionConfigurationElement.cs index 3bab8025ec..e8e07ca938 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Elements/SessionConfigurationElement.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Elements/SessionConfigurationElement.cs @@ -68,6 +68,7 @@ public string Password { /// [ConfigurationProperty(CacheSizeElementName, DefaultValue = SessionConfiguration.DefaultCacheSize)] + [IntegerValidator(MinValue = 1, MaxValue = int.MaxValue)] public int CacheSize { get { return (int) this[CacheSizeElementName]; } set { this[CacheSizeElementName] = value; } @@ -114,6 +115,7 @@ public int? DefaultCommandTimeout { /// [ConfigurationProperty(BatchSizeElementName, DefaultValue = SessionConfiguration.DefaultBatchSize)] + [IntegerValidator(MinValue = 1, MaxValue = int.MaxValue)] public int BatchSize { get { return (int) this[BatchSizeElementName]; } set { this[BatchSizeElementName] = value; } @@ -142,6 +144,7 @@ public string ServiceContainerType { /// [ConfigurationProperty(EntityChangeRegistrySizeElementName, DefaultValue = SessionConfiguration.DefaultEntityChangeRegistrySize)] + [IntegerValidator(MinValue = 1, MaxValue = int.MaxValue)] public int EntityChangeRegistrySize { get { return (int) this[EntityChangeRegistrySizeElementName]; } set { this[EntityChangeRegistrySizeElementName] = value; } From ace0243bc85a5fc0c06e72ae2e34e3c54242654e Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Tue, 27 Aug 2024 17:28:44 +0500 Subject: [PATCH 03/32] Added packages and files with test domain configurations --- .../Xtensive.Orm.Tests.csproj | 13 + Orm/Xtensive.Orm.Tests/domainSettings.config | 2378 +++++++++++++++++ Orm/Xtensive.Orm.Tests/domainSettings.json | 1414 ++++++++++ 3 files changed, 3805 insertions(+) create mode 100644 Orm/Xtensive.Orm.Tests/domainSettings.config create mode 100644 Orm/Xtensive.Orm.Tests/domainSettings.json diff --git a/Orm/Xtensive.Orm.Tests/Xtensive.Orm.Tests.csproj b/Orm/Xtensive.Orm.Tests/Xtensive.Orm.Tests.csproj index ed55956c3b..1ad40b510c 100644 --- a/Orm/Xtensive.Orm.Tests/Xtensive.Orm.Tests.csproj +++ b/Orm/Xtensive.Orm.Tests/Xtensive.Orm.Tests.csproj @@ -14,9 +14,15 @@ + + + + + + @@ -35,6 +41,12 @@ + + PreserveNewest + + + PreserveNewest + Always @@ -96,4 +108,5 @@ TwoPartsModel.tt + \ No newline at end of file diff --git a/Orm/Xtensive.Orm.Tests/domainSettings.config b/Orm/Xtensive.Orm.Tests/domainSettings.config new file mode 100644 index 0000000000..b2c4333fa6 --- /dev/null +++ b/Orm/Xtensive.Orm.Tests/domainSettings.config @@ -0,0 +1,2378 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sqlite + Data Source=DO-Testsaaa.db3 + + + sqlite:///DO-Tests.db3 + + + + sqlserver://localhost/DO40-Tests + 192 + + + sqlserver://localhost/DO40-Tests + -256 + + + + sqlserver://localhost/DO40-Tests + 192 + + + sqlserver://localhost/DO40-Tests + -256 + + + + sqlserver://localhost/DO40-Tests + 192 + + + sqlserver://localhost/DO40-Tests + -256 + + + + sqlserver://localhost/DO40-Tests + 192 + + + sqlserver://localhost/DO40-Tests + -256 + + + + sqlserver://localhost/DO40-Tests + MyFancyDatabase + + + + sqlserver://localhost/DO40-Tests + MyFancySchema + + + + + + + + sqlserver://localhost/DO40-Tests + Default + + + sqlserver://localhost/DO40-Tests + Recreate + + + sqlserver://localhost/DO40-Tests + Perform + + + sqlserver://localhost/DO40-Tests + PerformSafely + + + sqlserver://localhost/DO40-Tests + Validate + + + sqlserver://localhost/DO40-Tests + LegacyValidate + + + sqlserver://localhost/DO40-Tests + Skip + + + sqlserver://localhost/DO40-Tests + LegacySkip + + + + sqlserver://localhost/DO40-Tests + Defailt + + + + sqlserver://localhost/DO40-Tests + None + + + sqlserver://localhost/DO40-Tests + Hierarchy + + + sqlserver://localhost/DO40-Tests + Reference + + + sqlserver://localhost/DO40-Tests + All + + + sqlserver://localhost/DO40-Tests + Default + + + sqlserver://localhost/DO40-Tests + Hierarchy,Reference + + + + sqlserver://localhost/DO40-Tests + Defailt + + + + sqlserver://localhost/ + Off + + + sqlserver://localhost/ + Auto + + + sqlserver://localhost/ + Manual + + + sqlserver://localhost/ + OffWithNoPopulation + + + sqlserver://localhost/ + Default + + + + sqlserver://localhost/ + Defailt + + + + sqlserver://localhost/ + Default + + + sqlserver://localhost/ + None + + + + sqlserver://localhost/ + Defailt + + + + sqlserver://localhost/ + generalci + + + + sqlserver://localhost/ + Brief + + + sqlserver://localhost/ + Detailed + + + sqlserver://localhost/ + Default + + + sqlserver://localhost/ + Defailt + + + + sqlserver://localhost/ + Nowhere + + + sqlserver://localhost/ + BeforeStatement + + + sqlserver://localhost/ + WithinStatement + + + sqlserver://localhost/ + AfterStatement + + + sqlserver://localhost/ + Default + + + sqlserver://localhost/ + Defailt + + + + sqlserver://localhost/ + 10.0.0.0 + + + + sqlserver://localhost/ + use [OtherDb] + + + + sqlserver://localhost/ + true + + + sqlserver://localhost/ + false + + + sqlserver://localhost/ + true + + + sqlserver://localhost/ + false + + + + sqlserver://localhost/ + true + + + sqlserver://localhost/ + false + + + + sqlserver://localhost/ + true + + + sqlserver://localhost/ + false + + + + sqlserver://localhost/ + true + + + sqlserver://localhost/ + false + + + + sqlserver://localhost/ + true + + + sqlserver://localhost/ + false + + + + sqlserver://localhost/ + true + + + sqlserver://localhost/ + false + + + + sqlserver://localhost/ + + Uppercase + Synonymize + UnderscoreHyphens,RemoveDots + + + Xtensive.Orm + system + + + Xtensive.Orm.Tests + theRest + + + + + + + sqlserver://localhost/ + + Lowercase + Synonymize + UnderscoreHyphens,RemoveDots + + + Xtensive.Orm + system + + + Xtensive.Orm.Tests + theRest + + + + + + + sqlserver://localhost/ + + AsIs + Synonymize + UnderscoreHyphens,RemoveDots + + + Xtensive.Orm + system + + + Xtensive.Orm.Tests + theRest + + + + + + + sqlserver://localhost/ + + Default + Synonymize + UnderscoreHyphens,RemoveDots + + + Xtensive.Orm + system + + + Xtensive.Orm.Tests + theRest + + + + + + + sqlserver://localhost/ + + Uppercase + AsIs + UnderscoreHyphens,RemoveDots + + + + + sqlserver://localhost/ + + Uppercase + Hash + UnderscoreHyphens,RemoveDots + + + + + sqlserver://localhost/ + + Uppercase + Omit + UnderscoreHyphens,RemoveDots + + + + + sqlserver://localhost/ + + Uppercase + Default + UnderscoreHyphens,RemoveDots + + + + + sqlserver://localhost/ + + Uppercase + Hash + UnderscoreDots,RemoveHyphens + + + + + sqlserver://localhost/ + + Uppercase + Hash + None + + + + + sqlserver://localhost/ + + Uppercase + Hash + Default + + + + + sqlserver://localhost/ + + Defailt + Default + Default + + + + + sqlserver://localhost/ + + Default + Defailt + Default + + + + + sqlserver://localhost/ + + Default + Default + Defailt + + + + + + sqlserver://localhost/ + + Pessimistic + + + + + sqlserver://localhost/ + + Optimistic + + + + + sqlserver://localhost/ + + Default + + + + + sqlserver://localhost/ + + Optimistic + true + + + + + sqlserver://localhost/ + + Optimistic + false + + + + + sqlserver://localhost/ + + Defauit + + + + + sqlserver://localhost/ + + + Xtensive.Orm.Tests.Configuration.TypesToUseInTests.DummyEntity1, Xtensive.Orm.Tests + + + Xtensive.Orm.Tests.Configuration.TypesToUseInTests.DummyEntity2, Xtensive.Orm.Tests + + + + + + sqlserver://localhost/ + + + Xtensive.Orm + + + + + + sqlserver://localhost/ + + + Xtensive.Orm.Tests + Xtensive.Orm.Tests.Configuration.TypesToUseInTests.NestedNamespace + + + + + + sqlserver://localhost/ + + + Xtensive.Orm.Tests.Configuration.TypesToUseInTests.DummyEntity1, Xtensive.Orm.Tests + + + Xtensive.Orm.Tests.Configuration.TypesToUseInTests.DummyEntity2, Xtensive.Orm.Tests + + + Xtensive.Orm + + + Xtensive.Orm.Tests + Xtensive.Orm.Tests.Configuration.TypesToUseInTests.NestedNamespace + + + + + + sqlserver://localhost/ + + + Xtensive.Orm.Tests.Configuration.TypesToUseInTests.DummyEntity1, Xtensive.Orm.Tests + + + Xtensive.Orm.Tests.Configuration.TypesToUseInTests.DummyEntity1, Xtensive.Orm.Tests + + + + + + sqlserver://localhost/ + + + Xtensive.Orm + + + Xtensive.Orm + + + + + + sqlserver://localhost/ + + + Xtensive.Orm.Tests + Xtensive.Orm.Tests.Configuration.TypesToUseInTests.NestedNamespace + + + Xtensive.Orm.Tests + Xtensive.Orm.Tests.Configuration.TypesToUseInTests.NestedNamespace + + + + + + sqlserver://localhost/ + + + Xtensive.Orm.Tests.Configuration.TypesToUseInTests.DummyEntity1, Xtensive.Orm.Tests + Xtensive.Orm + Xtensive.Orm.Tests.Configuration.TypesToUseInTests.NestedNamespace + + + + + + sqlserver://localhost/ + + + Xtensive.Orm.Tests.Configuration.TypesToUseInTests.DummyEntity1, Xtensive.Orm.Tests + Xtensive.Orm + + + + + + sqlserver://localhost/ + + + Xtensive.Orm.Tests.Configuration.TypesToUseInTests.DummyEntity1, Xtensive.Orm.Tests + Xtensive.Orm.Tests.Configuration.TypesToUseInTests.NestedNamespace + + + + + + sqlserver://localhost/ + + + Xtensive.Orm.Tests.Configuration.TypesToUseInTests.NestedNamespace + + + + + + + sqlserver://localhost/ + + + main + DO-Tests-1 + + + other + DO-Tests-2 + + + + + sqlserver://localhost/ + + + main + DO-Tests-1 + 100 + 1000 + + + other + DO-Tests-2 + 2000 + 3000 + + + + + + + sqlserver://localhost/ + + + main + DO-Tests-1 + -10 + + + + + + sqlserver://localhost/ + + + main + DO-Tests-1 + 50 + + + + + + sqlserver://localhost/ + + + main + DO-Tests-1 + -10 + + + + + + sqlserver://localhost/ + + + main + DO-Tests-1 + 50 + + + + + + sqlserver://localhost/ + + + Int32 + 12 + 127 + + + + + + sqlserver://localhost/ + + + Int32 + DO-Tests-1 + + + Int32 + DO-Tests-2 + + + + + + sqlserver://localhost/ + + + Int32 + DO-Tests-1 + 12 + 127 + + + Int32 + DO-Tests-2 + 13 + 129 + + + + + + sqlserver://localhost/ + + + Int32 + main + 12 + 127 + + + Int32 + other + 13 + 129 + + + + + main + DO-Tests-1 + + + other + DO-Tests-2 + + + + + + sqlserver://localhost/ + + + Int32 + DO-Tests-1 + + + Int32 + DO-Tests-1 + + + + + sqlserver://localhost/ + + + Int32 + DO-Tests-1 + + + Int32 + main + + + + + main + DO-Tests-1 + + + other + DO-Tests-2 + + + + + sqlserver://localhost/ + + + Int32 + DO-Tests-1 + -12 + + + + + sqlserver://localhost/ + + + Int32 + DO-Tests-1 + -127 + + + + + + + sqlserver://localhost/ + + + Other-DO40-Tests + some-schema1 + table1
+
+ + some-database + some-schema2 + column2 + + + some-database + some-schema2 + index2 + + + some-database + some-schema3 + table2
+ col3 +
+ + some-database + some-schema3 + table2
+ index3 +
+ + another-some-database + some-table
+
+ + database1 + some-column + + + database1 + some-index + + + schema1 + table1
+
+ + schema1 + column2 + + + schema1 + index2 + + + schema1 + table2
+ column3 +
+ + schema1 + table2
+ index3 +
+ + table4
+ column3 +
+ + table4
+ index2 +
+ + single-table
+
+ + single-column + + + single-index + +
+
+ + + sqlserver://localhost/ + + + column1 + index1 + + + + + sqlserver://localhost/ + + + table1
+ column1 + index1 +
+
+
+ + sqlserver://localhost/ + + + database1 + + + + + sqlserver://localhost/ + + + Other-DO40-Tests + some-schema1 + + + + + + + sqlserver://localhost/ + main + dbo + + + Xtensive.Orm.Tests + DO-Tests-1 + + + + + main + DO-Tests + + + other + DO-Tests-2 + + + + + + sqlserver://localhost/ + main + dbo + + + Xtensive.Orm.Tests + Model1 + + + + + main + DO-Tests + + + other + DO-Tests-2 + + + + + + sqlserver://localhost/ + main + dbo + + + Xtensive.Orm.Configuration.Options + DO-Tests-2 + + + + + main + DO-Tests + + + other + DO-Tests-2 + + + + + + sqlserver://localhost/ + main + dbo + + + Xtensive.Orm.Tests.Configuration + Model2 + + + + + main + DO-Tests + + + other + DO-Tests-2 + + + + + + sqlserver://localhost/ + main + dbo + + + Xtensive.Orm.Tests + Xtensive.Orm.Tests.Configuration.TypesToUseInTests + DO-Tests-3 + + + + + main + DO-Tests + + + other + DO-Tests-2 + + + + + + sqlserver://localhost/ + main + dbo + + + Xtensive.Orm.Tests + Xtensive.Orm.Tests.Configuration.TypesToUseInTests.NestedNamespace + Model3 + + + + + main + DO-Tests + + + other + DO-Tests-2 + + + + + + sqlserver://localhost/ + main + dbo + + + Xtensive.Orm.Tests + Xtensive.Orm.Tests.Indexing + main + Model4 + + + + + main + DO-Tests + + + other + DO-Tests-2 + + + + + + sqlserver://localhost/ + main + dbo + + + Xtensive.Orm.Tests + DO-Tests-1 + + + Xtensive.Orm.Tests + Model1 + + + + + main + DO-Tests + + + other + DO-Tests-2 + + + + + + sqlserver://localhost/ + main + dbo + + + Xtensive.Orm.Tests.Configuration + DO-Tests-1 + + + Xtensive.Orm.Tests.Configuration + Model2 + + + + + main + DO-Tests + + + other + DO-Tests-2 + + + + + + sqlserver://localhost/ + main + dbo + + + DO-Tests-1 + + + + + main + DO-Tests + + + other + DO-Tests-2 + + + + + + sqlserver://localhost/ + main + dbo + + + Model4 + + + + + main + DO-Tests + + + other + DO-Tests-2 + + + + + + sqlserver://localhost/ + main + dbo + + + Xtensive.Orm.Tests + Xtensive.Orm.Tests.Configuration + + + + + main + DO-Tests + + + other + DO-Tests-2 + + + + + + sqlserver://localhost/ + main + dbo + + + Xtensive.Orm.Tests + + + + + main + DO-Tests + + + other + DO-Tests-2 + + + + + + sqlserver://localhost/ + main + dbo + + + Xtensive.Orm.Tests.Indexing + + + + + main + DO-Tests + + + other + DO-Tests-2 + + + + + + + + sqlserver://localhost/ + + + ClientProfile + + + + + + sqlserver://localhost/ + + + ClientProfile + + + + + + sqlserver://localhost/ + + + User + 126654 + + + + + + sqlserver://localhost/ + + + Default + + + + + sqlserver://localhost/ + + + ServerProfile + + + + + sqlserver://localhost/ + + + + + + sqlserver://localhost/ + + + AllowSwitching, AutoActivation, ReadRemovedObjects, ValidateEntityVersions + + + + + + sqlserver://localhost/ + + + 399 + 20 + 255 + + + + + sqlserver://localhost/ + + + Infinite + + + + + sqlserver://localhost/ + + + ReadCommitted + + + + + sqlserver://localhost/ + + + 300 + + + + + sqlserver://localhost/ + + + Always + + + + + + sqlserver://localhost/ + + + Data Source=localhost;Initial Catalog=DO-Tests;Integrated Security=True;MultipleActiveResultSets=True + + + + + + sqlserver://localhost/ + + + sqlserver://localhost/DO-Tests + + + + + + + + sqlserver://localhost/ + + + Infinite + 20 + 255 + AllowSwitching, AutoActivation, ReadRemovedObjects, ValidateEntityVersions + + + Infinite + 30 + ServerProfile + + + + + + sqlserver://localhost/ + + + Defailt + + + + + + sqlserver://localhost/ + + + -5 + + + + + + sqlserver://localhost/ + + + 0 + + + + + + sqlserver://localhost/ + + + 1 + + + + + + sqlserver://localhost/ + + + -5 + + + + + + sqlserver://localhost/ + + + 0 + + + + + + sqlserver://localhost/ + + + -5 + + + + + + sqlserver://localhost/ + + + 0 + + + + + + sqlserver://localhost/ + + + Defailt + + + +
+
+ \ No newline at end of file diff --git a/Orm/Xtensive.Orm.Tests/domainSettings.json b/Orm/Xtensive.Orm.Tests/domainSettings.json new file mode 100644 index 0000000000..c4ac8fef8e --- /dev/null +++ b/Orm/Xtensive.Orm.Tests/domainSettings.json @@ -0,0 +1,1414 @@ +{ + "Xtensive.Orm.Json": { + "Domains": { + "DomainWithProviderAndConnectionString": { + "Provider": "sqlite", + "ConnectionString": "Data Source=DO-Testsaaa.db3" + }, + + "DomainWithConnectionUrl": { + "ConnectionUrl": "sqlite:///DO-Tests.db3" + }, + + "DomainWithCustomValidKeyCacheSize": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "KeyCacheSize": 192 + }, + "DomainWithCustomInvalidKeyCacheSize": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "KeyCacheSize": -256 + }, + + "DomainWithCustomValidKeyGeneratorCacheSize": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "KeyGeneratorCacheSize": 192 + }, + "DomainWithCustomInvalidKeyGeneratorCacheSize": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "KeyGeneratorCacheSize": -256 + }, + + "DomainWithCustomValidQueryCacheSize": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "QueryCacheSize": 192 + }, + "DomainWithCustomInvalidQueryCacheSize": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "QueryCacheSize": -256 + }, + + "DomainWithCustomValidRecordSetMappingCacheSize": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "RecordSetMappingCacheSize": 192 + }, + "DomainWithCustomInvalidRecordSetMappingCacheSize": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "RecordSetMappingCacheSize": -256 + }, + + "DomainWithCustomDatabase": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "DefaultDatabase": "MyFancyDatabase" + }, + + "DomainWithCustomSchema": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "DefaultSchema": "MyFancySchema" + }, + + "DomainWithWrongConnectionInfo": { + "UpgradeMode": "Recreate", + "ConnectionString": "Data Source=localhost;Initial Catalog=DO40-Tests;Integrated Security=True;MultipleActiveResultSets=True" + }, + + "DomainWithUpgradeMode1": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "UpgradeMode": "Default" + }, + "DomainWithUpgradeMode2": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "UpgradeMode": "Recreate" + }, + "DomainWithUpgradeMode3": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "UpgradeMode": "Perform" + }, + "DomainWithUpgradeMode4": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "UpgradeMode": "PerformSafely" + }, + "DomainWithUpgradeMode5": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "UpgradeMode": "Validate" + }, + "DomainWithUpgradeMode6": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "UpgradeMode": "LegacyValidate" + }, + "DomainWithUpgradeMode7": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "UpgradeMode": "Skip" + }, + "DomainWithUpgradeMode8": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "UpgradeMode": "LegacySkip" + }, + + "DomainWithWrongUpgradeMode": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "UpgradeMode": "Defailt" + }, + + "DomainWithForeignKeyMode1": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "ForeignKeyMode": "None" + }, + "DomainWithForeignKeyMode2": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "ForeignKeyMode": "Hierarchy" + }, + "DomainWithForeignKeyMode3": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "ForeignKeyMode": "Reference" + }, + "DomainWithForeignKeyMode4": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "ForeignKeyMode": "All" + }, + "DomainWithForeignKeyMode5": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "ForeignKeyMode": "Default" + }, + "DomainWithForeignKeyMode6": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "ForeignKeyMode": "Hierarchy,Reference" + }, + "DomainWithInvalidForeignKeyMode": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "ForeignKeyMode": "Defauit" + }, + + "DomainWithChangeTrackingMode1": { + "ConnectionUrl": "sqlserver://localhost/", + "FullTextChangeTrackingMode": "Off" + }, + "DomainWithChangeTrackingMode2": { + "ConnectionUrl": "sqlserver://localhost/", + "FullTextChangeTrackingMode": "Auto" + }, + "DomainWithChangeTrackingMode3": { + "ConnectionUrl": "sqlserver://localhost/", + "FullTextChangeTrackingMode": "Manual" + }, + "DomainWithChangeTrackingMode4": { + "ConnectionUrl": "sqlserver://localhost/", + "FullTextChangeTrackingMode": "OffWithNoPopulation" + }, + "DomainWithChangeTrackingMode5": { + "ConnectionUrl": "sqlserver://localhost/", + "FullTextChangeTrackingMode": "Default" + }, + "DomainWithInvalidChangeTrackingMode": { + "ConnectionUrl": "sqlserver://localhost/", + "FullTextChangeTrackingMode": "Defauit" + }, + + "DomainWithDomainOptionsValid1": { + "ConnectionUrl": "sqlserver://localhost/", + "Options": "Default" + }, + "DomainWithDomainOptionsValid2": { + "ConnectionUrl": "sqlserver://localhost/", + "Options": "None" + }, + "DomainWithDomainOptionsInvalid": { + "ConnectionUrl": "sqlserver://localhost/", + "Options": "Defauit" + }, + + "DomainWithColation": { + "ConnectionUrl": "sqlserver://localhost/", + "Collation": "generalci" + }, + + "DomainWithBriefSchemaSyncExceptions": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "SchemaSyncExceptionFormat": "Brief" + }, + "DomainWithDetailedSchemaSyncExceptions": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "SchemaSyncExceptionFormat": "Detailed" + }, + "DomainWithDefaultSchemaSyncExceptions": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "SchemaSyncExceptionFormat": "Default" + }, + "DomainWithInvalidSchemaSyncExceptions": { + "ConnectionUrl": "sqlserver://localhost/DO40-Tests", + "SchemaSyncExceptionFormat": "Defailt" + }, + + "DomainWithTagsLocationNowhere": { + "ConnectionUrl": "sqlserver://localhost/", + "TagsLocation": "Nowhere" + }, + "DomainWithTagsLocationBefore": { + "ConnectionUrl": "sqlserver://localhost/", + "TagsLocation": "BeforeStatement" + }, + "DomainWithTagsLocationWithin": { + "ConnectionUrl": "sqlserver://localhost/", + "TagsLocation": "WithinStatement" + }, + "DomainWithTagsLocationAfter": { + "ConnectionUrl": "sqlserver://localhost/", + "TagsLocation": "AfterStatement" + }, + "DomainWithTagsLocationDefault": { + "ConnectionUrl": "sqlserver://localhost/", + "TagsLocation": "Default" + }, + "DomainWithTagsLocationInvalid": { + "ConnectionUrl": "sqlserver://localhost/", + "TagsLocation": "Defauit" + }, + + "DomainWithForcedServerVersion": { + "ConnectionUrl": "sqlserver://localhost/", + "ForcedServerVersion": "10.0.0.0" + }, + "DomainWithInitSql": { + "ConnectionUrl": "sqlserver://localhost/", + "ConnectionInitializationSql": "use [OtherDb]" + }, + + "IncludeSqlInExceptionsTrue": { + "ConnectionUrl": "sqlserver://localhost/", + "IncludeSqlInExceptions": true + }, + "IncludeSqlInExceptionsFalse": { + "ConnectionUrl": "sqlserver://localhost/", + "IncludeSqlInExceptions": false + }, + + "AllowCyclicDatabaseDependenciesTrue": { + "ConnectionUrl": "sqlserver://localhost/", + "AllowCyclicDatabaseDependencies": true + }, + "AllowCyclicDatabaseDependenciesFalse": { + "ConnectionUrl": "sqlserver://localhost/", + "AllowCyclicDatabaseDependencies": false + }, + + "BuildInParallelTrue": { + "ConnectionUrl": "sqlserver://localhost/", + "BuildInParallel": true + }, + "BuildInParallelFalse": { + "ConnectionUrl": "sqlserver://localhost/", + "BuildInParallel": false + }, + + "MultidatabaseKeysTrue": { + "ConnectionUrl": "sqlserver://localhost/", + "MultidatabaseKeys": true + }, + "MultidatabaseKeysFalse": { + "ConnectionUrl": "sqlserver://localhost/", + "MultidatabaseKeys": false + }, + + "SharedStorageSchemaOn": { + "ConnectionUrl": "sqlserver://localhost/", + "ShareStorageSchemaOverNodes": true + }, + "SharedStorageSchemaOff": { + "ConnectionUrl": "sqlserver://localhost/", + "ShareStorageSchemaOverNodes": false + }, + + "EnableConnectionIsAliveTrue": { + "ConnectionUrl": "sqlserver://localhost/", + "EnsureConnectionIsAlive": true + }, + "EnableConnectionIsAliveFalse": { + "ConnectionUrl": "sqlserver://localhost/", + "EnsureConnectionIsAlive": false + }, + + "PreferTypeIdsAsQueryParametersTrue": { + "ConnectionUrl": "sqlserver://localhost/", + "PreferTypeIdsAsQueryParameters": true + }, + "PreferTypeIdsAsQueryParametersFalse": { + "ConnectionUrl": "sqlserver://localhost/", + "PreferTypeIdsAsQueryParameters": false + }, + + "DomainWithNamingConvention1": { + "ConnectionUrl": "sqlserver://localhost/", + "NamingConvention": { + "LetterCasePolicy": "Uppercase", + "NamespacePolicy": "Synonymize", + "NamingRules": "UnderscoreHyphens,RemoveDots", + "NamespaceSynonyms": [ + { + "Namespace": "Xtensive.Orm", + "Synonym": "system" + }, + { + "Namespace": "Xtensive.Orm.Tests", + "Synonym": "theRest" + } + ] + } + }, + "DomainWithNamingConvention2": { + "ConnectionUrl": "sqlserver://localhost/", + "NamingConvention": { + "LetterCasePolicy": "Lowercase", + "NamespacePolicy": "Synonymize", + "NamingRules": "UnderscoreHyphens,RemoveDots", + "NamespaceSynonyms": [ + { + "Namespace": "Xtensive.Orm", + "Synonym": "system" + }, + { + "Namespace": "Xtensive.Orm.Tests", + "Synonym": "theRest" + } + ] + } + }, + "DomainWithNamingConvention3": { + "ConnectionUrl": "sqlserver://localhost/", + "NamingConvention": { + "LetterCasePolicy": "AsIs", + "NamespacePolicy": "Synonymize", + "NamingRules": "UnderscoreHyphens,RemoveDots", + "NamespaceSynonyms": [ + { + "Namespace": "Xtensive.Orm", + "Synonym": "system" + }, + { + "Namespace": "Xtensive.Orm.Tests", + "Synonym": "theRest" + } + ] + } + }, + "DomainWithNamingConvention4": { + "ConnectionUrl": "sqlserver://localhost/", + "NamingConvention": { + "LetterCasePolicy": "Default", + "NamespacePolicy": "Synonymize", + "NamingRules": "UnderscoreHyphens,RemoveDots", + "NamespaceSynonyms": [ + { + "Namespace": "Xtensive.Orm", + "Synonym": "system" + }, + { + "Namespace": "Xtensive.Orm.Tests", + "Synonym": "theRest" + } + ] + } + }, + "DomainWithNamingConvention5": { + "ConnectionUrl": "sqlserver://localhost/", + "NamingConvention": { + "LetterCasePolicy": "Uppercase", + "NamespacePolicy": "AsIs", + "NamingRules": "UnderscoreHyphens,RemoveDots" + } + }, + "DomainWithNamingConvention6": { + "ConnectionUrl": "sqlserver://localhost/", + "NamingConvention": { + "LetterCasePolicy": "Uppercase", + "NamespacePolicy": "Hash", + "NamingRules": "UnderscoreHyphens,RemoveDots" + } + }, + "DomainWithNamingConvention7": { + "ConnectionUrl": "sqlserver://localhost/", + "NamingConvention": { + "LetterCasePolicy": "Uppercase", + "NamespacePolicy": "Omit", + "NamingRules": "UnderscoreHyphens,RemoveDots" + } + }, + "DomainWithNamingConvention8": { + "ConnectionUrl": "sqlserver://localhost/", + "NamingConvention": { + "LetterCasePolicy": "Uppercase", + "NamespacePolicy": "Default", + "NamingRules": "UnderscoreHyphens,RemoveDots" + } + }, + "DomainWithNamingConvention9": { + "ConnectionUrl": "sqlserver://localhost/", + "NamingConvention": { + "LetterCasePolicy": "Uppercase", + "NamespacePolicy": "Hash", + "NamingRules": "UnderscoreDots,RemoveHyphens" + } + }, + "DomainWithNamingConvention10": { + "ConnectionUrl": "sqlserver://localhost/", + "NamingConvention": { + "LetterCasePolicy": "Uppercase", + "NamespacePolicy": "Hash", + "NamingRules": "None" + } + }, + "DomainWithNamingConvention11": { + "ConnectionUrl": "sqlserver://localhost/", + "NamingConvention": { + "LetterCasePolicy": "Uppercase", + "NamespacePolicy": "Hash", + "NamingRules": "Default" + } + }, + + "DomainWithInvalidNamingConvention1": { + "ConnectionUrl": "sqlserver://localhost/", + "NamingConvention": { + "LetterCasePolicy": "Defailt", + "NamespacePolicy": "Default", + "NamingRules": "Default" + } + }, + "DomainWithInvalidNamingConvention2": { + "ConnectionUrl": "sqlserver://localhost/", + "NamingConvention": { + "LetterCasePolicy": "Default", + "NamespacePolicy": "Defailt", + "NamingRules": "Default" + } + }, + "DomainWithInvalidNamingConvention3": { + "ConnectionUrl": "sqlserver://localhost/", + "NamingConvention": { + "LetterCasePolicy": "Default", + "NamespacePolicy": "Default", + "NamingRules": "Defailt" + } + }, + + "DomainWithVersioningConvention1": { + "ConnectionUrl": "sqlserver://localhost/", + "VersioningConvention": { + "EntityVersioningPolicy": "Pessimistic" + } + }, + "DomainWithVersioningConvention2": { + "ConnectionUrl": "sqlserver://localhost/", + "VersioningConvention": { + "EntityVersioningPolicy": "Optimistic" + } + }, + "DomainWithVersioningConvention3": { + "ConnectionUrl": "sqlserver://localhost/", + "VersioningConvention": { + "EntityVersioningPolicy": "Default" + } + }, + "DomainWithVersioningConvention4": { + "ConnectionUrl": "sqlserver://localhost/", + "VersioningConvention": { + "EntityVersioningPolicy": "Optimistic", + "DenyEntitySetOwnerVersionChange": true + } + }, + "DomainWithVersioningConvention5": { + "ConnectionUrl": "sqlserver://localhost/", + "VersioningConvention": { + "EntityVersioningPolicy": "Optimistic", + "DenyEntitySetOwnerVersionChange": false + } + }, + + "DomainWithInvalidVersioningConvention1": { + "ConnectionUrl": "sqlserver://localhost/", + "VersioningConvention": { + "EntityVersioningPolicy": "Defauit" + } + }, + + "DomainWithTypes": { + "ConnectionUrl": "sqlserver://localhost/", + "Types": [ + { + "Type": "Xtensive.Orm.Tests.Configuration.TypesToUseInTests.DummyEntity1, Xtensive.Orm.Tests" + }, + { + "Type": "Xtensive.Orm.Tests.Configuration.TypesToUseInTests.DummyEntity2, Xtensive.Orm.Tests" + } + ] + }, + "DomainWithAssemblies": { + "ConnectionUrl": "sqlserver://localhost/", + "Types": [ + { + "Assembly": "Xtensive.Orm" + } + ] + }, + "DomainWithAssembliesAndNamespaces": { + "ConnectionUrl": "sqlserver://localhost/", + "Types": [ + { + "Assembly": "Xtensive.Orm.Tests", + "Namespace": "Xtensive.Orm.Tests.Configuration.TypesToUseInTests.NestedNamespace" + } + ] + }, + + "DomainWithMixedRegistrations": { + "ConnectionUrl": "sqlserver://localhost/", + "Types": [ + { + "Type": "Xtensive.Orm.Tests.Configuration.TypesToUseInTests.DummyEntity1, Xtensive.Orm.Tests" + }, + { + "Type": "Xtensive.Orm.Tests.Configuration.TypesToUseInTests.DummyEntity2, Xtensive.Orm.Tests" + }, + { + "Assembly": "Xtensive.Orm" + }, + { + "Assembly": "Xtensive.Orm.Tests", + "Namespace": "Xtensive.Orm.Tests.Configuration.TypesToUseInTests.NestedNamespace" + } + ] + }, + + "DomainWithInvalidRegistrations1": { + "ConnectionUrl": "sqlserver://localhost/", + "Types": [ + { + "Type": "Xtensive.Orm.Tests.Configuration.TypesToUseInTests.DummyEntity1, Xtensive.Orm.Tests" + }, + { + "Type": "Xtensive.Orm.Tests.Configuration.TypesToUseInTests.DummyEntity1, Xtensive.Orm.Tests" + } + ] + }, + "DomainWithInvalidRegistrations2": { + "ConnectionUrl": "sqlserver://localhost/", + "Types": [ + { + "Assembly": "Xtensive.Orm" + }, + { + "Assembly": "Xtensive.Orm" + } + ] + }, + "DomainWithInvalidRegistrations3": { + "ConnectionUrl": "sqlserver://localhost/", + "Types": [ + { + "Assembly": "Xtensive.Orm.Tests", + "Namespace": "Xtensive.Orm.Tests.Configuration.TypesToUseInTests.NestedNamespace" + }, + { + "Assembly": "Xtensive.Orm.Tests", + "Namespace": "Xtensive.Orm.Tests.Configuration.TypesToUseInTests.NestedNamespace" + } + ] + }, + "DomainWithInvalidRegistrations4": { + "ConnectionUrl": "sqlserver://localhost/", + "Types": [ + { + "Type": "Xtensive.Orm.Tests.Configuration.TypesToUseInTests.DummyEntity1, Xtensive.Orm.Tests", + "Assembly": "Xtensive.Orm", + "Namespace": "Xtensive.Orm.Tests.Configuration.TypesToUseInTests.NestedNamespace" + } + ] + }, + "DomainWithInvalidRegistrations5": { + "ConnectionUrl": "sqlserver://localhost/", + "Types": [ + { + "Type": "Xtensive.Orm.Tests.Configuration.TypesToUseInTests.DummyEntity1, Xtensive.Orm.Tests", + "Assembly": "Xtensive.Orm" + } + ] + }, + "DomainWithInvalidRegistrations6": { + "ConnectionUrl": "sqlserver://localhost/", + "Types": [ + { + "Type": "Xtensive.Orm.Tests.Configuration.TypesToUseInTests.DummyEntity1, Xtensive.Orm.Tests", + "Namespace": "Xtensive.Orm.Tests.Configuration.TypesToUseInTests.NestedNamespace" + } + ] + }, + "DomainWithInvalidRegistrations7": { + "ConnectionUrl": "sqlserver://localhost/", + "Types": [ + { + "Namespace": "Xtensive.Orm.Tests.Configuration.TypesToUseInTests.NestedNamespace" + } + ] + }, + + "DomainWithDatabases1": { + "ConnectionUrl": "sqlserver://localhost/", + "Databases": { + "main": { + "RealName": "DO-Tests-1" + }, + "other": { + "RealName": "DO-Tests-2" + } + } + }, + "DomainWithDatabases2": { + "ConnectionUrl": "sqlserver://localhost/", + "Databases": { + "main": { + "RealName": "DO-Tests-1", + "MinTypeId": 100, + "MaxTypeId": 1000 + + }, + "other": { + "RealName": "DO-Tests-2", + "MinTypeId": 2000, + "MaxTypeId": 3000 + } + } + }, + + "DomainWithInvalidDatabases1": { + "ConnectionUrl": "sqlserver://localhost/", + "Databases": { + "main": { + "RealName": "DO-Tests-1", + "MinTypeId": -10 + } + } + }, + "DomainWithInvalidDatabases2": { + "ConnectionUrl": "sqlserver://localhost/", + "Databases": { + "main": { + "RealName": "DO-Tests-1", + "MinTypeId": 50 + } + } + }, + "DomainWithInvalidDatabases3": { + "ConnectionUrl": "sqlserver://localhost/", + "Databases": { + "main": { + "RealName": "DO-Tests-1", + "MaxTypeId": -10 + } + } + }, + "DomainWithInvalidDatabases4": { + "ConnectionUrl": "sqlserver://localhost/", + "Databases": { + "main": { + "RealName": "DO-Tests-1", + "MaxTypeId": 50 + } + } + }, + + "DomainWithCustomGenerator": { + "ConnectionUrl": "sqlserver://localhost/", + "KeyGenerators": [ + { + "Name": "Int32", + "Seed": 12, + "CacheSize": 127 + } + ] + }, + "DomainWithCustomGeneratorsWithDatabaseNames": { + "ConnectionUrl": "sqlserver://localhost/", + "KeyGenerators": [ + { + "Name": "Int32", + "Database": "DO-Tests-1" + }, + { + "Name": "Int32", + "Database": "DO-Tests-2" + } + ] + }, + "DomainWithCustomGeneratorsWithDatabaseNamesAndKeyParams": { + "ConnectionUrl": "sqlserver://localhost/", + "KeyGenerators": [ + { + "Name": "Int32", + "Database": "DO-Tests-1", + "Seed": 12, + "CacheSize": 127 + }, + { + "Name": "Int32", + "Database": "DO-Tests-2", + "Seed": 13, + "CacheSize": 129 + } + ] + }, + "DomainWithCustomGeneratorsWithDatabasesAliases": { + "ConnectionUrl": "sqlserver://localhost/", + "KeyGenerators": [ + { + "Name": "Int32", + "Database": "main", + "Seed": 12, + "CacheSize": 127 + }, + { + "Name": "Int32", + "Database": "Other", + "Seed": 13, + "CacheSize": 129 + } + ], + "Databases": { + "main": { + "RealName": "DO-Tests-1" + + }, + "other": { + "RealName": "DO-Tests-2" + } + } + }, + + "DomainWithCustomGeneratorsConflict1": { + "ConnectionUrl": "sqlserver://localhost/", + "KeyGenerators": [ + { + "Name": "Int32", + "Database": "DO-Tests-1" + }, + { + "Name": "Int32", + "Database": "DO-Tests-1" + } + ] + }, + "DomainWithCustomGeneratorsConflict2": { + "ConnectionUrl": "sqlserver://localhost/", + "KeyGenerators": [ + { + "Name": "Int32", + "Database": "DO-Tests-1" + }, + { + "Name": "Int32", + "Database": "main" + } + ], + "Databases": { + "main": { + "RealName": "DO-Tests-1" + + }, + "other": { + "RealName": "DO-Tests-2" + } + } + }, + "DomainWithCustomGeneratorNegativeSeed": { + "ConnectionUrl": "sqlserver://localhost/", + "KeyGenerators": [ + { + "Name": "Int32", + "Database": "DO-Tests-1", + "Seed": -12 + } + ] + }, + "DomainWithCustomGeneratorNegativeCache": { + "ConnectionUrl": "sqlserver://localhost/", + "KeyGenerators": [ + { + "Name": "Int32", + "Database": "DO-Tests-1", + "CacheSize": -127 + } + ] + }, + + "DomainWithIgnoreRules": { + "ConnectionUrl": "sqlserver://localhost/", + "IgnoreRules": [ + { + "Database": "Other-DO40-Tests", + "Schema": "some-schema1", + "Table": "table1" + }, + { + "Database": "some-database", + "Schema": "some-schema2", + "Column": "column2" + }, + { + "Database": "some-database", + "Schema": "some-schema2", + "Index": "index2" + }, + { + "Database": "some-database", + "Schema": "some-schema3", + "Table": "table2", + "Column": "col3" + }, + { + "Database": "some-database", + "Schema": "some-schema3", + "Table": "table2", + "Index": "index3" + }, + { + "Database": "another-some-database", + "Table": "some-table" + }, + { + "Database": "database1", + "Column": "some-column" + }, + { + "Database": "database1", + "Index": "some-index" + }, + { + "Schema": "schema1", + "Table": "table1" + }, + { + "Schema": "schema1", + "Column": "column2" + }, + { + "Schema": "schema1", + "Index": "index2" + }, + { + "Schema": "schema1", + "Table": "table2", + "Column": "column3" + }, + { + "Schema": "schema1", + "Table": "table2", + "Index": "index3" + }, + { + "Table": "table4", + "Column": "column3" + }, + { + "Table": "table4", + "Index": "index2" + }, + { + "Table": "single-table" + }, + { + "Column": "single-column" + }, + { + "Index": "single-index" + } + ] + }, + "DomainWithInvalidIgnoreRules1": { + "ConnectionUrl": "sqlserver://localhost/", + "IgnoreRules": [ + { + "Column": "column1", + "Index": "index1" + } + ] + }, + "DomainWithInvalidIgnoreRules2": { + "ConnectionUrl": "sqlserver://localhost/", + "IgnoreRules": [ + { + "Table": "table1", + "Column": "column1", + "Index": "index1" + } + ] + }, + "DomainWithInvalidIgnoreRules3": { + "ConnectionUrl": "sqlserver://localhost/", + "IgnoreRules": [ + { + "Database": "database1" + } + ] + }, + "DomainWithInvalidIgnoreRules4": { + "ConnectionUrl": "sqlserver://localhost/", + "IgnoreRules": [ + { + "Database": "database1", + "Schema": "schema1" + } + ] + }, + + "DomainWithMappingRules1": { + "ConnectionUrl": "sqlserver://localhost/", + "DefaultDatabase": "main", + "DefaultSchema": "dbo", + "MappingRules": [ + { + "Assembly": "Xtensive.Orm.Tests", + "Database": "DO-Tests-1" + } + ], + "Databases": { + "main": { + "RealName": "DO-Tests" + + }, + "other": { + "RealName": "DO-Tests-2" + } + } + }, + "DomainWithMappingRules2": { + "ConnectionUrl": "sqlserver://localhost/", + "DefaultDatabase": "main", + "DefaultSchema": "dbo", + "MappingRules": [ + { + "Assembly": "Xtensive.Orm.Tests", + "Schema": "Model1" + } + ], + "Databases": { + "main": { + "RealName": "DO-Tests" + + }, + "other": { + "RealName": "DO-Tests-2" + } + } + }, + "DomainWithMappingRules3": { + "ConnectionUrl": "sqlserver://localhost/", + "DefaultDatabase": "main", + "DefaultSchema": "dbo", + "MappingRules": [ + { + "Namespace": "Xtensive.Orm.Configuration.Options", + "Database": "DO-Tests-2" + } + ], + "Databases": { + "main": { + "RealName": "DO-Tests" + + }, + "other": { + "RealName": "DO-Tests-2" + } + } + }, + "DomainWithMappingRules4": { + "ConnectionUrl": "sqlserver://localhost/", + "DefaultDatabase": "main", + "DefaultSchema": "dbo", + "MappingRules": [ + { + "Namespace": "Xtensive.Orm.Tests.Configuration", + "Schema": "Model2" + } + ], + "Databases": { + "main": { + "RealName": "DO-Tests" + + }, + "other": { + "RealName": "DO-Tests-2" + } + } + }, + "DomainWithMappingRules5": { + "ConnectionUrl": "sqlserver://localhost/", + "DefaultDatabase": "main", + "DefaultSchema": "dbo", + "MappingRules": [ + { + "Assembly": "Xtensive.Orm.Tests", + "Namespace": "Xtensive.Orm.Tests.Configuration.TypesToUseInTests", + "Database": "DO-Tests-3" + } + ], + "Databases": { + "main": { + "RealName": "DO-Tests" + + }, + "other": { + "RealName": "DO-Tests-2" + } + } + }, + "DomainWithMappingRules6": { + "ConnectionUrl": "sqlserver://localhost/", + "DefaultDatabase": "main", + "DefaultSchema": "dbo", + "MappingRules": [ + { + "Assembly": "Xtensive.Orm.Tests", + "Namespace": "Xtensive.Orm.Tests.Configuration.TypesToUseInTests.NestedNamespace", + "Schema": "Model3" + } + ], + "Databases": { + "main": { + "RealName": "DO-Tests" + + }, + "other": { + "RealName": "DO-Tests-2" + } + } + }, + "DomainWithMappingRules7": { + "ConnectionUrl": "sqlserver://localhost/", + "DefaultDatabase": "main", + "DefaultSchema": "dbo", + "MappingRules": [ + { + "Assembly": "Xtensive.Orm.Tests", + "Namespace": "Xtensive.Orm.Tests.Indexing", + "Database": "main", + "Schema": "Model4" + } + ], + "Databases": { + "main": { + "RealName": "DO-Tests" + + }, + "other": { + "RealName": "DO-Tests-2" + } + } + }, + + "DomainWithConflictMappingRules1": { + "ConnectionUrl": "sqlserver://localhost/", + "DefaultDatabase": "main", + "DefaultSchema": "dbo", + "MappingRules": [ + { + "Assembly": "Xtensive.Orm.Tests", + "Database": "DO-Tests-1" + }, + { + "Assembly": "Xtensive.Orm.Tests", + "Schema": "Model1" + } + ], + "Databases": { + "main": { + "RealName": "DO-Tests" + + }, + "other": { + "RealName": "DO-Tests-2" + } + } + }, + "DomainWithConflictMappingRules2": { + "ConnectionUrl": "sqlserver://localhost/", + "DefaultDatabase": "main", + "DefaultSchema": "dbo", + "MappingRules": [ + { + "Namespace": "Xtensive.Orm.Tests.Configuration", + "Database": "DO-Tests-2" + }, + { + "Namespace": "Xtensive.Orm.Tests.Configuration", + "Schema": "Model2" + } + ], + "Databases": { + "main": { + "RealName": "DO-Tests" + + }, + "other": { + "RealName": "DO-Tests-2" + } + } + }, + + "DomainWithInvalidMappingRules1": { + "ConnectionUrl": "sqlserver://localhost/", + "DefaultDatabase": "main", + "DefaultSchema": "dbo", + "MappingRules": [ + { + "Database": "main" + } + ], + "Databases": { + "main": { + "RealName": "DO-Tests" + + }, + "other": { + "RealName": "DO-Tests-2" + } + } + }, + "DomainWithInvalidMappingRules2": { + "ConnectionUrl": "sqlserver://localhost/", + "DefaultDatabase": "main", + "DefaultSchema": "dbo", + "MappingRules": [ + { + "Schema": "Model4" + } + ], + "Databases": { + "main": { + "RealName": "DO-Tests" + + }, + "other": { + "RealName": "DO-Tests-2" + } + } + }, + "DomainWithInvalidMappingRules3": { + "ConnectionUrl": "sqlserver://localhost/", + "DefaultDatabase": "main", + "DefaultSchema": "dbo", + "MappingRules": [ + { + "Assembly": "Xtensive.Orm.Tests", + "Namespace": "Xtensive.Orm.Tests.Indexing" + } + ], + "Databases": { + "main": { + "RealName": "DO-Tests" + + }, + "other": { + "RealName": "DO-Tests-2" + } + } + }, + "DomainWithInvalidMappingRules4": { + "ConnectionUrl": "sqlserver://localhost/", + "DefaultDatabase": "main", + "DefaultSchema": "dbo", + "MappingRules": [ + { + "Assembly": "Xtensive.Orm.Tests" + } + ], + "Databases": { + "main": { + "RealName": "DO-Tests" + + }, + "other": { + "RealName": "DO-Tests-2" + } + } + }, + "DomainWithInvalidMappingRules5": { + "ConnectionUrl": "sqlserver://localhost/", + "DefaultDatabase": "main", + "DefaultSchema": "dbo", + "MappingRules": [ + { + "Namespace": "Xtensive.Orm.Tests.Indexing" + } + ], + "Databases": { + "main": { + "RealName": "DO-Tests" + + }, + "other": { + "RealName": "DO-Tests-2" + } + } + }, + + "DomainWithSessionEmptyName": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "": { + "Options": "ClientProfile" + } + } + }, + "DomainWithSessionCustomName": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "UserCreated": { + "Options": "ClientProfile" + } + } + }, + "DomainWithSessionCustomUser": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "UserName": "User", + "Password": "126654" + } + } + }, + "DomainWithSessionDefaultOptions": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "Options": "Default" + } + } + }, + "DomainWithSessionServerProfile": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "Options": "ServerProfile" + } + } + }, + "DomainWithSessionClientProfile": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "Options": "ClientProfile" + } + } + }, + "DomainWithSessionCustomOptions": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "Options": "AllowSwitching, AutoActivation, ReadRemovedObjects, ValidateEntityVersions" + } + } + }, + + "DomainWithSessionWithCollectionSizes": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "CacheSize": 399, + "BatchSize": 20, + "EntityChangeRegistrySize": 255 + } + } + }, + + "DomainWithSessionCustomCacheType": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "CacheType": "Infinite" + } + } + }, + + "DomainWithSessionCustomIsolationLevel": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "DefaultIsolationLevel": "ReadCommitted" + } + } + }, + + "DomainWithSessionCustomCommandTimeout": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "DefaultCommandTimeout": 300 + } + } + }, + + "DomainWithSessionCustomPreloadingPolicy": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "ReaderPreloading": "Always" + } + } + }, + + "DomainWithSessionCustomConnectionString": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "ConnectionString": "Data Source=localhost;Initial Catalog=DO-Tests;Integrated Security=True;MultipleActiveResultSets=True" + } + } + }, + "DomainWithSessionCustomConnectionUrl": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "ConnectionUrl": "sqlserver://localhost/DO-Tests" + } + } + }, + + "DomainWithMultipleSessionConfigurations": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "CacheType": "Infinite", + "BatchSize": 20, + "EntityChangeRegistrySize": 255, + "Options": "AllowSwitching, AutoActivation, ReadRemovedObjects, ValidateEntityVersions" + }, + "System": { + "CacheType": "Infinite", + "BatchSize": 30, + "Options": "ServerProfile" + } + } + }, + + "DomainWithSessionInvalidOptions": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "Options": "Defailt" + } + } + }, + "DomainWithSessionInvalidCacheSize1": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "CacheSize": -5 + } + } + }, + "DomainWithSessionInvalidCacheSize2": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "CacheSize": 0 + } + } + }, + "DomainWithSessionInvalidCacheSize3": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "CacheSize": 1 + } + } + }, + "DomainWithSessionInvalidBatchSize1": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "BatchSize": -5 + } + } + }, + "DomainWithSessionInvalidBatchSize2": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "BatchSize": 0 + } + } + }, + "DomainWithSessionInvalidEntityChangeRegistry1": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "EntityChangeRegistrySize": -5 + } + } + }, + "DomainWithSessionInvalidEntityChangeRegistry2": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "EntityChangeRegistrySize": 0 + } + } + }, + "DomainWithSessionInvalidCacheType": { + "ConnectionUrl": "sqlserver://localhost/", + "Sessions": { + "Default": { + "CacheType": "Defailt" + } + } + } + } + } +} From 4a0c8fcc50bd5bf7f7fdcbc85186bdeb408f479f Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Tue, 27 Aug 2024 17:47:20 +0500 Subject: [PATCH 04/32] Improved some configurations - added contants with default values - fixed typo in default constant --- .../Orm/Configuration/DomainConfiguration.cs | 12 ++++++++--- .../Orm/Configuration/NamingConvention.cs | 4 ++++ .../Orm/Configuration/SessionConfiguration.cs | 21 ++++++++++++++++--- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs b/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs index f4bd9984c8..1a0897981c 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs @@ -9,9 +9,9 @@ using System.Linq; using JetBrains.Annotations; using Xtensive.Core; -using Xtensive.Orm.Configuration.Elements; +using Xtensive.Orm.Configuration.Internals; using Xtensive.Orm.Internals; -using ConfigurationSection=Xtensive.Orm.Configuration.Elements.ConfigurationSection; +using ConfigurationSection = Xtensive.Orm.Configuration.Elements.ConfigurationSection; namespace Xtensive.Orm.Configuration { @@ -95,8 +95,14 @@ public class DomainConfiguration : ConfigurationBase /// /// Default value. /// + [Obsolete ("User DefaultForeignKeyMode")] public const ForeignKeyMode DefauktForeignKeyMode = ForeignKeyMode.Default; + /// + /// Default value. + /// + public const ForeignKeyMode DefaultForeignKeyMode = ForeignKeyMode.Default; + /// /// Default value. /// @@ -154,7 +160,7 @@ public class DomainConfiguration : ConfigurationBase private bool ensureConnectionIsAlive = DefaultEnsureConnectionIsAlive; private bool preferTypeIdsAsQueryParameters = DefaultPreferTypeIdsAsQueryParameters; private DomainUpgradeMode upgradeMode = DefaultUpgradeMode; - private ForeignKeyMode foreignKeyMode = DefauktForeignKeyMode; + private ForeignKeyMode foreignKeyMode = DefaultForeignKeyMode; private FullTextChangeTrackingMode fullTextChangeTrackingMode = DefaultFullTextChangeTrackingMode; private DomainOptions options = DefaultDomainOptions; private SchemaSyncExceptionFormat schemaSyncExceptionFormat = DefaultSchemaSyncExceptionFormat; diff --git a/Orm/Xtensive.Orm/Orm/Configuration/NamingConvention.cs b/Orm/Xtensive.Orm/Orm/Configuration/NamingConvention.cs index 461b274273..5a71e0f53b 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/NamingConvention.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/NamingConvention.cs @@ -18,6 +18,10 @@ namespace Xtensive.Orm.Configuration public class NamingConvention : LockableBase, ICloneable { + public const LetterCasePolicy DefaultLetterCasePolicy = LetterCasePolicy.Default; + public const NamespacePolicy DefaultNamespacePolicy = NamespacePolicy.Default; + public const NamingRules DefaultNamingRules = NamingRules.Default; + private LetterCasePolicy letterCasePolicy; private NamespacePolicy namespacePolicy; private NamingRules namingRules; diff --git a/Orm/Xtensive.Orm/Orm/Configuration/SessionConfiguration.cs b/Orm/Xtensive.Orm/Orm/Configuration/SessionConfiguration.cs index 1107f23c39..3f142a90d2 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/SessionConfiguration.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/SessionConfiguration.cs @@ -23,12 +23,27 @@ public class SessionConfiguration : ConfigurationBase /// Default cache size. /// public const int DefaultCacheSize = 16 * 1024; - + + /// + /// Default session options. + /// + public const SessionOptions DefaultSessionOptions = SessionOptions.Default; + /// /// Default isolation level. /// public const IsolationLevel DefaultDefaultIsolationLevel = IsolationLevel.RepeatableRead; + /// + /// Default cache type. + /// + public const SessionCacheType DefaultCacheType = SessionCacheType.Default; + + /// + /// Default reader preloading policy. + /// + public const ReaderPreloadingPolicy DefaultReaderPreloadingPolicy = ReaderPreloadingPolicy.Default; + /// /// Default batch size. /// @@ -46,13 +61,13 @@ public class SessionConfiguration : ConfigurationBase /// public static readonly SessionConfiguration Default = new SessionConfiguration(WellKnown.Sessions.Default); - private SessionOptions options = SessionOptions.Default; + private SessionOptions options = DefaultSessionOptions; private string userName = string.Empty; private string password = string.Empty; private int cacheSize = DefaultCacheSize; private int batchSize = DefaultBatchSize; private int entityChangeRegistrySize = DefaultEntityChangeRegistrySize; - private SessionCacheType cacheType = SessionCacheType.Default; + private SessionCacheType cacheType = DefaultCacheType; private IsolationLevel defaultIsolationLevel = DefaultDefaultIsolationLevel; // what a fancy name? private int? defaultCommandTimeout = null; private ReaderPreloadingPolicy readerPreloading = ReaderPreloadingPolicy.Default; From 81a152acf79265e00e38e2e7f8ff51708e0c2066 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Tue, 27 Aug 2024 18:01:34 +0500 Subject: [PATCH 05/32] Add tests for new configuration reading api --- .../Configuration/ModernConfigurationTests.cs | 1993 +++++++++++++++++ .../Orm/Configuration/DomainConfiguration.cs | 27 +- Orm/Xtensive.Orm/Xtensive.Orm.csproj | 6 +- 3 files changed, 2019 insertions(+), 7 deletions(-) create mode 100644 Orm/Xtensive.Orm.Tests/Configuration/ModernConfigurationTests.cs diff --git a/Orm/Xtensive.Orm.Tests/Configuration/ModernConfigurationTests.cs b/Orm/Xtensive.Orm.Tests/Configuration/ModernConfigurationTests.cs new file mode 100644 index 0000000000..5a1788dfac --- /dev/null +++ b/Orm/Xtensive.Orm.Tests/Configuration/ModernConfigurationTests.cs @@ -0,0 +1,1993 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Transactions; +using System.IO; +using System.Linq; +using System.Linq.Expressions; +using Microsoft.Extensions.Configuration; +using NUnit.Framework; +using Xtensive.Core; +using Xtensive.Orm.Configuration; + +namespace Xtensive.Orm.Tests.Configuration.TypesToUseInTests +{ + namespace NestedNamespace + { + [HierarchyRoot] + public class DummyNestedEntity1 : Entity + { + [Key, Field] + public int Id { get; private set; } + + [Field] + public string Name { get; set; } + } + + [HierarchyRoot] + public class DummyNestedEntity2 : Entity + { + [Key, Field] + public int Id { get; private set; } + + [Field] + public string Name { get; set; } + } + } + + [HierarchyRoot] + public class DummyEntity1 : Entity + { + [Key, Field] + public int Id { get; private set; } + + [Field] + public string Name { get; set; } + } + + [HierarchyRoot] + public class DummyEntity2 : Entity + { + [Key, Field] + public int Id { get; private set; } + + [Field] + public string Name { get; set; } + } + + [HierarchyRoot] + public class DummyEntity3 : Entity + { + [Key, Field] + public int Id { get; private set; } + + [Field] + public string Name { get; set; } + } +} + +namespace Xtensive.Orm.Tests.Configuration +{ + [TestFixture] + public sealed class AppConfigStyleConfigurationTest : ConfigurationFileTestBase + { + protected override string DefaultSectionName => "Xtensive.Orm.AppConfig"; + + protected override bool NameAttributeUnique => false; + + protected override void RegisterConfigurationFile(ConfigurationBuilder builder) + { + _ = builder.AddXmlFile("domainSettings.config"); + } + } + + [TestFixture] + public sealed class XmlConfigurationTest : ConfigurationFileTestBase + { + protected override string DefaultSectionName => "Xtensive.Orm.Xml"; + + protected override void RegisterConfigurationFile(ConfigurationBuilder builder) + { + _ = builder.AddXmlFile("domainSettings.config"); + } + } + + [TestFixture] + public sealed class JsonConfigurationTest : ConfigurationFileTestBase + { + protected override string DefaultSectionName => "Xtensive.Orm.Json"; + + protected override void RegisterConfigurationFile(ConfigurationBuilder builder) + { + _ = builder.AddJsonFile("domainSettings.json"); + } + } + + public abstract class ConfigurationFileTestBase + { + + private IConfigurationRoot configuration; + private IConfigurationSection configurationSection; + + protected abstract string DefaultSectionName { get; } + protected virtual bool NameAttributeUnique => true; + + [OneTimeSetUp] + public void OneTimeSetup() + { + var configurationBuilder = new ConfigurationBuilder(); + _ = configurationBuilder.SetBasePath(Directory.GetCurrentDirectory()); + + RegisterConfigurationFile(configurationBuilder); + configuration = configurationBuilder.Build(); + + configurationSection = configuration.GetSection(DefaultSectionName); + if (!configurationSection.GetChildren().Any()) { + throw new InconclusiveException($"{DefaultSectionName} section seems to be empty. Check registered file with domain settings"); + } + } + + protected abstract void RegisterConfigurationFile(ConfigurationBuilder builder); + + private DomainConfiguration GetDomainConfiguration(string domainName) + { + var domainConfiguration = DomainConfiguration.Load(configurationSection, domainName); + return domainConfiguration; + } + + #region Simple Domain settings that used to be attributes + + [Test] + public void ProviderAndConnectionStringTest() + { + var domainConfig = GetDomainConfiguration("DomainWithProviderAndConnectionString"); + Assert.That(domainConfig.ConnectionInfo.Provider, Is.EqualTo(WellKnown.Provider.Sqlite)); + Assert.That(domainConfig.ConnectionInfo.ConnectionString, Is.EqualTo("Data Source=DO-Testsaaa.db3")); + Assert.That(domainConfig.ConnectionInfo.ConnectionUrl, Is.Null); + + ValidateAllDefault(domainConfig); + } + + [Test] + public void ConnectionUrlTest() + { + var domainConfig = GetDomainConfiguration("DomainWithConnectionUrl"); + Assert.That(domainConfig.ConnectionInfo.Provider, Is.EqualTo(WellKnown.Provider.Sqlite)); + Assert.That(domainConfig.ConnectionInfo.ConnectionString, Is.Null); + Assert.That(domainConfig.ConnectionInfo.ConnectionUrl.Url, Is.EqualTo("sqlite:///DO-Tests.db3")); + + ValidateAllDefault(domainConfig); + } + + [Test] + public void CustomValidKeyCacheSizeTest() + { + var domainConfig = GetDomainConfiguration("DomainWithCustomValidKeyCacheSize"); + + ValidateAllDefaultExcept(domainConfig, ((d) => d.KeyCacheSize, 192)); + } + + [Test] + public void CustomInvalidKeyCacheSizeTest() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithCustomInvalidKeyCacheSize")); + + } + + [Test] + public void CustomValidKeyGeneratorCacheSizeTest() + { + var domainConfig = GetDomainConfiguration("DomainWithCustomValidKeyGeneratorCacheSize"); + + ValidateAllDefaultExcept(domainConfig, ((d) => d.KeyGeneratorCacheSize, 192)); + } + + [Test] + public void CustomInvalidKeyGeneratorCacheSizeTest() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithCustomInvalidKeyGeneratorCacheSize")); + } + + [Test] + public void CustomValidQueryCacheSizeTest() + { + var domainConfig = GetDomainConfiguration("DomainWithCustomValidQueryCacheSize"); + + ValidateAllDefaultExcept(domainConfig, ((d) => d.QueryCacheSize, 192)); + } + + [Test] + public void CustomInvalidQueryCacheSizeTest() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithCustomInvalidQueryCacheSize")); + } + + [Test] + public void CustomValidRecordSetMappingCacheSizeTest() + { + var domainConfig = GetDomainConfiguration("DomainWithCustomValidRecordSetMappingCacheSize"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.RecordSetMappingCacheSize, 192)); + } + + [Test] + public void CustomInvalidRecordSetMappingCacheSizeTest() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithCustomInvalidRecordSetMappingCacheSize")); + } + + [Test] + public void CustomDefaultDatabaseTest() + { + var domainConfig = GetDomainConfiguration("DomainWithCustomDatabase"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.DefaultDatabase, "MyFancyDatabase"), + ((d) => d.IsMultidatabase, true), + ((d) => d.IsMultischema, true) + ); + } + + [Test] + public void CustomDefaultSchemaTest() + { + var domainConfig = GetDomainConfiguration("DomainWithCustomSchema"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.DefaultSchema, "MyFancySchema"), + ((d) => d.IsMultidatabase, false), + ((d) => d.IsMultischema, true)); + } + + [Test] + public void UpgradeModesTest() + { + var domainConfig = GetDomainConfiguration("DomainWithUpgradeMode1"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.UpgradeMode, DomainUpgradeMode.Default)); + domainConfig.Lock(); + + domainConfig = GetDomainConfiguration("DomainWithUpgradeMode2"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.UpgradeMode, DomainUpgradeMode.Recreate)); + domainConfig.Lock(); + + domainConfig = GetDomainConfiguration("DomainWithUpgradeMode3"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.UpgradeMode, DomainUpgradeMode.Perform)); + domainConfig.Lock(); + + domainConfig = GetDomainConfiguration("DomainWithUpgradeMode4"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.UpgradeMode, DomainUpgradeMode.PerformSafely)); + domainConfig.Lock(); + + domainConfig = GetDomainConfiguration("DomainWithUpgradeMode5"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.UpgradeMode, DomainUpgradeMode.Validate)); + domainConfig.Lock(); + + domainConfig = GetDomainConfiguration("DomainWithUpgradeMode6"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.UpgradeMode, DomainUpgradeMode.LegacyValidate)); + domainConfig.Lock(); + + domainConfig = GetDomainConfiguration("DomainWithUpgradeMode7"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.UpgradeMode, DomainUpgradeMode.Skip)); + domainConfig.Lock(); + + domainConfig = GetDomainConfiguration("DomainWithUpgradeMode8"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.UpgradeMode, DomainUpgradeMode.LegacySkip)); + domainConfig.Lock(); + } + + [Test] + public void WrongUpgradeModeTest() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithWrongUpgradeMode")); + } + + [Test] + public void ForeighKeyModesTest() + { + var domainConfig = GetDomainConfiguration("DomainWithForeignKeyMode1"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.ForeignKeyMode, ForeignKeyMode.None)); + domainConfig.Lock(); + + domainConfig = GetDomainConfiguration("DomainWithForeignKeyMode2"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.ForeignKeyMode, ForeignKeyMode.Hierarchy)); + domainConfig.Lock(); + + domainConfig = GetDomainConfiguration("DomainWithForeignKeyMode3"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.ForeignKeyMode, ForeignKeyMode.Reference)); + domainConfig.Lock(); + + domainConfig = GetDomainConfiguration("DomainWithForeignKeyMode4"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.ForeignKeyMode, ForeignKeyMode.All)); + domainConfig.Lock(); + + domainConfig = GetDomainConfiguration("DomainWithForeignKeyMode5"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.ForeignKeyMode, ForeignKeyMode.Default)); + domainConfig.Lock(); + + domainConfig = GetDomainConfiguration("DomainWithForeignKeyMode6"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.ForeignKeyMode, ForeignKeyMode.Hierarchy | ForeignKeyMode.Reference)); + domainConfig.Lock(); + } + + [Test] + public void InvalidForeighKeyModeTest() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidForeignKeyMode")); + } + + [Test] + public void ChangeTrackingModesTest() + { + var domainConfig = GetDomainConfiguration("DomainWithChangeTrackingMode1"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.FullTextChangeTrackingMode, FullTextChangeTrackingMode.Off)); + domainConfig.Lock(); + + domainConfig = GetDomainConfiguration("DomainWithChangeTrackingMode2"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.FullTextChangeTrackingMode, FullTextChangeTrackingMode.Auto)); + domainConfig.Lock(); + + domainConfig = GetDomainConfiguration("DomainWithChangeTrackingMode3"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.FullTextChangeTrackingMode, FullTextChangeTrackingMode.Manual)); + domainConfig.Lock(); + + domainConfig = GetDomainConfiguration("DomainWithChangeTrackingMode4"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.FullTextChangeTrackingMode, FullTextChangeTrackingMode.OffWithNoPopulation)); + domainConfig.Lock(); + + domainConfig = GetDomainConfiguration("DomainWithChangeTrackingMode5"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.FullTextChangeTrackingMode, FullTextChangeTrackingMode.Default)); + domainConfig.Lock(); + } + + [Test] + public void InvalidChangeTrackingModeTest() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidChangeTrackingMode")); + } + + [Test] + public void DomainOptionsTest1() + { + var domainConfig = GetDomainConfiguration("DomainWithDomainOptionsValid1"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.Options, DomainOptions.Default)); + domainConfig.Lock(); + } + + [Test] + public void DomainOptionsTest2() + { + var domainConfig = GetDomainConfiguration("DomainWithDomainOptionsValid2"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.Options, DomainOptions.None)); + domainConfig.Lock(); + } + [Test] + public void InvalidDomainOptionsTest() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithDomainOptionsInvalid")); + } + + [Test] + public void CollationTest() + { + var domainConfig = GetDomainConfiguration("DomainWithColation"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.Collation, "generalci")); + } + + [Test] + public void BriefSchemaSyncExceptionsTest() + { + var domainConfig = GetDomainConfiguration("DomainWithBriefSchemaSyncExceptions"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.SchemaSyncExceptionFormat, SchemaSyncExceptionFormat.Brief)); + } + + [Test] + public void DetailedSchemaSyncExceptionsTest() + { + var domainConfig = GetDomainConfiguration("DomainWithDetailedSchemaSyncExceptions"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.SchemaSyncExceptionFormat, SchemaSyncExceptionFormat.Detailed)); + } + + [Test] + public void DefaultSchemaSyncExceptionsTest() + { + var domainConfig = GetDomainConfiguration("DomainWithDefaultSchemaSyncExceptions"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.SchemaSyncExceptionFormat, SchemaSyncExceptionFormat.Default)); + } + + [Test] + public void InvalidSchemaSyncExceptionsTest() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidSchemaSyncExceptions")); + } + + [Test] + public void TagsLocationNowhereTest() + { + var domainConfig = GetDomainConfiguration("DomainWithTagsLocationNowhere"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.TagsLocation, TagsLocation.Nowhere)); + } + + [Test] + public void TagsLocationBeforeTest() + { + var domainConfig = GetDomainConfiguration("DomainWithTagsLocationBefore"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.TagsLocation, TagsLocation.BeforeStatement)); + } + + [Test] + public void TagsLocationWithinTest() + { + var domainConfig = GetDomainConfiguration("DomainWithTagsLocationWithin"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.TagsLocation, TagsLocation.WithinStatement)); + } + + [Test] + public void TagsLocationAfterTest() + { + var domainConfig = GetDomainConfiguration("DomainWithTagsLocationAfter"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.TagsLocation, TagsLocation.AfterStatement)); + } + + [Test] + public void TagsLocationDefaultTest() + { + var domainConfig = GetDomainConfiguration("DomainWithTagsLocationDefault"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.TagsLocation, TagsLocation.Default)); + } + + [Test] + public void InvalidTagsLocationTest() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithTagsLocationInvalid")); + } + + [Test] + public void ForcedServerVersionTest() + { + var domainConfig = GetDomainConfiguration("DomainWithForcedServerVersion"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.ForcedServerVersion, "10.0.0.0")); + } + + [Test] + public void InitializationSqlTest() + { + var domainConfig = GetDomainConfiguration("DomainWithInitSql"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.ConnectionInitializationSql, "use [OtherDb]")); + } + + [Test] + public void IncludeSqlInExceptionsTest() + { + var domainConfig = GetDomainConfiguration("IncludeSqlInExceptionsTrue"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.IncludeSqlInExceptions, true)); + } + + [Test] + public void DontIncludeSqlInExceptionsTest() + { + var domainConfig = GetDomainConfiguration("IncludeSqlInExceptionsFalse"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.IncludeSqlInExceptions, false)); + } + + [Test] + public void AllowCyclicDatabaseDependanciesTest() + { + var domainConfig = GetDomainConfiguration("AllowCyclicDatabaseDependenciesTrue"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.AllowCyclicDatabaseDependencies, true)); + } + + [Test] + public void DisallowCyclicDatabaseDependanciesTest() + { + var domainConfig = GetDomainConfiguration("AllowCyclicDatabaseDependenciesFalse"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.AllowCyclicDatabaseDependencies, false)); + } + + [Test] + public void BuildInParallelTest() + { + var domainConfig = GetDomainConfiguration("BuildInParallelTrue"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.BuildInParallel, true)); + } + + [Test] + public void DontBuildInParallelTest() + { + var domainConfig = GetDomainConfiguration("BuildInParallelFalse"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.BuildInParallel, false)); + } + + [Test] + public void AllowMultidatabaseKeysTest() + { + var domainConfig = GetDomainConfiguration("MultidatabaseKeysTrue"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.MultidatabaseKeys, true)); + } + + [Test] + public void DisallowMultidatabaseKeysTest() + { + var domainConfig = GetDomainConfiguration("MultidatabaseKeysFalse"); + ValidateAllDefaultExcept(domainConfig, ((d) => d.MultidatabaseKeys, false)); + } + + [Test] + public void ShareStorageSchemaOverNodesTest() + { + var domainConfig = GetDomainConfiguration("SharedStorageSchemaOn"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.ShareStorageSchemaOverNodes, true)); + } + + [Test] + public void DontShareStorageSchemaOverNodesTest() + { + var domainConfig = GetDomainConfiguration("SharedStorageSchemaOff"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.ShareStorageSchemaOverNodes, false)); + } + + [Test] + public void EnsureConnectionIsAliveTest() + { + var domainConfig = GetDomainConfiguration("EnableConnectionIsAliveTrue"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.EnsureConnectionIsAlive, true)); + } + + [Test] + public void DontCheckConnectionIsAliveTest() + { + var domainConfig = GetDomainConfiguration("EnableConnectionIsAliveFalse"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.EnsureConnectionIsAlive, false)); + } + + [Test] + public void PreferTypeIdAsQueryParameterTest() + { + var domainConfig = GetDomainConfiguration("PreferTypeIdsAsQueryParametersTrue"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.PreferTypeIdsAsQueryParameters, true)); + } + + [Test] + public void DontPreferTypeIdAsQueryParameterTest() + { + var domainConfig = GetDomainConfiguration("PreferTypeIdsAsQueryParametersFalse"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.PreferTypeIdsAsQueryParameters, false)); + } + #endregion + + #region NamingConvention + + [Test] + public void NamingConventionSettingsTest01() + { + var domainConfig = GetDomainConfiguration("DomainWithNamingConvention1"); + ValidateAllDefault(domainConfig); + var namingConvention = domainConfig.NamingConvention; + Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); + Assert.That(namingConvention.NamespacePolicy, Is.EqualTo(NamespacePolicy.Synonymize)); + Assert.That(namingConvention.NamingRules, Is.EqualTo(NamingRules.UnderscoreHyphens | NamingRules.RemoveDots)); + + var synonyms = namingConvention.NamespaceSynonyms; + Assert.That(synonyms.Count, Is.EqualTo(2)); + Assert.That(synonyms["Xtensive.Orm"], Is.EqualTo("system")); + Assert.That(synonyms["Xtensive.Orm.Tests"], Is.EqualTo("theRest")); + } + + [Test] + public void NamingConventionSettingsTest02() + { + var domainConfig = GetDomainConfiguration("DomainWithNamingConvention2"); + ValidateAllDefault(domainConfig); + var namingConvention = domainConfig.NamingConvention; + Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Lowercase)); + Assert.That(namingConvention.NamespacePolicy, Is.EqualTo(NamespacePolicy.Synonymize)); + Assert.That(namingConvention.NamingRules, Is.EqualTo(NamingRules.UnderscoreHyphens | NamingRules.RemoveDots)); + + var synonyms = namingConvention.NamespaceSynonyms; + Assert.That(synonyms.Count, Is.EqualTo(2)); + Assert.That(synonyms["Xtensive.Orm"], Is.EqualTo("system")); + Assert.That(synonyms["Xtensive.Orm.Tests"], Is.EqualTo("theRest")); + } + + [Test] + public void NamingConventionSettingsTest03() + { + var domainConfig = GetDomainConfiguration("DomainWithNamingConvention3"); + ValidateAllDefault(domainConfig); + var namingConvention = domainConfig.NamingConvention; + Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.AsIs)); + Assert.That(namingConvention.NamespacePolicy, Is.EqualTo(NamespacePolicy.Synonymize)); + Assert.That(namingConvention.NamingRules, Is.EqualTo(NamingRules.UnderscoreHyphens | NamingRules.RemoveDots)); + + var synonyms = namingConvention.NamespaceSynonyms; + Assert.That(synonyms.Count, Is.EqualTo(2)); + Assert.That(synonyms["Xtensive.Orm"], Is.EqualTo("system")); + Assert.That(synonyms["Xtensive.Orm.Tests"], Is.EqualTo("theRest")); + } + + [Test] + public void NamingConventionSettingsTest04() + { + var domainConfig = GetDomainConfiguration("DomainWithNamingConvention4"); + ValidateAllDefault(domainConfig); + var namingConvention = domainConfig.NamingConvention; + Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Default)); + Assert.That(namingConvention.NamespacePolicy, Is.EqualTo(NamespacePolicy.Synonymize)); + Assert.That(namingConvention.NamingRules, Is.EqualTo(NamingRules.UnderscoreHyphens | NamingRules.RemoveDots)); + + var synonyms = namingConvention.NamespaceSynonyms; + Assert.That(synonyms.Count, Is.EqualTo(2)); + Assert.That(synonyms["Xtensive.Orm"], Is.EqualTo("system")); + Assert.That(synonyms["Xtensive.Orm.Tests"], Is.EqualTo("theRest")); + } + + [Test] + public void NamingConventionSettingsTest05() + { + var domainConfig = GetDomainConfiguration("DomainWithNamingConvention5"); + ValidateAllDefault(domainConfig); + var namingConvention = domainConfig.NamingConvention; + Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); + Assert.That(namingConvention.NamespacePolicy, Is.EqualTo(NamespacePolicy.AsIs)); + Assert.That(namingConvention.NamingRules, Is.EqualTo(NamingRules.UnderscoreHyphens | NamingRules.RemoveDots)); + } + + [Test] + public void NamingConventionSettingsTest06() + { + var domainConfig = GetDomainConfiguration("DomainWithNamingConvention6"); + ValidateAllDefault(domainConfig); + var namingConvention = domainConfig.NamingConvention; + Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); + Assert.That(namingConvention.NamespacePolicy, Is.EqualTo(NamespacePolicy.Hash)); + Assert.That(namingConvention.NamingRules, Is.EqualTo(NamingRules.UnderscoreHyphens | NamingRules.RemoveDots)); + } + + [Test] + public void NamingConventionSettingsTest07() + { + var domainConfig = GetDomainConfiguration("DomainWithNamingConvention7"); + ValidateAllDefault(domainConfig); + var namingConvention = domainConfig.NamingConvention; + Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); + Assert.That(namingConvention.NamespacePolicy, Is.EqualTo(NamespacePolicy.Omit)); + Assert.That(namingConvention.NamingRules, Is.EqualTo(NamingRules.UnderscoreHyphens | NamingRules.RemoveDots)); + } + + [Test] + public void NamingConventionSettingsTest08() + { + var domainConfig = GetDomainConfiguration("DomainWithNamingConvention8"); + ValidateAllDefault(domainConfig); + var namingConvention = domainConfig.NamingConvention; + Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); + Assert.That(namingConvention.NamespacePolicy, Is.EqualTo(NamespacePolicy.Default)); + Assert.That(namingConvention.NamingRules, Is.EqualTo(NamingRules.UnderscoreHyphens | NamingRules.RemoveDots)); + } + + [Test] + public void NamingConventionSettingsTest09() + { + var domainConfig = GetDomainConfiguration("DomainWithNamingConvention9"); + ValidateAllDefault(domainConfig); + var namingConvention = domainConfig.NamingConvention; + Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); + Assert.That(namingConvention.NamespacePolicy, Is.EqualTo(NamespacePolicy.Hash)); + Assert.That(namingConvention.NamingRules, Is.EqualTo(NamingRules.UnderscoreDots | NamingRules.RemoveHyphens)); + } + + [Test] + public void NamingConventionSettingsTest10() + { + var domainConfig = GetDomainConfiguration("DomainWithNamingConvention10"); + ValidateAllDefault(domainConfig); + var namingConvention = domainConfig.NamingConvention; + Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); + Assert.That(namingConvention.NamespacePolicy, Is.EqualTo(NamespacePolicy.Hash)); + Assert.That(namingConvention.NamingRules, Is.EqualTo(NamingRules.None)); + + } + + [Test] + public void NamingConventionSettingsTest11() + { + var domainConfig = GetDomainConfiguration("DomainWithNamingConvention11"); + ValidateAllDefault(domainConfig); + var namingConvention = domainConfig.NamingConvention; + Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); + Assert.That(namingConvention.NamespacePolicy, Is.EqualTo(NamespacePolicy.Hash)); + Assert.That(namingConvention.NamingRules, Is.EqualTo(NamingRules.Default)); + } + + [Test] + public void NamingConventionInvalidSettingsTest1() + { + _ = Assert.Throws (()=> GetDomainConfiguration("DomainWithInvalidNamingConvention1")); + } + + [Test] + public void NamingConventionInvalidSettingsTest2() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidNamingConvention2")); + } + + [Test] + public void NamingConventionInvalidSettingsTest3() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidNamingConvention3")); + } + + #endregion + + #region VersioningConvention + + [Test] + public void VersioningConventionPessimisticTest() + { + var domainConfig = GetDomainConfiguration("DomainWithVersioningConvention1"); + ValidateAllDefault(domainConfig); + Assert.That(domainConfig.VersioningConvention.EntityVersioningPolicy, Is.EqualTo(EntityVersioningPolicy.Pessimistic)); + Assert.That(domainConfig.VersioningConvention.DenyEntitySetOwnerVersionChange, Is.EqualTo(false)); + } + + [Test] + public void VersioningConventionOptimisticTest() + { + var domainConfig = GetDomainConfiguration("DomainWithVersioningConvention2"); + ValidateAllDefault(domainConfig); + Assert.That(domainConfig.VersioningConvention.EntityVersioningPolicy, Is.EqualTo(EntityVersioningPolicy.Optimistic)); + Assert.That(domainConfig.VersioningConvention.DenyEntitySetOwnerVersionChange, Is.EqualTo(false)); + } + + [Test] + public void VersioningConventionDefaultTest() + { + var domainConfig = GetDomainConfiguration("DomainWithVersioningConvention3"); + ValidateAllDefault(domainConfig); + + Assert.That(domainConfig.VersioningConvention.EntityVersioningPolicy, Is.EqualTo(EntityVersioningPolicy.Default)); + Assert.That(domainConfig.VersioningConvention.DenyEntitySetOwnerVersionChange, Is.EqualTo(false)); + } + + [Test] + public void VersioningConventionDenyEntitySetChangeVersionTest() + { + var domainConfig = GetDomainConfiguration("DomainWithVersioningConvention4"); + ValidateAllDefault(domainConfig); + + Assert.That(domainConfig.VersioningConvention.EntityVersioningPolicy, Is.EqualTo(EntityVersioningPolicy.Optimistic)); + Assert.That(domainConfig.VersioningConvention.DenyEntitySetOwnerVersionChange, Is.EqualTo(true)); + } + + [Test] + public void VersioningConventionAllowEntitySetChangeVersionTest() + { + var domainConfig = GetDomainConfiguration("DomainWithVersioningConvention5"); + ValidateAllDefault(domainConfig); + Assert.That(domainConfig.VersioningConvention.EntityVersioningPolicy, Is.EqualTo(EntityVersioningPolicy.Optimistic)); + Assert.That(domainConfig.VersioningConvention.DenyEntitySetOwnerVersionChange, Is.EqualTo(false)); + } + + [Test] + public void VersioningConventionInvalidTest() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidVersioningConvention1")); + } + + #endregion + + #region Types registration + [Test] + public void TypesRegistrationAsTypesTest() + { + var domainConfig = GetDomainConfiguration("DomainWithTypes"); + ValidateAllDefault(domainConfig); + Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.DummyEntity1)), Is.True); + Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.DummyEntity2)), Is.True); + Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.DummyEntity3)), Is.False); + } + + [Test] + public void TypesRegistrationAsAssembliesTest() + { + var domainConfig = GetDomainConfiguration("DomainWithAssemblies"); + ValidateAllDefault(domainConfig); + var ormAssembly = typeof(DomainConfiguration).Assembly; + Assert.That(domainConfig.Types.Count, Is.GreaterThan(0)); + Assert.That(domainConfig.Types.All((t) => t.Assembly == ormAssembly), Is.True); + } + + [Test] + public void TypesRegistrationAsAssembliesWithNamespace() + { + var domainConfig = GetDomainConfiguration("DomainWithAssembliesAndNamespaces"); + ValidateAllDefault(domainConfig); + Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.NestedNamespace.DummyNestedEntity1)), Is.True); + Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.NestedNamespace.DummyNestedEntity2)), Is.True); + } + + [Test] + public void MixedTypeRegistration() + { + var domainConfig = GetDomainConfiguration("DomainWithMixedRegistrations"); + ValidateAllDefault(domainConfig); + Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.DummyEntity1)), Is.True); + Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.DummyEntity2)), Is.True); + Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.DummyEntity3)), Is.False); + Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.NestedNamespace.DummyNestedEntity1)), Is.True); + Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.NestedNamespace.DummyNestedEntity2)), Is.True); + } + + [Test] + public void InvalidTypeRegistration1() + { + // same type twice + + var domainConfig = GetDomainConfiguration("DomainWithInvalidRegistrations1"); + + ValidateAllDefault(domainConfig); + Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.DummyEntity1)), Is.True); + Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.DummyEntity2)), Is.False); + Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.DummyEntity3)), Is.False); + } + + [Test] + public void InvalidTypeRegistration2() + { + // same Assembly + var domainConfig = GetDomainConfiguration("DomainWithInvalidRegistrations2"); + + ValidateAllDefault(domainConfig); + var ormAssembly = typeof(DomainConfiguration).Assembly; + Assert.That(domainConfig.Types.Count, Is.GreaterThan(0)); + Assert.That(domainConfig.Types.All((t) => t.Assembly == ormAssembly), Is.True); + } + + [Test] + public void InvalidTypeRegistration3() + { + // same assembly and namespace + var domainConfig = GetDomainConfiguration("DomainWithInvalidRegistrations3"); + ValidateAllDefault(domainConfig); + Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.NestedNamespace.DummyNestedEntity1)), Is.True); + Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.NestedNamespace.DummyNestedEntity2)), Is.True); + } + + [Test] + public void InvalidTypeRegistration4() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidRegistrations4")); + } + + [Test] + public void InvalidTypeRegistration5() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidRegistrations5")); + } + + [Test] + public void InvalidTypeRegistration6() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidRegistrations6")); + } + + [Test] + public void InvalidTypeRegistration7() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidRegistrations7")); + } + + #endregion + + #region Sessions + + [Test] + public void MultipleSessionsTest() + { + var domainConfig = GetDomainConfiguration("DomainWithMultipleSessionConfigurations"); + ValidateAllDefault(domainConfig); + + var sessions = domainConfig.Sessions; + Assert.That(sessions.Count, Is.EqualTo(2)); + var session = sessions[0]; + Assert.That(session.Name, Is.EqualTo(WellKnown.Sessions.Default)); + ValidateAllDefaultExcept(session, + ((s) => s.CacheType, SessionCacheType.Infinite), + ((s) => s.BatchSize, 20), + ((s) => s.EntityChangeRegistrySize, 255), + ((s) => s.Options, SessionOptions.AllowSwitching | SessionOptions.AutoActivation | SessionOptions.ReadRemovedObjects | SessionOptions.ValidateEntityVersions)); + + session = sessions[1]; + Assert.That(session.Name, Is.EqualTo(WellKnown.Sessions.System)); + ValidateAllDefaultExcept(session, + ((s) => s.CacheType, SessionCacheType.Infinite), + ((s) => s.BatchSize, 30), + ((s) => s.Options, SessionOptions.ServerProfile)); + } + + [Test] + public void SessionWithEmptyNameTest() + { + var domainConfig = GetDomainConfiguration("DomainWithSessionEmptyName"); + ValidateAllDefault(domainConfig); + + var sessions = domainConfig.Sessions; + Assert.That(sessions.Count, Is.EqualTo(1)); + Assert.That(sessions[0].Name, Is.EqualTo(WellKnown.Sessions.Default)); + ValidateAllDefaultExcept(sessions[0], + ((s) => s.Options, SessionOptions.ClientProfile)); + } + + [Test] + public void SessionWithCustomNameTest() + { + var domainConfig = GetDomainConfiguration("DomainWithSessionCustomName"); + ValidateAllDefault(domainConfig); + + var sessions = domainConfig.Sessions; + Assert.That(sessions.Count, Is.EqualTo(1)); + Assert.That(sessions[0].Name, Is.Not.EqualTo(WellKnown.Sessions.Default)); + Assert.That(sessions[0].Name, Is.EqualTo("UserCreated")); + + ValidateAllDefaultExcept(sessions[0], + ((s) => s.Options, SessionOptions.ClientProfile)); + } + + [Test] + public void SessionWithCustomUserNameTest() + { + var domainConfig = GetDomainConfiguration("DomainWithSessionCustomUser"); + ValidateAllDefault(domainConfig); + + var sessions = domainConfig.Sessions; + Assert.That(sessions.Count, Is.EqualTo(1)); + Assert.That(sessions[0].Name, Is.EqualTo(WellKnown.Sessions.Default)); + ValidateAllDefaultExcept(sessions[0], + ((s) => s.UserName, "User"), + ((s) => s.Password, "126654")); + } + + [Test] + public void SessionWithOptionsTest1() + { + var domainConfig = GetDomainConfiguration("DomainWithSessionDefaultOptions"); + ValidateAllDefault(domainConfig); + + var sessions = domainConfig.Sessions; + Assert.That(sessions.Count, Is.EqualTo(1)); + Assert.That(sessions[0].Name, Is.EqualTo(WellKnown.Sessions.Default)); + ValidateAllDefaultExcept(sessions[0], + ((s) => s.Options, SessionOptions.Default)); + + } + + [Test] + public void SessionWithOptionsTest2() + { + var domainConfig = GetDomainConfiguration("DomainWithSessionServerProfile"); + ValidateAllDefault(domainConfig); + + var sessions = domainConfig.Sessions; + Assert.That(sessions.Count, Is.EqualTo(1)); + Assert.That(sessions[0].Name, Is.EqualTo(WellKnown.Sessions.Default)); + ValidateAllDefaultExcept(sessions[0], + ((s) => s.Options, SessionOptions.ServerProfile)); + + } + + [Test] + public void SessionWithOptionsTest3() + { + var domainConfig = GetDomainConfiguration("DomainWithSessionClientProfile"); + ValidateAllDefault(domainConfig); + + var sessions = domainConfig.Sessions; + Assert.That(sessions.Count, Is.EqualTo(1)); + Assert.That(sessions[0].Name, Is.EqualTo(WellKnown.Sessions.Default)); + ValidateAllDefaultExcept(sessions[0], + ((s) => s.Options, SessionOptions.ClientProfile)); + + } + + [Test] + public void SessionWithOptionsTest4() + { + var domainConfig = GetDomainConfiguration("DomainWithSessionCustomOptions"); + ValidateAllDefault(domainConfig); + + var sessions = domainConfig.Sessions; + Assert.That(sessions.Count, Is.EqualTo(1)); + Assert.That(sessions[0].Name, Is.EqualTo(WellKnown.Sessions.Default)); + ValidateAllDefaultExcept(sessions[0], + ((s) => s.Options, SessionOptions.AllowSwitching | SessionOptions.AutoActivation | SessionOptions.ReadRemovedObjects | SessionOptions.ValidateEntityVersions)); + + } + + [Test] + public void SessionWithCollectionSizesTest() + { + var domainConfig = GetDomainConfiguration("DomainWithSessionWithCollectionSizes"); + ValidateAllDefault(domainConfig); + + var sessions = domainConfig.Sessions; + Assert.That(sessions.Count, Is.EqualTo(1)); + Assert.That(sessions[0].Name, Is.EqualTo(WellKnown.Sessions.Default)); + ValidateAllDefaultExcept(sessions[0], + ((s) => s.CacheSize, 399), + ((s) => s.BatchSize, 20), + ((s) => s.EntityChangeRegistrySize, 255)); + + } + + [Test] + public void SessionCustomCacheTypeTest() + { + var domainConfig = GetDomainConfiguration("DomainWithSessionCustomCacheType"); + ValidateAllDefault(domainConfig); + + var sessions = domainConfig.Sessions; + Assert.That(sessions.Count, Is.EqualTo(1)); + Assert.That(sessions[0].Name, Is.EqualTo(WellKnown.Sessions.Default)); + ValidateAllDefaultExcept(sessions[0], + ((s) => s.CacheType, SessionCacheType.Infinite)); + + } + + [Test] + public void SessionCustomIsolationLevelTest() + { + var domainConfig = GetDomainConfiguration("DomainWithSessionCustomIsolationLevel"); + ValidateAllDefault(domainConfig); + + var sessions = domainConfig.Sessions; + Assert.That(sessions.Count, Is.EqualTo(1)); + Assert.That(sessions[0].Name, Is.EqualTo(WellKnown.Sessions.Default)); + ValidateAllDefaultExcept(sessions[0], + ((s) => s.DefaultIsolationLevel, IsolationLevel.ReadCommitted)); + + } + + [Test] + public void SessionCustomCommandTimeoutTest() + { + var domainConfig = GetDomainConfiguration("DomainWithSessionCustomCommandTimeout"); + ValidateAllDefault(domainConfig); + + var sessions = domainConfig.Sessions; + Assert.That(sessions.Count, Is.EqualTo(1)); + Assert.That(sessions[0].Name, Is.EqualTo(WellKnown.Sessions.Default)); + ValidateAllDefaultExcept(sessions[0], + ((s) => s.DefaultCommandTimeout, (int?)300)); + + } + + [Test] + public void SessionCustomPreloadingPolicyTest() + { + var domainConfig = GetDomainConfiguration("DomainWithSessionCustomPreloadingPolicy"); + ValidateAllDefault(domainConfig); + + var sessions = domainConfig.Sessions; + Assert.That(sessions.Count, Is.EqualTo(1)); + Assert.That(sessions[0].Name, Is.EqualTo(WellKnown.Sessions.Default)); + ValidateAllDefaultExcept(sessions[0], + ((s) => s.ReaderPreloading, ReaderPreloadingPolicy.Always)); + + } + + [Test] + public void SessionCustomConnectionStringTest() + { + var domainConfig = GetDomainConfiguration("DomainWithSessionCustomConnectionString"); + ValidateAllDefault(domainConfig); + + var sessions = domainConfig.Sessions; + Assert.That(sessions.Count, Is.EqualTo(1)); + Assert.That(sessions[0].Name, Is.EqualTo(WellKnown.Sessions.Default)); + ValidateAllDefaultExcept(sessions[0], + ((s) => s.ConnectionInfo, new ConnectionInfo("_dummy_", "Data Source=localhost;Initial Catalog=DO-Tests;Integrated Security=True;MultipleActiveResultSets=True"))); + } + + [Test] + public void SessionCustomConnectionUrlTest() + { + var domainConfig = GetDomainConfiguration("DomainWithSessionCustomConnectionUrl"); + ValidateAllDefault(domainConfig); + var sessions = domainConfig.Sessions; + Assert.That(sessions.Count, Is.EqualTo(1)); + Assert.That(sessions[0].Name, Is.EqualTo(WellKnown.Sessions.Default)); + ValidateAllDefaultExcept(sessions[0], + ((s) => s.ConnectionInfo, new ConnectionInfo("sqlserver://localhost/DO-Tests"))); + } + + [Test] + public void SessionWithInvalidOptions() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithSessionInvalidOptions")); + } + + [Test] + public void SessionWithInvalidCacheSizeTest1() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithSessionInvalidCacheSize1")); + } + + [Test] + public void SessionWithInvalidCacheSizeTest2() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithSessionInvalidCacheSize2")); + } + + [Test] + public void SessionWithInvalidCacheSizeTest3() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithSessionInvalidCacheSize3")); + } + + [Test] + public void SessionWithInvalidBatchSizeTest1() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithSessionInvalidBatchSize1")); + } + + [Test] + public void SessionWithInvalidBatchSizeTest2() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithSessionInvalidBatchSize2")); + } + + [Test] + public void SessionWithInvalidEntityChangeRegistryTest1() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithSessionInvalidEntityChangeRegistry1")); + } + + [Test] + public void SessionWithInvalidEntityChangeRegistryTest2() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithSessionInvalidEntityChangeRegistry2")); + } + + [Test] + public void SessionWithInvalidCacheType1() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithSessionInvalidCacheType")); + } + + #endregion + + #region Databases configuration + + [Test] + public void DatabaseConfigurationOnlyAliasTest() + { + var domainConfig = GetDomainConfiguration("DomainWithDatabases1"); + ValidateAllDefault(domainConfig); + Assert.That(domainConfig.Databases.Count, Is.EqualTo(2)); + var db1 = domainConfig.Databases[0]; + Assert.That(db1.Name, Is.EqualTo("main")); + Assert.That(db1.RealName, Is.EqualTo("DO-Tests-1")); + Assert.That(db1.MinTypeId, Is.EqualTo(Orm.Model.TypeInfo.MinTypeId)); + Assert.That(db1.MaxTypeId, Is.EqualTo(int.MaxValue)); + var db2 = domainConfig.Databases[1]; + Assert.That(db2.Name, Is.EqualTo("other")); + Assert.That(db2.RealName, Is.EqualTo("DO-Tests-2")); + Assert.That(db2.MinTypeId, Is.EqualTo(Orm.Model.TypeInfo.MinTypeId)); + Assert.That(db2.MaxTypeId, Is.EqualTo(int.MaxValue)); + } + + [Test] + public void DatabaseConfigurationWithTypeIdsTest() + { + var domainConfig = GetDomainConfiguration("DomainWithDatabases2"); + ValidateAllDefault(domainConfig); + Assert.That(domainConfig.Databases.Count, Is.EqualTo(2)); + var db1 = domainConfig.Databases[0]; + Assert.That(db1.Name, Is.EqualTo("main")); + Assert.That(db1.RealName, Is.EqualTo("DO-Tests-1")); + Assert.That(db1.MinTypeId, Is.EqualTo(100)); + Assert.That(db1.MaxTypeId, Is.EqualTo(1000)); + var db2 = domainConfig.Databases[1]; + Assert.That(db2.Name, Is.EqualTo("other")); + Assert.That(db2.RealName, Is.EqualTo("DO-Tests-2")); + Assert.That(db2.MinTypeId, Is.EqualTo(2000)); + Assert.That(db2.MaxTypeId, Is.EqualTo(3000)); + } + + [Test] + public void DatabaseConfigurationNegativeMinTypeIdTest() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidDatabases1")); + } + + [Test] + public void DatabaseConfigurationInvalidMinTypeIdTest() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidDatabases2")); + } + + [Test] + public void DatabaseConfigurationNegativeMaxTypeIdTest() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidDatabases3")); + } + + [Test] + public void DatabaseConfigurationInvalidMaxTypeIdTest() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidDatabases4")); + } + + #endregion + + #region KeyGenerators + + [Test] + public void SimpleKeyGeneratorTest() + { + if (!NameAttributeUnique) + throw new IgnoreException(""); + var domainConfig = GetDomainConfiguration("DomainWithCustomGenerator"); + ValidateAllDefault(domainConfig); + } + + [Test] + public void KeyGeneratorWithDatabaseNamesTest() + { + if (!NameAttributeUnique) + throw new IgnoreException(""); + var domainConfig = GetDomainConfiguration("DomainWithCustomGeneratorsWithDatabaseNames"); + ValidateAllDefault(domainConfig); + } + + [Test] + public void KeyGeneratorWithDatabaseNamesAllParamsTest() + { + if (!NameAttributeUnique) + throw new IgnoreException(""); + var domainConfig = GetDomainConfiguration("DomainWithCustomGeneratorsWithDatabaseNamesAndKeyParams"); + ValidateAllDefault(domainConfig); + } + + [Test] + public void KeyGeneratorsWithDatabaseAliasesTest() + { + if (!NameAttributeUnique) + throw new IgnoreException(""); + var domainConfig = GetDomainConfiguration("DomainWithCustomGeneratorsWithDatabasesAliases"); + ValidateAllDefault(domainConfig); + } + + [Test] + public void KeyGeneratorsWithConflictByDatabaseTest1() + { + if (!NameAttributeUnique) + throw new IgnoreException(""); + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithCustomGeneratorsConflict1")); + } + + [Test] + public void KeyGeneratorsWithConflictByDatabaseTest2() + { + if (!NameAttributeUnique) + throw new IgnoreException(""); + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithCustomGeneratorsConflict2")); + } + + [Test] + public void KeyGeneratorWithNegativeSeedTest() + { + if (!NameAttributeUnique) + throw new IgnoreException(""); + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithCustomGeneratorNegativeSeed")); + } + + [Test] + public void KeyGeneratorWithNegativeCacheSizeTest() + { + if (!NameAttributeUnique) + throw new IgnoreException(""); + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithCustomGeneratorNegativeCache")); + } + + #endregion + + #region IgnoreRules + + [Test] + public void IgnoreRulesTest() + { + var domainConfig = GetDomainConfiguration("DomainWithIgnoreRules"); + ValidateAllDefault(domainConfig); + ValidateIgnoreRules(domainConfig.IgnoreRules); + } + + [Test] + public void IgnoreColumnAndIndexAtTheSameTimeTest() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidIgnoreRules1")); + } + + [Test] + public void IgnoreTableAndColumnAndIndexAtTheSameTimeTest() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidIgnoreRules2")); + } + + [Test] + public void IgnoreDatabaseOnlyTest() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidIgnoreRules3")); + } + + [Test] + public void IgnoreDatabaseAndSchemaOnlyTest() + { + _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidIgnoreRules4")); + } + + private void ValidateIgnoreRules(IgnoreRuleCollection rules) + { + Assert.That(rules.Count, Is.EqualTo(18)); + + var rule = rules[0]; + Assert.That(rule.Database, Is.EqualTo("Other-DO40-Tests")); + Assert.That(rule.Schema, Is.EqualTo("some-schema1")); + Assert.That(rule.Table, Is.EqualTo("table1")); + Assert.That(rule.Column, Is.Null.Or.Empty); + Assert.That(rule.Index, Is.Null.Or.Empty); + + rule = rules[1]; + Assert.That(rule.Database, Is.EqualTo("some-database")); + Assert.That(rule.Schema, Is.EqualTo("some-schema2")); + Assert.That(rule.Table, Is.Null.Or.Empty); + Assert.That(rule.Column, Is.EqualTo("column2")); + Assert.That(rule.Index, Is.Null.Or.Empty); + + rule = rules[2]; + Assert.That(rule.Database, Is.EqualTo("some-database")); + Assert.That(rule.Schema, Is.EqualTo("some-schema2")); + Assert.That(rule.Table, Is.Null.Or.Empty); + Assert.That(rule.Column, Is.Null.Or.Empty); + Assert.That(rule.Index, Is.EqualTo("index2")); + + rule = rules[3]; + Assert.That(rule.Database, Is.EqualTo("some-database")); + Assert.That(rule.Schema, Is.EqualTo("some-schema3")); + Assert.That(rule.Table, Is.EqualTo("table2")); + Assert.That(rule.Column, Is.EqualTo("col3")); + Assert.That(rule.Index, Is.Null.Or.Empty); + + rule = rules[4]; + Assert.That(rule.Database, Is.EqualTo("some-database")); + Assert.That(rule.Schema, Is.EqualTo("some-schema3")); + Assert.That(rule.Table, Is.EqualTo("table2")); + Assert.That(rule.Column, Is.Null.Or.Empty); + Assert.That(rule.Index, Is.EqualTo("index3")); + + rule = rules[5]; + Assert.That(rule.Database, Is.EqualTo("another-some-database")); + Assert.That(rule.Schema, Is.Null.Or.Empty); + Assert.That(rule.Table, Is.EqualTo("some-table")); + Assert.That(rule.Column, Is.Null.Or.Empty); + Assert.That(rule.Index, Is.Null.Or.Empty); + + rule = rules[6]; + Assert.That(rule.Database, Is.EqualTo("database1")); + Assert.That(rule.Schema, Is.Null.Or.Empty); + Assert.That(rule.Table, Is.Null.Or.Empty); + Assert.That(rule.Column, Is.EqualTo("some-column")); + Assert.That(rule.Index, Is.Null.Or.Empty); + + rule = rules[7]; + Assert.That(rule.Database, Is.EqualTo("database1")); + Assert.That(rule.Schema, Is.Null.Or.Empty); + Assert.That(rule.Table, Is.Null.Or.Empty); + Assert.That(rule.Column, Is.Null.Or.Empty); + Assert.That(rule.Index, Is.EqualTo("some-index")); + + rule = rules[8]; + Assert.That(rule.Database, Is.Null.Or.Empty); + Assert.That(rule.Schema, Is.EqualTo("schema1")); + Assert.That(rule.Table, Is.EqualTo("table1")); + Assert.That(rule.Column, Is.Null.Or.Empty); + Assert.That(rule.Index, Is.Null.Or.Empty); + + rule = rules[9]; + Assert.That(rule.Database, Is.Null.Or.Empty); + Assert.That(rule.Schema, Is.EqualTo("schema1")); + Assert.That(rule.Table, Is.Null.Or.Empty); + Assert.That(rule.Column, Is.EqualTo("column2")); + Assert.That(rule.Index, Is.Null.Or.Empty); + + rule = rules[10]; + Assert.That(rule.Database, Is.Null.Or.Empty); + Assert.That(rule.Schema, Is.EqualTo("schema1")); + Assert.That(rule.Table, Is.Null.Or.Empty); + Assert.That(rule.Column, Is.Null.Or.Empty); + Assert.That(rule.Index, Is.EqualTo("index2")); + + rule = rules[11]; + Assert.That(rule.Database, Is.Null.Or.Empty); + Assert.That(rule.Schema, Is.EqualTo("schema1")); + Assert.That(rule.Table, Is.EqualTo("table2")); + Assert.That(rule.Column, Is.EqualTo("column3")); + Assert.That(rule.Index, Is.Null.Or.Empty); + + rule = rules[12]; + Assert.That(rule.Database, Is.Null.Or.Empty); + Assert.That(rule.Schema, Is.EqualTo("schema1")); + Assert.That(rule.Table, Is.EqualTo("table2")); + Assert.That(rule.Column, Is.Null.Or.Empty); + Assert.That(rule.Index, Is.EqualTo("index3")); + + rule = rules[13]; + Assert.That(rule.Database, Is.Null.Or.Empty); + Assert.That(rule.Schema, Is.Null.Or.Empty); + Assert.That(rule.Table, Is.EqualTo("table4")); + Assert.That(rule.Column, Is.EqualTo("column3")); + Assert.That(rule.Index, Is.Null.Or.Empty); + + rule = rules[14]; + Assert.That(rule.Database, Is.Null.Or.Empty); + Assert.That(rule.Schema, Is.Null.Or.Empty); + Assert.That(rule.Table, Is.EqualTo("table4")); + Assert.That(rule.Column, Is.Null.Or.Empty); + Assert.That(rule.Index, Is.EqualTo("index2")); + + rule = rules[15]; + Assert.That(rule.Database, Is.Null.Or.Empty); + Assert.That(rule.Schema, Is.Null.Or.Empty); + Assert.That(rule.Table, Is.EqualTo("single-table")); + Assert.That(rule.Column, Is.Null.Or.Empty); + Assert.That(rule.Index, Is.Null.Or.Empty); + + rule = rules[16]; + Assert.That(rule.Database, Is.Null.Or.Empty); + Assert.That(rule.Schema, Is.Null.Or.Empty); + Assert.That(rule.Table, Is.Null.Or.Empty); + Assert.That(rule.Column, Is.EqualTo("single-column")); + Assert.That(rule.Index, Is.Null.Or.Empty); + + rule = rules[17]; + Assert.That(rule.Database, Is.Null.Or.Empty); + Assert.That(rule.Schema, Is.Null.Or.Empty); + Assert.That(rule.Table, Is.Null.Or.Empty); + Assert.That(rule.Column, Is.Null.Or.Empty); + Assert.That(rule.Index, Is.EqualTo("single-index")); + } + + #endregion + + #region MappingRules + + [Test] + public void MappingRulesTest1() + { + var domainConfig = GetDomainConfiguration("DomainWithMappingRules1"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.DefaultDatabase, "main"), + ((d) => d.DefaultSchema, "dbo"), + ((d) => d.IsMultidatabase, true), + ((d) => d.IsMultischema, true)); + var rules = domainConfig.MappingRules; + + Assert.That(rules.Count, Is.EqualTo(1)); + var rule = rules[0]; + Assert.That(rule.Assembly, Is.EqualTo(typeof(JsonConfigurationTest).Assembly)); + Assert.That(rule.Namespace, Is.Null); + Assert.That(rule.Database, Is.EqualTo("DO-Tests-1")); + Assert.That(rule.Schema, Is.Null); + } + + [Test] + public void MappingRulesTest2() + { + var domainConfig = GetDomainConfiguration("DomainWithMappingRules2"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.DefaultDatabase, "main"), + ((d) => d.DefaultSchema, "dbo"), + ((d) => d.IsMultidatabase, true), + ((d) => d.IsMultischema, true)); + var rules = domainConfig.MappingRules; + + Assert.That(rules.Count, Is.EqualTo(1)); + var rule = rules[0]; + Assert.That(rule.Assembly, Is.EqualTo(typeof(JsonConfigurationTest).Assembly)); + Assert.That(rule.Namespace, Is.Null); + Assert.That(rule.Database, Is.Null); + Assert.That(rule.Schema, Is.EqualTo("Model1")); + + + } + + [Test] + public void MappingRulesTest3() + { + var domainConfig = GetDomainConfiguration("DomainWithMappingRules3"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.DefaultDatabase, "main"), + ((d) => d.DefaultSchema, "dbo"), + ((d) => d.IsMultidatabase, true), + ((d) => d.IsMultischema, true)); + var rules = domainConfig.MappingRules; + + Assert.That(rules.Count, Is.EqualTo(1)); + var rule = rules[0]; + + Assert.That(rule.Assembly, Is.Null); + Assert.That(rule.Namespace, Is.EqualTo("Xtensive.Orm.Configuration.Options")); + Assert.That(rule.Database, Is.EqualTo("DO-Tests-2")); + Assert.That(rule.Schema, Is.Null); + } + + [Test] + public void MappingRulesTest4() + { + var domainConfig = GetDomainConfiguration("DomainWithMappingRules4"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.DefaultDatabase, "main"), + ((d) => d.DefaultSchema, "dbo"), + ((d) => d.IsMultidatabase, true), + ((d) => d.IsMultischema, true)); + var rules = domainConfig.MappingRules; + + Assert.That(rules.Count, Is.EqualTo(1)); + var rule = rules[0]; + + Assert.That(rule.Assembly, Is.Null); + Assert.That(rule.Namespace, Is.EqualTo("Xtensive.Orm.Tests.Configuration")); + Assert.That(rule.Database, Is.Null); + Assert.That(rule.Schema, Is.EqualTo("Model2")); + } + + [Test] + public void MappingRulesTest5() + { + var domainConfig = GetDomainConfiguration("DomainWithMappingRules5"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.DefaultDatabase, "main"), + ((d) => d.DefaultSchema, "dbo"), + ((d) => d.IsMultidatabase, true), + ((d) => d.IsMultischema, true)); + var rules = domainConfig.MappingRules; + + Assert.That(rules.Count, Is.EqualTo(1)); + var rule = rules[0]; + + Assert.That(rule.Assembly, Is.EqualTo(typeof (JsonConfigurationTest).Assembly)); + Assert.That(rule.Namespace, Is.EqualTo("Xtensive.Orm.Tests.Configuration.TypesToUseInTests")); + Assert.That(rule.Database, Is.EqualTo("DO-Tests-3")); + Assert.That(rule.Schema, Is.Null); + } + + [Test] + public void MappingRulesTest6() + { + var domainConfig = GetDomainConfiguration("DomainWithMappingRules6"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.DefaultDatabase, "main"), + ((d) => d.DefaultSchema, "dbo"), + ((d) => d.IsMultidatabase, true), + ((d) => d.IsMultischema, true)); + var rules = domainConfig.MappingRules; + + Assert.That(rules.Count, Is.EqualTo(1)); + var rule = rules[0]; + Assert.That(rule.Assembly, Is.EqualTo(typeof(JsonConfigurationTest).Assembly)); + Assert.That(rule.Namespace, Is.EqualTo("Xtensive.Orm.Tests.Configuration.TypesToUseInTests.NestedNamespace")); + Assert.That(rule.Database, Is.Null); + Assert.That(rule.Schema, Is.EqualTo("Model3")); + } + + [Test] + public void MappingRulesTest7() + { + var domainConfig = GetDomainConfiguration("DomainWithMappingRules7"); + ValidateAllDefaultExcept(domainConfig, + ((d) => d.DefaultDatabase, "main"), + ((d) => d.DefaultSchema, "dbo"), + ((d) => d.IsMultidatabase, true), + ((d) => d.IsMultischema, true)); + var rules = domainConfig.MappingRules; + + Assert.That(rules.Count, Is.EqualTo(1)); + var rule = rules[0]; + Assert.That(rule.Assembly, Is.EqualTo(typeof(JsonConfigurationTest).Assembly)); + Assert.That(rule.Namespace, Is.EqualTo("Xtensive.Orm.Tests.Indexing")); + Assert.That(rule.Database, Is.EqualTo("main")); + Assert.That(rule.Schema, Is.EqualTo("Model4")); + } + + [Test] + public void MappingRuleWithConflictByAssemblyTest() + { + var exception = Assert.Throws( + () => GetDomainConfiguration("DomainWithConflictMappingRules1")); + } + + [Test] + public void MappingRuleWithConflictByNamespaceTest() + { + var exception = Assert.Throws( + () => GetDomainConfiguration("DomainWithConflictMappingRules2")); + } + + [Test] + public void MappingRulesInvalidTest1() + { + var exception = Assert.Throws( + () => GetDomainConfiguration("DomainWithInvalidMappingRules1")); + } + + [Test] + public void MappingRulesInvalidTest2() + { + var exception = Assert.Throws( + () => GetDomainConfiguration("DomainWithInvalidMappingRules2")); + } + + [Test] + public void MappingRulesInvalidTest3() + { + var exception = Assert.Throws( + () => GetDomainConfiguration("DomainWithInvalidMappingRules3")); + } + + [Test] + public void MappingRulesInvalidTest4() + { + var exception = Assert.Throws( + () => GetDomainConfiguration("DomainWithInvalidMappingRules4")); + } + + [Test] + public void MappingRulesInvalidTest5() + { + var exception = Assert.Throws( + () => GetDomainConfiguration("DomainWithInvalidMappingRules5")); + } + + #endregion + + + + private void ValidateAllDefault(DomainConfiguration domainConfiguration) + { + Assert.That(domainConfiguration.AllowCyclicDatabaseDependencies, Is.EqualTo(DomainConfiguration.DefaultAllowCyclicDatabaseDependencies)); + Assert.That(domainConfiguration.BuildInParallel, Is.EqualTo(DomainConfiguration.DefaultBuildInParallel)); + Assert.That(domainConfiguration.Collation, Is.EqualTo(string.Empty)); + Assert.That(domainConfiguration.ConnectionInitializationSql, Is.EqualTo(string.Empty)); + Assert.That(domainConfiguration.DefaultDatabase, Is.EqualTo(string.Empty)); + Assert.That(domainConfiguration.DefaultSchema, Is.EqualTo(string.Empty)); + Assert.That(domainConfiguration.EnsureConnectionIsAlive, Is.EqualTo(DomainConfiguration.DefaultEnsureConnectionIsAlive)); + Assert.That(domainConfiguration.ForcedServerVersion, Is.EqualTo(string.Empty)); + Assert.That(domainConfiguration.ForeignKeyMode, Is.EqualTo(DomainConfiguration.DefaultForeignKeyMode)); + Assert.That(domainConfiguration.FullTextChangeTrackingMode, Is.EqualTo(DomainConfiguration.DefaultFullTextChangeTrackingMode)); + Assert.That(domainConfiguration.IncludeSqlInExceptions, Is.EqualTo(DomainConfiguration.DefaultIncludeSqlInExceptions)); + Assert.That(domainConfiguration.IsMultidatabase, Is.False); + Assert.That(domainConfiguration.IsMultischema, Is.False); + Assert.That(domainConfiguration.KeyCacheSize, Is.EqualTo(DomainConfiguration.DefaultKeyCacheSize)); + Assert.That(domainConfiguration.KeyGeneratorCacheSize, Is.EqualTo(DomainConfiguration.DefaultKeyGeneratorCacheSize)); + Assert.That(domainConfiguration.MultidatabaseKeys, Is.EqualTo(DomainConfiguration.DefaultMultidatabaseKeys)); + Assert.That(domainConfiguration.Options, Is.EqualTo(DomainConfiguration.DefaultDomainOptions)); + Assert.That(domainConfiguration.PreferTypeIdsAsQueryParameters, Is.EqualTo(DomainConfiguration.DefaultPreferTypeIdsAsQueryParameters)); + Assert.That(domainConfiguration.QueryCacheSize, Is.EqualTo(DomainConfiguration.DefaultQueryCacheSize)); + Assert.That(domainConfiguration.RecordSetMappingCacheSize, Is.EqualTo(DomainConfiguration.DefaultRecordSetMappingCacheSize)); + Assert.That(domainConfiguration.SchemaSyncExceptionFormat, Is.EqualTo(DomainConfiguration.DefaultSchemaSyncExceptionFormat)); + Assert.That(domainConfiguration.ShareStorageSchemaOverNodes, Is.EqualTo(DomainConfiguration.DefaultShareStorageSchemaOverNodes)); + Assert.That(domainConfiguration.TagsLocation, Is.EqualTo(DomainConfiguration.DefaultTagLocation)); + Assert.That(domainConfiguration.UpgradeMode, Is.EqualTo(DomainConfiguration.DefaultUpgradeMode)); + } + + private void ValidateAllDefault(SessionConfiguration sessionConfiguration) + { + Assert.That(sessionConfiguration.UserName, Is.Empty); + Assert.That(sessionConfiguration.Password, Is.Empty); + Assert.That(sessionConfiguration.Options, Is.EqualTo(SessionConfiguration.DefaultSessionOptions)); + Assert.That(sessionConfiguration.CacheSize, Is.EqualTo(SessionConfiguration.DefaultCacheSize)); + Assert.That(sessionConfiguration.CacheType, Is.EqualTo(SessionConfiguration.DefaultCacheType)); + Assert.That(sessionConfiguration.DefaultIsolationLevel, Is.EqualTo(SessionConfiguration.DefaultDefaultIsolationLevel)); + Assert.That(sessionConfiguration.DefaultCommandTimeout, Is.Null); + Assert.That(sessionConfiguration.BatchSize, Is.EqualTo(SessionConfiguration.DefaultBatchSize)); + Assert.That(sessionConfiguration.EntityChangeRegistrySize, Is.EqualTo(SessionConfiguration.DefaultEntityChangeRegistrySize)); + Assert.That(sessionConfiguration.ReaderPreloading, Is.EqualTo(SessionConfiguration.DefaultReaderPreloadingPolicy)); + Assert.That(sessionConfiguration.ServiceContainerType, Is.Null); + Assert.That(sessionConfiguration.ConnectionInfo, Is.Null); + } + + private void ValidateAllDefaultExcept(TConfiguration configuration, + (Expression> expression, T1 expectedValue) property) + { + Assert.That(configuration, Is.Not.Null); + var excludedProperties = new List(); + + + if (!TryExtractPropertyFormLambda(property.expression, out var prop)) + throw new InconclusiveException(""); + + Assert.That(property.expression.Compile()(configuration), + Is.EqualTo(property.expectedValue)); + + excludedProperties.Add(prop.Name); + + if (configuration is DomainConfiguration domainConfiguration) + ValidateAllPropertiesExcept(domainConfiguration, excludedProperties); + else if (configuration is SessionConfiguration sessionConfiguration) + ValidateAllPropertiesExcept(sessionConfiguration, excludedProperties); + else + throw new ArgumentOutOfRangeException(nameof(configuration)); + + } + + + private void ValidateAllDefaultExcept(TConfiguration configuration, + (Expression> expression, T1 expectedValue) property1, + (Expression> expression, T2 expectedValue) property2) + { + Assert.That(configuration, Is.Not.Null); + var excludedProperties = new List(); + + if (!TryExtractPropertyFormLambda(property1.expression, out var prop)) + throw new InconclusiveException(""); + + Assert.That(property1.expression.Compile()(configuration), + Is.EqualTo(property1.expectedValue)); + + excludedProperties.Add(prop.Name); + + if (!TryExtractPropertyFormLambda(property2.expression, out prop)) + throw new InconclusiveException(""); + + Assert.That(property2.expression.Compile()(configuration), + Is.EqualTo(property2.expectedValue)); + + excludedProperties.Add(prop.Name); + + if(configuration is DomainConfiguration domainConfiguration) + ValidateAllPropertiesExcept(domainConfiguration, excludedProperties); + else if (configuration is SessionConfiguration sessionConfiguration) + ValidateAllPropertiesExcept(sessionConfiguration, excludedProperties); + else + throw new ArgumentOutOfRangeException(nameof(configuration)); + } + + private void ValidateAllDefaultExcept(TConfiguration configuration, + (Expression> expression, T1 expectedValue) property1, + (Expression> expression, T2 expectedValue) property2, + (Expression> expression, T3 expectedValue) property3) + { + Assert.That(configuration, Is.Not.Null); + var excludedProperties = new List(); + + if (!TryExtractPropertyFormLambda(property1.expression, out var prop)) + throw new InconclusiveException(""); + + Assert.That(property1.expression.Compile()(configuration), + Is.EqualTo(property1.expectedValue)); + + excludedProperties.Add(prop.Name); + + if (!TryExtractPropertyFormLambda(property2.expression, out prop)) + throw new InconclusiveException(""); + + Assert.That(property2.expression.Compile()(configuration), + Is.EqualTo(property2.expectedValue)); + + excludedProperties.Add(prop.Name); + + if (!TryExtractPropertyFormLambda(property3.expression, out prop)) + throw new InconclusiveException(""); + + Assert.That(property3.expression.Compile()(configuration), + Is.EqualTo(property3.expectedValue)); + + excludedProperties.Add(prop.Name); + + if (configuration is DomainConfiguration domainConfiguration) + ValidateAllPropertiesExcept(domainConfiguration, excludedProperties); + else if (configuration is SessionConfiguration sessionConfiguration) + ValidateAllPropertiesExcept(sessionConfiguration, excludedProperties); + else + throw new ArgumentOutOfRangeException(nameof(configuration)); + } + + private void ValidateAllDefaultExcept(TConfiguration configuration, + (Expression> expression, T1 expectedValue) property1, + (Expression> expression, T2 expectedValue) property2, + (Expression> expression, T3 expectedValue) property3, + (Expression> expression, T4 expectedValue) property4) + { + Assert.That(configuration, Is.Not.Null); + var excludedProperties = new List(); + + if (!TryExtractPropertyFormLambda(property1.expression, out var prop)) + throw new InconclusiveException(""); + + Assert.That(property1.expression.Compile()(configuration), + Is.EqualTo(property1.expectedValue)); + + excludedProperties.Add(prop.Name); + + if (!TryExtractPropertyFormLambda(property2.expression, out prop)) + throw new InconclusiveException(""); + + Assert.That(property2.expression.Compile()(configuration), + Is.EqualTo(property2.expectedValue)); + + excludedProperties.Add(prop.Name); + + if (!TryExtractPropertyFormLambda(property3.expression, out prop)) + throw new InconclusiveException(""); + + Assert.That(property3.expression.Compile()(configuration), + Is.EqualTo(property3.expectedValue)); + + excludedProperties.Add(prop.Name); + + if (!TryExtractPropertyFormLambda(property4.expression, out prop)) + throw new InconclusiveException(""); + + Assert.That(property4.expression.Compile()(configuration), + Is.EqualTo(property4.expectedValue)); + + excludedProperties.Add(prop.Name); + + if (configuration is DomainConfiguration domainConfiguration) + ValidateAllPropertiesExcept(domainConfiguration, excludedProperties); + else if (configuration is SessionConfiguration sessionConfiguration) + ValidateAllPropertiesExcept(sessionConfiguration, excludedProperties); + else + throw new ArgumentOutOfRangeException(nameof(configuration)); + } + + public bool TryExtractPropertyFormLambda(Expression> lambda, + out System.Reflection.PropertyInfo property) + { + if (lambda.Body.StripCasts() is MemberExpression mExpression && mExpression.Member is System.Reflection.PropertyInfo prop) { + property = prop; + return true; + } + property = null; + return false; + } + + private void ValidateAllPropertiesExcept(DomainConfiguration domainConfiguration, List excludedProperties) + { + if (!nameof(domainConfiguration.AllowCyclicDatabaseDependencies).In(excludedProperties)) + Assert.That(domainConfiguration.AllowCyclicDatabaseDependencies, Is.EqualTo(DomainConfiguration.DefaultAllowCyclicDatabaseDependencies)); + + if (!nameof(domainConfiguration.BuildInParallel).In(excludedProperties)) + Assert.That(domainConfiguration.BuildInParallel, Is.EqualTo(DomainConfiguration.DefaultBuildInParallel)); + + if (!nameof(domainConfiguration.Collation).In(excludedProperties)) + Assert.That(domainConfiguration.Collation, Is.EqualTo(string.Empty)); + + if (!nameof(domainConfiguration.ConnectionInitializationSql).In(excludedProperties)) + Assert.That(domainConfiguration.ConnectionInitializationSql, Is.EqualTo(string.Empty)); + + if (!nameof(domainConfiguration.DefaultDatabase).In(excludedProperties)) + Assert.That(domainConfiguration.DefaultDatabase, Is.EqualTo(string.Empty)); + + if (!nameof(domainConfiguration.DefaultSchema).In(excludedProperties)) + Assert.That(domainConfiguration.DefaultSchema, Is.EqualTo(string.Empty)); + + if (!nameof(domainConfiguration.EnsureConnectionIsAlive).In(excludedProperties)) + Assert.That(domainConfiguration.EnsureConnectionIsAlive, Is.EqualTo(DomainConfiguration.DefaultEnsureConnectionIsAlive)); + + if (!nameof(domainConfiguration.ForcedServerVersion).In(excludedProperties)) + Assert.That(domainConfiguration.ForcedServerVersion, Is.EqualTo(string.Empty)); + + if (!nameof(domainConfiguration.ForeignKeyMode).In(excludedProperties)) + Assert.That(domainConfiguration.ForeignKeyMode, Is.EqualTo(DomainConfiguration.DefaultForeignKeyMode)); + + if (!nameof(domainConfiguration.FullTextChangeTrackingMode).In(excludedProperties)) + Assert.That(domainConfiguration.FullTextChangeTrackingMode, Is.EqualTo(DomainConfiguration.DefaultFullTextChangeTrackingMode)); + + if (!nameof(domainConfiguration.IncludeSqlInExceptions).In(excludedProperties)) + Assert.That(domainConfiguration.IncludeSqlInExceptions, Is.EqualTo(DomainConfiguration.DefaultIncludeSqlInExceptions)); + + if (!nameof(domainConfiguration.IsMultidatabase).In(excludedProperties)) + Assert.That(domainConfiguration.IsMultidatabase, Is.False); + + if (!nameof(domainConfiguration.IsMultischema).In(excludedProperties)) + Assert.That(domainConfiguration.IsMultischema, Is.False); + + if (!nameof(domainConfiguration.KeyCacheSize).In(excludedProperties)) + Assert.That(domainConfiguration.KeyCacheSize, Is.EqualTo(DomainConfiguration.DefaultKeyCacheSize)); + + if (!nameof(domainConfiguration.KeyGeneratorCacheSize).In(excludedProperties)) + Assert.That(domainConfiguration.KeyGeneratorCacheSize, Is.EqualTo(DomainConfiguration.DefaultKeyGeneratorCacheSize)); + + if (!nameof(domainConfiguration.MultidatabaseKeys).In(excludedProperties)) + Assert.That(domainConfiguration.MultidatabaseKeys, Is.EqualTo(DomainConfiguration.DefaultMultidatabaseKeys)); + + if (!nameof(domainConfiguration.Options).In(excludedProperties)) + Assert.That(domainConfiguration.Options, Is.EqualTo(DomainConfiguration.DefaultDomainOptions)); + + if (!nameof(domainConfiguration.PreferTypeIdsAsQueryParameters).In(excludedProperties)) + Assert.That(domainConfiguration.PreferTypeIdsAsQueryParameters, Is.EqualTo(DomainConfiguration.DefaultPreferTypeIdsAsQueryParameters)); + + if (!nameof(domainConfiguration.QueryCacheSize).In(excludedProperties)) + Assert.That(domainConfiguration.QueryCacheSize, Is.EqualTo(DomainConfiguration.DefaultQueryCacheSize)); + + if (!nameof(domainConfiguration.RecordSetMappingCacheSize).In(excludedProperties)) + Assert.That(domainConfiguration.RecordSetMappingCacheSize, Is.EqualTo(DomainConfiguration.DefaultRecordSetMappingCacheSize)); + + if (!nameof(domainConfiguration.SchemaSyncExceptionFormat).In(excludedProperties)) + Assert.That(domainConfiguration.SchemaSyncExceptionFormat, Is.EqualTo(DomainConfiguration.DefaultSchemaSyncExceptionFormat)); + + if (!nameof(domainConfiguration.ShareStorageSchemaOverNodes).In(excludedProperties)) + Assert.That(domainConfiguration.ShareStorageSchemaOverNodes, Is.EqualTo(DomainConfiguration.DefaultShareStorageSchemaOverNodes)); + + if (!nameof(domainConfiguration.TagsLocation).In(excludedProperties)) + Assert.That(domainConfiguration.TagsLocation, Is.EqualTo(DomainConfiguration.DefaultTagLocation)); + + if (!nameof(domainConfiguration.UpgradeMode).In(excludedProperties)) + Assert.That(domainConfiguration.UpgradeMode, Is.EqualTo(DomainConfiguration.DefaultUpgradeMode)); + } + + private void ValidateAllPropertiesExcept(SessionConfiguration sessionConfiguration, List excludedProperties) + { + if (!nameof(sessionConfiguration.UserName).In(excludedProperties)) + Assert.That(sessionConfiguration.UserName, Is.Empty); + + if (!nameof(sessionConfiguration.Password).In(excludedProperties)) + Assert.That(sessionConfiguration.Password, Is.Empty); + + if (!nameof(sessionConfiguration.Options).In(excludedProperties)) + Assert.That(sessionConfiguration.Options, Is.EqualTo(SessionConfiguration.DefaultSessionOptions)); + + if (!nameof(sessionConfiguration.CacheSize).In(excludedProperties)) + Assert.That(sessionConfiguration.CacheSize, Is.EqualTo(SessionConfiguration.DefaultCacheSize)); + + if (!nameof(sessionConfiguration.CacheType).In(excludedProperties)) + Assert.That(sessionConfiguration.CacheType, Is.EqualTo(SessionConfiguration.DefaultCacheType)); + + if (!nameof(sessionConfiguration.DefaultIsolationLevel).In(excludedProperties)) + Assert.That(sessionConfiguration.DefaultIsolationLevel, Is.EqualTo(SessionConfiguration.DefaultDefaultIsolationLevel)); + + if (!nameof(sessionConfiguration.DefaultCommandTimeout).In(excludedProperties)) + Assert.That(sessionConfiguration.DefaultCommandTimeout, Is.Null); + + if (!nameof(sessionConfiguration.BatchSize).In(excludedProperties)) + Assert.That(sessionConfiguration.BatchSize, Is.EqualTo(SessionConfiguration.DefaultBatchSize)); + + if (!nameof(sessionConfiguration.EntityChangeRegistrySize).In(excludedProperties)) + Assert.That(sessionConfiguration.EntityChangeRegistrySize, Is.EqualTo(SessionConfiguration.DefaultEntityChangeRegistrySize)); + + if (!nameof(sessionConfiguration.ReaderPreloading).In(excludedProperties)) + Assert.That(sessionConfiguration.ReaderPreloading, Is.EqualTo(SessionConfiguration.DefaultReaderPreloadingPolicy)); + + if (!nameof(sessionConfiguration.ServiceContainerType).In(excludedProperties)) + Assert.That(sessionConfiguration.ServiceContainerType, Is.Null); + + if (!nameof(sessionConfiguration.ConnectionInfo).In(excludedProperties)) + Assert.That(sessionConfiguration.ConnectionInfo, Is.Null); + } + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs b/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs index 1a0897981c..c33dee2c66 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs @@ -8,6 +8,7 @@ using System.Configuration; using System.Linq; using JetBrains.Annotations; +using Microsoft.Extensions.Configuration; using Xtensive.Core; using Xtensive.Orm.Configuration.Internals; using Xtensive.Orm.Internals; @@ -646,6 +647,9 @@ public TagsLocation TagsLocation /// public bool IsMultischema => isMultischema ?? GetIsMultischema(); + internal bool Supports(DomainOptions optionsToCheck) => (options & optionsToCheck) == optionsToCheck; + + internal bool Supports(ForeignKeyMode modeToCheck) => (foreignKeyMode & modeToCheck) == modeToCheck; private bool GetIsMultidatabase() { @@ -768,6 +772,8 @@ protected override void CopyFrom(ConfigurationBase source) /// The clone of this configuration. public new DomainConfiguration Clone() => (DomainConfiguration) base.Clone(); + #region Static DomainConfiguration.Load() methods + /// /// Loads the for /// with the specified @@ -847,11 +853,6 @@ public static DomainConfiguration Load(System.Configuration.Configuration config return LoadConfigurationFromSection(section, name); } - internal bool Supports(DomainOptions optionsToCheck) => (options & optionsToCheck) == optionsToCheck; - - internal bool Supports(ForeignKeyMode modeToCheck) => (foreignKeyMode & modeToCheck) == modeToCheck; - - private static DomainConfiguration LoadConfigurationFromSection(ConfigurationSection section, string name) { var domainElement = section.Domains[name]; @@ -862,6 +863,20 @@ private static DomainConfiguration LoadConfigurationFromSection(ConfigurationSec return domainElement.ToNative(); } + /// + /// Loads the for + /// with the specified . + /// + /// Root configuration section where domain configurations are placed + /// Name of the . + /// + /// The "domains" section is not found or domain with requested name is not found. + public static DomainConfiguration Load(IConfigurationSection configurationSection, string name) + { + throw new NotImplementedException(); + } + #endregion + // Constructors /// @@ -913,4 +928,4 @@ public DomainConfiguration() types.Register(WellKnownOrmTypes.Persistent.Assembly, WellKnownOrmTypes.Persistent.Namespace); } } -} +} \ No newline at end of file diff --git a/Orm/Xtensive.Orm/Xtensive.Orm.csproj b/Orm/Xtensive.Orm/Xtensive.Orm.csproj index 316508f708..666f8dfd63 100644 --- a/Orm/Xtensive.Orm/Xtensive.Orm.csproj +++ b/Orm/Xtensive.Orm/Xtensive.Orm.csproj @@ -1,4 +1,4 @@ - + true $(OutputPath)$(TargetFramework)\$(AssemblyName).xml @@ -51,9 +51,13 @@ + + + + From 3f6694240d594049e0d9057e2569b83e0ddbaade Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Wed, 28 Aug 2024 15:33:48 +0500 Subject: [PATCH 06/32] Summaries' improvements --- .../Configuration/DatabaseConfiguration.cs | 2 +- .../Orm/Configuration/DomainConfiguration.cs | 12 +++- .../Elements/DatabaseConfigurationElement.cs | 14 ++-- .../Elements/DomainConfigurationElement.cs | 72 +++++++++---------- .../Elements/IgnoreRuleElement.cs | 8 +-- .../KeyGeneratorConfigurationElement.cs | 14 ++-- .../Elements/MappingRuleElement.cs | 14 ++-- .../Elements/NamingConventionElement.cs | 14 ++-- .../Elements/SessionConfigurationElement.cs | 30 ++++---- .../Elements/VersioningConventionElement.cs | 10 +-- .../Orm/Configuration/SessionConfiguration.cs | 5 ++ 11 files changed, 104 insertions(+), 91 deletions(-) diff --git a/Orm/Xtensive.Orm/Orm/Configuration/DatabaseConfiguration.cs b/Orm/Xtensive.Orm/Orm/Configuration/DatabaseConfiguration.cs index 15deb1db86..83e0368494 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/DatabaseConfiguration.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/DatabaseConfiguration.cs @@ -52,7 +52,7 @@ public string RealName /// /// Gets or sets type ID minimal value /// for types mapped to this database. - /// Default value is 100. + /// Default value is . /// public int MinTypeId { diff --git a/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs b/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs index c33dee2c66..736c56d09b 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs @@ -68,7 +68,7 @@ public class DomainConfiguration : ConfigurationBase /// /// Default value: - /// + /// . /// public const bool DefaultShareStorageSchemaOverNodes = false; @@ -354,6 +354,7 @@ public ForeignKeyMode ForeignKeyMode /// /// Gets or sets a value indicating change tracking mode of full-text indexes. /// The property may have no effect for certain storages where there is no support for such option. + /// Default value is . /// public FullTextChangeTrackingMode FullTextChangeTrackingMode { @@ -590,7 +591,7 @@ public bool ShareStorageSchemaOverNodes } /// - /// Gets or sets versioning convention. + /// Gets or sets rules of entity versioning. /// public VersioningConvention VersioningConvention { @@ -603,6 +604,13 @@ public VersioningConvention VersioningConvention /// /// Enables extra check if connection is not broken on its opening. + /// For some RDBMSs physical connection may become broken but connection pool, which + /// is in charge of logical connections, is not aware of it. + /// In such cases connection pool provides connection + /// which is dead on arrival and causes exception on first use of it. + /// Such connection should be re-created and re-opened. The extra check + /// tests connection by making "first use" of it, if check failed connection + /// will be restored automatically. /// public bool EnsureConnectionIsAlive { diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Elements/DatabaseConfigurationElement.cs b/Orm/Xtensive.Orm/Orm/Configuration/Elements/DatabaseConfigurationElement.cs index 0e6fdafef0..487b8450a1 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Elements/DatabaseConfigurationElement.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Elements/DatabaseConfigurationElement.cs @@ -1,6 +1,6 @@ -// Copyright (C) 2012 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// Copyright (C) 2012-2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Denis Krjuchkov // Created: 2012.02.08 @@ -24,7 +24,7 @@ public class DatabaseConfigurationElement : ConfigurationCollectionElementBase public override object Identifier { get { return Name; } } /// - /// + /// /// [ConfigurationProperty(NameElementName, IsKey = true)] public string Name @@ -34,7 +34,7 @@ public string Name } /// - /// + /// /// [ConfigurationProperty(RealNameElementName)] public string RealName @@ -44,7 +44,7 @@ public string RealName } /// - /// + /// /// [ConfigurationProperty(MinTypeIdElementName, DefaultValue = TypeInfo.MinTypeId)] public int MinTypeId @@ -54,7 +54,7 @@ public int MinTypeId } /// - /// + /// /// [ConfigurationProperty(MaxTypeIdElementName, DefaultValue = int.MaxValue)] public int MaxTypeId diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Elements/DomainConfigurationElement.cs b/Orm/Xtensive.Orm/Orm/Configuration/Elements/DomainConfigurationElement.cs index 592699aed7..7837360145 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Elements/DomainConfigurationElement.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Elements/DomainConfigurationElement.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2008-2023 Xtensive LLC. +// Copyright (C) 2008-2024 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Aleksey Gamzov @@ -58,7 +58,7 @@ public class DomainConfigurationElement : ConfigurationCollectionElementBase public override object Identifier { get { return Name; } } /// - /// + /// /// [ConfigurationProperty(NameElementName, IsKey = true, DefaultValue = "")] public string Name @@ -68,7 +68,7 @@ public string Name } /// - /// + /// /// [ConfigurationProperty(ConnectionUrlElementName, DefaultValue = null)] public string ConnectionUrl @@ -78,7 +78,7 @@ public string ConnectionUrl } /// - /// + /// /// [ConfigurationProperty(ConnectionStringElementName, DefaultValue = null)] public string ConnectionString @@ -88,7 +88,7 @@ public string ConnectionString } /// - /// + /// /// [ConfigurationProperty(ProviderElementName, DefaultValue = WellKnown.Provider.SqlServer)] public string Provider @@ -98,7 +98,7 @@ public string Provider } /// - /// + /// /// [ConfigurationProperty(TypesElementName, IsDefaultCollection = false)] [ConfigurationCollection(typeof (ConfigurationCollection), AddItemName = "add")] @@ -108,7 +108,7 @@ public ConfigurationCollection Types } /// - /// + /// /// [ConfigurationProperty(NamingConventionElementName)] public NamingConventionElement NamingConvention @@ -118,7 +118,7 @@ public NamingConventionElement NamingConvention } /// - /// + /// /// [ConfigurationProperty(KeyCacheSizeElementName, DefaultValue = DomainConfiguration.DefaultKeyCacheSize)] [IntegerValidator(MinValue = 1, MaxValue = int.MaxValue)] @@ -129,7 +129,7 @@ public int KeyCacheSize } /// - /// + /// /// [ConfigurationProperty(KeyGeneratorCacheSizeElementName, DefaultValue = DomainConfiguration.DefaultKeyGeneratorCacheSize)] [IntegerValidator(MinValue = 1, MaxValue = int.MaxValue)] @@ -140,7 +140,7 @@ public int KeyGeneratorCacheSize } /// - /// + /// /// [ConfigurationProperty(QueryCacheSizeElementName, DefaultValue = DomainConfiguration.DefaultQueryCacheSize)] [IntegerValidator(MinValue = 1, MaxValue = int.MaxValue)] @@ -151,7 +151,7 @@ public int QueryCacheSize } /// - /// + /// /// [ConfigurationProperty(RecordSetMappingCacheSizeElementName, DefaultValue = DomainConfiguration.DefaultRecordSetMappingCacheSize)] [IntegerValidator(MinValue = 1, MaxValue = int.MaxValue)] @@ -162,7 +162,7 @@ public int RecordSetMappingCacheSize } /// - /// + /// /// [ConfigurationProperty(UpgradeModeElementName, DefaultValue = "Default")] public string UpgradeMode @@ -172,7 +172,7 @@ public string UpgradeMode } /// - /// + /// /// [ConfigurationProperty(SchemaSyncExceptionFormatElementName, DefaultValue = "Default")] public string SchemaSyncExceptionFormat @@ -182,7 +182,7 @@ public string SchemaSyncExceptionFormat } /// - /// + /// /// [ConfigurationProperty(ForeignKeyModeElementName, DefaultValue = "Default")] public string ForeignKeyMode @@ -192,7 +192,7 @@ public string ForeignKeyMode } /// - /// + /// /// [ConfigurationProperty(FullTextChangeTrackingModeElementName, DefaultValue = "Default")] public string FullTextChangeTrackingMode @@ -202,7 +202,7 @@ public string FullTextChangeTrackingMode } /// - /// + /// /// [ConfigurationProperty(CollationElementName)] public string Collation @@ -212,7 +212,7 @@ public string Collation } /// - /// + /// /// [ConfigurationProperty(SessionsElementName, IsDefaultCollection = false)] [ConfigurationCollection(typeof (ConfigurationCollection), AddItemName = "session")] @@ -222,7 +222,7 @@ public ConfigurationCollection Sessions } /// - /// + /// /// [ConfigurationProperty(MappingRulesElementName, IsDefaultCollection = false)] [ConfigurationCollection(typeof (ConfigurationCollection), AddItemName = "rule")] @@ -232,7 +232,7 @@ public ConfigurationCollection MappingRules } /// - /// + /// /// [ConfigurationProperty(DatabasesElementName, IsDefaultCollection = false)] [ConfigurationCollection(typeof (ConfigurationCollection), AddItemName = "database")] @@ -242,7 +242,7 @@ public ConfigurationCollection Databases } /// - /// + /// /// [ConfigurationProperty(KeyGeneratorsElementName, IsDefaultCollection = false)] [ConfigurationCollection(typeof (ConfigurationCollection), AddItemName = "keyGenerator")] @@ -252,7 +252,7 @@ public ConfigurationCollection KeyGenerators } /// - /// + /// /// [ConfigurationProperty(ServiceContainerTypeElementName, DefaultValue = null)] public string ServiceContainerType @@ -262,7 +262,7 @@ public string ServiceContainerType } /// - /// + /// /// [ConfigurationProperty(DefaultSchemaElementName)] public string DefaultSchema @@ -272,7 +272,7 @@ public string DefaultSchema } /// - /// + /// /// [ConfigurationProperty(DefaultDatabaseElementName)] public string DefaultDatabase @@ -282,7 +282,7 @@ public string DefaultDatabase } /// - /// + /// /// [ConfigurationProperty(IncludeSqlInExceptionsElementName, DefaultValue = DomainConfiguration.DefaultIncludeSqlInExceptions)] @@ -293,7 +293,7 @@ public bool IncludeSqlInExceptions } /// - /// + /// /// [ConfigurationProperty(AllowCyclicDatabaseDependenciesElementName, DefaultValue = DomainConfiguration.DefaultAllowCyclicDatabaseDependencies)] @@ -304,7 +304,7 @@ public bool AllowCyclicDatabaseDependencies } /// - /// + /// /// [ConfigurationProperty(BuildInParallelElementName, DefaultValue = DomainConfiguration.DefaultBuildInParallel)] @@ -315,7 +315,7 @@ public bool BuildInParallel } /// - /// + /// /// [ConfigurationProperty(ForcedServerVersionElementName)] public string ForcedServerVersion @@ -325,7 +325,7 @@ public string ForcedServerVersion } /// - /// + /// /// [ConfigurationProperty(ConnectionInitializationSqlElementName)] public string ConnectionInitializationSql @@ -335,7 +335,7 @@ public string ConnectionInitializationSql } /// - /// + /// /// [ConfigurationProperty(IgnoreRulesElementName, IsDefaultCollection = false)] [ConfigurationCollection(typeof (ConfigurationCollection), AddItemName = "rule")] @@ -345,7 +345,7 @@ public ConfigurationCollection IgnoreRules } /// - /// + /// /// [ConfigurationProperty(MultidatabaseKeysElementName, DefaultValue = DomainConfiguration.DefaultMultidatabaseKeys)] @@ -356,7 +356,7 @@ public bool MultidatabaseKeys } /// - /// + /// /// [ConfigurationProperty(OptionsElementName, DefaultValue = "Default")] public string Options @@ -366,7 +366,7 @@ public string Options } /// - /// + /// /// [ConfigurationProperty(ShareStorageSchemaOverNodesElementName, DefaultValue = false)] public bool ShareStorageSchemaOverNodes @@ -376,7 +376,7 @@ public bool ShareStorageSchemaOverNodes } /// - /// + /// /// [ConfigurationProperty(VersioningConventionElementName)] public VersioningConventionElement VersioningConvention @@ -386,7 +386,7 @@ public VersioningConventionElement VersioningConvention } /// - /// + /// /// [ConfigurationProperty(EnsureConnectionIsAliveElementName, DefaultValue = true)] public bool EnsureConnectionIsAlive @@ -396,7 +396,7 @@ public bool EnsureConnectionIsAlive } /// - /// . + /// . /// [ConfigurationProperty(TagsLocationElementName, DefaultValue = "Default")] public string TagsLocation @@ -406,7 +406,7 @@ public string TagsLocation } /// - /// + /// /// [ConfigurationProperty(PreferTypeIdsAsQueryParametersElementName, DefaultValue = true)] public bool PreferTypeIdsAsQueryParameters diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Elements/IgnoreRuleElement.cs b/Orm/Xtensive.Orm/Orm/Configuration/Elements/IgnoreRuleElement.cs index 583c2f1bb8..de43975349 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Elements/IgnoreRuleElement.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Elements/IgnoreRuleElement.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2013 Xtensive LLC. +// Copyright (C) 2013-2024 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Alexey Kulakov @@ -31,7 +31,7 @@ public class IgnoreRuleElement : ConfigurationCollectionElementBase Index ?? string.Empty); /// - /// + /// /// [ConfigurationProperty(DatabaseElementName)] public string Database @@ -41,7 +41,7 @@ public string Database } /// - /// + /// /// [ConfigurationProperty(SchemaElementName)] public string Schema @@ -51,7 +51,7 @@ public string Schema } /// - /// + /// /// [ConfigurationProperty(TableElementName)] public string Table diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Elements/KeyGeneratorConfigurationElement.cs b/Orm/Xtensive.Orm/Orm/Configuration/Elements/KeyGeneratorConfigurationElement.cs index c05b08e5a3..9c256bf689 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Elements/KeyGeneratorConfigurationElement.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Elements/KeyGeneratorConfigurationElement.cs @@ -1,6 +1,6 @@ -// Copyright (C) 2012 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// Copyright (C) 2012-2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Denis Krjuchkov // Created: 2012.03.28 @@ -25,7 +25,7 @@ public override object Identifier { } /// - /// + /// /// [ConfigurationProperty(NameElementName, IsKey = true)] public string Name @@ -35,7 +35,7 @@ public string Name } /// - /// + /// /// [ConfigurationProperty(DatabaseElementName, IsKey = true)] public string Database @@ -45,7 +45,7 @@ public string Database } /// - /// + /// /// [ConfigurationProperty(SeedElementName, DefaultValue = 0L)] public long Seed @@ -55,7 +55,7 @@ public long Seed } /// - /// + /// /// [ConfigurationProperty(CacheSizeElementName, DefaultValue = (long) DomainConfiguration.DefaultKeyGeneratorCacheSize)] public long CacheSize diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Elements/MappingRuleElement.cs b/Orm/Xtensive.Orm/Orm/Configuration/Elements/MappingRuleElement.cs index 22cc92471d..a2c00732cf 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Elements/MappingRuleElement.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Elements/MappingRuleElement.cs @@ -1,6 +1,6 @@ -// Copyright (C) 2012 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// Copyright (C) 2012-2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Denis Krjuchkov // Created: 2012.02.07 @@ -25,7 +25,7 @@ public override object Identifier { } /// - /// + /// /// [ConfigurationProperty(AssemblyElementName, IsKey = true)] public string Assembly @@ -35,7 +35,7 @@ public string Assembly } /// - /// + /// /// [ConfigurationProperty(NamespaceElementName, IsKey = true)] public string Namespace @@ -45,7 +45,7 @@ public string Namespace } /// - /// + /// /// [ConfigurationProperty(DatabaseElementName)] public string Database @@ -55,7 +55,7 @@ public string Database } /// - /// + /// /// [ConfigurationProperty(SchemaElementName)] public string Schema diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Elements/NamingConventionElement.cs b/Orm/Xtensive.Orm/Orm/Configuration/Elements/NamingConventionElement.cs index 4e891a8f42..3c3c84670e 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Elements/NamingConventionElement.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Elements/NamingConventionElement.cs @@ -1,6 +1,6 @@ -// Copyright (C) 2003-2010 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// Copyright (C) 2008-2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Alexey Gamzov // Created: 2008.08.07 @@ -21,7 +21,7 @@ public class NamingConventionElement : ConfigurationElement private const string NamespaceSynonymsElementName = "namespaceSynonyms"; /// - /// + /// /// [ConfigurationProperty(LetterCasePolicyElementName, IsRequired = false, IsKey = false, DefaultValue = "Default")] public string LetterCasePolicy @@ -31,7 +31,7 @@ public string LetterCasePolicy } /// - /// + /// /// [ConfigurationProperty(NamespacePolicyElementName, IsRequired = false, IsKey = false, DefaultValue = "Default")] public string NamespacePolicy @@ -41,7 +41,7 @@ public string NamespacePolicy } /// - /// + /// /// [ConfigurationProperty(NamingRulesElementName, IsRequired = false, IsKey = false, DefaultValue = "Default")] public string NamingRules @@ -51,7 +51,7 @@ public string NamingRules } /// - /// + /// /// [ConfigurationProperty(NamespaceSynonymsElementName, IsRequired = false, IsKey = false)] [ConfigurationCollection(typeof (ConfigurationCollection), AddItemName = "synonym")] diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Elements/SessionConfigurationElement.cs b/Orm/Xtensive.Orm/Orm/Configuration/Elements/SessionConfigurationElement.cs index e8e07ca938..1aaa1b7c05 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Elements/SessionConfigurationElement.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Elements/SessionConfigurationElement.cs @@ -1,6 +1,6 @@ -// Copyright (C) 2003-2010 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// Copyright (C) 2008-2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Aleksey Gamzov // Created: 2008.08.11 @@ -37,7 +37,7 @@ public class SessionConfigurationElement : ConfigurationCollectionElementBase public override object Identifier { get { return Name; } } /// - /// + /// /// [ConfigurationProperty(NameElementName, IsKey = true, DefaultValue = "Default")] public string Name { @@ -46,7 +46,7 @@ public string Name { } /// - /// + /// /// [ConfigurationProperty(UserNameElementName)] public string UserName { @@ -55,7 +55,7 @@ public string UserName { } /// - /// + /// /// [ConfigurationProperty(PasswordElementName)] public string Password { @@ -64,7 +64,7 @@ public string Password { } /// - /// + /// /// [ConfigurationProperty(CacheSizeElementName, DefaultValue = SessionConfiguration.DefaultCacheSize)] @@ -75,7 +75,7 @@ public int CacheSize { } /// - /// + /// /// [ConfigurationProperty(CacheTypeElementName, DefaultValue = "Default")] public string CacheType { @@ -84,7 +84,7 @@ public string CacheType { } /// - /// + /// /// [ConfigurationProperty(OptionsElementName, DefaultValue = "Default")] public string Options { @@ -93,7 +93,7 @@ public string Options { } /// - /// + /// /// [ConfigurationProperty(IsolationLevelElementName, DefaultValue = "RepeatableRead")] public string DefaultIsolationLevel { @@ -102,7 +102,7 @@ public string DefaultIsolationLevel { } /// - /// + /// /// [ConfigurationProperty(CommandTimeoutElementName, DefaultValue = null)] public int? DefaultCommandTimeout { @@ -111,7 +111,7 @@ public int? DefaultCommandTimeout { } /// - /// + /// /// [ConfigurationProperty(BatchSizeElementName, DefaultValue = SessionConfiguration.DefaultBatchSize)] @@ -122,7 +122,7 @@ public int BatchSize { } /// - /// + /// /// [ConfigurationProperty(ReaderPreloadingElementName, DefaultValue = "Default")] public string ReaderPreloading { @@ -131,7 +131,7 @@ public string ReaderPreloading { } /// - /// + /// /// [ConfigurationProperty(ServiceContainerTypeElementName, DefaultValue = null)] public string ServiceContainerType { @@ -140,7 +140,7 @@ public string ServiceContainerType { } /// - /// . + /// . /// [ConfigurationProperty(EntityChangeRegistrySizeElementName, DefaultValue = SessionConfiguration.DefaultEntityChangeRegistrySize)] diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Elements/VersioningConventionElement.cs b/Orm/Xtensive.Orm/Orm/Configuration/Elements/VersioningConventionElement.cs index 7cb63e06c3..ca4021dd89 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Elements/VersioningConventionElement.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Elements/VersioningConventionElement.cs @@ -1,6 +1,6 @@ -// Copyright (C) 2018 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// Copyright (C) 2018-2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Alexey Kulakov // Created: 2018.03.14 @@ -15,7 +15,7 @@ public sealed class VersioningConventionElement : ConfigurationElement private const string DenyEntitySetOwnerVersionChangeElementName = "denyEntitySetOwnerVersionChange"; /// - /// + /// /// [ConfigurationProperty(EntityVersioningPolicyElementName, IsRequired = false, IsKey = false, DefaultValue = "Default")] public string EntityVersioningPolicy @@ -25,7 +25,7 @@ public string EntityVersioningPolicy } /// - /// + /// /// [ConfigurationProperty(DenyEntitySetOwnerVersionChangeElementName, IsRequired = false, IsKey = false, DefaultValue = false)] public bool DenyEntitySetOwnerVersionChange diff --git a/Orm/Xtensive.Orm/Orm/Configuration/SessionConfiguration.cs b/Orm/Xtensive.Orm/Orm/Configuration/SessionConfiguration.cs index 3f142a90d2..e593097f5d 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/SessionConfiguration.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/SessionConfiguration.cs @@ -118,6 +118,7 @@ public int CacheSize { /// /// Gets or sets the type of the session cache. + /// Default value is . /// public SessionCacheType CacheType { get { return cacheType; } @@ -160,6 +161,7 @@ public int? DefaultCommandTimeout { /// /// Gets or sets the size of the batch. /// This affects create, update, delete operations and future queries. + /// Default value is . /// public int BatchSize { get { return batchSize; } @@ -183,6 +185,8 @@ public SessionOptions Options { /// /// Gets or sets the reader preloading policy. + /// It affects query results reading. + /// Default value is . /// public ReaderPreloadingPolicy ReaderPreloading { @@ -195,6 +199,7 @@ public ReaderPreloadingPolicy ReaderPreloading /// /// Gets or sets the size of the entity change registry. + /// Default value is . /// public int EntityChangeRegistrySize { From 29991390678f126368c8e6a0125ab1f6893c9712 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 29 Aug 2024 08:58:01 +0500 Subject: [PATCH 07/32] Add XxxOptions for reading configuration --- .../Configuration/Options/DatabaseOptions.cs | 69 ++++ .../Options/DomainConfigurationOptions.cs | 319 ++++++++++++++++++ .../Options/IgnoreRuleOptions.cs | 60 ++++ .../Interfaces/IIdentifyableOptions.cs | 32 ++ .../INamedOptionsCollectionElement.cs | 16 + .../Interfaces/IOptionsCollectionElement.cs | 13 + .../Interfaces/IToNativeConvertable.cs | 17 + .../Options/KeyGeneratorOptions.cs | 75 ++++ .../Options/MappingRuleOptions.cs | 59 ++++ .../Options/NamedOptionsCollection{T}.cs | 128 +++++++ .../Options/NamespaceSynonymOptions.cs | 19 ++ .../Options/NamingConventionOptions.cs | 54 +++ .../Options/OptionsCollection{T}.cs | 108 ++++++ .../Options/SessionConfigurationOptions.cs | 145 ++++++++ .../Options/TypeRegistrationOptions.cs | 72 ++++ .../Options/VersioningConventionOptions.cs | 31 ++ 16 files changed, 1217 insertions(+) create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Options/DatabaseOptions.cs create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Options/DomainConfigurationOptions.cs create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Options/IgnoreRuleOptions.cs create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IIdentifyableOptions.cs create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/INamedOptionsCollectionElement.cs create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IOptionsCollectionElement.cs create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IToNativeConvertable.cs create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Options/KeyGeneratorOptions.cs create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Options/MappingRuleOptions.cs create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Options/NamedOptionsCollection{T}.cs create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Options/NamespaceSynonymOptions.cs create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Options/NamingConventionOptions.cs create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Options/OptionsCollection{T}.cs create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Options/SessionConfigurationOptions.cs create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Options/TypeRegistrationOptions.cs create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Options/VersioningConventionOptions.cs diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/DatabaseOptions.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/DatabaseOptions.cs new file mode 100644 index 0000000000..e609e57754 --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/DatabaseOptions.cs @@ -0,0 +1,69 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System; +using Xtensive.Core; +using Xtensive.Orm.Model; + +namespace Xtensive.Orm.Configuration.Options +{ + internal sealed class DatabaseOptions : IIdentifyableOptions, + IValidatableOptions, + IToNativeConvertable, + INamedOptionsCollectionElement + { + public object Identifier => Name; + + /// + /// Logical database name. + /// + public string Name { get; set; } + + /// + /// Physical database name. + /// + public string RealName { get; set; } + + /// + /// Type ID minimal value + /// for types mapped to this database. + /// Default value is . + /// + public int MinTypeId { get; set; } = TypeInfo.MinTypeId; + + /// + /// Type ID maximal value + /// for types mapped to this database. + /// Default value is . + /// + public int MaxTypeId { get; set; } = int.MaxValue; + + /// + /// is empty or null. + /// or is not in valid range. + public void Validate() + { + if (Name.IsNullOrEmpty()) + throw new ArgumentException(Strings.ExArgumentCannotBeEmptyString,"Name"); + if (MinTypeId < TypeInfo.MinTypeId) + throw new ArgumentOutOfRangeException("MinTypeId", MinTypeId, + string.Format(Strings.ExArgumentMustBeGreaterThatOrEqualX, TypeInfo.MinTypeId)); + if (MaxTypeId < TypeInfo.MinTypeId) + throw new ArgumentOutOfRangeException("MaxTypeId", MinTypeId, + string.Format(Strings.ExArgumentMustBeGreaterThatOrEqualX, TypeInfo.MinTypeId)); + } + + /// + public DatabaseConfiguration ToNative() + { + Validate(); + + return new DatabaseConfiguration(Name) { + RealName = RealName, + MinTypeId = MinTypeId, + MaxTypeId = MaxTypeId, + }; + } + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/DomainConfigurationOptions.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/DomainConfigurationOptions.cs new file mode 100644 index 0000000000..b2a3769c51 --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/DomainConfigurationOptions.cs @@ -0,0 +1,319 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System; +using System.Collections.Generic; +using Xtensive.Core; + +namespace Xtensive.Orm.Configuration.Options +{ + internal sealed class DomainConfigurationOptions + { + /// + /// Domain configuration name. + /// + public string Name { get; set; } = string.Empty; + + /// + /// Url that will be used in . + /// + public string ConnectionUrl { get; set; } = null; + + /// + /// Connection string that will be used in . + /// + public string ConnectionString { get; set; } = null; + + /// + /// Provider that will be used in . + /// + public string Provider { get; set; } = WellKnown.Provider.SqlServer; + + /// + /// Types tha are about to be registered in . + /// + public TypeRegistrationOptions[] Types { get; set; } = Array.Empty(); + + /// + /// Size of the key cache. Default value is + /// + public int KeyCacheSize { get; set; } = DomainConfiguration.DefaultKeyCacheSize; + + /// + /// Size of the key generator cache size. + /// Default value is + /// + public int KeyGeneratorCacheSize { get; set; } = DomainConfiguration.DefaultKeyGeneratorCacheSize; + + /// + /// Size of the query cache (see ). + /// Default value is . + /// + public int QueryCacheSize { get; set; } = DomainConfiguration.DefaultQueryCacheSize; + + /// + /// Size of the record set mapping cache. + /// Default value is . + /// + public int RecordSetMappingCacheSize { get; set; } = DomainConfiguration.DefaultRecordSetMappingCacheSize; + + /// + /// Domain upgrade behavior. + /// + public DomainUpgradeMode UpgradeMode { get; set; } = DomainConfiguration.DefaultUpgradeMode; + + /// + /// format. + /// + public SchemaSyncExceptionFormat SchemaSyncExceptionFormat { get; set; } = DomainConfiguration.DefaultSchemaSyncExceptionFormat; + + /// + /// Foreign key mode. + /// Default value is . + /// + public ForeignKeyMode ForeignKeyMode { get; set; } = DomainConfiguration.DefaultForeignKeyMode; + + /// + /// Change tracking mode of full-text indexes. + /// Default value is . + /// + public FullTextChangeTrackingMode FullTextChangeTrackingMode { get; set; } = DomainConfiguration.DefaultFullTextChangeTrackingMode; + + /// + /// Collation for all columns. See for details. + /// + public string Collation { get; set; } = string.Empty; + + /// + /// Session configurations. + /// + public SessionOptionsCollection Sessions { get; set; } = new SessionOptionsCollection(); + + /// + /// Registered mapping rules. + /// + public MappingRuleOptionsCollection MappingRules { get; set; } = new MappingRuleOptionsCollection(); + + /// + /// Registered ignore rules. + /// + public IgnoreRuleOptionsCollection IgnoreRules { get; set; } = new IgnoreRuleOptionsCollection(); + + /// + /// Registered database aliases. + /// + public DatabaseOptionsCollection Databases { get; set; } = new DatabaseOptionsCollection(); + + /// + /// Key generators. + /// + public KeyGeneratorOptionsCollection KeyGenerators {get; set;} = new KeyGeneratorOptionsCollection(); + + /// + /// Type of service container + /// + public string ServiceContainerType { get; set; } = null; + + /// + /// Default schema. + /// + public string DefaultSchema { get; set; } = string.Empty; + + /// + /// Default database. + /// + public string DefaultDatabase { get; set; } = string.Empty; + + + /// + /// Value indicating whether SQL should be included in exception messages. + /// Default value is + /// + public bool IncludeSqlInExceptions { get; set; } = DomainConfiguration.DefaultIncludeSqlInExceptions; + + /// + /// Value indicating whether cyclic database dependencied are allowed. + /// Default value is + /// + public bool AllowCyclicDatabaseDependencies { get; set; } = DomainConfiguration.DefaultAllowCyclicDatabaseDependencies; + + /// + /// Value indicating whether parallel build should be used where and if it is possible. + /// Default value is + /// + public bool BuildInParallel { get; set; } = DomainConfiguration.DefaultBuildInParallel; + + /// + /// Value indicating whether multidatabase keys should be used. + /// Default value is + /// + public bool MultidatabaseKeys { get; set; } = DomainConfiguration.DefaultMultidatabaseKeys; + + /// + /// Value indicating whether same storage schema is shared across s. + /// Default value is + /// + public bool ShareStorageSchemaOverNodes { get; set; } = DomainConfiguration.DefaultShareStorageSchemaOverNodes; + + /// + /// Enables extra check if connection is not broken on its opening. + /// + public bool EnsureConnectionIsAlive { get; set; } = DomainConfiguration.DefaultEnsureConnectionIsAlive; + + /// + /// Makes queries use parameters instead of constant values for persistent type identifiers. + /// + public bool PreferTypeIdsAsQueryParameters { get; set; } = DomainConfiguration.DefaultPreferTypeIdsAsQueryParameters; + + /// + /// Forced server version. + /// + public string ForcedServerVersion { get; set; } = string.Empty; + + /// + /// Connection initialization SQL script. + /// + public string ConnectionInitializationSql { get; set; } = string.Empty; + + /// + /// Domain options + /// + public DomainOptions Options { get; set; } = DomainConfiguration.DefaultDomainOptions; + + /// + /// Naming convention. + /// + public NamingConventionOptions NamingConventionRaw { get; internal set; } = null; + + /// + /// Versioning convention. + /// + public VersioningConventionOptions VersioningConvention { get; set; } = null; + + /// + /// Defines tags location within query or turn them off if is set. + /// + public TagsLocation TagsLocation { get; set; } = DomainConfiguration.DefaultTagLocation; + + /// + /// + /// + /// + /// + /// + /// + /// + public DomainConfiguration ToNative(IDictionary connectionStrings) + { + var config = new DomainConfiguration { + Name = Name, + ConnectionInfo = ConnectionInfoParser.GetConnectionInfo(connectionStrings, + ConnectionUrl, Provider, ConnectionString), + KeyCacheSize = KeyCacheSize, + KeyGeneratorCacheSize = KeyGeneratorCacheSize, + QueryCacheSize = QueryCacheSize, + RecordSetMappingCacheSize = RecordSetMappingCacheSize, + DefaultSchema = DefaultSchema, + DefaultDatabase = DefaultDatabase, + UpgradeMode = UpgradeMode, + ForeignKeyMode = ForeignKeyMode, + SchemaSyncExceptionFormat = SchemaSyncExceptionFormat, + Options = Options, + ServiceContainerType = !ServiceContainerType.IsNullOrEmpty() ? Type.GetType(ServiceContainerType) : null, + IncludeSqlInExceptions = IncludeSqlInExceptions, + BuildInParallel = BuildInParallel, + AllowCyclicDatabaseDependencies = AllowCyclicDatabaseDependencies, + ForcedServerVersion = ForcedServerVersion, + Collation = Collation, + ConnectionInitializationSql = ConnectionInitializationSql, + MultidatabaseKeys = MultidatabaseKeys, + ShareStorageSchemaOverNodes = ShareStorageSchemaOverNodes, + EnsureConnectionIsAlive = EnsureConnectionIsAlive, + PreferTypeIdsAsQueryParameters = PreferTypeIdsAsQueryParameters, + FullTextChangeTrackingMode = FullTextChangeTrackingMode, + TagsLocation = TagsLocation, + }; + + if (NamingConventionRaw != null) + config.NamingConvention = NamingConventionRaw.ToNative(); + if (VersioningConvention != null) + config.VersioningConvention = VersioningConvention.ToNative(); + + foreach (var element in Types) { + _ = config.Types.Register(element.ToNative()); + } + HashSet uniqueElements; + if (Databases.AnyExceptionOccur) { + var exceptions = Databases.Exceptions; + if (exceptions.Count == 1) + throw exceptions[0]; + throw new System.AggregateException(Strings.ExASetOfExceptionsIsCaught + " during reading 'Databases' section of configuration", exceptions.ToArray()); + } + else if (Databases.Count > 0) { + foreach (var element in Databases) { + config.Databases.Add(element.Value.ToNative()); + } + } + + if (KeyGenerators.AnyExceptionOccur) { + var exceptions = KeyGenerators.Exceptions; + if (exceptions.Count == 1) + throw exceptions[0]; + throw new System.AggregateException(Strings.ExASetOfExceptionsIsCaught + " during reading 'KeyGenerators' section of configuration", exceptions.ToArray()); + } + else if (KeyGenerators.Count > 0) { + uniqueElements = new HashSet(); + foreach (var element in KeyGenerators) { + //resolves cases when alias and database was used which provides different indetifiers but database conflict exists + var identifier = element.GetMappedIdentifier(Databases); + if (!uniqueElements.Add(identifier)) + throw new ArgumentException($"Key generator with name '{element.Name}' for database '{element.Database}' has already been declared."); + + config.KeyGenerators.Add(element.ToNative()); + } + } + if (IgnoreRules.AnyExceptionOccur) { + var exceptions = IgnoreRules.Exceptions; + if (exceptions.Count==1) + throw exceptions[0]; + throw new System.AggregateException("Set of exceptions occured during reading 'IgnoreRules' section of configuration", exceptions.ToArray()); + } + else if (IgnoreRules.Count > 0) { + uniqueElements = new HashSet(); + foreach (var element in IgnoreRules) { + var identifier = element.GetMappedIdentifier(Databases); + if (!uniqueElements.Add(identifier)) + throw new Exception("Ignore rule with same set of properties has already been declared."); + config.IgnoreRules.Add(element.ToNative()); + } + } + + if (MappingRules.AnyExceptionOccur) { + var exceptions = MappingRules.Exceptions; + if (exceptions.Count == 1) + throw exceptions[0]; + throw new System.AggregateException("Set of exceptions occured during reading 'MappingRules' section of configuration", exceptions.ToArray()); + } + else if (MappingRules.Count > 0) { + foreach (var element in MappingRules) { + config.MappingRules.Add(element.ToNative()); + } + } + + foreach (var element in Sessions) + config.Sessions.Add(element.Value.ToNative(connectionStrings)); + + return config; + } + + private static T ParseEnum(string value) + where T : struct + { + if (!Enum.TryParse(value, true, out var result)) { + throw new ArgumentException($"Can't parse given value '{value}' to enum type '{typeof(T).FullName}'"); + } + return result; + } + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/IgnoreRuleOptions.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/IgnoreRuleOptions.cs new file mode 100644 index 0000000000..02d1b5d168 --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/IgnoreRuleOptions.cs @@ -0,0 +1,60 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System; +using System.Collections.Generic; +using Xtensive.Core; + +namespace Xtensive.Orm.Configuration.Options +{ + internal sealed class IgnoreRuleOptions : IIdentifyableOptions, + IHasDatabaseOption, + IValidatableOptions, + IToNativeConvertable + { + public object Identifier => + (Database ?? string.Empty, + Schema ?? string.Empty, + Table ?? string.Empty, + Column ?? string.Empty, + Index ?? string.Empty); + + public string Database { get; set; } + public string Schema { get; set; } + public string Table { get; set; } + public string Column { get; set; } + public string Index { get; set; } + + /// + /// Configuration of properties is not valid, e.g. + /// none of Table, Column and Index filled, or both Column and Index filled. + public void Validate() + { + if (Table.IsNullOrEmpty() && Column.IsNullOrEmpty() && Index.IsNullOrEmpty()) { + throw new ArgumentException("Ignore rule should be configured for at least column, index or table"); + } + if (!Column.IsNullOrEmpty() && !Index.IsNullOrEmpty()) { + throw new ArgumentException("Ignore rule can't be configured for column and index at the same time"); + } + } + + public object GetMappedIdentifier(IDictionary databaseMap) + { + if (!Database.IsNullOrEmpty() && databaseMap.TryGetValue(Database, out var map) && !map.RealName.IsNullOrEmpty()) { + return (map.RealName, Schema ?? string.Empty, Table ?? string.Empty, Column ?? string.Empty, Index ?? string.Empty); + } + return Identifier; + } + + /// + public IgnoreRule ToNative() + { + Validate(); + + return new IgnoreRule(Database, Schema, Table, Column, Index); + } + + + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IIdentifyableOptions.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IIdentifyableOptions.cs new file mode 100644 index 0000000000..e665d94eb8 --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IIdentifyableOptions.cs @@ -0,0 +1,32 @@ +// Copyright (C) 2007-2022 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. +// Created by: Dmitri Maximov +// Created: 2007.08.03 + +using System; +using System.Collections.Generic; + +namespace Xtensive.Orm.Configuration.Options +{ + internal interface IIdentifyableOptions + { + object Identifier { get; } + } + + internal interface IValidatableOptions + { + /// + /// Performs validation of properties + /// + void Validate(); + } + + internal interface IHasDatabaseOption : IIdentifyableOptions + { + string Database { get; set; } + + object GetMappedIdentifier(IDictionary databaseMap); + } + +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/INamedOptionsCollectionElement.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/INamedOptionsCollectionElement.cs new file mode 100644 index 0000000000..5f02e3d7af --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/INamedOptionsCollectionElement.cs @@ -0,0 +1,16 @@ +// Copyright (C) 2007-2022 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. +// Created by: Dmitri Maximov +// Created: 2007.08.03 + +namespace Xtensive.Orm.Configuration.Options +{ + /// + /// Defines options where name is key of collection + /// + internal interface INamedOptionsCollectionElement + { + string Name { get; set; } + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IOptionsCollectionElement.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IOptionsCollectionElement.cs new file mode 100644 index 0000000000..1ebdf74bcb --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IOptionsCollectionElement.cs @@ -0,0 +1,13 @@ +// Copyright (C) 2007-2022 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. +// Created by: Dmitri Maximov +// Created: 2007.08.03 + +namespace Xtensive.Orm.Configuration.Options +{ + internal interface IOptionsCollectionElement + { + + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IToNativeConvertable.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IToNativeConvertable.cs new file mode 100644 index 0000000000..8ad5b978a2 --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IToNativeConvertable.cs @@ -0,0 +1,17 @@ +// Copyright (C) 2007-2022 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. +// Created by: Dmitri Maximov +// Created: 2007.08.03 + +namespace Xtensive.Orm.Configuration.Options +{ + internal interface IToNativeConvertable + { + /// + /// Converts element of options pattern to native configuration it corresponds to () + /// + /// instance. + TNative ToNative(); + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/KeyGeneratorOptions.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/KeyGeneratorOptions.cs new file mode 100644 index 0000000000..21c8e9a428 --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/KeyGeneratorOptions.cs @@ -0,0 +1,75 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System; +using System.Collections.Generic; +using Xtensive.Core; + +namespace Xtensive.Orm.Configuration.Options +{ + internal sealed class KeyGeneratorOptions : IIdentifyableOptions, + IValidatableOptions, + IHasDatabaseOption, + IToNativeConvertable + { + public object Identifier => (Name ?? string.Empty, Database ?? string.Empty); + + /// + /// Key generator name. + /// + public string Name { get; set; } + + /// + /// Database for key generator + /// + public string Database { get; set; } + + /// + /// Seed (initial value) for key generator. + /// + public long Seed { get; set; } = 0L; + + /// + /// Cache size (increment) for cache generator. + /// + public long CacheSize { get; set; } = DomainConfiguration.DefaultKeyGeneratorCacheSize; + + public object GetMappedIdentifier(IDictionary databaseMap) + { + if (!Database.IsNullOrEmpty() && databaseMap.TryGetValue(Database, out var map) && !map.RealName.IsNullOrEmpty()) { + return(Name ?? string.Empty, map.RealName); + } + return Identifier; + } + + /// + /// Name is null or empty. + /// Seed or CacheSize value is out of valid range. + public void Validate() + { + if (Name.IsNullOrEmpty()) { + throw new ArgumentException("Key generator should have not empty name."); + } + if (Seed < 0) { + throw new ArgumentOutOfRangeException("Key generator seed must be non-negative value"); + } + if (CacheSize <= 0) { + throw new ArgumentOutOfRangeException("Key generator cache size must be positive value"); + } + } + + /// + public KeyGeneratorConfiguration ToNative() + { + Validate(); + + return new KeyGeneratorConfiguration(Name) { + CacheSize = CacheSize, + Seed = Seed, + Database = Database, + }; + } + + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/MappingRuleOptions.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/MappingRuleOptions.cs new file mode 100644 index 0000000000..fe9cc1125f --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/MappingRuleOptions.cs @@ -0,0 +1,59 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System; +using Xtensive.Core; + +namespace Xtensive.Orm.Configuration.Options +{ + internal sealed class MappingRuleOptions : IIdentifyableOptions, + IValidatableOptions, + IToNativeConvertable + { + public object Identifier => (Assembly ?? string.Empty, Namespace ?? string.Empty); + + /// + /// Assembly condition. + /// See for details. + /// + public string Assembly { get; set; } + + /// + /// Namespace condition. + /// See for details. + /// + public string Namespace { get; set; } + + /// + /// Database that is assigned to mapped type when this rule is applied. + /// See for details. + /// + public string Database { get; set; } + + /// + /// Schema that is assigned to mapped type when this rule is applied. + /// See for details. + /// + public string Schema { get; set; } + + /// + /// Configuration of values in properties is not valid. + public void Validate() + { + if (Assembly.IsNullOrEmpty() && Namespace.IsNullOrEmpty()) + throw new ArgumentException("Mapping rule should declare at least either Assembly or Namespace"); + if (Database.IsNullOrEmpty() && Schema.IsNullOrEmpty()) + throw new ArgumentException("Mapping rule should map assembly and(or) namespace to database, schema or both"); + } + + /// + public MappingRule ToNative() + { + Validate(); + + var assembly = !string.IsNullOrEmpty(Assembly) ? System.Reflection.Assembly.Load(Assembly) : null; + return new MappingRule(assembly, Namespace, Database, Schema); + } + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/NamedOptionsCollection{T}.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/NamedOptionsCollection{T}.cs new file mode 100644 index 0000000000..342a601402 --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/NamedOptionsCollection{T}.cs @@ -0,0 +1,128 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Xtensive.Core; + +namespace Xtensive.Orm.Configuration.Options +{ + internal sealed class SessionOptionsCollection : NamedOptionsCollection + { + protected override bool AllowEmptyNames => true; + } + + internal sealed class DatabaseOptionsCollection : NamedOptionsCollection + { + + } + + internal abstract class NamedOptionsCollection : IDictionary + where T: INamedOptionsCollectionElement + { + private readonly Dictionary internalDictionary = new(); + private readonly List exceptionsOccur = new(); + + public T this[string key] + { + get => internalDictionary[key]; + set { + + if (!internalDictionary.ContainsKey(key)) { + Add(key, value); + } + else { + ValidateName(key); + value.Name = key; + ValidateItemOnAdd(value); + internalDictionary[key] = value; + } + } + } + + public ICollection Keys => internalDictionary.Keys; + + public ICollection Values => internalDictionary.Values; + + public int Count => internalDictionary.Count; + + protected virtual bool AllowEmptyNames => false; + + internal bool AnyExceptionOccur => exceptionsOccur.Any(); + + // Section to object materialisation "swollows" exceptions, + // which means we will get partially populated collections + // without even knowing that something went wrong. + // This collection of exceptions helps to understand whether + // the collection populated without an issues or not. + internal List Exceptions => exceptionsOccur; + + public void Add(string name, T value) + { + ValidateName(name); + + if (value == null) { + throw new ArgumentNullException(nameof(value)); + } + value.Name = name; + + if (!internalDictionary.TryAdd(name, value)) { + throw new ArgumentException(string.Format(Strings.ExItemWithNameXAlreadyExists, name)); + } + } + + public void Clear() => internalDictionary.Clear(); + + public bool ContainsKey(string key) => internalDictionary.ContainsKey(key); + public IEnumerator> GetEnumerator() => ((ICollection>) internalDictionary).GetEnumerator(); + public bool Remove(string key) => internalDictionary.Remove(key); + public bool TryGetValue(string key, [MaybeNullWhen(false)] out T value) => internalDictionary.TryGetValue(key, out value); + + + protected virtual void ValidateItemOnAdd(T item) + { + if (item is IValidatableOptions validatableOptions) { + validatableOptions.Validate(); + } + } + + protected Exception RegisterValidationException(Exception exception) + { + exceptionsOccur.Add(exception); + return exception; + } + + private void ValidateName(string name) + { + if (!AllowEmptyNames && name.IsNullOrEmpty()) { + throw RegisterValidationException((name == null) + ? new ArgumentNullException(nameof(name)) + : new ArgumentException(Strings.ExArgumentCannotBeEmptyString, nameof(name))); + } + else { + if (name == null) { + throw RegisterValidationException(new ArgumentNullException(nameof(name))); + } + } + } + + bool ICollection>.IsReadOnly => ((ICollection>) internalDictionary).IsReadOnly; + void ICollection>.Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) => + ((IDictionary) internalDictionary).CopyTo(array, arrayIndex); + bool ICollection>.Contains(KeyValuePair item) => + ((IDictionary) internalDictionary).Contains(item); + bool ICollection>.Remove(KeyValuePair item) => + ((IDictionary) internalDictionary).Remove(item); + + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/NamespaceSynonymOptions.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/NamespaceSynonymOptions.cs new file mode 100644 index 0000000000..95917fb24b --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/NamespaceSynonymOptions.cs @@ -0,0 +1,19 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +namespace Xtensive.Orm.Configuration.Options +{ + internal sealed class NamespaceSynonymOptions + { + /// + /// Namespace to synonymize. + /// + public string Namespace { get; set; } + + /// + /// Synonym of namespace. + /// + public string Synonym { get; set; } + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/NamingConventionOptions.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/NamingConventionOptions.cs new file mode 100644 index 0000000000..9aba88ebdd --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/NamingConventionOptions.cs @@ -0,0 +1,54 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using Xtensive.Core; + +namespace Xtensive.Orm.Configuration.Options +{ + internal sealed class NamingConventionOptions : IToNativeConvertable + { + /// + /// Letter case policy. + /// + public LetterCasePolicy LetterCasePolicy { get; set; } = NamingConvention.DefaultLetterCasePolicy; + + /// + /// Namespace policy. + /// + public NamespacePolicy NamespacePolicy { get; set; } = NamingConvention.DefaultNamespacePolicy; + + /// + /// Rules of naming. + /// + public NamingRules NamingRules { get; set; } = NamingConvention.DefaultNamingRules; + + /// + /// Collection of namespace synonyms. + /// + public NamespaceSynonymOptions[] NamespaceSynonyms { get; set; } + + /// + public NamingConvention ToNative() + { + var result = new NamingConvention { + LetterCasePolicy = LetterCasePolicy, + NamespacePolicy = NamespacePolicy, + NamingRules = NamingRules, + }; + + foreach (var namespaceSynonym in NamespaceSynonyms) { + if (namespaceSynonym.Namespace.IsNullOrEmpty()) { + ArgumentValidator.EnsureArgumentNotNullOrEmpty(namespaceSynonym.Namespace, namespaceSynonym.Namespace); + } + if (!result.NamespaceSynonyms.TryAdd(namespaceSynonym.Namespace, namespaceSynonym.Synonym)) { + throw new Exception($"Synonym for namespace '{namespaceSynonym.Namespace}' has already been assigned."); + } + } + return result; + } + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/OptionsCollection{T}.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/OptionsCollection{T}.cs new file mode 100644 index 0000000000..a8bd0d8bc3 --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/OptionsCollection{T}.cs @@ -0,0 +1,108 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Xtensive.Core; + +namespace Xtensive.Orm.Configuration.Options +{ + internal sealed class MappingRuleOptionsCollection : OptionsCollection + { + } + + internal sealed class IgnoreRuleOptionsCollection : OptionsCollection + { + } + + internal sealed class KeyGeneratorOptionsCollection : OptionsCollection + { + } + + internal abstract class OptionsCollection : ICollection + where T : class, IIdentifyableOptions + { + private readonly Dictionary map = new(); + private readonly List exceptionsOccur = new(); + + public int Count => map.Count; + + public bool IsReadOnly => false; + + internal bool AnyExceptionOccur => exceptionsOccur.Any(); + + // Section to object materialisation "swollows" exceptions, + // which means we will get partially populated collections + // without even knowing that something went wrong. + // This collection of exceptions helps to understand whether + // the collection populated without an issues or not. + internal List Exceptions => exceptionsOccur; + + public void Add(T item) + { + if (item == null) { + throw RegisterValidationException(new ArgumentNullException(nameof(item))); + } + + if (!map.TryAdd(item.Identifier, item)) { + throw RegisterValidationException( + new ArgumentException( + $"Item with the same identifier '{item.Identifier}' has already been declared.")); + } + } + + public bool Contains(T item) + { + if (item == null) + return false; + if (map.ContainsKey(item.Identifier)) + return true; + if (map.Values.Contains(item)) { + return true; + } + return false; + } + + public void Clear() => map.Clear(); + + public bool Remove(T item) + { + if (map.Remove(item.Identifier)) + return true; + var result = map.Where(kv => kv.Value == item).Select(kv => kv.Key).FirstOrDefault(); + if (result != null) { + return map.Remove(result); + } + return false; + } + + public void CopyTo(T[] array, int arrayIndex) + { + ArgumentValidator.EnsureArgumentNotNull(array, nameof(array)); + ArgumentValidator.EnsureArgumentIsGreaterThanOrEqual(arrayIndex, 0, nameof(arrayIndex)); + + if (array.Length - arrayIndex < map.Count) { + throw new ArgumentException( + "The number of elements in the source collection is greater than the available space from arrayIndex to the end of the destination array"); + } + + var index = arrayIndex; + foreach (var item in map.Values) { + array[index] = item; + index++; + } + } + + protected Exception RegisterValidationException(Exception exception) + { + exceptionsOccur.Add(exception); + return exception; + } + + public IEnumerator GetEnumerator() => map.Values.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/SessionConfigurationOptions.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/SessionConfigurationOptions.cs new file mode 100644 index 0000000000..1263ca5c67 --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/SessionConfigurationOptions.cs @@ -0,0 +1,145 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Transactions; +using Xtensive.Core; + +namespace Xtensive.Orm.Configuration.Options +{ + internal sealed class SessionConfigurationOptions : + IIdentifyableOptions, + IValidatableOptions, + INamedOptionsCollectionElement + { + public object Identifier => Name; + + /// + /// Session name. + /// + /// + public string Name { get; set; } = WellKnown.Sessions.Default; + + /// + /// User name to authenticate. + /// Default value is . + /// + public string UserName { get; set; } = string.Empty; + + /// + /// Password to authenticate. + /// Default value is . + /// + public string Password { get; set; } = string.Empty; + + /// + /// session options. + /// Default value is . + /// + public SessionOptions Options { get; set; } = SessionOptions.Default; + + /// + /// Size of the session entity state cache. + /// Default value is . + /// + public int CacheSize { get; set; } = SessionConfiguration.DefaultCacheSize; + + /// + /// Type of session cache. + /// Default value is . + /// + public SessionCacheType CacheType { get; set; } = SessionConfiguration.DefaultCacheType; + + /// + /// Default isolation level. + /// Default value is . + /// + public IsolationLevel DefaultIsolationLevel { get; set; } = SessionConfiguration.DefaultDefaultIsolationLevel; + + /// + /// Default command timeout. + /// Default value is . + /// + public int? DefaultCommandTimeout { get; set; } = null; + + /// + /// Size of the batch. + /// This affects create, update, delete operations and future queries. + /// Default value is + /// + public int BatchSize { get; set; } = SessionConfiguration.DefaultBatchSize; + + /// + /// Size of the entity change registry. + /// Default value is + /// + public int EntityChangeRegistrySize { get; set; } = SessionConfiguration.DefaultEntityChangeRegistrySize; + + /// + /// Reader preloading policy. + /// It affects query results reading. + /// Default value is . + /// + public ReaderPreloadingPolicy ReaderPreloading { get; set; } = SessionConfiguration.DefaultReaderPreloadingPolicy; + + /// + /// Type of the service container + /// + public string ServiceContainerType { get; set; } = null; + + public string ConnectionString { get; set; } = null; + public string ConnectionUrl { get; set; } = null; + + /// + /// Name is null or empty. + /// CacheSize, BatchSize or EntityChangeRegistry value is out of valid range. + public void Validate() + { + if (Name.IsNullOrEmpty()) + throw new ArgumentException(Strings.ExNameMustBeNotNullOrEmpty); + if (CacheSize <= 1) + throw new ArgumentOutOfRangeException(nameof(CacheSize), CacheSize, string.Format(Strings.ExArgumentMustBeGreaterThanX, 1)); + if (BatchSize < 1) + throw new ArgumentOutOfRangeException(nameof(BatchSize), BatchSize, string.Format(Strings.ExArgumentMustBeGreaterThatOrEqualX, 1)); + if (EntityChangeRegistrySize < 1) + throw new ArgumentOutOfRangeException(nameof(EntityChangeRegistrySize), EntityChangeRegistrySize, string.Format(Strings.ExArgumentMustBeGreaterThatOrEqualX, 1)); + } + + /// + public SessionConfiguration ToNative(IDictionary connectionStrings) + { + // Minor hack: + // We should not require user to specify provider name. + // We actually know it when opening new session. + // However, we do not know it in this method + // We are going easy way and substituting a fake provider. + // SQL SessionHandler is aware of this and always uses correct provider. + + var connectionInfo = ConnectionInfoParser.GetConnectionInfo(connectionStrings, ConnectionUrl, "_dummy_", ConnectionString); + + if (Name.IsNullOrEmpty()) { + Name = WellKnown.Sessions.Default; + } + + Validate(); + + var result = new SessionConfiguration(Name) { + UserName = UserName, + Password = Password, + CacheSize = CacheSize, + BatchSize = BatchSize, + CacheType = CacheType, + Options = Options, + DefaultIsolationLevel = DefaultIsolationLevel, + ReaderPreloading = ReaderPreloading, + ServiceContainerType = (!ServiceContainerType.IsNullOrEmpty()) ? Type.GetType(ServiceContainerType) : null, + EntityChangeRegistrySize = EntityChangeRegistrySize, + DefaultCommandTimeout = DefaultCommandTimeout, + ConnectionInfo = connectionInfo, + }; + return result; + } + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/TypeRegistrationOptions.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/TypeRegistrationOptions.cs new file mode 100644 index 0000000000..050b40741a --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/TypeRegistrationOptions.cs @@ -0,0 +1,72 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System; +using Xtensive.Collections; +using Xtensive.Core; + +namespace Xtensive.Orm.Configuration.Options +{ + internal sealed class TypeRegistrationOptions : IIdentifyableOptions, + IValidatableOptions, + IToNativeConvertable + { + public object Identifier + { + get { + if (!Type.IsNullOrEmpty()) + return Type; + else + return (Assembly, Namespace.IsNullOrEmpty() ? null : Namespace); + } + } + + /// + /// Gets or sets the name of the type to register. + /// + public string Type { get; set; } = null; + + /// + /// Gets or sets the assembly where types to register are located. + /// + public string Assembly { get; set; } = null; + + /// + /// Gets or sets the namespace withing the , + /// where types to register are located. + /// If or , + /// all the persistent types from the will be registered. + /// + public string Namespace { get; set; } = null; + + /// + /// Combination of properties is not valid. + public void Validate() + { + if (!Type.IsNullOrEmpty() && (!Assembly.IsNullOrEmpty() || !Namespace.IsNullOrEmpty())) + throw new ArgumentException("Either type or assembly can be declared, not both at the same time."); + if (!Assembly.IsNullOrEmpty() && !Type.IsNullOrEmpty()) + throw new ArgumentException("Either type or assembly can be declared, not both at the same time."); + if (!Namespace.IsNullOrEmpty() && Assembly.IsNullOrEmpty()) + throw new ArgumentException("Namespace can only be declared with Assembly."); + } + + /// + public TypeRegistration ToNative() + { + Validate(); + + if (!Type.IsNullOrEmpty()) + return new TypeRegistration(System.Type.GetType(Type, true)); + else if (!Assembly.IsNullOrEmpty()) { + var assembly = System.Reflection.Assembly.Load(Assembly); + if (Namespace.IsNullOrEmpty()) + return new TypeRegistration(assembly); + else + return new TypeRegistration(assembly, Namespace); + } + throw new InvalidOperationException(); + } + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/VersioningConventionOptions.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/VersioningConventionOptions.cs new file mode 100644 index 0000000000..7bcaf702ff --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/VersioningConventionOptions.cs @@ -0,0 +1,31 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +namespace Xtensive.Orm.Configuration.Options +{ + internal sealed class VersioningConventionOptions : IToNativeConvertable + { + /// + /// Versioning policy for entities. + /// Default value is + /// + public EntityVersioningPolicy EntityVersioningPolicy { get; set; } = VersioningConvention.DefaultVersioningPolicy; + + /// + /// Value indicating that change of an owner version should be denied where possible. + /// Default value is + /// + public bool DenyEntitySetOwnerVersionChange { get; set; } = false; + + /// + public VersioningConvention ToNative() + { + var result = new VersioningConvention { + EntityVersioningPolicy = EntityVersioningPolicy, + DenyEntitySetOwnerVersionChange = DenyEntitySetOwnerVersionChange + }; + return result; + } + } +} From 551d6c2afc28251b0f7d912cb110957c9ee6fef9 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 29 Aug 2024 09:14:35 +0500 Subject: [PATCH 08/32] ConnectionInfoParser: supports connection strings as dictionary --- .../Internals/ConnectionInfoParser.cs | 63 ++++++++++++++++--- 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Internals/ConnectionInfoParser.cs b/Orm/Xtensive.Orm/Orm/Configuration/Internals/ConnectionInfoParser.cs index 452d684ab9..908bd3bbfc 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Internals/ConnectionInfoParser.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Internals/ConnectionInfoParser.cs @@ -5,17 +5,61 @@ // Created: 2013.09.27 using System; +using System.Collections; +using System.Collections.Generic; using System.Configuration; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Extensions.Configuration; using Xtensive.Core; namespace Xtensive.Orm.Configuration { internal static class ConnectionInfoParser { + private readonly struct UnifiedAccessor + { + private readonly IDictionary connectionStringsAsDict; + private readonly ConnectionStringSettingsCollection connectionStrings; + + public string this[string key] { + get { + if (connectionStrings != null) + return connectionStrings[key]?.ConnectionString; + else if(connectionStringsAsDict!=null) + return connectionStringsAsDict[key]; + return null; + } + } + + public UnifiedAccessor(ConnectionStringSettingsCollection oldConnectionStrings) + { + connectionStringsAsDict = null; + connectionStrings = oldConnectionStrings; + } + public UnifiedAccessor(IDictionary connectionStrings) + { + connectionStringsAsDict = connectionStrings; + this.connectionStrings = null; + } + } + public static ConnectionInfo GetConnectionInfo(System.Configuration.Configuration configuration,string connectionUrl, string provider, string connectionString) { - bool connectionUrlSpecified = !string.IsNullOrEmpty(connectionUrl); - bool connectionStringSpecified = !string.IsNullOrEmpty(connectionString) && !string.IsNullOrEmpty(provider); + var accessor = new UnifiedAccessor(configuration.ConnectionStrings.ConnectionStrings); + return GetConnectionInfoInternal(accessor, connectionUrl, provider, connectionString); + } + + public static ConnectionInfo GetConnectionInfo(IDictionary connectionStrings, string connectionUrl, string provider, string connectionString) + { + var accessor = new UnifiedAccessor(connectionStrings); + return GetConnectionInfoInternal(accessor, connectionUrl, provider, connectionString); + } + + private static ConnectionInfo GetConnectionInfoInternal(in UnifiedAccessor connectionStringAccessor, + string connectionUrl, string provider, string connectionString) + { + var connectionUrlSpecified = !string.IsNullOrEmpty(connectionUrl); + var connectionStringSpecified = !string.IsNullOrEmpty(connectionString) && !string.IsNullOrEmpty(provider); if (connectionUrlSpecified && connectionStringSpecified) throw new InvalidOperationException(Strings.ExConnectionInfoIsWrongYouShouldSetEitherConnectionUrlElementOrProviderAndConnectionStringElements); @@ -24,30 +68,31 @@ public static ConnectionInfo GetConnectionInfo(System.Configuration.Configuratio return new ConnectionInfo(connectionUrl); if (connectionStringSpecified) - return new ConnectionInfo(provider, ExpandConnectionString(configuration, connectionString)); + return new ConnectionInfo(provider, + ExpandConnectionString(connectionStringAccessor, connectionString)); // Neither connection string, nor connection url specified. // Leave connection information undefined. return null; } - private static string ExpandConnectionString(System.Configuration.Configuration configuration, string connectionString) + private static string ExpandConnectionString(in UnifiedAccessor connectionStrings, string connectionString) { const string prefix = "#"; if (!connectionString.StartsWith(prefix, StringComparison.Ordinal)) return connectionString; - string connectionStringName = connectionString.Substring(prefix.Length); + var connectionStringName = connectionString[prefix.Length..]; - var connectionStringSetting = configuration.ConnectionStrings.ConnectionStrings[connectionStringName]; - if (connectionStringSetting==null) + var connectionStringSetting = connectionStrings[connectionStringName]; + if (connectionStringSetting == null) throw new InvalidOperationException(string.Format(Strings.ExConnectionStringWithNameXIsNotFound, connectionStringName)); - if (string.IsNullOrEmpty(connectionStringSetting.ConnectionString)) + if (string.IsNullOrEmpty(connectionStringSetting)) throw new InvalidOperationException(string.Format(Strings.ExConnectionStringWithNameXIsNullOrEmpty, connectionStringName)); - return connectionStringSetting.ConnectionString; + return connectionStringSetting; } } } \ No newline at end of file From facc5931e1a5534ba16465566d4b2f130b70fefc Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 29 Aug 2024 11:25:08 +0500 Subject: [PATCH 09/32] DomainConfigurationParsers for json and for xml formats --- .../Internals/DomainConfigurationParsers.cs | 334 ++++++++++++++++++ 1 file changed, 334 insertions(+) create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Internals/DomainConfigurationParsers.cs diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Internals/DomainConfigurationParsers.cs b/Orm/Xtensive.Orm/Orm/Configuration/Internals/DomainConfigurationParsers.cs new file mode 100644 index 0000000000..6eab250774 --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Internals/DomainConfigurationParsers.cs @@ -0,0 +1,334 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + + +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.Configuration; +using Xtensive.Collections; +using Xtensive.Orm.Configuration.Options; + +namespace Xtensive.Orm.Configuration.Internals +{ + internal interface IConfigurationSectionParser + { + DomainConfiguration Parse(IConfiguration configuration); + + DomainConfiguration Parse(IConfigurationRoot configuration, string sectionName); + + DomainConfiguration Parse(IConfigurationSection domainConfiguration, Dictionary connectionStrings = null); + + } + + internal sealed class XmlDomainConfigParser : DomainConfigurationParser + { + + protected override void ProcessNamingConvention(IConfigurationSection namingConventionSection, DomainConfigurationOptions domainConfiguratonOptions) + { + if (namingConventionSection == null) { + domainConfiguratonOptions.NamingConventionRaw = null; + return; + } + + if (namingConventionSection.GetChildren().Any()) { + var namingConvetion = namingConventionSection.Get(); + if (namingConvetion!= null) { + var synonymsSection = namingConventionSection.GetSection(NamespaceSynonymSectionName); + var synonyms = synonymsSection != null && synonymsSection.GetChildren().Any() + ? GetSelfOrChildren(synonymsSection.GetSection(SynonymElementName)) + .Select(s => s.Get()) + .Where(ns => ns != null) + .ToArray() + : Array.Empty(); + + namingConvetion.NamespaceSynonyms = synonyms; + domainConfiguratonOptions.NamingConventionRaw = namingConvetion; + } + else { + domainConfiguratonOptions.NamingConventionRaw = null; + } + } + } + + protected override void ProcessVersioningConvention(IConfigurationSection versioningConventionSection, DomainConfigurationOptions domainConfiguratonOptions) + { + if (versioningConventionSection == null) { + domainConfiguratonOptions.VersioningConvention = null; + return; + } + + if (versioningConventionSection.GetChildren().Any()) { + var versioningConvention = versioningConventionSection.Get(); + + domainConfiguratonOptions.VersioningConvention = versioningConvention != null + ? versioningConvention + : null; + } + } + + protected override void ProcessTypes(IConfigurationSection typesSection, DomainConfigurationOptions domainConfigurationOptions) + { + if (typesSection == null) { + domainConfigurationOptions.Types = Array.Empty(); + return; + } + if (TryProcessTypeRegistrationsWithAttributes(typesSection, domainConfigurationOptions) + || TryProcessTypeRegistrationsWithNodes(typesSection, domainConfigurationOptions)) + return; + domainConfigurationOptions.Types = Array.Empty(); + } + + private bool TryProcessTypeRegistrationsWithAttributes(IConfigurationSection typesSection, + DomainConfigurationOptions domainConfigurationOptions) + { + var registrations = typesSection.GetSection(OldStyleTypeRegistrationElementName); + if (registrations != null && registrations.GetChildren().Any()) { + domainConfigurationOptions.Types = GetSelfOrChildren(registrations) + .Select(s => s.Get()) + .Where(tr => tr != null) + .ToArray(); + return true; + } + return false; + } + + private bool TryProcessTypeRegistrationsWithNodes(IConfigurationSection typesSection, + DomainConfigurationOptions domainConfigurationOptions) + { + var registrations = typesSection.GetSection(TypeRegistrationElementName); + if (registrations == null) + return false; + + domainConfigurationOptions.Types = GetSelfOrChildren(registrations) + .Select(s => s.Get()) + .Where(tr => tr != null) + .ToArray(); + return true; + } + + protected override void ProcessDatabases(IConfigurationSection databasesSection, DomainConfigurationOptions domainConfiguratonOptions) + { + domainConfiguratonOptions.Databases.Clear(); + if (databasesSection == null) + return; + var databaseElement = databasesSection.GetSection(DatabaseElementName); + if (databaseElement == null) + return; + foreach (var section in GetSelfOrChildren(databaseElement, true)) { + var dbItem = section.Get(); + if (dbItem == null) + continue; + domainConfiguratonOptions.Databases.Add(dbItem.Name, dbItem); + } + } + + protected override void ProcessKeyGenerators(IConfigurationSection keyGeneratorsSection, DomainConfigurationOptions domainConfiguratonOptions) + { + domainConfiguratonOptions.KeyGenerators.Clear(); + ProcessCollectionOfOptions(keyGeneratorsSection, KeyGeneratorElementName, domainConfiguratonOptions.KeyGenerators); + } + + protected override void ProcessIgnoreRules(IConfigurationSection ignoreRulesSection, Options.DomainConfigurationOptions domainConfiguratonOptions) + { + domainConfiguratonOptions.IgnoreRules.Clear(); + ProcessCollectionOfOptions(ignoreRulesSection, RuleElementName, domainConfiguratonOptions.IgnoreRules); + } + + protected override void ProcessMappingRules(IConfigurationSection mappingRulesSection, Options.DomainConfigurationOptions domainConfiguratonOptions) + { + domainConfiguratonOptions.MappingRules.Clear(); + ProcessCollectionOfOptions(mappingRulesSection, RuleElementName, domainConfiguratonOptions.MappingRules); + } + + protected override void ProcessSessions(IConfigurationSection sessionsSection, Options.DomainConfigurationOptions domainConfiguratonOptions) + { + domainConfiguratonOptions.Sessions.Clear(); + if (sessionsSection == null) + return; + var sessionElement = sessionsSection.GetSection(SessionElementName); + if (sessionElement == null) + return; + foreach (var section in GetSelfOrChildren(sessionElement, true)) { + var sessionItem = section.Get(); + if (sessionItem == null) + continue; + domainConfiguratonOptions.Sessions.Add(sessionItem.Name, sessionItem); + } + } + + private void ProcessCollectionOfOptions(IConfigurationSection collectionSection, string itemKey, OptionsCollection collection) + where TOption : class, IIdentifyableOptions + { + if (collectionSection == null) + return; + var collectionElement = collectionSection.GetSection(itemKey); + if (collectionElement == null) + return; + foreach (var item in GetSelfOrChildren(collectionElement)) { + var optItem = item.Get(); + collection.Add(optItem); + } + } + + private IEnumerable GetSelfOrChildren(IConfigurationSection section, bool requiredName = false) + { + var children = section.GetChildren().ToList(); + if (children.Count > 0) { + if (requiredName) { + var anyItemWithName = children.Any(i => i["name"] != null); + if (anyItemWithName) { + return children; + } + } + var firstChild = children[0]; + var isIndexed = firstChild.Key == "0"; + if (isIndexed) + return children; + else + return EnumerableUtils.One(section); + } + return children; + } + } + + internal class FromJsonToDomainConfigurationParser : DomainConfigurationParser + { + + protected override void ProcessNamingConvention(IConfigurationSection namingConventionSection, DomainConfigurationOptions domainConfiguratonOptions) + { + if (namingConventionSection == null || !namingConventionSection.GetChildren().Any()) + return; + var jsonListVariant = namingConventionSection.Get(); + if (jsonListVariant.NamespaceSynonyms == null) + jsonListVariant.NamespaceSynonyms = Array.Empty(); + domainConfiguratonOptions.NamingConventionRaw = jsonListVariant; + } + } + + internal abstract class DomainConfigurationParser : IConfigurationSectionParser + { + protected const string RuleElementName = "Rule"; + protected const string KeyGeneratorElementName = "KeyGenerator"; + protected const string OldStyleTypeRegistrationElementName = "Add"; + protected const string TypeRegistrationElementName = "Registration"; + protected const string SynonymElementName = "Synonym"; + protected const string DatabaseElementName = "Database"; + protected const string SessionElementName = "Session"; + + protected const string NamingConventionSectionName = "NamingConvention"; + protected const string VersioningConventionSectionName = "VersioningConvention"; + protected const string TypesSectionName = "Types"; + protected const string DatabasesSectionName = "Databases"; + protected const string KeyGeneratorsSectionName = "KeyGenerators"; + protected const string IgnoreRulesSectionName = "IgnoreRules"; + protected const string MappingRulesSectionName = "MappingRules"; + protected const string SessionsSectionName = "Sessions"; + protected const string NamespaceSynonymSectionName = "NamespaceSynonyms"; + + public DomainConfiguration Parse(IConfiguration configuration) + { + if (configuration is IConfigurationRoot configurationRoot) { + return Parse(configurationRoot, WellKnown.DefaultConfigurationSection); + } + else if (configuration is IConfigurationSection configurationSection) { + return Parse(configurationSection); + } + throw new InvalidOperationException(""); + } + + public DomainConfiguration Parse(IConfigurationRoot configuration, string sectionName) + { + var context = new ConfigurationParserContext(configuration, sectionName); + return ParseInternal(context); + } + + public DomainConfiguration Parse(IConfigurationSection domainConfiguration, Dictionary connectionStrings = null) + { + var context = new ConfigurationParserContext(domainConfiguration, connectionStrings); + return ParseInternal(context); + } + + private DomainConfiguration ParseInternal(ConfigurationParserContext context) + { + var domainByNameSection = context.CurrentSection; + if (domainByNameSection == null || !domainByNameSection.GetChildren().Any()) { + return null; + } + // this handles only root properties of domain configuration + var domainConfigurationOptions = context.CurrentSection.Get(); + if (domainConfigurationOptions == null) { + return null; + } + + // all sub-items require manual reading; + ProcessNamingConvention(domainByNameSection.GetSection(NamingConventionSectionName), domainConfigurationOptions); + ProcessVersioningConvention(domainByNameSection.GetSection(VersioningConventionSectionName), domainConfigurationOptions); + ProcessTypes(domainByNameSection.GetSection(TypesSectionName), domainConfigurationOptions); + ProcessDatabases(domainByNameSection.GetSection(DatabasesSectionName), domainConfigurationOptions); + ProcessKeyGenerators(domainByNameSection.GetSection(KeyGeneratorsSectionName), domainConfigurationOptions); + ProcessIgnoreRules(domainByNameSection.GetSection(IgnoreRulesSectionName), domainConfigurationOptions); + ProcessMappingRules(domainByNameSection.GetSection(MappingRulesSectionName), domainConfigurationOptions); + ProcessSessions(domainByNameSection.GetSection(SessionsSectionName), domainConfigurationOptions); + + return domainConfigurationOptions.ToNative(context.ConnectionStrings); + } + + protected virtual void ProcessNamingConvention(IConfigurationSection namingConventionSection, DomainConfigurationOptions domainConfiguratonOptions) + { + } + + protected virtual void ProcessVersioningConvention(IConfigurationSection versioningConventionSection, DomainConfigurationOptions domainConfiguratonOptions) + { + } + + protected virtual void ProcessTypes(IConfigurationSection typesSection, DomainConfigurationOptions domainConfigurationOptions) + { + } + + protected virtual void ProcessDatabases(IConfigurationSection databasesSection, DomainConfigurationOptions domainConfiguratonOptions) + { + } + + protected virtual void ProcessKeyGenerators(IConfigurationSection keyGeneratorsSection, DomainConfigurationOptions domainConfiguratonOptions) + { + } + + protected virtual void ProcessIgnoreRules(IConfigurationSection ignoreRulesSection, DomainConfigurationOptions domainConfiguratonOptions) + { + } + + protected virtual void ProcessMappingRules(IConfigurationSection mappingRulesSection, DomainConfigurationOptions domainConfiguratonOptions) + { + } + + protected virtual void ProcessSessions(IConfigurationSection sessionsSection, DomainConfigurationOptions domainConfiguratonOptions) + { + } + } + + internal sealed class ConfigurationParserContext + { + public readonly IConfigurationRoot CurrentConfiguration; + + public readonly IConfigurationSection CurrentSection; + + public readonly string SectionName; + + public readonly IDictionary ConnectionStrings; + + public ConfigurationParserContext(IConfigurationRoot currentConfiguration, string sectionName) + { + CurrentConfiguration = currentConfiguration; + CurrentSection = currentConfiguration.GetSection(sectionName); + ConnectionStrings = currentConfiguration.Get>(); + } + + public ConfigurationParserContext(IConfigurationSection currentSection, IDictionary connectionStrings) + { + CurrentSection = currentSection; + ConnectionStrings = connectionStrings; + } + } +} From 5eec51216b09d945df290672d697ba2534b3ba9f Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 29 Aug 2024 11:41:15 +0500 Subject: [PATCH 10/32] DomainConfiguration.Load() implemented --- .../Orm/Configuration/DomainConfiguration.cs | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs b/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs index 736c56d09b..f28ddea87c 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2022 Xtensive LLC. +// Copyright (C) 2007-2024 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Dmitri Maximov @@ -73,7 +73,7 @@ public class DomainConfiguration : ConfigurationBase public const bool DefaultShareStorageSchemaOverNodes = false; /// - /// Default value: + /// Default value: . /// public const bool DefaultAllowCyclicDatabaseDependencies = false; @@ -881,8 +881,25 @@ private static DomainConfiguration LoadConfigurationFromSection(ConfigurationSec /// The "domains" section is not found or domain with requested name is not found. public static DomainConfiguration Load(IConfigurationSection configurationSection, string name) { - throw new NotImplementedException(); + var allDomainsSection = configurationSection.GetSection("Domains"); + if (allDomainsSection != null && allDomainsSection.GetChildren().Any()) { + var domainSection = allDomainsSection.GetSection(name); + if (domainSection.GetChildren().Any()) { + var parseResult = new FromJsonToDomainConfigurationParser().Parse(domainSection); + if (parseResult != null) + return parseResult; + } + else if ((domainSection = allDomainsSection.GetSection($"Domain:{name}")).GetChildren().Any()) { + var parseResult = new XmlDomainConfigParser().Parse(domainSection); + if (parseResult != null) + return parseResult; + } + } + + throw new InvalidOperationException(string.Format( + Strings.ExConfigurationForDomainIsNotFoundInApplicationConfigurationFile, name, sectionName)); } + #endregion // Constructors From bf3516d51659c8b5f4c23bbfd762e45db7bf5bfb Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Tue, 17 Sep 2024 16:28:23 +0500 Subject: [PATCH 11/32] Tests for LoggingConfiguration loading --- .../Configuration/ModernConfigurationTests.cs | 392 +++++++++++------- Orm/Xtensive.Orm.Tests/domainSettings.config | 75 ++++ Orm/Xtensive.Orm.Tests/domainSettings.json | 54 +++ .../Orm/Configuration/LoggingConfiguration.cs | 10 + 4 files changed, 377 insertions(+), 154 deletions(-) diff --git a/Orm/Xtensive.Orm.Tests/Configuration/ModernConfigurationTests.cs b/Orm/Xtensive.Orm.Tests/Configuration/ModernConfigurationTests.cs index 5a1788dfac..42c8152e15 100644 --- a/Orm/Xtensive.Orm.Tests/Configuration/ModernConfigurationTests.cs +++ b/Orm/Xtensive.Orm.Tests/Configuration/ModernConfigurationTests.cs @@ -75,6 +75,7 @@ namespace Xtensive.Orm.Tests.Configuration public sealed class AppConfigStyleConfigurationTest : ConfigurationFileTestBase { protected override string DefaultSectionName => "Xtensive.Orm.AppConfig"; + protected override string Postfix => "AppConfig"; protected override bool NameAttributeUnique => false; @@ -88,6 +89,7 @@ protected override void RegisterConfigurationFile(ConfigurationBuilder builder) public sealed class XmlConfigurationTest : ConfigurationFileTestBase { protected override string DefaultSectionName => "Xtensive.Orm.Xml"; + protected override string Postfix => "Xml"; protected override void RegisterConfigurationFile(ConfigurationBuilder builder) { @@ -99,6 +101,7 @@ protected override void RegisterConfigurationFile(ConfigurationBuilder builder) public sealed class JsonConfigurationTest : ConfigurationFileTestBase { protected override string DefaultSectionName => "Xtensive.Orm.Json"; + protected override string Postfix => "Json"; protected override void RegisterConfigurationFile(ConfigurationBuilder builder) { @@ -113,6 +116,7 @@ public abstract class ConfigurationFileTestBase private IConfigurationSection configurationSection; protected abstract string DefaultSectionName { get; } + protected abstract string Postfix { get; } protected virtual bool NameAttributeUnique => true; [OneTimeSetUp] @@ -132,18 +136,24 @@ public void OneTimeSetup() protected abstract void RegisterConfigurationFile(ConfigurationBuilder builder); - private DomainConfiguration GetDomainConfiguration(string domainName) + private DomainConfiguration LoadDomainConfiguration(string domainName) { var domainConfiguration = DomainConfiguration.Load(configurationSection, domainName); return domainConfiguration; } + private LoggingConfiguration LoadLoggingConfiguration(IConfigurationSection customConfigurationSection = null) + { + var loggingConfiguration = LoggingConfiguration.Load(customConfigurationSection ?? configurationSection); + return loggingConfiguration; + } + #region Simple Domain settings that used to be attributes [Test] public void ProviderAndConnectionStringTest() { - var domainConfig = GetDomainConfiguration("DomainWithProviderAndConnectionString"); + var domainConfig = LoadDomainConfiguration("DomainWithProviderAndConnectionString"); Assert.That(domainConfig.ConnectionInfo.Provider, Is.EqualTo(WellKnown.Provider.Sqlite)); Assert.That(domainConfig.ConnectionInfo.ConnectionString, Is.EqualTo("Data Source=DO-Testsaaa.db3")); Assert.That(domainConfig.ConnectionInfo.ConnectionUrl, Is.Null); @@ -154,7 +164,7 @@ public void ProviderAndConnectionStringTest() [Test] public void ConnectionUrlTest() { - var domainConfig = GetDomainConfiguration("DomainWithConnectionUrl"); + var domainConfig = LoadDomainConfiguration("DomainWithConnectionUrl"); Assert.That(domainConfig.ConnectionInfo.Provider, Is.EqualTo(WellKnown.Provider.Sqlite)); Assert.That(domainConfig.ConnectionInfo.ConnectionString, Is.Null); Assert.That(domainConfig.ConnectionInfo.ConnectionUrl.Url, Is.EqualTo("sqlite:///DO-Tests.db3")); @@ -165,7 +175,7 @@ public void ConnectionUrlTest() [Test] public void CustomValidKeyCacheSizeTest() { - var domainConfig = GetDomainConfiguration("DomainWithCustomValidKeyCacheSize"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomValidKeyCacheSize"); ValidateAllDefaultExcept(domainConfig, ((d) => d.KeyCacheSize, 192)); } @@ -173,14 +183,14 @@ public void CustomValidKeyCacheSizeTest() [Test] public void CustomInvalidKeyCacheSizeTest() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithCustomInvalidKeyCacheSize")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomInvalidKeyCacheSize")); } [Test] public void CustomValidKeyGeneratorCacheSizeTest() { - var domainConfig = GetDomainConfiguration("DomainWithCustomValidKeyGeneratorCacheSize"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomValidKeyGeneratorCacheSize"); ValidateAllDefaultExcept(domainConfig, ((d) => d.KeyGeneratorCacheSize, 192)); } @@ -188,13 +198,13 @@ public void CustomValidKeyGeneratorCacheSizeTest() [Test] public void CustomInvalidKeyGeneratorCacheSizeTest() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithCustomInvalidKeyGeneratorCacheSize")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomInvalidKeyGeneratorCacheSize")); } [Test] public void CustomValidQueryCacheSizeTest() { - var domainConfig = GetDomainConfiguration("DomainWithCustomValidQueryCacheSize"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomValidQueryCacheSize"); ValidateAllDefaultExcept(domainConfig, ((d) => d.QueryCacheSize, 192)); } @@ -202,26 +212,26 @@ public void CustomValidQueryCacheSizeTest() [Test] public void CustomInvalidQueryCacheSizeTest() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithCustomInvalidQueryCacheSize")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomInvalidQueryCacheSize")); } [Test] public void CustomValidRecordSetMappingCacheSizeTest() { - var domainConfig = GetDomainConfiguration("DomainWithCustomValidRecordSetMappingCacheSize"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomValidRecordSetMappingCacheSize"); ValidateAllDefaultExcept(domainConfig, ((d) => d.RecordSetMappingCacheSize, 192)); } [Test] public void CustomInvalidRecordSetMappingCacheSizeTest() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithCustomInvalidRecordSetMappingCacheSize")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomInvalidRecordSetMappingCacheSize")); } [Test] public void CustomDefaultDatabaseTest() { - var domainConfig = GetDomainConfiguration("DomainWithCustomDatabase"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomDatabase"); ValidateAllDefaultExcept(domainConfig, ((d) => d.DefaultDatabase, "MyFancyDatabase"), ((d) => d.IsMultidatabase, true), @@ -232,7 +242,7 @@ public void CustomDefaultDatabaseTest() [Test] public void CustomDefaultSchemaTest() { - var domainConfig = GetDomainConfiguration("DomainWithCustomSchema"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomSchema"); ValidateAllDefaultExcept(domainConfig, ((d) => d.DefaultSchema, "MyFancySchema"), ((d) => d.IsMultidatabase, false), @@ -242,42 +252,42 @@ public void CustomDefaultSchemaTest() [Test] public void UpgradeModesTest() { - var domainConfig = GetDomainConfiguration("DomainWithUpgradeMode1"); + var domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode1"); ValidateAllDefaultExcept(domainConfig, ((d) => d.UpgradeMode, DomainUpgradeMode.Default)); domainConfig.Lock(); - domainConfig = GetDomainConfiguration("DomainWithUpgradeMode2"); + domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode2"); ValidateAllDefaultExcept(domainConfig, ((d) => d.UpgradeMode, DomainUpgradeMode.Recreate)); domainConfig.Lock(); - domainConfig = GetDomainConfiguration("DomainWithUpgradeMode3"); + domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode3"); ValidateAllDefaultExcept(domainConfig, ((d) => d.UpgradeMode, DomainUpgradeMode.Perform)); domainConfig.Lock(); - domainConfig = GetDomainConfiguration("DomainWithUpgradeMode4"); + domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode4"); ValidateAllDefaultExcept(domainConfig, ((d) => d.UpgradeMode, DomainUpgradeMode.PerformSafely)); domainConfig.Lock(); - domainConfig = GetDomainConfiguration("DomainWithUpgradeMode5"); + domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode5"); ValidateAllDefaultExcept(domainConfig, ((d) => d.UpgradeMode, DomainUpgradeMode.Validate)); domainConfig.Lock(); - domainConfig = GetDomainConfiguration("DomainWithUpgradeMode6"); + domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode6"); ValidateAllDefaultExcept(domainConfig, ((d) => d.UpgradeMode, DomainUpgradeMode.LegacyValidate)); domainConfig.Lock(); - domainConfig = GetDomainConfiguration("DomainWithUpgradeMode7"); + domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode7"); ValidateAllDefaultExcept(domainConfig, ((d) => d.UpgradeMode, DomainUpgradeMode.Skip)); domainConfig.Lock(); - domainConfig = GetDomainConfiguration("DomainWithUpgradeMode8"); + domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode8"); ValidateAllDefaultExcept(domainConfig, ((d) => d.UpgradeMode, DomainUpgradeMode.LegacySkip)); domainConfig.Lock(); @@ -286,33 +296,33 @@ public void UpgradeModesTest() [Test] public void WrongUpgradeModeTest() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithWrongUpgradeMode")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithWrongUpgradeMode")); } [Test] public void ForeighKeyModesTest() { - var domainConfig = GetDomainConfiguration("DomainWithForeignKeyMode1"); + var domainConfig = LoadDomainConfiguration("DomainWithForeignKeyMode1"); ValidateAllDefaultExcept(domainConfig, ((d) => d.ForeignKeyMode, ForeignKeyMode.None)); domainConfig.Lock(); - domainConfig = GetDomainConfiguration("DomainWithForeignKeyMode2"); + domainConfig = LoadDomainConfiguration("DomainWithForeignKeyMode2"); ValidateAllDefaultExcept(domainConfig, ((d) => d.ForeignKeyMode, ForeignKeyMode.Hierarchy)); domainConfig.Lock(); - domainConfig = GetDomainConfiguration("DomainWithForeignKeyMode3"); + domainConfig = LoadDomainConfiguration("DomainWithForeignKeyMode3"); ValidateAllDefaultExcept(domainConfig, ((d) => d.ForeignKeyMode, ForeignKeyMode.Reference)); domainConfig.Lock(); - domainConfig = GetDomainConfiguration("DomainWithForeignKeyMode4"); + domainConfig = LoadDomainConfiguration("DomainWithForeignKeyMode4"); ValidateAllDefaultExcept(domainConfig, ((d) => d.ForeignKeyMode, ForeignKeyMode.All)); domainConfig.Lock(); - domainConfig = GetDomainConfiguration("DomainWithForeignKeyMode5"); + domainConfig = LoadDomainConfiguration("DomainWithForeignKeyMode5"); ValidateAllDefaultExcept(domainConfig, ((d) => d.ForeignKeyMode, ForeignKeyMode.Default)); domainConfig.Lock(); - domainConfig = GetDomainConfiguration("DomainWithForeignKeyMode6"); + domainConfig = LoadDomainConfiguration("DomainWithForeignKeyMode6"); ValidateAllDefaultExcept(domainConfig, ((d) => d.ForeignKeyMode, ForeignKeyMode.Hierarchy | ForeignKeyMode.Reference)); domainConfig.Lock(); } @@ -320,29 +330,29 @@ public void ForeighKeyModesTest() [Test] public void InvalidForeighKeyModeTest() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidForeignKeyMode")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidForeignKeyMode")); } [Test] public void ChangeTrackingModesTest() { - var domainConfig = GetDomainConfiguration("DomainWithChangeTrackingMode1"); + var domainConfig = LoadDomainConfiguration("DomainWithChangeTrackingMode1"); ValidateAllDefaultExcept(domainConfig, ((d) => d.FullTextChangeTrackingMode, FullTextChangeTrackingMode.Off)); domainConfig.Lock(); - domainConfig = GetDomainConfiguration("DomainWithChangeTrackingMode2"); + domainConfig = LoadDomainConfiguration("DomainWithChangeTrackingMode2"); ValidateAllDefaultExcept(domainConfig, ((d) => d.FullTextChangeTrackingMode, FullTextChangeTrackingMode.Auto)); domainConfig.Lock(); - domainConfig = GetDomainConfiguration("DomainWithChangeTrackingMode3"); + domainConfig = LoadDomainConfiguration("DomainWithChangeTrackingMode3"); ValidateAllDefaultExcept(domainConfig, ((d) => d.FullTextChangeTrackingMode, FullTextChangeTrackingMode.Manual)); domainConfig.Lock(); - domainConfig = GetDomainConfiguration("DomainWithChangeTrackingMode4"); + domainConfig = LoadDomainConfiguration("DomainWithChangeTrackingMode4"); ValidateAllDefaultExcept(domainConfig, ((d) => d.FullTextChangeTrackingMode, FullTextChangeTrackingMode.OffWithNoPopulation)); domainConfig.Lock(); - domainConfig = GetDomainConfiguration("DomainWithChangeTrackingMode5"); + domainConfig = LoadDomainConfiguration("DomainWithChangeTrackingMode5"); ValidateAllDefaultExcept(domainConfig, ((d) => d.FullTextChangeTrackingMode, FullTextChangeTrackingMode.Default)); domainConfig.Lock(); } @@ -350,13 +360,13 @@ public void ChangeTrackingModesTest() [Test] public void InvalidChangeTrackingModeTest() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidChangeTrackingMode")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidChangeTrackingMode")); } [Test] public void DomainOptionsTest1() { - var domainConfig = GetDomainConfiguration("DomainWithDomainOptionsValid1"); + var domainConfig = LoadDomainConfiguration("DomainWithDomainOptionsValid1"); ValidateAllDefaultExcept(domainConfig, ((d) => d.Options, DomainOptions.Default)); domainConfig.Lock(); } @@ -364,54 +374,54 @@ public void DomainOptionsTest1() [Test] public void DomainOptionsTest2() { - var domainConfig = GetDomainConfiguration("DomainWithDomainOptionsValid2"); + var domainConfig = LoadDomainConfiguration("DomainWithDomainOptionsValid2"); ValidateAllDefaultExcept(domainConfig, ((d) => d.Options, DomainOptions.None)); domainConfig.Lock(); } [Test] public void InvalidDomainOptionsTest() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithDomainOptionsInvalid")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithDomainOptionsInvalid")); } [Test] public void CollationTest() { - var domainConfig = GetDomainConfiguration("DomainWithColation"); + var domainConfig = LoadDomainConfiguration("DomainWithColation"); ValidateAllDefaultExcept(domainConfig, ((d) => d.Collation, "generalci")); } [Test] public void BriefSchemaSyncExceptionsTest() { - var domainConfig = GetDomainConfiguration("DomainWithBriefSchemaSyncExceptions"); + var domainConfig = LoadDomainConfiguration("DomainWithBriefSchemaSyncExceptions"); ValidateAllDefaultExcept(domainConfig, ((d) => d.SchemaSyncExceptionFormat, SchemaSyncExceptionFormat.Brief)); } [Test] public void DetailedSchemaSyncExceptionsTest() { - var domainConfig = GetDomainConfiguration("DomainWithDetailedSchemaSyncExceptions"); + var domainConfig = LoadDomainConfiguration("DomainWithDetailedSchemaSyncExceptions"); ValidateAllDefaultExcept(domainConfig, ((d) => d.SchemaSyncExceptionFormat, SchemaSyncExceptionFormat.Detailed)); } [Test] public void DefaultSchemaSyncExceptionsTest() { - var domainConfig = GetDomainConfiguration("DomainWithDefaultSchemaSyncExceptions"); + var domainConfig = LoadDomainConfiguration("DomainWithDefaultSchemaSyncExceptions"); ValidateAllDefaultExcept(domainConfig, ((d) => d.SchemaSyncExceptionFormat, SchemaSyncExceptionFormat.Default)); } [Test] public void InvalidSchemaSyncExceptionsTest() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidSchemaSyncExceptions")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidSchemaSyncExceptions")); } [Test] public void TagsLocationNowhereTest() { - var domainConfig = GetDomainConfiguration("DomainWithTagsLocationNowhere"); + var domainConfig = LoadDomainConfiguration("DomainWithTagsLocationNowhere"); ValidateAllDefaultExcept(domainConfig, ((d) => d.TagsLocation, TagsLocation.Nowhere)); } @@ -419,7 +429,7 @@ public void TagsLocationNowhereTest() [Test] public void TagsLocationBeforeTest() { - var domainConfig = GetDomainConfiguration("DomainWithTagsLocationBefore"); + var domainConfig = LoadDomainConfiguration("DomainWithTagsLocationBefore"); ValidateAllDefaultExcept(domainConfig, ((d) => d.TagsLocation, TagsLocation.BeforeStatement)); } @@ -427,7 +437,7 @@ public void TagsLocationBeforeTest() [Test] public void TagsLocationWithinTest() { - var domainConfig = GetDomainConfiguration("DomainWithTagsLocationWithin"); + var domainConfig = LoadDomainConfiguration("DomainWithTagsLocationWithin"); ValidateAllDefaultExcept(domainConfig, ((d) => d.TagsLocation, TagsLocation.WithinStatement)); } @@ -435,7 +445,7 @@ public void TagsLocationWithinTest() [Test] public void TagsLocationAfterTest() { - var domainConfig = GetDomainConfiguration("DomainWithTagsLocationAfter"); + var domainConfig = LoadDomainConfiguration("DomainWithTagsLocationAfter"); ValidateAllDefaultExcept(domainConfig, ((d) => d.TagsLocation, TagsLocation.AfterStatement)); } @@ -443,7 +453,7 @@ public void TagsLocationAfterTest() [Test] public void TagsLocationDefaultTest() { - var domainConfig = GetDomainConfiguration("DomainWithTagsLocationDefault"); + var domainConfig = LoadDomainConfiguration("DomainWithTagsLocationDefault"); ValidateAllDefaultExcept(domainConfig, ((d) => d.TagsLocation, TagsLocation.Default)); } @@ -451,13 +461,13 @@ public void TagsLocationDefaultTest() [Test] public void InvalidTagsLocationTest() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithTagsLocationInvalid")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithTagsLocationInvalid")); } [Test] public void ForcedServerVersionTest() { - var domainConfig = GetDomainConfiguration("DomainWithForcedServerVersion"); + var domainConfig = LoadDomainConfiguration("DomainWithForcedServerVersion"); ValidateAllDefaultExcept(domainConfig, ((d) => d.ForcedServerVersion, "10.0.0.0")); } @@ -465,7 +475,7 @@ public void ForcedServerVersionTest() [Test] public void InitializationSqlTest() { - var domainConfig = GetDomainConfiguration("DomainWithInitSql"); + var domainConfig = LoadDomainConfiguration("DomainWithInitSql"); ValidateAllDefaultExcept(domainConfig, ((d) => d.ConnectionInitializationSql, "use [OtherDb]")); } @@ -473,7 +483,7 @@ public void InitializationSqlTest() [Test] public void IncludeSqlInExceptionsTest() { - var domainConfig = GetDomainConfiguration("IncludeSqlInExceptionsTrue"); + var domainConfig = LoadDomainConfiguration("IncludeSqlInExceptionsTrue"); ValidateAllDefaultExcept(domainConfig, ((d) => d.IncludeSqlInExceptions, true)); } @@ -481,7 +491,7 @@ public void IncludeSqlInExceptionsTest() [Test] public void DontIncludeSqlInExceptionsTest() { - var domainConfig = GetDomainConfiguration("IncludeSqlInExceptionsFalse"); + var domainConfig = LoadDomainConfiguration("IncludeSqlInExceptionsFalse"); ValidateAllDefaultExcept(domainConfig, ((d) => d.IncludeSqlInExceptions, false)); } @@ -489,7 +499,7 @@ public void DontIncludeSqlInExceptionsTest() [Test] public void AllowCyclicDatabaseDependanciesTest() { - var domainConfig = GetDomainConfiguration("AllowCyclicDatabaseDependenciesTrue"); + var domainConfig = LoadDomainConfiguration("AllowCyclicDatabaseDependenciesTrue"); ValidateAllDefaultExcept(domainConfig, ((d) => d.AllowCyclicDatabaseDependencies, true)); } @@ -497,7 +507,7 @@ public void AllowCyclicDatabaseDependanciesTest() [Test] public void DisallowCyclicDatabaseDependanciesTest() { - var domainConfig = GetDomainConfiguration("AllowCyclicDatabaseDependenciesFalse"); + var domainConfig = LoadDomainConfiguration("AllowCyclicDatabaseDependenciesFalse"); ValidateAllDefaultExcept(domainConfig, ((d) => d.AllowCyclicDatabaseDependencies, false)); } @@ -505,35 +515,35 @@ public void DisallowCyclicDatabaseDependanciesTest() [Test] public void BuildInParallelTest() { - var domainConfig = GetDomainConfiguration("BuildInParallelTrue"); + var domainConfig = LoadDomainConfiguration("BuildInParallelTrue"); ValidateAllDefaultExcept(domainConfig, ((d) => d.BuildInParallel, true)); } [Test] public void DontBuildInParallelTest() { - var domainConfig = GetDomainConfiguration("BuildInParallelFalse"); + var domainConfig = LoadDomainConfiguration("BuildInParallelFalse"); ValidateAllDefaultExcept(domainConfig, ((d) => d.BuildInParallel, false)); } [Test] public void AllowMultidatabaseKeysTest() { - var domainConfig = GetDomainConfiguration("MultidatabaseKeysTrue"); + var domainConfig = LoadDomainConfiguration("MultidatabaseKeysTrue"); ValidateAllDefaultExcept(domainConfig, ((d) => d.MultidatabaseKeys, true)); } [Test] public void DisallowMultidatabaseKeysTest() { - var domainConfig = GetDomainConfiguration("MultidatabaseKeysFalse"); + var domainConfig = LoadDomainConfiguration("MultidatabaseKeysFalse"); ValidateAllDefaultExcept(domainConfig, ((d) => d.MultidatabaseKeys, false)); } [Test] public void ShareStorageSchemaOverNodesTest() { - var domainConfig = GetDomainConfiguration("SharedStorageSchemaOn"); + var domainConfig = LoadDomainConfiguration("SharedStorageSchemaOn"); ValidateAllDefaultExcept(domainConfig, ((d) => d.ShareStorageSchemaOverNodes, true)); } @@ -541,7 +551,7 @@ public void ShareStorageSchemaOverNodesTest() [Test] public void DontShareStorageSchemaOverNodesTest() { - var domainConfig = GetDomainConfiguration("SharedStorageSchemaOff"); + var domainConfig = LoadDomainConfiguration("SharedStorageSchemaOff"); ValidateAllDefaultExcept(domainConfig, ((d) => d.ShareStorageSchemaOverNodes, false)); } @@ -549,7 +559,7 @@ public void DontShareStorageSchemaOverNodesTest() [Test] public void EnsureConnectionIsAliveTest() { - var domainConfig = GetDomainConfiguration("EnableConnectionIsAliveTrue"); + var domainConfig = LoadDomainConfiguration("EnableConnectionIsAliveTrue"); ValidateAllDefaultExcept(domainConfig, ((d) => d.EnsureConnectionIsAlive, true)); } @@ -557,7 +567,7 @@ public void EnsureConnectionIsAliveTest() [Test] public void DontCheckConnectionIsAliveTest() { - var domainConfig = GetDomainConfiguration("EnableConnectionIsAliveFalse"); + var domainConfig = LoadDomainConfiguration("EnableConnectionIsAliveFalse"); ValidateAllDefaultExcept(domainConfig, ((d) => d.EnsureConnectionIsAlive, false)); } @@ -565,7 +575,7 @@ public void DontCheckConnectionIsAliveTest() [Test] public void PreferTypeIdAsQueryParameterTest() { - var domainConfig = GetDomainConfiguration("PreferTypeIdsAsQueryParametersTrue"); + var domainConfig = LoadDomainConfiguration("PreferTypeIdsAsQueryParametersTrue"); ValidateAllDefaultExcept(domainConfig, ((d) => d.PreferTypeIdsAsQueryParameters, true)); } @@ -573,7 +583,7 @@ public void PreferTypeIdAsQueryParameterTest() [Test] public void DontPreferTypeIdAsQueryParameterTest() { - var domainConfig = GetDomainConfiguration("PreferTypeIdsAsQueryParametersFalse"); + var domainConfig = LoadDomainConfiguration("PreferTypeIdsAsQueryParametersFalse"); ValidateAllDefaultExcept(domainConfig, ((d) => d.PreferTypeIdsAsQueryParameters, false)); } @@ -584,7 +594,7 @@ public void DontPreferTypeIdAsQueryParameterTest() [Test] public void NamingConventionSettingsTest01() { - var domainConfig = GetDomainConfiguration("DomainWithNamingConvention1"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention1"); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); @@ -600,7 +610,7 @@ public void NamingConventionSettingsTest01() [Test] public void NamingConventionSettingsTest02() { - var domainConfig = GetDomainConfiguration("DomainWithNamingConvention2"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention2"); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Lowercase)); @@ -616,7 +626,7 @@ public void NamingConventionSettingsTest02() [Test] public void NamingConventionSettingsTest03() { - var domainConfig = GetDomainConfiguration("DomainWithNamingConvention3"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention3"); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.AsIs)); @@ -632,7 +642,7 @@ public void NamingConventionSettingsTest03() [Test] public void NamingConventionSettingsTest04() { - var domainConfig = GetDomainConfiguration("DomainWithNamingConvention4"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention4"); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Default)); @@ -648,7 +658,7 @@ public void NamingConventionSettingsTest04() [Test] public void NamingConventionSettingsTest05() { - var domainConfig = GetDomainConfiguration("DomainWithNamingConvention5"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention5"); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); @@ -659,7 +669,7 @@ public void NamingConventionSettingsTest05() [Test] public void NamingConventionSettingsTest06() { - var domainConfig = GetDomainConfiguration("DomainWithNamingConvention6"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention6"); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); @@ -670,7 +680,7 @@ public void NamingConventionSettingsTest06() [Test] public void NamingConventionSettingsTest07() { - var domainConfig = GetDomainConfiguration("DomainWithNamingConvention7"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention7"); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); @@ -681,7 +691,7 @@ public void NamingConventionSettingsTest07() [Test] public void NamingConventionSettingsTest08() { - var domainConfig = GetDomainConfiguration("DomainWithNamingConvention8"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention8"); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); @@ -692,7 +702,7 @@ public void NamingConventionSettingsTest08() [Test] public void NamingConventionSettingsTest09() { - var domainConfig = GetDomainConfiguration("DomainWithNamingConvention9"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention9"); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); @@ -703,7 +713,7 @@ public void NamingConventionSettingsTest09() [Test] public void NamingConventionSettingsTest10() { - var domainConfig = GetDomainConfiguration("DomainWithNamingConvention10"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention10"); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); @@ -715,7 +725,7 @@ public void NamingConventionSettingsTest10() [Test] public void NamingConventionSettingsTest11() { - var domainConfig = GetDomainConfiguration("DomainWithNamingConvention11"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention11"); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); @@ -726,19 +736,19 @@ public void NamingConventionSettingsTest11() [Test] public void NamingConventionInvalidSettingsTest1() { - _ = Assert.Throws (()=> GetDomainConfiguration("DomainWithInvalidNamingConvention1")); + _ = Assert.Throws (()=> LoadDomainConfiguration("DomainWithInvalidNamingConvention1")); } [Test] public void NamingConventionInvalidSettingsTest2() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidNamingConvention2")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidNamingConvention2")); } [Test] public void NamingConventionInvalidSettingsTest3() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidNamingConvention3")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidNamingConvention3")); } #endregion @@ -748,7 +758,7 @@ public void NamingConventionInvalidSettingsTest3() [Test] public void VersioningConventionPessimisticTest() { - var domainConfig = GetDomainConfiguration("DomainWithVersioningConvention1"); + var domainConfig = LoadDomainConfiguration("DomainWithVersioningConvention1"); ValidateAllDefault(domainConfig); Assert.That(domainConfig.VersioningConvention.EntityVersioningPolicy, Is.EqualTo(EntityVersioningPolicy.Pessimistic)); Assert.That(domainConfig.VersioningConvention.DenyEntitySetOwnerVersionChange, Is.EqualTo(false)); @@ -757,7 +767,7 @@ public void VersioningConventionPessimisticTest() [Test] public void VersioningConventionOptimisticTest() { - var domainConfig = GetDomainConfiguration("DomainWithVersioningConvention2"); + var domainConfig = LoadDomainConfiguration("DomainWithVersioningConvention2"); ValidateAllDefault(domainConfig); Assert.That(domainConfig.VersioningConvention.EntityVersioningPolicy, Is.EqualTo(EntityVersioningPolicy.Optimistic)); Assert.That(domainConfig.VersioningConvention.DenyEntitySetOwnerVersionChange, Is.EqualTo(false)); @@ -766,7 +776,7 @@ public void VersioningConventionOptimisticTest() [Test] public void VersioningConventionDefaultTest() { - var domainConfig = GetDomainConfiguration("DomainWithVersioningConvention3"); + var domainConfig = LoadDomainConfiguration("DomainWithVersioningConvention3"); ValidateAllDefault(domainConfig); Assert.That(domainConfig.VersioningConvention.EntityVersioningPolicy, Is.EqualTo(EntityVersioningPolicy.Default)); @@ -776,7 +786,7 @@ public void VersioningConventionDefaultTest() [Test] public void VersioningConventionDenyEntitySetChangeVersionTest() { - var domainConfig = GetDomainConfiguration("DomainWithVersioningConvention4"); + var domainConfig = LoadDomainConfiguration("DomainWithVersioningConvention4"); ValidateAllDefault(domainConfig); Assert.That(domainConfig.VersioningConvention.EntityVersioningPolicy, Is.EqualTo(EntityVersioningPolicy.Optimistic)); @@ -786,7 +796,7 @@ public void VersioningConventionDenyEntitySetChangeVersionTest() [Test] public void VersioningConventionAllowEntitySetChangeVersionTest() { - var domainConfig = GetDomainConfiguration("DomainWithVersioningConvention5"); + var domainConfig = LoadDomainConfiguration("DomainWithVersioningConvention5"); ValidateAllDefault(domainConfig); Assert.That(domainConfig.VersioningConvention.EntityVersioningPolicy, Is.EqualTo(EntityVersioningPolicy.Optimistic)); Assert.That(domainConfig.VersioningConvention.DenyEntitySetOwnerVersionChange, Is.EqualTo(false)); @@ -795,7 +805,7 @@ public void VersioningConventionAllowEntitySetChangeVersionTest() [Test] public void VersioningConventionInvalidTest() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidVersioningConvention1")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidVersioningConvention1")); } #endregion @@ -804,7 +814,7 @@ public void VersioningConventionInvalidTest() [Test] public void TypesRegistrationAsTypesTest() { - var domainConfig = GetDomainConfiguration("DomainWithTypes"); + var domainConfig = LoadDomainConfiguration("DomainWithTypes"); ValidateAllDefault(domainConfig); Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.DummyEntity1)), Is.True); Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.DummyEntity2)), Is.True); @@ -814,7 +824,7 @@ public void TypesRegistrationAsTypesTest() [Test] public void TypesRegistrationAsAssembliesTest() { - var domainConfig = GetDomainConfiguration("DomainWithAssemblies"); + var domainConfig = LoadDomainConfiguration("DomainWithAssemblies"); ValidateAllDefault(domainConfig); var ormAssembly = typeof(DomainConfiguration).Assembly; Assert.That(domainConfig.Types.Count, Is.GreaterThan(0)); @@ -824,7 +834,7 @@ public void TypesRegistrationAsAssembliesTest() [Test] public void TypesRegistrationAsAssembliesWithNamespace() { - var domainConfig = GetDomainConfiguration("DomainWithAssembliesAndNamespaces"); + var domainConfig = LoadDomainConfiguration("DomainWithAssembliesAndNamespaces"); ValidateAllDefault(domainConfig); Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.NestedNamespace.DummyNestedEntity1)), Is.True); Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.NestedNamespace.DummyNestedEntity2)), Is.True); @@ -833,7 +843,7 @@ public void TypesRegistrationAsAssembliesWithNamespace() [Test] public void MixedTypeRegistration() { - var domainConfig = GetDomainConfiguration("DomainWithMixedRegistrations"); + var domainConfig = LoadDomainConfiguration("DomainWithMixedRegistrations"); ValidateAllDefault(domainConfig); Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.DummyEntity1)), Is.True); Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.DummyEntity2)), Is.True); @@ -847,7 +857,7 @@ public void InvalidTypeRegistration1() { // same type twice - var domainConfig = GetDomainConfiguration("DomainWithInvalidRegistrations1"); + var domainConfig = LoadDomainConfiguration("DomainWithInvalidRegistrations1"); ValidateAllDefault(domainConfig); Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.DummyEntity1)), Is.True); @@ -859,7 +869,7 @@ public void InvalidTypeRegistration1() public void InvalidTypeRegistration2() { // same Assembly - var domainConfig = GetDomainConfiguration("DomainWithInvalidRegistrations2"); + var domainConfig = LoadDomainConfiguration("DomainWithInvalidRegistrations2"); ValidateAllDefault(domainConfig); var ormAssembly = typeof(DomainConfiguration).Assembly; @@ -871,7 +881,7 @@ public void InvalidTypeRegistration2() public void InvalidTypeRegistration3() { // same assembly and namespace - var domainConfig = GetDomainConfiguration("DomainWithInvalidRegistrations3"); + var domainConfig = LoadDomainConfiguration("DomainWithInvalidRegistrations3"); ValidateAllDefault(domainConfig); Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.NestedNamespace.DummyNestedEntity1)), Is.True); Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.NestedNamespace.DummyNestedEntity2)), Is.True); @@ -880,25 +890,25 @@ public void InvalidTypeRegistration3() [Test] public void InvalidTypeRegistration4() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidRegistrations4")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidRegistrations4")); } [Test] public void InvalidTypeRegistration5() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidRegistrations5")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidRegistrations5")); } [Test] public void InvalidTypeRegistration6() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidRegistrations6")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidRegistrations6")); } [Test] public void InvalidTypeRegistration7() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidRegistrations7")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidRegistrations7")); } #endregion @@ -908,7 +918,7 @@ public void InvalidTypeRegistration7() [Test] public void MultipleSessionsTest() { - var domainConfig = GetDomainConfiguration("DomainWithMultipleSessionConfigurations"); + var domainConfig = LoadDomainConfiguration("DomainWithMultipleSessionConfigurations"); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -932,7 +942,7 @@ public void MultipleSessionsTest() [Test] public void SessionWithEmptyNameTest() { - var domainConfig = GetDomainConfiguration("DomainWithSessionEmptyName"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionEmptyName"); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -945,7 +955,7 @@ public void SessionWithEmptyNameTest() [Test] public void SessionWithCustomNameTest() { - var domainConfig = GetDomainConfiguration("DomainWithSessionCustomName"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomName"); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -960,7 +970,7 @@ public void SessionWithCustomNameTest() [Test] public void SessionWithCustomUserNameTest() { - var domainConfig = GetDomainConfiguration("DomainWithSessionCustomUser"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomUser"); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -974,7 +984,7 @@ public void SessionWithCustomUserNameTest() [Test] public void SessionWithOptionsTest1() { - var domainConfig = GetDomainConfiguration("DomainWithSessionDefaultOptions"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionDefaultOptions"); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -988,7 +998,7 @@ public void SessionWithOptionsTest1() [Test] public void SessionWithOptionsTest2() { - var domainConfig = GetDomainConfiguration("DomainWithSessionServerProfile"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionServerProfile"); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -1002,7 +1012,7 @@ public void SessionWithOptionsTest2() [Test] public void SessionWithOptionsTest3() { - var domainConfig = GetDomainConfiguration("DomainWithSessionClientProfile"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionClientProfile"); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -1016,7 +1026,7 @@ public void SessionWithOptionsTest3() [Test] public void SessionWithOptionsTest4() { - var domainConfig = GetDomainConfiguration("DomainWithSessionCustomOptions"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomOptions"); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -1030,7 +1040,7 @@ public void SessionWithOptionsTest4() [Test] public void SessionWithCollectionSizesTest() { - var domainConfig = GetDomainConfiguration("DomainWithSessionWithCollectionSizes"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionWithCollectionSizes"); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -1046,7 +1056,7 @@ public void SessionWithCollectionSizesTest() [Test] public void SessionCustomCacheTypeTest() { - var domainConfig = GetDomainConfiguration("DomainWithSessionCustomCacheType"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomCacheType"); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -1060,7 +1070,7 @@ public void SessionCustomCacheTypeTest() [Test] public void SessionCustomIsolationLevelTest() { - var domainConfig = GetDomainConfiguration("DomainWithSessionCustomIsolationLevel"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomIsolationLevel"); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -1074,7 +1084,7 @@ public void SessionCustomIsolationLevelTest() [Test] public void SessionCustomCommandTimeoutTest() { - var domainConfig = GetDomainConfiguration("DomainWithSessionCustomCommandTimeout"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomCommandTimeout"); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -1088,7 +1098,7 @@ public void SessionCustomCommandTimeoutTest() [Test] public void SessionCustomPreloadingPolicyTest() { - var domainConfig = GetDomainConfiguration("DomainWithSessionCustomPreloadingPolicy"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomPreloadingPolicy"); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -1102,7 +1112,7 @@ public void SessionCustomPreloadingPolicyTest() [Test] public void SessionCustomConnectionStringTest() { - var domainConfig = GetDomainConfiguration("DomainWithSessionCustomConnectionString"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomConnectionString"); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -1115,7 +1125,7 @@ public void SessionCustomConnectionStringTest() [Test] public void SessionCustomConnectionUrlTest() { - var domainConfig = GetDomainConfiguration("DomainWithSessionCustomConnectionUrl"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomConnectionUrl"); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; Assert.That(sessions.Count, Is.EqualTo(1)); @@ -1127,55 +1137,55 @@ public void SessionCustomConnectionUrlTest() [Test] public void SessionWithInvalidOptions() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithSessionInvalidOptions")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidOptions")); } [Test] public void SessionWithInvalidCacheSizeTest1() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithSessionInvalidCacheSize1")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidCacheSize1")); } [Test] public void SessionWithInvalidCacheSizeTest2() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithSessionInvalidCacheSize2")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidCacheSize2")); } [Test] public void SessionWithInvalidCacheSizeTest3() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithSessionInvalidCacheSize3")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidCacheSize3")); } [Test] public void SessionWithInvalidBatchSizeTest1() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithSessionInvalidBatchSize1")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidBatchSize1")); } [Test] public void SessionWithInvalidBatchSizeTest2() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithSessionInvalidBatchSize2")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidBatchSize2")); } [Test] public void SessionWithInvalidEntityChangeRegistryTest1() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithSessionInvalidEntityChangeRegistry1")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidEntityChangeRegistry1")); } [Test] public void SessionWithInvalidEntityChangeRegistryTest2() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithSessionInvalidEntityChangeRegistry2")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidEntityChangeRegistry2")); } [Test] public void SessionWithInvalidCacheType1() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithSessionInvalidCacheType")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidCacheType")); } #endregion @@ -1185,7 +1195,7 @@ public void SessionWithInvalidCacheType1() [Test] public void DatabaseConfigurationOnlyAliasTest() { - var domainConfig = GetDomainConfiguration("DomainWithDatabases1"); + var domainConfig = LoadDomainConfiguration("DomainWithDatabases1"); ValidateAllDefault(domainConfig); Assert.That(domainConfig.Databases.Count, Is.EqualTo(2)); var db1 = domainConfig.Databases[0]; @@ -1203,7 +1213,7 @@ public void DatabaseConfigurationOnlyAliasTest() [Test] public void DatabaseConfigurationWithTypeIdsTest() { - var domainConfig = GetDomainConfiguration("DomainWithDatabases2"); + var domainConfig = LoadDomainConfiguration("DomainWithDatabases2"); ValidateAllDefault(domainConfig); Assert.That(domainConfig.Databases.Count, Is.EqualTo(2)); var db1 = domainConfig.Databases[0]; @@ -1221,25 +1231,25 @@ public void DatabaseConfigurationWithTypeIdsTest() [Test] public void DatabaseConfigurationNegativeMinTypeIdTest() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidDatabases1")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidDatabases1")); } [Test] public void DatabaseConfigurationInvalidMinTypeIdTest() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidDatabases2")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidDatabases2")); } [Test] public void DatabaseConfigurationNegativeMaxTypeIdTest() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidDatabases3")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidDatabases3")); } [Test] public void DatabaseConfigurationInvalidMaxTypeIdTest() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidDatabases4")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidDatabases4")); } #endregion @@ -1251,7 +1261,7 @@ public void SimpleKeyGeneratorTest() { if (!NameAttributeUnique) throw new IgnoreException(""); - var domainConfig = GetDomainConfiguration("DomainWithCustomGenerator"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomGenerator"); ValidateAllDefault(domainConfig); } @@ -1260,7 +1270,7 @@ public void KeyGeneratorWithDatabaseNamesTest() { if (!NameAttributeUnique) throw new IgnoreException(""); - var domainConfig = GetDomainConfiguration("DomainWithCustomGeneratorsWithDatabaseNames"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomGeneratorsWithDatabaseNames"); ValidateAllDefault(domainConfig); } @@ -1269,7 +1279,7 @@ public void KeyGeneratorWithDatabaseNamesAllParamsTest() { if (!NameAttributeUnique) throw new IgnoreException(""); - var domainConfig = GetDomainConfiguration("DomainWithCustomGeneratorsWithDatabaseNamesAndKeyParams"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomGeneratorsWithDatabaseNamesAndKeyParams"); ValidateAllDefault(domainConfig); } @@ -1278,7 +1288,7 @@ public void KeyGeneratorsWithDatabaseAliasesTest() { if (!NameAttributeUnique) throw new IgnoreException(""); - var domainConfig = GetDomainConfiguration("DomainWithCustomGeneratorsWithDatabasesAliases"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomGeneratorsWithDatabasesAliases"); ValidateAllDefault(domainConfig); } @@ -1287,7 +1297,7 @@ public void KeyGeneratorsWithConflictByDatabaseTest1() { if (!NameAttributeUnique) throw new IgnoreException(""); - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithCustomGeneratorsConflict1")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomGeneratorsConflict1")); } [Test] @@ -1295,7 +1305,7 @@ public void KeyGeneratorsWithConflictByDatabaseTest2() { if (!NameAttributeUnique) throw new IgnoreException(""); - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithCustomGeneratorsConflict2")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomGeneratorsConflict2")); } [Test] @@ -1303,7 +1313,7 @@ public void KeyGeneratorWithNegativeSeedTest() { if (!NameAttributeUnique) throw new IgnoreException(""); - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithCustomGeneratorNegativeSeed")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomGeneratorNegativeSeed")); } [Test] @@ -1311,7 +1321,7 @@ public void KeyGeneratorWithNegativeCacheSizeTest() { if (!NameAttributeUnique) throw new IgnoreException(""); - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithCustomGeneratorNegativeCache")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomGeneratorNegativeCache")); } #endregion @@ -1321,7 +1331,7 @@ public void KeyGeneratorWithNegativeCacheSizeTest() [Test] public void IgnoreRulesTest() { - var domainConfig = GetDomainConfiguration("DomainWithIgnoreRules"); + var domainConfig = LoadDomainConfiguration("DomainWithIgnoreRules"); ValidateAllDefault(domainConfig); ValidateIgnoreRules(domainConfig.IgnoreRules); } @@ -1329,25 +1339,25 @@ public void IgnoreRulesTest() [Test] public void IgnoreColumnAndIndexAtTheSameTimeTest() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidIgnoreRules1")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidIgnoreRules1")); } [Test] public void IgnoreTableAndColumnAndIndexAtTheSameTimeTest() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidIgnoreRules2")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidIgnoreRules2")); } [Test] public void IgnoreDatabaseOnlyTest() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidIgnoreRules3")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidIgnoreRules3")); } [Test] public void IgnoreDatabaseAndSchemaOnlyTest() { - _ = Assert.Throws(() => GetDomainConfiguration("DomainWithInvalidIgnoreRules4")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidIgnoreRules4")); } private void ValidateIgnoreRules(IgnoreRuleCollection rules) @@ -1488,7 +1498,7 @@ private void ValidateIgnoreRules(IgnoreRuleCollection rules) [Test] public void MappingRulesTest1() { - var domainConfig = GetDomainConfiguration("DomainWithMappingRules1"); + var domainConfig = LoadDomainConfiguration("DomainWithMappingRules1"); ValidateAllDefaultExcept(domainConfig, ((d) => d.DefaultDatabase, "main"), ((d) => d.DefaultSchema, "dbo"), @@ -1507,7 +1517,7 @@ public void MappingRulesTest1() [Test] public void MappingRulesTest2() { - var domainConfig = GetDomainConfiguration("DomainWithMappingRules2"); + var domainConfig = LoadDomainConfiguration("DomainWithMappingRules2"); ValidateAllDefaultExcept(domainConfig, ((d) => d.DefaultDatabase, "main"), ((d) => d.DefaultSchema, "dbo"), @@ -1528,7 +1538,7 @@ public void MappingRulesTest2() [Test] public void MappingRulesTest3() { - var domainConfig = GetDomainConfiguration("DomainWithMappingRules3"); + var domainConfig = LoadDomainConfiguration("DomainWithMappingRules3"); ValidateAllDefaultExcept(domainConfig, ((d) => d.DefaultDatabase, "main"), ((d) => d.DefaultSchema, "dbo"), @@ -1548,7 +1558,7 @@ public void MappingRulesTest3() [Test] public void MappingRulesTest4() { - var domainConfig = GetDomainConfiguration("DomainWithMappingRules4"); + var domainConfig = LoadDomainConfiguration("DomainWithMappingRules4"); ValidateAllDefaultExcept(domainConfig, ((d) => d.DefaultDatabase, "main"), ((d) => d.DefaultSchema, "dbo"), @@ -1568,7 +1578,7 @@ public void MappingRulesTest4() [Test] public void MappingRulesTest5() { - var domainConfig = GetDomainConfiguration("DomainWithMappingRules5"); + var domainConfig = LoadDomainConfiguration("DomainWithMappingRules5"); ValidateAllDefaultExcept(domainConfig, ((d) => d.DefaultDatabase, "main"), ((d) => d.DefaultSchema, "dbo"), @@ -1588,7 +1598,7 @@ public void MappingRulesTest5() [Test] public void MappingRulesTest6() { - var domainConfig = GetDomainConfiguration("DomainWithMappingRules6"); + var domainConfig = LoadDomainConfiguration("DomainWithMappingRules6"); ValidateAllDefaultExcept(domainConfig, ((d) => d.DefaultDatabase, "main"), ((d) => d.DefaultSchema, "dbo"), @@ -1607,7 +1617,7 @@ public void MappingRulesTest6() [Test] public void MappingRulesTest7() { - var domainConfig = GetDomainConfiguration("DomainWithMappingRules7"); + var domainConfig = LoadDomainConfiguration("DomainWithMappingRules7"); ValidateAllDefaultExcept(domainConfig, ((d) => d.DefaultDatabase, "main"), ((d) => d.DefaultSchema, "dbo"), @@ -1627,54 +1637,101 @@ public void MappingRulesTest7() public void MappingRuleWithConflictByAssemblyTest() { var exception = Assert.Throws( - () => GetDomainConfiguration("DomainWithConflictMappingRules1")); + () => LoadDomainConfiguration("DomainWithConflictMappingRules1")); } [Test] public void MappingRuleWithConflictByNamespaceTest() { var exception = Assert.Throws( - () => GetDomainConfiguration("DomainWithConflictMappingRules2")); + () => LoadDomainConfiguration("DomainWithConflictMappingRules2")); } [Test] public void MappingRulesInvalidTest1() { var exception = Assert.Throws( - () => GetDomainConfiguration("DomainWithInvalidMappingRules1")); + () => LoadDomainConfiguration("DomainWithInvalidMappingRules1")); } [Test] public void MappingRulesInvalidTest2() { var exception = Assert.Throws( - () => GetDomainConfiguration("DomainWithInvalidMappingRules2")); + () => LoadDomainConfiguration("DomainWithInvalidMappingRules2")); } [Test] public void MappingRulesInvalidTest3() { var exception = Assert.Throws( - () => GetDomainConfiguration("DomainWithInvalidMappingRules3")); + () => LoadDomainConfiguration("DomainWithInvalidMappingRules3")); } [Test] public void MappingRulesInvalidTest4() { var exception = Assert.Throws( - () => GetDomainConfiguration("DomainWithInvalidMappingRules4")); + () => LoadDomainConfiguration("DomainWithInvalidMappingRules4")); } [Test] public void MappingRulesInvalidTest5() { var exception = Assert.Throws( - () => GetDomainConfiguration("DomainWithInvalidMappingRules5")); + () => LoadDomainConfiguration("DomainWithInvalidMappingRules5")); } #endregion + #region Logging + + [Test] + public void LoggingConfigurationTest() + { + var configuration = LoadLoggingConfiguration(); + ValidateLoggingConfiguration(configuration); + } + + [Test] + public void LoggingEmptyLoggingSectionTest() + { + var section = configuration.GetSection($"Xtensive.Orm.EmptyLogging.{Postfix}"); + _ = Assert.Throws(() => LoadLoggingConfiguration(section)); + } + + [Test] + public void LoggingEmptyLogsTest() + { + if (Postfix == "AppConfig") + throw new IgnoreException(""); + + var section = configuration.GetSection($"Xtensive.Orm.EmptyLogs.{Postfix}"); + _ = Assert.Throws(() => LoadLoggingConfiguration(section)); + } + + [Test] + public void LoggingOnlyProviderDeclaredTest() + { + var section = configuration.GetSection($"Xtensive.Orm.OnlyLogProvider.{Postfix}"); + var loggingConfig = LoadLoggingConfiguration(section); + Assert.That(loggingConfig.Logs.Count, Is.EqualTo(0)); + Assert.That(loggingConfig.Provider, Is.EqualTo("Xtensive.Orm.Logging.log4net.LogProvider")); + } + + [Test] + public void LoggingProviderAndEmptyLogsTest() + { + if (Postfix == "AppConfig") + throw new IgnoreException(""); + + var section = configuration.GetSection($"Xtensive.Orm.LogProviderAndEmptyLogs.{Postfix}"); + var loggingConfig = LoadLoggingConfiguration(section); + Assert.That(loggingConfig.Logs.Count, Is.EqualTo(0)); + Assert.That(loggingConfig.Provider, Is.EqualTo("Xtensive.Orm.Logging.log4net.LogProvider")); + } + #endregion private void ValidateAllDefault(DomainConfiguration domainConfiguration) { @@ -1865,7 +1922,7 @@ private void ValidateAllDefaultExcept(TConfigura throw new ArgumentOutOfRangeException(nameof(configuration)); } - public bool TryExtractPropertyFormLambda(Expression> lambda, + private bool TryExtractPropertyFormLambda(Expression> lambda, out System.Reflection.PropertyInfo property) { if (lambda.Body.StripCasts() is MemberExpression mExpression && mExpression.Member is System.Reflection.PropertyInfo prop) { @@ -1989,5 +2046,32 @@ private void ValidateAllPropertiesExcept(SessionConfiguration sessionConfigurati if (!nameof(sessionConfiguration.ConnectionInfo).In(excludedProperties)) Assert.That(sessionConfiguration.ConnectionInfo, Is.Null); } + + private void ValidateLoggingConfiguration(LoggingConfiguration configuration) + { + Assert.That(configuration.Provider, Is.Not.Null.Or.Empty); + Assert.That(configuration.Provider, Is.EqualTo("Xtensive.Orm.Logging.log4net.LogProvider")); + + Assert.That(configuration.Logs[0].Source, Is.EqualTo("*")); + Assert.That(configuration.Logs[0].Target, Is.EqualTo("Console")); + + Assert.That(configuration.Logs[1].Source, Is.EqualTo("SomeLogName")); + Assert.That(configuration.Logs[1].Target, Is.EqualTo("DebugOnlyConsole")); + + Assert.That(configuration.Logs[2].Source, Is.EqualTo("FirstLogName,SecondLogName")); + Assert.That(configuration.Logs[2].Target, Is.EqualTo(@"d:\log.txt")); + + Assert.That(configuration.Logs[3].Source, Is.EqualTo("LogName, AnotherLogName")); + Assert.That(configuration.Logs[3].Target, Is.EqualTo("Console")); + + Assert.That(configuration.Logs[4].Source, Is.EqualTo("FileLog")); + Assert.That(configuration.Logs[4].Target, Is.EqualTo("log.txt")); + + Assert.That(configuration.Logs[5].Source, Is.EqualTo("NullLog")); + Assert.That(configuration.Logs[5].Target, Is.EqualTo("None")); + + Assert.That(configuration.Logs[6].Source, Is.EqualTo("Trash")); + Assert.That(configuration.Logs[6].Target, Is.EqualTo("skjdhfjsdf sdfsdfksjdghj fgdfg")); + } } } diff --git a/Orm/Xtensive.Orm.Tests/domainSettings.config b/Orm/Xtensive.Orm.Tests/domainSettings.config index b2c4333fa6..7b6c54deb4 100644 --- a/Orm/Xtensive.Orm.Tests/domainSettings.config +++ b/Orm/Xtensive.Orm.Tests/domainSettings.config @@ -879,7 +879,27 @@ + + + + + + + + + + + + + + + + + + + + @@ -2374,5 +2394,60 @@ + + Xtensive.Orm.Logging.log4net.LogProvider + + + * + Console + + + SomeLogName + DebugOnlyConsole + + + FirstLogName,SecondLogName + d:\log.txt + + + LogName, AnotherLogName + Console + + + FileLog + log.txt + + + NullLog + None + + + Trash + skjdhfjsdf sdfsdfksjdghj fgdfg + + + + + + + + + + + + + + + + Xtensive.Orm.Logging.log4net.LogProvider + + + + + Xtensive.Orm.Logging.log4net.LogProvider + + + + \ No newline at end of file diff --git a/Orm/Xtensive.Orm.Tests/domainSettings.json b/Orm/Xtensive.Orm.Tests/domainSettings.json index c4ac8fef8e..7dde27cf13 100644 --- a/Orm/Xtensive.Orm.Tests/domainSettings.json +++ b/Orm/Xtensive.Orm.Tests/domainSettings.json @@ -1409,6 +1409,60 @@ } } } + }, + "Logging": { + "Provider": "Xtensive.Orm.Logging.log4net.LogProvider", + "Logs": [ + { + "Source": "*", + "Target": "Console" + }, + { + "Source": "SomeLogName", + "Target": "DebugOnlyConsole" + }, + { + "Source": "FirstLogName,SecondLogName", + "Target": "d:\\log.txt" + }, + { + "Source": "LogName, AnotherLogName", + "Target": "Console" + }, + { + "Source": "FileLog", + "Target": "log.txt" + }, + { + "Source": "NullLog", + "Target": "None" + }, + { + "Source": "Trash", + "Target": "skjdhfjsdf sdfsdfksjdghj fgdfg" + } + ] + } + }, + "Xtensive.Orm.EmptyLogging.Json": { + "Logging": { + + } + }, + "Xtensive.Orm.EmptyLogs.Json": { + "Logging": { + "Logs": [] + } + }, + "Xtensive.Orm.OnlyLogProvider.Json": { + "Logging": { + "Provider": "Xtensive.Orm.Logging.log4net.LogProvider" + } + }, + "Xtensive.Orm.LogProviderAndEmptyLogs.Json": { + "Logging": { + "Provider": "Xtensive.Orm.Logging.log4net.LogProvider", + "Logs": [] } } } diff --git a/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs b/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs index 8975e4e86f..c83ee968f2 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs @@ -80,6 +80,16 @@ public static LoggingConfiguration Load(System.Configuration.Configuration confi return loggingConfiguration; } + public static LoggingConfiguration Load(IConfigurationSection configurationSection) + { + throw new NotImplementedException(); + } + + public static LoggingConfiguration Load(IConfigurationRoot configurationRoot, string sectionName = null) + { + throw new NotImplementedException(); + } + /// /// Creates instance of this class. /// From 925a1b1da79514a35f0567f54b4d3df3c0d71077 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Tue, 17 Sep 2024 16:29:57 +0500 Subject: [PATCH 12/32] Implement Sections-to-LoggingConfiguration parser --- .../ConfigurationSectionExtensions.cs | 33 +++++ .../Internals/DomainConfigurationParsers.cs | 117 +++++++++++++----- .../Orm/Configuration/LoggingConfiguration.cs | 4 +- 3 files changed, 119 insertions(+), 35 deletions(-) create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Internals/ConfigurationSectionExtensions.cs diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Internals/ConfigurationSectionExtensions.cs b/Orm/Xtensive.Orm/Orm/Configuration/Internals/ConfigurationSectionExtensions.cs new file mode 100644 index 0000000000..d2d4d6c19c --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Internals/ConfigurationSectionExtensions.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; +using Xtensive.Collections; + +namespace Xtensive.Orm.Configuration.Internals +{ + internal static class ConfigurationSectionExtensions + { + public static IEnumerable GetSelfOrChildren(this IConfigurationSection section, bool requiredName = false) + { + var children = section.GetChildren().ToList(); + if (children.Count > 0) { + if (requiredName) { + var anyItemWithName = children.Any(i => i["name"] != null); + if (anyItemWithName) { + return children; + } + } + var firstChild = children[0]; + var isIndexed = firstChild.Key == "0"; + if (isIndexed) + return children; + else + return EnumerableUtils.One(section); + } + return children; + } + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Internals/DomainConfigurationParsers.cs b/Orm/Xtensive.Orm/Orm/Configuration/Internals/DomainConfigurationParsers.cs index 6eab250774..e5bbe74bc1 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Internals/DomainConfigurationParsers.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Internals/DomainConfigurationParsers.cs @@ -8,23 +8,92 @@ using System.Linq; using Microsoft.Extensions.Configuration; using Xtensive.Collections; +using Xtensive.Core; using Xtensive.Orm.Configuration.Options; namespace Xtensive.Orm.Configuration.Internals { - internal interface IConfigurationSectionParser + internal interface IConfigurationSectionParser { - DomainConfiguration Parse(IConfiguration configuration); + TConfiguration Parse(IConfiguration configuration); - DomainConfiguration Parse(IConfigurationRoot configuration, string sectionName); + TConfiguration Parse(IConfigurationRoot configuration, string sectionName); + } + + internal sealed class LoggingConfigurationParser : IConfigurationSectionParser + { + private const string LoggingSectionName = "Logging"; + private const string LogsSectionName = "Logs"; + + private const string ProviderElementName = "Provider"; + private const string LogElementName = "Log"; + private const string LogSourceElementName = "Source"; + private const string LogTargerElementName = "Target"; + + public LoggingConfiguration Parse(IConfiguration configuration) + { + ArgumentValidator.EnsureArgumentNotNull(configuration, nameof(configuration)); + + if (configuration is IConfigurationRoot configurationRoot) { + return Parse(configurationRoot, WellKnown.DefaultConfigurationSection); + } + else if (configuration is IConfigurationSection configurationSection) { + return Parse(configurationSection); + } + throw new InvalidOperationException(""); + } + + public LoggingConfiguration Parse(IConfigurationRoot configuration, string sectionName) + { + ArgumentValidator.EnsureArgumentNotNull(configuration, nameof(configuration)); + ArgumentValidator.EnsureArgumentNotNullOrEmpty(sectionName, nameof(sectionName)); + + return Parse(configuration.GetSection(sectionName)); + } + + public LoggingConfiguration Parse(IConfigurationSection configurationSection) + { + ArgumentValidator.EnsureArgumentNotNull(configurationSection, nameof(configurationSection)); - DomainConfiguration Parse(IConfigurationSection domainConfiguration, Dictionary connectionStrings = null); + var ormConfigurationSection = configurationSection; + var loggingSection = ormConfigurationSection.GetSection(LoggingSectionName); + + if (loggingSection != null && loggingSection.GetChildren().Any()) { + var provider = loggingSection.GetSection(ProviderElementName)?.Value; + var logsSection = loggingSection.GetSection(LogsSectionName); + IConfigurationSection logElement; + + if (logsSection != null && logsSection.GetChildren().Any()) { + logElement = logsSection.GetSection(LogElementName); + if (logElement == null || !logElement.GetChildren().Any()) { + logElement = logsSection; + } + } + else { + logElement = loggingSection.GetSection(LogElementName); + } + + var configuration = new LoggingConfiguration(provider); + + foreach (var logItem in logElement.GetSelfOrChildren()) { + var source = logItem.GetSection(LogSourceElementName).Value; + var target = logItem.GetSection(LogTargerElementName).Value; + if (source.IsNullOrEmpty() || target.IsNullOrEmpty()) + throw new InvalidOperationException(); + configuration.Logs.Add(new LogConfiguration(source, target)); + } + + return configuration; + } + + throw new InvalidOperationException( + string.Format(Strings.ExSectionIsNotFoundInApplicationConfigurationFile, WellKnown.DefaultConfigurationSection)); + } } internal sealed class XmlDomainConfigParser : DomainConfigurationParser { - protected override void ProcessNamingConvention(IConfigurationSection namingConventionSection, DomainConfigurationOptions domainConfiguratonOptions) { if (namingConventionSection == null) { @@ -37,7 +106,8 @@ protected override void ProcessNamingConvention(IConfigurationSection namingConv if (namingConvetion!= null) { var synonymsSection = namingConventionSection.GetSection(NamespaceSynonymSectionName); var synonyms = synonymsSection != null && synonymsSection.GetChildren().Any() - ? GetSelfOrChildren(synonymsSection.GetSection(SynonymElementName)) + ? synonymsSection.GetSection(SynonymElementName) + .GetSelfOrChildren() .Select(s => s.Get()) .Where(ns => ns != null) .ToArray() @@ -85,7 +155,8 @@ private bool TryProcessTypeRegistrationsWithAttributes(IConfigurationSection typ { var registrations = typesSection.GetSection(OldStyleTypeRegistrationElementName); if (registrations != null && registrations.GetChildren().Any()) { - domainConfigurationOptions.Types = GetSelfOrChildren(registrations) + domainConfigurationOptions.Types = registrations + .GetSelfOrChildren() .Select(s => s.Get()) .Where(tr => tr != null) .ToArray(); @@ -101,7 +172,8 @@ private bool TryProcessTypeRegistrationsWithNodes(IConfigurationSection typesSec if (registrations == null) return false; - domainConfigurationOptions.Types = GetSelfOrChildren(registrations) + domainConfigurationOptions.Types = registrations + .GetSelfOrChildren() .Select(s => s.Get()) .Where(tr => tr != null) .ToArray(); @@ -116,7 +188,7 @@ protected override void ProcessDatabases(IConfigurationSection databasesSection, var databaseElement = databasesSection.GetSection(DatabaseElementName); if (databaseElement == null) return; - foreach (var section in GetSelfOrChildren(databaseElement, true)) { + foreach (var section in databaseElement.GetSelfOrChildren(true)) { var dbItem = section.Get(); if (dbItem == null) continue; @@ -150,7 +222,7 @@ protected override void ProcessSessions(IConfigurationSection sessionsSection, O var sessionElement = sessionsSection.GetSection(SessionElementName); if (sessionElement == null) return; - foreach (var section in GetSelfOrChildren(sessionElement, true)) { + foreach (var section in sessionElement.GetSelfOrChildren(true)) { var sessionItem = section.Get(); if (sessionItem == null) continue; @@ -166,36 +238,15 @@ private void ProcessCollectionOfOptions(IConfigurationSection collectio var collectionElement = collectionSection.GetSection(itemKey); if (collectionElement == null) return; - foreach (var item in GetSelfOrChildren(collectionElement)) { + foreach (var item in collectionElement.GetSelfOrChildren()) { var optItem = item.Get(); collection.Add(optItem); } } - - private IEnumerable GetSelfOrChildren(IConfigurationSection section, bool requiredName = false) - { - var children = section.GetChildren().ToList(); - if (children.Count > 0) { - if (requiredName) { - var anyItemWithName = children.Any(i => i["name"] != null); - if (anyItemWithName) { - return children; - } - } - var firstChild = children[0]; - var isIndexed = firstChild.Key == "0"; - if (isIndexed) - return children; - else - return EnumerableUtils.One(section); - } - return children; - } } internal class FromJsonToDomainConfigurationParser : DomainConfigurationParser { - protected override void ProcessNamingConvention(IConfigurationSection namingConventionSection, DomainConfigurationOptions domainConfiguratonOptions) { if (namingConventionSection == null || !namingConventionSection.GetChildren().Any()) @@ -207,7 +258,7 @@ protected override void ProcessNamingConvention(IConfigurationSection namingConv } } - internal abstract class DomainConfigurationParser : IConfigurationSectionParser + internal abstract class DomainConfigurationParser : IConfigurationSectionParser { protected const string RuleElementName = "Rule"; protected const string KeyGeneratorElementName = "KeyGenerator"; diff --git a/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs b/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs index c83ee968f2..9ef4a6aff8 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs @@ -82,12 +82,12 @@ public static LoggingConfiguration Load(System.Configuration.Configuration confi public static LoggingConfiguration Load(IConfigurationSection configurationSection) { - throw new NotImplementedException(); + return new LoggingConfigurationParser().Parse(configurationSection); } public static LoggingConfiguration Load(IConfigurationRoot configurationRoot, string sectionName = null) { - throw new NotImplementedException(); + return new LoggingConfigurationParser().Parse(configurationRoot, sectionName); } /// From 8d6da21f046fb761bc35f2129f48dd84bf6b5b98 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Mon, 23 Sep 2024 18:07:22 +0500 Subject: [PATCH 13/32] Made interfaces have their own file --- .../Options/Interfaces/IHasDatabaseOption.cs | 26 +++++++++++++++++++ .../Interfaces/IIdentifyableOptions.cs | 23 +++------------- .../INamedOptionsCollectionElement.cs | 4 +-- .../Interfaces/IToNativeConvertable.cs | 4 +-- ...ctionElement.cs => IValidatableOptions.cs} | 11 ++++---- 5 files changed, 37 insertions(+), 31 deletions(-) create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IHasDatabaseOption.cs rename Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/{IOptionsCollectionElement.cs => IValidatableOptions.cs} (50%) diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IHasDatabaseOption.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IHasDatabaseOption.cs new file mode 100644 index 0000000000..0b6cb6bf2f --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IHasDatabaseOption.cs @@ -0,0 +1,26 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System.Collections.Generic; + +namespace Xtensive.Orm.Configuration.Options +{ + internal interface IHasDatabaseOption : IIdentifyableOptions + { + /// + /// Database (real or alias). In cases when database is part of instance identifier + /// it might require to be mapped + /// + string Database { get; set; } + + /// + /// Tries to map database part of identifier from alias to real database names. + /// It might be required if declare + /// aliases and + /// + /// Map of databases + /// If alias is used then new identifier with substituted alias, otherwise, the same identifier. + object GetMappedIdentifier(IDictionary databaseMap); + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IIdentifyableOptions.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IIdentifyableOptions.cs index e665d94eb8..4b71870d31 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IIdentifyableOptions.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IIdentifyableOptions.cs @@ -1,32 +1,15 @@ -// Copyright (C) 2007-2022 Xtensive LLC. +// Copyright (C) 2024 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. -// Created by: Dmitri Maximov -// Created: 2007.08.03 -using System; -using System.Collections.Generic; namespace Xtensive.Orm.Configuration.Options { internal interface IIdentifyableOptions - { - object Identifier { get; } - } - - internal interface IValidatableOptions { /// - /// Performs validation of properties + /// Identifier of options instance in collections where uniqueness is required. /// - void Validate(); - } - - internal interface IHasDatabaseOption : IIdentifyableOptions - { - string Database { get; set; } - - object GetMappedIdentifier(IDictionary databaseMap); + object Identifier { get; } } - } diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/INamedOptionsCollectionElement.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/INamedOptionsCollectionElement.cs index 5f02e3d7af..4d42dddb01 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/INamedOptionsCollectionElement.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/INamedOptionsCollectionElement.cs @@ -1,8 +1,6 @@ -// Copyright (C) 2007-2022 Xtensive LLC. +// Copyright (C) 2024 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. -// Created by: Dmitri Maximov -// Created: 2007.08.03 namespace Xtensive.Orm.Configuration.Options { diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IToNativeConvertable.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IToNativeConvertable.cs index 8ad5b978a2..71a90ef825 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IToNativeConvertable.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IToNativeConvertable.cs @@ -1,8 +1,6 @@ -// Copyright (C) 2007-2022 Xtensive LLC. +// Copyright (C) 2024 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. -// Created by: Dmitri Maximov -// Created: 2007.08.03 namespace Xtensive.Orm.Configuration.Options { diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IOptionsCollectionElement.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IValidatableOptions.cs similarity index 50% rename from Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IOptionsCollectionElement.cs rename to Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IValidatableOptions.cs index 1ebdf74bcb..707ca81d67 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IOptionsCollectionElement.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/Interfaces/IValidatableOptions.cs @@ -1,13 +1,14 @@ -// Copyright (C) 2007-2022 Xtensive LLC. +// Copyright (C) 2024 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. -// Created by: Dmitri Maximov -// Created: 2007.08.03 namespace Xtensive.Orm.Configuration.Options { - internal interface IOptionsCollectionElement + internal interface IValidatableOptions { - + /// + /// Performs validation of properties. + /// + void Validate(); } } From b5ad889e1ca44d819519c01fc4455744ae13a408 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Mon, 23 Sep 2024 18:08:21 +0500 Subject: [PATCH 14/32] IConfigurationSectionParser -> IConfigurationSectionReader --- .../Orm/Configuration/DomainConfiguration.cs | 29 +-- .../IConfigurationSectionReader{T}.cs | 55 ++++++ ...rsers.cs => DomainConfigurationReaders.cs} | 181 ++++++++---------- .../Internals/LoggingConfigurationReader.cs | 94 +++++++++ .../Orm/Configuration/LoggingConfiguration.cs | 6 +- 5 files changed, 251 insertions(+), 114 deletions(-) create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Interfaces/IConfigurationSectionReader{T}.cs rename Orm/Xtensive.Orm/Orm/Configuration/Internals/{DomainConfigurationParsers.cs => DomainConfigurationReaders.cs} (72%) create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Internals/LoggingConfigurationReader.cs diff --git a/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs b/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs index f28ddea87c..d28560d18e 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs @@ -881,20 +881,21 @@ private static DomainConfiguration LoadConfigurationFromSection(ConfigurationSec /// The "domains" section is not found or domain with requested name is not found. public static DomainConfiguration Load(IConfigurationSection configurationSection, string name) { - var allDomainsSection = configurationSection.GetSection("Domains"); - if (allDomainsSection != null && allDomainsSection.GetChildren().Any()) { - var domainSection = allDomainsSection.GetSection(name); - if (domainSection.GetChildren().Any()) { - var parseResult = new FromJsonToDomainConfigurationParser().Parse(domainSection); - if (parseResult != null) - return parseResult; - } - else if ((domainSection = allDomainsSection.GetSection($"Domain:{name}")).GetChildren().Any()) { - var parseResult = new XmlDomainConfigParser().Parse(domainSection); - if (parseResult != null) - return parseResult; - } - } + ArgumentValidator.EnsureArgumentNotNull(configurationSection, nameof(configurationSection)); + + var jsonParser = new JsonToDomainConfigurationReader(); + var xmlParser = new XmlToDomainConfigurationReader(); + + var parseResult = jsonParser.Read(configurationSection, name); + if (parseResult != null) + return parseResult; + parseResult = xmlParser.Read(configurationSection, name); + if (parseResult != null) + return parseResult; + + throw new InvalidOperationException(string.Format( + Strings.ExConfigurationForDomainIsNotFoundInApplicationConfigurationFile, name, sectionName)); + } throw new InvalidOperationException(string.Format( Strings.ExConfigurationForDomainIsNotFoundInApplicationConfigurationFile, name, sectionName)); diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Interfaces/IConfigurationSectionReader{T}.cs b/Orm/Xtensive.Orm/Orm/Configuration/Interfaces/IConfigurationSectionReader{T}.cs new file mode 100644 index 0000000000..9227e82b2f --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Interfaces/IConfigurationSectionReader{T}.cs @@ -0,0 +1,55 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + + +using Microsoft.Extensions.Configuration; + +namespace Xtensive.Orm.Configuration +{ + /// + /// Reads certain type of configuration (DomainConfiguration, LoggingConfiguration, etc.) from IConfigurationSection API + /// + /// + public interface IConfigurationSectionReader + { + /// + /// Reads configuration from given configuration section. + /// + /// Root configuration section where specific configuration is placed (for domain configuration - where all domain configurations). + /// Instance of configuration. + TConfiguration Read(IConfigurationSection configurationSection); + + /// + /// Reads configuration from given configuration section with specified name (if named configuration supported e.g. doman configuration) + /// + /// Root configuration section where specific configuration is placed (for domain configuration - where all domain configurations). + /// Name of configuration. + /// Instance of configuration. + TConfiguration Read(IConfigurationSection configurationSection, string nameOfConfiguration); + + /// + /// Reads configuration (with default name if name is required) from default section (and with default name) from given configuration root. + /// + /// Root of all configuration sections. + /// Instance of configuration. + TConfiguration Read(IConfigurationRoot configurationRoot); + + /// + /// Reads configuration (with default name if name is required) from given section of given configuration root. + /// + /// Root of all configuration sections. + /// Specific section name from which configuration should be read. + /// Instance of configuration. + TConfiguration Read(IConfigurationRoot configurationRoot, string sectionName); + + /// + /// Reads configuration with given name from given section of given configuration root. + /// + /// Root of all configuration sections. + /// Specific section name from which configuration should be read. + /// Name of configuration. + /// Instance of configuration. + TConfiguration Read(IConfigurationRoot configurationRoot, string sectionName, string nameOfConfiguration); + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Internals/DomainConfigurationParsers.cs b/Orm/Xtensive.Orm/Orm/Configuration/Internals/DomainConfigurationReaders.cs similarity index 72% rename from Orm/Xtensive.Orm/Orm/Configuration/Internals/DomainConfigurationParsers.cs rename to Orm/Xtensive.Orm/Orm/Configuration/Internals/DomainConfigurationReaders.cs index e5bbe74bc1..32e9b99a66 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Internals/DomainConfigurationParsers.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Internals/DomainConfigurationReaders.cs @@ -7,93 +7,22 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Configuration; -using Xtensive.Collections; using Xtensive.Core; using Xtensive.Orm.Configuration.Options; namespace Xtensive.Orm.Configuration.Internals { - internal interface IConfigurationSectionParser + internal sealed class XmlToDomainConfigurationReader : DomainConfigurationReader { - TConfiguration Parse(IConfiguration configuration); - - TConfiguration Parse(IConfigurationRoot configuration, string sectionName); - } - - internal sealed class LoggingConfigurationParser : IConfigurationSectionParser - { - private const string LoggingSectionName = "Logging"; - private const string LogsSectionName = "Logs"; - - private const string ProviderElementName = "Provider"; - private const string LogElementName = "Log"; - private const string LogSourceElementName = "Source"; - private const string LogTargerElementName = "Target"; - - public LoggingConfiguration Parse(IConfiguration configuration) - { - ArgumentValidator.EnsureArgumentNotNull(configuration, nameof(configuration)); - - if (configuration is IConfigurationRoot configurationRoot) { - return Parse(configurationRoot, WellKnown.DefaultConfigurationSection); - } - else if (configuration is IConfigurationSection configurationSection) { - return Parse(configurationSection); - } - throw new InvalidOperationException(""); - } - - public LoggingConfiguration Parse(IConfigurationRoot configuration, string sectionName) + protected override bool ValidateCorrectFormat(IConfigurationSection allDomainsSection, string domainName) { - ArgumentValidator.EnsureArgumentNotNull(configuration, nameof(configuration)); - ArgumentValidator.EnsureArgumentNotNullOrEmpty(sectionName, nameof(sectionName)); - - return Parse(configuration.GetSection(sectionName)); + return !allDomainsSection.GetSection(domainName).GetChildren().Any() + && allDomainsSection.GetSection(string.Format(NamedDomainTemplate, domainName)).GetChildren().Any(); } - public LoggingConfiguration Parse(IConfigurationSection configurationSection) - { - ArgumentValidator.EnsureArgumentNotNull(configurationSection, nameof(configurationSection)); + protected override IConfigurationSection GetDomainSection(IConfigurationSection allDomainsSection, string domainName) => + allDomainsSection.GetSection(string.Format(NamedDomainTemplate, domainName)); - var ormConfigurationSection = configurationSection; - - var loggingSection = ormConfigurationSection.GetSection(LoggingSectionName); - - if (loggingSection != null && loggingSection.GetChildren().Any()) { - var provider = loggingSection.GetSection(ProviderElementName)?.Value; - var logsSection = loggingSection.GetSection(LogsSectionName); - IConfigurationSection logElement; - - if (logsSection != null && logsSection.GetChildren().Any()) { - logElement = logsSection.GetSection(LogElementName); - if (logElement == null || !logElement.GetChildren().Any()) { - logElement = logsSection; - } - } - else { - logElement = loggingSection.GetSection(LogElementName); - } - - var configuration = new LoggingConfiguration(provider); - - foreach (var logItem in logElement.GetSelfOrChildren()) { - var source = logItem.GetSection(LogSourceElementName).Value; - var target = logItem.GetSection(LogTargerElementName).Value; - if (source.IsNullOrEmpty() || target.IsNullOrEmpty()) - throw new InvalidOperationException(); - configuration.Logs.Add(new LogConfiguration(source, target)); - } - - return configuration; - } - - throw new InvalidOperationException( - string.Format(Strings.ExSectionIsNotFoundInApplicationConfigurationFile, WellKnown.DefaultConfigurationSection)); - } - } - - internal sealed class XmlDomainConfigParser : DomainConfigurationParser - { protected override void ProcessNamingConvention(IConfigurationSection namingConventionSection, DomainConfigurationOptions domainConfiguratonOptions) { if (namingConventionSection == null) { @@ -245,8 +174,17 @@ private void ProcessCollectionOfOptions(IConfigurationSection collectio } } - internal class FromJsonToDomainConfigurationParser : DomainConfigurationParser + internal sealed class JsonToDomainConfigurationReader : DomainConfigurationReader { + protected override bool ValidateCorrectFormat(IConfigurationSection allDomainsSection, string domainName) + { + return allDomainsSection.GetSection(domainName).GetChildren().Any() + && !allDomainsSection.GetSection(string.Format(NamedDomainTemplate, domainName)).GetChildren().Any(); + } + + protected override IConfigurationSection GetDomainSection(IConfigurationSection allDomainsSection, string domainName) => + allDomainsSection.GetSection(domainName); + protected override void ProcessNamingConvention(IConfigurationSection namingConventionSection, DomainConfigurationOptions domainConfiguratonOptions) { if (namingConventionSection == null || !namingConventionSection.GetChildren().Any()) @@ -258,7 +196,7 @@ protected override void ProcessNamingConvention(IConfigurationSection namingConv } } - internal abstract class DomainConfigurationParser : IConfigurationSectionParser + internal abstract class DomainConfigurationReader : IConfigurationSectionReader { protected const string RuleElementName = "Rule"; protected const string KeyGeneratorElementName = "KeyGenerator"; @@ -277,31 +215,78 @@ internal abstract class DomainConfigurationParser : IConfigurationSectionParser< protected const string MappingRulesSectionName = "MappingRules"; protected const string SessionsSectionName = "Sessions"; protected const string NamespaceSynonymSectionName = "NamespaceSynonyms"; - - public DomainConfiguration Parse(IConfiguration configuration) + protected const string DomainsSectionName = "Domains"; + + protected const string NamedDomainTemplate = "Domain:{0}"; + + /// + /// Gets domain configuration with name "Default" from default section. + /// + /// + /// + public DomainConfiguration Read(IConfigurationRoot configurationRoot) => + Read(configurationRoot, WellKnown.DefaultConfigurationSection, "Default"); + + /// + /// Gets domain configuration with name "Default" from . + /// + /// + /// + /// + public DomainConfiguration Read(IConfigurationRoot configurationRoot, string sectionName) => + Read(configurationRoot, sectionName, "Default"); + + /// + /// Gets domain configuration with given name from . + /// + /// + /// + /// + /// + public DomainConfiguration Read(IConfigurationRoot configurationRoot, string sectionName, string nameOfConfiguration) { - if (configuration is IConfigurationRoot configurationRoot) { - return Parse(configurationRoot, WellKnown.DefaultConfigurationSection); - } - else if (configuration is IConfigurationSection configurationSection) { - return Parse(configurationSection); - } - throw new InvalidOperationException(""); - } + var allDomainsSection = configurationRoot.GetSection(sectionName).GetSection(DomainsSectionName); + if (allDomainsSection == null || !allDomainsSection.GetChildren().Any()) + return null; - public DomainConfiguration Parse(IConfigurationRoot configuration, string sectionName) - { - var context = new ConfigurationParserContext(configuration, sectionName); - return ParseInternal(context); + var domainConfigurationSection = GetDomainSection(allDomainsSection, nameOfConfiguration); + if (domainConfigurationSection == null || !domainConfigurationSection.GetChildren().Any()) + return null; + + var connectionStrings = configurationRoot.GetSection("ConnectionStrings").Get>(); + var context = new ConfigurationParserContext(domainConfigurationSection, connectionStrings); + + return ReadInternal(context); } - public DomainConfiguration Parse(IConfigurationSection domainConfiguration, Dictionary connectionStrings = null) + public DomainConfiguration Read(IConfigurationSection rootSection) => + Parse(rootSection, "Default", null); + + public DomainConfiguration Read(IConfigurationSection rootSection, string nameOfConfiguration) => + Parse(rootSection, nameOfConfiguration, null); + + public DomainConfiguration Parse(IConfigurationSection rootSection, Dictionary connectionStrings) + => Parse(rootSection, "Default", connectionStrings); + + public DomainConfiguration Parse(IConfigurationSection rootSection, string nameOfConfiguration, Dictionary connectionStrings) { - var context = new ConfigurationParserContext(domainConfiguration, connectionStrings); - return ParseInternal(context); + var allDomainsSection = rootSection.GetSection(DomainsSectionName); + if (allDomainsSection == null || !allDomainsSection.GetChildren().Any()) + return null; + + var domainConfigurationSection = GetDomainSection(allDomainsSection, nameOfConfiguration); + if (domainConfigurationSection == null || !domainConfigurationSection.GetChildren().Any()) + return null; + + var context = new ConfigurationParserContext(domainConfigurationSection, connectionStrings); + return ReadInternal(context); } - private DomainConfiguration ParseInternal(ConfigurationParserContext context) + protected abstract bool ValidateCorrectFormat(IConfigurationSection allDomainsSection, string domainName); + + protected abstract IConfigurationSection GetDomainSection(IConfigurationSection allDomainsSection, string domainName); + + private DomainConfiguration ReadInternal(ConfigurationParserContext context) { var domainByNameSection = context.CurrentSection; if (domainByNameSection == null || !domainByNameSection.GetChildren().Any()) { @@ -357,6 +342,8 @@ protected virtual void ProcessMappingRules(IConfigurationSection mappingRulesSec protected virtual void ProcessSessions(IConfigurationSection sessionsSection, DomainConfigurationOptions domainConfiguratonOptions) { } + + } internal sealed class ConfigurationParserContext diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Internals/LoggingConfigurationReader.cs b/Orm/Xtensive.Orm/Orm/Configuration/Internals/LoggingConfigurationReader.cs new file mode 100644 index 0000000000..c583720e9e --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Internals/LoggingConfigurationReader.cs @@ -0,0 +1,94 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + + +using System; +using System.Linq; +using Microsoft.Extensions.Configuration; +using Xtensive.Core; + +namespace Xtensive.Orm.Configuration.Internals +{ + internal sealed class LoggingConfigurationReader : IConfigurationSectionReader + { + private const string LoggingSectionName = "Logging"; + private const string LogsSectionName = "Logs"; + + private const string ProviderElementName = "Provider"; + private const string LogElementName = "Log"; + private const string LogSourceElementName = "Source"; + private const string LogTargerElementName = "Target"; + + /// + public LoggingConfiguration Read(IConfigurationRoot configurationRoot, string sectionName) + { + ArgumentValidator.EnsureArgumentNotNull(configurationRoot, nameof(configurationRoot)); + ArgumentValidator.EnsureArgumentNotNullOrEmpty(sectionName, nameof(sectionName)); + + return Read(configurationRoot.GetSection(sectionName)); + } + + /// + public LoggingConfiguration Read(IConfigurationRoot configurationRoot) + { + ArgumentValidator.EnsureArgumentNotNull(configurationRoot, nameof(configurationRoot)); + return Read(configurationRoot.GetSection(WellKnown.DefaultConfigurationSection)); + } + + /// + public LoggingConfiguration Read(IConfigurationRoot configurationRoot, string sectionName, string nameOfConfiguration) + { + throw new NotSupportedException(); + } + + /// + public LoggingConfiguration Read(IConfigurationSection configurationSection) + { + ArgumentValidator.EnsureArgumentNotNull(configurationSection, nameof(configurationSection)); + + var ormConfigurationSection = configurationSection; + + var loggingSection = ormConfigurationSection.GetSection(LoggingSectionName); + + if (loggingSection != null && loggingSection.GetChildren().Any()) { + var provider = loggingSection.GetSection(ProviderElementName)?.Value; + var logsSection = loggingSection.GetSection(LogsSectionName); + IConfigurationSection logElement; + + if (logsSection != null && logsSection.GetChildren().Any()) { + logElement = logsSection.GetSection(LogElementName); + if (logElement == null || !logElement.GetChildren().Any()) { + logElement = logsSection; + } + } + else { + logElement = loggingSection.GetSection(LogElementName); + } + + var configuration = new LoggingConfiguration(provider); + foreach (var logItem in logElement.GetSelfOrChildren()) { + var source = logItem.GetSection(LogSourceElementName).Value; + var target = logItem.GetSection(LogTargerElementName).Value; + if (source.IsNullOrEmpty() || target.IsNullOrEmpty()) + throw new InvalidOperationException(); + configuration.Logs.Add(new LogConfiguration(source, target)); + } + + if (configuration.Provider == null && configuration.Logs.Count==0) + throw new InvalidOperationException(); + + return configuration; + } + + throw new InvalidOperationException( + string.Format(Strings.ExSectionIsNotFoundInApplicationConfigurationFile, WellKnown.DefaultConfigurationSection)); + } + + /// + public LoggingConfiguration Read(IConfigurationSection configurationSection, string nameOfConfiguration) + { + throw new NotSupportedException(); + } + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs b/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs index 9ef4a6aff8..514f6556ac 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs @@ -82,12 +82,12 @@ public static LoggingConfiguration Load(System.Configuration.Configuration confi public static LoggingConfiguration Load(IConfigurationSection configurationSection) { - return new LoggingConfigurationParser().Parse(configurationSection); + return new LoggingConfigurationReader().Read(configurationSection); } - public static LoggingConfiguration Load(IConfigurationRoot configurationRoot, string sectionName = null) + return new LoggingConfigurationReader().Read(configurationRoot); { - return new LoggingConfigurationParser().Parse(configurationRoot, sectionName); + return new LoggingConfigurationReader().Read(configurationRoot, sectionName); } /// From aeb639ffe509a8de33a484ee8330351d67c914cd Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Mon, 23 Sep 2024 18:12:26 +0500 Subject: [PATCH 15/32] Minor changes in main project --- .../Orm/Configuration/DomainConfiguration.cs | 2 +- .../ConfigurationSectionExtensions.cs | 7 ++-- .../Orm/Configuration/LoggingConfiguration.cs | 32 +++++++++++++++++-- .../Options/DomainConfigurationOptions.cs | 12 ++----- .../Options/IgnoreRuleOptions.cs | 20 ++++++++++++ 5 files changed, 56 insertions(+), 17 deletions(-) diff --git a/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs b/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs index d28560d18e..bdbed0af23 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs @@ -877,7 +877,7 @@ private static DomainConfiguration LoadConfigurationFromSection(ConfigurationSec /// /// Root configuration section where domain configurations are placed /// Name of the . - /// + /// Domain configuration. /// The "domains" section is not found or domain with requested name is not found. public static DomainConfiguration Load(IConfigurationSection configurationSection, string name) { diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Internals/ConfigurationSectionExtensions.cs b/Orm/Xtensive.Orm/Orm/Configuration/Internals/ConfigurationSectionExtensions.cs index d2d4d6c19c..4e5844ddfe 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Internals/ConfigurationSectionExtensions.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Internals/ConfigurationSectionExtensions.cs @@ -1,8 +1,9 @@ -using System; +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.Extensions.Configuration; using Xtensive.Collections; diff --git a/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs b/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs index 514f6556ac..9209e502cd 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs @@ -7,7 +7,9 @@ using System; using System.Collections.Generic; using System.Configuration; +using Microsoft.Extensions.Configuration; using Xtensive.Core; +using Xtensive.Orm.Configuration.Internals; using ConfigurationSection = Xtensive.Orm.Configuration.Elements.ConfigurationSection; namespace Xtensive.Orm.Configuration @@ -43,7 +45,7 @@ public static LoggingConfiguration Load() /// Loaded configuration. public static LoggingConfiguration Load(string sectionName) { - ArgumentValidator.EnsureArgumentNotNullOrEmpty(sectionName, "sectionName"); + ArgumentValidator.EnsureArgumentNotNullOrEmpty(sectionName, nameof(sectionName)); var section = (ConfigurationSection)ConfigurationManager.GetSection(sectionName); if (section==null) @@ -70,8 +72,8 @@ public static LoggingConfiguration Load(System.Configuration.Configuration confi /// Loaded configuration. public static LoggingConfiguration Load(System.Configuration.Configuration configuration, string sectionName) { - ArgumentValidator.EnsureArgumentNotNull(configuration, "configuration"); - ArgumentValidator.EnsureArgumentNotNullOrEmpty(sectionName, "sectionName"); + ArgumentValidator.EnsureArgumentNotNull(configuration, nameof(configuration)); + ArgumentValidator.EnsureArgumentNotNullOrEmpty(sectionName, nameof(sectionName)); var section = (ConfigurationSection) configuration.GetSection(sectionName); if (section==null) @@ -80,12 +82,36 @@ public static LoggingConfiguration Load(System.Configuration.Configuration confi return loggingConfiguration; } + /// + /// Loads logging configuration from the specified configuration section. + /// + /// Root configuration section where logging configuration is placed. + /// Logging configuration. + /// The logging section is not found. public static LoggingConfiguration Load(IConfigurationSection configurationSection) { return new LoggingConfigurationReader().Read(configurationSection); } + /// + /// Loads logging configuration from default section. + /// + /// Root of configuration. + /// Read configuration. + /// The logging section is not found. + public static LoggingConfiguration Load(IConfigurationRoot configurationRoot) + { return new LoggingConfigurationReader().Read(configurationRoot); + } + + /// + /// Loads logging configuration from specific section. + /// + /// Root of configuration. + /// Section name where logging configuration is defined. + /// Read configuration. + /// The logging section is not found. + public static LoggingConfiguration Load(IConfigurationRoot configurationRoot, string sectionName) { return new LoggingConfigurationReader().Read(configurationRoot, sectionName); } diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/DomainConfigurationOptions.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/DomainConfigurationOptions.cs index b2a3769c51..fa29acef41 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Options/DomainConfigurationOptions.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/DomainConfigurationOptions.cs @@ -301,19 +301,11 @@ public DomainConfiguration ToNative(IDictionary connectionString } } - foreach (var element in Sessions) + foreach (var element in Sessions) { config.Sessions.Add(element.Value.ToNative(connectionStrings)); + } return config; } - - private static T ParseEnum(string value) - where T : struct - { - if (!Enum.TryParse(value, true, out var result)) { - throw new ArgumentException($"Can't parse given value '{value}' to enum type '{typeof(T).FullName}'"); - } - return result; - } } } diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Options/IgnoreRuleOptions.cs b/Orm/Xtensive.Orm/Orm/Configuration/Options/IgnoreRuleOptions.cs index 02d1b5d168..aa3b231dd0 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Options/IgnoreRuleOptions.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Options/IgnoreRuleOptions.cs @@ -13,6 +13,7 @@ internal sealed class IgnoreRuleOptions : IIdentifyableOptions, IValidatableOptions, IToNativeConvertable { + /// public object Identifier => (Database ?? string.Empty, Schema ?? string.Empty, @@ -20,10 +21,29 @@ internal sealed class IgnoreRuleOptions : IIdentifyableOptions, Column ?? string.Empty, Index ?? string.Empty); + /// + /// Database part of the rule + /// public string Database { get; set; } + + /// + /// Schema part of the rule. + /// public string Schema { get; set; } + + /// + /// Table part of the rule. + /// public string Table { get; set; } + + /// + /// Column part of the rule. + /// public string Column { get; set; } + + /// + /// Index part of the rule. + /// public string Index { get; set; } /// From 1b9be6f0b8510fc4ecd71d50bde60af22373fcb4 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Mon, 23 Sep 2024 18:14:15 +0500 Subject: [PATCH 16/32] DomainConfiguration(IConfigurationRoot) methods --- .../Orm/Configuration/DomainConfiguration.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs b/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs index bdbed0af23..1c5bcc4a01 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs @@ -897,6 +897,38 @@ public static DomainConfiguration Load(IConfigurationSection configurationSectio Strings.ExConfigurationForDomainIsNotFoundInApplicationConfigurationFile, name, sectionName)); } + public static DomainConfiguration Load(IConfigurationRoot configurationRoot, string name) + { + ArgumentValidator.EnsureArgumentNotNull(configurationRoot, nameof(configurationRoot)); + + var jsonParser = new JsonToDomainConfigurationReader(); + var xmlParser = new XmlToDomainConfigurationReader(); + + var parseResult = jsonParser.Read(configurationRoot, name); + if (parseResult != null) + return parseResult; + parseResult = xmlParser.Read(configurationRoot, name); + if (parseResult != null) + return parseResult; + + throw new InvalidOperationException(string.Format( + Strings.ExConfigurationForDomainIsNotFoundInApplicationConfigurationFile, name, sectionName)); + } + + public static DomainConfiguration Load(IConfigurationRoot configurationRoot, string sectionName, string name) + { + ArgumentValidator.EnsureArgumentNotNull(configurationRoot, nameof(configurationRoot)); + + var jsonParser = new JsonToDomainConfigurationReader(); + var xmlParser = new XmlToDomainConfigurationReader(); + + var parseResult = jsonParser.Read(configurationRoot, sectionName, name); + if (parseResult != null) + return parseResult; + parseResult = xmlParser.Read(configurationRoot, sectionName, name); + if (parseResult != null) + return parseResult; + throw new InvalidOperationException(string.Format( Strings.ExConfigurationForDomainIsNotFoundInApplicationConfigurationFile, name, sectionName)); } From beeffe29e2e084eb6f877120d52f73de92cd756c Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Mon, 23 Sep 2024 18:14:48 +0500 Subject: [PATCH 17/32] Tests' improvements --- .../Configuration/ModernConfigurationTests.cs | 882 +++++++++++------- 1 file changed, 569 insertions(+), 313 deletions(-) diff --git a/Orm/Xtensive.Orm.Tests/Configuration/ModernConfigurationTests.cs b/Orm/Xtensive.Orm.Tests/Configuration/ModernConfigurationTests.cs index 42c8152e15..df50fe29e4 100644 --- a/Orm/Xtensive.Orm.Tests/Configuration/ModernConfigurationTests.cs +++ b/Orm/Xtensive.Orm.Tests/Configuration/ModernConfigurationTests.cs @@ -74,7 +74,6 @@ namespace Xtensive.Orm.Tests.Configuration [TestFixture] public sealed class AppConfigStyleConfigurationTest : ConfigurationFileTestBase { - protected override string DefaultSectionName => "Xtensive.Orm.AppConfig"; protected override string Postfix => "AppConfig"; protected override bool NameAttributeUnique => false; @@ -88,7 +87,6 @@ protected override void RegisterConfigurationFile(ConfigurationBuilder builder) [TestFixture] public sealed class XmlConfigurationTest : ConfigurationFileTestBase { - protected override string DefaultSectionName => "Xtensive.Orm.Xml"; protected override string Postfix => "Xml"; protected override void RegisterConfigurationFile(ConfigurationBuilder builder) @@ -100,7 +98,6 @@ protected override void RegisterConfigurationFile(ConfigurationBuilder builder) [TestFixture] public sealed class JsonConfigurationTest : ConfigurationFileTestBase { - protected override string DefaultSectionName => "Xtensive.Orm.Json"; protected override string Postfix => "Json"; protected override void RegisterConfigurationFile(ConfigurationBuilder builder) @@ -115,10 +112,12 @@ public abstract class ConfigurationFileTestBase private IConfigurationRoot configuration; private IConfigurationSection configurationSection; - protected abstract string DefaultSectionName { get; } + protected abstract string Postfix { get; } protected virtual bool NameAttributeUnique => true; + protected virtual string DefaultSectionName => $"Xtensive.Orm.{Postfix}"; + [OneTimeSetUp] public void OneTimeSetup() { @@ -136,10 +135,11 @@ public void OneTimeSetup() protected abstract void RegisterConfigurationFile(ConfigurationBuilder builder); - private DomainConfiguration LoadDomainConfiguration(string domainName) + private DomainConfiguration LoadDomainConfiguration(string domainName, bool useRoot) { - var domainConfiguration = DomainConfiguration.Load(configurationSection, domainName); - return domainConfiguration; + return useRoot + ? DomainConfiguration.Load(configuration, DefaultSectionName, domainName) + : DomainConfiguration.Load(configurationSection, domainName); } private LoggingConfiguration LoadLoggingConfiguration(IConfigurationSection customConfigurationSection = null) { @@ -151,9 +151,11 @@ private LoggingConfiguration LoadLoggingConfiguration(IConfigurationSection cust #region Simple Domain settings that used to be attributes [Test] - public void ProviderAndConnectionStringTest() + [TestCase(true)] + [TestCase(false)] + public void ProviderAndConnectionStringTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithProviderAndConnectionString"); + var domainConfig = LoadDomainConfiguration("DomainWithProviderAndConnectionString", useRoot); Assert.That(domainConfig.ConnectionInfo.Provider, Is.EqualTo(WellKnown.Provider.Sqlite)); Assert.That(domainConfig.ConnectionInfo.ConnectionString, Is.EqualTo("Data Source=DO-Testsaaa.db3")); Assert.That(domainConfig.ConnectionInfo.ConnectionUrl, Is.Null); @@ -162,9 +164,11 @@ public void ProviderAndConnectionStringTest() } [Test] - public void ConnectionUrlTest() + [TestCase(true)] + [TestCase(false)] + public void ConnectionUrlTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithConnectionUrl"); + var domainConfig = LoadDomainConfiguration("DomainWithConnectionUrl", useRoot); Assert.That(domainConfig.ConnectionInfo.Provider, Is.EqualTo(WellKnown.Provider.Sqlite)); Assert.That(domainConfig.ConnectionInfo.ConnectionString, Is.Null); Assert.That(domainConfig.ConnectionInfo.ConnectionUrl.Url, Is.EqualTo("sqlite:///DO-Tests.db3")); @@ -173,65 +177,83 @@ public void ConnectionUrlTest() } [Test] - public void CustomValidKeyCacheSizeTest() + [TestCase(true)] + [TestCase(false)] + public void CustomValidKeyCacheSizeTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithCustomValidKeyCacheSize"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomValidKeyCacheSize", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.KeyCacheSize, 192)); } [Test] - public void CustomInvalidKeyCacheSizeTest() + [TestCase(true)] + [TestCase(false)] + public void CustomInvalidKeyCacheSizeTest(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomInvalidKeyCacheSize")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomInvalidKeyCacheSize", useRoot)); } [Test] - public void CustomValidKeyGeneratorCacheSizeTest() + [TestCase(true)] + [TestCase(false)] + public void CustomValidKeyGeneratorCacheSizeTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithCustomValidKeyGeneratorCacheSize"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomValidKeyGeneratorCacheSize", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.KeyGeneratorCacheSize, 192)); } [Test] - public void CustomInvalidKeyGeneratorCacheSizeTest() + [TestCase(true)] + [TestCase(false)] + public void CustomInvalidKeyGeneratorCacheSizeTest(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomInvalidKeyGeneratorCacheSize")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomInvalidKeyGeneratorCacheSize", useRoot)); } [Test] - public void CustomValidQueryCacheSizeTest() + [TestCase(true)] + [TestCase(false)] + public void CustomValidQueryCacheSizeTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithCustomValidQueryCacheSize"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomValidQueryCacheSize", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.QueryCacheSize, 192)); } [Test] - public void CustomInvalidQueryCacheSizeTest() + [TestCase(true)] + [TestCase(false)] + public void CustomInvalidQueryCacheSizeTest(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomInvalidQueryCacheSize")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomInvalidQueryCacheSize", useRoot)); } [Test] - public void CustomValidRecordSetMappingCacheSizeTest() + [TestCase(true)] + [TestCase(false)] + public void CustomValidRecordSetMappingCacheSizeTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithCustomValidRecordSetMappingCacheSize"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomValidRecordSetMappingCacheSize", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.RecordSetMappingCacheSize, 192)); } [Test] - public void CustomInvalidRecordSetMappingCacheSizeTest() + [TestCase(true)] + [TestCase(false)] + public void CustomInvalidRecordSetMappingCacheSizeTest(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomInvalidRecordSetMappingCacheSize")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomInvalidRecordSetMappingCacheSize", useRoot)); } [Test] - public void CustomDefaultDatabaseTest() + [TestCase(true)] + [TestCase(false)] + public void CustomDefaultDatabaseTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithCustomDatabase"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomDatabase", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.DefaultDatabase, "MyFancyDatabase"), ((d) => d.IsMultidatabase, true), @@ -240,9 +262,11 @@ public void CustomDefaultDatabaseTest() } [Test] - public void CustomDefaultSchemaTest() + [TestCase(true)] + [TestCase(false)] + public void CustomDefaultSchemaTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithCustomSchema"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomSchema", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.DefaultSchema, "MyFancySchema"), ((d) => d.IsMultidatabase, false), @@ -250,340 +274,413 @@ public void CustomDefaultSchemaTest() } [Test] - public void UpgradeModesTest() + [TestCase(true)] + [TestCase(false)] + public void UpgradeModesTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode1"); + var domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode1", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.UpgradeMode, DomainUpgradeMode.Default)); domainConfig.Lock(); - domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode2"); + domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode2", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.UpgradeMode, DomainUpgradeMode.Recreate)); domainConfig.Lock(); - domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode3"); + domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode3", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.UpgradeMode, DomainUpgradeMode.Perform)); domainConfig.Lock(); - domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode4"); + domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode4", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.UpgradeMode, DomainUpgradeMode.PerformSafely)); domainConfig.Lock(); - domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode5"); + domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode5", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.UpgradeMode, DomainUpgradeMode.Validate)); domainConfig.Lock(); - domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode6"); + domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode6", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.UpgradeMode, DomainUpgradeMode.LegacyValidate)); domainConfig.Lock(); - domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode7"); + domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode7", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.UpgradeMode, DomainUpgradeMode.Skip)); domainConfig.Lock(); - domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode8"); + domainConfig = LoadDomainConfiguration("DomainWithUpgradeMode8", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.UpgradeMode, DomainUpgradeMode.LegacySkip)); domainConfig.Lock(); } [Test] - public void WrongUpgradeModeTest() + [TestCase(true)] + [TestCase(false)] + public void WrongUpgradeModeTest(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithWrongUpgradeMode")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithWrongUpgradeMode", useRoot)); } [Test] - public void ForeighKeyModesTest() + [TestCase(true)] + [TestCase(false)] + public void ForeighKeyModesTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithForeignKeyMode1"); + var domainConfig = LoadDomainConfiguration("DomainWithForeignKeyMode1", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.ForeignKeyMode, ForeignKeyMode.None)); domainConfig.Lock(); - domainConfig = LoadDomainConfiguration("DomainWithForeignKeyMode2"); + domainConfig = LoadDomainConfiguration("DomainWithForeignKeyMode2", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.ForeignKeyMode, ForeignKeyMode.Hierarchy)); domainConfig.Lock(); - domainConfig = LoadDomainConfiguration("DomainWithForeignKeyMode3"); + domainConfig = LoadDomainConfiguration("DomainWithForeignKeyMode3", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.ForeignKeyMode, ForeignKeyMode.Reference)); domainConfig.Lock(); - domainConfig = LoadDomainConfiguration("DomainWithForeignKeyMode4"); + domainConfig = LoadDomainConfiguration("DomainWithForeignKeyMode4", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.ForeignKeyMode, ForeignKeyMode.All)); domainConfig.Lock(); - domainConfig = LoadDomainConfiguration("DomainWithForeignKeyMode5"); + domainConfig = LoadDomainConfiguration("DomainWithForeignKeyMode5", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.ForeignKeyMode, ForeignKeyMode.Default)); domainConfig.Lock(); - domainConfig = LoadDomainConfiguration("DomainWithForeignKeyMode6"); + domainConfig = LoadDomainConfiguration("DomainWithForeignKeyMode6", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.ForeignKeyMode, ForeignKeyMode.Hierarchy | ForeignKeyMode.Reference)); domainConfig.Lock(); } [Test] - public void InvalidForeighKeyModeTest() + [TestCase(true)] + [TestCase(false)] + public void InvalidForeighKeyModeTest(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidForeignKeyMode")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidForeignKeyMode", useRoot)); } [Test] - public void ChangeTrackingModesTest() + [TestCase(true)] + [TestCase(false)] + public void ChangeTrackingModesTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithChangeTrackingMode1"); + var domainConfig = LoadDomainConfiguration("DomainWithChangeTrackingMode1", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.FullTextChangeTrackingMode, FullTextChangeTrackingMode.Off)); domainConfig.Lock(); - domainConfig = LoadDomainConfiguration("DomainWithChangeTrackingMode2"); + domainConfig = LoadDomainConfiguration("DomainWithChangeTrackingMode2", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.FullTextChangeTrackingMode, FullTextChangeTrackingMode.Auto)); domainConfig.Lock(); - domainConfig = LoadDomainConfiguration("DomainWithChangeTrackingMode3"); + domainConfig = LoadDomainConfiguration("DomainWithChangeTrackingMode3", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.FullTextChangeTrackingMode, FullTextChangeTrackingMode.Manual)); domainConfig.Lock(); - domainConfig = LoadDomainConfiguration("DomainWithChangeTrackingMode4"); + domainConfig = LoadDomainConfiguration("DomainWithChangeTrackingMode4", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.FullTextChangeTrackingMode, FullTextChangeTrackingMode.OffWithNoPopulation)); domainConfig.Lock(); - domainConfig = LoadDomainConfiguration("DomainWithChangeTrackingMode5"); + domainConfig = LoadDomainConfiguration("DomainWithChangeTrackingMode5", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.FullTextChangeTrackingMode, FullTextChangeTrackingMode.Default)); domainConfig.Lock(); } [Test] - public void InvalidChangeTrackingModeTest() + [TestCase(true)] + [TestCase(false)] + public void InvalidChangeTrackingModeTest(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidChangeTrackingMode")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidChangeTrackingMode", useRoot)); } [Test] - public void DomainOptionsTest1() + [TestCase(true)] + [TestCase(false)] + public void DomainOptionsTest1(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithDomainOptionsValid1"); + var domainConfig = LoadDomainConfiguration("DomainWithDomainOptionsValid1", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.Options, DomainOptions.Default)); domainConfig.Lock(); } [Test] - public void DomainOptionsTest2() + [TestCase(true)] + [TestCase(false)] + public void DomainOptionsTest2(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithDomainOptionsValid2"); + var domainConfig = LoadDomainConfiguration("DomainWithDomainOptionsValid2", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.Options, DomainOptions.None)); domainConfig.Lock(); } + [Test] - public void InvalidDomainOptionsTest() + [TestCase(true)] + [TestCase(false)] + public void InvalidDomainOptionsTest(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithDomainOptionsInvalid")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithDomainOptionsInvalid", useRoot)); } [Test] - public void CollationTest() + [TestCase(true)] + [TestCase(false)] + public void CollationTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithColation"); + var domainConfig = LoadDomainConfiguration("DomainWithColation", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.Collation, "generalci")); } [Test] - public void BriefSchemaSyncExceptionsTest() + [TestCase(true)] + [TestCase(false)] + public void BriefSchemaSyncExceptionsTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithBriefSchemaSyncExceptions"); + var domainConfig = LoadDomainConfiguration("DomainWithBriefSchemaSyncExceptions", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.SchemaSyncExceptionFormat, SchemaSyncExceptionFormat.Brief)); } [Test] - public void DetailedSchemaSyncExceptionsTest() + [TestCase(true)] + [TestCase(false)] + public void DetailedSchemaSyncExceptionsTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithDetailedSchemaSyncExceptions"); + var domainConfig = LoadDomainConfiguration("DomainWithDetailedSchemaSyncExceptions", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.SchemaSyncExceptionFormat, SchemaSyncExceptionFormat.Detailed)); } [Test] - public void DefaultSchemaSyncExceptionsTest() + [TestCase(true)] + [TestCase(false)] + public void DefaultSchemaSyncExceptionsTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithDefaultSchemaSyncExceptions"); + var domainConfig = LoadDomainConfiguration("DomainWithDefaultSchemaSyncExceptions", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.SchemaSyncExceptionFormat, SchemaSyncExceptionFormat.Default)); } [Test] - public void InvalidSchemaSyncExceptionsTest() + [TestCase(true)] + [TestCase(false)] + public void InvalidSchemaSyncExceptionsTest(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidSchemaSyncExceptions")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidSchemaSyncExceptions", useRoot)); } [Test] - public void TagsLocationNowhereTest() + [TestCase(true)] + [TestCase(false)] + public void TagsLocationNowhereTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithTagsLocationNowhere"); + var domainConfig = LoadDomainConfiguration("DomainWithTagsLocationNowhere", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.TagsLocation, TagsLocation.Nowhere)); } [Test] - public void TagsLocationBeforeTest() + [TestCase(true)] + [TestCase(false)] + public void TagsLocationBeforeTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithTagsLocationBefore"); + var domainConfig = LoadDomainConfiguration("DomainWithTagsLocationBefore", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.TagsLocation, TagsLocation.BeforeStatement)); } [Test] - public void TagsLocationWithinTest() + [TestCase(true)] + [TestCase(false)] + public void TagsLocationWithinTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithTagsLocationWithin"); + var domainConfig = LoadDomainConfiguration("DomainWithTagsLocationWithin", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.TagsLocation, TagsLocation.WithinStatement)); } [Test] - public void TagsLocationAfterTest() + [TestCase(true)] + [TestCase(false)] + public void TagsLocationAfterTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithTagsLocationAfter"); + var domainConfig = LoadDomainConfiguration("DomainWithTagsLocationAfter", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.TagsLocation, TagsLocation.AfterStatement)); } [Test] - public void TagsLocationDefaultTest() + [TestCase(true)] + [TestCase(false)] + public void TagsLocationDefaultTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithTagsLocationDefault"); + var domainConfig = LoadDomainConfiguration("DomainWithTagsLocationDefault", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.TagsLocation, TagsLocation.Default)); } [Test] - public void InvalidTagsLocationTest() + [TestCase(true)] + [TestCase(false)] + public void InvalidTagsLocationTest(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithTagsLocationInvalid")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithTagsLocationInvalid", useRoot)); } [Test] - public void ForcedServerVersionTest() + [TestCase(true)] + [TestCase(false)] + public void ForcedServerVersionTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithForcedServerVersion"); + var domainConfig = LoadDomainConfiguration("DomainWithForcedServerVersion", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.ForcedServerVersion, "10.0.0.0")); } [Test] - public void InitializationSqlTest() + [TestCase(true)] + [TestCase(false)] + public void InitializationSqlTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithInitSql"); + var domainConfig = LoadDomainConfiguration("DomainWithInitSql", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.ConnectionInitializationSql, "use [OtherDb]")); } [Test] - public void IncludeSqlInExceptionsTest() + [TestCase(true)] + [TestCase(false)] + public void IncludeSqlInExceptionsTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("IncludeSqlInExceptionsTrue"); + var domainConfig = LoadDomainConfiguration("IncludeSqlInExceptionsTrue", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.IncludeSqlInExceptions, true)); } [Test] - public void DontIncludeSqlInExceptionsTest() + [TestCase(true)] + [TestCase(false)] + public void DontIncludeSqlInExceptionsTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("IncludeSqlInExceptionsFalse"); + var domainConfig = LoadDomainConfiguration("IncludeSqlInExceptionsFalse", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.IncludeSqlInExceptions, false)); } [Test] - public void AllowCyclicDatabaseDependanciesTest() + [TestCase(true)] + [TestCase(false)] + public void AllowCyclicDatabaseDependanciesTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("AllowCyclicDatabaseDependenciesTrue"); + var domainConfig = LoadDomainConfiguration("AllowCyclicDatabaseDependenciesTrue", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.AllowCyclicDatabaseDependencies, true)); } [Test] - public void DisallowCyclicDatabaseDependanciesTest() + [TestCase(true)] + [TestCase(false)] + public void DisallowCyclicDatabaseDependanciesTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("AllowCyclicDatabaseDependenciesFalse"); + var domainConfig = LoadDomainConfiguration("AllowCyclicDatabaseDependenciesFalse", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.AllowCyclicDatabaseDependencies, false)); } [Test] - public void BuildInParallelTest() + [TestCase(true)] + [TestCase(false)] + public void BuildInParallelTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("BuildInParallelTrue"); + var domainConfig = LoadDomainConfiguration("BuildInParallelTrue", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.BuildInParallel, true)); } [Test] - public void DontBuildInParallelTest() + [TestCase(true)] + [TestCase(false)] + public void DontBuildInParallelTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("BuildInParallelFalse"); + var domainConfig = LoadDomainConfiguration("BuildInParallelFalse", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.BuildInParallel, false)); } [Test] - public void AllowMultidatabaseKeysTest() + [TestCase(true)] + [TestCase(false)] + public void AllowMultidatabaseKeysTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("MultidatabaseKeysTrue"); + var domainConfig = LoadDomainConfiguration("MultidatabaseKeysTrue", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.MultidatabaseKeys, true)); } [Test] - public void DisallowMultidatabaseKeysTest() + [TestCase(true)] + [TestCase(false)] + public void DisallowMultidatabaseKeysTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("MultidatabaseKeysFalse"); + var domainConfig = LoadDomainConfiguration("MultidatabaseKeysFalse", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.MultidatabaseKeys, false)); } [Test] - public void ShareStorageSchemaOverNodesTest() + [TestCase(true)] + [TestCase(false)] + public void ShareStorageSchemaOverNodesTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("SharedStorageSchemaOn"); + var domainConfig = LoadDomainConfiguration("SharedStorageSchemaOn", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.ShareStorageSchemaOverNodes, true)); } [Test] - public void DontShareStorageSchemaOverNodesTest() + [TestCase(true)] + [TestCase(false)] + public void DontShareStorageSchemaOverNodesTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("SharedStorageSchemaOff"); + var domainConfig = LoadDomainConfiguration("SharedStorageSchemaOff", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.ShareStorageSchemaOverNodes, false)); } [Test] - public void EnsureConnectionIsAliveTest() + [TestCase(true)] + [TestCase(false)] + public void EnsureConnectionIsAliveTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("EnableConnectionIsAliveTrue"); + var domainConfig = LoadDomainConfiguration("EnableConnectionIsAliveTrue", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.EnsureConnectionIsAlive, true)); } [Test] - public void DontCheckConnectionIsAliveTest() + [TestCase(true)] + [TestCase(false)] + public void DontCheckConnectionIsAliveTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("EnableConnectionIsAliveFalse"); + var domainConfig = LoadDomainConfiguration("EnableConnectionIsAliveFalse", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.EnsureConnectionIsAlive, false)); } [Test] - public void PreferTypeIdAsQueryParameterTest() + [TestCase(true)] + [TestCase(false)] + public void PreferTypeIdAsQueryParameterTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("PreferTypeIdsAsQueryParametersTrue"); + var domainConfig = LoadDomainConfiguration("PreferTypeIdsAsQueryParametersTrue", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.PreferTypeIdsAsQueryParameters, true)); } [Test] - public void DontPreferTypeIdAsQueryParameterTest() + [TestCase(true)] + [TestCase(false)] + public void DontPreferTypeIdAsQueryParameterTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("PreferTypeIdsAsQueryParametersFalse"); + var domainConfig = LoadDomainConfiguration("PreferTypeIdsAsQueryParametersFalse", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.PreferTypeIdsAsQueryParameters, false)); } @@ -592,9 +689,11 @@ public void DontPreferTypeIdAsQueryParameterTest() #region NamingConvention [Test] - public void NamingConventionSettingsTest01() + [TestCase(true)] + [TestCase(false)] + public void NamingConventionSettingsTest01(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention1"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention1", useRoot); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); @@ -608,9 +707,11 @@ public void NamingConventionSettingsTest01() } [Test] - public void NamingConventionSettingsTest02() + [TestCase(true)] + [TestCase(false)] + public void NamingConventionSettingsTest02(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention2"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention2", useRoot); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Lowercase)); @@ -624,9 +725,11 @@ public void NamingConventionSettingsTest02() } [Test] - public void NamingConventionSettingsTest03() + [TestCase(true)] + [TestCase(false)] + public void NamingConventionSettingsTest03(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention3"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention3", useRoot); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.AsIs)); @@ -640,9 +743,11 @@ public void NamingConventionSettingsTest03() } [Test] - public void NamingConventionSettingsTest04() + [TestCase(true)] + [TestCase(false)] + public void NamingConventionSettingsTest04(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention4"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention4", useRoot); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Default)); @@ -656,9 +761,11 @@ public void NamingConventionSettingsTest04() } [Test] - public void NamingConventionSettingsTest05() + [TestCase(true)] + [TestCase(false)] + public void NamingConventionSettingsTest05(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention5"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention5", useRoot); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); @@ -667,9 +774,11 @@ public void NamingConventionSettingsTest05() } [Test] - public void NamingConventionSettingsTest06() + [TestCase(true)] + [TestCase(false)] + public void NamingConventionSettingsTest06(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention6"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention6", useRoot); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); @@ -678,9 +787,11 @@ public void NamingConventionSettingsTest06() } [Test] - public void NamingConventionSettingsTest07() + [TestCase(true)] + [TestCase(false)] + public void NamingConventionSettingsTest07(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention7"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention7", useRoot); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); @@ -689,9 +800,11 @@ public void NamingConventionSettingsTest07() } [Test] - public void NamingConventionSettingsTest08() + [TestCase(true)] + [TestCase(false)] + public void NamingConventionSettingsTest08(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention8"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention8", useRoot); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); @@ -700,9 +813,11 @@ public void NamingConventionSettingsTest08() } [Test] - public void NamingConventionSettingsTest09() + [TestCase(true)] + [TestCase(false)] + public void NamingConventionSettingsTest09(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention9"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention9", useRoot); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); @@ -711,9 +826,11 @@ public void NamingConventionSettingsTest09() } [Test] - public void NamingConventionSettingsTest10() + [TestCase(true)] + [TestCase(false)] + public void NamingConventionSettingsTest10(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention10"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention10", useRoot); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); @@ -723,9 +840,11 @@ public void NamingConventionSettingsTest10() } [Test] - public void NamingConventionSettingsTest11() + [TestCase(true)] + [TestCase(false)] + public void NamingConventionSettingsTest11(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention11"); + var domainConfig = LoadDomainConfiguration("DomainWithNamingConvention11", useRoot); ValidateAllDefault(domainConfig); var namingConvention = domainConfig.NamingConvention; Assert.That(namingConvention.LetterCasePolicy, Is.EqualTo(LetterCasePolicy.Uppercase)); @@ -734,21 +853,27 @@ public void NamingConventionSettingsTest11() } [Test] - public void NamingConventionInvalidSettingsTest1() + [TestCase(true)] + [TestCase(false)] + public void NamingConventionInvalidSettingsTest1(bool useRoot) { - _ = Assert.Throws (()=> LoadDomainConfiguration("DomainWithInvalidNamingConvention1")); + _ = Assert.Throws (() => LoadDomainConfiguration("DomainWithInvalidNamingConvention1", useRoot)); } [Test] - public void NamingConventionInvalidSettingsTest2() + [TestCase(true)] + [TestCase(false)] + public void NamingConventionInvalidSettingsTest2(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidNamingConvention2")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidNamingConvention2", useRoot)); } [Test] - public void NamingConventionInvalidSettingsTest3() + [TestCase(true)] + [TestCase(false)] + public void NamingConventionInvalidSettingsTest3(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidNamingConvention3")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidNamingConvention3", useRoot)); } #endregion @@ -756,27 +881,33 @@ public void NamingConventionInvalidSettingsTest3() #region VersioningConvention [Test] - public void VersioningConventionPessimisticTest() + [TestCase(true)] + [TestCase(false)] + public void VersioningConventionPessimisticTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithVersioningConvention1"); + var domainConfig = LoadDomainConfiguration("DomainWithVersioningConvention1", useRoot); ValidateAllDefault(domainConfig); Assert.That(domainConfig.VersioningConvention.EntityVersioningPolicy, Is.EqualTo(EntityVersioningPolicy.Pessimistic)); Assert.That(domainConfig.VersioningConvention.DenyEntitySetOwnerVersionChange, Is.EqualTo(false)); } [Test] - public void VersioningConventionOptimisticTest() + [TestCase(true)] + [TestCase(false)] + public void VersioningConventionOptimisticTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithVersioningConvention2"); + var domainConfig = LoadDomainConfiguration("DomainWithVersioningConvention2", useRoot); ValidateAllDefault(domainConfig); Assert.That(domainConfig.VersioningConvention.EntityVersioningPolicy, Is.EqualTo(EntityVersioningPolicy.Optimistic)); Assert.That(domainConfig.VersioningConvention.DenyEntitySetOwnerVersionChange, Is.EqualTo(false)); } [Test] - public void VersioningConventionDefaultTest() + [TestCase(true)] + [TestCase(false)] + public void VersioningConventionDefaultTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithVersioningConvention3"); + var domainConfig = LoadDomainConfiguration("DomainWithVersioningConvention3", useRoot); ValidateAllDefault(domainConfig); Assert.That(domainConfig.VersioningConvention.EntityVersioningPolicy, Is.EqualTo(EntityVersioningPolicy.Default)); @@ -784,9 +915,11 @@ public void VersioningConventionDefaultTest() } [Test] - public void VersioningConventionDenyEntitySetChangeVersionTest() + [TestCase(true)] + [TestCase(false)] + public void VersioningConventionDenyEntitySetChangeVersionTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithVersioningConvention4"); + var domainConfig = LoadDomainConfiguration("DomainWithVersioningConvention4", useRoot); ValidateAllDefault(domainConfig); Assert.That(domainConfig.VersioningConvention.EntityVersioningPolicy, Is.EqualTo(EntityVersioningPolicy.Optimistic)); @@ -794,27 +927,34 @@ public void VersioningConventionDenyEntitySetChangeVersionTest() } [Test] - public void VersioningConventionAllowEntitySetChangeVersionTest() + [TestCase(true)] + [TestCase(false)] + public void VersioningConventionAllowEntitySetChangeVersionTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithVersioningConvention5"); + var domainConfig = LoadDomainConfiguration("DomainWithVersioningConvention5", useRoot); ValidateAllDefault(domainConfig); Assert.That(domainConfig.VersioningConvention.EntityVersioningPolicy, Is.EqualTo(EntityVersioningPolicy.Optimistic)); Assert.That(domainConfig.VersioningConvention.DenyEntitySetOwnerVersionChange, Is.EqualTo(false)); } [Test] - public void VersioningConventionInvalidTest() + [TestCase(true)] + [TestCase(false)] + public void VersioningConventionInvalidTest(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidVersioningConvention1")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidVersioningConvention1", useRoot)); } #endregion #region Types registration + [Test] - public void TypesRegistrationAsTypesTest() + [TestCase(true)] + [TestCase(false)] + public void TypesRegistrationAsTypesTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithTypes"); + var domainConfig = LoadDomainConfiguration("DomainWithTypes", useRoot); ValidateAllDefault(domainConfig); Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.DummyEntity1)), Is.True); Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.DummyEntity2)), Is.True); @@ -822,9 +962,11 @@ public void TypesRegistrationAsTypesTest() } [Test] - public void TypesRegistrationAsAssembliesTest() + [TestCase(true)] + [TestCase(false)] + public void TypesRegistrationAsAssembliesTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithAssemblies"); + var domainConfig = LoadDomainConfiguration("DomainWithAssemblies", useRoot); ValidateAllDefault(domainConfig); var ormAssembly = typeof(DomainConfiguration).Assembly; Assert.That(domainConfig.Types.Count, Is.GreaterThan(0)); @@ -832,18 +974,22 @@ public void TypesRegistrationAsAssembliesTest() } [Test] - public void TypesRegistrationAsAssembliesWithNamespace() + [TestCase(true)] + [TestCase(false)] + public void TypesRegistrationAsAssembliesWithNamespace(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithAssembliesAndNamespaces"); + var domainConfig = LoadDomainConfiguration("DomainWithAssembliesAndNamespaces", useRoot); ValidateAllDefault(domainConfig); Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.NestedNamespace.DummyNestedEntity1)), Is.True); Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.NestedNamespace.DummyNestedEntity2)), Is.True); } [Test] - public void MixedTypeRegistration() + [TestCase(true)] + [TestCase(false)] + public void MixedTypeRegistration(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithMixedRegistrations"); + var domainConfig = LoadDomainConfiguration("DomainWithMixedRegistrations", useRoot); ValidateAllDefault(domainConfig); Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.DummyEntity1)), Is.True); Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.DummyEntity2)), Is.True); @@ -853,11 +999,13 @@ public void MixedTypeRegistration() } [Test] - public void InvalidTypeRegistration1() + [TestCase(true)] + [TestCase(false)] + public void InvalidTypeRegistration1(bool useRoot) { // same type twice - var domainConfig = LoadDomainConfiguration("DomainWithInvalidRegistrations1"); + var domainConfig = LoadDomainConfiguration("DomainWithInvalidRegistrations1", useRoot); ValidateAllDefault(domainConfig); Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.DummyEntity1)), Is.True); @@ -866,10 +1014,12 @@ public void InvalidTypeRegistration1() } [Test] - public void InvalidTypeRegistration2() + [TestCase(true)] + [TestCase(false)] + public void InvalidTypeRegistration2(bool useRoot) { // same Assembly - var domainConfig = LoadDomainConfiguration("DomainWithInvalidRegistrations2"); + var domainConfig = LoadDomainConfiguration("DomainWithInvalidRegistrations2", useRoot); ValidateAllDefault(domainConfig); var ormAssembly = typeof(DomainConfiguration).Assembly; @@ -878,37 +1028,47 @@ public void InvalidTypeRegistration2() } [Test] - public void InvalidTypeRegistration3() + [TestCase(true)] + [TestCase(false)] + public void InvalidTypeRegistration3(bool useRoot) { // same assembly and namespace - var domainConfig = LoadDomainConfiguration("DomainWithInvalidRegistrations3"); + var domainConfig = LoadDomainConfiguration("DomainWithInvalidRegistrations3", useRoot); ValidateAllDefault(domainConfig); Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.NestedNamespace.DummyNestedEntity1)), Is.True); Assert.That(domainConfig.Types.Contains(typeof(TypesToUseInTests.NestedNamespace.DummyNestedEntity2)), Is.True); } [Test] - public void InvalidTypeRegistration4() + [TestCase(true)] + [TestCase(false)] + public void InvalidTypeRegistration4(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidRegistrations4")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidRegistrations4", useRoot)); } [Test] - public void InvalidTypeRegistration5() + [TestCase(true)] + [TestCase(false)] + public void InvalidTypeRegistration5(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidRegistrations5")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidRegistrations5", useRoot)); } [Test] - public void InvalidTypeRegistration6() + [TestCase(true)] + [TestCase(false)] + public void InvalidTypeRegistration6(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidRegistrations6")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidRegistrations6", useRoot)); } [Test] - public void InvalidTypeRegistration7() + [TestCase(true)] + [TestCase(false)] + public void InvalidTypeRegistration7(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidRegistrations7")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidRegistrations7", useRoot)); } #endregion @@ -916,9 +1076,11 @@ public void InvalidTypeRegistration7() #region Sessions [Test] - public void MultipleSessionsTest() + [TestCase(true)] + [TestCase(false)] + public void MultipleSessionsTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithMultipleSessionConfigurations"); + var domainConfig = LoadDomainConfiguration("DomainWithMultipleSessionConfigurations", useRoot); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -940,9 +1102,11 @@ public void MultipleSessionsTest() } [Test] - public void SessionWithEmptyNameTest() + [TestCase(true)] + [TestCase(false)] + public void SessionWithEmptyNameTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithSessionEmptyName"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionEmptyName", useRoot); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -953,9 +1117,11 @@ public void SessionWithEmptyNameTest() } [Test] - public void SessionWithCustomNameTest() + [TestCase(true)] + [TestCase(false)] + public void SessionWithCustomNameTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomName"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomName", useRoot); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -968,9 +1134,11 @@ public void SessionWithCustomNameTest() } [Test] - public void SessionWithCustomUserNameTest() + [TestCase(true)] + [TestCase(false)] + public void SessionWithCustomUserNameTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomUser"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomUser", useRoot); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -982,9 +1150,11 @@ public void SessionWithCustomUserNameTest() } [Test] - public void SessionWithOptionsTest1() + [TestCase(true)] + [TestCase(false)] + public void SessionWithOptionsTest1(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithSessionDefaultOptions"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionDefaultOptions", useRoot); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -996,9 +1166,11 @@ public void SessionWithOptionsTest1() } [Test] - public void SessionWithOptionsTest2() + [TestCase(true)] + [TestCase(false)] + public void SessionWithOptionsTest2(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithSessionServerProfile"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionServerProfile", useRoot); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -1010,9 +1182,11 @@ public void SessionWithOptionsTest2() } [Test] - public void SessionWithOptionsTest3() + [TestCase(true)] + [TestCase(false)] + public void SessionWithOptionsTest3(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithSessionClientProfile"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionClientProfile", useRoot); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -1024,9 +1198,11 @@ public void SessionWithOptionsTest3() } [Test] - public void SessionWithOptionsTest4() + [TestCase(true)] + [TestCase(false)] + public void SessionWithOptionsTest4(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomOptions"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomOptions", useRoot); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -1038,9 +1214,11 @@ public void SessionWithOptionsTest4() } [Test] - public void SessionWithCollectionSizesTest() + [TestCase(true)] + [TestCase(false)] + public void SessionWithCollectionSizesTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithSessionWithCollectionSizes"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionWithCollectionSizes", useRoot); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -1054,9 +1232,11 @@ public void SessionWithCollectionSizesTest() } [Test] - public void SessionCustomCacheTypeTest() + [TestCase(true)] + [TestCase(false)] + public void SessionCustomCacheTypeTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomCacheType"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomCacheType", useRoot); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -1068,9 +1248,11 @@ public void SessionCustomCacheTypeTest() } [Test] - public void SessionCustomIsolationLevelTest() + [TestCase(true)] + [TestCase(false)] + public void SessionCustomIsolationLevelTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomIsolationLevel"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomIsolationLevel", useRoot); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -1082,9 +1264,11 @@ public void SessionCustomIsolationLevelTest() } [Test] - public void SessionCustomCommandTimeoutTest() + [TestCase(true)] + [TestCase(false)] + public void SessionCustomCommandTimeoutTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomCommandTimeout"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomCommandTimeout", useRoot); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -1096,9 +1280,11 @@ public void SessionCustomCommandTimeoutTest() } [Test] - public void SessionCustomPreloadingPolicyTest() + [TestCase(true)] + [TestCase(false)] + public void SessionCustomPreloadingPolicyTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomPreloadingPolicy"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomPreloadingPolicy", useRoot); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -1110,9 +1296,11 @@ public void SessionCustomPreloadingPolicyTest() } [Test] - public void SessionCustomConnectionStringTest() + [TestCase(true)] + [TestCase(false)] + public void SessionCustomConnectionStringTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomConnectionString"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomConnectionString", useRoot); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; @@ -1123,9 +1311,11 @@ public void SessionCustomConnectionStringTest() } [Test] - public void SessionCustomConnectionUrlTest() + [TestCase(true)] + [TestCase(false)] + public void SessionCustomConnectionUrlTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomConnectionUrl"); + var domainConfig = LoadDomainConfiguration("DomainWithSessionCustomConnectionUrl", useRoot); ValidateAllDefault(domainConfig); var sessions = domainConfig.Sessions; Assert.That(sessions.Count, Is.EqualTo(1)); @@ -1135,57 +1325,75 @@ public void SessionCustomConnectionUrlTest() } [Test] - public void SessionWithInvalidOptions() + [TestCase(true)] + [TestCase(false)] + public void SessionWithInvalidOptions(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidOptions")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidOptions", useRoot)); } [Test] - public void SessionWithInvalidCacheSizeTest1() + [TestCase(true)] + [TestCase(false)] + public void SessionWithInvalidCacheSizeTest1(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidCacheSize1")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidCacheSize1", useRoot)); } [Test] - public void SessionWithInvalidCacheSizeTest2() + [TestCase(true)] + [TestCase(false)] + public void SessionWithInvalidCacheSizeTest2(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidCacheSize2")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidCacheSize2", useRoot)); } [Test] - public void SessionWithInvalidCacheSizeTest3() + [TestCase(true)] + [TestCase(false)] + public void SessionWithInvalidCacheSizeTest3(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidCacheSize3")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidCacheSize3", useRoot)); } [Test] - public void SessionWithInvalidBatchSizeTest1() + [TestCase(true)] + [TestCase(false)] + public void SessionWithInvalidBatchSizeTest1(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidBatchSize1")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidBatchSize1", useRoot)); } [Test] - public void SessionWithInvalidBatchSizeTest2() + [TestCase(true)] + [TestCase(false)] + public void SessionWithInvalidBatchSizeTest2(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidBatchSize2")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidBatchSize2", useRoot)); } [Test] - public void SessionWithInvalidEntityChangeRegistryTest1() + [TestCase(true)] + [TestCase(false)] + public void SessionWithInvalidEntityChangeRegistryTest1(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidEntityChangeRegistry1")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidEntityChangeRegistry1", useRoot)); } [Test] - public void SessionWithInvalidEntityChangeRegistryTest2() + [TestCase(true)] + [TestCase(false)] + public void SessionWithInvalidEntityChangeRegistryTest2(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidEntityChangeRegistry2")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidEntityChangeRegistry2", useRoot)); } [Test] - public void SessionWithInvalidCacheType1() + [TestCase(true)] + [TestCase(false)] + public void SessionWithInvalidCacheType1(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidCacheType")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithSessionInvalidCacheType", useRoot)); } #endregion @@ -1193,9 +1401,11 @@ public void SessionWithInvalidCacheType1() #region Databases configuration [Test] - public void DatabaseConfigurationOnlyAliasTest() + [TestCase(true)] + [TestCase(false)] + public void DatabaseConfigurationOnlyAliasTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithDatabases1"); + var domainConfig = LoadDomainConfiguration("DomainWithDatabases1", useRoot); ValidateAllDefault(domainConfig); Assert.That(domainConfig.Databases.Count, Is.EqualTo(2)); var db1 = domainConfig.Databases[0]; @@ -1211,9 +1421,11 @@ public void DatabaseConfigurationOnlyAliasTest() } [Test] - public void DatabaseConfigurationWithTypeIdsTest() + [TestCase(true)] + [TestCase(false)] + public void DatabaseConfigurationWithTypeIdsTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithDatabases2"); + var domainConfig = LoadDomainConfiguration("DomainWithDatabases2", useRoot); ValidateAllDefault(domainConfig); Assert.That(domainConfig.Databases.Count, Is.EqualTo(2)); var db1 = domainConfig.Databases[0]; @@ -1229,27 +1441,35 @@ public void DatabaseConfigurationWithTypeIdsTest() } [Test] - public void DatabaseConfigurationNegativeMinTypeIdTest() + [TestCase(true)] + [TestCase(false)] + public void DatabaseConfigurationNegativeMinTypeIdTest(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidDatabases1")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidDatabases1", useRoot)); } [Test] - public void DatabaseConfigurationInvalidMinTypeIdTest() + [TestCase(true)] + [TestCase(false)] + public void DatabaseConfigurationInvalidMinTypeIdTest(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidDatabases2")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidDatabases2", useRoot)); } [Test] - public void DatabaseConfigurationNegativeMaxTypeIdTest() + [TestCase(true)] + [TestCase(false)] + public void DatabaseConfigurationNegativeMaxTypeIdTest(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidDatabases3")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidDatabases3", useRoot)); } [Test] - public void DatabaseConfigurationInvalidMaxTypeIdTest() + [TestCase(true)] + [TestCase(false)] + public void DatabaseConfigurationInvalidMaxTypeIdTest(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidDatabases4")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidDatabases4", useRoot)); } #endregion @@ -1257,71 +1477,87 @@ public void DatabaseConfigurationInvalidMaxTypeIdTest() #region KeyGenerators [Test] - public void SimpleKeyGeneratorTest() + [TestCase(true)] + [TestCase(false)] + public void SimpleKeyGeneratorTest(bool useRoot) { if (!NameAttributeUnique) throw new IgnoreException(""); - var domainConfig = LoadDomainConfiguration("DomainWithCustomGenerator"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomGenerator", useRoot); ValidateAllDefault(domainConfig); } [Test] - public void KeyGeneratorWithDatabaseNamesTest() + [TestCase(true)] + [TestCase(false)] + public void KeyGeneratorWithDatabaseNamesTest(bool useRoot) { if (!NameAttributeUnique) throw new IgnoreException(""); - var domainConfig = LoadDomainConfiguration("DomainWithCustomGeneratorsWithDatabaseNames"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomGeneratorsWithDatabaseNames", useRoot); ValidateAllDefault(domainConfig); } [Test] - public void KeyGeneratorWithDatabaseNamesAllParamsTest() + [TestCase(true)] + [TestCase(false)] + public void KeyGeneratorWithDatabaseNamesAllParamsTest(bool useRoot) { if (!NameAttributeUnique) throw new IgnoreException(""); - var domainConfig = LoadDomainConfiguration("DomainWithCustomGeneratorsWithDatabaseNamesAndKeyParams"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomGeneratorsWithDatabaseNamesAndKeyParams", useRoot); ValidateAllDefault(domainConfig); } [Test] - public void KeyGeneratorsWithDatabaseAliasesTest() + [TestCase(true)] + [TestCase(false)] + public void KeyGeneratorsWithDatabaseAliasesTest(bool useRoot) { if (!NameAttributeUnique) throw new IgnoreException(""); - var domainConfig = LoadDomainConfiguration("DomainWithCustomGeneratorsWithDatabasesAliases"); + var domainConfig = LoadDomainConfiguration("DomainWithCustomGeneratorsWithDatabasesAliases", useRoot); ValidateAllDefault(domainConfig); } [Test] - public void KeyGeneratorsWithConflictByDatabaseTest1() + [TestCase(true)] + [TestCase(false)] + public void KeyGeneratorsWithConflictByDatabaseTest1(bool useRoot) { if (!NameAttributeUnique) throw new IgnoreException(""); - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomGeneratorsConflict1")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomGeneratorsConflict1", useRoot)); } [Test] - public void KeyGeneratorsWithConflictByDatabaseTest2() + [TestCase(true)] + [TestCase(false)] + public void KeyGeneratorsWithConflictByDatabaseTest2(bool useRoot) { if (!NameAttributeUnique) throw new IgnoreException(""); - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomGeneratorsConflict2")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomGeneratorsConflict2", useRoot)); } [Test] - public void KeyGeneratorWithNegativeSeedTest() + [TestCase(true)] + [TestCase(false)] + public void KeyGeneratorWithNegativeSeedTest(bool useRoot) { if (!NameAttributeUnique) throw new IgnoreException(""); - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomGeneratorNegativeSeed")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomGeneratorNegativeSeed", useRoot)); } [Test] - public void KeyGeneratorWithNegativeCacheSizeTest() + [TestCase(true)] + [TestCase(false)] + public void KeyGeneratorWithNegativeCacheSizeTest(bool useRoot) { if (!NameAttributeUnique) throw new IgnoreException(""); - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomGeneratorNegativeCache")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithCustomGeneratorNegativeCache", useRoot)); } #endregion @@ -1329,35 +1565,45 @@ public void KeyGeneratorWithNegativeCacheSizeTest() #region IgnoreRules [Test] - public void IgnoreRulesTest() + [TestCase(true)] + [TestCase(false)] + public void IgnoreRulesTest(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithIgnoreRules"); + var domainConfig = LoadDomainConfiguration("DomainWithIgnoreRules", useRoot); ValidateAllDefault(domainConfig); ValidateIgnoreRules(domainConfig.IgnoreRules); } [Test] - public void IgnoreColumnAndIndexAtTheSameTimeTest() + [TestCase(true)] + [TestCase(false)] + public void IgnoreColumnAndIndexAtTheSameTimeTest(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidIgnoreRules1")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidIgnoreRules1", useRoot)); } [Test] - public void IgnoreTableAndColumnAndIndexAtTheSameTimeTest() + [TestCase(true)] + [TestCase(false)] + public void IgnoreTableAndColumnAndIndexAtTheSameTimeTest(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidIgnoreRules2")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidIgnoreRules2", useRoot)); } [Test] - public void IgnoreDatabaseOnlyTest() + [TestCase(true)] + [TestCase(false)] + public void IgnoreDatabaseOnlyTest(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidIgnoreRules3")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidIgnoreRules3", useRoot)); } [Test] - public void IgnoreDatabaseAndSchemaOnlyTest() + [TestCase(true)] + [TestCase(false)] + public void IgnoreDatabaseAndSchemaOnlyTest(bool useRoot) { - _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidIgnoreRules4")); + _ = Assert.Throws(() => LoadDomainConfiguration("DomainWithInvalidIgnoreRules4", useRoot)); } private void ValidateIgnoreRules(IgnoreRuleCollection rules) @@ -1496,9 +1742,11 @@ private void ValidateIgnoreRules(IgnoreRuleCollection rules) #region MappingRules [Test] - public void MappingRulesTest1() + [TestCase(true)] + [TestCase(false)] + public void MappingRulesTest1(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithMappingRules1"); + var domainConfig = LoadDomainConfiguration("DomainWithMappingRules1", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.DefaultDatabase, "main"), ((d) => d.DefaultSchema, "dbo"), @@ -1515,9 +1763,11 @@ public void MappingRulesTest1() } [Test] - public void MappingRulesTest2() + [TestCase(true)] + [TestCase(false)] + public void MappingRulesTest2(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithMappingRules2"); + var domainConfig = LoadDomainConfiguration("DomainWithMappingRules2", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.DefaultDatabase, "main"), ((d) => d.DefaultSchema, "dbo"), @@ -1531,14 +1781,14 @@ public void MappingRulesTest2() Assert.That(rule.Namespace, Is.Null); Assert.That(rule.Database, Is.Null); Assert.That(rule.Schema, Is.EqualTo("Model1")); - - } [Test] - public void MappingRulesTest3() + [TestCase(true)] + [TestCase(false)] + public void MappingRulesTest3(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithMappingRules3"); + var domainConfig = LoadDomainConfiguration("DomainWithMappingRules3", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.DefaultDatabase, "main"), ((d) => d.DefaultSchema, "dbo"), @@ -1556,9 +1806,11 @@ public void MappingRulesTest3() } [Test] - public void MappingRulesTest4() + [TestCase(true)] + [TestCase(false)] + public void MappingRulesTest4(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithMappingRules4"); + var domainConfig = LoadDomainConfiguration("DomainWithMappingRules4", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.DefaultDatabase, "main"), ((d) => d.DefaultSchema, "dbo"), @@ -1576,9 +1828,11 @@ public void MappingRulesTest4() } [Test] - public void MappingRulesTest5() + [TestCase(true)] + [TestCase(false)] + public void MappingRulesTest5(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithMappingRules5"); + var domainConfig = LoadDomainConfiguration("DomainWithMappingRules5", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.DefaultDatabase, "main"), ((d) => d.DefaultSchema, "dbo"), @@ -1596,9 +1850,11 @@ public void MappingRulesTest5() } [Test] - public void MappingRulesTest6() + [TestCase(true)] + [TestCase(false)] + public void MappingRulesTest6(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithMappingRules6"); + var domainConfig = LoadDomainConfiguration("DomainWithMappingRules6", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.DefaultDatabase, "main"), ((d) => d.DefaultSchema, "dbo"), @@ -1615,9 +1871,11 @@ public void MappingRulesTest6() } [Test] - public void MappingRulesTest7() + [TestCase(true)] + [TestCase(false)] + public void MappingRulesTest7(bool useRoot) { - var domainConfig = LoadDomainConfiguration("DomainWithMappingRules7"); + var domainConfig = LoadDomainConfiguration("DomainWithMappingRules7", useRoot); ValidateAllDefaultExcept(domainConfig, ((d) => d.DefaultDatabase, "main"), ((d) => d.DefaultSchema, "dbo"), @@ -1634,52 +1892,66 @@ public void MappingRulesTest7() } [Test] - public void MappingRuleWithConflictByAssemblyTest() + [TestCase(true)] + [TestCase(false)] + public void MappingRuleWithConflictByAssemblyTest(bool useRoot) { var exception = Assert.Throws( - () => LoadDomainConfiguration("DomainWithConflictMappingRules1")); + () => LoadDomainConfiguration("DomainWithConflictMappingRules1", useRoot)); } [Test] - public void MappingRuleWithConflictByNamespaceTest() + [TestCase(true)] + [TestCase(false)] + public void MappingRuleWithConflictByNamespaceTest(bool useRoot) { var exception = Assert.Throws( - () => LoadDomainConfiguration("DomainWithConflictMappingRules2")); + () => LoadDomainConfiguration("DomainWithConflictMappingRules2", useRoot)); } [Test] - public void MappingRulesInvalidTest1() + [TestCase(true)] + [TestCase(false)] + public void MappingRulesInvalidTest1(bool useRoot) { var exception = Assert.Throws( - () => LoadDomainConfiguration("DomainWithInvalidMappingRules1")); + () => LoadDomainConfiguration("DomainWithInvalidMappingRules1", useRoot)); } [Test] - public void MappingRulesInvalidTest2() + [TestCase(true)] + [TestCase(false)] + public void MappingRulesInvalidTest2(bool useRoot) { var exception = Assert.Throws( - () => LoadDomainConfiguration("DomainWithInvalidMappingRules2")); + () => LoadDomainConfiguration("DomainWithInvalidMappingRules2", useRoot)); } [Test] - public void MappingRulesInvalidTest3() + [TestCase(true)] + [TestCase(false)] + public void MappingRulesInvalidTest3(bool useRoot) { var exception = Assert.Throws( - () => LoadDomainConfiguration("DomainWithInvalidMappingRules3")); + () => LoadDomainConfiguration("DomainWithInvalidMappingRules3", useRoot)); } [Test] - public void MappingRulesInvalidTest4() + [TestCase(true)] + [TestCase(false)] + public void MappingRulesInvalidTest4(bool useRoot) { var exception = Assert.Throws( - () => LoadDomainConfiguration("DomainWithInvalidMappingRules4")); + () => LoadDomainConfiguration("DomainWithInvalidMappingRules4", useRoot)); } [Test] - public void MappingRulesInvalidTest5() + [TestCase(true)] + [TestCase(false)] + public void MappingRulesInvalidTest5(bool useRoot) { var exception = Assert.Throws( - () => LoadDomainConfiguration("DomainWithInvalidMappingRules5")); + () => LoadDomainConfiguration("DomainWithInvalidMappingRules5", useRoot)); } #endregion @@ -1761,22 +2033,6 @@ private void ValidateAllDefault(DomainConfiguration domainConfiguration) Assert.That(domainConfiguration.UpgradeMode, Is.EqualTo(DomainConfiguration.DefaultUpgradeMode)); } - private void ValidateAllDefault(SessionConfiguration sessionConfiguration) - { - Assert.That(sessionConfiguration.UserName, Is.Empty); - Assert.That(sessionConfiguration.Password, Is.Empty); - Assert.That(sessionConfiguration.Options, Is.EqualTo(SessionConfiguration.DefaultSessionOptions)); - Assert.That(sessionConfiguration.CacheSize, Is.EqualTo(SessionConfiguration.DefaultCacheSize)); - Assert.That(sessionConfiguration.CacheType, Is.EqualTo(SessionConfiguration.DefaultCacheType)); - Assert.That(sessionConfiguration.DefaultIsolationLevel, Is.EqualTo(SessionConfiguration.DefaultDefaultIsolationLevel)); - Assert.That(sessionConfiguration.DefaultCommandTimeout, Is.Null); - Assert.That(sessionConfiguration.BatchSize, Is.EqualTo(SessionConfiguration.DefaultBatchSize)); - Assert.That(sessionConfiguration.EntityChangeRegistrySize, Is.EqualTo(SessionConfiguration.DefaultEntityChangeRegistrySize)); - Assert.That(sessionConfiguration.ReaderPreloading, Is.EqualTo(SessionConfiguration.DefaultReaderPreloadingPolicy)); - Assert.That(sessionConfiguration.ServiceContainerType, Is.Null); - Assert.That(sessionConfiguration.ConnectionInfo, Is.Null); - } - private void ValidateAllDefaultExcept(TConfiguration configuration, (Expression> expression, T1 expectedValue) property) { From 573d12492bcecad83280e7dbd629e9a05f633c21 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Mon, 23 Sep 2024 18:19:33 +0500 Subject: [PATCH 18/32] Fix wrong section names in tests --- .../Tests/ModernConfigurationTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Extensions/Xtensive.Orm.Security.Tests/Tests/ModernConfigurationTests.cs b/Extensions/Xtensive.Orm.Security.Tests/Tests/ModernConfigurationTests.cs index 257fefa286..d77849ab0d 100644 --- a/Extensions/Xtensive.Orm.Security.Tests/Tests/ModernConfigurationTests.cs +++ b/Extensions/Xtensive.Orm.Security.Tests/Tests/ModernConfigurationTests.cs @@ -389,7 +389,7 @@ public void OnlyAuthenticationServiceWithNameNodeNotDefault() [Test] public void NameNodeInLowCase() { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.LC"); + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.Naming.LC"); var secConfig = SecurityConfiguration.Load(section); ValidateNamingConfigurationResults(secConfig); } @@ -397,7 +397,7 @@ public void NameNodeInLowCase() [Test] public void NameNodeInUpperCase() { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.UC"); + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.Naming.UC"); var secConfig = SecurityConfiguration.Load(section); ValidateNamingConfigurationResults(secConfig); } @@ -405,7 +405,7 @@ public void NameNodeInUpperCase() [Test] public void NameNodeInCamelCase() { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.CC"); + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.Naming.CC"); var secConfig = SecurityConfiguration.Load(section); ValidateNamingConfigurationResults(secConfig); } @@ -413,7 +413,7 @@ public void NameNodeInCamelCase() [Test] public void NameNodeInPascalCase() { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.PC"); + var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.Naming.PC"); var secConfig = SecurityConfiguration.Load(section); ValidateNamingConfigurationResults(secConfig); } From 6759bb38a90db66de43287ce3d6f3a982ee16c5c Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Mon, 23 Sep 2024 18:40:35 +0500 Subject: [PATCH 19/32] Update package version for NET5 build --- .../Xtensive.Orm.Localization.csproj | 4 ++-- .../Xtensive.Orm.Reprocessing.csproj | 4 ++-- Extensions/Xtensive.Orm.Security/Xtensive.Orm.Security.csproj | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Extensions/Xtensive.Orm.Localization/Xtensive.Orm.Localization.csproj b/Extensions/Xtensive.Orm.Localization/Xtensive.Orm.Localization.csproj index e39ae0b162..bea774e22d 100644 --- a/Extensions/Xtensive.Orm.Localization/Xtensive.Orm.Localization.csproj +++ b/Extensions/Xtensive.Orm.Localization/Xtensive.Orm.Localization.csproj @@ -31,8 +31,8 @@ - - + + diff --git a/Extensions/Xtensive.Orm.Reprocessing/Xtensive.Orm.Reprocessing.csproj b/Extensions/Xtensive.Orm.Reprocessing/Xtensive.Orm.Reprocessing.csproj index a578eae546..6bf37921d3 100644 --- a/Extensions/Xtensive.Orm.Reprocessing/Xtensive.Orm.Reprocessing.csproj +++ b/Extensions/Xtensive.Orm.Reprocessing/Xtensive.Orm.Reprocessing.csproj @@ -17,8 +17,8 @@ - - + + diff --git a/Extensions/Xtensive.Orm.Security/Xtensive.Orm.Security.csproj b/Extensions/Xtensive.Orm.Security/Xtensive.Orm.Security.csproj index bde5c3aff8..c1ee63836a 100644 --- a/Extensions/Xtensive.Orm.Security/Xtensive.Orm.Security.csproj +++ b/Extensions/Xtensive.Orm.Security/Xtensive.Orm.Security.csproj @@ -18,8 +18,8 @@ - - + + From b6c3adf045487a4ddd40f61cb7ab0362b2322525 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Mon, 23 Sep 2024 18:44:09 +0500 Subject: [PATCH 20/32] Configuration reading based on IConfigurationSectionReader implementations --- .../LocalizationConfiguration.cs | 91 ++------ .../LocalizationConfigurationReader.cs | 66 ++++++ .../ReprocessingConfiguration.cs | 49 +---- .../ReprocessingConfigurationReader.cs | 61 ++++++ .../Configuration/SecurityConfiguration.cs | 194 +++--------------- .../SecurityConfigurationReaders.cs | 114 ++++++++++ 6 files changed, 294 insertions(+), 281 deletions(-) create mode 100644 Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfigurationReader.cs create mode 100644 Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfigurationReader.cs create mode 100644 Extensions/Xtensive.Orm.Security/Configuration/SecurityConfigurationReaders.cs diff --git a/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfiguration.cs b/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfiguration.cs index 72a90d34d3..7c5b57b842 100644 --- a/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfiguration.cs +++ b/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfiguration.cs @@ -11,6 +11,7 @@ using System.Threading; using Microsoft.Extensions.Configuration; using Xtensive.Core; +using Xtensive.Orm.Configuration; namespace Xtensive.Orm.Localization.Configuration { @@ -38,7 +39,7 @@ private class LocalizationOptions /// Gets or sets the default culture. /// /// The default culture. - public CultureInfo DefaultCulture { get; private set; } + public CultureInfo DefaultCulture { get; internal set; } /// /// Loads the @@ -114,90 +115,30 @@ private static LocalizationConfiguration GetConfigurationFromSection(Configurati return result; } + /// + /// Loads from given configuration section. + /// + /// to load from. + /// Loaded configuration or default configuration if loading failed for some reason. public static LocalizationConfiguration Load(IConfigurationSection configurationSection) { ArgumentValidator.EnsureArgumentNotNull(configurationSection, nameof(configurationSection)); - if (TryReadAsOptions(configurationSection, out var localizationConfiguration)) - return localizationConfiguration; - - // if failed then try to handle unusual formats or xml with name attribute - return TryReadUnusualOrOldFormats(configurationSection, out var fallbackConfiguration) - ? fallbackConfiguration - : new LocalizationConfiguration { - DefaultCulture = Thread.CurrentThread.CurrentCulture - }; - } - - private static bool TryReadAsOptions(IConfigurationSection rootSection, out LocalizationConfiguration localizationConfiguration) - { - LocalizationOptions localizationOptions; - try { - localizationOptions = rootSection.Get(); - } - catch { - localizationConfiguration = null; - return false; - } - - if (localizationOptions != null) { - if (!string.IsNullOrEmpty(localizationOptions.DefaultCulture)) { - try { - var culture = new CultureInfo(localizationOptions.DefaultCulture); - localizationConfiguration = new LocalizationConfiguration() { DefaultCulture = culture }; - return true; - } - catch (CultureNotFoundException) { - } - } - } - localizationConfiguration = null; - return false; + return new LocalizationConfigurationReader().Read(configurationSection); } /// - /// Tries to read configuration of old format that supported by - /// old - /// or configuration where name of service is element, not attribute. + /// Loads from given configuration section of . + /// If section name is not provided is used. /// - /// A configuration section that contains data to read. - /// Read configuration or null if reading was not successful. - /// if reading is successful, otherwise . - private static bool TryReadUnusualOrOldFormats(IConfigurationSection rootSection, - out LocalizationConfiguration localizationConfiguration) + /// of sections. + /// Custom section name to load from. + /// Loaded configuration or default configuration if loading failed for some reason. + public static LocalizationConfiguration Load(IConfigurationRoot configurationRoot, string sectionName = null) { - var defaultCultureSection = rootSection.GetSection(DefaultCultureElementName); - - if (defaultCultureSection == null) { - localizationConfiguration = null; - return false; - } - - var cultureName = defaultCultureSection.GetSection(CultureNameAttributeName)?.Value; - if (cultureName == null) { - var children = defaultCultureSection.GetChildren().ToList(); - if (children.Count > 0) { - cultureName = children[0].GetSection(CultureNameAttributeName).Value; - } - } + ArgumentValidator.EnsureArgumentNotNull(configurationRoot, nameof(configurationRoot)); - if (cultureName != null && ! string.IsNullOrEmpty(cultureName)) { - try { - var culture = new CultureInfo(cultureName); - localizationConfiguration = new LocalizationConfiguration() { - DefaultCulture = culture - }; - return true; - } - catch (CultureNotFoundException) { - localizationConfiguration = new LocalizationConfiguration() { - DefaultCulture = Thread.CurrentThread.CurrentCulture - }; - return true; - } - } - localizationConfiguration = null; - return false; + return new LocalizationConfigurationReader().Read(configurationRoot, sectionName ?? DefaultSectionName); } } } \ No newline at end of file diff --git a/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfigurationReader.cs b/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfigurationReader.cs new file mode 100644 index 0000000000..11cc298693 --- /dev/null +++ b/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfigurationReader.cs @@ -0,0 +1,66 @@ +// Copyright (C) 2011-2024 Xtensive LLC. +// All rights reserved. +// For conditions of distribution and use, see license. +// Created by: Dmitri Maximov +// Created: 2012.07.06 + +using System; +using System.Globalization; +using System.Linq; +using System.Threading; +using Microsoft.Extensions.Configuration; +using Xtensive.Core; +using Xtensive.Orm.Configuration; + +namespace Xtensive.Orm.Localization.Configuration +{ + internal sealed class LocalizationConfigurationReader : IConfigurationSectionReader + { + public LocalizationConfiguration Read(IConfigurationSection configurationSection) => ReadInternal(configurationSection); + + public LocalizationConfiguration Read(IConfigurationSection configurationSection, string nameOfConfiguration) => + throw new NotSupportedException(); + + public LocalizationConfiguration Read(IConfigurationRoot configurationRoot) => + Read(configurationRoot, LocalizationConfiguration.DefaultSectionName); + + public LocalizationConfiguration Read(IConfigurationRoot configurationRoot, string sectionName) + { + var section = configurationRoot.GetSection(sectionName); + return ReadInternal(section); + } + + public LocalizationConfiguration Read(IConfigurationRoot configurationRoot, string sectionName, string nameOfConfiguration) => + throw new NotSupportedException(); + + private const string DefaultCultureElementName = "DefaultCulture"; + private const string CultureNameAttributeName = "name"; + + private LocalizationConfiguration ReadInternal(IConfigurationSection configurationSection) + { + var defaultCultureSection = configurationSection.GetSection(DefaultCultureElementName); + if (defaultCultureSection == null) + return new LocalizationConfiguration() { DefaultCulture = Thread.CurrentThread.CurrentCulture }; + + var cultureName = defaultCultureSection.Value; + if (cultureName == null) { + cultureName = defaultCultureSection.GetSection(CultureNameAttributeName)?.Value; + if (cultureName == null) { + var children = defaultCultureSection.GetChildren().ToList(); + if (children.Count > 0) { + cultureName = children[0].GetSection(CultureNameAttributeName).Value; + } + } + } + + if (cultureName.IsNullOrEmpty()) + return new LocalizationConfiguration() { DefaultCulture = Thread.CurrentThread.CurrentCulture }; + try { + return new LocalizationConfiguration() { DefaultCulture = new CultureInfo(cultureName) }; + } + catch (CultureNotFoundException) { + return new LocalizationConfiguration() { DefaultCulture = Thread.CurrentThread.CurrentCulture }; + } + } + } +} \ No newline at end of file diff --git a/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfiguration.cs b/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfiguration.cs index 7dc4fac9ee..3c72c56469 100644 --- a/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfiguration.cs +++ b/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfiguration.cs @@ -2,6 +2,7 @@ using System.Configuration; using Microsoft.Extensions.Configuration; using Xtensive.Core; +using Xtensive.Orm.Configuration; namespace Xtensive.Orm.Reprocessing.Configuration { @@ -10,14 +11,6 @@ namespace Xtensive.Orm.Reprocessing.Configuration /// public class ReprocessingConfiguration { - // intermediate class for reading section - private class ReprocessingOptions - { - public string DefaultTransactionOpenMode { get; set; } - - public string DefaultExecuteStrategy { get; set; } - } - /// /// Gets default value of the property. /// @@ -99,40 +92,20 @@ public static ReprocessingConfiguration Load(IConfigurationSection configuration { ArgumentValidator.EnsureArgumentNotNull(configurationSection, nameof(configurationSection)); - return TryReadAsOptions(configurationSection, out var reprocessingConfiguration) - ? reprocessingConfiguration - : new ReprocessingConfiguration(); + return new ReprocessingConfigurationReader().Read(configurationSection); } - private static bool TryReadAsOptions(IConfigurationSection configuration, out ReprocessingConfiguration reprocessingConfiguration) + /// + /// Loads the from specified section of configuration root. + /// + /// to load section from. + /// Name of the section where configuration is stored. + /// Loaded configuration or configuration with default settings. + public static ReprocessingConfiguration Load(IConfigurationRoot configurationRoot, string sectionName = null) { - var reprocessingOptions = configuration.Get(); - - if (reprocessingOptions == default) { - reprocessingConfiguration = null; - return false; - } - - if (reprocessingOptions.DefaultTransactionOpenMode == default - && reprocessingOptions.DefaultExecuteStrategy == default) { - // that means instance is default. probably invalid - reprocessingConfiguration = null; - return false; - } + ArgumentValidator.EnsureArgumentNotNull(configurationRoot, nameof(configurationRoot)); - var result = new ReprocessingConfiguration(); - if (reprocessingOptions.DefaultTransactionOpenMode != default - && Enum.TryParse(reprocessingOptions.DefaultTransactionOpenMode, out var enumValue)) { - result.DefaultTransactionOpenMode = enumValue; - } - if (!string.IsNullOrEmpty(reprocessingOptions.DefaultExecuteStrategy)) { - var type = Type.GetType(reprocessingOptions.DefaultExecuteStrategy, false); - if (type == null) - throw new InvalidOperationException($"Can't resolve type '{reprocessingOptions.DefaultExecuteStrategy}'. Note that DefaultExecuteStrategy value should be in form of Assembly Qualified Name"); - result.DefaultExecuteStrategy = type; - } - reprocessingConfiguration = result; - return true; + return new ReprocessingConfigurationReader().Read(configurationRoot, sectionName ?? ConfigurationSection.DefaultSectionName); } /// diff --git a/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfigurationReader.cs b/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfigurationReader.cs new file mode 100644 index 0000000000..7ea1ba6e47 --- /dev/null +++ b/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfigurationReader.cs @@ -0,0 +1,61 @@ +using System; +using Microsoft.Extensions.Configuration; +using Xtensive.Orm.Configuration; + +namespace Xtensive.Orm.Reprocessing.Configuration +{ + internal sealed class ReprocessingConfigurationReader : IConfigurationSectionReader + { + // intermediate class for reading section + private class ReprocessingOptions + { + public TransactionOpenMode DefaultTransactionOpenMode { get; set; } + + public string DefaultExecuteStrategy { get; set; } + } + + public ReprocessingConfiguration Read(IConfigurationSection configurationSection) => ReadInternal(configurationSection); + + public ReprocessingConfiguration Read(IConfigurationSection configurationSection, string nameOfConfiguration) => + throw new NotSupportedException(); + + public ReprocessingConfiguration Read(IConfigurationRoot configurationRoot) => + Read(configurationRoot, ConfigurationSection.DefaultSectionName); + + public ReprocessingConfiguration Read(IConfigurationRoot configurationRoot, string sectionName) + { + var section = configurationRoot.GetSection(sectionName); + return ReadInternal(section); + } + + public ReprocessingConfiguration Read(IConfigurationRoot configurationRoot, string sectionName, string nameOfConfiguration) => + throw new NotSupportedException(); + + private ReprocessingConfiguration ReadInternal(IConfigurationSection section) + { + var reprocessingOptions = section.Get(); + + if (reprocessingOptions == default) { + return new ReprocessingConfiguration(); + } + + if (reprocessingOptions.DefaultTransactionOpenMode == default + && reprocessingOptions.DefaultExecuteStrategy == default) { + // that means instance is default. probably invalid + return new ReprocessingConfiguration(); + } + + var result = new ReprocessingConfiguration(); + if (reprocessingOptions.DefaultTransactionOpenMode != default) { + result.DefaultTransactionOpenMode = reprocessingOptions.DefaultTransactionOpenMode; + } + if (!string.IsNullOrEmpty(reprocessingOptions.DefaultExecuteStrategy)) { + var type = Type.GetType(reprocessingOptions.DefaultExecuteStrategy, false); + if (type == null) + throw new InvalidOperationException($"Can't resolve type '{reprocessingOptions.DefaultExecuteStrategy}'. Note that DefaultExecuteStrategy value should be in form of Assembly Qualified Name"); + result.DefaultExecuteStrategy = type; + } + return result; + } + } +} \ No newline at end of file diff --git a/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfiguration.cs b/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfiguration.cs index 679d762549..3e7332a87f 100644 --- a/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfiguration.cs +++ b/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfiguration.cs @@ -19,43 +19,6 @@ namespace Xtensive.Orm.Security.Configuration [Serializable] public class SecurityConfiguration { - #region nested types -#pragma warning disable CS0661, CS0659 // Type defines operator == or operator != but does not override Object.GetHashCode() -#if !NET6_0_OR_GREATER - /// - /// Represents Json and XML without neither name attributes nor name as child element; - /// - private struct SecurityOptions - { - public string HashingService { get; set; } - - public string AuthenticationService { get; set; } - - public static bool operator ==(SecurityOptions r1, SecurityOptions r2) - { - return (r1.HashingService, r1.AuthenticationService) == (r2.HashingService, r2.AuthenticationService); - } - - public static bool operator !=(SecurityOptions r1, SecurityOptions r2) - { - return (r1.HashingService, r1.AuthenticationService) != (r2.HashingService, r2.AuthenticationService); - } - - public override bool Equals(object obj) - { - if (obj is null) - return false; - if (obj is SecurityOptions objRep) - return (HashingService, AuthenticationService) == (objRep.HashingService, objRep.AuthenticationService); - return false; - } - } - -#endif -#pragma warning restore CS0661, CS0659 // Type defines operator == or operator != but does not override Object.GetHashCode() - -#endregion - /// /// Default SectionName value: /// "". @@ -65,11 +28,9 @@ public override bool Equals(object obj) internal const string HashingServiceElementName = "HashingService"; internal const string AuthenticationServiceElementName = "AuthenticationService"; - private const string DefaultHashingServiceName = "plain"; - private const string DefaultAuthenticationServiceName = "default"; - private const string ServiceNameAttributeName = "name"; + internal const string DefaultHashingServiceName = "plain"; + internal const string DefaultAuthenticationServiceName = "default"; -#if NET6_0_OR_GREATER /// /// Gets or sets the name of the hashing service. /// @@ -83,19 +44,6 @@ public override bool Equals(object obj) /// The name of the authentication service. [ConfigurationKeyName(AuthenticationServiceElementName)] public string AuthenticationServiceName { get; set; } -#else - /// - /// Gets or sets the name of the hashing service. - /// - /// The name of the hashing service. - public string HashingServiceName { get; set; } - - /// - /// Gets or sets the name of the authentication service. - /// - /// The name of the authentication service. - public string AuthenticationServiceName { get; set; } -#endif /// /// Loads the @@ -175,127 +123,34 @@ public static SecurityConfiguration Load(IConfigurationSection configurationSect { ArgumentValidator.EnsureArgumentNotNull(configurationSection, nameof(configurationSection)); - // First attempt is to read modern xml or json - if (TryReadConfigurationAsTypeInstance(configurationSection, out var fromModerntStyle)) - return fromModerntStyle; + var configuration = new NamelessFormatSecurityConfigurationReader().Read(configurationSection); + if (configuration != null) + return configuration; - // if failed then try to handle unusual formats or xml with name attribute - return TryReadUnusualOrOldFormats(configurationSection, out var fallbackConfiguration) - ? fallbackConfiguration - : new SecurityConfiguration(true); + configuration = new BasedOnNamesFormatSecurityConfigurationReader().Read(configurationSection); + if (configuration != null) + return configuration; + return new SecurityConfiguration(true); } /// - /// Tries to read configuration of most relevant format where service names declared as child nodes. - /// - /// A configuration section that contains data to read. - /// - /// if reading is successful, otherwise - private static bool TryReadConfigurationAsTypeInstance(IConfigurationSection configuration, out SecurityConfiguration securityConfiguration) - { - // - // sha1 - // SomeServiceName - // - // or - // "Xtensive.Orm.Security" : { - // "hashingService" :"sha1", - // "authenticationService" : "SomeServiceName" - // } - -#if NET6_0_OR_GREATER - try { - - var configAsIs = configuration.Get(); - if (configAsIs != null && (configAsIs.AuthenticationServiceName ?? configAsIs.HashingServiceName) != null) { - configAsIs.HashingServiceName = string.IsNullOrEmpty(configAsIs.HashingServiceName) - ? DefaultHashingServiceName - : configAsIs.HashingServiceName.ToLowerInvariant(); - configAsIs.AuthenticationServiceName = string.IsNullOrEmpty(configAsIs.AuthenticationServiceName) - ? DefaultAuthenticationServiceName - : (configAsIs.AuthenticationServiceName?.ToLowerInvariant()); - securityConfiguration = configAsIs; - return true; - } - } - catch { - securityConfiguration = null; - return false; - } -#else - try { - var securityOptions = configuration.Get(); - if (securityOptions != default) { - securityConfiguration = new SecurityConfiguration(true); - if (!string.IsNullOrEmpty(securityOptions.HashingService)) - securityConfiguration.HashingServiceName = securityOptions.HashingService.ToLowerInvariant(); - if(!string.IsNullOrEmpty(securityOptions.AuthenticationService)) - securityConfiguration.AuthenticationServiceName = securityOptions.AuthenticationService.ToLowerInvariant(); ; - - return true; - } - } - catch { - securityConfiguration = null; - return false; - } -#endif - var children = configuration.GetChildren().ToList(); - if (!children.Any()) { - securityConfiguration = new SecurityConfiguration(true); - return true; - } - else { - securityConfiguration = null; - return false; - } - } - - /// - /// Tries to read configuration of old format that supported by - /// old - /// or configuration where name of service is element, not attribute. + /// Loads the from given configuration section. /// - /// A configuration section that contains data to read. - /// Read configuration or null if reading was not successful. - /// if reading is successful, otherwise . - private static bool TryReadUnusualOrOldFormats(IConfigurationSection configuration, - out SecurityConfiguration securityConfiguration) + /// to load section from. + /// Name of the section where configuration is stored. + /// Loaded configuration or configuration with default settings. + public static SecurityConfiguration Load(IConfigurationRoot configurationRoot, string sectionName) { - var hashingServiceSection = configuration.GetSection(HashingServiceElementName); - var authenticationServiceSection = configuration.GetSection(AuthenticationServiceElementName); - - if (hashingServiceSection == null && authenticationServiceSection == null) { - securityConfiguration = null; - return false; - } + ArgumentValidator.EnsureArgumentNotNull(configurationRoot, nameof(configurationRoot)); - var hashingServiceName = hashingServiceSection.GetSection(ServiceNameAttributeName)?.Value; - if (hashingServiceName == null) { - var children = hashingServiceSection.GetChildren().ToList(); - if (children.Count > 0) { - hashingServiceName = children[0].GetSection(ServiceNameAttributeName).Value; - } - } - - var authenticationServiceName = authenticationServiceSection.GetSection(ServiceNameAttributeName)?.Value; - if (authenticationServiceName == null) { - var children = authenticationServiceSection.GetChildren().ToList(); - if (children.Count > 0) { - authenticationServiceName = children[0].GetSection(ServiceNameAttributeName).Value; - } - } - if ((hashingServiceName ?? authenticationServiceName) != null) { - securityConfiguration = new SecurityConfiguration(true); - if (!string.IsNullOrEmpty(hashingServiceName)) - securityConfiguration.HashingServiceName = hashingServiceName.ToLowerInvariant(); - if (!string.IsNullOrEmpty(authenticationServiceName)) - securityConfiguration.AuthenticationServiceName = authenticationServiceName.ToLowerInvariant(); + var configuration = new NamelessFormatSecurityConfigurationReader().Read(configurationRoot, sectionName ?? DefaultSectionName); + if (configuration != null) + return configuration; - return true; - } - securityConfiguration = null; - return false; + configuration = new BasedOnNamesFormatSecurityConfigurationReader().Read(configurationRoot, sectionName ?? DefaultSectionName); + if (configuration != null) + return configuration; + return new SecurityConfiguration(true); } /// @@ -305,7 +160,10 @@ public SecurityConfiguration() { } - private SecurityConfiguration(bool initWithDefaults) + /// + /// Creates instance of with properties initialized on demand. + /// + internal SecurityConfiguration(bool initWithDefaults) { if (initWithDefaults) { HashingServiceName = DefaultHashingServiceName; diff --git a/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfigurationReaders.cs b/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfigurationReaders.cs new file mode 100644 index 0000000000..dfd98f5193 --- /dev/null +++ b/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfigurationReaders.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; +using Xtensive.Orm.Configuration; + +namespace Xtensive.Orm.Security.Configuration +{ + internal sealed class NamelessFormatSecurityConfigurationReader : SecurityConfigurationReader + { + protected override SecurityConfiguration ReadInternal(IConfigurationSection configuration) + { + // + // sha1 + // SomeServiceName + // + // or + // "Xtensive.Orm.Security" : { + // "hashingService" :"sha1", + // "authenticationService" : "SomeServiceName" + // } + + try { + var configAsIs = configuration.Get(); + if (configAsIs != null && (configAsIs.AuthenticationServiceName ?? configAsIs.HashingServiceName) != null) { + configAsIs.HashingServiceName = string.IsNullOrEmpty(configAsIs.HashingServiceName) + ? SecurityConfiguration.DefaultHashingServiceName + : configAsIs.HashingServiceName.ToLowerInvariant(); + configAsIs.AuthenticationServiceName = string.IsNullOrEmpty(configAsIs.AuthenticationServiceName) + ? SecurityConfiguration.DefaultAuthenticationServiceName + : (configAsIs.AuthenticationServiceName?.ToLowerInvariant()); + return configAsIs; + } + } + catch { + return null; + } + + var children = configuration.GetChildren().ToList(); + if (!children.Any()) { + return new SecurityConfiguration(true); + } + else { + return null; + } + } + } + + internal sealed class BasedOnNamesFormatSecurityConfigurationReader : SecurityConfigurationReader + { + private const string ServiceNameAttributeName = "name"; + + protected override SecurityConfiguration ReadInternal(IConfigurationSection configuration) + { + + var hashingServiceSection = configuration.GetSection(SecurityConfiguration.HashingServiceElementName); + var authenticationServiceSection = configuration.GetSection(SecurityConfiguration.AuthenticationServiceElementName); + + if (hashingServiceSection == null && authenticationServiceSection == null) { + return null; + } + + var hashingServiceName = hashingServiceSection.GetSection(ServiceNameAttributeName)?.Value; + if (hashingServiceName == null) { + var children = hashingServiceSection.GetChildren().ToList(); + if (children.Count > 0) { + hashingServiceName = children[0].GetSection(ServiceNameAttributeName).Value; + } + } + + var authenticationServiceName = authenticationServiceSection.GetSection(ServiceNameAttributeName)?.Value; + if (authenticationServiceName == null) { + var children = authenticationServiceSection.GetChildren().ToList(); + if (children.Count > 0) { + authenticationServiceName = children[0].GetSection(ServiceNameAttributeName).Value; + } + } + if ((hashingServiceName ?? authenticationServiceName) != null) { + var securityConfiguration = new SecurityConfiguration(true); + if (!string.IsNullOrEmpty(hashingServiceName)) + securityConfiguration.HashingServiceName = hashingServiceName.ToLowerInvariant(); + if (!string.IsNullOrEmpty(authenticationServiceName)) + securityConfiguration.AuthenticationServiceName = authenticationServiceName.ToLowerInvariant(); + + return securityConfiguration; + } + return null; + } + } + + internal abstract class SecurityConfigurationReader : IConfigurationSectionReader + { + public SecurityConfiguration Read(IConfigurationSection configurationSection) => ReadInternal(configurationSection); + + public SecurityConfiguration Read(IConfigurationSection configurationSection, string nameOfConfiguration) => + throw new NotSupportedException(); + + public SecurityConfiguration Read(IConfigurationRoot configurationRoot) => + Read(configurationRoot, SecurityConfiguration.DefaultSectionName); + + public SecurityConfiguration Read(IConfigurationRoot configurationRoot, string sectionName) + { + var section = configurationRoot.GetSection(sectionName); + return ReadInternal(section); + } + + public SecurityConfiguration Read(IConfigurationRoot configurationRoot, string sectionName, string nameOfConfiguration) => + throw new NotSupportedException(); + + protected abstract SecurityConfiguration ReadInternal(IConfigurationSection section); + } +} From 496f9680ef402be7f4eae38ef084871446895ff4 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Tue, 1 Oct 2024 15:47:40 +0500 Subject: [PATCH 21/32] Unified place for extension configurations introduced - This allow extensions to be configured not only after domain is built but, if needed, during Upgrade process. Localization extension needs it. - This source is alternative to XxxConfiguration.Load() call which is outdated. - It also allow users to instanciate configurations and actually use them instead of forcefully configure them in config files. This gives a way to not rely on our Load methods or any other new "fancy" configuration APIs Microsoft "invents" (which sometimes broken for certain types of configuration sources :-)). Instance of configuration can be put to well-known collection instead of finding a work-around by looking at source code to figure out how to get configuration and where to put the instance of it to make extension work. - For user convenience a set of extensions for DomainConfiguration provided to configure extensions from different resources, including configuration instance --- .../LocalizationConfiguration.cs | 58 ++++++-- .../DomainConfugurationExtensions.cs | 130 +++++++++++++++++ .../Internals/TypeLocalizationMap.cs | 15 +- .../ReprocessingConfiguration.cs | 70 +++++++-- .../DomainConfigurationExtensions.cs | 104 ++++++++++++++ .../DomainExtensions.cs | 7 +- .../Configuration/SecurityConfiguration.cs | 62 ++++++-- .../DomainConfugurationExtensions.cs | 108 ++++++++++++++ .../SessionExtensions.cs | 16 ++- .../Orm/Configuration/ConfigurationBase.cs | 2 +- .../Orm/Configuration/DomainConfiguration.cs | 16 +++ .../ExtensionConfigurationCollection.cs | 133 ++++++++++++++++++ .../Orm/Configuration/LogConfiguration.cs | 29 +++- .../Orm/Configuration/LoggingConfiguration.cs | 55 +++++++- .../Orm/Upgrade/UpgradingDomainBuilder.cs | 12 +- 15 files changed, 762 insertions(+), 55 deletions(-) create mode 100644 Extensions/Xtensive.Orm.Localization/DomainConfugurationExtensions.cs create mode 100644 Extensions/Xtensive.Orm.Reprocessing/DomainConfigurationExtensions.cs create mode 100644 Extensions/Xtensive.Orm.Security/DomainConfugurationExtensions.cs create mode 100644 Orm/Xtensive.Orm/Orm/Configuration/Internals/ExtensionConfigurationCollection.cs diff --git a/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfiguration.cs b/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfiguration.cs index 7c5b57b842..ac8c0a3e1e 100644 --- a/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfiguration.cs +++ b/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfiguration.cs @@ -19,27 +19,43 @@ namespace Xtensive.Orm.Localization.Configuration /// The configuration of the localization extension. /// [Serializable] - public class LocalizationConfiguration + public class LocalizationConfiguration : ConfigurationBase { - private class LocalizationOptions - { - public string DefaultCulture { get; set; } = null; - } - /// /// Default SectionName value: /// "". /// public const string DefaultSectionName = "Xtensive.Orm.Localization"; - private const string DefaultCultureElementName = "DefaultCulture"; - private const string CultureNameAttributeName = "name"; + private CultureInfo culture; /// /// Gets or sets the default culture. /// /// The default culture. - public CultureInfo DefaultCulture { get; internal set; } + public CultureInfo DefaultCulture { + get => culture; + internal set { + EnsureNotLocked(); + culture = value; + } + } + + /// + protected override LocalizationConfiguration CreateClone() => new LocalizationConfiguration(); + + /// + protected override void CopyFrom(ConfigurationBase source) + { + base.CopyFrom(source); + + var nativeConfig = source as LocalizationConfiguration; + nativeConfig.DefaultCulture = DefaultCulture; + } + + /// + public override LocalizationConfiguration Clone() => (LocalizationConfiguration) base.Clone(); + /// /// Loads the @@ -115,6 +131,30 @@ private static LocalizationConfiguration GetConfigurationFromSection(Configurati return result; } + /// + /// Loads from given configuration section of . + /// If section name is not provided is used. + /// + /// of sections. + /// Custom section name to load from. + /// Loaded configuration or default configuration if loading failed for some reason. + public static LocalizationConfiguration Load(IConfiguration configuration, string sectionName = null) + { + ArgumentValidator.EnsureArgumentNotNull(configuration, nameof(configuration)); + + if (configuration is IConfigurationRoot configurationRoot) + return new LocalizationConfigurationReader().Read(configurationRoot, sectionName ?? DefaultSectionName); + else if (configuration is IConfigurationSection configurationSection) { + if (sectionName.IsNullOrEmpty()) + return new LocalizationConfigurationReader().Read(configurationSection); + else { + return new LocalizationConfigurationReader().Read(configurationSection.GetSection(sectionName)); + } + } + + throw new NotSupportedException("Type of configuration is not supported"); + } + /// /// Loads from given configuration section. /// diff --git a/Extensions/Xtensive.Orm.Localization/DomainConfugurationExtensions.cs b/Extensions/Xtensive.Orm.Localization/DomainConfugurationExtensions.cs new file mode 100644 index 0000000000..e63b2b0c74 --- /dev/null +++ b/Extensions/Xtensive.Orm.Localization/DomainConfugurationExtensions.cs @@ -0,0 +1,130 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using Microsoft.Extensions.Configuration; +using Xtensive.Orm.Configuration; +using Xtensive.Orm.Localization.Configuration; + +namespace Xtensive.Orm.Localization +{ + /// + /// Contains extensions for DomainConfiguration that help to configure the extension. + /// + public static class DomainConfugurationLocalizationExtensions + { + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// instance with configured extension. + public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration) + => ConfigureLocalizationExtension(domainConfiguration, LocalizationConfiguration.Load()); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Section name. + /// instance with configured extension. + public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration, + string configurationSectionName) => + ConfigureLocalizationExtension(domainConfiguration, LocalizationConfiguration.Load(configurationSectionName)); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Configuration to load from. + /// instance with configured extension. + public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration, + System.Configuration.Configuration configuration) => + ConfigureLocalizationExtension(domainConfiguration, LocalizationConfiguration.Load(configuration)); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Configuration to load from. + /// Section in + /// instance with configured extension. + public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration, + System.Configuration.Configuration configuration, string sectionName) => + ConfigureLocalizationExtension(domainConfiguration, LocalizationConfiguration.Load(configuration, sectionName)); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Configuration to load from. + /// instance with configured extension. + public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration, + IConfiguration configuration) => + ConfigureLocalizationExtension(domainConfiguration, LocalizationConfiguration.Load(configuration)); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Configuration to load from. + /// Section in + /// instance with configured extension. + public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration, + IConfiguration configuration, string sectionName = null) => + ConfigureLocalizationExtension(domainConfiguration, LocalizationConfiguration.Load(configuration, sectionName)); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Configuration to load from. + /// instance with configured extension. + public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration, + IConfigurationRoot configurationRoot) => + ConfigureLocalizationExtension(domainConfiguration, LocalizationConfiguration.Load(configurationRoot)); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Configuration to load from. + /// Section in + /// instance with configured extension. + public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration, + IConfigurationRoot configurationRoot, string sectionName) => + ConfigureLocalizationExtension(domainConfiguration, LocalizationConfiguration.Load(configurationRoot, sectionName)); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Configuration section to load from. + /// instance with configured extension. + public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration, + IConfigurationSection configurationSection) => + ConfigureLocalizationExtension(domainConfiguration, LocalizationConfiguration.Load(configurationSection)); + + /// + /// Configures the extension with given localization configuration instance. + /// + /// Domain configuration. + /// Localization configuration instance. + /// instance with configured extension. + public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration, + LocalizationConfiguration localizationConfiguration) + { + domainConfiguration.ExtensionConfigurations.Set(localizationConfiguration); + domainConfiguration.Types.Register(typeof(DomainConfugurationLocalizationExtensions).Assembly); + return domainConfiguration; + } + } +} \ No newline at end of file diff --git a/Extensions/Xtensive.Orm.Localization/Internals/TypeLocalizationMap.cs b/Extensions/Xtensive.Orm.Localization/Internals/TypeLocalizationMap.cs index 51e17ff140..2ac7db18cd 100644 --- a/Extensions/Xtensive.Orm.Localization/Internals/TypeLocalizationMap.cs +++ b/Extensions/Xtensive.Orm.Localization/Internals/TypeLocalizationMap.cs @@ -10,6 +10,7 @@ using Xtensive.Orm.Model; using Xtensive.Orm; using Xtensive.Reflection; +using Xtensive.Core; namespace Xtensive.Orm.Localization { @@ -21,13 +22,19 @@ internal class TypeLocalizationMap public static void Initialize(Domain domain) { - if (domain == null) - throw new ArgumentNullException("domain"); - if (domain.Extensions.Get() != null) + ArgumentValidator.EnsureArgumentNotNull(domain, nameof(domain)); + + var existing = domain.Extensions.Get(); + if (existing != null) { return; + } + + var configFromNewSource = domain.Configuration.ExtensionConfigurations.Get(); var map = new TypeLocalizationMap() { - Configuration = LocalizationConfiguration.Load() + Configuration = (configFromNewSource != null) + ? configFromNewSource + : LocalizationConfiguration.Load()// config from old source. }; foreach (var localizableTypeInfo in domain.Model.Types.Entities) { var type = localizableTypeInfo.UnderlyingType; diff --git a/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfiguration.cs b/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfiguration.cs index 3c72c56469..679ecbe256 100644 --- a/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfiguration.cs +++ b/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfiguration.cs @@ -9,7 +9,7 @@ namespace Xtensive.Orm.Reprocessing.Configuration /// /// The configuration of the reprocessing system. /// - public class ReprocessingConfiguration + public class ReprocessingConfiguration : ConfigurationBase { /// /// Gets default value of the property. @@ -21,15 +21,46 @@ public class ReprocessingConfiguration /// public static readonly Type DefaultDefaultExecuteStrategy = typeof (HandleReprocessableExceptionStrategy); + private TransactionOpenMode defaultTransactionOpenMode; + private Type defaultExecuteStrategy; + /// /// Gets or sets default value of the parameter. /// - public TransactionOpenMode DefaultTransactionOpenMode { get; set; } + public TransactionOpenMode DefaultTransactionOpenMode { + get => defaultTransactionOpenMode; + set { + EnsureNotLocked(); + defaultTransactionOpenMode = value; + } + } /// /// Gets or sets default value of the parameter. /// - public Type DefaultExecuteStrategy { get; set; } + public Type DefaultExecuteStrategy { + get => defaultExecuteStrategy; + set { + EnsureNotLocked(); + defaultExecuteStrategy = value; + } + } + + /// + protected override ReprocessingConfiguration CreateClone() => new ReprocessingConfiguration(); + + /// + protected override void CopyFrom(ConfigurationBase source) + { + base.CopyFrom(source); + + var configuration = (ReprocessingConfiguration) source; + configuration.DefaultTransactionOpenMode = configuration.DefaultTransactionOpenMode; + configuration.DefaultExecuteStrategy = configuration.DefaultExecuteStrategy; + } + + /// + public override ReprocessingConfiguration Clone() => (ReprocessingConfiguration) base.Clone(); /// /// Loads the reprocessing configuration from default section in application configuration file. @@ -84,17 +115,26 @@ private static ReprocessingConfiguration GetConfigurationFromSection(Configurati } /// - /// Loads the from given configuration section. + /// Loads the from specified section of configuration root. /// - /// to load from. + /// to load section from. + /// Name of the section where configuration is stored. Not applied if /// Loaded configuration or configuration with default settings. - public static ReprocessingConfiguration Load(IConfigurationSection configurationSection) + public static ReprocessingConfiguration Load(IConfiguration configuration, string sectionName = null) { - ArgumentValidator.EnsureArgumentNotNull(configurationSection, nameof(configurationSection)); + ArgumentValidator.EnsureArgumentNotNull(configuration, nameof(configuration)); - return new ReprocessingConfigurationReader().Read(configurationSection); + if (configuration is IConfigurationRoot configurationRoot) { + return new ReprocessingConfigurationReader().Read(configurationRoot, sectionName ?? ConfigurationSection.DefaultSectionName); + } + else if (configuration is IConfigurationSection configurationSection) { + return new ReprocessingConfigurationReader().Read(configurationSection); + } + + throw new NotSupportedException("Type of configuration is not supported"); } + /// /// Loads the from specified section of configuration root. /// @@ -108,6 +148,20 @@ public static ReprocessingConfiguration Load(IConfigurationRoot configurationRoo return new ReprocessingConfigurationReader().Read(configurationRoot, sectionName ?? ConfigurationSection.DefaultSectionName); } + /// + /// Loads the from given configuration section. + /// + /// to load from. + /// Loaded configuration or configuration with default settings. + public static ReprocessingConfiguration Load(IConfigurationSection configurationSection) + { + ArgumentValidator.EnsureArgumentNotNull(configurationSection, nameof(configurationSection)); + + return new ReprocessingConfigurationReader().Read(configurationSection); + } + + + /// /// Initializes a new instance of the class. /// diff --git a/Extensions/Xtensive.Orm.Reprocessing/DomainConfigurationExtensions.cs b/Extensions/Xtensive.Orm.Reprocessing/DomainConfigurationExtensions.cs new file mode 100644 index 0000000000..f0ddf8fda4 --- /dev/null +++ b/Extensions/Xtensive.Orm.Reprocessing/DomainConfigurationExtensions.cs @@ -0,0 +1,104 @@ +using Microsoft.Extensions.Configuration; +using Xtensive.Orm.Configuration; +using Xtensive.Orm.Reprocessing.Configuration; + +namespace Xtensive.Orm.Reprocessing +{ + /// + /// Contains extensions for DomainConfiguration that help to configure the extension. + /// + public static class DomainConfigurationReprocessingExtensions + { + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// instance with configured extension. + public static DomainConfiguration ConfigureReprocessingExtension(this DomainConfiguration domainConfiguration) => + ConfigureReprocessingExtension(domainConfiguration, ReprocessingConfiguration.Load()); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Section name. + /// instance with configured extension. + public static DomainConfiguration ConfigureReprocessingExtension(this DomainConfiguration domainConfiguration, + string configurationSectionName) => + ConfigureReprocessingExtension(domainConfiguration, ReprocessingConfiguration.Load(configurationSectionName)); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Configuration to load from. + /// instance with configured extension. + public static DomainConfiguration ConfigureReprocessingExtension(this DomainConfiguration domainConfiguration, + System.Configuration.Configuration configuration) => + ConfigureReprocessingExtension(domainConfiguration, ReprocessingConfiguration.Load(configuration)); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Configuration to load from. + /// Section in + /// instance with configured extension. + public static DomainConfiguration ConfigureReprocessingExtension(this DomainConfiguration domainConfiguration, + System.Configuration.Configuration configuration, string sectionName) => + ConfigureReprocessingExtension(domainConfiguration, ReprocessingConfiguration.Load(configuration, sectionName)); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Configuration to load from. + /// Section in + /// instance with configured extension. + public static DomainConfiguration ConfigureReprocessingExtension(this DomainConfiguration domainConfiguration, + IConfiguration configuration, string sectionName = null) => + ConfigureReprocessingExtension(domainConfiguration, ReprocessingConfiguration.Load(configuration, sectionName)); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Configuration to load from. + /// Section in + /// instance with configured extension. + public static DomainConfiguration ConfigureReprocessingExtension(this DomainConfiguration domainConfiguration, + IConfigurationRoot configurationRoot, string sectionName = null) => + ConfigureReprocessingExtension(domainConfiguration, ReprocessingConfiguration.Load(configurationRoot, sectionName)); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Configuration section to load from. + /// instance with configured extension. + public static DomainConfiguration ConfigureReprocessingExtension(this DomainConfiguration domainConfiguration, + IConfigurationSection configurationSection) => + ConfigureReprocessingExtension(domainConfiguration, ReprocessingConfiguration.Load(configurationSection)); + + /// + /// Configures the extension with given reprocessing configuration instance. + /// + /// Domain configuration. + /// Security configuration instance. + /// instance with configured extension. + public static DomainConfiguration ConfigureReprocessingExtension(this DomainConfiguration domainConfiguration, + ReprocessingConfiguration reprocessingConfiguration) + { + domainConfiguration.ExtensionConfigurations.Set(reprocessingConfiguration); + domainConfiguration.Types.Register(typeof(DomainConfigurationReprocessingExtensions).Assembly); + return domainConfiguration; + } + } +} \ No newline at end of file diff --git a/Extensions/Xtensive.Orm.Reprocessing/DomainExtensions.cs b/Extensions/Xtensive.Orm.Reprocessing/DomainExtensions.cs index 5e50e81184..dc14da20a0 100644 --- a/Extensions/Xtensive.Orm.Reprocessing/DomainExtensions.cs +++ b/Extensions/Xtensive.Orm.Reprocessing/DomainExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Transactions; +using Xtensive.Orm.Configuration; using Xtensive.Orm.Reprocessing.Configuration; namespace Xtensive.Orm.Reprocessing @@ -190,7 +191,8 @@ internal static T ExecuteInternal( IExecuteActionStrategy strategy, Func func) { - var config = domain.GetReprocessingConfiguration(); + var config = domain.Configuration.ExtensionConfigurations.Get() + ?? domain.GetReprocessingConfiguration(); if (strategy == null) { strategy = ExecuteActionStrategy.GetSingleton(config.DefaultExecuteStrategy); } @@ -208,7 +210,8 @@ internal static T ExecuteInternal( IExecuteActionStrategy strategy, Func func) { - var config = domain.GetReprocessingConfiguration(); + var config = domain.Configuration.ExtensionConfigurations.Get() + ?? domain.GetReprocessingConfiguration(); if (strategy == null) { strategy = ExecuteActionStrategy.GetSingleton(config.DefaultExecuteStrategy); } diff --git a/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfiguration.cs b/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfiguration.cs index 3e7332a87f..1a38c9e447 100644 --- a/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfiguration.cs +++ b/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfiguration.cs @@ -10,6 +10,7 @@ using System.Threading; using Microsoft.Extensions.Configuration; using Xtensive.Core; +using Xtensive.Orm.Configuration; namespace Xtensive.Orm.Security.Configuration { @@ -17,7 +18,7 @@ namespace Xtensive.Orm.Security.Configuration /// The configuration of the security system. /// [Serializable] - public class SecurityConfiguration + public class SecurityConfiguration : ConfigurationBase { /// /// Default SectionName value: @@ -45,6 +46,22 @@ public class SecurityConfiguration [ConfigurationKeyName(AuthenticationServiceElementName)] public string AuthenticationServiceName { get; set; } + /// + protected override SecurityConfiguration CreateClone() => new SecurityConfiguration(); + + /// + protected override void CopyFrom(ConfigurationBase source) + { + base.CopyFrom(source); + + var configuration = (SecurityConfiguration) source; + configuration.HashingServiceName = configuration.HashingServiceName; + configuration.AuthenticationServiceName = configuration.AuthenticationServiceName; + } + + /// + public override SecurityConfiguration Clone() => (SecurityConfiguration) base.Clone(); + /// /// Loads the /// from application configuration file (section with ). @@ -117,29 +134,31 @@ private static SecurityConfiguration GetConfigurationFromSection(ConfigurationSe /// /// Loads the from given configuration section. /// - /// to load from. + /// to load section from. + /// Name of the section where configuration is stored. /// Loaded configuration or configuration with default settings. - public static SecurityConfiguration Load(IConfigurationSection configurationSection) + public static SecurityConfiguration Load(IConfiguration configuration, string sectionName = null) { - ArgumentValidator.EnsureArgumentNotNull(configurationSection, nameof(configurationSection)); + ArgumentValidator.EnsureArgumentNotNull(configuration, nameof(configuration)); - var configuration = new NamelessFormatSecurityConfigurationReader().Read(configurationSection); - if (configuration != null) - return configuration; + if (configuration is IConfigurationRoot configurationRoot) { + return Load(configurationRoot, sectionName); + } + else if (configuration is IConfigurationSection configurationSection) { + return Load(configurationSection); + } - configuration = new BasedOnNamesFormatSecurityConfigurationReader().Read(configurationSection); - if (configuration != null) - return configuration; - return new SecurityConfiguration(true); + throw new NotSupportedException("Type of configuration is not supported"); } + /// /// Loads the from given configuration section. /// /// to load section from. /// Name of the section where configuration is stored. /// Loaded configuration or configuration with default settings. - public static SecurityConfiguration Load(IConfigurationRoot configurationRoot, string sectionName) + public static SecurityConfiguration Load(IConfigurationRoot configurationRoot, string sectionName = null) { ArgumentValidator.EnsureArgumentNotNull(configurationRoot, nameof(configurationRoot)); @@ -153,6 +172,25 @@ public static SecurityConfiguration Load(IConfigurationRoot configurationRoot, s return new SecurityConfiguration(true); } + /// + /// Loads the from given configuration section. + /// + /// to load from. + /// Loaded configuration or configuration with default settings. + public static SecurityConfiguration Load(IConfigurationSection configurationSection) + { + ArgumentValidator.EnsureArgumentNotNull(configurationSection, nameof(configurationSection)); + + var configuration = new NamelessFormatSecurityConfigurationReader().Read(configurationSection); + if (configuration != null) + return configuration; + + configuration = new BasedOnNamesFormatSecurityConfigurationReader().Read(configurationSection); + if (configuration != null) + return configuration; + return new SecurityConfiguration(true); + } + /// /// Creates instance of with no properties initialized. /// diff --git a/Extensions/Xtensive.Orm.Security/DomainConfugurationExtensions.cs b/Extensions/Xtensive.Orm.Security/DomainConfugurationExtensions.cs new file mode 100644 index 0000000000..d480dc4995 --- /dev/null +++ b/Extensions/Xtensive.Orm.Security/DomainConfugurationExtensions.cs @@ -0,0 +1,108 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using Microsoft.Extensions.Configuration; +using Xtensive.Orm.Configuration; +using Xtensive.Orm.Security.Configuration; + +namespace Xtensive.Orm.Security +{ + /// + /// Contains extensions for DomainConfiguration that help to configure the extension. + /// + public static class DomainConfugurationSecurityExtensions + { + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// instance with configured extension. + public static DomainConfiguration ConfigureSecurityExtension(this DomainConfiguration domainConfiguration) => + ConfigureSecurityExtension(domainConfiguration, SecurityConfiguration.Load()); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Section name. + /// instance with configured extension. + public static DomainConfiguration ConfigureSecurityExtension(this DomainConfiguration domainConfiguration, + string configurationSectionName) => + ConfigureSecurityExtension(domainConfiguration, SecurityConfiguration.Load(configurationSectionName)); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Configuraton to load from. + /// instance with configured extension. + public static DomainConfiguration ConfigureSecurityExtension(this DomainConfiguration domainConfiguration, + System.Configuration.Configuration configuration) => + ConfigureSecurityExtension(domainConfiguration, SecurityConfiguration.Load(configuration)); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Configuraton to load from. + /// Section in + /// instance with configured extension. + public static DomainConfiguration ConfigureSecurityExtension(this DomainConfiguration domainConfiguration, + System.Configuration.Configuration configuration, string sectionName) => + ConfigureSecurityExtension(domainConfiguration, SecurityConfiguration.Load(configuration, sectionName)); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Configuraton to load from. + /// Section in + /// instance with configured extension. + public static DomainConfiguration ConfigureSecurityExtension(this DomainConfiguration domainConfiguration, + IConfiguration configuration, string sectionName = null) => + ConfigureSecurityExtension(domainConfiguration, SecurityConfiguration.Load(configuration, sectionName)); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Configuraton to load from. + /// Section in + /// instance with configured extension. + public static DomainConfiguration ConfigureSecurityExtension(this DomainConfiguration domainConfiguration, + IConfigurationRoot configurationRoot, string sectionName = null) => + ConfigureSecurityExtension(domainConfiguration, SecurityConfiguration.Load(configurationRoot, sectionName)); + + /// + /// Loads configuration by calling + /// and uses it to configure the extension. + /// + /// Domain configuration. + /// Configuration section to load from. + /// instance with configured extension. + public static DomainConfiguration ConfigureSecurityExtension(this DomainConfiguration domainConfiguration, + IConfigurationSection configurationSection) => + ConfigureSecurityExtension(domainConfiguration, SecurityConfiguration.Load(configurationSection)); + + /// + /// Configures the extension with given security configuration instance. + /// + /// Domain configuration. + /// Security configuration instance. + /// instance with configured extension. + public static DomainConfiguration ConfigureSecurityExtension(this DomainConfiguration domainConfiguration, + SecurityConfiguration securityConfiguration) + { + domainConfiguration.ExtensionConfigurations.Set(securityConfiguration); + domainConfiguration.Types.Register(typeof(DomainConfugurationSecurityExtensions).Assembly); + return domainConfiguration; + } + } +} \ No newline at end of file diff --git a/Extensions/Xtensive.Orm.Security/SessionExtensions.cs b/Extensions/Xtensive.Orm.Security/SessionExtensions.cs index 4df2ecefb4..39f02e4c89 100644 --- a/Extensions/Xtensive.Orm.Security/SessionExtensions.cs +++ b/Extensions/Xtensive.Orm.Security/SessionExtensions.cs @@ -4,6 +4,7 @@ // Created by: Dmitri Maximov // Created: 2011.05.22 +using System; using System.Security.Principal; using Xtensive.Core; using Xtensive.Orm.Security; @@ -12,6 +13,7 @@ namespace Xtensive.Orm { + /// /// Session extension methods for security-related stuff. /// @@ -24,12 +26,16 @@ public static class SessionExtensions /// instance. public static SecurityConfiguration GetSecurityConfiguration(this Session session) { - var result = session.Domain.Extensions.Get(); - if (result == null) { - result = SecurityConfiguration.Load(); - session.Domain.Extensions.Set(result); + var fromNewSource = session.Domain.Configuration.ExtensionConfigurations.Get(); + if (fromNewSource!=null) + return fromNewSource; + + var fromOldSource = session.Domain.Extensions.Get(); + if (fromOldSource == null) { + fromOldSource = SecurityConfiguration.Load(); + session.Domain.Extensions.Set(fromOldSource); } - return result; + return fromOldSource; } /// diff --git a/Orm/Xtensive.Orm/Orm/Configuration/ConfigurationBase.cs b/Orm/Xtensive.Orm/Orm/Configuration/ConfigurationBase.cs index 30aed0ce16..8b10852968 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/ConfigurationBase.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/ConfigurationBase.cs @@ -35,7 +35,7 @@ public override void Lock(bool recursive) /// public virtual object Clone() { - ConfigurationBase clone = CreateClone(); + var clone = CreateClone(); clone.CopyFrom(this); return clone; } diff --git a/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs b/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs index 1c5bcc4a01..46367fc1d9 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs @@ -9,6 +9,7 @@ using System.Linq; using JetBrains.Annotations; using Microsoft.Extensions.Configuration; +using Xtensive.Collections; using Xtensive.Core; using Xtensive.Orm.Configuration.Internals; using Xtensive.Orm.Internals; @@ -145,6 +146,7 @@ public class DomainConfiguration : ConfigurationBase private DatabaseConfigurationCollection databases = new(); private KeyGeneratorConfigurationCollection keyGenerators = new(); private IgnoreRuleCollection ignoreRules = new(); + private ExtensionConfigurationCollection extensionConfigurations = new(); private NamingConvention namingConvention = new(); private VersioningConvention versioningConvention = new(); private int keyCacheSize = DefaultKeyCacheSize; @@ -444,6 +446,18 @@ public Type ServiceContainerType } } + /// + /// Gets collection of additional configurations (configurations of extensions) + /// that might be required during domain build process. + /// + public ExtensionConfigurationCollection ExtensionConfigurations { + get => extensionConfigurations; + set { + EnsureNotLocked(); + extensionConfigurations = value; + } + } + /// /// Gets or sets value indicating whether SQL text of a query /// that caused error should be included in exception message. @@ -694,6 +708,7 @@ public override void Lock(bool recursive) keyGenerators.Lock(true); ignoreRules.Lock(true); versioningConvention.Lock(true); + extensionConfigurations.Lock(true); base.Lock(recursive); @@ -772,6 +787,7 @@ protected override void CopyFrom(ConfigurationBase source) shareStorageSchemaOverNodes = configuration.ShareStorageSchemaOverNodes; versioningConvention = (VersioningConvention) configuration.VersioningConvention.Clone(); preferTypeIdsAsQueryParameters = configuration.PreferTypeIdsAsQueryParameters; + ExtensionConfigurations = (ExtensionConfigurationCollection) configuration.ExtensionConfigurations.Clone(); } /// diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Internals/ExtensionConfigurationCollection.cs b/Orm/Xtensive.Orm/Orm/Configuration/Internals/ExtensionConfigurationCollection.cs new file mode 100644 index 0000000000..95b96b3e1b --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Configuration/Internals/ExtensionConfigurationCollection.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xtensive.Core; + +namespace Xtensive.Orm.Configuration +{ + /// + /// Default implementation (lockable). + /// + [Serializable] + public sealed class ExtensionConfigurationCollection : LockableBase + IEnumerable + { + private Dictionary extensionConfigurations; + + /// + /// Number of configurations in collection. + /// + public long Count + { + [DebuggerStepThrough] + get => extensionConfigurations != null ? extensionConfigurations.Count : 0; + } + + /// + /// Gets configuration of certain type from collection. + /// + /// Type of configuration to get. + /// Found configuration or . + [DebuggerStepThrough] + public T Get() + where T : ConfigurationBase + { + return extensionConfigurations != null && extensionConfigurations.TryGetValue(typeof(T), out var result) + ? (T) result + : null; + } + + /// + /// Adds or replace configuration of certain type + /// + /// Type of configuration. + /// Configuration to add or to replace existing one. + [DebuggerStepThrough] + public void Set(T value) + where T : ConfigurationBase + { + EnsureNotLocked(); + ArgumentValidator.EnsureArgumentNotNull(value, nameof(value)); + + var extensionConfigurationType = typeof(T); + + if (extensionConfigurations == null) { + extensionConfigurations = new Dictionary(); + } + + extensionConfigurations[extensionConfigurationType] = value; + } + + /// + /// Clears the collection. + /// + public void Clear() + { + EnsureNotLocked(); + extensionConfigurations = null; + } + + /// + public override void Lock(bool recursive) + { + base.Lock(recursive); + if (extensionConfigurations != null) + foreach (var pair in extensionConfigurations) { + pair.Value.Lock(recursive); + } + } + + #region ICloneable methods + + /// + public object Clone() + { + return new ExtensionConfigurationCollection(this); + } + + #endregion + + #region IEnumerable methods + + /// + [DebuggerStepThrough] + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + /// + public IEnumerator GetEnumerator() + { + return extensionConfigurations != null + ? extensionConfigurations.Values.GetEnumerator() + : Enumerable.Empty().GetEnumerator(); + } + + #endregion + + + // Constructors + + /// + /// Initializes new instance of this type. + /// + public ExtensionConfigurationCollection() + { + } + + /// + /// Initializes new instance of this type. + /// + /// The source to copy into this collection. + public ExtensionConfigurationCollection(ExtensionConfigurationCollection source) + : this() + { + ArgumentValidator.EnsureArgumentNotNull(source, nameof(source)); + if (source.Count == 0) + return; + extensionConfigurations = new Dictionary(source.extensionConfigurations); + } + } +} diff --git a/Orm/Xtensive.Orm/Orm/Configuration/LogConfiguration.cs b/Orm/Xtensive.Orm/Orm/Configuration/LogConfiguration.cs index 79fdbea29e..8326636011 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/LogConfiguration.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/LogConfiguration.cs @@ -1,25 +1,42 @@ -// Copyright (C) 2013 Xtensive LLC. +// Copyright (C) 2013 Xtensive LLC. // All rights reserved. // For conditions of distribution and use, see license. // Created by: Alexey Kulakov // Created: 2013.09.17 +using Xtensive.Core; + namespace Xtensive.Orm.Configuration { /// /// Configuration of log. /// - public class LogConfiguration + public class LogConfiguration : LockableBase { + private string source; + private string target; + /// /// Gets or sets source or sources of log separated by comma. /// - public string Source { get; set; } + public string Source { + get => source; + set { + EnsureNotLocked(); + source = value; + } + } /// /// Gets or sets targer of log. /// - public string Target { get; set; } + public string Target { + get => target; + set { + EnsureNotLocked(); + target = value; + } + } /// /// Creates new instance of this class @@ -28,8 +45,8 @@ public class LogConfiguration /// Targer for new log public LogConfiguration(string source, string target) { - Source = source; - Target = target; + this.source = source; + this.target = target; } } } diff --git a/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs b/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs index 9209e502cd..880c88ada6 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Configuration; +using System.Linq; using Microsoft.Extensions.Configuration; using Xtensive.Core; using Xtensive.Orm.Configuration.Internals; @@ -17,17 +18,59 @@ namespace Xtensive.Orm.Configuration /// /// Configuration of logging /// - public sealed class LoggingConfiguration + public sealed class LoggingConfiguration : ConfigurationBase { + private string provider; + private IList logs; + /// /// Gets or sets external provider. Provider's name specified as assembly qualified name. /// - public string Provider { get; set; } + public string Provider { + get => provider; + set { + EnsureNotLocked(); + provider = value; + } + } /// /// Gets or sets list of /// - public IList Logs { get; set; } + public IList Logs { + get => logs; + set { EnsureNotLocked(); logs = value; } + } + + public override void Lock(bool recursive) + { + if (logs is ListnativeList) { + logs = nativeList.AsReadOnly(); + } + else { + logs = logs.ToList().AsReadOnly(); + } + base.Lock(recursive); + + foreach (var log in logs) { + log.Lock(recursive); + } + } + + /// + protected override LoggingConfiguration CreateClone() => new LoggingConfiguration(); + + /// + protected override void CopyFrom(ConfigurationBase source) + { + base.CopyFrom(source); + var configuration = source as LoggingConfiguration; + Logs = new List(configuration.Logs); + Provider = configuration.Provider; + } + + /// + public override LoggingConfiguration Clone() => (LoggingConfiguration) base.Clone(); /// /// Loads logging configuration from the default configuration section. @@ -121,7 +164,7 @@ public static LoggingConfiguration Load(IConfigurationRoot configurationRoot, st /// public LoggingConfiguration() { - Logs = new List(); + logs = new List(); } /// @@ -130,8 +173,8 @@ public LoggingConfiguration() /// External provider for logging. Provider's name specified as assembly qualified name. public LoggingConfiguration(string provider) { - Provider = provider; - Logs = new List(); + this.provider = provider; + logs = new List(); } } } diff --git a/Orm/Xtensive.Orm/Orm/Upgrade/UpgradingDomainBuilder.cs b/Orm/Xtensive.Orm/Orm/Upgrade/UpgradingDomainBuilder.cs index 98e91c2910..a8e72e3e93 100644 --- a/Orm/Xtensive.Orm/Orm/Upgrade/UpgradingDomainBuilder.cs +++ b/Orm/Xtensive.Orm/Orm/Upgrade/UpgradingDomainBuilder.cs @@ -50,7 +50,11 @@ public static Domain Build(DomainConfiguration configuration) configuration.Lock(); } - LogManager.Default.AutoInitialize(); + var logConfiguration = configuration.ExtensionConfigurations.Get(); + if (logConfiguration != null) + LogManager.Default.Initialize(logConfiguration); + else + LogManager.Default.AutoInitialize(); var context = new UpgradeContext(configuration); @@ -72,7 +76,11 @@ public static async Task BuildAsync(DomainConfiguration configuration, C configuration.Lock(); } - LogManager.Default.AutoInitialize(); + var logConfiguration = configuration.ExtensionConfigurations.Get(); + if (logConfiguration != null) + LogManager.Default.Initialize(logConfiguration); + else + LogManager.Default.AutoInitialize(); var context = new UpgradeContext(configuration); From 702f88529aceab5b010ad0eb28632b25f1e13773 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Tue, 1 Oct 2024 16:22:37 +0500 Subject: [PATCH 22/32] Tests improved --- .../TestCommon/ModernConfigurationTestBase.cs | 6 +- .../ModernConfigurationTests.cs | 201 +++++++----- .../Tests/ModernConfugurationTests.cs | 207 +++++++----- .../Tests/ModernConfigurationTests.cs | 300 ++++++++++-------- 4 files changed, 419 insertions(+), 295 deletions(-) diff --git a/Extensions/TestCommon/ModernConfigurationTestBase.cs b/Extensions/TestCommon/ModernConfigurationTestBase.cs index 3a263ef80c..64a2a6b405 100644 --- a/Extensions/TestCommon/ModernConfigurationTestBase.cs +++ b/Extensions/TestCommon/ModernConfigurationTestBase.cs @@ -17,7 +17,7 @@ protected enum ConfigTypes Xml, } - protected IConfiguration configuration; + protected IConfigurationRoot configurationRoot; protected abstract ConfigTypes ConfigFormat { get; } @@ -29,7 +29,7 @@ public virtual void BeforeAllTestsSetUp() var configurationBuilder = new ConfigurationBuilder(); configurationBuilder.SetBasePath(Directory.GetCurrentDirectory()); AddConfigurationFile(configurationBuilder); - configuration = (ConfigurationRoot) configurationBuilder.Build(); + configurationRoot = (ConfigurationRoot) configurationBuilder.Build(); } protected void IgnoreIfXml() @@ -45,7 +45,7 @@ protected void IgnoreIfJson() protected IConfigurationSection GetAndCheckConfigurationSection(string sectionName) { - var section = configuration.GetSection(sectionName); + var section = configurationRoot.GetSection(sectionName); Assert.That(section, Is.Not.Null); return section; } diff --git a/Extensions/Xtensive.Orm.Localization.Tests/ModernConfigurationTests.cs b/Extensions/Xtensive.Orm.Localization.Tests/ModernConfigurationTests.cs index 40e861d528..b42a62fe0b 100644 --- a/Extensions/Xtensive.Orm.Localization.Tests/ModernConfigurationTests.cs +++ b/Extensions/Xtensive.Orm.Localization.Tests/ModernConfigurationTests.cs @@ -30,62 +30,68 @@ protected override void AddConfigurationFile(IConfigurationBuilder configuration } [Test] - public void NameAttributeEmptyNameTest() + [TestCase(true)] + [TestCase(false)] + public void NameAttributeEmptyNameTest(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Localization.NameAttribute.NameEmpty"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration("Xtensive.Orm.Localization.NameAttribute.NameEmpty", useRoot); CheckConfigurationIsDefault(locConfig); } [Test] - public void NameAttributeAbsentTest() + [TestCase(true)] + [TestCase(false)] + public void NameAttributeAbsentTest(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Localization.NameAttribute.None"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration("Xtensive.Orm.Localization.NameAttribute.None", useRoot); CheckConfigurationIsDefault(locConfig); } - [Test] - public void NameAttributeDefinedTest() + [TestCase(true)] + [TestCase(false)] + public void NameAttributeDefinedTest(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Localization.NameAttribute.Defined"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration("Xtensive.Orm.Localization.NameAttribute.Defined", useRoot); Assert.That(locConfig, Is.Not.Null); Assert.That(locConfig.DefaultCulture, Is.EqualTo(expectedCulture)); } [Test] - public void NameAttributeFaultyValueTest() + [TestCase(true)] + [TestCase(false)] + public void NameAttributeFaultyValueTest(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Localization.NameAttribute.FaultyValue"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration("Xtensive.Orm.Localization.NameAttribute.FaultyValue", useRoot); CheckConfigurationIsDefault(locConfig); } [Test] - public void NameAttributeLowCase() + [TestCase(true)] + [TestCase(false)] + public void NameAttributeLowCase(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Localization.NameAttribute.LC"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration("Xtensive.Orm.Localization.NameAttribute.LC", useRoot); Assert.That(locConfig, Is.Not.Null); Assert.That(locConfig.DefaultCulture, Is.EqualTo(expectedCulture)); } [Test] - public void NameAttributeUpperCase() + [TestCase(true)] + [TestCase(false)] + public void NameAttributeUpperCase(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Localization.NameAttribute.UC"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration("Xtensive.Orm.Localization.NameAttribute.UC", useRoot); Assert.That(locConfig, Is.Not.Null); Assert.That(locConfig.DefaultCulture, Is.EqualTo(expectedCulture)); } [Test] - public void NameAttributePascalCase() + [TestCase(true)] + [TestCase(false)] + public void NameAttributePascalCase(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Localization.NameAttribute.PC"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration("Xtensive.Orm.Localization.NameAttribute.PC", useRoot); Assert.That(locConfig, Is.Not.Null); Assert.That(locConfig.DefaultCulture, Is.EqualTo(expectedCulture)); } @@ -105,6 +111,13 @@ public override void BeforeAllTestsSetUp() } + protected LocalizationConfiguration LoadConfiguration(string sectionName, bool useRoot) + { + return useRoot + ? LocalizationConfiguration.Load(configurationRoot, sectionName) + : LocalizationConfiguration.Load(configurationRoot.GetSection(sectionName)); + } + [SetUp] public void SetUp() { @@ -119,69 +132,77 @@ public void TearDown() } [Test] - public void EmptySectionCase() + [TestCase(true)] + [TestCase(false)] + public void EmptySectionCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.Empty"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.Empty", useRoot); CheckConfigurationIsDefault(locConfig); } [Test] - public void EmptyName() + [TestCase(true)] + [TestCase(false)] + public void EmptyName(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameEmpty"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.NameEmpty", useRoot); CheckConfigurationIsDefault(locConfig); } [Test] - public void NameDefined() + [TestCase(true)] + [TestCase(false)] + public void NameDefined(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameDefined"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.NameDefined", useRoot); Assert.That(locConfig, Is.Not.Null); Assert.That(locConfig.DefaultCulture, Is.EqualTo(expectedCulture)); } [Test] - public void FaultyValue() + [TestCase(true)] + [TestCase(false)] + public void FaultyValue(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.FaultyValue"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.FaultyValue", useRoot); CheckConfigurationIsDefault(locConfig); } - #region Naming + [Test] - public void NamingInLowCase() + [TestCase(true)] + [TestCase(false)] + public void NamingInLowCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.Naming.LC"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.Naming.LC", useRoot); ValidateNamingConfigurationResults(locConfig); } [Test] - public void NamingInUpperCase() + [TestCase(true)] + [TestCase(false)] + public void NamingInUpperCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.Naming.UC"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.Naming.UC", useRoot); ValidateNamingConfigurationResults(locConfig); } [Test] - public void NamingInCamelCase() + [TestCase(true)] + [TestCase(false)] + public void NamingInCamelCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.Naming.CC"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.Naming.CC", useRoot); ValidateNamingConfigurationResults(locConfig); } [Test] - public void NamingInPascalCase() + [TestCase(true)] + [TestCase(false)] + public void NamingInPascalCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.Naming.PC"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.Naming.PC", useRoot); ValidateNamingConfigurationResults(locConfig); } @@ -190,38 +211,44 @@ private void ValidateNamingConfigurationResults(LocalizationConfiguration locCon Assert.That(locConfig, Is.Not.Null); Assert.That(locConfig.DefaultCulture, Is.EqualTo(expectedCulture)); } + #endregion #region mistype cases + [Test] - public void MistypeInLowCase() + [TestCase(true)] + [TestCase(false)] + public void MistypeInLowCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.Mistype.LC"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.Mistype.LC", useRoot); ValidateMistypeConfigurationResults(locConfig); } [Test] - public void MistypeInUpperCase() + [TestCase(true)] + [TestCase(false)] + public void MistypeInUpperCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.Mistype.UC"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.Mistype.UC", useRoot); ValidateMistypeConfigurationResults(locConfig); } [Test] - public void MistypeInCamelCase() + [TestCase(true)] + [TestCase(false)] + public void MistypeInCamelCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.Mistype.CC"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.Mistype.CC", useRoot); ValidateMistypeConfigurationResults(locConfig); } [Test] - public void MistypeInPascalCase() + [TestCase(true)] + [TestCase(false)] + public void MistypeInPascalCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.Mistype.PC"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.Mistype.PC", useRoot); ValidateMistypeConfigurationResults(locConfig); } @@ -235,69 +262,77 @@ private void ValidateMistypeConfigurationResults(LocalizationConfiguration locCo #region Name as node [Test] - public void NoNameNodes() + [TestCase(true)] + [TestCase(false)] + public void NoNameNodes(bool useRoot) { IgnoreIfXml(); - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Empty"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Empty", useRoot); CheckConfigurationIsDefault(locConfig); } [Test] - public void NameNodeIsEmpty() + [TestCase(true)] + [TestCase(false)] + public void NameNodeIsEmpty(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.NameEmpty"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.NameEmpty", useRoot); CheckConfigurationIsDefault(locConfig); } [Test] - public void DefinedNameNode() + [TestCase(true)] + [TestCase(false)] + public void DefinedNameNode(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Espaniol"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Espaniol", useRoot); Assert.That(locConfig, Is.Not.Null); Assert.That(locConfig.DefaultCulture, Is.EqualTo(expectedCulture)); } [Test] - public void FaultyNameNodeValue() + [TestCase(true)] + [TestCase(false)] + public void FaultyNameNodeValue(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.FaultyValue"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.FaultyValue", useRoot); CheckConfigurationIsDefault(locConfig); } [Test] - public void NameNodeInLowCase() + [TestCase(true)] + [TestCase(false)] + public void NameNodeInLowCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.LC"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.LC", useRoot); ValidateNamingConfigurationResults(locConfig); } [Test] - public void NameNodeInUpperCase() + [TestCase(true)] + [TestCase(false)] + public void NameNodeInUpperCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.UC"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.UC", useRoot); ValidateNamingConfigurationResults(locConfig); } [Test] - public void NameNodeInCamelCase() + [TestCase(true)] + [TestCase(false)] + public void NameNodeInCamelCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.CC"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.CC", useRoot); ValidateNamingConfigurationResults(locConfig); } [Test] - public void NameNodeInPascalCase() + [TestCase(true)] + [TestCase(false)] + public void NameNodeInPascalCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.PC"); - var locConfig = LocalizationConfiguration.Load(section); + var locConfig = LoadConfiguration($"Xtensive.Orm.Localization.{ConfigFormat}.NameNode.Naming.PC", useRoot); ValidateNamingConfigurationResults(locConfig); } diff --git a/Extensions/Xtensive.Orm.Reprocessing.Tests/Tests/ModernConfugurationTests.cs b/Extensions/Xtensive.Orm.Reprocessing.Tests/Tests/ModernConfugurationTests.cs index dd545ae3ed..29f931c110 100644 --- a/Extensions/Xtensive.Orm.Reprocessing.Tests/Tests/ModernConfugurationTests.cs +++ b/Extensions/Xtensive.Orm.Reprocessing.Tests/Tests/ModernConfugurationTests.cs @@ -29,92 +29,102 @@ protected override void AddConfigurationFile(IConfigurationBuilder configuration } [Test] - public void EmptyNodesTest() + [TestCase(true)] + [TestCase(false)] + public void EmptyNodesTest(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Xml.EmptyNodes"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration("Xtensive.Orm.Reprocessing.Xml.EmptyNodes", useRoot); CheckConfigIsDefault(repConfig); } [Test] - public void EmptyValuesTest() + [TestCase(true)] + [TestCase(false)] + public void EmptyValuesTest(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Attributes.EmptyValues"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration("Xtensive.Orm.Reprocessing.Attributes.EmptyValues", useRoot); CheckConfigIsDefault(repConfig); } [Test] - public void EmptyTransactionModeOnlyTest() + [TestCase(true)] + [TestCase(false)] + public void EmptyTransactionModeOnlyTest(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Attributes.EmptyTMOnly"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration("Xtensive.Orm.Reprocessing.Attributes.EmptyTMOnly", useRoot); CheckConfigIsDefault(repConfig); } [Test] - public void EmptyStrategyOnlyTest() + [TestCase(true)] + [TestCase(false)] + public void EmptyStrategyOnlyTest(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Attributes.EmptyStrategyOnly"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration("Xtensive.Orm.Reprocessing.Attributes.EmptyStrategyOnly", useRoot); CheckConfigIsDefault(repConfig); } [Test] - public void AllAttributesHasValuesTest() + [TestCase(true)] + [TestCase(false)] + public void AllAttributesHasValuesTest(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Attributes.All"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration("Xtensive.Orm.Reprocessing.Attributes.All", useRoot); Assert.That(repConfig, Is.Not.Null); Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.Auto)); Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleUniqueConstraintViolationStrategy))); } [Test] - public void OnlyTMAttributeHasValueTest() + [TestCase(true)] + [TestCase(false)] + public void OnlyTMAttributeHasValueTest(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Attributes.OnlyTM"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration("Xtensive.Orm.Reprocessing.Attributes.OnlyTM", useRoot); Assert.That(repConfig, Is.Not.Null); Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.Auto)); Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleReprocessableExceptionStrategy))); } [Test] - public void OnlyStrategyAttributeHasValueTest() + [TestCase(true)] + [TestCase(false)] + public void OnlyStrategyAttributeHasValueTest(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Attributes.OnlyStrategy"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration("Xtensive.Orm.Reprocessing.Attributes.OnlyStrategy", useRoot); Assert.That(repConfig, Is.Not.Null); Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.New)); Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleUniqueConstraintViolationStrategy))); } [Test] - public void AttributesInLowCase() + [TestCase(true)] + [TestCase(false)] + public void AttributesInLowCase(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Attributes.LC"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration("Xtensive.Orm.Reprocessing.Attributes.LC", useRoot); Assert.That(repConfig, Is.Not.Null); Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.Auto)); Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleUniqueConstraintViolationStrategy))); } [Test] - public void AttributesInUpperCase() + [TestCase(true)] + [TestCase(false)] + public void AttributesInUpperCase(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Attributes.UC"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration("Xtensive.Orm.Reprocessing.Attributes.UC", useRoot); Assert.That(repConfig, Is.Not.Null); Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.Auto)); Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleUniqueConstraintViolationStrategy))); } [Test] - public void AttributesInPascalCase() + [TestCase(true)] + [TestCase(false)] + public void AttributesInPascalCase(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Reprocessing.Attributes.PC"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration("Xtensive.Orm.Reprocessing.Attributes.PC", useRoot); Assert.That(repConfig, Is.Not.Null); Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.Auto)); Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleUniqueConstraintViolationStrategy))); @@ -123,65 +133,80 @@ public void AttributesInPascalCase() public abstract class ModernConfigurationTest : TestCommon.ModernConfigurationTestBase { + protected ReprocessingConfiguration LoadConfiguration(string sectionName, bool useRoot) + { + return useRoot + ? ReprocessingConfiguration.Load(configurationRoot, sectionName) + : ReprocessingConfiguration.Load(configurationRoot.GetSection(sectionName)); + } + + [Test] - public void EmptySectionCase() + [TestCase(true)] + [TestCase(false)] + public void EmptySectionCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Empty"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Empty", useRoot); CheckConfigIsDefault(repConfig); } [Test] - public void EmptyNames() + [TestCase(true)] + [TestCase(false)] + public void EmptyNames(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.AllEmpty"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration($"Xtensive.Orm.Reprocessing.{ConfigFormat}.AllEmpty", useRoot); CheckConfigIsDefault(repConfig); } [Test] - public void OnlyTransactionOpenModeAndEmpty() + [TestCase(true)] + [TestCase(false)] + public void OnlyTransactionOpenModeAndEmpty(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyTM.Empty"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyTM.Empty", useRoot); CheckConfigIsDefault(repConfig); } [Test] - public void OnlyTransactionOpenModeAuto() + [TestCase(true)] + [TestCase(false)] + public void OnlyTransactionOpenModeAuto(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyTM.Auto"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyTM.Auto", useRoot); Assert.That(repConfig, Is.Not.Null); Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.Auto)); Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleReprocessableExceptionStrategy))); } [Test] - public void OnlyTransactionOpenModeNew() + [TestCase(true)] + [TestCase(false)] + public void OnlyTransactionOpenModeNew(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyTM.New"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyTM.New", useRoot); Assert.That(repConfig, Is.Not.Null); Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.New)); Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleReprocessableExceptionStrategy))); } [Test] - public void OnlyTransactionOpenModeDefault() + [TestCase(true)] + [TestCase(false)] + public void OnlyTransactionOpenModeDefault(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyTM.Default"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyTM.Default", useRoot); Assert.That(repConfig, Is.Not.Null); Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.Default)); Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleReprocessableExceptionStrategy))); } [Test] - public void OnlyStrategyAndEmpty() + [TestCase(true)] + [TestCase(false)] + public void OnlyStrategyAndEmpty(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyStrategy.Empty"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyStrategy.Empty", useRoot); CheckConfigIsDefault(repConfig); Assert.That(repConfig, Is.Not.Null); Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.New)); @@ -189,63 +214,72 @@ public void OnlyStrategyAndEmpty() } [Test] - public void OnlyStrategyHandleReprocessible() + [TestCase(true)] + [TestCase(false)] + public void OnlyStrategyHandleReprocessible(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyStrategy.HandleReprocessible"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyStrategy.HandleReprocessible", useRoot); Assert.That(repConfig, Is.Not.Null); Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.New)); Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleReprocessableExceptionStrategy))); } [Test] - public void OnlyStrategyHandleUnique() + [TestCase(true)] + [TestCase(false)] + public void OnlyStrategyHandleUnique(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyStrategy.HandleUnique"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyStrategy.HandleUnique", useRoot); Assert.That(repConfig, Is.Not.Null); Assert.That(repConfig.DefaultTransactionOpenMode, Is.EqualTo(TransactionOpenMode.New)); Assert.That(repConfig.DefaultExecuteStrategy, Is.EqualTo(typeof(HandleUniqueConstraintViolationStrategy))); } [Test] - public void OnlyStrategyNonExistent() + [TestCase(true)] + [TestCase(false)] + public void OnlyStrategyNonExistent(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyStrategy.NonExistent"); - _ = Assert.Throws(() => ReprocessingConfiguration.Load(section)); + _ = Assert.Throws( + () => LoadConfiguration($"Xtensive.Orm.Reprocessing.{ConfigFormat}.OnlyStrategy.NonExistent", useRoot)); } #region Naming + [Test] - public void NamingInLowCase() + [TestCase(true)] + [TestCase(false)] + public void NamingInLowCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Naming.LC"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Naming.LC", useRoot); ValidateNamingConfigurationResults(repConfig); } [Test] - public void NamingInUpperCase() + [TestCase(true)] + [TestCase(false)] + public void NamingInUpperCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Naming.UC"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Naming.UC", useRoot); ValidateNamingConfigurationResults(repConfig); } [Test] - public void NamingInCamelCase() + [TestCase(true)] + [TestCase(false)] + public void NamingInCamelCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Naming.CC"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Naming.CC", useRoot); ValidateNamingConfigurationResults(repConfig); } [Test] - public void NamingInPascalCase() + [TestCase(true)] + [TestCase(false)] + public void NamingInPascalCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Naming.PC"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Naming.PC", useRoot); ValidateNamingConfigurationResults(repConfig); } @@ -258,35 +292,40 @@ private static void ValidateNamingConfigurationResults(ReprocessingConfiguration #endregion #region mistype cases + [Test] - public void MistypeInLowCase() + [TestCase(true)] + [TestCase(false)] + public void MistypeInLowCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Mistype.LC"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Mistype.LC", useRoot); ValidateMistypeConfigurationResults(repConfig); } [Test] - public void MistypeInUpperCase() + [TestCase(true)] + [TestCase(false)] + public void MistypeInUpperCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Mistype.UC"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Mistype.UC", useRoot); ValidateMistypeConfigurationResults(repConfig); } [Test] - public void MistypeInCamelCase() + [TestCase(true)] + [TestCase(false)] + public void MistypeInCamelCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Mistype.CC"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Mistype.CC", useRoot); ValidateMistypeConfigurationResults(repConfig); } [Test] - public void MistypeInPascalCase() + [TestCase(true)] + [TestCase(false)] + public void MistypeInPascalCase(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Mistype.PC"); - var repConfig = ReprocessingConfiguration.Load(section); + var repConfig = LoadConfiguration($"Xtensive.Orm.Reprocessing.{ConfigFormat}.Mistype.PC", useRoot); ValidateMistypeConfigurationResults(repConfig); } diff --git a/Extensions/Xtensive.Orm.Security.Tests/Tests/ModernConfigurationTests.cs b/Extensions/Xtensive.Orm.Security.Tests/Tests/ModernConfigurationTests.cs index d77849ab0d..24c5b243ff 100644 --- a/Extensions/Xtensive.Orm.Security.Tests/Tests/ModernConfigurationTests.cs +++ b/Extensions/Xtensive.Orm.Security.Tests/Tests/ModernConfigurationTests.cs @@ -28,84 +28,93 @@ protected override void AddConfigurationFile(IConfigurationBuilder configuration } [Test] - public void NameAttributeEmptyNamesTest() + [TestCase(true)] + [TestCase(false)] + public void NameAttributeEmptyNamesTest(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Security.NameAttribute.NamesEmpty"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration("Xtensive.Orm.Security.NameAttribute.NamesEmpty", useRoot); CheckConfigurationIsDefault(secConfig); } [Test] - public void NameAttributeEmptyAndNonExistentNameTest1() + [TestCase(true)] + [TestCase(false)] + public void NameAttributeEmptyAndNonExistentNameTest1(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Security.NameAttribute.NameExistPartially1"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration("Xtensive.Orm.Security.NameAttribute.NameExistPartially1", useRoot); CheckConfigurationIsDefault(secConfig); } [Test] - public void NameAttributeEmptyAndNonExistentNameTest2() + [TestCase(true)] + [TestCase(false)] + public void NameAttributeEmptyAndNonExistentNameTest2(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Security.NameAttribute.NameExistPartially2"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration("Xtensive.Orm.Security.NameAttribute.NameExistPartially2", useRoot); CheckConfigurationIsDefault(secConfig); } [Test] - public void NameAttributeAllNamesTest() + [TestCase(true)] + [TestCase(false)] + public void NameAttributeAllNamesTest(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Security.NameAttribute.AllNames"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration("Xtensive.Orm.Security.NameAttribute.AllNames", useRoot); Assert.That(secConfig, Is.Not.Null); Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha1")); Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("notdefault")); } [Test] - public void NameAttributeOnlyHashingServiceTest() + [TestCase(true)] + [TestCase(false)] + public void NameAttributeOnlyHashingServiceTest(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Security.NameAttribute.OnlyHashing"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration("Xtensive.Orm.Security.NameAttribute.OnlyHashing", useRoot); Assert.That(secConfig, Is.Not.Null); Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha1")); Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); } [Test] - public void NameAttributeOnlyAuthServiceTest() + [TestCase(true)] + [TestCase(false)] + public void NameAttributeOnlyAuthServiceTest(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Security.NameAttribute.OnlyAuth"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration("Xtensive.Orm.Security.NameAttribute.OnlyAuth", useRoot); Assert.That(secConfig, Is.Not.Null); Assert.That(secConfig.HashingServiceName, Is.EqualTo("plain")); Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("notdefault")); } [Test] - public void NameAttributeLowCase() + [TestCase(true)] + [TestCase(false)] + public void NameAttributeLowCaseTest(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Security.NameAttribute.LC"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration("Xtensive.Orm.Security.NameAttribute.LC", useRoot); Assert.That(secConfig, Is.Not.Null); Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha1")); Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("notdefault")); } [Test] - public void NameAttributeUpperCase() + [TestCase(true)] + [TestCase(false)] + public void NameAttributeUpperCaseTest(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Security.NameAttribute.UC"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration("Xtensive.Orm.Security.NameAttribute.UC", useRoot); Assert.That(secConfig, Is.Not.Null); Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha1")); Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("notdefault")); } [Test] - public void NameAttributePascalCase() + [TestCase(true)] + [TestCase(false)] + public void NameAttributePascalCaseTest(bool useRoot) { - var section = GetAndCheckConfigurationSection("Xtensive.Orm.Security.NameAttribute.PC"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration("Xtensive.Orm.Security.NameAttribute.PC", useRoot); Assert.That(secConfig, Is.Not.Null); Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha1")); Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("notdefault")); @@ -116,129 +125,150 @@ public void NameAttributePascalCase() [TestFixture] public abstract class ModernConfigurationTests : TestCommon.ModernConfigurationTestBase { + protected SecurityConfiguration LoadConfiguration(string sectionName, bool useRoot) + { + return useRoot + ? SecurityConfiguration.Load(configurationRoot, sectionName) + : SecurityConfiguration.Load(configurationRoot.GetSection(sectionName)); + } + [Test] - public void EmptySectionCase() + [TestCase(true)] + [TestCase(false)] + public void EmptySectionCaseTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.Empty"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.Empty", useRoot); CheckConfigurationIsDefault(secConfig); } [Test] - public void EmptyNames() + [TestCase(true)] + [TestCase(false)] + public void EmptyNamesTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.AllEmpty"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.AllEmpty", useRoot); CheckConfigurationIsDefault(secConfig); } [Test] - public void OnlyHashingServiceEmpty() + [TestCase(true)] + [TestCase(false)] + public void OnlyHashingServiceEmptyTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.OnlyHashing.Empty"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.OnlyHashing.Empty", useRoot); CheckConfigurationIsDefault(secConfig); } [Test] - public void OnlyHashingServiceMd5() + [TestCase(true)] + [TestCase(false)] + public void OnlyHashingServiceMd5Test(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.OnlyHashing.Md5"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.OnlyHashing.Md5", useRoot); Assert.That(secConfig, Is.Not.Null); Assert.That(secConfig.HashingServiceName, Is.EqualTo("md5")); Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); } [Test] - public void OnlyHashingServiceSha1() + [TestCase(true)] + [TestCase(false)] + public void OnlyHashingServiceSha1Test(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.OnlyHashing.Sha1"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.OnlyHashing.Sha1", useRoot); Assert.That(secConfig, Is.Not.Null); Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha1")); Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); } [Test] - public void OnlyHashingServiceSha256() + [TestCase(true)] + [TestCase(false)] + public void OnlyHashingServiceSha256Test(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.OnlyHashing.Sha256"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.OnlyHashing.Sha256", useRoot); Assert.That(secConfig, Is.Not.Null); Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha256")); Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); } [Test] - public void OnlyHashingServiceSha384() + [TestCase(true)] + [TestCase(false)] + public void OnlyHashingServiceSha384Test(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.OnlyHashing.Sha384"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.OnlyHashing.Sha384", useRoot); Assert.That(secConfig, Is.Not.Null); Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha384")); Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); } [Test] - public void OnlyHashingServiceSha512() + [TestCase(true)] + [TestCase(false)] + public void OnlyHashingServiceSha512Test(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.OnlyHashing.Sha512"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.OnlyHashing.Sha512", useRoot); Assert.That(secConfig, Is.Not.Null); Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha512")); Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); } [Test] - public void OnlyAuthenticationServiceEmptyName() + [TestCase(true)] + [TestCase(false)] + public void OnlyAuthenticationServiceEmptyNameTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.OnlyAuth.Empty"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.OnlyAuth.Empty", useRoot); CheckConfigurationIsDefault(secConfig); } [Test] - public void OnlyAuthenticationServiceNotDefault() + [TestCase(true)] + [TestCase(false)] + public void OnlyAuthenticationServiceNotDefaultTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.OnlyAuth"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.OnlyAuth", useRoot); Assert.That(secConfig, Is.Not.Null); Assert.That(secConfig.HashingServiceName, Is.EqualTo("plain")); Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("notdefault")); } - #region Naming + [Test] - public void NamingInLowCase() + [TestCase(true)] + [TestCase(false)] + public void NamingInLowCaseTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.Naming.LC"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.Naming.LC", useRoot); ValidateNamingConfigurationResults(secConfig); } [Test] - public void NamingInUpperCase() + [TestCase(true)] + [TestCase(false)] + public void NamingInUpperCaseTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.Naming.UC"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.Naming.UC", useRoot); ValidateNamingConfigurationResults(secConfig); } [Test] - public void NamingInCamelCase() + [TestCase(true)] + [TestCase(false)] + public void NamingInCamelCaseTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.Naming.CC"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.Naming.CC", useRoot); ValidateNamingConfigurationResults(secConfig); } [Test] - public void NamingInPascalCase() + [TestCase(true)] + [TestCase(false)] + public void NamingInPascalCaseTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.Naming.PC"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.Naming.PC", useRoot); ValidateNamingConfigurationResults(secConfig); } @@ -248,38 +278,44 @@ private static void ValidateNamingConfigurationResults(SecurityConfiguration sec Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha1")); Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("notdefault")); } + #endregion #region mistype cases + [Test] - public void MistypeInLowCase() + [TestCase(true)] + [TestCase(false)] + public void MistypeInLowCaseTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.Mistype.LC"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.Mistype.LC", useRoot); ValidateMistypeConfigurationResults(secConfig); } [Test] - public void MistypeInUpperCase() + [TestCase(true)] + [TestCase(false)] + public void MistypeInUpperCaseTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.Mistype.UC"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.Mistype.UC", useRoot); ValidateMistypeConfigurationResults(secConfig); } [Test] - public void MistypeInCamelCase() + [TestCase(true)] + [TestCase(false)] + public void MistypeInCamelCaseTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.Mistype.CC"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.Mistype.CC", useRoot); ValidateMistypeConfigurationResults(secConfig); } [Test] - public void MistypeInPascalCase() + [TestCase(true)] + [TestCase(false)] + public void MistypeInPascalCaseTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.Mistype.PC"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.Mistype.PC", useRoot); ValidateMistypeConfigurationResults(secConfig); } @@ -290,131 +326,145 @@ private static void ValidateMistypeConfigurationResults(SecurityConfiguration se #endregion - #region Name as node + #region Name as node [Test] - public void NoNameNodes() + [TestCase(true)] + [TestCase(false)] + public void NoNameNodesTest(bool useRoot) { IgnoreIfXml(); - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.Json.NameNode.AllEmpty"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.Json.NameNode.AllEmpty", useRoot); CheckConfigurationIsDefault(secConfig); } [Test] - public void NameNodesAreEmpty() + [TestCase(true)] + [TestCase(false)] + public void NameNodesAreEmptyTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.Json.NameNode.NamesEmpty"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.Json.NameNode.NamesEmpty", useRoot); CheckConfigurationIsDefault(secConfig); } [Test] - public void OnlyHashingServiceNameIsEmpty() + [TestCase(true)] + [TestCase(false)] + public void OnlyHashingServiceNameIsEmptyTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyHashing.Empty"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyHashing.Empty", useRoot); CheckConfigurationIsDefault(secConfig); } [Test] - public void OnlyHashingServiceWithNameNodeMd5() + [TestCase(true)] + [TestCase(false)] + public void OnlyHashingServiceWithNameNodeMd5Test(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyHashing.Md5"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyHashing.Md5", useRoot); Assert.That(secConfig, Is.Not.Null); Assert.That(secConfig.HashingServiceName, Is.EqualTo("md5")); Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); } [Test] - public void OnlyHashingServiceWithNameNodeSha1() + [TestCase(true)] + [TestCase(false)] + public void OnlyHashingServiceWithNameNodeSha1Test(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyHashing.Sha1"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyHashing.Sha1", useRoot); Assert.That(secConfig, Is.Not.Null); Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha1")); Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); } [Test] - public void OnlyHashingServiceWithNameNodeSha256() + [TestCase(true)] + [TestCase(false)] + public void OnlyHashingServiceWithNameNodeSha256Test(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyHashing.Sha256"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyHashing.Sha256", useRoot); Assert.That(secConfig, Is.Not.Null); Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha256")); Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); } [Test] - public void OnlyHashingServiceWithNameNodeSha384() + [TestCase(true)] + [TestCase(false)] + public void OnlyHashingServiceWithNameNodeSha384Test(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyHashing.Sha384"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyHashing.Sha384", useRoot); Assert.That(secConfig, Is.Not.Null); Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha384")); Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); } [Test] - public void OnlyHashingServiceWithNameNodeSha512() + [TestCase(true)] + [TestCase(false)] + public void OnlyHashingServiceWithNameNodeSha512Test(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyHashing.Sha512"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyHashing.Sha512", useRoot); Assert.That(secConfig, Is.Not.Null); Assert.That(secConfig.HashingServiceName, Is.EqualTo("sha512")); Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("default")); } [Test] - public void OnlyAuthenticationServiceWithNameNodeEmptyName() + [TestCase(true)] + [TestCase(false)] + public void OnlyAuthenticationServiceWithNameNodeEmptyNameTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyAuth.Empty"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyAuth.Empty", useRoot); CheckConfigurationIsDefault(secConfig); } [Test] - public void OnlyAuthenticationServiceWithNameNodeNotDefault() + [TestCase(true)] + [TestCase(false)] + public void OnlyAuthenticationServiceWithNameNodeNotDefaultTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyAuth"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.OnlyAuth", useRoot); Assert.That(secConfig, Is.Not.Null); Assert.That(secConfig.HashingServiceName, Is.EqualTo("plain")); Assert.That(secConfig.AuthenticationServiceName, Is.EqualTo("notdefault")); } [Test] - public void NameNodeInLowCase() + [TestCase(true)] + [TestCase(false)] + public void NameNodeInLowCaseTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.Naming.LC"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.Naming.LC", useRoot); ValidateNamingConfigurationResults(secConfig); } [Test] - public void NameNodeInUpperCase() + [TestCase(true)] + [TestCase(false)] + public void NameNodeInUpperCaseTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.Naming.UC"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.Naming.UC", useRoot); ValidateNamingConfigurationResults(secConfig); } [Test] - public void NameNodeInCamelCase() + [TestCase(true)] + [TestCase(false)] + public void NameNodeInCamelCaseTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.Naming.CC"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.Naming.CC", useRoot); ValidateNamingConfigurationResults(secConfig); } [Test] - public void NameNodeInPascalCase() + [TestCase(true)] + [TestCase(false)] + public void NameNodeInPascalCaseTest(bool useRoot) { - var section = GetAndCheckConfigurationSection($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.Naming.PC"); - var secConfig = SecurityConfiguration.Load(section); + var secConfig = LoadConfiguration($"Xtensive.Orm.Security.{ConfigFormat}.NameNode.Naming.PC", useRoot); ValidateNamingConfigurationResults(secConfig); } From aae811429311f73015462e6bccde4c4b0dcc949a Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Tue, 1 Oct 2024 16:39:55 +0500 Subject: [PATCH 23/32] Better names for tests of Microsoft.Extensions.Configuration-based config loading --- Extensions/TestCommon/ModernConfigurationTestBase.cs | 2 +- ...gurationTests.cs => MicrosoftConfigurationTests.cs} | 6 +++--- ...gurationTests.cs => MicrosoftConfugurationTests.cs} | 6 +++--- ...gurationTests.cs => MicrosoftConfigurationTests.cs} | 6 +++--- ...gurationTests.cs => MicrosoftConfigurationTests.cs} | 10 ++++------ 5 files changed, 14 insertions(+), 16 deletions(-) rename Extensions/Xtensive.Orm.Localization.Tests/{ModernConfigurationTests.cs => MicrosoftConfigurationTests.cs} (97%) rename Extensions/Xtensive.Orm.Reprocessing.Tests/Tests/{ModernConfugurationTests.cs => MicrosoftConfugurationTests.cs} (98%) rename Extensions/Xtensive.Orm.Security.Tests/Tests/{ModernConfigurationTests.cs => MicrosoftConfigurationTests.cs} (98%) rename Orm/Xtensive.Orm.Tests/Configuration/{ModernConfigurationTests.cs => MicrosoftConfigurationTests.cs} (99%) diff --git a/Extensions/TestCommon/ModernConfigurationTestBase.cs b/Extensions/TestCommon/ModernConfigurationTestBase.cs index 64a2a6b405..a0faf76c24 100644 --- a/Extensions/TestCommon/ModernConfigurationTestBase.cs +++ b/Extensions/TestCommon/ModernConfigurationTestBase.cs @@ -9,7 +9,7 @@ namespace TestCommon { - public abstract class ModernConfigurationTestBase + public abstract class MicrosoftConfigurationTestBase { protected enum ConfigTypes { diff --git a/Extensions/Xtensive.Orm.Localization.Tests/ModernConfigurationTests.cs b/Extensions/Xtensive.Orm.Localization.Tests/MicrosoftConfigurationTests.cs similarity index 97% rename from Extensions/Xtensive.Orm.Localization.Tests/ModernConfigurationTests.cs rename to Extensions/Xtensive.Orm.Localization.Tests/MicrosoftConfigurationTests.cs index b42a62fe0b..9bb8d2b77c 100644 --- a/Extensions/Xtensive.Orm.Localization.Tests/ModernConfigurationTests.cs +++ b/Extensions/Xtensive.Orm.Localization.Tests/MicrosoftConfigurationTests.cs @@ -10,7 +10,7 @@ namespace Xtensive.Orm.Localization.Tests.Configuration { - public sealed class JsonConfigurationTest : ModernConfigurationTest + public sealed class JsonConfigurationTest : MicrosoftConfigurationTest { protected override ConfigTypes ConfigFormat => ConfigTypes.Json; @@ -20,7 +20,7 @@ protected override void AddConfigurationFile(IConfigurationBuilder configuration } } - public sealed class XmlConfigurationTest : ModernConfigurationTest + public sealed class XmlConfigurationTest : MicrosoftConfigurationTest { protected override ConfigTypes ConfigFormat => ConfigTypes.Xml; @@ -98,7 +98,7 @@ public void NameAttributePascalCase(bool useRoot) } [TestFixture] - public abstract class ModernConfigurationTest : TestCommon.ModernConfigurationTestBase + public abstract class MicrosoftConfigurationTest : TestCommon.MicrosoftConfigurationTestBase { protected readonly CultureInfo defaultCulture = new CultureInfo("en-US"); protected readonly CultureInfo expectedCulture = new CultureInfo("es-ES"); diff --git a/Extensions/Xtensive.Orm.Reprocessing.Tests/Tests/ModernConfugurationTests.cs b/Extensions/Xtensive.Orm.Reprocessing.Tests/Tests/MicrosoftConfugurationTests.cs similarity index 98% rename from Extensions/Xtensive.Orm.Reprocessing.Tests/Tests/ModernConfugurationTests.cs rename to Extensions/Xtensive.Orm.Reprocessing.Tests/Tests/MicrosoftConfugurationTests.cs index 29f931c110..d6221b7018 100644 --- a/Extensions/Xtensive.Orm.Reprocessing.Tests/Tests/ModernConfugurationTests.cs +++ b/Extensions/Xtensive.Orm.Reprocessing.Tests/Tests/MicrosoftConfugurationTests.cs @@ -9,7 +9,7 @@ namespace Xtensive.Orm.Reprocessing.Tests.Configuration { - public sealed class JsonConfigurationTest : ModernConfigurationTest + public sealed class JsonConfigurationTest : MicrosoftConfigurationTest { protected override ConfigTypes ConfigFormat => ConfigTypes.Json; @@ -19,7 +19,7 @@ protected override void AddConfigurationFile(IConfigurationBuilder configuration } } - public sealed class XmlConfigurationTest : ModernConfigurationTest + public sealed class XmlConfigurationTest : MicrosoftConfigurationTest { protected override ConfigTypes ConfigFormat => ConfigTypes.Xml; @@ -131,7 +131,7 @@ public void AttributesInPascalCase(bool useRoot) } } - public abstract class ModernConfigurationTest : TestCommon.ModernConfigurationTestBase + public abstract class MicrosoftConfigurationTest : TestCommon.MicrosoftConfigurationTestBase { protected ReprocessingConfiguration LoadConfiguration(string sectionName, bool useRoot) { diff --git a/Extensions/Xtensive.Orm.Security.Tests/Tests/ModernConfigurationTests.cs b/Extensions/Xtensive.Orm.Security.Tests/Tests/MicrosoftConfigurationTests.cs similarity index 98% rename from Extensions/Xtensive.Orm.Security.Tests/Tests/ModernConfigurationTests.cs rename to Extensions/Xtensive.Orm.Security.Tests/Tests/MicrosoftConfigurationTests.cs index 24c5b243ff..2a1fe93dd1 100644 --- a/Extensions/Xtensive.Orm.Security.Tests/Tests/ModernConfigurationTests.cs +++ b/Extensions/Xtensive.Orm.Security.Tests/Tests/MicrosoftConfigurationTests.cs @@ -8,7 +8,7 @@ namespace Xtensive.Orm.Security.Tests.Configuration { - public sealed class JsonConfigurationTests : ModernConfigurationTests + public sealed class JsonConfigurationTests : MicrosoftConfigurationTests { protected override ConfigTypes ConfigFormat => ConfigTypes.Json; @@ -18,7 +18,7 @@ protected override void AddConfigurationFile(IConfigurationBuilder configuration } } - public sealed class XmlConfigurationTests : ModernConfigurationTests + public sealed class XmlConfigurationTests : MicrosoftConfigurationTests { protected override ConfigTypes ConfigFormat => ConfigTypes.Xml; @@ -123,7 +123,7 @@ public void NameAttributePascalCaseTest(bool useRoot) [TestFixture] - public abstract class ModernConfigurationTests : TestCommon.ModernConfigurationTestBase + public abstract class MicrosoftConfigurationTests : TestCommon.MicrosoftConfigurationTestBase { protected SecurityConfiguration LoadConfiguration(string sectionName, bool useRoot) { diff --git a/Orm/Xtensive.Orm.Tests/Configuration/ModernConfigurationTests.cs b/Orm/Xtensive.Orm.Tests/Configuration/MicrosoftConfigurationTests.cs similarity index 99% rename from Orm/Xtensive.Orm.Tests/Configuration/ModernConfigurationTests.cs rename to Orm/Xtensive.Orm.Tests/Configuration/MicrosoftConfigurationTests.cs index df50fe29e4..c47023207a 100644 --- a/Orm/Xtensive.Orm.Tests/Configuration/ModernConfigurationTests.cs +++ b/Orm/Xtensive.Orm.Tests/Configuration/MicrosoftConfigurationTests.cs @@ -72,7 +72,7 @@ public class DummyEntity3 : Entity namespace Xtensive.Orm.Tests.Configuration { [TestFixture] - public sealed class AppConfigStyleConfigurationTest : ConfigurationFileTestBase + public sealed class AppConfigStyleConfigurationTest : MicrosoftConfigurationTestBase { protected override string Postfix => "AppConfig"; @@ -85,7 +85,7 @@ protected override void RegisterConfigurationFile(ConfigurationBuilder builder) } [TestFixture] - public sealed class XmlConfigurationTest : ConfigurationFileTestBase + public sealed class XmlConfigurationTest : MicrosoftConfigurationTestBase { protected override string Postfix => "Xml"; @@ -96,7 +96,7 @@ protected override void RegisterConfigurationFile(ConfigurationBuilder builder) } [TestFixture] - public sealed class JsonConfigurationTest : ConfigurationFileTestBase + public sealed class JsonConfigurationTest : MicrosoftConfigurationTestBase { protected override string Postfix => "Json"; @@ -106,13 +106,11 @@ protected override void RegisterConfigurationFile(ConfigurationBuilder builder) } } - public abstract class ConfigurationFileTestBase + public abstract class MicrosoftConfigurationTestBase { - private IConfigurationRoot configuration; private IConfigurationSection configurationSection; - protected abstract string Postfix { get; } protected virtual bool NameAttributeUnique => true; From 46620ddffa8cc6db1867c6a2a2bab7033e9a0d7e Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 3 Oct 2024 16:11:44 +0500 Subject: [PATCH 24/32] ReadMe files of extensions updated with new configuration examples + updated version value in Prerequisites --- .../NugetContent/ReadMe.md | 2 +- .../NugetContent/ReadMe.md | 263 +++++++++++++++++- .../NugetContent/ReadMe.md | 4 +- .../NugetContent/ReadMe.md | 4 +- .../NugetContent/ReadMe.md | 258 ++++++++++++++++- .../NugetContent/ReadMe.md | 258 ++++++++++++++++- .../NugetContent/ReadMe.md | 4 +- .../Xtensive.Orm.Web/NugetContent/ReadMe.md | 4 +- 8 files changed, 780 insertions(+), 17 deletions(-) diff --git a/Extensions/Xtensive.Orm.BulkOperations/NugetContent/ReadMe.md b/Extensions/Xtensive.Orm.BulkOperations/NugetContent/ReadMe.md index 9fccda4329..2500340342 100644 --- a/Extensions/Xtensive.Orm.BulkOperations/NugetContent/ReadMe.md +++ b/Extensions/Xtensive.Orm.BulkOperations/NugetContent/ReadMe.md @@ -8,7 +8,7 @@ to server-side UPDATE or DELETE commands. Prerequisites ------------- -DataObjects.Net 7.0.x (http://dataobjects.net) +DataObjects.Net 7.1.x (http://dataobjects.net) Examples of usage diff --git a/Extensions/Xtensive.Orm.Localization/NugetContent/ReadMe.md b/Extensions/Xtensive.Orm.Localization/NugetContent/ReadMe.md index 87434ac868..79579ed074 100644 --- a/Extensions/Xtensive.Orm.Localization/NugetContent/ReadMe.md +++ b/Extensions/Xtensive.Orm.Localization/NugetContent/ReadMe.md @@ -8,7 +8,7 @@ This implies that localizable resources are a part of domain model so they are s Prerequisites ------------- -DataObjects.Net 7.0.x or later (http://dataobjects.net) +DataObjects.Net 7.1.x or later (http://dataobjects.net) Implementation -------------- @@ -50,6 +50,7 @@ Define corresponding localizations, e.g.: } ``` + Examples of usage ----------------- @@ -106,4 +107,264 @@ Examples of usage where p.Title=="Bienvenido" select p; Assert.AreEqual(1, query.Count()); +``` + + +Examples of how to configure extension +-------------------------------------- + +Following examples show different ways to configure extension in configuration files of various types. + +**Example #1** Confugure in App.config/Web.config + +```xml + + +
+
+ + + + + + + + +``` + +Such configuration is only compatible with System.Configuration.ConfigurationManager. +If project still supports such configurations then Localization configuration will be read automatically when it needed to be read. +Sometimes a work-around is needed to read such configuration, for more read Example #2 and Example #3 + + +**Example #2** Reading old-style configuration of an assembly in NET 5 and newer. + +Due to new architecture without AppDomain (which among the other things was in charge of gathering configuration files of loaded assemblies +as it would be one configuration file) System.Configuration.ConfigurationManager now reads only configuration file of actual executable, loaded +assemblies' configuration files stay unreachable by default, though there is need to read some data from them. +A great example is test projects which are usually get loaded by test runner executable, and the only configuration accessible in this case +is test runner one. + +Extra step is required to read configuration files in such cases. Thankfully ConfigurationManager has methods to get access to assemblies' configurations. + +To get access to an assembly configuration file it should be opened explicitly by + +```csharp + var configuration = ConfigurationManager.OpenExeConfiguration(typeof(SomeTypeInConfigOwnerAssembly).Assembly.Location); +``` + +The instance returned from ```OpenExeConfiguration``` provides access to sections of the assembly configuration. DataObjects.Net configurations +(```DomainConfiguration```, ```LocalizationConfiguration```, etc.) have ```Load()``` methods that can recieve this instance. +```LocalizationConfiguration``` can be read like so + +```csharp + var configuration = ConfigurationManager.OpenExeConfiguration(typeof(SomeTypeInConfigOwnerAssembly).Assembly.Location); + var localizationConfig = LocalizationConfiguration.Load(configuration); + + // loaded configuration should be manually placed to + domainConfiguration.ExtensionConfigurations.Set(localizationConfig); +``` + +The ```domainConfiguration.ExtensionConfigurations``` is a new unified place from which an extension will try to get its configuration +instead of calling default parameterless ```Load()``` method, which has not a lot of sense now, though the method is kept as a second source +for backwards compatibility. + +For more convenience, DomainConfiguration extensions are provided, which make code more neat and clear. +For instance, + +```csharp + var configuration = ConfigurationManager.OpenExeConfiguration(typeof(SomeTypeInConfigOwnerAssembly).Assembly.Location); + + var domainConfiguration = DomainConfiguration.Load(configuration); + + // the extension hides getting configuration with LocalizationConfiguration.Load(configuration) + // and also putting it to ExtensionConfigurations collection. + domainConfiguration.ConfigureLocalizationExtension(configuration); +``` + +Custom section names are also supported if for some reason default section name is not used. + + +**Example #3** Reading old-style configuration of an assembly in a project that uses appsettings.json file. + +If for some reason there is need to keep the old-style configuration then there is a work-around as well. +Static configuration manager provides method ```OpenMappedExeConfiguration()``` which allows to get +any *.config file as ```System.Configuration.Configuration``` instance. For example + +```csharp + ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap(); + configFileMap.ExeConfigFilename = "Orm.config"; //or other file name, the file should exist bin folder + var configuration = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None); +``` + +After that, as in previous example, the instance can be passed to ```Load``` method of ```LocalizationConfiguration``` to read extension configuration +and later put it to ```DomainConfiguration.ExtensionConfigurations```. +After ```System.Configuration.Configuration``` instance is provided it is possible to pass it into Load method of different DataObjects.Net configurations, +including ```LocalizationConfiguration```. Then put localization configuration to ```DomainConfiguration.ExtensionConfigurations``` collection. + +```csharp + var localizationConfiguration = LocalizationConfiguration.Load(configuration); + + domainConfiguration.ExtensionConfigurations.Set(localizationConfiguration); +``` + +or to extension method + +```csharp + domainConfiguration.ConfigureLocalizationExtension(configuration); +``` + + +**Example #4** Configure using Microsoft.Extensions.Configuration API. + +This API allows to have configurations in various forms including JSON and XML formats. +Loading of such files may differ depending on .NET version, check Microsoft manuals for instructions. + +Allowed Json and Xml configuration definition look like below + +```xml + + + es-ES + + +``` + +```json +{ + "Xtensive.Orm.Localization": { + "DefaultCulture": "es-ES" + } +} +``` + +The API has certain issues with Xml elements with attributes so it is recommended to use +more up-to-date attributeless nodes. +For JSON it is pretty clear. + +```LocalizationConfiguration.Load``` method can accept different types of abstractions from the +API, including +- ```Microsoft.Extensions.Configuration.IConfiguration```, +- ```Microsoft.Extensions.Configuration.IConfigurationRoot``` +- ```Microsoft.Extensions.Configuration.IConfigurationSection```. + +Loading of configuration may look like + +```csharp + + var app = builder.Build(); + + // tries to load from default section "Xtensive.Orm.Localization" + var localizationConfig = LocalizationConfiguration.Load(app.Configuration); + + domainConfiguration.ExtensionConfigurations.Set(localizationConfig); +``` + +or, with use of extension + + +```csharp + + var app = builder.Build(); + + // tries to load from default section "Xtensive.Orm.Localization" + // and additionally adds Xtensive.Orm.Localization assembly to domain types. + + domainConfiguration.ConfigureLocalizationExtension(app.Configuration); +``` + + + +**Example #5** Configure using Microsoft.Extensions.Configuration API from section with non-default name. + +For configurations like + +```xml + + + es-ES + + +``` + +```json +{ + "Orm.Localization": { + "DefaultCulture": "es-ES" + } +} +``` + +Loading of configuration may look like + +```csharp + + var app = builder.Build(); + + var localizationConfig = LocalizationConfiguration.Load(app.Configuration, "Orm.Localization"); + + domainConfiguration.ExtensionConfigurations.Set(localizationConfig); +``` + +or with use of extension + +```csharp + + var app = builder.Build(); + + domainConfiguration.ConfigureLocalizationExtension(app.Configuration, "Orm.Localization"); +``` + + +**Example #6** Configure using Microsoft.Extensions.Configuration API from sub-section deeper in section tree. + +If for some reason extension configuration should be moved deeper in section tree like something below + +```xml + + + + es-ES + + + +``` + +or in JSON + +```json +{ + "Orm.Extensions": { + "Xtensive.Orm.Localization": { + "DefaultCulture": "es-ES" + } + } +} +``` + +Then section must be provided manually, code may look like + +```csharp + + var app = builder.Build(); + + var configurationRoot = app.Configuration; + var extensionsGroupSection = configurationRoot.GetSection("Orm.Extensions"); + var localizationSection = extensionsGroupSection.GetSection("Xtensive.Orm.Localization"); + var localizationConfig = LocalizationConfiguration.Load(localizationSection); + + domainConfiguration.ExtensionConfigurations.Set(localizationConfig); +``` + +or with use of extension method + +```csharp + + var app = builder.Build(); + + var configurationRoot = app.Configuration; + var extensionsGroupSection = configurationRoot.GetSection("Orm.Extensions"); + var localizationSection = extensionsGroupSection.GetSection("Xtensive.Orm.Localization"); + + domainConfiguration.ConfigureLocalizationExtension(localizationSection); ``` \ No newline at end of file diff --git a/Extensions/Xtensive.Orm.Logging.NLog/NugetContent/ReadMe.md b/Extensions/Xtensive.Orm.Logging.NLog/NugetContent/ReadMe.md index 3fb46089a9..450daa9b68 100644 --- a/Extensions/Xtensive.Orm.Logging.NLog/NugetContent/ReadMe.md +++ b/Extensions/Xtensive.Orm.Logging.NLog/NugetContent/ReadMe.md @@ -1,4 +1,4 @@ -Xtensive.Orm.Logging.NLog +Xtensive.Orm.Logging.NLog ========================= Summary @@ -8,7 +8,7 @@ The extension provides integration points between DataObjects.Net internal loggi Prerequisites ------------- -DataObjects.Net 7.0.x (http://dataobjects.net) +DataObjects.Net 7.1.x (http://dataobjects.net) NLog 4.5 or later (http://nlog-project.org) Implementation diff --git a/Extensions/Xtensive.Orm.Logging.log4net/NugetContent/ReadMe.md b/Extensions/Xtensive.Orm.Logging.log4net/NugetContent/ReadMe.md index d5169400ed..664c522177 100644 --- a/Extensions/Xtensive.Orm.Logging.log4net/NugetContent/ReadMe.md +++ b/Extensions/Xtensive.Orm.Logging.log4net/NugetContent/ReadMe.md @@ -1,4 +1,4 @@ -Xtensive.Orm.Logging.log4net +Xtensive.Orm.Logging.log4net ============================ Summary @@ -7,7 +7,7 @@ The extension provides integration points between DataObjects.Net internal loggi Prerequisites ------------- -DataObjects.Net 7.0.x (http://dataobjects.net) +DataObjects.Net 7.1.x (http://dataobjects.net) log4net 2.0.10 or later (http://logging.apache.org/log4net/) Implementation diff --git a/Extensions/Xtensive.Orm.Reprocessing/NugetContent/ReadMe.md b/Extensions/Xtensive.Orm.Reprocessing/NugetContent/ReadMe.md index 8129b98f32..96bbcb134a 100644 --- a/Extensions/Xtensive.Orm.Reprocessing/NugetContent/ReadMe.md +++ b/Extensions/Xtensive.Orm.Reprocessing/NugetContent/ReadMe.md @@ -8,7 +8,7 @@ should represent a separate block of logic, usually a delegate of a method and b Prerequisites ------------- -DataObjects.Net 7.0.x (http://dataobjects.net) +DataObjects.Net 7.1.x (http://dataobjects.net) Examples of usage ----------------- @@ -40,10 +40,16 @@ To indicate that a particular strategy should be used, use the following syntax: }); ``` -**Expample #3**. Confugure reprocessing in configuration file. To omit setting up the strategy each time consider configuring it in -application configuration file, e.g.: + +Examples of how to configure extension +-------------------------------------- + +Following examples show different ways to configure extension in configuration files of various types. + +**Example #1** Confugure in App.config/Web.config ```xml +
+ +``` + +Such configuration is only compatible with System.Configuration.ConfigurationManager. +If project still supports such configurations then Reprocessing configuration will be read automatically when it needed to be read. +Sometimes a work-around is needed to read such configuration, for more read Example #2 and Example #3 + + +**Example #2** Reading old-style configuration of an assembly in NET 5 and newer. + +Due to new architecture without AppDomain (which among the other things was in charge of gathering configuration files of loaded assemblies +as it would be one configuration file) System.Configuration.ConfigurationManager now reads only configuration file of actual executable, loaded +assemblies' configuration files stay unreachable by default, though there is need to read some data from them. +A great example is test projects which are usually get loaded by test runner executable, and the only configuration accessible in this case +is test runner one. + +Extra step is required to read configuration files in such cases. Thankfully ConfigurationManager has methods to get access to assemblies' configurations. + +To get access to an assembly configuration file it should be opened explicitly by + +```csharp + var configuration = ConfigurationManager.OpenExeConfiguration(typeof(SomeTypeInConfigOwnerAssembly).Assembly.Location); +``` + +The instance returned from ```OpenExeConfiguration``` provides access to sections of the assembly configuration. DataObjects.Net configurations +(```DomainConfiguration```, ```ReprocessingConfiguration```, etc.) have ```Load()``` methods that can recieve this instance. +```ReprocessingConfiguration``` can be read like so + +```csharp + var configuration = ConfigurationManager.OpenExeConfiguration(typeof(SomeTypeInConfigOwnerAssembly).Assembly.Location); + var reprocessingConfig = ReprocessingConfiguration.Load(configuration); + + // loaded configuration should be manually placed to + domainConfiguration.ExtensionConfigurations.Set(reprocessingConfig); +``` + +The ```domainConfiguration.ExtensionConfigurations``` is a new unified place from which an extension will try to get its configuration +instead of calling default parameterless ```Load()``` method, which has not a lot of sense now, though the method is kept as a second source +for backwards compatibility. + +For more convenience, DomainConfiguration extensions are provided, which make code more neat and clear. +For instance, + +```csharp + var configuration = ConfigurationManager.OpenExeConfiguration(typeof(SomeTypeInConfigOwnerAssembly).Assembly.Location); + + var domainConfiguration = DomainConfiguration.Load(configuration); + + // the extension hides getting configuration with ReprocessingConfiguration.Load(configuration) + // and also putting it to ExtensionConfigurations collection. + domainConfiguration.ConfigureReprocessingExtension(configuration); +``` + +Custom section names are also supported if for some reason default section name is not used. + + +**Example #3** Reading old-style configuration of an assembly in a project that uses appsettings.json file. + +If for some reason there is need to keep the old-style configuration then there is a work-around as well. +Static configuration manager provides method ```OpenMappedExeConfiguration()``` which allows to get +any *.config file as ```System.Configuration.Configuration``` instance. For example + +```csharp + ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap(); + configFileMap.ExeConfigFilename = "Orm.config"; //or other file name, the file should exist bin folder + var configuration = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None); +``` + +After that, as in previous example, the instance can be passed to ```Load``` method of ```ReprocessingConfiguration``` to read extension configuration +and later put it to ```DomainConfiguration.ExtensionConfigurations```. +After ```System.Configuration.Configuration``` instance is provided it is possible to pass it into Load method of different DataObjects.Net configurations, +including ```ReprocessingConfiguration```. Then put reprocessing configuration to ```DomainConfiguration.ExtensionConfigurations``` collection. + +```csharp + var reprocessingConfiguration = ReprocessingConfiguration.Load(configuration); + + domainConfiguration.ExtensionConfigurations.Set(reprocessingConfiguration); +``` + +or to extension method + +```csharp + domainConfiguration.ConfigureReprocessingExtension(configuration); +``` + + +**Example #4** Configure using Microsoft.Extensions.Configuration API. + +This API allows to have configurations in various forms including JSON and XML formats. +Loading of such files may differ depending on .NET version, check Microsoft manuals for instructions. + +Allowed Json and Xml configuration definition look like below + +```xml + + + New + Xtensive.Orm.Reprocessing.HandleReprocessableExceptionStrategy, Xtensive.Orm.Reprocessing + + +``` + +```json +{ + "Xtensive.Orm.Reprocessing": { + "DefaultTransactionOpenMode" : "New", + "DefaultExecuteStrategy" : "Xtensive.Orm.Reprocessing.HandleReprocessableExceptionStrategy, Xtensive.Orm.Reprocessing" + } +} +``` + +The API has certain issues with Xml elements with attributes so it is recommended to use +more up-to-date attributeless nodes. +For JSON it is pretty clear. + +```ReprocessingConfiguration.Load``` method can accept different types of abstractions from the +API, including +- ```Microsoft.Extensions.Configuration.IConfiguration```, +- ```Microsoft.Extensions.Configuration.IConfigurationRoot``` +- ```Microsoft.Extensions.Configuration.IConfigurationSection```. + +Loading of configuration may look like + +```csharp + + var app = builder.Build(); + + // tries to load from default section "Xtensive.Orm.Reprocessing" + var reprocessingConfig = ReprocessingConfiguration.Load(app.Configuration); + + domainConfiguration.ExtensionConfigurations.Set(reprocessingConfig); +``` + +or, with use of extension + + +```csharp + + var app = builder.Build(); + + // tries to load from default section "Xtensive.Orm.Reprocessing" + // and put it into domainConfiguration.ExtensionConfigurations + + domainConfiguration.ConfigureReprocessingExtension(app.Configuration); +``` + + + +**Example #5** Configure using Microsoft.Extensions.Configuration API from section with non-default name. + +For configurations like + +```xml + + + New + Xtensive.Orm.Reprocessing.HandleReprocessableExceptionStrategy, Xtensive.Orm.Reprocessing + + +``` + +```json +{ + "Orm.Reprocessing": { + "DefaultTransactionOpenMode" : "New", + "DefaultExecuteStrategy" : "Xtensive.Orm.Reprocessing.HandleReprocessableExceptionStrategy, Xtensive.Orm.Reprocessing" + } +} +``` + +Loading of configuration may look like + +```csharp + + var app = builder.Build(); + + var reprocessingConfig = ReprocessingConfiguration.Load(app.Configuration, "Orm.Reprocessing"); + + domainConfiguration.ExtensionConfigurations.Set(reprocessingConfig); ``` -Having that done, in scenarios with no strategy specified, the extension will automatically use -the strategy from the configuration. \ No newline at end of file +or with use of extension + +```csharp + + var app = builder.Build(); + + domainConfiguration.ConfigureReprocessingExtension(app.Configuration, "Orm.Reprocessing"); +``` + + +**Example #6** Configure using Microsoft.Extensions.Configuration API from sub-section deeper in section tree. + +If for some reason extension configuration should be moved deeper in section tree like something below + +```xml + + + + New + Xtensive.Orm.Reprocessing.HandleReprocessableExceptionStrategy, Xtensive.Orm.Reprocessing + + + +``` + +or in JSON + +```json +{ + "Orm.Extensions": { + "Xtensive.Orm.Reprocessing": { + "DefaultTransactionOpenMode" : "New", + "DefaultExecuteStrategy" : "Xtensive.Orm.Reprocessing.HandleReprocessableExceptionStrategy, Xtensive.Orm.Reprocessing" + } + } +} +``` + +Then section must be provided manually, code may look like + +```csharp + + var app = builder.Build(); + + var configurationRoot = app.Configuration; + var extensionsGroupSection = configurationRoot.GetSection("Orm.Extensions"); + var reprocessingSection = extensionsGroupSection.GetSection("Xtensive.Orm.Reprocessing"); + + var reprocessingConfig = ReprocessingConfiguration.Load(reprocessingSection); + + domainConfiguration.ExtensionConfigurations.Set(reprocessingConfig); +``` + +or with use of extension method + +```csharp + + var app = builder.Build(); + + var configurationRoot = app.Configuration; + var extensionsGroupSection = configurationRoot.GetSection("Orm.Extensions"); + var reprocessingSection = extensionsGroupSection.GetSection("Xtensive.Orm.Reprocessing"); + + domainConfiguration.ConfigureReprocessingExtension(reprocessingSection); +``` diff --git a/Extensions/Xtensive.Orm.Security/NugetContent/ReadMe.md b/Extensions/Xtensive.Orm.Security/NugetContent/ReadMe.md index 143b111b76..426919e90b 100644 --- a/Extensions/Xtensive.Orm.Security/NugetContent/ReadMe.md +++ b/Extensions/Xtensive.Orm.Security/NugetContent/ReadMe.md @@ -8,7 +8,7 @@ There are 2 main parts that can also be used separately: authentication services Prerequisites ------------- -DataObjects.Net 7.0.x or later (http://dataobjects.net) +DataObjects.Net 7.1.x or later (http://dataobjects.net) How to use ---------- @@ -43,6 +43,8 @@ and set up the desired hashing service: ``` +Other examples of how to configure the extension are in section below + Examples -------- @@ -311,4 +313,256 @@ customers that have IsAutomobileIndustry property set to true, e.g.: transaction.Complete(); } } -``` \ No newline at end of file +``` + + + +Examples of how to configure extension +-------------------------------------- + +Additionally to "How to use" section it provides extra examples of how to configure and/or read extension configuration. + +The example in "How to use" section uses old fasioned API of configuration files, yet usable in many applications. But +there are some cases which may require usage of different API or work-around certain cases with existing one. + +**Example #1** Reading old-style configuration of an assembly in NET 5 and newer. + +Due to new architecture without AppDomain (which among the other things was in charge of gathering configuration files of loaded assemblies +as it would be one configuration file) System.Configuration.ConfigurationManager now reads only configuration file of actual executable, loaded +assemblies' configuration files stay unreachable by default, though there is need to read some data from them. +A great example is test projects which are usually get loaded by test runner executable, and the only configuration accessible in this case +is test runner one. + +Extra step is required to read configuration files in such cases. Thankfully ConfigurationManager has methods to get access to assemblies' configurations. + +To get access to an assembly configuration file it should be opened explicitly by + +```csharp + var configuration = ConfigurationManager.OpenExeConfiguration(typeof(SomeTypeInConfigOwnerAssembly).Assembly.Location); +``` + +The instance returned from ```OpenExeConfiguration``` provides access to sections of the assembly configuration. DataObjects.Net configurations +(```DomainConfiguration```, ```SecurityConfiguration```, etc.) have ```Load()``` methods that can recieve this instance. +```SecurityConfiguration``` can be read like so + +```csharp + var configuration = ConfigurationManager.OpenExeConfiguration(typeof(SomeTypeInConfigOwnerAssembly).Assembly.Location); + var securityConfig = SecurityConfiguration.Load(configuration); + + // loaded configuration should be manually placed to + domainConfiguration.ExtensionConfigurations.Set(securityConfig); +``` + +The ```domainConfiguration.ExtensionConfigurations``` is a new unified place from which an extension will try to get its configuration +instead of calling default parameterless ```Load()``` method, which has not a lot of sense now, though the method is kept as a second source +for backwards compatibility. + +For more convenience, DomainConfiguration extensions are provided, which make code more neat and clear. +For instance, + +```csharp + var configuration = ConfigurationManager.OpenExeConfiguration(typeof(SomeTypeInConfigOwnerAssembly).Assembly.Location); + + var domainConfiguration = DomainConfiguration.Load(configuration); + + // the extension hides getting configuration with SecurityConfiguration.Load(configuration) + // and also putting it to ExtensionConfigurations collection. + domainConfiguration.ConfigureSecurityExtension(configuration); +``` + +Remember the requirement to register ```Xtensive.Orm.Security``` to domain? The extension tries to register this assembly to ```DomainConfiguration.Types``` collection +so even if you miss registration but called extension method required types of Security extension will be registered in Domain types. + +Custom section names are also supported if for some reason default section name is not used. + + +**Example #3** Reading old-style configuration of an assembly in a project that uses appsettings.json file. + +If for some reason there is need to keep the old-style configuration then there is a work-around as well. +Static configuration manager provides method ```OpenMappedExeConfiguration()``` which allows to get access to +any *.config file as ```System.Configuration.Configuration``` instance. For example + +```csharp + ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap(); + configFileMap.ExeConfigFilename = "Orm.config"; //or other file name, the file should exist bin folder + var configuration = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None); +``` + +After that, as in previous example, the instance can be passed to ```Load``` method of ```SecurityConfiguration``` to read extension configuration +and later put it to ```DomainConfiguration.ExtensionConfigurations```. +After ```System.Configuration.Configuration``` instance is providedit is possible to pass it into Load method of different DataObjects.Net configurations, +including ```SecurityConfiguration```. Then put security configuration to ```DomainConfiguration.ExtensionConfigurations``` collection. + +```csharp + var securityConfiguration = SecurityConfiguration.Load(configuration); + + domainConfiguration.ExtensionConfigurations.Set(securityConfiguration); +``` + +or to extension method + +```csharp + domainConfiguration.ConfigureSecurityExtension(configuration); +``` + + +**Example #4** Configure using Microsoft.Extensions.Configuration API. + +This API allows to have configurations in various forms including JSON and XML formats. +Loading of such files may differ depending on .NET version, check Microsoft manuals for instructions. + +Allowed JSON and XML configuration definition look like below + +```xml + + + sha512 + CustomAuthenticationService + + +``` + +```json +{ + "Xtensive.Orm.Security": { + "HashingService" : "sha512", + "AuthenticationService" : "CustomAuthenticationService" + } +} +``` + +The API has certain issues with Xml elements with attributes so it is recommended to use +more up-to-date attributeless nodes. +For JSON it is pretty clear. + +```SecurityConfiguration.Load``` method can accept different types of abstractions from the +API, including +- ```Microsoft.Extensions.Configuration.IConfiguration```, +- ```Microsoft.Extensions.Configuration.IConfigurationRoot``` +- ```Microsoft.Extensions.Configuration.IConfigurationSection```. + +Loading of configuration may look like + +```csharp + + var app = builder.Build(); + + // tries to load from default section "Xtensive.Orm.Security" + var securityConfig = SecurityConfiguration.Load(app.Configuration); + + domainConfiguration.ExtensionConfigurations.Set(securityConfig); +``` + +or, with use of extension + + +```csharp + + var app = builder.Build(); + + // Tries to load from default section "Xtensive.Orm.Security" + // and put it into domainConfiguration.ExtensionConfigurations. + // Additionally, registers types of "Xtensive.Orm.Security" assembly. + + domainConfiguration.ConfigureSecurityExtension(app.Configuration); +``` + + + +**Example #5** Configure using Microsoft.Extensions.Configuration API from section with non-default name. + +For configurations like + +```xml + + + sha512 + CustomAuthenticationService + + +``` + +```json +{ + "Orm.Security": { + "HashingService" : "sha512", + "AuthenticationService" : "CustomAuthenticationService" + } +} + +Loading of configuration may look like + +```csharp + + var app = builder.Build(); + + var securityConfig = SecurityConfiguration.Load(app.Configuration, "Orm.Security"); + + domainConfiguration.ExtensionConfigurations.Set(securityConfig); +``` + +or with use of extension + +```csharp + + var app = builder.Build(); + + domainConfiguration.ConfigureSecurityExtension(app.Configuration, "Orm.Security"); +``` + + +**Example #6** Configure using Microsoft.Extensions.Configuration API from sub-section deeper in section tree. + +If for some reason extension configuration should be moved deeper in section tree like something below + +```xml + + + + sha512 + CustomAuthenticationService + + + +``` + +or in JSON + +```json +{ + "Orm.Extensions": { + "Xtensive.Orm.Security": { + "HashingService" : "sha512", + "AuthenticationService" : "CustomAuthenticationService" + } + } +} +``` + +Then section must be provided manually, code may look like + +```csharp + + var app = builder.Build(); + + var configurationRoot = app.Configuration; + var extensionsGroupSection = configurationRoot.GetSection("Orm.Extensions"); + var securitySection = extensionsGroupSection.GetSection("Xtensive.Orm.Security"); + + var securityConfig = SecurityConfiguration.Load(securitySection); + + domainConfiguration.ExtensionConfigurations.Set(securityConfig); +``` + +or with use of extension method + +```csharp + + var app = builder.Build(); + + var configurationRoot = app.Configuration; + var extensionsGroupSection = configurationRoot.GetSection("Orm.Extensions"); + var securitySection = extensionsGroupSection.GetSection("Xtensive.Orm.Security"); + + domainConfiguration.ConfigureSecurityExtension(securitySection); +``` diff --git a/Extensions/Xtensive.Orm.Tracking/NugetContent/ReadMe.md b/Extensions/Xtensive.Orm.Tracking/NugetContent/ReadMe.md index baefbb2de6..81bf58b227 100644 --- a/Extensions/Xtensive.Orm.Tracking/NugetContent/ReadMe.md +++ b/Extensions/Xtensive.Orm.Tracking/NugetContent/ReadMe.md @@ -1,4 +1,4 @@ -Xtensive.Orm.Tracking +Xtensive.Orm.Tracking ===================== Summary @@ -7,7 +7,7 @@ Provides tracking/auditing funtionality on Session/Domain level. Prerequisites ------------- -DataObjects.Net 7.0.x or later (http://dataobjects.net) +DataObjects.Net 7.1.x or later (http://dataobjects.net) Implementation -------------- diff --git a/Extensions/Xtensive.Orm.Web/NugetContent/ReadMe.md b/Extensions/Xtensive.Orm.Web/NugetContent/ReadMe.md index d19d1779f1..08223c0fb1 100644 --- a/Extensions/Xtensive.Orm.Web/NugetContent/ReadMe.md +++ b/Extensions/Xtensive.Orm.Web/NugetContent/ReadMe.md @@ -1,4 +1,4 @@ -Xtensive.Orm.Web +Xtensive.Orm.Web ================ Summary @@ -11,7 +11,7 @@ by default unless an exeption appeared. (more info on https://dataobjects.net) Prerequisites ------------- -DataObjects.Net 7 or later (https://dataobjects.net) +DataObjects.Net 7.1 or later (https://dataobjects.net) Usage of action filter ---------------------- From eb5536ea15287ec156b64c0f19b27600c29ddffb Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 3 Oct 2024 16:42:01 +0500 Subject: [PATCH 25/32] Fix build --- .../Configuration/Internals/ExtensionConfigurationCollection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Internals/ExtensionConfigurationCollection.cs b/Orm/Xtensive.Orm/Orm/Configuration/Internals/ExtensionConfigurationCollection.cs index 95b96b3e1b..193953843c 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Internals/ExtensionConfigurationCollection.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Internals/ExtensionConfigurationCollection.cs @@ -13,7 +13,7 @@ namespace Xtensive.Orm.Configuration /// Default implementation (lockable). ///
[Serializable] - public sealed class ExtensionConfigurationCollection : LockableBase + public sealed class ExtensionConfigurationCollection : LockableBase, IEnumerable { private Dictionary extensionConfigurations; From 6ba683fa24f2b2ac0beb71862aa476a48e73e798 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Fri, 11 Oct 2024 19:14:53 +0500 Subject: [PATCH 26/32] Fix some problems in extensions' configuration loading --- .../ReprocessingConfigurationReader.cs | 4 ++-- .../Elements/ConfigurationSection.cs | 15 +++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfigurationReader.cs b/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfigurationReader.cs index 7ea1ba6e47..d4d27f99d4 100644 --- a/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfigurationReader.cs +++ b/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfigurationReader.cs @@ -9,7 +9,7 @@ internal sealed class ReprocessingConfigurationReader : IConfigurationSectionRea // intermediate class for reading section private class ReprocessingOptions { - public TransactionOpenMode DefaultTransactionOpenMode { get; set; } + public TransactionOpenMode? DefaultTransactionOpenMode { get; set; } public string DefaultExecuteStrategy { get; set; } } @@ -47,7 +47,7 @@ private ReprocessingConfiguration ReadInternal(IConfigurationSection section) var result = new ReprocessingConfiguration(); if (reprocessingOptions.DefaultTransactionOpenMode != default) { - result.DefaultTransactionOpenMode = reprocessingOptions.DefaultTransactionOpenMode; + result.DefaultTransactionOpenMode = reprocessingOptions.DefaultTransactionOpenMode.Value; } if (!string.IsNullOrEmpty(reprocessingOptions.DefaultExecuteStrategy)) { var type = Type.GetType(reprocessingOptions.DefaultExecuteStrategy, false); diff --git a/Extensions/Xtensive.Orm.Security/Configuration/Elements/ConfigurationSection.cs b/Extensions/Xtensive.Orm.Security/Configuration/Elements/ConfigurationSection.cs index 24956db0b8..86899f68d4 100644 --- a/Extensions/Xtensive.Orm.Security/Configuration/Elements/ConfigurationSection.cs +++ b/Extensions/Xtensive.Orm.Security/Configuration/Elements/ConfigurationSection.cs @@ -21,26 +21,29 @@ public class ConfigurationSection : System.Configuration.ConfigurationSection [Obsolete("Use SecurityConfiguration.DefaultSectionName instead")] public static readonly string DefaultSectionName = "Xtensive.Orm.Security"; + private const string HashingServiceElementName = "hashingService"; + private const string AuthenticationServiceElementName = "authenticationService"; + /// /// Gets or sets the hashing service. /// /// The hashing service. - [ConfigurationProperty(SecurityConfiguration.HashingServiceElementName, IsRequired = false)] + [ConfigurationProperty(HashingServiceElementName, IsRequired = false)] public HashingServiceConfigurationElement HashingService { - get { return (HashingServiceConfigurationElement) this[SecurityConfiguration.HashingServiceElementName]; } - set { this[SecurityConfiguration.HashingServiceElementName] = value; } + get { return (HashingServiceConfigurationElement) this[HashingServiceElementName]; } + set { this[HashingServiceElementName] = value; } } /// /// Gets or sets the authentication service. /// /// The authentication service. - [ConfigurationProperty(SecurityConfiguration.AuthenticationServiceElementName, IsRequired = false)] + [ConfigurationProperty(AuthenticationServiceElementName, IsRequired = false)] public AuthenticationServiceConfigurationElement AuthenticationService { - get { return (AuthenticationServiceConfigurationElement) this[SecurityConfiguration.AuthenticationServiceElementName]; } - set { this[SecurityConfiguration.AuthenticationServiceElementName] = value; } + get { return (AuthenticationServiceConfigurationElement) this[AuthenticationServiceElementName]; } + set { this[AuthenticationServiceElementName] = value; } } } } \ No newline at end of file From 558683fdaf86c1488ea51b030cc29e287ad8c9a1 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Mon, 14 Oct 2024 12:15:54 +0500 Subject: [PATCH 27/32] One version of packages for net5 and net6 --- .../Xtensive.Orm.Localization.Tests.csproj | 6 ++---- .../Xtensive.Orm.Localization.csproj | 4 ++-- .../Xtensive.Orm.Reprocessing.Tests.csproj | 6 ++---- .../Xtensive.Orm.Reprocessing.csproj | 4 ++-- .../Xtensive.Orm.Security.Tests.csproj | 6 ++---- .../Xtensive.Orm.Security.csproj | 4 ++-- Orm/Xtensive.Orm.Tests/Xtensive.Orm.Tests.csproj | 11 +++-------- Orm/Xtensive.Orm/Xtensive.Orm.csproj | 6 ++---- 8 files changed, 17 insertions(+), 30 deletions(-) diff --git a/Extensions/Xtensive.Orm.Localization.Tests/Xtensive.Orm.Localization.Tests.csproj b/Extensions/Xtensive.Orm.Localization.Tests/Xtensive.Orm.Localization.Tests.csproj index ab65999ee8..0cd2670c26 100644 --- a/Extensions/Xtensive.Orm.Localization.Tests/Xtensive.Orm.Localization.Tests.csproj +++ b/Extensions/Xtensive.Orm.Localization.Tests/Xtensive.Orm.Localization.Tests.csproj @@ -8,16 +8,14 @@ + + - - - - diff --git a/Extensions/Xtensive.Orm.Localization/Xtensive.Orm.Localization.csproj b/Extensions/Xtensive.Orm.Localization/Xtensive.Orm.Localization.csproj index bea774e22d..318bb83b12 100644 --- a/Extensions/Xtensive.Orm.Localization/Xtensive.Orm.Localization.csproj +++ b/Extensions/Xtensive.Orm.Localization/Xtensive.Orm.Localization.csproj @@ -31,11 +31,11 @@ - - + + diff --git a/Extensions/Xtensive.Orm.Reprocessing.Tests/Xtensive.Orm.Reprocessing.Tests.csproj b/Extensions/Xtensive.Orm.Reprocessing.Tests/Xtensive.Orm.Reprocessing.Tests.csproj index e620d91ca5..4f22c02059 100644 --- a/Extensions/Xtensive.Orm.Reprocessing.Tests/Xtensive.Orm.Reprocessing.Tests.csproj +++ b/Extensions/Xtensive.Orm.Reprocessing.Tests/Xtensive.Orm.Reprocessing.Tests.csproj @@ -8,16 +8,14 @@ + + - - - - diff --git a/Extensions/Xtensive.Orm.Reprocessing/Xtensive.Orm.Reprocessing.csproj b/Extensions/Xtensive.Orm.Reprocessing/Xtensive.Orm.Reprocessing.csproj index 6bf37921d3..dcc997498e 100644 --- a/Extensions/Xtensive.Orm.Reprocessing/Xtensive.Orm.Reprocessing.csproj +++ b/Extensions/Xtensive.Orm.Reprocessing/Xtensive.Orm.Reprocessing.csproj @@ -17,11 +17,11 @@ - - + + diff --git a/Extensions/Xtensive.Orm.Security.Tests/Xtensive.Orm.Security.Tests.csproj b/Extensions/Xtensive.Orm.Security.Tests/Xtensive.Orm.Security.Tests.csproj index 8cc858fa2d..70465a2674 100644 --- a/Extensions/Xtensive.Orm.Security.Tests/Xtensive.Orm.Security.Tests.csproj +++ b/Extensions/Xtensive.Orm.Security.Tests/Xtensive.Orm.Security.Tests.csproj @@ -8,16 +8,14 @@ + + - - - - diff --git a/Extensions/Xtensive.Orm.Security/Xtensive.Orm.Security.csproj b/Extensions/Xtensive.Orm.Security/Xtensive.Orm.Security.csproj index c1ee63836a..4e15c012c7 100644 --- a/Extensions/Xtensive.Orm.Security/Xtensive.Orm.Security.csproj +++ b/Extensions/Xtensive.Orm.Security/Xtensive.Orm.Security.csproj @@ -18,11 +18,11 @@ - - + + diff --git a/Orm/Xtensive.Orm.Tests/Xtensive.Orm.Tests.csproj b/Orm/Xtensive.Orm.Tests/Xtensive.Orm.Tests.csproj index 1ad40b510c..f048eb412e 100644 --- a/Orm/Xtensive.Orm.Tests/Xtensive.Orm.Tests.csproj +++ b/Orm/Xtensive.Orm.Tests/Xtensive.Orm.Tests.csproj @@ -14,18 +14,11 @@ - - - - - - - @@ -34,7 +27,9 @@ - + + + diff --git a/Orm/Xtensive.Orm/Xtensive.Orm.csproj b/Orm/Xtensive.Orm/Xtensive.Orm.csproj index 666f8dfd63..b6ed0b3f02 100644 --- a/Orm/Xtensive.Orm/Xtensive.Orm.csproj +++ b/Orm/Xtensive.Orm/Xtensive.Orm.csproj @@ -51,16 +51,14 @@ - - - - + + From 1d3f31033f17ea70c94f5faa9860d9723a7b18dc Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Mon, 14 Oct 2024 12:45:57 +0500 Subject: [PATCH 28/32] Fix wrong version of basis assembly --- .../Xtensive.Orm.Localization.Tests.csproj | 5 ----- .../Xtensive.Orm.Reprocessing.Tests.csproj | 5 ----- .../Xtensive.Orm.Security.Tests.csproj | 5 ----- 3 files changed, 15 deletions(-) diff --git a/Extensions/Xtensive.Orm.Localization.Tests/Xtensive.Orm.Localization.Tests.csproj b/Extensions/Xtensive.Orm.Localization.Tests/Xtensive.Orm.Localization.Tests.csproj index 0cd2670c26..79c0f9f637 100644 --- a/Extensions/Xtensive.Orm.Localization.Tests/Xtensive.Orm.Localization.Tests.csproj +++ b/Extensions/Xtensive.Orm.Localization.Tests/Xtensive.Orm.Localization.Tests.csproj @@ -10,11 +10,6 @@ - - - - - diff --git a/Extensions/Xtensive.Orm.Reprocessing.Tests/Xtensive.Orm.Reprocessing.Tests.csproj b/Extensions/Xtensive.Orm.Reprocessing.Tests/Xtensive.Orm.Reprocessing.Tests.csproj index 4f22c02059..3c995ffcc5 100644 --- a/Extensions/Xtensive.Orm.Reprocessing.Tests/Xtensive.Orm.Reprocessing.Tests.csproj +++ b/Extensions/Xtensive.Orm.Reprocessing.Tests/Xtensive.Orm.Reprocessing.Tests.csproj @@ -10,11 +10,6 @@ - - - - - diff --git a/Extensions/Xtensive.Orm.Security.Tests/Xtensive.Orm.Security.Tests.csproj b/Extensions/Xtensive.Orm.Security.Tests/Xtensive.Orm.Security.Tests.csproj index 70465a2674..b40c1f9f11 100644 --- a/Extensions/Xtensive.Orm.Security.Tests/Xtensive.Orm.Security.Tests.csproj +++ b/Extensions/Xtensive.Orm.Security.Tests/Xtensive.Orm.Security.Tests.csproj @@ -10,11 +10,6 @@ - - - - - From 0bed3feba7203295a9ff1c11d4c6465d07c6ebcf Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Mon, 14 Oct 2024 13:51:58 +0500 Subject: [PATCH 29/32] Fixed lost reference to v5.0.0 packages --- Extensions/TestCommon/TestCommon.csproj | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/Extensions/TestCommon/TestCommon.csproj b/Extensions/TestCommon/TestCommon.csproj index 5b01dd3730..16a3f08891 100644 --- a/Extensions/TestCommon/TestCommon.csproj +++ b/Extensions/TestCommon/TestCommon.csproj @@ -8,22 +8,13 @@ $(ExtensionsKeyFile) - - - - - - - - - - - - + + + From 62319d104ae3e0d96eecc155ed55a263b4776d9f Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Mon, 14 Oct 2024 17:24:09 +0500 Subject: [PATCH 30/32] Minor changes - summaries for files, types, type members - small code improvements --- .../LocalizationConfiguration.cs | 21 ++-- .../LocalizationConfigurationReader.cs | 37 +++--- .../Configuration/ConfigurationSection.cs | 5 +- .../ReprocessingConfiguration.cs | 18 +-- .../ReprocessingConfigurationReader.cs | 8 +- .../DomainConfigurationExtensions.cs | 4 + .../Configuration/SecurityConfiguration.cs | 29 +++-- .../SecurityConfigurationReaders.cs | 36 +++--- .../Orm/Configuration/DomainConfiguration.cs | 4 +- .../ExtensionConfigurationCollection.cs | 8 +- .../ConfigurationSectionExtensions.cs | 2 +- .../Internals/DomainConfigurationReaders.cs | 113 +++++++++++------- .../Internals/LoggingConfigurationReader.cs | 8 +- .../Orm/Configuration/LoggingConfiguration.cs | 3 +- Orm/Xtensive.Orm/Orm/WellKnown.cs | 5 + 15 files changed, 170 insertions(+), 131 deletions(-) rename Orm/Xtensive.Orm/Orm/Configuration/{Internals => }/ExtensionConfigurationCollection.cs (94%) diff --git a/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfiguration.cs b/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfiguration.cs index ac8c0a3e1e..6b84a40dd2 100644 --- a/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfiguration.cs +++ b/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfiguration.cs @@ -1,6 +1,6 @@ -// Copyright (C) 2011-2024 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// Copyright (C) 2012-2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Dmitri Maximov // Created: 2012.07.06 @@ -132,7 +132,7 @@ private static LocalizationConfiguration GetConfigurationFromSection(Configurati } /// - /// Loads from given configuration section of . + /// Loads from given configuration section of . /// If section name is not provided is used. /// /// of sections. @@ -142,17 +142,16 @@ public static LocalizationConfiguration Load(IConfiguration configuration, strin { ArgumentValidator.EnsureArgumentNotNull(configuration, nameof(configuration)); - if (configuration is IConfigurationRoot configurationRoot) + if (configuration is IConfigurationRoot configurationRoot) { return new LocalizationConfigurationReader().Read(configurationRoot, sectionName ?? DefaultSectionName); + } else if (configuration is IConfigurationSection configurationSection) { - if (sectionName.IsNullOrEmpty()) - return new LocalizationConfigurationReader().Read(configurationSection); - else { - return new LocalizationConfigurationReader().Read(configurationSection.GetSection(sectionName)); - } + return sectionName.IsNullOrEmpty() + ? new LocalizationConfigurationReader().Read(configurationSection) + : new LocalizationConfigurationReader().Read(configurationSection.GetSection(sectionName)); } - throw new NotSupportedException("Type of configuration is not supported"); + throw new NotSupportedException("Type of configuration is not supported."); } /// diff --git a/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfigurationReader.cs b/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfigurationReader.cs index 11cc298693..0b7fce4531 100644 --- a/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfigurationReader.cs +++ b/Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfigurationReader.cs @@ -1,8 +1,6 @@ -// Copyright (C) 2011-2024 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. -// Created by: Dmitri Maximov -// Created: 2012.07.06 +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. using System; using System.Globalization; @@ -16,6 +14,9 @@ namespace Xtensive.Orm.Localization.Configuration { internal sealed class LocalizationConfigurationReader : IConfigurationSectionReader { + private const string DefaultCultureElementName = "DefaultCulture"; + private const string CultureNameAttributeName = "name"; + public LocalizationConfiguration Read(IConfigurationSection configurationSection) => ReadInternal(configurationSection); public LocalizationConfiguration Read(IConfigurationSection configurationSection, string nameOfConfiguration) => @@ -33,14 +34,13 @@ public LocalizationConfiguration Read(IConfigurationRoot configurationRoot, stri public LocalizationConfiguration Read(IConfigurationRoot configurationRoot, string sectionName, string nameOfConfiguration) => throw new NotSupportedException(); - private const string DefaultCultureElementName = "DefaultCulture"; - private const string CultureNameAttributeName = "name"; - private LocalizationConfiguration ReadInternal(IConfigurationSection configurationSection) { var defaultCultureSection = configurationSection.GetSection(DefaultCultureElementName); - if (defaultCultureSection == null) - return new LocalizationConfiguration() { DefaultCulture = Thread.CurrentThread.CurrentCulture }; + var defaultCulture = Thread.CurrentThread.CurrentCulture; + if (defaultCultureSection == null) { + return new LocalizationConfiguration() { DefaultCulture = defaultCulture }; + } var cultureName = defaultCultureSection.Value; if (cultureName == null) { @@ -52,15 +52,16 @@ private LocalizationConfiguration ReadInternal(IConfigurationSection configurati } } } - - if (cultureName.IsNullOrEmpty()) - return new LocalizationConfiguration() { DefaultCulture = Thread.CurrentThread.CurrentCulture }; - try { - return new LocalizationConfiguration() { DefaultCulture = new CultureInfo(cultureName) }; - } - catch (CultureNotFoundException) { - return new LocalizationConfiguration() { DefaultCulture = Thread.CurrentThread.CurrentCulture }; + if(!cultureName.IsNullOrEmpty()) { + try { + defaultCulture = CultureInfo.GetCultureInfo(cultureName); + } + catch(CultureNotFoundException) { + // swallow it, this is mark wrong culture name; + } } + + return new LocalizationConfiguration() { DefaultCulture = defaultCulture }; } } } \ No newline at end of file diff --git a/Extensions/Xtensive.Orm.Reprocessing/Configuration/ConfigurationSection.cs b/Extensions/Xtensive.Orm.Reprocessing/Configuration/ConfigurationSection.cs index d93d13802c..6b8d0d2718 100644 --- a/Extensions/Xtensive.Orm.Reprocessing/Configuration/ConfigurationSection.cs +++ b/Extensions/Xtensive.Orm.Reprocessing/Configuration/ConfigurationSection.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using System.Configuration; @@ -11,8 +11,9 @@ public class ConfigurationSection : System.Configuration.ConfigurationSection { /// /// Gets default section name for reprocessing configuration. - /// Value is "Xtensive.Reprocessing". + /// Value is "Xtensive.Orm.Reprocessing". /// + [Obsolete("Use ReprocessingConfiguration.DefaultSectionName instead")] public static readonly string DefaultSectionName = "Xtensive.Orm.Reprocessing"; /// diff --git a/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfiguration.cs b/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfiguration.cs index 679ecbe256..6e7adbc458 100644 --- a/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfiguration.cs +++ b/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfiguration.cs @@ -11,6 +11,12 @@ namespace Xtensive.Orm.Reprocessing.Configuration /// public class ReprocessingConfiguration : ConfigurationBase { + /// + /// Gets default section name for reprocessing configuration. + /// Value is "Xtensive.Orm.Reprocessing". + /// + public static readonly string DefaultSectionName = "Xtensive.Orm.Reprocessing"; + /// /// Gets default value of the property. /// @@ -68,7 +74,7 @@ protected override void CopyFrom(ConfigurationBase source) /// The reprocessing configuration. public static ReprocessingConfiguration Load() { - return Load(ConfigurationSection.DefaultSectionName); + return Load(DefaultSectionName); } /// @@ -89,7 +95,7 @@ public static ReprocessingConfiguration Load(string sectionName) /// The reprocessing configuration. public static ReprocessingConfiguration Load(System.Configuration.Configuration configuration) { - return Load(configuration, ConfigurationSection.DefaultSectionName); + return Load(configuration, DefaultSectionName); } /// @@ -125,13 +131,13 @@ public static ReprocessingConfiguration Load(IConfiguration configuration, strin ArgumentValidator.EnsureArgumentNotNull(configuration, nameof(configuration)); if (configuration is IConfigurationRoot configurationRoot) { - return new ReprocessingConfigurationReader().Read(configurationRoot, sectionName ?? ConfigurationSection.DefaultSectionName); + return new ReprocessingConfigurationReader().Read(configurationRoot, sectionName ?? DefaultSectionName); } else if (configuration is IConfigurationSection configurationSection) { return new ReprocessingConfigurationReader().Read(configurationSection); } - throw new NotSupportedException("Type of configuration is not supported"); + throw new NotSupportedException("Type of configuration is not supported."); } @@ -145,7 +151,7 @@ public static ReprocessingConfiguration Load(IConfigurationRoot configurationRoo { ArgumentValidator.EnsureArgumentNotNull(configurationRoot, nameof(configurationRoot)); - return new ReprocessingConfigurationReader().Read(configurationRoot, sectionName ?? ConfigurationSection.DefaultSectionName); + return new ReprocessingConfigurationReader().Read(configurationRoot, sectionName ?? DefaultSectionName); } /// @@ -160,8 +166,6 @@ public static ReprocessingConfiguration Load(IConfigurationSection configuration return new ReprocessingConfigurationReader().Read(configurationSection); } - - /// /// Initializes a new instance of the class. /// diff --git a/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfigurationReader.cs b/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfigurationReader.cs index d4d27f99d4..36a553b34d 100644 --- a/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfigurationReader.cs +++ b/Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfigurationReader.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System; using Microsoft.Extensions.Configuration; using Xtensive.Orm.Configuration; @@ -20,7 +24,7 @@ public ReprocessingConfiguration Read(IConfigurationSection configurationSection throw new NotSupportedException(); public ReprocessingConfiguration Read(IConfigurationRoot configurationRoot) => - Read(configurationRoot, ConfigurationSection.DefaultSectionName); + Read(configurationRoot, ReprocessingConfiguration.DefaultSectionName); public ReprocessingConfiguration Read(IConfigurationRoot configurationRoot, string sectionName) { diff --git a/Extensions/Xtensive.Orm.Reprocessing/DomainConfigurationExtensions.cs b/Extensions/Xtensive.Orm.Reprocessing/DomainConfigurationExtensions.cs index f0ddf8fda4..ca17256a8c 100644 --- a/Extensions/Xtensive.Orm.Reprocessing/DomainConfigurationExtensions.cs +++ b/Extensions/Xtensive.Orm.Reprocessing/DomainConfigurationExtensions.cs @@ -1,3 +1,7 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + using Microsoft.Extensions.Configuration; using Xtensive.Orm.Configuration; using Xtensive.Orm.Reprocessing.Configuration; diff --git a/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfiguration.cs b/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfiguration.cs index 1a38c9e447..2ecd46f8cb 100644 --- a/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfiguration.cs +++ b/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfiguration.cs @@ -1,6 +1,6 @@ // Copyright (C) 2011-2024 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Dmitri Maximov // Created: 2011.06.10 @@ -21,8 +21,7 @@ namespace Xtensive.Orm.Security.Configuration public class SecurityConfiguration : ConfigurationBase { /// - /// Default SectionName value: - /// "". + /// Default section in configuration. Used if custom name is not provided. /// public const string DefaultSectionName = "Xtensive.Orm.Security"; @@ -119,14 +118,16 @@ private static SecurityConfiguration GetConfigurationFromSection(ConfigurationSe var hashingService = configurationSection == null ? string.Empty : configurationSection.HashingService.Name; - if (!string.IsNullOrEmpty(hashingService)) + if (!string.IsNullOrEmpty(hashingService)) { result.HashingServiceName = hashingService.ToLowerInvariant(); + } var authenticationService = configurationSection == null ? string.Empty : configurationSection.AuthenticationService.Name; - if (!string.IsNullOrEmpty(authenticationService)) + if (!string.IsNullOrEmpty(authenticationService)) { result.AuthenticationServiceName = authenticationService.ToLowerInvariant(); + } return result; } @@ -148,7 +149,7 @@ public static SecurityConfiguration Load(IConfiguration configuration, string se return Load(configurationSection); } - throw new NotSupportedException("Type of configuration is not supported"); + throw new NotSupportedException("Type of configuration is not supported."); } @@ -163,13 +164,12 @@ public static SecurityConfiguration Load(IConfigurationRoot configurationRoot, s ArgumentValidator.EnsureArgumentNotNull(configurationRoot, nameof(configurationRoot)); var configuration = new NamelessFormatSecurityConfigurationReader().Read(configurationRoot, sectionName ?? DefaultSectionName); - if (configuration != null) + if (configuration != null) { return configuration; + } configuration = new BasedOnNamesFormatSecurityConfigurationReader().Read(configurationRoot, sectionName ?? DefaultSectionName); - if (configuration != null) - return configuration; - return new SecurityConfiguration(true); + return configuration ?? new SecurityConfiguration(true); } /// @@ -182,13 +182,12 @@ public static SecurityConfiguration Load(IConfigurationSection configurationSect ArgumentValidator.EnsureArgumentNotNull(configurationSection, nameof(configurationSection)); var configuration = new NamelessFormatSecurityConfigurationReader().Read(configurationSection); - if (configuration != null) + if (configuration != null) { return configuration; + } configuration = new BasedOnNamesFormatSecurityConfigurationReader().Read(configurationSection); - if (configuration != null) - return configuration; - return new SecurityConfiguration(true); + return configuration ?? new SecurityConfiguration(true); } /// diff --git a/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfigurationReaders.cs b/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfigurationReaders.cs index dfd98f5193..8597af2750 100644 --- a/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfigurationReaders.cs +++ b/Extensions/Xtensive.Orm.Security/Configuration/SecurityConfigurationReaders.cs @@ -1,9 +1,11 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + using System; -using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.Extensions.Configuration; +using Xtensive.Core; using Xtensive.Orm.Configuration; namespace Xtensive.Orm.Security.Configuration @@ -12,16 +14,6 @@ internal sealed class NamelessFormatSecurityConfigurationReader : SecurityConfig { protected override SecurityConfiguration ReadInternal(IConfigurationSection configuration) { - // - // sha1 - // SomeServiceName - // - // or - // "Xtensive.Orm.Security" : { - // "hashingService" :"sha1", - // "authenticationService" : "SomeServiceName" - // } - try { var configAsIs = configuration.Get(); if (configAsIs != null && (configAsIs.AuthenticationServiceName ?? configAsIs.HashingServiceName) != null) { @@ -38,13 +30,10 @@ protected override SecurityConfiguration ReadInternal(IConfigurationSection conf return null; } - var children = configuration.GetChildren().ToList(); - if (!children.Any()) { - return new SecurityConfiguration(true); - } - else { - return null; - } + var children = configuration.GetChildren(); + return !children.Any() + ? new SecurityConfiguration(true) + : null; } } @@ -79,10 +68,13 @@ protected override SecurityConfiguration ReadInternal(IConfigurationSection conf } if ((hashingServiceName ?? authenticationServiceName) != null) { var securityConfiguration = new SecurityConfiguration(true); - if (!string.IsNullOrEmpty(hashingServiceName)) + if (!hashingServiceName.IsNullOrEmpty()) { securityConfiguration.HashingServiceName = hashingServiceName.ToLowerInvariant(); - if (!string.IsNullOrEmpty(authenticationServiceName)) + } + + if (!authenticationServiceName.IsNullOrEmpty()) { securityConfiguration.AuthenticationServiceName = authenticationServiceName.ToLowerInvariant(); + } return securityConfiguration; } diff --git a/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs b/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs index 46367fc1d9..573c530650 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/DomainConfiguration.cs @@ -9,9 +9,7 @@ using System.Linq; using JetBrains.Annotations; using Microsoft.Extensions.Configuration; -using Xtensive.Collections; using Xtensive.Core; -using Xtensive.Orm.Configuration.Internals; using Xtensive.Orm.Internals; using ConfigurationSection = Xtensive.Orm.Configuration.Elements.ConfigurationSection; @@ -19,7 +17,7 @@ namespace Xtensive.Orm.Configuration { /// /// The configuration of the . - /// + /// [Serializable] public class DomainConfiguration : ConfigurationBase { diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Internals/ExtensionConfigurationCollection.cs b/Orm/Xtensive.Orm/Orm/Configuration/ExtensionConfigurationCollection.cs similarity index 94% rename from Orm/Xtensive.Orm/Orm/Configuration/Internals/ExtensionConfigurationCollection.cs rename to Orm/Xtensive.Orm/Orm/Configuration/ExtensionConfigurationCollection.cs index 193953843c..ec6fee1c60 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Internals/ExtensionConfigurationCollection.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/ExtensionConfigurationCollection.cs @@ -1,16 +1,18 @@ +// Copyright (C) 2024 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Xtensive.Core; namespace Xtensive.Orm.Configuration { /// - /// Default implementation (lockable). + /// Collection of configurations of extensions. /// [Serializable] public sealed class ExtensionConfigurationCollection : LockableBase, diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Internals/ConfigurationSectionExtensions.cs b/Orm/Xtensive.Orm/Orm/Configuration/Internals/ConfigurationSectionExtensions.cs index 4e5844ddfe..35f4c1d3e5 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Internals/ConfigurationSectionExtensions.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Internals/ConfigurationSectionExtensions.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.Configuration; using Xtensive.Collections; -namespace Xtensive.Orm.Configuration.Internals +namespace Xtensive.Orm.Configuration { internal static class ConfigurationSectionExtensions { diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Internals/DomainConfigurationReaders.cs b/Orm/Xtensive.Orm/Orm/Configuration/Internals/DomainConfigurationReaders.cs index 32e9b99a66..73af7f4711 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Internals/DomainConfigurationReaders.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Internals/DomainConfigurationReaders.cs @@ -2,7 +2,6 @@ // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. - using System; using System.Collections.Generic; using System.Linq; @@ -10,7 +9,7 @@ using Xtensive.Core; using Xtensive.Orm.Configuration.Options; -namespace Xtensive.Orm.Configuration.Internals +namespace Xtensive.Orm.Configuration { internal sealed class XmlToDomainConfigurationReader : DomainConfigurationReader { @@ -74,8 +73,10 @@ protected override void ProcessTypes(IConfigurationSection typesSection, DomainC return; } if (TryProcessTypeRegistrationsWithAttributes(typesSection, domainConfigurationOptions) - || TryProcessTypeRegistrationsWithNodes(typesSection, domainConfigurationOptions)) + || TryProcessTypeRegistrationsWithNodes(typesSection, domainConfigurationOptions)) { return; + } + domainConfigurationOptions.Types = Array.Empty(); } @@ -198,6 +199,30 @@ protected override void ProcessNamingConvention(IConfigurationSection namingConv internal abstract class DomainConfigurationReader : IConfigurationSectionReader { + protected sealed class ConfigurationParserContext + { + public readonly IConfigurationRoot CurrentConfiguration; + + public readonly IConfigurationSection CurrentSection; + + public readonly string SectionName; + + public readonly IDictionary ConnectionStrings; + + public ConfigurationParserContext(IConfigurationRoot currentConfiguration, string sectionName) + { + CurrentConfiguration = currentConfiguration; + CurrentSection = currentConfiguration.GetSection(sectionName); + ConnectionStrings = currentConfiguration.Get>(); + } + + public ConfigurationParserContext(IConfigurationSection currentSection, IDictionary connectionStrings) + { + CurrentSection = currentSection; + ConnectionStrings = connectionStrings; + } + } + protected const string RuleElementName = "Rule"; protected const string KeyGeneratorElementName = "KeyGenerator"; protected const string OldStyleTypeRegistrationElementName = "Add"; @@ -222,27 +247,27 @@ internal abstract class DomainConfigurationReader : IConfigurationSectionReader< /// /// Gets domain configuration with name "Default" from default section. /// - /// - /// + /// Configration root. + /// DomainConfiguration instance if it was read successfully, otherwise, . public DomainConfiguration Read(IConfigurationRoot configurationRoot) => - Read(configurationRoot, WellKnown.DefaultConfigurationSection, "Default"); + Read(configurationRoot, WellKnown.DefaultConfigurationSection, WellKnown.DefaultDomainConfigurationName); /// /// Gets domain configuration with name "Default" from . /// - /// - /// - /// + /// Configration root + /// Custom section name where domains are placed. + /// DomainConfiguration instance if it was read successfully, otherwise, . public DomainConfiguration Read(IConfigurationRoot configurationRoot, string sectionName) => - Read(configurationRoot, sectionName, "Default"); + Read(configurationRoot, sectionName, WellKnown.DefaultDomainConfigurationName); /// /// Gets domain configuration with given name from . /// - /// - /// - /// - /// + /// Configration root. + /// Custom section name where domains are placed. + /// Name of domain configuration. + /// DomainConfiguration instance if it was read successfully, otherwise, . public DomainConfiguration Read(IConfigurationRoot configurationRoot, string sectionName, string nameOfConfiguration) { var allDomainsSection = configurationRoot.GetSection(sectionName).GetSection(DomainsSectionName); @@ -259,15 +284,43 @@ public DomainConfiguration Read(IConfigurationRoot configurationRoot, string sec return ReadInternal(context); } + /// + /// Gets domain configuration with name "Default" from . + /// + /// Root section where all domain configurations stored, by default + /// DomainConfiguration instance if it was read successfully, otherwise, . public DomainConfiguration Read(IConfigurationSection rootSection) => - Parse(rootSection, "Default", null); + Parse(rootSection, WellKnown.DefaultDomainConfigurationName, null); + /// + /// Gets domain configuration with given name from . + /// + /// Root section where all domain configurations stored, by default + /// Name of domain configuration. + /// DomainConfiguration instance if it was read successfully, otherwise, . public DomainConfiguration Read(IConfigurationSection rootSection, string nameOfConfiguration) => Parse(rootSection, nameOfConfiguration, null); + /// + /// Gets domain configuration with name "Default" from . + /// + /// Root section where all domain configurations stored, by default + /// + /// Connection strings in form of dictionary of strings. Required if connection string alias is used in domain configuration connection settings + /// + /// DomainConfiguration instance if it was read successfully, otherwise, . public DomainConfiguration Parse(IConfigurationSection rootSection, Dictionary connectionStrings) - => Parse(rootSection, "Default", connectionStrings); + => Parse(rootSection, WellKnown.DefaultDomainConfigurationName, connectionStrings); + /// + /// Gets domain configuration with given name from . + /// + /// Root section where all domain configurations stored, by default + /// Name of domain configuration. + /// + /// Connection strings in form of dictionary of strings. Required if connection string alias is used in domain configuration connection settings + /// + /// DomainConfiguration instance if it was read successfully, otherwise, . public DomainConfiguration Parse(IConfigurationSection rootSection, string nameOfConfiguration, Dictionary connectionStrings) { var allDomainsSection = rootSection.GetSection(DomainsSectionName); @@ -342,31 +395,5 @@ protected virtual void ProcessMappingRules(IConfigurationSection mappingRulesSec protected virtual void ProcessSessions(IConfigurationSection sessionsSection, DomainConfigurationOptions domainConfiguratonOptions) { } - - - } - - internal sealed class ConfigurationParserContext - { - public readonly IConfigurationRoot CurrentConfiguration; - - public readonly IConfigurationSection CurrentSection; - - public readonly string SectionName; - - public readonly IDictionary ConnectionStrings; - - public ConfigurationParserContext(IConfigurationRoot currentConfiguration, string sectionName) - { - CurrentConfiguration = currentConfiguration; - CurrentSection = currentConfiguration.GetSection(sectionName); - ConnectionStrings = currentConfiguration.Get>(); - } - - public ConfigurationParserContext(IConfigurationSection currentSection, IDictionary connectionStrings) - { - CurrentSection = currentSection; - ConnectionStrings = connectionStrings; - } } -} +} \ No newline at end of file diff --git a/Orm/Xtensive.Orm/Orm/Configuration/Internals/LoggingConfigurationReader.cs b/Orm/Xtensive.Orm/Orm/Configuration/Internals/LoggingConfigurationReader.cs index c583720e9e..6308dc9fde 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/Internals/LoggingConfigurationReader.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/Internals/LoggingConfigurationReader.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.Configuration; using Xtensive.Core; -namespace Xtensive.Orm.Configuration.Internals +namespace Xtensive.Orm.Configuration { internal sealed class LoggingConfigurationReader : IConfigurationSectionReader { @@ -33,13 +33,17 @@ public LoggingConfiguration Read(IConfigurationRoot configurationRoot, string se public LoggingConfiguration Read(IConfigurationRoot configurationRoot) { ArgumentValidator.EnsureArgumentNotNull(configurationRoot, nameof(configurationRoot)); + return Read(configurationRoot.GetSection(WellKnown.DefaultConfigurationSection)); } /// public LoggingConfiguration Read(IConfigurationRoot configurationRoot, string sectionName, string nameOfConfiguration) { - throw new NotSupportedException(); + ArgumentValidator.EnsureArgumentNotNull(configurationRoot, nameof(configurationRoot)); + ArgumentValidator.EnsureArgumentNotNullOrEmpty(sectionName, nameof(sectionName)); + + return Read(configurationRoot.GetSection(sectionName)); } /// diff --git a/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs b/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs index 880c88ada6..ed8e7cbaac 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/LoggingConfiguration.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2013-2020 Xtensive LLC. +// Copyright (C) 2013-2024 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Alexey Kulakov @@ -10,7 +10,6 @@ using System.Linq; using Microsoft.Extensions.Configuration; using Xtensive.Core; -using Xtensive.Orm.Configuration.Internals; using ConfigurationSection = Xtensive.Orm.Configuration.Elements.ConfigurationSection; namespace Xtensive.Orm.Configuration diff --git a/Orm/Xtensive.Orm/Orm/WellKnown.cs b/Orm/Xtensive.Orm/Orm/WellKnown.cs index 1df1e4de33..0e9e7ef5b3 100644 --- a/Orm/Xtensive.Orm/Orm/WellKnown.cs +++ b/Orm/Xtensive.Orm/Orm/WellKnown.cs @@ -32,6 +32,11 @@ public static partial class WellKnown /// public const string DefaultConfigurationSection = "Xtensive.Orm"; + /// + /// Default name of domain. + /// + public const string DefaultDomainConfigurationName = "Default"; + /// /// Name of the field. /// From b38fbc49107c4f029f161dade0e6f9a55d8240f3 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Tue, 15 Oct 2024 18:48:31 +0500 Subject: [PATCH 31/32] Improved ReadMe files of certain extensions --- .../NugetContent/ReadMe.md | 55 ++++++++++--------- .../NugetContent/ReadMe.md | 51 +++++++++-------- .../NugetContent/ReadMe.md | 55 +++++++++++-------- 3 files changed, 89 insertions(+), 72 deletions(-) diff --git a/Extensions/Xtensive.Orm.Localization/NugetContent/ReadMe.md b/Extensions/Xtensive.Orm.Localization/NugetContent/ReadMe.md index 79579ed074..58ec4541c9 100644 --- a/Extensions/Xtensive.Orm.Localization/NugetContent/ReadMe.md +++ b/Extensions/Xtensive.Orm.Localization/NugetContent/ReadMe.md @@ -115,7 +115,7 @@ Examples of how to configure extension Following examples show different ways to configure extension in configuration files of various types. -**Example #1** Confugure in App.config/Web.config +**Example #1** Confugure default culture in App.config/Web.config ```xml @@ -132,20 +132,20 @@ Following examples show different ways to configure extension in configuration f ``` -Such configuration is only compatible with System.Configuration.ConfigurationManager. -If project still supports such configurations then Localization configuration will be read automatically when it needed to be read. +Such configuration is usually read with ```System.Configuration.ConfigurationManager```. +If project still supports such configurations then Localization configuration will be read automatically when it needs to be read. Sometimes a work-around is needed to read such configuration, for more read Example #2 and Example #3 **Example #2** Reading old-style configuration of an assembly in NET 5 and newer. Due to new architecture without AppDomain (which among the other things was in charge of gathering configuration files of loaded assemblies -as it would be one configuration file) System.Configuration.ConfigurationManager now reads only configuration file of actual executable, loaded +as it would be one configuration file) ```System.Configuration.ConfigurationManager``` now reads only configuration file of actual executable, loaded assemblies' configuration files stay unreachable by default, though there is need to read some data from them. A great example is test projects which are usually get loaded by test runner executable, and the only configuration accessible in this case is test runner one. -Extra step is required to read configuration files in such cases. Thankfully ConfigurationManager has methods to get access to assemblies' configurations. +Extra step is required to read configuration files in such cases. Thankfully, ```ConfigurationManager``` has methods to get access to assemblies' configuration files. To get access to an assembly configuration file it should be opened explicitly by @@ -165,18 +165,16 @@ The instance returned from ```OpenExeConfiguration``` provides access to section domainConfiguration.ExtensionConfigurations.Set(localizationConfig); ``` -The ```domainConfiguration.ExtensionConfigurations``` is a new unified place from which an extension will try to get its configuration +The ```domainConfiguration.ExtensionConfigurations``` is a new unified place from which the extension will try to get its configuration instead of calling default parameterless ```Load()``` method, which has not a lot of sense now, though the method is kept as a second source for backwards compatibility. -For more convenience, DomainConfiguration extensions are provided, which make code more neat and clear. +For more convenience, ```DomainConfiguration``` extensions are provided, which make code neater. For instance, ```csharp var configuration = ConfigurationManager.OpenExeConfiguration(typeof(SomeTypeInConfigOwnerAssembly).Assembly.Location); - var domainConfiguration = DomainConfiguration.Load(configuration); - // the extension hides getting configuration with LocalizationConfiguration.Load(configuration) // and also putting it to ExtensionConfigurations collection. domainConfiguration.ConfigureLocalizationExtension(configuration); @@ -189,7 +187,7 @@ Custom section names are also supported if for some reason default section name If for some reason there is need to keep the old-style configuration then there is a work-around as well. Static configuration manager provides method ```OpenMappedExeConfiguration()``` which allows to get -any *.config file as ```System.Configuration.Configuration``` instance. For example +any *.config file as ```System.Configuration.Configuration``` instance. For example, ```csharp ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap(); @@ -198,9 +196,7 @@ any *.config file as ```System.Configuration.Configuration``` instance. For exam ``` After that, as in previous example, the instance can be passed to ```Load``` method of ```LocalizationConfiguration``` to read extension configuration -and later put it to ```DomainConfiguration.ExtensionConfigurations```. -After ```System.Configuration.Configuration``` instance is provided it is possible to pass it into Load method of different DataObjects.Net configurations, -including ```LocalizationConfiguration```. Then put localization configuration to ```DomainConfiguration.ExtensionConfigurations``` collection. +and later put it to ```DomainConfiguration.ExtensionConfigurations``` ```csharp var localizationConfiguration = LocalizationConfiguration.Load(configuration); @@ -208,7 +204,7 @@ including ```LocalizationConfiguration```. Then put localization configuration t domainConfiguration.ExtensionConfigurations.Set(localizationConfiguration); ``` -or to extension method +Extension usage will look like ```csharp domainConfiguration.ConfigureLocalizationExtension(configuration); @@ -220,7 +216,7 @@ or to extension method This API allows to have configurations in various forms including JSON and XML formats. Loading of such files may differ depending on .NET version, check Microsoft manuals for instructions. -Allowed Json and Xml configuration definition look like below +Allowed JSON and XML configuration definition look like below ```xml @@ -238,14 +234,13 @@ Allowed Json and Xml configuration definition look like below } ``` -The API has certain issues with Xml elements with attributes so it is recommended to use +The API has certain issues with XML elements with attributes so it is recommended to use more up-to-date attributeless nodes. -For JSON it is pretty clear. +For JSON it is pretty clear, almost averyone knows its format. -```LocalizationConfiguration.Load``` method can accept different types of abstractions from the -API, including -- ```Microsoft.Extensions.Configuration.IConfiguration```, -- ```Microsoft.Extensions.Configuration.IConfigurationRoot``` +```LocalizationConfiguration.Load``` method can accept different types of abstractions from the API, including +- ```Microsoft.Extensions.Configuration.IConfiguration```; +- ```Microsoft.Extensions.Configuration.IConfigurationRoot```; - ```Microsoft.Extensions.Configuration.IConfigurationSection```. Loading of configuration may look like @@ -254,19 +249,23 @@ Loading of configuration may look like var app = builder.Build(); + //... + // tries to load from default section "Xtensive.Orm.Localization" var localizationConfig = LocalizationConfiguration.Load(app.Configuration); domainConfiguration.ExtensionConfigurations.Set(localizationConfig); ``` -or, with use of extension +or, with use of extension, like ```csharp var app = builder.Build(); + //... + // tries to load from default section "Xtensive.Orm.Localization" // and additionally adds Xtensive.Orm.Localization assembly to domain types. @@ -301,17 +300,17 @@ Loading of configuration may look like var app = builder.Build(); + //... + var localizationConfig = LocalizationConfiguration.Load(app.Configuration, "Orm.Localization"); domainConfiguration.ExtensionConfigurations.Set(localizationConfig); ``` -or with use of extension +or, with use of extension, like ```csharp - var app = builder.Build(); - domainConfiguration.ConfigureLocalizationExtension(app.Configuration, "Orm.Localization"); ``` @@ -348,6 +347,8 @@ Then section must be provided manually, code may look like var app = builder.Build(); + //... + var configurationRoot = app.Configuration; var extensionsGroupSection = configurationRoot.GetSection("Orm.Extensions"); var localizationSection = extensionsGroupSection.GetSection("Xtensive.Orm.Localization"); @@ -356,12 +357,14 @@ Then section must be provided manually, code may look like domainConfiguration.ExtensionConfigurations.Set(localizationConfig); ``` -or with use of extension method +or, with use of extension method, like ```csharp var app = builder.Build(); + //... + var configurationRoot = app.Configuration; var extensionsGroupSection = configurationRoot.GetSection("Orm.Extensions"); var localizationSection = extensionsGroupSection.GetSection("Xtensive.Orm.Localization"); diff --git a/Extensions/Xtensive.Orm.Reprocessing/NugetContent/ReadMe.md b/Extensions/Xtensive.Orm.Reprocessing/NugetContent/ReadMe.md index 96bbcb134a..678a948360 100644 --- a/Extensions/Xtensive.Orm.Reprocessing/NugetContent/ReadMe.md +++ b/Extensions/Xtensive.Orm.Reprocessing/NugetContent/ReadMe.md @@ -63,20 +63,20 @@ Following examples show different ways to configure extension in configuration f ``` -Such configuration is only compatible with System.Configuration.ConfigurationManager. -If project still supports such configurations then Reprocessing configuration will be read automatically when it needed to be read. +Such configuration is usually read with ```System.Configuration.ConfigurationManager```. +If project still supports such configurations then Reprocessing configuration will be read automatically when it needs to be read. Sometimes a work-around is needed to read such configuration, for more read Example #2 and Example #3 **Example #2** Reading old-style configuration of an assembly in NET 5 and newer. Due to new architecture without AppDomain (which among the other things was in charge of gathering configuration files of loaded assemblies -as it would be one configuration file) System.Configuration.ConfigurationManager now reads only configuration file of actual executable, loaded +as it would be one configuration file) ```System.Configuration.ConfigurationManager``` now reads only configuration file of actual executable, loaded assemblies' configuration files stay unreachable by default, though there is need to read some data from them. A great example is test projects which are usually get loaded by test runner executable, and the only configuration accessible in this case is test runner one. -Extra step is required to read configuration files in such cases. Thankfully ConfigurationManager has methods to get access to assemblies' configurations. +Extra step is required to read configuration files in such cases. Thankfully, ```ConfigurationManager``` has methods to get access to assemblies' configuration files. To get access to an assembly configuration file it should be opened explicitly by @@ -96,18 +96,16 @@ The instance returned from ```OpenExeConfiguration``` provides access to section domainConfiguration.ExtensionConfigurations.Set(reprocessingConfig); ``` -The ```domainConfiguration.ExtensionConfigurations``` is a new unified place from which an extension will try to get its configuration +The ```domainConfiguration.ExtensionConfigurations``` is a new unified place from which the extension will try to get its configuration instead of calling default parameterless ```Load()``` method, which has not a lot of sense now, though the method is kept as a second source for backwards compatibility. -For more convenience, DomainConfiguration extensions are provided, which make code more neat and clear. +For more convenience, ```DomainConfiguration``` extensions are provided, which make code more neater. For instance, ```csharp var configuration = ConfigurationManager.OpenExeConfiguration(typeof(SomeTypeInConfigOwnerAssembly).Assembly.Location); - var domainConfiguration = DomainConfiguration.Load(configuration); - // the extension hides getting configuration with ReprocessingConfiguration.Load(configuration) // and also putting it to ExtensionConfigurations collection. domainConfiguration.ConfigureReprocessingExtension(configuration); @@ -120,7 +118,7 @@ Custom section names are also supported if for some reason default section name If for some reason there is need to keep the old-style configuration then there is a work-around as well. Static configuration manager provides method ```OpenMappedExeConfiguration()``` which allows to get -any *.config file as ```System.Configuration.Configuration``` instance. For example +any *.config file as ```System.Configuration.Configuration``` instance. For example, ```csharp ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap(); @@ -129,9 +127,7 @@ any *.config file as ```System.Configuration.Configuration``` instance. For exam ``` After that, as in previous example, the instance can be passed to ```Load``` method of ```ReprocessingConfiguration``` to read extension configuration -and later put it to ```DomainConfiguration.ExtensionConfigurations```. -After ```System.Configuration.Configuration``` instance is provided it is possible to pass it into Load method of different DataObjects.Net configurations, -including ```ReprocessingConfiguration```. Then put reprocessing configuration to ```DomainConfiguration.ExtensionConfigurations``` collection. +and later put it to ```DomainConfiguration.ExtensionConfigurations``` ```csharp var reprocessingConfiguration = ReprocessingConfiguration.Load(configuration); @@ -139,7 +135,7 @@ including ```ReprocessingConfiguration```. Then put reprocessing configuration t domainConfiguration.ExtensionConfigurations.Set(reprocessingConfiguration); ``` -or to extension method +Extension usage will look like ```csharp domainConfiguration.ConfigureReprocessingExtension(configuration); @@ -151,7 +147,7 @@ or to extension method This API allows to have configurations in various forms including JSON and XML formats. Loading of such files may differ depending on .NET version, check Microsoft manuals for instructions. -Allowed Json and Xml configuration definition look like below +Allowed JSON and XML configuration definition look like below ```xml @@ -173,12 +169,11 @@ Allowed Json and Xml configuration definition look like below The API has certain issues with Xml elements with attributes so it is recommended to use more up-to-date attributeless nodes. -For JSON it is pretty clear. +For JSON it is pretty clear, almost averyone knows its format. -```ReprocessingConfiguration.Load``` method can accept different types of abstractions from the -API, including -- ```Microsoft.Extensions.Configuration.IConfiguration```, -- ```Microsoft.Extensions.Configuration.IConfigurationRoot``` +```ReprocessingConfiguration.Load``` method can accept different types of abstractions from the API, including +- ```Microsoft.Extensions.Configuration.IConfiguration```; +- ```Microsoft.Extensions.Configuration.IConfigurationRoot```; - ```Microsoft.Extensions.Configuration.IConfigurationSection```. Loading of configuration may look like @@ -187,19 +182,23 @@ Loading of configuration may look like var app = builder.Build(); + //... + // tries to load from default section "Xtensive.Orm.Reprocessing" var reprocessingConfig = ReprocessingConfiguration.Load(app.Configuration); domainConfiguration.ExtensionConfigurations.Set(reprocessingConfig); ``` -or, with use of extension +or, with use of extension, like ```csharp var app = builder.Build(); + //... + // tries to load from default section "Xtensive.Orm.Reprocessing" // and put it into domainConfiguration.ExtensionConfigurations @@ -236,17 +235,21 @@ Loading of configuration may look like var app = builder.Build(); + //... + var reprocessingConfig = ReprocessingConfiguration.Load(app.Configuration, "Orm.Reprocessing"); domainConfiguration.ExtensionConfigurations.Set(reprocessingConfig); ``` -or with use of extension +or, with use of extension, like ```csharp var app = builder.Build(); + //... + domainConfiguration.ConfigureReprocessingExtension(app.Configuration, "Orm.Reprocessing"); ``` @@ -285,6 +288,8 @@ Then section must be provided manually, code may look like var app = builder.Build(); + //... + var configurationRoot = app.Configuration; var extensionsGroupSection = configurationRoot.GetSection("Orm.Extensions"); var reprocessingSection = extensionsGroupSection.GetSection("Xtensive.Orm.Reprocessing"); @@ -294,12 +299,14 @@ Then section must be provided manually, code may look like domainConfiguration.ExtensionConfigurations.Set(reprocessingConfig); ``` -or with use of extension method +or, with use of extension method, like ```csharp var app = builder.Build(); + //... + var configurationRoot = app.Configuration; var extensionsGroupSection = configurationRoot.GetSection("Orm.Extensions"); var reprocessingSection = extensionsGroupSection.GetSection("Xtensive.Orm.Reprocessing"); diff --git a/Extensions/Xtensive.Orm.Security/NugetContent/ReadMe.md b/Extensions/Xtensive.Orm.Security/NugetContent/ReadMe.md index 426919e90b..2b5f0f72d8 100644 --- a/Extensions/Xtensive.Orm.Security/NugetContent/ReadMe.md +++ b/Extensions/Xtensive.Orm.Security/NugetContent/ReadMe.md @@ -328,12 +328,12 @@ there are some cases which may require usage of different API or work-around cer **Example #1** Reading old-style configuration of an assembly in NET 5 and newer. Due to new architecture without AppDomain (which among the other things was in charge of gathering configuration files of loaded assemblies -as it would be one configuration file) System.Configuration.ConfigurationManager now reads only configuration file of actual executable, loaded +as it would be one configuration file) ```System.Configuration.ConfigurationManager``` now reads only configuration file of actual executable, loaded assemblies' configuration files stay unreachable by default, though there is need to read some data from them. A great example is test projects which are usually get loaded by test runner executable, and the only configuration accessible in this case is test runner one. -Extra step is required to read configuration files in such cases. Thankfully ConfigurationManager has methods to get access to assemblies' configurations. +Extra step is required to read configuration files in such cases. Thankfully, ```ConfigurationManager``` has methods to get access to assemblies' configurations. To get access to an assembly configuration file it should be opened explicitly by @@ -353,11 +353,11 @@ The instance returned from ```OpenExeConfiguration``` provides access to section domainConfiguration.ExtensionConfigurations.Set(securityConfig); ``` -The ```domainConfiguration.ExtensionConfigurations``` is a new unified place from which an extension will try to get its configuration +The ```domainConfiguration.ExtensionConfigurations``` is a new unified place from which the extension will try to get its configuration instead of calling default parameterless ```Load()``` method, which has not a lot of sense now, though the method is kept as a second source for backwards compatibility. -For more convenience, DomainConfiguration extensions are provided, which make code more neat and clear. +For more convenience, ```DomainConfiguration``` extensions are provided, which make code more neater. For instance, ```csharp @@ -376,11 +376,11 @@ so even if you miss registration but called extension method required types of S Custom section names are also supported if for some reason default section name is not used. -**Example #3** Reading old-style configuration of an assembly in a project that uses appsettings.json file. +**Example #2** Reading old-style configuration of an assembly in a project that uses appsettings.json file. If for some reason there is need to keep the old-style configuration then there is a work-around as well. Static configuration manager provides method ```OpenMappedExeConfiguration()``` which allows to get access to -any *.config file as ```System.Configuration.Configuration``` instance. For example +any *.config file as ```System.Configuration.Configuration``` instance. For example, ```csharp ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap(); @@ -389,9 +389,7 @@ any *.config file as ```System.Configuration.Configuration``` instance. For exam ``` After that, as in previous example, the instance can be passed to ```Load``` method of ```SecurityConfiguration``` to read extension configuration -and later put it to ```DomainConfiguration.ExtensionConfigurations```. -After ```System.Configuration.Configuration``` instance is providedit is possible to pass it into Load method of different DataObjects.Net configurations, -including ```SecurityConfiguration```. Then put security configuration to ```DomainConfiguration.ExtensionConfigurations``` collection. +and later put it to ```DomainConfiguration.ExtensionConfigurations``` ```csharp var securityConfiguration = SecurityConfiguration.Load(configuration); @@ -399,14 +397,14 @@ including ```SecurityConfiguration```. Then put security configuration to ```Dom domainConfiguration.ExtensionConfigurations.Set(securityConfiguration); ``` -or to extension method +Extension usage will look like ```csharp domainConfiguration.ConfigureSecurityExtension(configuration); ``` -**Example #4** Configure using Microsoft.Extensions.Configuration API. +**Example #3** Configure using Microsoft.Extensions.Configuration API. This API allows to have configurations in various forms including JSON and XML formats. Loading of such files may differ depending on .NET version, check Microsoft manuals for instructions. @@ -431,14 +429,13 @@ Allowed JSON and XML configuration definition look like below } ``` -The API has certain issues with Xml elements with attributes so it is recommended to use +The API has certain issues with XML elements with attributes so it is recommended to use more up-to-date attributeless nodes. -For JSON it is pretty clear. +For JSON it is pretty clear, almost averyone knows its format. -```SecurityConfiguration.Load``` method can accept different types of abstractions from the -API, including -- ```Microsoft.Extensions.Configuration.IConfiguration```, -- ```Microsoft.Extensions.Configuration.IConfigurationRoot``` +```SecurityConfiguration.Load``` method can accept different types of abstractions from the API, including +- ```Microsoft.Extensions.Configuration.IConfiguration```; +- ```Microsoft.Extensions.Configuration.IConfigurationRoot```; - ```Microsoft.Extensions.Configuration.IConfigurationSection```. Loading of configuration may look like @@ -447,19 +444,23 @@ Loading of configuration may look like var app = builder.Build(); + //... + // tries to load from default section "Xtensive.Orm.Security" var securityConfig = SecurityConfiguration.Load(app.Configuration); domainConfiguration.ExtensionConfigurations.Set(securityConfig); ``` -or, with use of extension +or, with use of extension, like ```csharp var app = builder.Build(); + //... + // Tries to load from default section "Xtensive.Orm.Security" // and put it into domainConfiguration.ExtensionConfigurations. // Additionally, registers types of "Xtensive.Orm.Security" assembly. @@ -469,7 +470,7 @@ or, with use of extension -**Example #5** Configure using Microsoft.Extensions.Configuration API from section with non-default name. +**Example #4** Configure using Microsoft.Extensions.Configuration API from section with non-default name. For configurations like @@ -493,25 +494,27 @@ For configurations like Loading of configuration may look like ```csharp - var app = builder.Build(); + //... + var securityConfig = SecurityConfiguration.Load(app.Configuration, "Orm.Security"); domainConfiguration.ExtensionConfigurations.Set(securityConfig); ``` -or with use of extension +or, with use of extension, like ```csharp - var app = builder.Build(); + //... + domainConfiguration.ConfigureSecurityExtension(app.Configuration, "Orm.Security"); ``` -**Example #6** Configure using Microsoft.Extensions.Configuration API from sub-section deeper in section tree. +**Example #5** Configure using Microsoft.Extensions.Configuration API from sub-section deeper in section tree. If for some reason extension configuration should be moved deeper in section tree like something below @@ -545,6 +548,8 @@ Then section must be provided manually, code may look like var app = builder.Build(); + //... + var configurationRoot = app.Configuration; var extensionsGroupSection = configurationRoot.GetSection("Orm.Extensions"); var securitySection = extensionsGroupSection.GetSection("Xtensive.Orm.Security"); @@ -554,12 +559,14 @@ Then section must be provided manually, code may look like domainConfiguration.ExtensionConfigurations.Set(securityConfig); ``` -or with use of extension method +or, with use of extension method, like ```csharp var app = builder.Build(); + //... + var configurationRoot = app.Configuration; var extensionsGroupSection = configurationRoot.GetSection("Orm.Extensions"); var securitySection = extensionsGroupSection.GetSection("Xtensive.Orm.Security"); From b26102819fe3f7ff60021fa4718d591e1b8d8593 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 17 Oct 2024 18:35:11 +0500 Subject: [PATCH 32/32] Improve changelog --- ChangeLog/7.1.2_dev.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ChangeLog/7.1.2_dev.txt b/ChangeLog/7.1.2_dev.txt index 78b15d4fc6..68137d651a 100644 --- a/ChangeLog/7.1.2_dev.txt +++ b/ChangeLog/7.1.2_dev.txt @@ -1 +1,9 @@ -[main] Addressed issue when cycles in Entity dependency graph were not detected \ No newline at end of file +[main] Addressed issue when cycles in Entity dependency graph were not detected +[main] Intoduced DomainConfuguration.ExtensionConfigurations as unified configuration storage for extensions' configurations +[main] DomainConfiguration.Load() method now has overloads which gets abstractions from Microsoft.Extensions.Configuration API +[localization] LocalizationConfiguration.Load() method now has overloads which gets abstractions from Microsoft.Extensions.Configuration API +[localization] ConfigureLocalizationExtension() extensions for DomainConfiguration are added, check ReadMe/documentation for examples of usage +[reprocessing] ReprocessingConfiguration.Load() method now has overloads which gets abstractions from Microsoft.Extensions.Configuration API +[reprocessing] ConfigureReprocessingExtension() extensions for DomainConfiguration are added, check ReadMe/documentation for examples of usage +[security] SecurityConfiguration.Load() method now has overloads which gets abstractions from Microsoft.Extensions.Configuration API +[security] ConfigureSecurityExtension() extensions for DomainConfiguration are added, check ReadMe/documentation for examples of usage \ No newline at end of file