@@ -8,7 +8,7 @@ This implies that localizable resources are a part of domain model so they are s
8
8
9
9
Prerequisites
10
10
-------------
11
- DataObjects.Net 7.0 .x or later (http://dataobjects.net )
11
+ DataObjects.Net 7.1 .x or later (http://dataobjects.net )
12
12
13
13
Implementation
14
14
--------------
@@ -50,6 +50,7 @@ Define corresponding localizations, e.g.:
50
50
}
51
51
```
52
52
53
+
53
54
Examples of usage
54
55
-----------------
55
56
@@ -106,4 +107,264 @@ Examples of usage
106
107
where p .Title == " Bienvenido"
107
108
select p ;
108
109
Assert .AreEqual (1 , query .Count ());
110
+ ```
111
+
112
+
113
+ Examples of how to configure extension
114
+ --------------------------------------
115
+
116
+ Following examples show different ways to configure extension in configuration files of various types.
117
+
118
+ ** Example #1 ** Confugure in App.config/Web.config
119
+
120
+ ``` xml
121
+ <configuration >
122
+ <configSections >
123
+ <section name =" Xtensive.Orm" type =" Xtensive.Orm.Configuration.Elements.ConfigurationSection, Xtensive.Orm" />
124
+ <section name =" Xtensive.Orm.Localization" type =" Xtensive.Orm.Localization.Configuration.ConfigurationSection, Xtensive.Orm.Localization" />
125
+ </configSections >
126
+ <Xtensive .Orm>
127
+ <!-- domain(s) configured -->
128
+ </Xtensive .Orm>
129
+ <Xtensive .Orm.Localization>
130
+ <defaultCulture name =" es-ES" />
131
+ </Xtensive .Orm.Localization>
132
+ </configuration >
133
+ ```
134
+
135
+ Such configuration is only compatible with System.Configuration.ConfigurationManager.
136
+ If project still supports such configurations then Localization configuration will be read automatically when it needed to be read.
137
+ Sometimes a work-around is needed to read such configuration, for more read Example #2 and Example #3
138
+
139
+
140
+ ** Example #2 ** Reading old-style configuration of an assembly in NET 5 and newer.
141
+
142
+ Due to new architecture without AppDomain (which among the other things was in charge of gathering configuration files of loaded assemblies
143
+ as it would be one configuration file) System.Configuration.ConfigurationManager now reads only configuration file of actual executable, loaded
144
+ assemblies' configuration files stay unreachable by default, though there is need to read some data from them.
145
+ A great example is test projects which are usually get loaded by test runner executable, and the only configuration accessible in this case
146
+ is test runner one.
147
+
148
+ Extra step is required to read configuration files in such cases. Thankfully ConfigurationManager has methods to get access to assemblies' configurations.
149
+
150
+ To get access to an assembly configuration file it should be opened explicitly by
151
+
152
+ ``` csharp
153
+ var configuration = ConfigurationManager .OpenExeConfiguration (typeof (SomeTypeInConfigOwnerAssembly ).Assembly .Location );
154
+ ```
155
+
156
+ The instance returned from ``` OpenExeConfiguration ``` provides access to sections of the assembly configuration. DataObjects.Net configurations
157
+ (``` DomainConfiguration ``` , ``` LocalizationConfiguration ``` , etc.) have ``` Load() ``` methods that can recieve this instance.
158
+ ``` LocalizationConfiguration ``` can be read like so
159
+
160
+ ``` csharp
161
+ var configuration = ConfigurationManager .OpenExeConfiguration (typeof (SomeTypeInConfigOwnerAssembly ).Assembly .Location );
162
+ var localizationConfig = LocalizationConfiguration .Load (configuration );
163
+
164
+ // loaded configuration should be manually placed to
165
+ domainConfiguration .ExtensionConfigurations .Set (localizationConfig );
166
+ ```
167
+
168
+ The ``` domainConfiguration.ExtensionConfigurations ``` is a new unified place from which an extension will try to get its configuration
169
+ instead of calling default parameterless ``` Load() ``` method, which has not a lot of sense now, though the method is kept as a second source
170
+ for backwards compatibility.
171
+
172
+ For more convenience, DomainConfiguration extensions are provided, which make code more neat and clear.
173
+ For instance,
174
+
175
+ ``` csharp
176
+ var configuration = ConfigurationManager .OpenExeConfiguration (typeof (SomeTypeInConfigOwnerAssembly ).Assembly .Location );
177
+
178
+ var domainConfiguration = DomainConfiguration .Load (configuration );
179
+
180
+ // the extension hides getting configuration with LocalizationConfiguration.Load(configuration)
181
+ // and also putting it to ExtensionConfigurations collection.
182
+ domainConfiguration .ConfigureLocalizationExtension (configuration );
183
+ ```
184
+
185
+ Custom section names are also supported if for some reason default section name is not used.
186
+
187
+
188
+ ** Example #3 ** Reading old-style configuration of an assembly in a project that uses appsettings.json file.
189
+
190
+ If for some reason there is need to keep the old-style configuration then there is a work-around as well.
191
+ Static configuration manager provides method ``` OpenMappedExeConfiguration() ``` which allows to get
192
+ any * .config file as ``` System.Configuration.Configuration ``` instance. For example
193
+
194
+ ``` csharp
195
+ ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap ();
196
+ configFileMap .ExeConfigFilename = " Orm.config" ; // or other file name, the file should exist bin folder
197
+ var configuration = System .Configuration .ConfigurationManager .OpenMappedExeConfiguration (configFileMap , ConfigurationUserLevel .None );
198
+ ```
199
+
200
+ After that, as in previous example, the instance can be passed to ``` Load ``` method of ``` LocalizationConfiguration ``` to read extension configuration
201
+ and later put it to ``` DomainConfiguration.ExtensionConfigurations ``` .
202
+ After ``` System.Configuration.Configuration ``` instance is provided it is possible to pass it into Load method of different DataObjects.Net configurations,
203
+ including ``` LocalizationConfiguration ``` . Then put localization configuration to ``` DomainConfiguration.ExtensionConfigurations ``` collection.
204
+
205
+ ``` csharp
206
+ var localizationConfiguration = LocalizationConfiguration .Load (configuration );
207
+
208
+ domainConfiguration .ExtensionConfigurations .Set (localizationConfiguration );
209
+ ```
210
+
211
+ or to extension method
212
+
213
+ ``` csharp
214
+ domainConfiguration .ConfigureLocalizationExtension (configuration );
215
+ ```
216
+
217
+
218
+ ** Example #4 ** Configure using Microsoft.Extensions.Configuration API.
219
+
220
+ This API allows to have configurations in various forms including JSON and XML formats.
221
+ Loading of such files may differ depending on .NET version, check Microsoft manuals for instructions.
222
+
223
+ Allowed Json and Xml configuration definition look like below
224
+
225
+ ``` xml
226
+ <configuration >
227
+ <Xtensive .Orm.Localization>
228
+ <DefaultCulture >es-ES</DefaultCulture >
229
+ </Xtensive .Orm.Localization>
230
+ </configuration >
231
+ ```
232
+
233
+ ``` json
234
+ {
235
+ "Xtensive.Orm.Localization" : {
236
+ "DefaultCulture" : " es-ES"
237
+ }
238
+ }
239
+ ```
240
+
241
+ The API has certain issues with Xml elements with attributes so it is recommended to use
242
+ more up-to-date attributeless nodes.
243
+ For JSON it is pretty clear.
244
+
245
+ ``` LocalizationConfiguration.Load ``` method can accept different types of abstractions from the
246
+ API, including
247
+ - ``` Microsoft.Extensions.Configuration.IConfiguration ``` ,
248
+ - ``` Microsoft.Extensions.Configuration.IConfigurationRoot ```
249
+ - ``` Microsoft.Extensions.Configuration.IConfigurationSection ``` .
250
+
251
+ Loading of configuration may look like
252
+
253
+ ``` csharp
254
+
255
+ var app = builder .Build ();
256
+
257
+ // tries to load from default section "Xtensive.Orm.Localization"
258
+ var localizationConfig = LocalizationConfiguration .Load (app .Configuration );
259
+
260
+ domainConfiguration .ExtensionConfigurations .Set (localizationConfig );
261
+ ```
262
+
263
+ or, with use of extension
264
+
265
+
266
+ ``` csharp
267
+
268
+ var app = builder .Build ();
269
+
270
+ // tries to load from default section "Xtensive.Orm.Localization"
271
+ // and additionally adds Xtensive.Orm.Localization assembly to domain types.
272
+
273
+ domainConfiguration .ConfigureLocalizationExtension (app .Configuration );
274
+ ```
275
+
276
+
277
+
278
+ ** Example #5 ** Configure using Microsoft.Extensions.Configuration API from section with non-default name.
279
+
280
+ For configurations like
281
+
282
+ ``` xml
283
+ <configuration >
284
+ <Orm .Localization>
285
+ <DefaultCulture >es-ES</DefaultCulture >
286
+ </Orm .Localization>
287
+ </configuration >
288
+ ```
289
+
290
+ ``` json
291
+ {
292
+ "Orm.Localization" : {
293
+ "DefaultCulture" : " es-ES"
294
+ }
295
+ }
296
+ ```
297
+
298
+ Loading of configuration may look like
299
+
300
+ ``` csharp
301
+
302
+ var app = builder .Build ();
303
+
304
+ var localizationConfig = LocalizationConfiguration .Load (app .Configuration , " Orm.Localization" );
305
+
306
+ domainConfiguration .ExtensionConfigurations .Set (localizationConfig );
307
+ ```
308
+
309
+ or with use of extension
310
+
311
+ ``` csharp
312
+
313
+ var app = builder .Build ();
314
+
315
+ domainConfiguration .ConfigureLocalizationExtension (app .Configuration , " Orm.Localization" );
316
+ ```
317
+
318
+
319
+ ** Example #6 ** Configure using Microsoft.Extensions.Configuration API from sub-section deeper in section tree.
320
+
321
+ If for some reason extension configuration should be moved deeper in section tree like something below
322
+
323
+ ``` xml
324
+ <configuration >
325
+ <Orm .Extensions>
326
+ <Xtensive .Orm.Localization>
327
+ <DefaultCulture >es-ES</DefaultCulture >
328
+ </Xtensive .Orm.Localization>
329
+ </Orm .Extensions>
330
+ </configuration >
331
+ ```
332
+
333
+ or in JSON
334
+
335
+ ``` json
336
+ {
337
+ "Orm.Extensions" : {
338
+ "Xtensive.Orm.Localization" : {
339
+ "DefaultCulture" : " es-ES"
340
+ }
341
+ }
342
+ }
343
+ ```
344
+
345
+ Then section must be provided manually, code may look like
346
+
347
+ ``` csharp
348
+
349
+ var app = builder .Build ();
350
+
351
+ var configurationRoot = app .Configuration ;
352
+ var extensionsGroupSection = configurationRoot .GetSection (" Orm.Extensions" );
353
+ var localizationSection = extensionsGroupSection .GetSection (" Xtensive.Orm.Localization" );
354
+ var localizationConfig = LocalizationConfiguration .Load (localizationSection );
355
+
356
+ domainConfiguration .ExtensionConfigurations .Set (localizationConfig );
357
+ ```
358
+
359
+ or with use of extension method
360
+
361
+ ``` csharp
362
+
363
+ var app = builder .Build ();
364
+
365
+ var configurationRoot = app .Configuration ;
366
+ var extensionsGroupSection = configurationRoot .GetSection (" Orm.Extensions" );
367
+ var localizationSection = extensionsGroupSection .GetSection (" Xtensive.Orm.Localization" );
368
+
369
+ domainConfiguration .ConfigureLocalizationExtension (localizationSection );
109
370
```
0 commit comments