Skip to content

Commit 496f968

Browse files
committed
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
1 parent b6c3adf commit 496f968

15 files changed

Lines changed: 762 additions & 55 deletions

File tree

Extensions/Xtensive.Orm.Localization/Configuration/LocalizationConfiguration.cs

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,43 @@ namespace Xtensive.Orm.Localization.Configuration
1919
/// The configuration of the localization extension.
2020
/// </summary>
2121
[Serializable]
22-
public class LocalizationConfiguration
22+
public class LocalizationConfiguration : ConfigurationBase
2323
{
24-
private class LocalizationOptions
25-
{
26-
public string DefaultCulture { get; set; } = null;
27-
}
28-
2924
/// <summary>
3025
/// Default SectionName value:
3126
/// "<see langword="Xtensive.Orm.Localization" />".
3227
/// </summary>
3328
public const string DefaultSectionName = "Xtensive.Orm.Localization";
3429

35-
private const string DefaultCultureElementName = "DefaultCulture";
36-
private const string CultureNameAttributeName = "name";
30+
private CultureInfo culture;
3731

3832
/// <summary>
3933
/// Gets or sets the default culture.
4034
/// </summary>
4135
/// <value>The default culture.</value>
42-
public CultureInfo DefaultCulture { get; internal set; }
36+
public CultureInfo DefaultCulture {
37+
get => culture;
38+
internal set {
39+
EnsureNotLocked();
40+
culture = value;
41+
}
42+
}
43+
44+
/// <inheritdoc />
45+
protected override LocalizationConfiguration CreateClone() => new LocalizationConfiguration();
46+
47+
/// <inheritdoc />
48+
protected override void CopyFrom(ConfigurationBase source)
49+
{
50+
base.CopyFrom(source);
51+
52+
var nativeConfig = source as LocalizationConfiguration;
53+
nativeConfig.DefaultCulture = DefaultCulture;
54+
}
55+
56+
/// <inheritdoc />
57+
public override LocalizationConfiguration Clone() => (LocalizationConfiguration) base.Clone();
58+
4359

4460
/// <summary>
4561
/// Loads the <see cref="LocalizationConfiguration"/>
@@ -115,6 +131,30 @@ private static LocalizationConfiguration GetConfigurationFromSection(Configurati
115131
return result;
116132
}
117133

134+
/// <summary>
135+
/// Loads <see cref="LocalizationConfiguration"/> from given configuration section of <paramref name="configurationRoot"/>.
136+
/// If section name is not provided <see cref="LocalizationConfiguration.DefaultSectionName"/> is used.
137+
/// </summary>
138+
/// <param name="configuration"><see cref="IConfiguration"/> of sections.</param>
139+
/// <param name="sectionName">Custom section name to load from.</param>
140+
/// <returns>Loaded configuration or default configuration if loading failed for some reason.</returns>
141+
public static LocalizationConfiguration Load(IConfiguration configuration, string sectionName = null)
142+
{
143+
ArgumentValidator.EnsureArgumentNotNull(configuration, nameof(configuration));
144+
145+
if (configuration is IConfigurationRoot configurationRoot)
146+
return new LocalizationConfigurationReader().Read(configurationRoot, sectionName ?? DefaultSectionName);
147+
else if (configuration is IConfigurationSection configurationSection) {
148+
if (sectionName.IsNullOrEmpty())
149+
return new LocalizationConfigurationReader().Read(configurationSection);
150+
else {
151+
return new LocalizationConfigurationReader().Read(configurationSection.GetSection(sectionName));
152+
}
153+
}
154+
155+
throw new NotSupportedException("Type of configuration is not supported");
156+
}
157+
118158
/// <summary>
119159
/// Loads <see cref="LocalizationConfiguration"/> from given configuration section.
120160
/// </summary>
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
// Copyright (C) 2024 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
4+
5+
using Microsoft.Extensions.Configuration;
6+
using Xtensive.Orm.Configuration;
7+
using Xtensive.Orm.Localization.Configuration;
8+
9+
namespace Xtensive.Orm.Localization
10+
{
11+
/// <summary>
12+
/// Contains extensions for DomainConfiguration that help to configure the extension.
13+
/// </summary>
14+
public static class DomainConfugurationLocalizationExtensions
15+
{
16+
/// <summary>
17+
/// Loads configuration by calling <see cref="LocalizationConfiguration.Load()"/>
18+
/// and uses it to configure the extension.
19+
/// </summary>
20+
/// <param name="domainConfiguration">Domain configuration.</param>
21+
/// <returns><paramref name="domainConfiguration"/> instance with configured extension.</returns>
22+
public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration)
23+
=> ConfigureLocalizationExtension(domainConfiguration, LocalizationConfiguration.Load());
24+
25+
/// <summary>
26+
/// Loads configuration by calling <see cref="LocalizationConfiguration.Load(string)"/>
27+
/// and uses it to configure the extension.
28+
/// </summary>
29+
/// <param name="domainConfiguration">Domain configuration.</param>
30+
/// <param name="configurationSectionName">Section name.</param>
31+
/// <returns><paramref name="domainConfiguration"/> instance with configured extension.</returns>
32+
public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration,
33+
string configurationSectionName) =>
34+
ConfigureLocalizationExtension(domainConfiguration, LocalizationConfiguration.Load(configurationSectionName));
35+
36+
/// <summary>
37+
/// Loads configuration by calling <see cref="LocalizationConfiguration.Load(System.Configuration.Configuration)"/>
38+
/// and uses it to configure the extension.
39+
/// </summary>
40+
/// <param name="domainConfiguration">Domain configuration.</param>
41+
/// <param name="configuration">Configuration to load from.</param>
42+
/// <returns><paramref name="domainConfiguration"/> instance with configured extension.</returns>
43+
public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration,
44+
System.Configuration.Configuration configuration) =>
45+
ConfigureLocalizationExtension(domainConfiguration, LocalizationConfiguration.Load(configuration));
46+
47+
/// <summary>
48+
/// Loads configuration by calling <see cref="LocalizationConfiguration.Load(System.Configuration.Configuration)"/>
49+
/// and uses it to configure the extension.
50+
/// </summary>
51+
/// <param name="domainConfiguration">Domain configuration.</param>
52+
/// <param name="configuration">Configuration to load from.</param>
53+
/// <param name="sectionName">Section in <paramref name="configuration"/></param>
54+
/// <returns><paramref name="domainConfiguration"/> instance with configured extension.</returns>
55+
public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration,
56+
System.Configuration.Configuration configuration, string sectionName) =>
57+
ConfigureLocalizationExtension(domainConfiguration, LocalizationConfiguration.Load(configuration, sectionName));
58+
59+
/// <summary>
60+
/// Loads configuration by calling <see cref="LocalizationConfiguration.Load(IConfigurationRoot, string)"/>
61+
/// and uses it to configure the extension.
62+
/// </summary>
63+
/// <param name="domainConfiguration">Domain configuration.</param>
64+
/// <param name="configuration">Configuration to load from.</param>
65+
/// <returns><paramref name="domainConfiguration"/> instance with configured extension.</returns>
66+
public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration,
67+
IConfiguration configuration) =>
68+
ConfigureLocalizationExtension(domainConfiguration, LocalizationConfiguration.Load(configuration));
69+
70+
/// <summary>
71+
/// Loads configuration by calling <see cref="LocalizationConfiguration.Load(IConfigurationRoot, string)"/>
72+
/// and uses it to configure the extension.
73+
/// </summary>
74+
/// <param name="domainConfiguration">Domain configuration.</param>
75+
/// <param name="configuration">Configuration to load from.</param>
76+
/// <param name="sectionName">Section in <paramref name="configuration"/></param>
77+
/// <returns><paramref name="domainConfiguration"/> instance with configured extension.</returns>
78+
public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration,
79+
IConfiguration configuration, string sectionName = null) =>
80+
ConfigureLocalizationExtension(domainConfiguration, LocalizationConfiguration.Load(configuration, sectionName));
81+
82+
/// <summary>
83+
/// Loads configuration by calling <see cref="LocalizationConfiguration.Load(IConfigurationRoot, string)"/>
84+
/// and uses it to configure the extension.
85+
/// </summary>
86+
/// <param name="domainConfiguration">Domain configuration.</param>
87+
/// <param name="configurationRoot">Configuration to load from.</param>
88+
/// <returns><paramref name="domainConfiguration"/> instance with configured extension.</returns>
89+
public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration,
90+
IConfigurationRoot configurationRoot) =>
91+
ConfigureLocalizationExtension(domainConfiguration, LocalizationConfiguration.Load(configurationRoot));
92+
93+
/// <summary>
94+
/// Loads configuration by calling <see cref="LocalizationConfiguration.Load(IConfigurationRoot, string)"/>
95+
/// and uses it to configure the extension.
96+
/// </summary>
97+
/// <param name="domainConfiguration">Domain configuration.</param>
98+
/// <param name="configurationRoot">Configuration to load from.</param>
99+
/// <param name="sectionName">Section in <paramref name="configurationRoot"/></param>
100+
/// <returns><paramref name="domainConfiguration"/> instance with configured extension.</returns>
101+
public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration,
102+
IConfigurationRoot configurationRoot, string sectionName) =>
103+
ConfigureLocalizationExtension(domainConfiguration, LocalizationConfiguration.Load(configurationRoot, sectionName));
104+
105+
/// <summary>
106+
/// Loads configuration by calling <see cref="LocalizationConfiguration.Load(IConfigurationRoot, string)"/>
107+
/// and uses it to configure the extension.
108+
/// </summary>
109+
/// <param name="domainConfiguration">Domain configuration.</param>
110+
/// <param name="configurationSection">Configuration section to load from.</param>
111+
/// <returns><paramref name="domainConfiguration"/> instance with configured extension.</returns>
112+
public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration,
113+
IConfigurationSection configurationSection) =>
114+
ConfigureLocalizationExtension(domainConfiguration, LocalizationConfiguration.Load(configurationSection));
115+
116+
/// <summary>
117+
/// Configures the extension with given localization configuration instance.
118+
/// </summary>
119+
/// <param name="domainConfiguration">Domain configuration.</param>
120+
/// <param name="localizationConfiguration">Localization configuration instance.</param>
121+
/// <returns><paramref name="domainConfiguration"/> instance with configured extension.</returns>
122+
public static DomainConfiguration ConfigureLocalizationExtension(this DomainConfiguration domainConfiguration,
123+
LocalizationConfiguration localizationConfiguration)
124+
{
125+
domainConfiguration.ExtensionConfigurations.Set(localizationConfiguration);
126+
domainConfiguration.Types.Register(typeof(DomainConfugurationLocalizationExtensions).Assembly);
127+
return domainConfiguration;
128+
}
129+
}
130+
}

