diff --git a/Source/Microsoft.Gateway/Microsoft.InnerEye.Gateway.Logging/ServiceStatus.cs b/Source/Microsoft.Gateway/Microsoft.InnerEye.Gateway.Logging/ServiceStatus.cs
index be9be32..65c3a93 100644
--- a/Source/Microsoft.Gateway/Microsoft.InnerEye.Gateway.Logging/ServiceStatus.cs
+++ b/Source/Microsoft.Gateway/Microsoft.InnerEye.Gateway.Logging/ServiceStatus.cs
@@ -56,6 +56,11 @@
///
NewConfigurationError,
+ ///
+ /// Configuration files have changed.
+ ///
+ NewConfigurationDetetected,
+
///
/// Error in ping.
///
diff --git a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Common/Providers/AETConfigProvider.cs b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Common/Providers/AETConfigProvider.cs
index 59c6536..24d3f93 100644
--- a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Common/Providers/AETConfigProvider.cs
+++ b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Common/Providers/AETConfigProvider.cs
@@ -6,17 +6,17 @@
using Microsoft.Extensions.Logging;
///
- /// Monitor a JSON file containing a list of AETConfigModels.
+ /// Monitor a JSON file or folder containing a list of .
///
- public class AETConfigProvider : BaseConfigProvider>
+ public class AETConfigProvider : BaseConfigProvider>
{
///
- /// File name for JSON file containing a list of AETConfigModels.
+ /// File name for JSON file containing a list of .
///
public static readonly string AETConfigFileName = "GatewayModelRulesConfig.json";
///
- /// Folder name for folder containing JSON files, each containing a list of AETConfigModels.
+ /// Folder name for folder containing JSON files, each containing a list of .
///
public static readonly string AETConfigFolderName = "GatewayModelRulesConfig";
@@ -30,25 +30,18 @@
ILogger logger,
string configurationsPathRoot,
bool useFile = false) : base(logger,
- Path.Combine(configurationsPathRoot, useFile ? AETConfigFileName : AETConfigFolderName))
+ Path.Combine(configurationsPathRoot, useFile ? string.Empty : AETConfigFolderName),
+ useFile ? AETConfigFileName : string.Empty,
+ MergeModels)
{
}
///
- /// Lookup list of AETConfigModels from a JSON file.
+ /// Helper to create a for returning list of from cache.
///
- /// List of AETConfigModels.
- public IEnumerable GetAETConfigs()
- {
- Load();
-
- _t = _ts != null ? MergeModels(_ts) : _t;
-
- // no need to keep two copies of all the config data.
- _ts = null;
-
- return _t;
- }
+ /// Cached list of .
+ public IEnumerable AETConfigModels() =>
+ Config;
///
/// Merge a list of lists of AET config models into one list.
@@ -64,7 +57,7 @@
///
/// List of lists of AET config models.
/// List of AET config models.
- private static List MergeModels(IEnumerable> modelLists)
+ private static List MergeModels(IEnumerable> modelLists)
{
var mergedModels = new List();
diff --git a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Common/Providers/BaseConfigProvider.cs b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Common/Providers/BaseConfigProvider.cs
index 6c70e9c..858182a 100644
--- a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Common/Providers/BaseConfigProvider.cs
+++ b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Common/Providers/BaseConfigProvider.cs
@@ -12,8 +12,50 @@
/// Class that monitors a JSON settings file or folder.
///
/// Data type underlying the JSON settings.
- public class BaseConfigProvider
+ public class BaseConfigProvider : IDisposable
{
+ ///
+ /// Class to hold results from trying to open and parse a possible JSON file.
+ ///
+ private class LoadJsonResult
+ {
+ ///
+ /// True if the file has loaded, false otherwise.
+ ///
+ ///
+ /// The FileSystemWatcher can report file changed events whilst another process is saving
+ /// a file. In this case there may be a System.IO.IOException (“File used by another process”).
+ ///
+ public bool Loaded { get; }
+
+ ///
+ /// True if the file has been parsed, false otherwise.
+ ///
+ ///
+ /// In the case of loading from a folder, all files are loaded and parsed. There may be other files
+ /// there and they are to be ignored.
+ ///
+ public bool Parsed { get; }
+
+ ///
+ /// An instance of type T if the file has been loaded and parsed correctly. Default(T) otherwise.
+ ///
+ public T Result { get; }
+
+ ///
+ /// Initialize a new instance of the class.
+ ///
+ /// True if file loaded.
+ /// True if file parsed.
+ /// Instance of type T if loaded and parsed.
+ public LoadJsonResult(bool loaded, bool parsed, T result)
+ {
+ Loaded = loaded;
+ Parsed = parsed;
+ Result = result;
+ }
+ }
+
///
/// Logger for errors loading or parsing JSON.
///
@@ -25,60 +67,139 @@
private readonly string _settingsFileOrFolderName;
///
- /// Cached copy of data as last loaded from JSON file.
+ /// Optional flat map to handle folders.
///
- protected T _t;
+ private readonly Func, T> _flatMap;
///
- /// Cached copy of data as last loaded from folder of JSON files.
+ /// File system watcher to monitor changes to file or folder.
///
- protected IEnumerable _ts;
+ private readonly FileSystemWatcher _fileSystemWatcher;
+
+ ///
+ /// Disposed flag for IDisposable.
+ ///
+ private bool disposedValue;
+
+ ///
+ /// Config as last loaded from file or folder.
+ ///
+ public T Config { get; private set; }
+
+ ///
+ /// Called when the config has changed.
+ ///
+ public event EventHandler ConfigChanged;
///
/// Initialize a new instance of the class.
///
/// Logger.
- /// JSON settings file or folder.
+ /// Settings folder name.
+ /// Optional settings file, use String.Empty to monitor a folder.
+ /// Optional flat map to handle folders. This should merge a T from each file in the folder
+ /// into a single new T. This is required if monitoring a folder.
public BaseConfigProvider(
ILogger logger,
- string settingsFileOrFolderName)
+ string folderName,
+ string settingsFile,
+ Func, T> flatMap = null)
{
_logger = logger;
- _settingsFileOrFolderName = settingsFileOrFolderName;
+ _settingsFileOrFolderName = Path.Combine(folderName, settingsFile);
+ _flatMap = flatMap;
+
+ if (string.IsNullOrWhiteSpace(settingsFile) && flatMap == null)
+ {
+ throw new ArgumentNullException(nameof(flatMap), "If monitoring a folder, flatMap must be supplied");
+ }
+
+ _fileSystemWatcher = new FileSystemWatcher(folderName)
+ {
+ Filter = !string.IsNullOrWhiteSpace(settingsFile) ? settingsFile : "*.json",
+ NotifyFilter = NotifyFilters.LastWrite,
+ };
+
+ _fileSystemWatcher.Changed += OnChanged;
+ _fileSystemWatcher.EnableRaisingEvents = true;
+
+ Load();
}
///
- /// Load T or Ts from a JSON file or folder.
+ /// File watcher Changed event handler. Filter the events, reload the config and if successful invoke ConfigChanged.
///
- protected void Load()
+ /// Sender.
+ /// File system event args.
+ private void OnChanged(object sender, FileSystemEventArgs e)
+ {
+ if (e.ChangeType != WatcherChangeTypes.Changed)
+ {
+ return;
+ }
+
+ var logEntry = LogEntry.Create(ServiceStatus.NewConfigurationDetetected,
+ string.Format("Settings have changed: {0}", e.FullPath));
+ logEntry.Log(_logger, LogLevel.Information);
+
+ if (!Load())
+ {
+ return;
+ }
+
+ ConfigChanged?.Invoke(this, new EventArgs());
+ }
+
+ ///
+ /// Load T from a JSON file or folder.
+ ///
+ /// True if new config has been loaded, false otherwise.
+ private bool Load()
{
if (File.Exists(_settingsFileOrFolderName))
{
- _ts = null;
+ var loadJsonResult = LoadFile(_settingsFileOrFolderName);
- (_t, _) = LoadFile(_settingsFileOrFolderName);
+ if (!loadJsonResult.Loaded || !loadJsonResult.Parsed)
+ {
+ return false;
+ }
+
+ Config = loadJsonResult.Result;
+
+ return true;
}
else if (Directory.Exists(_settingsFileOrFolderName))
{
- _t = default(T);
var ts = new List();
foreach (var file in Directory.EnumerateFiles(_settingsFileOrFolderName, "*.json"))
{
- var (t, loaded) = LoadFile(file);
- if (loaded)
+ var loadJsonResult = LoadFile(file);
+ if (!loadJsonResult.Loaded)
{
- ts.Add(t);
+ // File still in use, FileWatcher has reported file changed but
+ // the other process has not finished yet.
+ return false;
+ }
+
+ if (loadJsonResult.Parsed)
+ {
+ ts.Add(loadJsonResult.Result);
}
}
- _ts = ts.ToArray();
+ Config = _flatMap(ts);
+
+ return true;
}
else
{
var logEntry = LogEntry.Create(ServiceStatus.NewConfigurationError,
string.Format("Settings is neither a file nor a folder: {0}", _settingsFileOrFolderName));
logEntry.Log(_logger, LogLevel.Error);
+
+ return false;
}
}
@@ -86,49 +207,62 @@
/// Update settings file, according to an update callback function.
///
/// Callback to update the settings. Return new settings for update, or the same object to not update.
- /// How to compare objects.
- protected void UpdateFile(Func updater, IEqualityComparer equalityComparer)
+ /// Optional, how to compare objects.
+ public (T, bool) Update(Func updater, IEqualityComparer equalityComparer = null)
{
if (!File.Exists(_settingsFileOrFolderName))
{
throw new NotImplementedException(string.Format("Can only update single settings files: {0}", _settingsFileOrFolderName));
}
- var (t, loaded) = LoadFile(_settingsFileOrFolderName);
- if (!loaded)
+ var loadJsonResult = LoadFile(_settingsFileOrFolderName);
+ if (!loadJsonResult.Loaded || !loadJsonResult.Parsed)
{
- return;
+ return (default(T), false);
}
- var newt = updater.Invoke(t);
- if (equalityComparer.Equals(newt, t))
+ var newt = updater(loadJsonResult.Result);
+
+ equalityComparer = equalityComparer ?? EqualityComparer.Default;
+
+ if (equalityComparer.Equals(newt, loadJsonResult.Result))
{
- return;
+ return (default(T), false);
}
SaveFile(newt, _settingsFileOrFolderName);
+
+ return (newt, true);
}
///
/// Load T from a JSON file.
///
/// Path to file.
- /// Pair of T and true if file loaded correctly, false otherwise.
- private (T, bool) LoadFile(string path)
+ /// New .
+ private LoadJsonResult LoadFile(string path)
{
try
{
var jsonText = File.ReadAllText(path);
- return (JsonConvert.DeserializeObject(jsonText), true);
+ return new LoadJsonResult(true, true, JsonConvert.DeserializeObject(jsonText));
}
- catch (Exception e)
+ catch (JsonSerializationException e)
+ {
+ var logEntry = LogEntry.Create(ServiceStatus.NewConfigurationError,
+ string.Format("Unable to parse settings file {0}", path));
+ logEntry.Log(_logger, LogLevel.Error, e);
+
+ return new LoadJsonResult(true, false, default(T));
+ }
+ catch (IOException e)
{
var logEntry = LogEntry.Create(ServiceStatus.NewConfigurationError,
string.Format("Unable to load settings file {0}", path));
logEntry.Log(_logger, LogLevel.Error, e);
- return (default(T), false);
+ return new LoadJsonResult(false, false, default(T));
}
}
@@ -149,5 +283,33 @@
var jsonText = JsonConvert.SerializeObject(t, serializerSettings);
File.WriteAllText(path, jsonText);
}
+
+ ///
+ /// Disposes of all managed resources.
+ ///
+ /// If we are disposing.
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposedValue)
+ {
+ return;
+ }
+
+ if (disposing)
+ {
+ _fileSystemWatcher.Dispose();
+ }
+
+ disposedValue = true;
+ }
+
+ ///
+ /// Implements the disposable pattern.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
}
}
diff --git a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Common/Providers/GatewayProcessorConfigProvider.cs b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Common/Providers/GatewayProcessorConfigProvider.cs
index 74ec29a..c8cfc96 100644
--- a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Common/Providers/GatewayProcessorConfigProvider.cs
+++ b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Common/Providers/GatewayProcessorConfigProvider.cs
@@ -1,20 +1,18 @@
namespace Microsoft.InnerEye.Listener.Common.Providers
{
using System;
- using System.Collections.Generic;
- using System.IO;
using Microsoft.Extensions.Logging;
using Microsoft.InnerEye.Azure.Segmentation.Client;
using Microsoft.InnerEye.Gateway.Logging;
using Microsoft.InnerEye.Gateway.Models;
///
- /// Monitor a JSON file containing a GatewayProcessorConfig.
+ /// Monitor a JSON file containing a .
///
public class GatewayProcessorConfigProvider : BaseConfigProvider
{
///
- /// File name for JSON file containing a GatewayProcessorConfig.
+ /// File name for JSON file containing a .
///
public static readonly string GatewayProcessorConfigFileName = "GatewayProcessorConfig.json";
@@ -26,27 +24,10 @@
public GatewayProcessorConfigProvider(
ILogger logger,
string configurationsPathRoot) : base(logger,
- Path.Combine(configurationsPathRoot, GatewayProcessorConfigFileName))
+ configurationsPathRoot, GatewayProcessorConfigFileName)
{
}
- ///
- /// Load GatewayProcessorConfig from a JSON file.
- ///
- /// Loaded GatewayProcessorConfig.
- public GatewayProcessorConfig GatewayProcessorConfig()
- {
- Load();
- return _t;
- }
-
- ///
- /// Update GatewayProcessorConfig file, according to an update callback function.
- ///
- /// Callback to update the settings. Return new settings for update, or the same object to not update.
- public void Update(Func updater) =>
- UpdateFile(updater, EqualityComparer.Default);
-
///
/// Set ServiceSettings.RunAsConsole.
///
@@ -55,7 +36,7 @@
Update(gatewayProcessorConfig => gatewayProcessorConfig.With(new ServiceSettings(runAsConsole)));
///
- /// Update ProcessorSettings.
+ /// Update .
///
/// Optional new inference API Uri.
/// Optional new license key.
@@ -78,45 +59,45 @@
}
///
- /// Load ServiceSettings from a JSON file.
+ /// Helper to create a for returning from cached .
///
- /// Loaded ServiceSettings.
+ /// Cached .
public ServiceSettings ServiceSettings() =>
- GatewayProcessorConfig().ServiceSettings;
+ Config.ServiceSettings;
///
- /// Load ProcessorSettings from a JSON file.
+ /// Helper to create a for returning from cached .
///
- /// Loaded ProcessorSettings.
+ /// Cached .
public ProcessorSettings ProcessorSettings() =>
- GatewayProcessorConfig().ProcessorSettings;
+ Config.ProcessorSettings;
///
- /// Load DequeueServiceConfig from a JSON file.
+ /// Helper to create a for returning from cached .
///
- /// Loaded DequeueServiceConfig.
+ /// Cached .
public DequeueServiceConfig DequeueServiceConfig() =>
- GatewayProcessorConfig().DequeueServiceConfig;
+ Config.DequeueServiceConfig;
///
- /// Load DownloadServiceConfig from a JSON file.
+ /// Helper to create a for returning from cached .
///
- /// Loaded DownloadServiceConfig.
+ /// Cached .
public DownloadServiceConfig DownloadServiceConfig() =>
- GatewayProcessorConfig().DownloadServiceConfig;
+ Config.DownloadServiceConfig;
///
- /// Load ConfigurationServiceConfig from a JSON file.
+ /// Helper to create a for returning from cached .
///
- /// Loaded ConfigurationServiceConfig.
+ /// Cached .
public ConfigurationServiceConfig ConfigurationServiceConfig() =>
- GatewayProcessorConfig().ConfigurationServiceConfig;
+ Config.ConfigurationServiceConfig;
///
- /// Create a new segmentation client based on settings in JSON file.
+ /// Create a new based on settings in JSON file.
///
/// Optional logger for client.
- /// New IInnerEyeSegmentationClient.
+ /// New .
public Func CreateInnerEyeSegmentationClient(ILogger logger = null) =>
() =>
{
diff --git a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Common/Providers/GatewayReceiveConfigProvider.cs b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Common/Providers/GatewayReceiveConfigProvider.cs
index e56e242..1731529 100644
--- a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Common/Providers/GatewayReceiveConfigProvider.cs
+++ b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Common/Providers/GatewayReceiveConfigProvider.cs
@@ -1,18 +1,15 @@
namespace Microsoft.InnerEye.Listener.Common.Providers
{
- using System;
- using System.Collections.Generic;
- using System.IO;
using Microsoft.Extensions.Logging;
using Microsoft.InnerEye.Gateway.Models;
///
- /// Monitor a JSON file containing a GatewayReceiveConfig.
+ /// Monitor a JSON file containing a .
///
public class GatewayReceiveConfigProvider : BaseConfigProvider
{
///
- /// File name for JSON file containing a GatewayReceiveConfig.
+ /// File name for JSON file containing a .
///
public static readonly string GatewayReceiveConfigFileName = "GatewayReceiveConfig.json";
@@ -24,27 +21,10 @@
public GatewayReceiveConfigProvider(
ILogger logger,
string configurationsPathRoot) : base(logger,
- Path.Combine(configurationsPathRoot, GatewayReceiveConfigFileName))
+ configurationsPathRoot, GatewayReceiveConfigFileName)
{
}
- ///
- /// Load GatewayReceiveConfig from a JSON file.
- ///
- /// Loaded GatewayReceiveConfig.
- public GatewayReceiveConfig GatewayReceiveConfig()
- {
- Load();
- return _t;
- }
-
- ///
- /// Update GatewayReceiveConfig file, according to an update callback function.
- ///
- /// Callback to update the settings. Return new settings for update, or the same object to not update.
- public void Update(Func updater) =>
- UpdateFile(updater, EqualityComparer.Default);
-
///
/// Set ServiceSettings.RunAsConsole.
///
@@ -53,24 +33,24 @@
Update(gatewayReceiveConfig => gatewayReceiveConfig.With(new ServiceSettings(runAsConsole)));
///
- /// Load ServiceSettings from a JSON file.
+ /// Helper to create a for returning from cached .
///
- /// Loaded ServiceSettings.
+ /// Cached .
public ServiceSettings ServiceSettings() =>
- GatewayReceiveConfig().ServiceSettings;
+ Config.ServiceSettings;
///
- /// Load ConfigurationServiceConfig from a JSON file.
+ /// Helper to create a for returning from cached .
///
- /// Loaded ConfigurationServiceConfig.
+ /// Cached .
public ConfigurationServiceConfig ConfigurationServiceConfig() =>
- GatewayReceiveConfig().ConfigurationServiceConfig;
+ Config.ConfigurationServiceConfig;
///
- /// Load ReceiveServiceConfig from a JSON file.
+ /// Helper to create a for returning from cached .
///
- /// Loaded ReceiveServiceConfig.
+ /// Cached .
public ReceiveServiceConfig ReceiveServiceConfig() =>
- GatewayReceiveConfig().ReceiveServiceConfig;
+ Config.ReceiveServiceConfig;
}
}
diff --git a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Processor/Program.cs b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Processor/Program.cs
index b69a6ca..c528fe8 100644
--- a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Processor/Program.cs
+++ b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Processor/Program.cs
@@ -34,55 +34,55 @@
var configurationsPathRoot = ConfigurationService.FindRelativeDirectory(relativePaths, loggerFactory.CreateLogger("Main"));
- var aetConfigurationProvider = new AETConfigProvider(
- loggerFactory.CreateLogger("ModelSettings"),
- configurationsPathRoot);
+ using (var aetConfigurationProvider = new AETConfigProvider(
+ loggerFactory.CreateLogger("ModelSettings"),
+ configurationsPathRoot))
+ using (var gatewayProcessorConfigProvider = new GatewayProcessorConfigProvider(
+ loggerFactory.CreateLogger("ProcessorSettings"),
+ configurationsPathRoot))
+ {
+ var segmentationClientLogger = loggerFactory.CreateLogger("SegmentationClient");
- var gatewayProcessorConfigProvider = new GatewayProcessorConfigProvider(
- loggerFactory.CreateLogger("ProcessorSettings"),
- configurationsPathRoot);
-
- var segmentationClientLogger = loggerFactory.CreateLogger("SegmentationClient");
-
- // The ProjectInstaller.cs uses the service name to install the service.
- // If you change it please update the ProjectInstaller.cs
- ServiceHelpers.RunServices(
- ServiceName,
- gatewayProcessorConfigProvider.ServiceSettings(),
- new ConfigurationService(
- gatewayProcessorConfigProvider.CreateInnerEyeSegmentationClient(segmentationClientLogger),
- gatewayProcessorConfigProvider.ConfigurationServiceConfig,
- loggerFactory.CreateLogger("ConfigurationService"),
- new UploadService(
+ // The ProjectInstaller.cs uses the service name to install the service.
+ // If you change it please update the ProjectInstaller.cs
+ ServiceHelpers.RunServices(
+ ServiceName,
+ gatewayProcessorConfigProvider.ServiceSettings(),
+ new ConfigurationService(
gatewayProcessorConfigProvider.CreateInnerEyeSegmentationClient(segmentationClientLogger),
- aetConfigurationProvider.GetAETConfigs,
- GatewayMessageQueue.UploadQueuePath,
- GatewayMessageQueue.DownloadQueuePath,
- GatewayMessageQueue.DeleteQueuePath,
- gatewayProcessorConfigProvider.DequeueServiceConfig,
- loggerFactory.CreateLogger("UploadService"),
- instances: 2),
- new DownloadService(
- gatewayProcessorConfigProvider.CreateInnerEyeSegmentationClient(segmentationClientLogger),
- GatewayMessageQueue.DownloadQueuePath,
- GatewayMessageQueue.PushQueuePath,
- GatewayMessageQueue.DeleteQueuePath,
- gatewayProcessorConfigProvider.DownloadServiceConfig,
- gatewayProcessorConfigProvider.DequeueServiceConfig,
- loggerFactory.CreateLogger("DownloadService"),
- instances: 1),
- new PushService(
- aetConfigurationProvider.GetAETConfigs,
- new DicomDataSender(),
- GatewayMessageQueue.PushQueuePath,
- GatewayMessageQueue.DeleteQueuePath,
- gatewayProcessorConfigProvider.DequeueServiceConfig,
- loggerFactory.CreateLogger("PushService"),
- instances: 1),
- new DeleteService(
- GatewayMessageQueue.DeleteQueuePath,
- gatewayProcessorConfigProvider.DequeueServiceConfig,
- loggerFactory.CreateLogger("DeleteService"))));
+ gatewayProcessorConfigProvider.ConfigurationServiceConfig,
+ loggerFactory.CreateLogger("ConfigurationService"),
+ new UploadService(
+ gatewayProcessorConfigProvider.CreateInnerEyeSegmentationClient(segmentationClientLogger),
+ aetConfigurationProvider.AETConfigModels,
+ GatewayMessageQueue.UploadQueuePath,
+ GatewayMessageQueue.DownloadQueuePath,
+ GatewayMessageQueue.DeleteQueuePath,
+ gatewayProcessorConfigProvider.DequeueServiceConfig,
+ loggerFactory.CreateLogger("UploadService"),
+ instances: 2),
+ new DownloadService(
+ gatewayProcessorConfigProvider.CreateInnerEyeSegmentationClient(segmentationClientLogger),
+ GatewayMessageQueue.DownloadQueuePath,
+ GatewayMessageQueue.PushQueuePath,
+ GatewayMessageQueue.DeleteQueuePath,
+ gatewayProcessorConfigProvider.DownloadServiceConfig,
+ gatewayProcessorConfigProvider.DequeueServiceConfig,
+ loggerFactory.CreateLogger("DownloadService"),
+ instances: 1),
+ new PushService(
+ aetConfigurationProvider.AETConfigModels,
+ new DicomDataSender(),
+ GatewayMessageQueue.PushQueuePath,
+ GatewayMessageQueue.DeleteQueuePath,
+ gatewayProcessorConfigProvider.DequeueServiceConfig,
+ loggerFactory.CreateLogger("PushService"),
+ instances: 1),
+ new DeleteService(
+ GatewayMessageQueue.DeleteQueuePath,
+ gatewayProcessorConfigProvider.DequeueServiceConfig,
+ loggerFactory.CreateLogger("DeleteService"))));
+ }
}
}
}
diff --git a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Receiver/Program.cs b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Receiver/Program.cs
index a0cff82..4b18a08 100644
--- a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Receiver/Program.cs
+++ b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Receiver/Program.cs
@@ -33,23 +33,24 @@
var configurationsPathRoot = ConfigurationService.FindRelativeDirectory(relativePaths, loggerFactory.CreateLogger("Main"));
- var gatewayReceiveConfigProvider = new GatewayReceiveConfigProvider(
+ using (var gatewayReceiveConfigProvider = new GatewayReceiveConfigProvider(
loggerFactory.CreateLogger("ProcessorSettings"),
- configurationsPathRoot);
-
- // The ProjectInstaller.cs uses the service name to install the service.
- // If you change it please update the ProjectInstaller.cs
- ServiceHelpers.RunServices(
- ServiceName,
- gatewayReceiveConfigProvider.ServiceSettings(),
- new ConfigurationService(
- null,
- gatewayReceiveConfigProvider.ConfigurationServiceConfig,
- loggerFactory.CreateLogger("ConfigurationService"),
- new ReceiveService(
- gatewayReceiveConfigProvider.ReceiveServiceConfig,
- GatewayMessageQueue.UploadQueuePath,
- loggerFactory.CreateLogger("ReceiveService"))));
+ configurationsPathRoot))
+ {
+ // The ProjectInstaller.cs uses the service name to install the service.
+ // If you change it please update the ProjectInstaller.cs
+ ServiceHelpers.RunServices(
+ ServiceName,
+ gatewayReceiveConfigProvider.ServiceSettings(),
+ new ConfigurationService(
+ null,
+ gatewayReceiveConfigProvider.ConfigurationServiceConfig,
+ loggerFactory.CreateLogger("ConfigurationService"),
+ new ReceiveService(
+ gatewayReceiveConfigProvider.ReceiveServiceConfig,
+ GatewayMessageQueue.UploadQueuePath,
+ loggerFactory.CreateLogger("ReceiveService"))));
+ }
}
}
}
diff --git a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/BaseTestClass.cs b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/BaseTestClass.cs
index a9d2db6..0067ed1 100644
--- a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/BaseTestClass.cs
+++ b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/BaseTestClass.cs
@@ -34,7 +34,7 @@
/// The base test class.
///
[TestClass]
- public class BaseTestClass
+ public class BaseTestClass : IDisposable
{
///
/// List of chars to use for random string generation.
@@ -44,12 +44,12 @@
///
/// LoggerFactory for creating more ILoggers.
///
- protected readonly Microsoft.Extensions.Logging.ILoggerFactory _loggerFactory;
+ private readonly Microsoft.Extensions.Logging.ILoggerFactory _loggerFactory;
///
/// Logger for common use.
///
- protected readonly ILogger _baseTestLogger;
+ private readonly ILogger _baseTestLogger;
///
/// Gets or sets the test context.
@@ -110,7 +110,12 @@
///
/// GatewayReceiveConfigProvider as loaded from _basePathConfigs.
///
- private GatewayReceiveConfigProvider _testGatewayReceiveConfigProvider;
+ protected GatewayReceiveConfigProvider TestGatewayReceiveConfigProvider { get; }
+
+ ///
+ /// Disposed flag for IDisposable.
+ ///
+ private bool disposedValue;
///
/// Initializes a new instance of the class.
@@ -125,9 +130,9 @@
// Set a logger for fo-dicom network operations so that they show up in VS output when debugging
Dicom.Log.LogManager.SetImplementation(new Dicom.Log.TextWriterLogManager(new DataProviderTests.DebugTextWriter()));
- _testAETConfigProvider = new AETConfigProvider(_loggerFactory.CreateLogger("ModelSettings"), _basePathConfigs);
- TestGatewayProcessorConfigProvider = new GatewayProcessorConfigProvider(_loggerFactory.CreateLogger("ProcessorSettings"), _basePathConfigs);
- _testGatewayReceiveConfigProvider = new GatewayReceiveConfigProvider(_loggerFactory.CreateLogger("ProcessorSettings"), _basePathConfigs);
+ _testAETConfigProvider = CreateAETConfigProvider(_basePathConfigs);
+ TestGatewayProcessorConfigProvider = CreateGatewayProcessorConfigProvider(_basePathConfigs);
+ TestGatewayReceiveConfigProvider = CreateGatewayReceiveConfigProvider(_basePathConfigs);
}
[TestInitialize]
@@ -170,6 +175,35 @@
TryKillAnyZombieProcesses();
}
+ ///
+ /// Create a new based on the given folder.
+ ///
+ /// Path to folder containing config folder.
+ /// True to use config file, false to use folder of files.
+ /// New .
+ protected AETConfigProvider CreateAETConfigProvider(
+ string configurationsPathRoot,
+ bool useFile = false) =>
+ new AETConfigProvider(_loggerFactory.CreateLogger("ModelSettings"), configurationsPathRoot, useFile);
+
+ ///
+ /// Create a new based on the given folder.
+ ///
+ /// Path to folder containing config file.
+ /// New .
+ protected GatewayProcessorConfigProvider CreateGatewayProcessorConfigProvider(
+ string configurationsPathRoot) =>
+ new GatewayProcessorConfigProvider(_loggerFactory.CreateLogger("ProcessorSettings"), configurationsPathRoot);
+
+ ///
+ /// Create a new based on the given folder.
+ ///
+ /// Path to folder containing config file.
+ /// New .
+ protected GatewayReceiveConfigProvider CreateGatewayReceiveConfigProvider(
+ string configurationsPathRoot) =>
+ new GatewayReceiveConfigProvider(_loggerFactory.CreateLogger("ReceiveSettings"), configurationsPathRoot);
+
protected void WriteDicomFileForBuildPackage(string fileName, DicomFile dicomFile)
{
var path = GetBuildPackageResultPath(fileName, "AnonymisationProtocols");
@@ -312,7 +346,7 @@
}
protected AETConfigModel GetTestAETConfigModel() =>
- _testAETConfigProvider.GetAETConfigs().First();
+ _testAETConfigProvider.Config.First();
///
/// Create ReceiveServiceConfig from test files, but overwrite the port and rootDicomFolder.
@@ -324,7 +358,7 @@
int port,
DirectoryInfo rootDicomFolder = null)
{
- var gatewayConfig = _testGatewayReceiveConfigProvider.GatewayReceiveConfig().ReceiveServiceConfig;
+ var gatewayConfig = TestGatewayReceiveConfigProvider.Config.ReceiveServiceConfig;
return gatewayConfig.With(
new DicomEndPoint(gatewayConfig.GatewayDicomEndPoint.Title, port, gatewayConfig.GatewayDicomEndPoint.Ip),
@@ -522,7 +556,7 @@
protected PushService CreatePushService(
Func> aetConfigProvider = null) =>
new PushService(
- aetConfigProvider ?? _testAETConfigProvider.GetAETConfigs,
+ aetConfigProvider ?? _testAETConfigProvider.AETConfigModels,
new DicomDataSender(),
TestPushQueuePath,
TestDeleteQueuePath,
@@ -560,7 +594,7 @@
int instances = 1) =>
new UploadService(
innerEyeSegmentationClient != null ? () => innerEyeSegmentationClient : TestGatewayProcessorConfigProvider.CreateInnerEyeSegmentationClient(),
- aetConfigProvider ?? _testAETConfigProvider.GetAETConfigs,
+ aetConfigProvider ?? _testAETConfigProvider.AETConfigModels,
TestUploadQueuePath,
TestDownloadQueuePath,
TestDeleteQueuePath,
@@ -824,5 +858,35 @@
///
public static readonly Func RandomDicomTime = (tag, random) =>
new DicomTime(tag, DateTime.UtcNow.AddSeconds(random.NextDouble() * 1000.0));
+
+ ///
+ /// Disposes of all managed resources.
+ ///
+ /// If we are disposing.
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposedValue)
+ {
+ return;
+ }
+
+ if (disposing)
+ {
+ _testAETConfigProvider.Dispose();
+ TestGatewayProcessorConfigProvider.Dispose();
+ TestGatewayReceiveConfigProvider.Dispose();
+ }
+
+ disposedValue = true;
+ }
+
+ ///
+ /// Implements the disposable pattern.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
}
}
diff --git a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/Models/MockConfigurationProvider.cs b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/Models/MockConfigurationProvider.cs
index 8a54e26..77e7828 100644
--- a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/Models/MockConfigurationProvider.cs
+++ b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/Models/MockConfigurationProvider.cs
@@ -1,18 +1,17 @@
namespace Microsoft.InnerEye.Listener.Tests.Models
{
using System;
- using System.Collections.Generic;
///
- /// Mock implementation of IConfigurationProvider.
+ /// Mock returning configuration, but sometimes throwing an exception.
///
- ///
+ /// Configuration type.
public class MockConfigurationProvider
{
///
- /// Previous configuration, if there was a queue.
+ /// Configuration.
///
- private T _previousConfiguration;
+ private T _configuration;
///
/// TestException to throw on GetConfiguration to mock failure.
@@ -20,11 +19,18 @@
public Exception TestException { get; set; }
///
- /// Mock queue of configurations.
+ /// Initialize a new instance of the.
///
- public Queue ConfigurationQueue { get; } = new Queue();
+ /// Configuration.
+ public MockConfigurationProvider(T configuration)
+ {
+ _configuration = configuration;
+ }
- ///
+ ///
+ /// Return configuration or throw an exception.
+ ///
+ /// Configuration.
public T GetConfiguration()
{
if (TestException != null)
@@ -32,12 +38,7 @@
throw TestException;
}
- if (ConfigurationQueue.Count > 0)
- {
- _previousConfiguration = ConfigurationQueue.Dequeue();
- }
-
- return _previousConfiguration;
+ return _configuration;
}
}
}
diff --git a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/ServiceTests/ConfigurationProviderTests.cs b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/ServiceTests/ConfigurationProviderTests.cs
index c6d4a40..7ef6c6f 100644
--- a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/ServiceTests/ConfigurationProviderTests.cs
+++ b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/ServiceTests/ConfigurationProviderTests.cs
@@ -5,6 +5,7 @@
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
+ using System.Threading;
using Microsoft.InnerEye.Azure.Segmentation.API.Common;
using Microsoft.InnerEye.DicomConstraints;
using Microsoft.InnerEye.Gateway.Models;
@@ -503,8 +504,10 @@
[TestCategory("ConfigurationProvider")]
[Description("Creates a random gateway receive config, saves it, and checks it loads correctly.")]
+ [DataRow(false, DisplayName = "Load GatewayReceiveConfig")]
+ [DataRow(true, DisplayName = "Reload GatewayReceiveConfig")]
[TestMethod]
- public void TestLoadGatewayReceiveConfig()
+ public void TestLoadGatewayReceiveConfig(bool reload)
{
var configurationDirectory = CreateTemporaryDirectory().FullName;
var random = new Random();
@@ -512,16 +515,68 @@
var expectedGatewayReceiveConfig = RandomGatewayReceiveConfig(random);
Serialise(expectedGatewayReceiveConfig, configurationDirectory, GatewayReceiveConfigProvider.GatewayReceiveConfigFileName);
- var gatewayReceiveConfigProvider = new GatewayReceiveConfigProvider(_baseTestLogger, configurationDirectory);
- var actualGatewayReceiveConfig = gatewayReceiveConfigProvider.GatewayReceiveConfig();
+ using (var gatewayReceiveConfigProvider = CreateGatewayReceiveConfigProvider(configurationDirectory))
+ {
+ Assert.AreEqual(expectedGatewayReceiveConfig, gatewayReceiveConfigProvider.Config);
- Assert.AreEqual(expectedGatewayReceiveConfig, actualGatewayReceiveConfig);
+ if (reload)
+ {
+ var configReloadedCount = 0;
+
+ gatewayReceiveConfigProvider.ConfigChanged += (s, e) =>
+ {
+ Interlocked.Increment(ref configReloadedCount);
+ };
+
+ var expectedGatewayReceiveConfig2 = RandomGatewayReceiveConfig(random);
+ Serialise(expectedGatewayReceiveConfig2, configurationDirectory, GatewayReceiveConfigProvider.GatewayReceiveConfigFileName);
+
+ SpinWait.SpinUntil(() => configReloadedCount > 0, TimeSpan.FromSeconds(10));
+
+ Assert.AreEqual(expectedGatewayReceiveConfig2, gatewayReceiveConfigProvider.Config);
+ }
+ }
+ }
+
+ [TestCategory("ConfigurationProvider")]
+ [Description("Creates a random gateway receive config, saves it, and checks it loads correctly. Then toggles runAsConsole.")]
+ [TestMethod]
+ public void TestUpdateGatewayReceiveConfigRunAsConsole()
+ {
+ var configurationDirectory = CreateTemporaryDirectory().FullName;
+ var random = new Random();
+
+ var expectedGatewayReceiveConfig = RandomGatewayReceiveConfig(random);
+ Serialise(expectedGatewayReceiveConfig, configurationDirectory, GatewayReceiveConfigProvider.GatewayReceiveConfigFileName);
+
+ using (var gatewayReceiveConfigProvider = CreateGatewayReceiveConfigProvider(configurationDirectory))
+ {
+ Assert.AreEqual(expectedGatewayReceiveConfig, gatewayReceiveConfigProvider.Config);
+
+ var configReloadedCount = 0;
+
+ gatewayReceiveConfigProvider.ConfigChanged += (s, e) =>
+ {
+ Interlocked.Increment(ref configReloadedCount);
+ };
+
+ var runAsConsole = gatewayReceiveConfigProvider.Config.ServiceSettings.RunAsConsole;
+
+ gatewayReceiveConfigProvider.SetRunAsConsole(!runAsConsole);
+
+ SpinWait.SpinUntil(() => configReloadedCount > 0, TimeSpan.FromSeconds(10));
+
+ // RunAsConsole should have now toggled.
+ Assert.AreEqual(!runAsConsole, gatewayReceiveConfigProvider.Config.ServiceSettings.RunAsConsole);
+ }
}
[TestCategory("ConfigurationProvider")]
[Description("Creates a random gateway processor config, saves it, and checks it loads correctly.")]
+ [DataRow(false, DisplayName = "Load GatewayProcessorConfig")]
+ [DataRow(true, DisplayName = "Reload GatewayProcessorConfig")]
[TestMethod]
- public void TestLoadGatewayProcessorConfig()
+ public void TestLoadGatewayProcessorConfig(bool reload)
{
var configurationDirectory = CreateTemporaryDirectory().FullName;
var random = new Random();
@@ -529,112 +584,191 @@
var expectedGatewayProcessorConfig = RandomGatewayProcessorConfig(random);
Serialise(expectedGatewayProcessorConfig, configurationDirectory, GatewayProcessorConfigProvider.GatewayProcessorConfigFileName);
- var gatewayProcessorConfigProvider = new GatewayProcessorConfigProvider(_baseTestLogger, configurationDirectory);
- var actualGatewayProcessorConfig = gatewayProcessorConfigProvider.GatewayProcessorConfig();
+ using (var gatewayProcessorConfigProvider = CreateGatewayProcessorConfigProvider(configurationDirectory))
+ {
+ Assert.AreEqual(expectedGatewayProcessorConfig, gatewayProcessorConfigProvider.Config);
- Assert.AreEqual(expectedGatewayProcessorConfig, actualGatewayProcessorConfig);
+ if (reload)
+ {
+ var configReloadedCount = 0;
+
+ gatewayProcessorConfigProvider.ConfigChanged += (s, e) =>
+ {
+ Interlocked.Increment(ref configReloadedCount);
+ };
+
+ var expectedGatewayProcessorConfig2 = RandomGatewayProcessorConfig(random);
+ Serialise(expectedGatewayProcessorConfig2, configurationDirectory, GatewayProcessorConfigProvider.GatewayProcessorConfigFileName);
+
+ SpinWait.SpinUntil(() => configReloadedCount > 0, TimeSpan.FromSeconds(10));
+
+ Assert.AreEqual(expectedGatewayProcessorConfig2, gatewayProcessorConfigProvider.Config);
+ }
+ }
+ }
+
+ [TestCategory("ConfigurationProvider")]
+ [Description("Creates a random gateway processor config, saves it, and checks it loads correctly. Then toggles runAsConsole.")]
+ [TestMethod]
+ public void TestUpdateGatewayProcessorConfigRunAsConsole()
+ {
+ var configurationDirectory = CreateTemporaryDirectory().FullName;
+ var random = new Random();
+
+ var expectedGatewayProcessorConfig = RandomGatewayProcessorConfig(random);
+ Serialise(expectedGatewayProcessorConfig, configurationDirectory, GatewayProcessorConfigProvider.GatewayProcessorConfigFileName);
+
+ using (var gatewayProcessorConfigProvider = CreateGatewayProcessorConfigProvider(configurationDirectory))
+ {
+ Assert.AreEqual(expectedGatewayProcessorConfig, gatewayProcessorConfigProvider.Config);
+
+ var configReloadedCount = 0;
+
+ gatewayProcessorConfigProvider.ConfigChanged += (s, e) =>
+ {
+ Interlocked.Increment(ref configReloadedCount);
+ };
+
+ var runAsConsole = gatewayProcessorConfigProvider.Config.ServiceSettings.RunAsConsole;
+
+ gatewayProcessorConfigProvider.SetRunAsConsole(!runAsConsole);
+
+ SpinWait.SpinUntil(() => configReloadedCount > 0, TimeSpan.FromSeconds(10));
+
+ // RunAsConsole should have now toggled.
+ Assert.AreEqual(!runAsConsole, gatewayProcessorConfigProvider.Config.ServiceSettings.RunAsConsole);
+ }
+ }
+
+ [TestCategory("ConfigurationProvider")]
+ [Description("Creates a random gateway processor config, saves it, and checks it loads correctly. Then toggles updates processor settings.")]
+ [TestMethod]
+ public void TestUpdateGatewayProcessorConfigProcessorSettings()
+ {
+ var configurationDirectory = CreateTemporaryDirectory().FullName;
+ var random = new Random();
+
+ var expectedGatewayProcessorConfig = RandomGatewayProcessorConfig(random);
+ Serialise(expectedGatewayProcessorConfig, configurationDirectory, GatewayProcessorConfigProvider.GatewayProcessorConfigFileName);
+
+ using (var gatewayProcessorConfigProvider = CreateGatewayProcessorConfigProvider(configurationDirectory))
+ {
+ Assert.AreEqual(expectedGatewayProcessorConfig, gatewayProcessorConfigProvider.Config);
+
+ var configReloadedCount = 0;
+
+ gatewayProcessorConfigProvider.ConfigChanged += (s, e) =>
+ {
+ Interlocked.Increment(ref configReloadedCount);
+ };
+
+ var processorSettings = RandomProcessorSettings(random);
+
+ gatewayProcessorConfigProvider.SetProcessorSettings(processorSettings.InferenceUri);
+
+ SpinWait.SpinUntil(() => configReloadedCount > 0, TimeSpan.FromSeconds(10));
+
+ // InferenceUri should have now changed.
+ Assert.AreEqual(processorSettings.InferenceUri, gatewayProcessorConfigProvider.Config.ProcessorSettings.InferenceUri);
+ }
}
///
- /// Create a list of random AET config models, save them to a single file, and check they load correctly.
+ /// Create an Action for saving a set of AETConfigModels to a single file.
///
- /// True to use AETConfigProvider in single file mode, false to use it in folder mode.
- public void TestLoadAETConfigCommon(bool useFile)
- {
- var configurationDirectory = CreateTemporaryDirectory().FullName;
- var random = new Random();
+ /// Folder to store file in.
+ /// Action.
+ public static Action SaveFileAETConfigModels(string configurationDirectory) =>
+ (random, aetConfigModels) => Serialise(aetConfigModels, configurationDirectory, AETConfigProvider.AETConfigFileName);
- var expectedAETConfigModels = RandomArray(random, 2, 10, RandomAETConfigModel);
- var folder = string.Empty;
- var filename = string.Empty;
-
- if (useFile)
+ ///
+ /// Create an Action for saving a set of AETConfigModels to a folder.
+ ///
+ /// Folder to store folder in.
+ /// True to add junk files that should be ignored.
+ /// True to split config across multiple files.
+ /// Action.
+ public static Action SaveFolderAETConfigModels(string configurationDirectory, bool addJunk, bool multipleFiles) =>
+ (random, aetConfigModels) =>
{
- folder = configurationDirectory;
- filename = AETConfigProvider.AETConfigFileName;
- }
- else
- {
- folder = Path.Combine(configurationDirectory, AETConfigProvider.AETConfigFolderName);
+ var folder = Path.Combine(configurationDirectory, AETConfigProvider.AETConfigFolderName);
Directory.CreateDirectory(folder);
- filename = "test1.json";
- }
- Serialise(expectedAETConfigModels, folder, filename);
+ // Add in two extra files that should be ignored.
+ if (addJunk)
+ {
+ // Write a random GatewayProcessorConfig
+ var gatewayProcessorConfig = RandomGatewayProcessorConfig(random);
+ Serialise(gatewayProcessorConfig, folder, GatewayProcessorConfigProvider.GatewayProcessorConfigFileName);
- var aetConfigProvider = new AETConfigProvider(_baseTestLogger, configurationDirectory, useFile);
- var actualAETConfigModels = aetConfigProvider.GetAETConfigs().ToArray();
+ // Write a random GatewayReceiverConfig
+ var gatewayReceiveConfig = RandomGatewayReceiveConfig(random);
+ Serialise(gatewayReceiveConfig, folder, GatewayReceiveConfigProvider.GatewayReceiveConfigFileName);
+ }
- Assert.IsTrue(expectedAETConfigModels.SequenceEqual(actualAETConfigModels));
- }
+ if (multipleFiles)
+ {
+ for (var i = 0; i < aetConfigModels.Length; i++)
+ {
+ var expectedAETConfig = new[] { aetConfigModels[i] };
+ Serialise(expectedAETConfig, folder, string.Format("test{0}.json", i + 1));
+ }
+ }
+ else
+ {
+ Serialise(aetConfigModels, folder, "test1.json");
+ }
+ };
+
+ public static AETConfigModel[] OrderAETConfigModels(IEnumerable aetConfigModels) =>
+ aetConfigModels.OrderBy(m => m.CalledAET).ThenBy(m => m.CallingAET).ToArray();
+
+ public static void AssertAETConfigModelsEqual(IEnumerable expectedAETConfigModels, IEnumerable actualAETConfigModels) =>
+ Assert.IsTrue(OrderAETConfigModels(expectedAETConfigModels).SequenceEqual(OrderAETConfigModels(actualAETConfigModels)));
[TestCategory("ConfigurationProvider")]
- [Description("Creates a list of AET config models, saves it to a file, and checks it loads correctly.")]
+ [Description("Creates a list of AET config models, saves it to a file or folder, and checks it loads correctly.")]
+ [DataRow(false, false, false, false, DisplayName = "Load folder AETConfigModels")]
+ [DataRow(false, false, false, true, DisplayName = "Load folder AETConfigModels, split files")]
+ [DataRow(false, false, true, false, DisplayName = "Load folder AETConfigModels, ignore junk")]
+ [DataRow(false, true, false, false, DisplayName = "Reload folder AETConfigModels")]
+ [DataRow(false, true, true, false, DisplayName = "Reload folder AETConfigModels, ignore junk")]
+ [DataRow(true, false, false, false, DisplayName = "Load file AETConfigModels")]
+ [DataRow(true, true, false, false, DisplayName = "Reload file AETConfigModels")]
[TestMethod]
- public void TestLoadAETConfigFile()
- {
- TestLoadAETConfigCommon(true);
- }
-
- [TestCategory("ConfigurationProvider")]
- [Description("Creates a list of AET config models, saves it to a file in a folder, and checks it loads correctly.")]
- [TestMethod]
- public void TestLoadAETConfigFolder()
- {
- TestLoadAETConfigCommon(false);
- }
-
- [TestCategory("ConfigurationProvider")]
- [Description("Creates a list of AET config models, saves them along with two other config files, and checks the models load correctly" +
- "and the other configs are ignored.")]
- [TestMethod]
- public void TestLoadAETConfigInvalidFiles()
+ public void TestLoadAETConfigModels(bool useFile, bool reload, bool addJunk, bool multipleFiles)
{
var configurationDirectory = CreateTemporaryDirectory().FullName;
var random = new Random();
- var aetConfigFolder = Path.Combine(configurationDirectory, AETConfigProvider.AETConfigFolderName);
- Directory.CreateDirectory(aetConfigFolder);
+ var saveAETConfigModels = useFile ?
+ SaveFileAETConfigModels(configurationDirectory) :
+ SaveFolderAETConfigModels(configurationDirectory, addJunk, multipleFiles);
var expectedAETConfigModels = RandomArray(random, 3, 10, RandomAETConfigModel);
- Serialise(expectedAETConfigModels, aetConfigFolder, "test1.json");
+ saveAETConfigModels.Invoke(random, expectedAETConfigModels);
- // Write a random GatewayProcessorConfig
- var gatewayProcessorConfig = RandomGatewayProcessorConfig(random);
- Serialise(gatewayProcessorConfig, aetConfigFolder, "test2.json");
-
- // Write a random GatewayReceiverConfig
- var gatewayReceiveConfig = RandomGatewayReceiveConfig(random);
- Serialise(gatewayReceiveConfig, aetConfigFolder, "test3.json");
-
- var aetConfigProvider = new AETConfigProvider(_baseTestLogger, configurationDirectory);
- var actualAETConfigModels = aetConfigProvider.GetAETConfigs().ToArray();
-
- Assert.IsTrue(expectedAETConfigModels.SequenceEqual(actualAETConfigModels));
- }
-
- [TestCategory("ConfigurationProvider")]
- [Description("Creates a list of AET config models, saves them to one file per called/calling pair, and checks they all load correctly.")]
- [TestMethod]
- public void TestLoadAETConfigConcatenate()
- {
- var configurationDirectory = CreateTemporaryDirectory().FullName;
- var random = new Random();
-
- var aetConfigFolder = Path.Combine(configurationDirectory, AETConfigProvider.AETConfigFolderName);
- Directory.CreateDirectory(aetConfigFolder);
-
- var expectedAETConfigModels = RandomArray(random, 3, 10, RandomAETConfigModel);
- for (var i = 0; i < expectedAETConfigModels.Length; i++)
+ using (var aetConfigProvider = CreateAETConfigProvider(configurationDirectory, useFile))
{
- var expectedAETConfig = new[] { expectedAETConfigModels[i] };
- Serialise(expectedAETConfig, aetConfigFolder, string.Format("GatewayModelRulesConfig{0}.json", i));
+ AssertAETConfigModelsEqual(expectedAETConfigModels, aetConfigProvider.Config);
+
+ if (reload)
+ {
+ var configReloadedCount = 0;
+
+ aetConfigProvider.ConfigChanged += (s, e) =>
+ {
+ Interlocked.Increment(ref configReloadedCount);
+ };
+
+ var expectedAETConfigModels2 = RandomArray(random, 3, 10, RandomAETConfigModel);
+ saveAETConfigModels.Invoke(random, expectedAETConfigModels2);
+
+ SpinWait.SpinUntil(() => configReloadedCount > (addJunk ? 4 : 0), TimeSpan.FromSeconds(10));
+
+ AssertAETConfigModelsEqual(expectedAETConfigModels2, aetConfigProvider.Config);
+ }
}
-
- var aetConfigProvider = new AETConfigProvider(_baseTestLogger, configurationDirectory);
- var actualAETConfigModels = aetConfigProvider.GetAETConfigs().ToArray();
-
- Assert.IsTrue(expectedAETConfigModels.SequenceEqual(actualAETConfigModels));
}
[TestCategory("ConfigurationProvider")]
@@ -669,10 +803,10 @@
Serialise(expectedAETConfig, aetConfigFolder, string.Format("GatewayModelRulesConfig{0}.json", i), true);
}
- var aetConfigProvider = new AETConfigProvider(_baseTestLogger, configurationDirectory);
- var actualAETConfigModels = aetConfigProvider.GetAETConfigs().ToArray();
-
- Assert.IsTrue(expectedAETConfigModels.SequenceEqual(actualAETConfigModels));
+ using (var aetConfigProvider = CreateAETConfigProvider(configurationDirectory))
+ {
+ AssertAETConfigModelsEqual(expectedAETConfigModels, aetConfigProvider.Config);
+ }
}
[TestCategory("ConfigurationProvider")]
@@ -714,10 +848,10 @@
}
}
- var aetConfigProvider = new AETConfigProvider(_baseTestLogger, configurationDirectory);
- var actualAETConfigModels = aetConfigProvider.GetAETConfigs().ToArray();
-
- Assert.IsTrue(expectedAETConfigModels.SequenceEqual(actualAETConfigModels));
+ using (var aetConfigProvider = CreateAETConfigProvider(configurationDirectory))
+ {
+ AssertAETConfigModelsEqual(expectedAETConfigModels, aetConfigProvider.Config);
+ }
}
}
}
diff --git a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/ServiceTests/ReceiveServiceTests.cs b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/ServiceTests/ReceiveServiceTests.cs
index 224df2b..b72e647 100644
--- a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/ServiceTests/ReceiveServiceTests.cs
+++ b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/ServiceTests/ReceiveServiceTests.cs
@@ -6,6 +6,7 @@
using System.Threading.Tasks;
using Microsoft.InnerEye.Gateway.MessageQueueing.Exceptions;
using Microsoft.InnerEye.Gateway.Models;
+ using Microsoft.InnerEye.Listener.Common.Providers;
using Microsoft.InnerEye.Listener.DataProvider.Implementations;
using Microsoft.InnerEye.Listener.Tests.Common.Helpers;
using Microsoft.InnerEye.Listener.Tests.Models;
@@ -20,38 +21,25 @@
[TestMethod]
public void ReceiveServiceRestartTest()
{
- var callingAet = "ProstateRTMl";
+ var testAETConfigModel = GetTestAETConfigModel();
+
+ var configurationDirectory = CreateTemporaryDirectory().FullName;
+
+ var expectedGatewayReceiveConfig1 = TestGatewayReceiveConfigProvider.Config.With(
+ receiveServiceConfig: GetTestGatewayReceiveServiceConfig(110),
+ configurationServiceConfig: new ConfigurationServiceConfig(
+ configurationRefreshDelaySeconds: 1));
+
+ ConfigurationProviderTests.Serialise(expectedGatewayReceiveConfig1, configurationDirectory, GatewayReceiveConfigProvider.GatewayReceiveConfigFileName);
var client = GetMockInnerEyeSegmentationClient();
-
- var mockConfigurationServiceConfigProvider = new MockConfigurationProvider();
-
- var configurationServiceConfig1 = new ConfigurationServiceConfig(
- configurationRefreshDelaySeconds: 1);
-
- var configurationServiceConfig2 = new ConfigurationServiceConfig(
- configurationServiceConfig1.ConfigCreationDateTime.AddSeconds(5),
- configurationServiceConfig1.ApplyConfigDateTime.AddSeconds(10));
-
- mockConfigurationServiceConfigProvider.ConfigurationQueue.Clear();
- mockConfigurationServiceConfigProvider.ConfigurationQueue.Enqueue(configurationServiceConfig1);
- mockConfigurationServiceConfigProvider.ConfigurationQueue.Enqueue(configurationServiceConfig2);
-
- var mockReceiverConfigurationProvider2 = new MockConfigurationProvider();
-
- var testReceiveServiceConfig1 = GetTestGatewayReceiveServiceConfig(110);
- var testReceiveServiceConfig2 = GetTestGatewayReceiveServiceConfig(111);
-
- mockReceiverConfigurationProvider2.ConfigurationQueue.Clear();
- mockReceiverConfigurationProvider2.ConfigurationQueue.Enqueue(testReceiveServiceConfig1);
- mockReceiverConfigurationProvider2.ConfigurationQueue.Enqueue(testReceiveServiceConfig2);
-
- using (var receiveService = CreateReceiveService(mockReceiverConfigurationProvider2.GetConfiguration))
+ using (var gatewayReceiveConfigProvider = CreateGatewayReceiveConfigProvider(configurationDirectory))
+ using (var receiveService = CreateReceiveService(gatewayReceiveConfigProvider.ReceiveServiceConfig))
using (var uploadQueue = receiveService.UploadQueue)
using (var configurationService = CreateConfigurationService(
client,
- mockConfigurationServiceConfigProvider.GetConfiguration,
+ gatewayReceiveConfigProvider.ConfigurationServiceConfig,
receiveService))
{
// Start the service
@@ -59,28 +47,36 @@
uploadQueue.Clear(); // Clear the message queue
+ var expectedGatewayReceiveConfig2 = TestGatewayReceiveConfigProvider.Config.With(
+ receiveServiceConfig: GetTestGatewayReceiveServiceConfig(111),
+ configurationServiceConfig: new ConfigurationServiceConfig(
+ expectedGatewayReceiveConfig1.ConfigurationServiceConfig.ConfigCreationDateTime.AddSeconds(5),
+ expectedGatewayReceiveConfig1.ConfigurationServiceConfig.ApplyConfigDateTime.AddSeconds(10)));
+
+ ConfigurationProviderTests.Serialise(expectedGatewayReceiveConfig2, configurationDirectory, GatewayReceiveConfigProvider.GatewayReceiveConfigFileName);
+
SpinWait.SpinUntil(() => receiveService.StartCount == 2);
- // Send on the new config
+ // Send on the old config
var result = DcmtkHelpers.SendFileUsingDCMTK(
@"Images\1ValidSmall\1.dcm",
- testReceiveServiceConfig1.GatewayDicomEndPoint.Port,
+ expectedGatewayReceiveConfig1.ReceiveServiceConfig.GatewayDicomEndPoint.Port,
ScuProfile.LEExplicitCT,
TestContext,
- applicationEntityTitle: callingAet,
- calledAETitle: testReceiveServiceConfig1.GatewayDicomEndPoint.Title);
+ applicationEntityTitle: testAETConfigModel.CallingAET,
+ calledAETitle: testAETConfigModel.CalledAET);
- // Check this did send on the old config
+ // Check this did not send on the old config
Assert.IsFalse(string.IsNullOrWhiteSpace(result));
// Send on the new config
result = DcmtkHelpers.SendFileUsingDCMTK(
@"Images\1ValidSmall\1.dcm",
- testReceiveServiceConfig2.GatewayDicomEndPoint.Port,
+ expectedGatewayReceiveConfig2.ReceiveServiceConfig.GatewayDicomEndPoint.Port,
ScuProfile.LEExplicitCT,
TestContext,
- applicationEntityTitle: callingAet,
- calledAETitle: testReceiveServiceConfig2.GatewayDicomEndPoint.Title);
+ applicationEntityTitle: testAETConfigModel.CallingAET,
+ calledAETitle: testAETConfigModel.CalledAET);
// Check this did send on the new config
Assert.IsTrue(string.IsNullOrWhiteSpace(result));
@@ -88,8 +84,8 @@
var receiveQueueItem = TransactionalDequeue(uploadQueue);
Assert.IsNotNull(receiveQueueItem);
- Assert.AreEqual(callingAet, receiveQueueItem.CallingApplicationEntityTitle);
- Assert.AreEqual(testReceiveServiceConfig2.GatewayDicomEndPoint.Title, receiveQueueItem.CalledApplicationEntityTitle);
+ Assert.AreEqual(testAETConfigModel.CallingAET, receiveQueueItem.CallingApplicationEntityTitle);
+ Assert.AreEqual(testAETConfigModel.CalledAET, receiveQueueItem.CalledApplicationEntityTitle);
Assert.IsFalse(string.IsNullOrEmpty(receiveQueueItem.AssociationFolderPath));
@@ -113,15 +109,12 @@
[TestMethod]
public void ReceiveServiceAPIDownTest()
{
- var callingAet = "ProstateRTMl";
+ var testAETConfigModel = GetTestAETConfigModel();
- var mockReceiverConfigurationProvider = new MockConfigurationProvider();
var client = GetMockInnerEyeSegmentationClient();
var gatewayReceiveConfig = GetTestGatewayReceiveServiceConfig(140);
-
- mockReceiverConfigurationProvider.ConfigurationQueue.Clear();
- mockReceiverConfigurationProvider.ConfigurationQueue.Enqueue(gatewayReceiveConfig);
+ var mockReceiverConfigurationProvider = new MockConfigurationProvider(gatewayReceiveConfig);
using (var receiveService = CreateReceiveService(mockReceiverConfigurationProvider.GetConfiguration))
using (var uploadQueue = receiveService.UploadQueue)
@@ -138,14 +131,14 @@
gatewayReceiveConfig.GatewayDicomEndPoint.Port,
ScuProfile.LEExplicitCT,
TestContext,
- applicationEntityTitle: callingAet,
- calledAETitle: gatewayReceiveConfig.GatewayDicomEndPoint.Title);
+ applicationEntityTitle: testAETConfigModel.CallingAET,
+ calledAETitle: testAETConfigModel.CalledAET);
var receiveQueueItem = TransactionalDequeue(uploadQueue, 10000);
Assert.IsNotNull(receiveQueueItem);
- Assert.AreEqual(callingAet, receiveQueueItem.CallingApplicationEntityTitle);
- Assert.AreEqual(gatewayReceiveConfig.GatewayDicomEndPoint.Title, receiveQueueItem.CalledApplicationEntityTitle);
+ Assert.AreEqual(testAETConfigModel.CallingAET, receiveQueueItem.CallingApplicationEntityTitle);
+ Assert.AreEqual(testAETConfigModel.CalledAET, receiveQueueItem.CalledApplicationEntityTitle);
Assert.IsFalse(string.IsNullOrEmpty(receiveQueueItem.AssociationFolderPath));
@@ -169,11 +162,9 @@
[TestMethod]
public void ReceiveServiceLiveEndToEndTest()
{
+ var testAETConfigModel = GetTestAETConfigModel();
var receivePort = 160;
- var callingAet = "ProstateRTMl";
- var calledAet = "testname";
-
using (var receiveService = CreateReceiveService(receivePort))
using (var uploadQueue = receiveService.UploadQueue)
{
@@ -185,14 +176,14 @@
receivePort,
ScuProfile.LEExplicitCT,
TestContext,
- applicationEntityTitle: callingAet,
- calledAETitle: calledAet);
+ applicationEntityTitle: testAETConfigModel.CallingAET,
+ calledAETitle: testAETConfigModel.CalledAET);
var receiveQueueItem = TransactionalDequeue(uploadQueue, timeoutMs: 20 * 1000);
Assert.IsNotNull(receiveQueueItem);
- Assert.AreEqual(callingAet, receiveQueueItem.CallingApplicationEntityTitle);
- Assert.AreEqual(calledAet, receiveQueueItem.CalledApplicationEntityTitle);
+ Assert.AreEqual(testAETConfigModel.CallingAET, receiveQueueItem.CallingApplicationEntityTitle);
+ Assert.AreEqual(testAETConfigModel.CalledAET, receiveQueueItem.CalledApplicationEntityTitle);
Assert.IsFalse(string.IsNullOrEmpty(receiveQueueItem.AssociationFolderPath));
@@ -216,7 +207,7 @@
[TestMethod]
public async Task ReceiveServiceEchoTest()
{
- var calledAet = "testname";
+ var testAETConfigModel = GetTestAETConfigModel();
var receivePort = 180;
using (var receiveService = CreateReceiveService(receivePort))
@@ -229,7 +220,7 @@
await sender.DicomEchoAsync(
"Hello",
- calledAet,
+ testAETConfigModel.CalledAET,
receivePort,
"127.0.0.1");
@@ -242,15 +233,15 @@
receivePort,
ScuProfile.LEExplicitCT,
TestContext,
- applicationEntityTitle: "ProstateRTMl",
- calledAETitle: calledAet);
+ applicationEntityTitle: testAETConfigModel.CallingAET,
+ calledAETitle: testAETConfigModel.CalledAET);
Assert.IsNotNull(TransactionalDequeue(uploadQueue, timeoutMs: 1000));
// Now try another Dicom echo
await sender.DicomEchoAsync(
"Hello",
- calledAet,
+ testAETConfigModel.CalledAET,
receivePort,
"127.0.0.1");
diff --git a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/ServiceTests/SystemTests.cs b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/ServiceTests/SystemTests.cs
index 93badc4..ee3dbca 100644
--- a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/ServiceTests/SystemTests.cs
+++ b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Tests/ServiceTests/SystemTests.cs
@@ -8,10 +8,10 @@
using Dicom;
using Microsoft.InnerEye.Gateway.MessageQueueing.Exceptions;
using Microsoft.InnerEye.Gateway.Models;
+ using Microsoft.InnerEye.Listener.Common.Providers;
using Microsoft.InnerEye.Listener.DataProvider.Implementations;
using Microsoft.InnerEye.Listener.DataProvider.Models;
using Microsoft.InnerEye.Listener.Tests.Common.Helpers;
- using Microsoft.InnerEye.Listener.Tests.Models;
using Microsoft.VisualStudio.TestTools.UnitTesting;
[TestClass]
@@ -23,6 +23,14 @@
[TestMethod]
public async Task ProcessorServiceRestartTest()
{
+ var configurationDirectory = CreateTemporaryDirectory().FullName;
+
+ var expectedGatewayProcessorConfig1 = TestGatewayProcessorConfigProvider.Config.With(
+ configurationServiceConfig: new ConfigurationServiceConfig(
+ configurationRefreshDelaySeconds: 1));
+
+ ConfigurationProviderTests.Serialise(expectedGatewayProcessorConfig1, configurationDirectory, GatewayProcessorConfigProvider.GatewayProcessorConfigFileName);
+
var tempFolder = CreateTemporaryDirectory();
foreach (var file in new DirectoryInfo(@"Images\1ValidSmall\").GetFiles())
@@ -32,21 +40,7 @@
var client = GetMockInnerEyeSegmentationClient();
- var mockConfigurationServiceConfigProvider = new MockConfigurationProvider();
-
- var configurationServiceConfig1 = new ConfigurationServiceConfig(
- configurationRefreshDelaySeconds: 1);
-
- var configurationServiceConfig2 = new ConfigurationServiceConfig(
- configurationServiceConfig1.ConfigCreationDateTime.AddSeconds(5),
- configurationServiceConfig1.ApplyConfigDateTime.AddSeconds(10));
-
- mockConfigurationServiceConfigProvider.ConfigurationQueue.Enqueue(configurationServiceConfig1);
- mockConfigurationServiceConfigProvider.ConfigurationQueue.Enqueue(configurationServiceConfig2);
-
- var resultDirectory = CreateTemporaryDirectory();
-
- using (var dicomDataReceiver = new ListenerDataReceiver(new ListenerDicomSaver(resultDirectory.FullName)))
+ using (var dicomDataReceiver = new ListenerDataReceiver(new ListenerDicomSaver(CreateTemporaryDirectory().FullName)))
{
var eventCount = 0;
var folderPath = string.Empty;
@@ -65,9 +59,10 @@
using (var uploadService = CreateUploadService(client))
using (var uploadQueue = uploadService.UploadQueue)
using (var downloadService = CreateDownloadService(client))
+ using (var gatewayProcessorConfigProvider = CreateGatewayProcessorConfigProvider(configurationDirectory))
using (var configurationService = CreateConfigurationService(
client,
- mockConfigurationServiceConfigProvider.GetConfiguration,
+ gatewayProcessorConfigProvider.ConfigurationServiceConfig,
downloadService,
uploadService,
pushService))
@@ -77,6 +72,14 @@
uploadQueue.Clear(); // Clear the message queue
+ // Save a new config, this should be picked up and the services restart in 10 seconds.
+ var expectedGatewayProcessorConfig2 = TestGatewayProcessorConfigProvider.Config.With(
+ configurationServiceConfig: new ConfigurationServiceConfig(
+ expectedGatewayProcessorConfig1.ConfigurationServiceConfig.ConfigCreationDateTime.AddSeconds(5),
+ expectedGatewayProcessorConfig1.ConfigurationServiceConfig.ApplyConfigDateTime.AddSeconds(10)));
+
+ ConfigurationProviderTests.Serialise(expectedGatewayProcessorConfig2, configurationDirectory, GatewayProcessorConfigProvider.GatewayProcessorConfigFileName);
+
SpinWait.SpinUntil(() => pushService.StartCount == 2);
SpinWait.SpinUntil(() => uploadService.StartCount == 2);
SpinWait.SpinUntil(() => downloadService.StartCount == 2);
diff --git a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Wix.Actions/CustomActions.cs b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Wix.Actions/CustomActions.cs
index 6b8023e..2f2f297 100644
--- a/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Wix.Actions/CustomActions.cs
+++ b/Source/Microsoft.Gateway/Microsoft.InnerEye.Listener.Wix.Actions/CustomActions.cs
@@ -53,40 +53,42 @@ namespace Microsoft.InnerEye.Listener.Wix.Actions
#endif
// Make sure that the applications are run as services.
- var gatewayProcessorConfigProvider = new GatewayProcessorConfigProvider(
- null,
- ConfigInstallDirectory);
- gatewayProcessorConfigProvider.SetRunAsConsole(false);
-
- var gatewayReceiveConfigProvider = new GatewayReceiveConfigProvider(
- null,
- ConfigInstallDirectory);
- gatewayReceiveConfigProvider.SetRunAsConsole(false);
-
- // Check if the installer is running unattended - lets skip the UI if true
- if (session.CustomActionData[UILevelCustomActionKey] == "2")
+ using (var gatewayProcessorConfigProvider = new GatewayProcessorConfigProvider(null, ConfigInstallDirectory))
{
- return ActionResult.Success;
- }
+ gatewayProcessorConfigProvider.SetRunAsConsole(false);
- // In the context of the installer, this may have a different SecurityProtocol to the application.
- // In testing it was: SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls
- // but it may vary. In order to value the uri and license key, we need TLS 1.2
- ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
-
- // First time install so lets display a form to grab the license key.
- using (var form = new LicenseKeyForm(gatewayProcessorConfigProvider))
- {
- var licenseKeyDialogResult = form.ShowDialog();
-
- switch (licenseKeyDialogResult)
+ using (var gatewayReceiveConfigProvider = new GatewayReceiveConfigProvider(
+ null,
+ ConfigInstallDirectory))
{
- case DialogResult.Cancel:
- return ActionResult.UserExit;
- case DialogResult.No:
- return ActionResult.NotExecuted;
- default:
- return ActionResult.Success;
+ gatewayReceiveConfigProvider.SetRunAsConsole(false);
+ }
+
+ // Check if the installer is running unattended - lets skip the UI if true
+ if (session.CustomActionData[UILevelCustomActionKey] == "2")
+ {
+ return ActionResult.Success;
+ }
+
+ // In the context of the installer, this may have a different SecurityProtocol to the application.
+ // In testing it was: SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls
+ // but it may vary. In order to value the uri and license key, we need TLS 1.2
+ ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
+
+ // First time install so lets display a form to grab the license key.
+ using (var form = new LicenseKeyForm(gatewayProcessorConfigProvider))
+ {
+ var licenseKeyDialogResult = form.ShowDialog();
+
+ switch (licenseKeyDialogResult)
+ {
+ case DialogResult.Cancel:
+ return ActionResult.UserExit;
+ case DialogResult.No:
+ return ActionResult.NotExecuted;
+ default:
+ return ActionResult.Success;
+ }
}
}
}