diff --git a/src/ServiceControl.Audit.UnitTests/PopulateAppSettingsTests.cs b/src/ServiceControl.Audit.UnitTests/PopulateAppSettingsTests.cs
new file mode 100644
index 0000000000..294e40cd78
--- /dev/null
+++ b/src/ServiceControl.Audit.UnitTests/PopulateAppSettingsTests.cs
@@ -0,0 +1,74 @@
+namespace ServiceControl.UnitTests;
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+using NUnit.Framework;
+
+[TestFixture]
+public class PopulateAppSettingsTests
+{
+ [Test]
+ public async Task Should_populate_appSettings_from_exe_config_file()
+ {
+ const string MagicValue = "7303A0AA-1003-4DC4-823B-4E8B2A35CF57";
+
+ var config = $"""
+
+
+
+
+
+
+ """;
+
+ await File.WriteAllTextAsync("ServiceControl.Audit.exe.config", config);
+
+ var fileName = "ServiceControl.Audit";
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ fileName = "ServiceControl.Audit.exe";
+ }
+
+ var startInfo = new ProcessStartInfo(fileName) { RedirectStandardOutput = true, UseShellExecute = false };
+
+ var p = Process.Start(startInfo);
+
+ if (p == null)
+ {
+ throw new Exception($"Failed to start {fileName}");
+ }
+
+ var pathIsSet = false;
+
+ var outputTask = Task.Run(async () =>
+ {
+ while (!p.StandardOutput.EndOfStream)
+ {
+ var line = await p.StandardOutput.ReadLineAsync();
+
+ Console.WriteLine(line);
+
+ if (line.Contains($"Logging to {MagicValue}"))
+ {
+ pathIsSet = true;
+ p.Kill(true);
+ }
+ }
+ });
+
+ if (!p.WaitForExit(5000))
+ {
+ p.Kill(true);
+ }
+
+ await outputTask;
+
+ Assert.That(pathIsSet, Is.True);
+ }
+
+ [TearDown]
+ public void TearDown() => File.Delete("ServiceControl.exe.config");
+}
\ No newline at end of file
diff --git a/src/ServiceControl.Audit/Program.cs b/src/ServiceControl.Audit/Program.cs
index dbe5268e93..763329c2f6 100644
--- a/src/ServiceControl.Audit/Program.cs
+++ b/src/ServiceControl.Audit/Program.cs
@@ -11,6 +11,8 @@
try
{
+ ExeConfiguration.PopulateAppSettings(Assembly.GetExecutingAssembly());
+
var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace);
LoggingConfigurator.ConfigureLogging(loggingSettings);
logger = LoggerUtil.CreateStaticLogger(typeof(Program));
@@ -25,7 +27,6 @@
return exitCode;
}
- ExeConfiguration.PopulateAppSettings(Assembly.GetExecutingAssembly());
var arguments = new HostArguments(args);
diff --git a/src/ServiceControl.Configuration/ExeConfiguration.cs b/src/ServiceControl.Configuration/ExeConfiguration.cs
index 2f0b0f3c5b..671d490ab3 100644
--- a/src/ServiceControl.Configuration/ExeConfiguration.cs
+++ b/src/ServiceControl.Configuration/ExeConfiguration.cs
@@ -1,5 +1,6 @@
namespace ServiceControl.Configuration
{
+ using System;
using System.Configuration;
using System.IO;
using System.Linq;
@@ -12,27 +13,37 @@ public static class ExeConfiguration
// This code reads in the exe.config files and adds all the values into the ConfigurationManager's collections.
public static void PopulateAppSettings(Assembly assembly)
{
- var location = Path.GetDirectoryName(assembly.Location);
- var assemblyName = Path.GetFileNameWithoutExtension(assembly.Location);
- var exeConfigPath = Path.Combine(location, $"{assemblyName}.exe.config");
- var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = exeConfigPath };
- var configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
-
- foreach (var key in configuration.AppSettings.Settings.AllKeys)
+ try
{
- ConfigurationManager.AppSettings.Set(key, configuration.AppSettings.Settings[key].Value);
+ var location = Path.GetDirectoryName(assembly.Location);
+ var assemblyName = Path.GetFileNameWithoutExtension(assembly.Location);
+ var exeConfigPath = Path.Combine(location, $"{assemblyName}.exe.config");
+ var fileMap = new ExeConfigurationFileMap
+ {
+ ExeConfigFilename = exeConfigPath
+ };
+ var configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
+
+ foreach (var key in configuration.AppSettings.Settings.AllKeys)
+ {
+ ConfigurationManager.AppSettings.Set(key, configuration.AppSettings.Settings[key].Value);
+ }
+
+ // The connection strings collection has had its read only flag set, so we need to clear it before we can add items to it
+ UnsetCollectionReadonly(ConfigurationManager.ConnectionStrings);
+
+ foreach (var connectionStringSetting in configuration.ConnectionStrings.ConnectionStrings.Cast())
+ {
+ ConfigurationManager.ConnectionStrings.Add(connectionStringSetting);
+ }
+
+ // Put the collection back into its previous state after we're done adding items to it
+ SetCollectionReadOnly(ConfigurationManager.ConnectionStrings);
}
-
- // The connection strings collection has had its read only flag set, so we need to clear it before we can add items to it
- UnsetCollectionReadonly(ConfigurationManager.ConnectionStrings);
-
- foreach (var connectionStringSetting in configuration.ConnectionStrings.ConnectionStrings.Cast())
+ catch (Exception e)
{
- ConfigurationManager.ConnectionStrings.Add(connectionStringSetting);
+ throw new Exception("Failed to populate app settings.", e);
}
-
- // Put the collection back into its previous state after we're done adding items to it
- SetCollectionReadOnly(ConfigurationManager.ConnectionStrings);
}
static void UnsetCollectionReadonly(ConfigurationElementCollection collection)
@@ -47,4 +58,4 @@ static void UnsetCollectionReadonly(ConfigurationElementCollection collection)
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "SetReadOnly")]
static extern void SetCollectionReadOnly(ConfigurationElementCollection collection);
}
-}
+}
\ No newline at end of file
diff --git a/src/ServiceControl.Monitoring.UnitTests/PopulateAppSettingsTests.cs b/src/ServiceControl.Monitoring.UnitTests/PopulateAppSettingsTests.cs
new file mode 100644
index 0000000000..b7abd42264
--- /dev/null
+++ b/src/ServiceControl.Monitoring.UnitTests/PopulateAppSettingsTests.cs
@@ -0,0 +1,78 @@
+namespace ServiceControl.UnitTests;
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+using NUnit.Framework;
+
+[TestFixture]
+public class PopulateAppSettingsTests
+{
+ [Test]
+ public async Task Should_populate_appSettings_from_exe_config_file()
+ {
+ const string MagicValue = "7303A0AA-1003-4DC4-823B-4E8B2A35CF57";
+
+ var config = $"""
+
+
+
+
+
+
+ """;
+
+ await File.WriteAllTextAsync("ServiceControl.Monitoring.exe.config", config);
+
+ var fileName = "ServiceControl.Monitoring";
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ fileName = "ServiceControl.Monitoring.exe";
+ }
+
+ var startInfo = new ProcessStartInfo(fileName)
+ {
+ RedirectStandardOutput = true,
+ UseShellExecute = false
+ };
+
+ var p = Process.Start(startInfo);
+
+ if (p == null)
+ {
+ throw new Exception($"Failed to start {fileName}");
+ }
+
+ var pathIsSet = false;
+
+ var outputTask = Task.Run(async () =>
+ {
+ while (!p.StandardOutput.EndOfStream)
+ {
+ var line = await p.StandardOutput.ReadLineAsync();
+
+ Console.WriteLine(line);
+
+ if (line.Contains($"Logging to {MagicValue}"))
+ {
+ pathIsSet = true;
+ p.Kill(true);
+ }
+ }
+ });
+
+ if (!p.WaitForExit(5000))
+ {
+ p.Kill(true);
+ }
+
+ await outputTask;
+
+ Assert.That(pathIsSet, Is.True);
+ }
+
+ [TearDown]
+ public void TearDown() => File.Delete("ServiceControl.exe.config");
+}
\ No newline at end of file
diff --git a/src/ServiceControl.Monitoring/Program.cs b/src/ServiceControl.Monitoring/Program.cs
index e8dce81512..81393c0c61 100644
--- a/src/ServiceControl.Monitoring/Program.cs
+++ b/src/ServiceControl.Monitoring/Program.cs
@@ -9,6 +9,8 @@
try
{
+ ExeConfiguration.PopulateAppSettings(Assembly.GetExecutingAssembly());
+
var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace);
LoggingConfigurator.ConfigureLogging(loggingSettings);
logger = LoggerUtil.CreateStaticLogger(typeof(Program));
@@ -23,8 +25,6 @@
return exitCode;
}
- ExeConfiguration.PopulateAppSettings(Assembly.GetExecutingAssembly());
-
var arguments = new HostArguments(args);
var settings = new Settings(loggingSettings: loggingSettings);
diff --git a/src/ServiceControl.UnitTests/PopulateAppSettingsTests.cs b/src/ServiceControl.UnitTests/PopulateAppSettingsTests.cs
new file mode 100644
index 0000000000..28b5e3e088
--- /dev/null
+++ b/src/ServiceControl.UnitTests/PopulateAppSettingsTests.cs
@@ -0,0 +1,76 @@
+namespace ServiceControl.UnitTests;
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+using NUnit.Framework;
+
+[TestFixture]
+public class PopulateAppSettingsTests
+{
+ [Test]
+ public async Task Should_populate_appSettings_from_exe_config_file()
+ {
+ const string MagicValue = "7303A0AA-1003-4DC4-823B-4E8B2A35CF57";
+
+ var config = $"""
+
+
+
+
+
+
+ """;
+
+ await File.WriteAllTextAsync("ServiceControl.exe.config", config);
+
+ var fileName = "ServiceControl";
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ fileName = "ServiceControl.exe";
+ }
+
+ var startInfo = new ProcessStartInfo(fileName)
+ {
+ RedirectStandardOutput = true,
+ UseShellExecute = false
+ };
+
+ var p = Process.Start(startInfo);
+
+ if (p == null)
+ {
+ throw new Exception("Failed to start ServiceControl");
+ }
+
+ var pathIsSet = false;
+
+ var outputTask = Task.Run(async () =>
+ {
+ while (!p.StandardOutput.EndOfStream)
+ {
+ var line = await p.StandardOutput.ReadLineAsync();
+
+ if (line.Contains($"Logging to {MagicValue}"))
+ {
+ pathIsSet = true;
+ p.Kill(true);
+ }
+ }
+ });
+
+ if (!p.WaitForExit(5000))
+ {
+ p.Kill(true);
+ }
+
+ await outputTask;
+
+ Assert.That(pathIsSet, Is.True);
+ }
+
+ [TearDown]
+ public void TearDown() => File.Delete("ServiceControl.exe.config");
+}
\ No newline at end of file
diff --git a/src/ServiceControl/Program.cs b/src/ServiceControl/Program.cs
index ec4a0bc70d..857ed0a782 100644
--- a/src/ServiceControl/Program.cs
+++ b/src/ServiceControl/Program.cs
@@ -11,6 +11,8 @@
try
{
+ ExeConfiguration.PopulateAppSettings(Assembly.GetExecutingAssembly());
+
var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace);
LoggingConfigurator.ConfigureLogging(loggingSettings);
logger = LoggerUtil.CreateStaticLogger(typeof(Program));
@@ -25,8 +27,6 @@
return exitCode;
}
- ExeConfiguration.PopulateAppSettings(Assembly.GetExecutingAssembly());
-
var arguments = new HostArguments(args);
if (arguments.Help)