Extensions/Xtensive.Orm.Localization/Internals/TypeLocalizationMap.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Xtensive.Orm.Model;
1111
using Xtensive.Orm;
1212
using Xtensive.Reflection;
13+
using Xtensive.Core;
1314

1415
namespace Xtensive.Orm.Localization
1516
{
@@ -21,13 +22,19 @@ internal class TypeLocalizationMap
2122

2223
public static void Initialize(Domain domain)
2324
{
24-
if (domain == null)
25-
throw new ArgumentNullException("domain");
26-
if (domain.Extensions.Get<TypeLocalizationMap>() != null)
25+
ArgumentValidator.EnsureArgumentNotNull(domain, nameof(domain));
26+
27+
var existing = domain.Extensions.Get<TypeLocalizationMap>();
28+
if (existing != null) {
2729
return;
30+
}
31+
32+
var configFromNewSource = domain.Configuration.ExtensionConfigurations.Get<LocalizationConfiguration>();
2833

2934
var map = new TypeLocalizationMap() {
30-
Configuration = LocalizationConfiguration.Load()
35+
Configuration = (configFromNewSource != null)
36+
? configFromNewSource
37+
: LocalizationConfiguration.Load()// config from old source.
3138
};
3239
foreach (var localizableTypeInfo in domain.Model.Types.Entities) {
3340
var type = localizableTypeInfo.UnderlyingType;

Extensions/Xtensive.Orm.Reprocessing/Configuration/ReprocessingConfiguration.cs

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Xtensive.Orm.Reprocessing.Configuration
99
/// <summary>
1010
/// The configuration of the reprocessing system.
1111
/// </summary>
12-
public class ReprocessingConfiguration
12+
public class ReprocessingConfiguration : ConfigurationBase
1313
{
1414
/// <summary>
1515
/// Gets default value of the <see cref="DefaultTransactionOpenMode"/> property.
@@ -21,15 +21,46 @@ public class ReprocessingConfiguration
2121
/// </summary>
2222
public static readonly Type DefaultDefaultExecuteStrategy = typeof (HandleReprocessableExceptionStrategy);
2323

24+
private TransactionOpenMode defaultTransactionOpenMode;
25+
private Type defaultExecuteStrategy;
26+
2427
/// <summary>
2528
/// Gets or sets default value of the <see cref="TransactionOpenMode"/> parameter.
2629
/// </summary>
27-
public TransactionOpenMode DefaultTransactionOpenMode { get; set; }
30+
public TransactionOpenMode DefaultTransactionOpenMode {
31+
get => defaultTransactionOpenMode;
32+
set {
33+
EnsureNotLocked();
34+
defaultTransactionOpenMode = value;
35+
}
36+
}
2837

2938
/// <summary>
3039
/// Gets or sets default value of the <see cref="IExecuteActionStrategy"/> parameter.
3140
/// </summary>
32-
public Type DefaultExecuteStrategy { get; set; }
41+
public Type DefaultExecuteStrategy {
42+
get => defaultExecuteStrategy;
43+
set {
44+
EnsureNotLocked();
45+
defaultExecuteStrategy = value;
46+
}
47+
}
48+
49+
/// <inheritdoc />
50+
protected override ReprocessingConfiguration CreateClone() => new ReprocessingConfiguration();
51+
52+
/// <inheritdoc />
53+
protected override void CopyFrom(ConfigurationBase source)
54+
{
55+
base.CopyFrom(source);
56+
57+
var configuration = (ReprocessingConfiguration) source;
58+
configuration.DefaultTransactionOpenMode = configuration.DefaultTransactionOpenMode;
59+
configuration.DefaultExecuteStrategy = configuration.DefaultExecuteStrategy;
60+
}
61+
62+
/// <inheritdoc />
63+
public override ReprocessingConfiguration Clone() => (ReprocessingConfiguration) base.Clone();
3364

3465
/// <summary>
3566
/// Loads the reprocessing configuration from default section in application configuration file.
@@ -84,17 +115,26 @@ private static ReprocessingConfiguration GetConfigurationFromSection(Configurati
84115
}
85116

86117
/// <summary>
87-
/// Loads the <see cref="ReprocessingConfiguration"/> from given configuration section.
118+
/// Loads the <see cref="ReprocessingConfiguration"/> from specified section of configuration root.
88119
/// </summary>
89-
/// <param name="configurationSection"><see cref="IConfigurationSection"/> to load from.</param>
120+
/// <param name="configuration"><see cref="IConfiguration"/> to load section from.</param>
121+
/// <param name="sectionName">Name of the section where configuration is stored. Not applied if</param>
90122
/// <returns>Loaded configuration or configuration with default settings.</returns>
91-
public static ReprocessingConfiguration Load(IConfigurationSection configurationSection)
123+
public static ReprocessingConfiguration Load(IConfiguration configuration, string sectionName = null)
92124
{
93-
ArgumentValidator.EnsureArgumentNotNull(configurationSection, nameof(configurationSection));
125+
ArgumentValidator.EnsureArgumentNotNull(configuration, nameof(configuration));
94126

95-
return new ReprocessingConfigurationReader().Read(configurationSection);
127+
if (configuration is IConfigurationRoot configurationRoot) {
128+
return new ReprocessingConfigurationReader().Read(configurationRoot, sectionName ?? ConfigurationSection.DefaultSectionName);
129+
}
130+
else if (configuration is IConfigurationSection configurationSection) {
131+
return new ReprocessingConfigurationReader().Read(configurationSection);
132+
}
133+
134+
throw new NotSupportedException("Type of configuration is not supported");
96135
}
97136

137+
98138
/// <summary>
99139
/// Loads the <see cref="ReprocessingConfiguration"/> from specified section of configuration root.
100140
/// </summary>
@@ -108,6 +148,20 @@ public static ReprocessingConfiguration Load(IConfigurationRoot configurationRoo
108148
return new ReprocessingConfigurationReader().Read(configurationRoot, sectionName ?? ConfigurationSection.DefaultSectionName);
109149
}
110150

151+
/// <summary>
152+
/// Loads the <see cref="ReprocessingConfiguration"/> from given configuration section.
153+
/// </summary>
154+
/// <param name="configurationSection"><see cref="IConfigurationSection"/> to load from.</param>
155+
/// <returns>Loaded configuration or configuration with default settings.</returns>
156+
public static ReprocessingConfiguration Load(IConfigurationSection configurationSection)
157+
{
158+
ArgumentValidator.EnsureArgumentNotNull(configurationSection, nameof(configurationSection));
159+
160+
return new ReprocessingConfigurationReader().Read(configurationSection);
161+
}
162+
163+
164+
111165
/// <summary>
112166
/// Initializes a new instance of the <see cref="ReprocessingConfiguration"/> class.
113167
/// </summary>

0 commit comments

Comments
 (0)