diff --git a/docs/Reference/Generated/MigrationTools.xml b/docs/Reference/Generated/MigrationTools.xml
index d507badcf..66d112224 100644
--- a/docs/Reference/Generated/MigrationTools.xml
+++ b/docs/Reference/Generated/MigrationTools.xml
@@ -263,27 +263,27 @@
- => @"cd3dc28e"
+ => @"d11381cb"
- => @"cd3dc28e52a31c168b7b951d34456f95caf338f6"
+ => @"d11381cbf462b62fad3a9813d37bf264d8296cf6"
- => @"2024-08-28T17:45:31+01:00"
+ => @"2024-08-28T18:43:28+01:00"
- => @"221"
+ => @"222"
- => @"v15.2.1-221-gcd3dc28e"
+ => @"v15.2.1-222-gd11381cb"
@@ -318,7 +318,7 @@
- => @"222"
+ => @"223"
diff --git a/src/MigrationTools.Host/Commands/InitMigrationCommand.cs b/src/MigrationTools.Host/Commands/InitMigrationCommand.cs
index e5e49b4a5..5a83c9787 100644
--- a/src/MigrationTools.Host/Commands/InitMigrationCommand.cs
+++ b/src/MigrationTools.Host/Commands/InitMigrationCommand.cs
@@ -74,7 +74,7 @@ public override async Task ExecuteAsync(CommandContext context, InitMigrati
_logger.LogInformation("Populating config with {Options}", settings.Options.ToString());
- OptionsConfigurationBuilder optionsBuilder = Services.GetService();
+ OptionsConfiguration optionsBuilder = Services.GetService();
switch (settings.Options)
{
diff --git a/src/MigrationTools/Options/OptionsConfiguration.cs b/src/MigrationTools/Options/OptionsConfiguration.cs
new file mode 100644
index 000000000..65a70a894
--- /dev/null
+++ b/src/MigrationTools/Options/OptionsConfiguration.cs
@@ -0,0 +1,195 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using Elmah.Io.Client;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using Microsoft.VisualStudio.Services.Audit;
+using Microsoft.VisualStudio.Services.Common.CommandLine;
+using MigrationTools.EndpointEnrichers;
+using MigrationTools.Endpoints.Infrastructure;
+using MigrationTools.Enrichers;
+using Newtonsoft.Json.Linq;
+using Serilog.Core;
+
+namespace MigrationTools.Options
+{
+ public class OptionsConfiguration
+ {
+ readonly ILogger logger;
+ readonly IConfiguration configuration;
+
+ private List OptionsToInclude { get; }
+ private Dictionary NamedOptionsToInclude { get; }
+
+ private List catalogue;
+
+ public OptionsConfiguration(
+ IConfiguration configuration,
+ ILogger logger,
+ ITelemetryLogger telemetryLogger)
+ {
+ this.configuration = configuration;
+ this.logger = logger;
+ OptionsToInclude = new List();
+ NamedOptionsToInclude = new Dictionary();
+ catalogue = AppDomain.CurrentDomain.GetMigrationToolsTypes().WithInterface().ToList();
+ }
+
+ public void AddAllOptions()
+ {
+ var keyGen = new KeyGenerator();
+
+ foreach (var optionType in catalogue)
+ {
+ switch (optionType)
+ {
+ case Type t when typeof(IEndpointOptions).IsAssignableFrom(t):
+ AddOption(optionType.Name, keyGen.GetNextKey());
+ break;
+ case Type t when typeof(IProcessorEnricherOptions).IsAssignableFrom(t):
+ logger.LogInformation("Skipping ProcessorEnricherOptions: {optionType}", optionType.Name);
+ break;
+ case Type t when typeof(IEndpointEnricherOptions).IsAssignableFrom(t):
+ logger.LogInformation("Skipping ProcessorEnricherOptions: {optionType}", optionType.Name);
+ break;
+ default:
+ AddOption(optionType.Name);
+ break;
+ }
+ }
+ }
+
+ public void AddOption(IOptions option)
+ {
+ OptionsToInclude.Add(option);
+ }
+
+ public void AddOption(string optionName)
+ {
+ optionName = optionName.Replace("Options", "");
+ var optionType = catalogue.FirstOrDefault(x => x.Name.StartsWith(optionName));
+ if (optionType == null)
+ {
+ logger.LogWarning("Could not find option type for {optionName}", optionName);
+ } else
+ {
+ logger.LogInformation("Adding {optionName}", optionName);
+ OptionsToInclude.Add(CreateOptionFromType(optionType));
+ }
+
+ }
+
+ private IOptions CreateOptionFromType(Type optionType)
+ {
+ IOptions instanceOfOption = (IOptions)Activator.CreateInstance(optionType);
+ var section = configuration.GetSection(instanceOfOption.ConfigurationMetadata.PathToSample);
+ section.Bind(instanceOfOption);
+ return instanceOfOption;
+ }
+
+ public void AddOption(IOptions option, string key)
+ {
+ NamedOptionsToInclude.Add(key, option);
+ }
+
+ public void AddOption(string optionName, string key)
+ {
+ optionName = optionName.Replace("Options", "");
+ var optionType = catalogue.FirstOrDefault(x => x.Name.StartsWith(optionName));
+ if (optionType == null)
+ {
+ logger.LogWarning("Could not find option type for {optionName}", optionName);
+ }
+ else
+ {
+ logger.LogInformation("Adding {optionName} as {key}", optionName, key);
+ NamedOptionsToInclude.Add(key, CreateOptionFromType(optionType));
+ }
+ }
+
+ public string Build()
+ {
+ logger.LogInformation("Building Configuration");
+ JObject configJson = new JObject();
+ configJson["Serilog"] = new JObject();
+ configJson["Serilog"]["MinimumLevel"] = $"Information";
+ var version = Assembly.GetExecutingAssembly().GetName().Version;
+ configJson["MigrationTools"]["Version"] = $"{version.Major}.{version.Minor}";
+ configJson["MigrationTools"] = new JObject();
+ configJson["MigrationTools"]["Endpoints"] = new JObject();
+ configJson["MigrationTools"]["Processors"] = new JArray();
+ configJson["MigrationTools"]["CommonTools"] = new JObject();
+ foreach (var item in OptionsToInclude)
+ {
+ configJson = AddOptionToConfig(configuration, configJson, item);
+ }
+ foreach (var item in NamedOptionsToInclude)
+ {
+ configJson = AddNamedOptionToConfig(configuration, configJson, item.Key, item.Value);
+ }
+ return configJson.ToString(Newtonsoft.Json.Formatting.Indented);
+ }
+
+ private JObject AddNamedOptionToConfig(IConfiguration configuration, JObject configJson, string key, IOptions option)
+ {
+ if (option.ConfigurationMetadata.PathToInstance == null)
+ {
+ logger.LogWarning("Skipping Option: {item} with {key} as it has no PathToInstance", option.GetType().Name, key);
+ return configJson;
+ }
+ try
+ {
+ var hardPath = $"MigrationTools:Endpoints:{key}";
+ logger.LogInformation("Building Option: {item} to {hardPath}", option.GetType().Name, hardPath);
+ configJson = OptionsConfigurationBuilder.AddOptionsToConfiguration(configJson, option, hardPath, true);
+
+ }
+ catch (Exception)
+ {
+
+ logger.LogWarning("FAILED!! Adding Option: {item}", option.GetType().FullName);
+ }
+
+ return configJson;
+ }
+
+ private JObject AddOptionToConfig(IConfiguration configuration, JObject configJson, IOptions option)
+ {
+ if (option.ConfigurationMetadata.PathToInstance == null)
+ {
+ logger.LogWarning("Skipping Option: {item} as it has no PathToInstance", option.GetType().Name);
+ return configJson;
+ }
+ try
+ {
+ logger.LogInformation("Building Option: {item} to {path}", option.GetType().Name, option.ConfigurationMetadata.PathToInstance);
+ configJson = OptionsConfigurationBuilder.AddOptionsToConfiguration(configJson, option, false);
+
+ }
+ catch (Exception)
+ {
+
+ logger.LogWarning("FAILED!! Adding Option: {item}", option.GetType().FullName);
+ }
+
+ return configJson;
+ }
+
+
+ }
+
+ public class KeyGenerator
+ {
+ private int _counter = 1;
+
+ public string GetNextKey()
+ {
+ _counter++;
+ return $"Key{_counter}";
+ }
+ }
+}
diff --git a/src/MigrationTools/Options/OptionsConfigurationBuilder.cs b/src/MigrationTools/Options/OptionsConfigurationBuilder.cs
index ea393dbce..2d294bf4c 100644
--- a/src/MigrationTools/Options/OptionsConfigurationBuilder.cs
+++ b/src/MigrationTools/Options/OptionsConfigurationBuilder.cs
@@ -1,206 +1,246 @@
using System;
using System.Collections.Generic;
-using System.Configuration;
+using System.IO;
using System.Linq;
using System.Reflection;
-using System.Text;
-using Elmah.Io.Client;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.Logging;
-using Microsoft.VisualStudio.Services.Audit;
-using Microsoft.VisualStudio.Services.Common.CommandLine;
-using MigrationTools.EndpointEnrichers;
-using MigrationTools.Endpoints.Infrastructure;
-using MigrationTools.Enrichers;
using Newtonsoft.Json.Linq;
-using Serilog.Core;
namespace MigrationTools.Options
{
- public class OptionsConfigurationBuilder
+
+
+public static class OptionsConfigurationBuilder
+{
+ public static IOptions LoadConfiguration(string filePath, IOptions options, bool isCollection = false)
{
- readonly ILogger logger;
- readonly IConfiguration configuration;
+ var optionsConfig = options.ConfigurationMetadata;
+ JObject json = File.Exists(filePath) ? JObject.Parse(File.ReadAllText(filePath)) : new JObject();
- private List OptionsToInclude { get; }
- private Dictionary NamedOptionsToInclude { get; }
+ // Determine the path based on whether this is a collection or a section
+ string path = optionsConfig.PathToInstance;
+
+ if (isCollection)
+ {
+ // Load from a collection
+ var collection = json.SelectToken(path.Replace(":", ".")) as JArray;
- private List catalogue;
+ var item = collection?.FirstOrDefault(p => p[optionsConfig.ObjectName]?.ToString() == optionsConfig.OptionFor);
- public OptionsConfigurationBuilder(
- IConfiguration configuration,
- ILogger logger,
- ITelemetryLogger telemetryLogger)
+ return item != null ? item.ToObject(options.GetType()) as IOptions : Activator.CreateInstance(options.GetType()) as IOptions;
+ }
+ else
{
- this.configuration = configuration;
- this.logger = logger;
- OptionsToInclude = new List();
- NamedOptionsToInclude = new Dictionary();
- catalogue = AppDomain.CurrentDomain.GetMigrationToolsTypes().WithInterface().ToList();
+ // Load from a section
+ var section = json.SelectToken(path.Replace(":", "."));
+
+ return section != null ? section.ToObject(options.GetType()) as IOptions : Activator.CreateInstance(options.GetType()) as IOptions;
}
+ }
- public void AddAllOptions()
- {
- var keyGen = new KeyGenerator();
+ public static void SaveConfiguration(string filePath, IOptions options, bool isCollection = false)
+ {
+ JObject json = File.Exists(filePath) ? JObject.Parse(File.ReadAllText(filePath)) : new JObject();
- foreach (var optionType in catalogue)
+ // Determine the path based on whether this is a collection or a section
+ string path = options.ConfigurationMetadata.PathToInstance;
+
+ string[] pathParts = path.Split(':');
+ JObject currentSection = json;
+
+ // Build the JSON structure for the section or collection
+ for (int i = 0; i < pathParts.Length; i++)
+ {
+ if (i == pathParts.Length - 1 && isCollection)
{
- switch (optionType)
+ // If it's a collection, create or find the JArray
+ if (currentSection[pathParts[i]] == null)
{
- case Type t when typeof(IEndpointOptions).IsAssignableFrom(t):
- AddOption(optionType.Name, keyGen.GetNextKey());
- break;
- case Type t when typeof(IProcessorEnricherOptions).IsAssignableFrom(t):
- logger.LogInformation("Skipping ProcessorEnricherOptions: {optionType}", optionType.Name);
- break;
- case Type t when typeof(IEndpointEnricherOptions).IsAssignableFrom(t):
- logger.LogInformation("Skipping ProcessorEnricherOptions: {optionType}", optionType.Name);
- break;
- default:
- AddOption(optionType.Name);
- break;
+ currentSection[pathParts[i]] = new JArray();
}
- }
- }
- public void AddOption(IOptions option)
- {
- OptionsToInclude.Add(option);
- }
+ var collectionArray = (JArray)currentSection[pathParts[i]];
- public void AddOption(string optionName)
- {
- optionName = optionName.Replace("Options", "");
- var optionType = catalogue.FirstOrDefault(x => x.Name.StartsWith(optionName));
- if (optionType == null)
- {
- logger.LogWarning("Could not find option type for {optionName}", optionName);
- } else
+ // Check if the object already exists in the collection
+ var existingItem = collectionArray.FirstOrDefault(p => p[options.ConfigurationMetadata.ObjectName]?.ToString() == options.ConfigurationMetadata.OptionFor);
+
+ if (existingItem != null)
+ {
+ // Update the existing item
+ var index = collectionArray.IndexOf(existingItem);
+ collectionArray[index] = JObject.FromObject(options);
+ }
+ else
+ {
+ // Add the new item to the collection
+ var newItem = JObject.FromObject(options);
+ newItem[options.ConfigurationMetadata.ObjectName] = options.ConfigurationMetadata.OptionFor;
+ collectionArray.Add(newItem);
+ }
+ }
+ else
{
- logger.LogInformation("Adding {optionName}", optionName);
- OptionsToInclude.Add(CreateOptionFromType(optionType));
+ // Create or navigate to the JObject for the section
+ if (currentSection[pathParts[i]] == null)
+ {
+ currentSection[pathParts[i]] = new JObject();
+ }
+ currentSection = (JObject)currentSection[pathParts[i]];
}
-
}
- private IOptions CreateOptionFromType(Type optionType)
+ // If it's not a collection, replace the content directly in the final section
+ if (!isCollection)
{
- IOptions instanceOfOption = (IOptions)Activator.CreateInstance(optionType);
- var section = configuration.GetSection(instanceOfOption.ConfigurationMetadata.PathToSample);
- section.Bind(instanceOfOption);
- return instanceOfOption;
+ currentSection.Replace(JObject.FromObject(options));
}
- public void AddOption(IOptions option, string key)
- {
- NamedOptionsToInclude.Add(key, option);
- }
+ // Save the updated JSON file
+ File.WriteAllText(filePath, json.ToString(Newtonsoft.Json.Formatting.Indented));
+ }
+
+ public static List LoadAll(string filePath, IOptions templateOption)
+ {
+ var optionsConfig = templateOption.ConfigurationMetadata;
+ JObject json = File.Exists(filePath) ? JObject.Parse(File.ReadAllText(filePath)) : new JObject();
+
+ var foundOptions = new List();
+
+ // Recursively search through the entire JSON hierarchy
+ SearchForOptions(json, optionsConfig, foundOptions, templateOption.GetType());
- public void AddOption(string optionName, string key)
+ return foundOptions;
+ }
+
+ private static void SearchForOptions(JToken token, ConfigurationMetadata config, List foundTools, Type optionType)
+ {
+ if (token is JObject obj)
{
- optionName = optionName.Replace("Options", "");
- var optionType = catalogue.FirstOrDefault(x => x.Name.StartsWith(optionName));
- if (optionType == null)
+ // Check if this object has the appropriate property with the value matching the config
+ if (obj.TryGetValue(config.ObjectName, out JToken fieldTypeToken) && fieldTypeToken.ToString() == config.OptionFor)
{
- logger.LogWarning("Could not find option type for {optionName}", optionName);
+ // Deserialize the JObject into an IOptions object
+ var options = obj.ToObject(optionType) as IOptions;
+ foundTools.Add(options);
}
- else
- {
- logger.LogInformation("Adding {optionName} as {key}", optionName, key);
- NamedOptionsToInclude.Add(key, CreateOptionFromType(optionType));
- }
- }
- public string Build()
- {
- logger.LogInformation("Building Configuration");
- JObject configJson = new JObject();
- configJson["MigrationTools"] = new JObject();
- configJson["MigrationTools"]["Endpoints"] = new JObject();
- configJson["MigrationTools"]["Processors"] = new JArray();
- configJson["MigrationTools"]["CommonTools"] = new JObject();
- // Add the version element
- AddSerilog(configJson);
- AddVersionInfo(configJson);
- foreach (var item in OptionsToInclude)
+ // Recursively search child objects
+ foreach (var property in obj.Properties())
{
- configJson = AddOptionToConfig(configuration, configJson, item);
+ SearchForOptions(property.Value, config, foundTools, optionType);
}
- foreach (var item in NamedOptionsToInclude)
+ }
+ else if (token is JArray array)
+ {
+ // Recursively search elements in the array
+ foreach (var item in array)
{
- configJson = AddNamedOptionToConfig(configuration, configJson, item.Key, item.Value);
+ SearchForOptions(item, config, foundTools, optionType);
}
- return configJson.ToString(Newtonsoft.Json.Formatting.Indented);
}
+ }
+
+ public static string CreateNewConfigurationJson(IOptions options, string path, string objectName, string optionFor, bool isCollection = false, bool shouldAddObjectName = false)
+ {
+ // Load existing configuration from a file or create a new JObject if necessary
+ JObject configJson = new JObject();
+
+ // Add or update the options in the configuration using the new method signature
+ configJson = AddOptionsToConfiguration(configJson, options, path, objectName, optionFor, isCollection, shouldAddObjectName);
+
+ // Return the updated JSON as a formatted string
+ return configJson.ToString(Newtonsoft.Json.Formatting.Indented);
+ }
+
- private static void AddSerilog(JObject configJson)
+ public static JObject AddOptionsToConfiguration(JObject configJson, IOptions iOption, bool shouldAddObjectName = false)
{
- configJson["Serilog"] = new JObject();
- configJson["Serilog"]["MinimumLevel"] = $"Information";
+ return AddOptionsToConfiguration(configJson, iOption, iOption.ConfigurationMetadata.PathToInstance, shouldAddObjectName);
}
- private static void AddVersionInfo(JObject configJson)
+ public static JObject AddOptionsToConfiguration(JObject configJson, IOptions iOption, string sectionPath, bool shouldAddObjectName = false)
{
- var version = Assembly.GetExecutingAssembly().GetName().Version;
- configJson["MigrationTools"]["Version"] = $"{version.Major}.{version.Minor}";
+ return AddOptionsToConfiguration(configJson, iOption, sectionPath, iOption.ConfigurationMetadata.ObjectName, iOption.ConfigurationMetadata.OptionFor, iOption.ConfigurationMetadata.IsCollection, shouldAddObjectName);
}
- private JObject AddNamedOptionToConfig(IConfiguration configuration, JObject configJson, string key, IOptions option)
+ public static JObject AddOptionsToConfiguration(
+ JObject configJson,
+ IOptions options,
+ string path,
+ string objectName,
+ string optionFor,
+ bool isCollection = false,
+ bool shouldAddObjectName = false)
+ {
+ // Initialize the JObject if it was null
+ if (configJson == null)
{
- if (option.ConfigurationMetadata.PathToInstance == null)
- {
- logger.LogWarning("Skipping Option: {item} with {key} as it has no PathToInstance", option.GetType().Name, key);
- return configJson;
- }
- try
- {
- var hardPath = $"MigrationTools:Endpoints:{key}";
- logger.LogInformation("Building Option: {item} to {hardPath}", option.GetType().Name, hardPath);
- configJson = Options.OptionsManager.AddOptionsToConfiguration(configJson, option, hardPath, true);
-
- }
- catch (Exception)
- {
-
- logger.LogWarning("FAILED!! Adding Option: {item}", option.GetType().FullName);
- }
-
- return configJson;
+ configJson = new JObject();
}
- private JObject AddOptionToConfig(IConfiguration configuration, JObject configJson, IOptions option)
+ // Split the path into its components
+ string[] pathParts = path.Split(':');
+ JObject currentSection = configJson;
+
+ // Traverse or create the JSON structure for the section or collection
+ for (int i = 0; i < pathParts.Length; i++)
{
- if (option.ConfigurationMetadata.PathToInstance == null)
+ // If this is the last part of the path
+ if (i == pathParts.Length - 1)
{
- logger.LogWarning("Skipping Option: {item} as it has no PathToInstance", option.GetType().Name);
- return configJson;
- }
- try
- {
- logger.LogInformation("Building Option: {item} to {path}", option.GetType().Name, option.ConfigurationMetadata.PathToInstance);
- configJson = Options.OptionsManager.AddOptionsToConfiguration(configJson, option, false);
-
+ if (isCollection)
+ {
+ // Ensure we have a JArray at this position
+ if (currentSection[pathParts[i]] == null)
+ {
+ currentSection[pathParts[i]] = new JArray();
+ }
+
+ // Add the options object as part of the collection
+ var collectionArray = (JArray)currentSection[pathParts[i]];
+ var optionsObject = JObject.FromObject(options);
+
+ // Add the object name if required
+ if (shouldAddObjectName)
+ {
+ optionsObject.AddFirst(new JProperty(objectName, optionFor));
+ }
+
+ collectionArray.Add(optionsObject);
+ }
+ else
+ {
+ // We're at the last part of the path, so add the options object here
+ var optionsObject = new JObject();
+
+ // Add the object name and options
+ if (shouldAddObjectName)
+ {
+ optionsObject[objectName] = optionFor;
+ }
+
+ // Add the other properties from the options object
+ optionsObject.Merge(JObject.FromObject(options), new JsonMergeSettings
+ {
+ MergeArrayHandling = MergeArrayHandling.Concat
+ });
+
+ // Replace or add the object in the current section
+ currentSection[pathParts[i]] = optionsObject;
+ }
}
- catch (Exception)
+ else
{
-
- logger.LogWarning("FAILED!! Adding Option: {item}", option.GetType().FullName);
+ // Traverse or create the JObject for the current section
+ if (currentSection[pathParts[i]] == null)
+ {
+ currentSection[pathParts[i]] = new JObject();
+ }
+ currentSection = (JObject)currentSection[pathParts[i]];
}
-
- return configJson;
}
-
- }
-
- public class KeyGenerator
- {
- private int _counter = 1;
-
- public string GetNextKey()
- {
- _counter++;
- return $"Key{_counter}";
- }
+ // Return the modified JObject
+ return configJson;
}
}
+}
\ No newline at end of file
diff --git a/src/MigrationTools/Options/OptionsManager.cs b/src/MigrationTools/Options/OptionsManager.cs
deleted file mode 100644
index 2165568e0..000000000
--- a/src/MigrationTools/Options/OptionsManager.cs
+++ /dev/null
@@ -1,326 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Security.AccessControl;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Options;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-
-namespace MigrationTools.Options
-{
- public class OptionsManager
- {
-
- public static dynamic GetOptionsManager(Type option)
- {
- Type optionsManagerType = typeof(OptionsManager<>);
- Type specificOptionsManagerType = optionsManagerType.MakeGenericType(option);
-
- object optionsManagerInstance = Activator.CreateInstance(
- specificOptionsManagerType
- );
- return optionsManagerInstance;
- }
-
- public static string CreateNewConfigurationJson(IOptions iOption, bool isCollection = false)
- {
- Type optionsManagerType = typeof(OptionsManager<>).MakeGenericType(iOption.GetType());
-
- // Create an instance of OptionsManager
- object optionsManagerInstance = Activator.CreateInstance(optionsManagerType);
-
- // Get the method information for CreateNewConfigurationJson
- MethodInfo createMethod = optionsManagerType.GetMethod("CreateNewConfigurationJson");
-
- // Prepare parameters for the method
- object[] parameters = { iOption, isCollection };
-
- // Invoke the method dynamically
- string result = (string)createMethod.Invoke(optionsManagerInstance, parameters);
-
- // Output the result
- return result;
- }
-
- public static JObject AddOptionsToConfiguration(JObject configJson, IOptions iOption, bool shouldAddObjectName = false)
- {
- //JObject configJson, TOptions options, string path, string objectName, string optionFor, bool isCollection = false, bool shouldAddObjectName = false
- return AddOptionsToConfiguration(configJson, iOption, iOption.ConfigurationMetadata.PathToInstance,shouldAddObjectName);
- }
-
- public static JObject AddOptionsToConfiguration(JObject configJson, IOptions iOption, string sectionPath, bool shouldAddObjectName = false)
- {
- Type optionsManagerType = typeof(OptionsManager<>).MakeGenericType(iOption.GetType());
-
- // Create an instance of OptionsManager
- object optionsManagerInstance = Activator.CreateInstance(optionsManagerType);
-
- // Get the method information for CreateNewConfigurationJson
- MethodInfo createMethod = optionsManagerType.GetMethod("AddOptionsToConfiguration");
-
- // Prepare parameters for the method
- object[] parameters = { configJson, iOption, sectionPath, iOption.ConfigurationMetadata.ObjectName, iOption.ConfigurationMetadata.OptionFor, iOption.ConfigurationMetadata.IsCollection, shouldAddObjectName };
-
- // Invoke the method dynamically
- JObject result = (JObject)createMethod.Invoke(optionsManagerInstance, parameters);
-
- // Output the result
- return result;
- }
-
- public static ConfigurationMetadata GetOptionsConfiguration(Type option)
- {
- // ActivatorUtilities.CreateInstance(option);
- IOptions optionInsance = (IOptions)Activator.CreateInstance(option);
- return optionInsance.ConfigurationMetadata;
- }
-
- }
-
- public class OptionsManager where TOptions : class, IOptions, new()
- {
- public TOptions LoadConfiguration(string filePath, bool isCollection = false)
- {
- var optionsConfig = GetOptionsConfiguration();
- JObject json = File.Exists(filePath) ? JObject.Parse(File.ReadAllText(filePath)) : new JObject();
-
- // Determine the path based on whether this is a collection or a section
- string path = optionsConfig.PathToInstance;
-
- if (isCollection)
- {
- // Load from a collection
- var collection = json.SelectToken(path.Replace(":", ".")) as JArray;
-
- var item = collection?.FirstOrDefault(p => p[optionsConfig.ObjectName]?.ToString() == optionsConfig.OptionFor);
-
- return item != null ? item.ToObject() : new TOptions();
- }
- else
- {
- // Load from a section
- var section = json.SelectToken(path.Replace(":", "."));
-
- return section != null ? section.ToObject() : new TOptions();
- }
- }
-
- public void SaveConfiguration(string filePath, TOptions options, bool isCollection = false)
- {
- JObject json = File.Exists(filePath) ? JObject.Parse(File.ReadAllText(filePath)) : new JObject();
-
- // Determine the path based on whether this is a collection or a section
- string path = options.ConfigurationMetadata.PathToInstance;
-
- string[] pathParts = path.Split(':');
- JObject currentSection = json;
-
- // Build the JSON structure for the section or collection
- for (int i = 0; i < pathParts.Length; i++)
- {
- if (i == pathParts.Length - 1 && isCollection)
- {
- // If it's a collection, create or find the JArray
- if (currentSection[pathParts[i]] == null)
- {
- currentSection[pathParts[i]] = new JArray();
- }
-
- var collectionArray = (JArray)currentSection[pathParts[i]];
-
- // Check if the object already exists in the collection
- var existingItem = collectionArray.FirstOrDefault(p => p[options.ConfigurationMetadata.ObjectName]?.ToString() == options.ConfigurationMetadata.OptionFor);
-
- if (existingItem != null)
- {
- // Update the existing item
- var index = collectionArray.IndexOf(existingItem);
- collectionArray[index] = JObject.FromObject(options);
- }
- else
- {
- // Add the new item to the collection
- var newItem = JObject.FromObject(options);
- newItem[options.ConfigurationMetadata.ObjectName] = options.ConfigurationMetadata.OptionFor;
- collectionArray.Add(newItem);
- }
- }
- else
- {
- // Create or navigate to the JObject for the section
- if (currentSection[pathParts[i]] == null)
- {
- currentSection[pathParts[i]] = new JObject();
- }
- currentSection = (JObject)currentSection[pathParts[i]];
- }
- }
-
- // If it's not a collection, replace the content directly in the final section
- if (!isCollection)
- {
- currentSection.Replace(JObject.FromObject(options));
- }
-
- // Save the updated JSON file
- File.WriteAllText(filePath, json.ToString(Formatting.Indented));
- }
-
- public List LoadAll(string filePath)
- {
- var optionsConfig = GetOptionsConfiguration();
- JObject json = File.Exists(filePath) ? JObject.Parse(File.ReadAllText(filePath)) : new JObject();
-
- var foundOptions = new List();
-
- // Recursively search through the entire JSON hierarchy
- SearchForOptions(json, optionsConfig, foundOptions);
-
- return foundOptions;
- }
-
-
- private void SearchForOptions(JToken token, ConfigurationMetadata config, List foundTools)
- {
- if (token is JObject obj)
- {
- // Check if this object has a "FieldType" property with the value "FieldMappingTool"
- if (obj.TryGetValue(config.ObjectName, out JToken fieldTypeToken) && fieldTypeToken.ToString() == config.OptionFor)
- {
- // Deserialize the JObject into a FieldMappingToolOptions object
- var options = obj.ToObject();
- foundTools.Add(options);
- }
-
- // Recursively search child objects
- foreach (var property in obj.Properties())
- {
- SearchForOptions(property.Value, config, foundTools);
- }
- }
- else if (token is JArray array)
- {
- // Recursively search elements in the array
- foreach (var item in array)
- {
- SearchForOptions(item, config, foundTools);
- }
- }
- }
-
- public string CreateNewConfigurationJson(TOptions options, string path, string objectName, string optionFor, bool isCollection = false, bool shouldAddObjectName = false)
- {
- // Load existing configuration from a file or create a new JObject if necessary
- JObject configJson = new JObject();
-
- // Add or update the options in the configuration using the new method signature
- configJson = AddOptionsToConfiguration(configJson, options, path, objectName, optionFor, isCollection, shouldAddObjectName);
-
- // Return the updated JSON as a formatted string
- return configJson.ToString(Formatting.Indented);
- }
-
- // New method that updates the configuration
- public JObject AddOptionsToConfiguration(
- JObject configJson,
- TOptions options,
- string path,
- string objectName,
- string optionFor,
- bool isCollection = false,
- bool shouldAddObjectName = false)
- {
- // Initialize the JObject if it was null
- if (configJson == null)
- {
- configJson = new JObject();
- }
-
- // Split the path into its components
- string[] pathParts = path.Split(':');
- JObject currentSection = configJson;
-
- // Traverse or create the JSON structure for the section or collection
- for (int i = 0; i < pathParts.Length; i++)
- {
- // If this is the last part of the path
- if (i == pathParts.Length - 1)
- {
- if (isCollection)
- {
- // Ensure we have a JArray at this position
- if (currentSection[pathParts[i]] == null)
- {
- currentSection[pathParts[i]] = new JArray();
- }
-
- // Add the options object as part of the collection
- var collectionArray = (JArray)currentSection[pathParts[i]];
- var optionsObject = JObject.FromObject(options);
-
- // Add the object name if required
- if (shouldAddObjectName)
- {
- optionsObject.AddFirst(new JProperty(objectName, optionFor));
- }
-
- collectionArray.Add(optionsObject);
- }
- else
- {
- // We're at the last part of the path, so add the options object here
- var optionsObject = new JObject();
-
- // Add the object name and options
- if (shouldAddObjectName)
- {
- optionsObject[objectName] = optionFor;
- }
-
- // Add the other properties from the options object
- optionsObject.Merge(JObject.FromObject(options), new JsonMergeSettings
- {
- MergeArrayHandling = MergeArrayHandling.Concat
- });
-
- // Replace or add the object in the current section
- currentSection[pathParts[i]] = optionsObject;
- }
- }
- else
- {
- // Traverse or create the JObject for the current section
- if (currentSection[pathParts[i]] == null)
- {
- currentSection[pathParts[i]] = new JObject();
- }
- currentSection = (JObject)currentSection[pathParts[i]];
- }
- }
-
- // Return the modified JObject
- return configJson;
- }
-
-
-
-
-
-
- private ConfigurationMetadata GetOptionsConfiguration()
- {
- TOptions options = new TOptions();
- return options.ConfigurationMetadata;
- }
-
-
-
-
-
-
- }
-}
diff --git a/src/MigrationTools/ServiceCollectionExtensions.cs b/src/MigrationTools/ServiceCollectionExtensions.cs
index 47e16bb0a..d937eb13c 100644
--- a/src/MigrationTools/ServiceCollectionExtensions.cs
+++ b/src/MigrationTools/ServiceCollectionExtensions.cs
@@ -28,7 +28,7 @@ public static OptionsBuilder AddMigrationToolsOptions(this I
public static void AddMigrationToolServices(this IServiceCollection context, IConfiguration configuration, string configFile = "configuration.json")
{
- context.AddSingleton();
+ context.AddSingleton();
context.AddConfiguredEndpoints(configuration);
//Containers
context.AddTransient();