ConfigurationExtension.cs 4.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. using Microsoft.Extensions.Configuration;
  2. using Newtonsoft.Json;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Threading.Tasks;
  7. namespace Porta.Kundenzähler.Services.Extension
  8. {
  9. public static class ConfigurationExtension
  10. {
  11. #region Configuration reading
  12. /// <summary>
  13. /// Read a section of the configuration and bind it to a corresponding object containing the same properties (Names must match)
  14. /// </summary>
  15. /// <typeparam name="T">The type of the config section object.</typeparam>
  16. /// <param name="configuration">The full configuration.</param>
  17. /// <param name="key">The key of the section.</param>
  18. /// <returns>The config section object.</returns>
  19. public static T GetSection<T>(this IConfiguration configuration, string key)
  20. {
  21. if (String.IsNullOrEmpty(key))
  22. throw new ArgumentException("The section key must not be NULL or empty.", key);
  23. // Create empty instance of config object type
  24. var optionsObj = Activator.CreateInstance<T>();
  25. var section = configuration.GetSection(key);
  26. if (section == null)
  27. throw new ArgumentException("The requested section cannot be found in configuration file.", key);
  28. // Map the object properties to the section properties
  29. MapSectionPropertiesToObject(configuration, optionsObj, section);
  30. return optionsObj;
  31. }
  32. /// <summary>
  33. /// Map the properties of a configuration object to the corresponding properties in the configuration section
  34. /// </summary>
  35. /// <param name="configuration">The full configuration.</param>
  36. /// <param name="optionsObj">The current options object.</param>
  37. /// <param name="currentSection">The current processing section.</param>
  38. private static void MapSectionPropertiesToObject(IConfiguration configuration, object optionsObj,
  39. IConfigurationSection currentSection)
  40. {
  41. // Get all options object properties
  42. var properties = optionsObj.GetType().GetProperties();
  43. foreach (var propertyInfo in properties)
  44. {
  45. // Check non primitive, not value typed, only classed properties
  46. if (propertyInfo.PropertyType.IsClass
  47. && !propertyInfo.PropertyType.IsArray
  48. && !propertyInfo.PropertyType.IsValueType
  49. && !propertyInfo.PropertyType.IsPrimitive
  50. && propertyInfo.PropertyType.FullName != "System.String")
  51. {
  52. // Get the section configuration value of the current property
  53. var valueObj = currentSection.GetValue<object>(propertyInfo.Name);
  54. // Proceed when value object can be created
  55. if (valueObj != null)
  56. {
  57. // If the property is NULL, create an object for the property
  58. if (propertyInfo.GetValue(optionsObj) == null)
  59. propertyInfo.SetValue(optionsObj, Activator.CreateInstance(propertyInfo.PropertyType));
  60. // Recursive call
  61. MapSectionPropertiesToObject(configuration, propertyInfo.GetValue(optionsObj),
  62. currentSection.GetSection(propertyInfo.Name));
  63. }
  64. }
  65. else
  66. {
  67. // Read the value from the current section
  68. var valueObj = currentSection.GetValue<object>(propertyInfo.Name);
  69. // If the value object is NULL then it might not be set or cannot be evaluated
  70. if (valueObj != null)
  71. {
  72. // Serialize the value as a JSON string
  73. var jsonStr = JsonConvert.SerializeObject(valueObj);
  74. // Deserialize from the JSON string to prevent conversion issues
  75. var value = JsonConvert.DeserializeObject(jsonStr, propertyInfo.PropertyType);
  76. propertyInfo.SetValue(optionsObj, value);
  77. }
  78. }
  79. }
  80. }
  81. #endregion
  82. }
  83. }