diff --git a/Directory.Build.targets b/Directory.Build.targets
index d12d3f6bd..61e496c59 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -34,6 +34,7 @@
+
diff --git a/src/Moryx.Runtime.Kernel/KernelServiceCollectionExtensions.cs b/src/Moryx.Runtime.Kernel/KernelServiceCollectionExtensions.cs
index 83bc5b833..8275f2db1 100644
--- a/src/Moryx.Runtime.Kernel/KernelServiceCollectionExtensions.cs
+++ b/src/Moryx.Runtime.Kernel/KernelServiceCollectionExtensions.cs
@@ -74,6 +74,15 @@ public static void AddMoryxModules(this IServiceCollection serviceCollection)
}
}
+ ///
+ /// Register BackgroundService that controls that starts and stops the MORYX modules inside the lifetime of the host.
+ /// The MORYX Service can hook into the command line and gracefuly stop the modules when the user tries to close the window.
+ ///
+ public static void AddMoryxService(this IServiceCollection serviceCollection)
+ {
+ serviceCollection.AddHostedService();
+ }
+
///
/// Use the moryx config manager
///
diff --git a/src/Moryx.Runtime.Kernel/Moryx.Runtime.Kernel.csproj b/src/Moryx.Runtime.Kernel/Moryx.Runtime.Kernel.csproj
index 054c7834f..650956a63 100644
--- a/src/Moryx.Runtime.Kernel/Moryx.Runtime.Kernel.csproj
+++ b/src/Moryx.Runtime.Kernel/Moryx.Runtime.Kernel.csproj
@@ -7,11 +7,14 @@
MORYX;Kernel;Runtime;Server
+
+
+
+
-
\ No newline at end of file
diff --git a/src/Moryx.Runtime.Kernel/MoryxHost.cs b/src/Moryx.Runtime.Kernel/MoryxHost.cs
new file mode 100644
index 000000000..16344b7e1
--- /dev/null
+++ b/src/Moryx.Runtime.Kernel/MoryxHost.cs
@@ -0,0 +1,103 @@
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using Moryx.Runtime.Modules;
+using System;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Moryx.Runtime.Kernel
+{
+ internal class MoryxHost : BackgroundService
+ {
+ private readonly IModuleManager moduleManager;
+ private readonly IHost lifeTime;
+ private readonly ILogger logger;
+
+ // Console shutdown handling according to https://stackoverflow.com/questions/21751545/how-to-make-a-console-app-exit-gracefully-when-it-is-closed
+ [DllImport("Kernel32")]
+ public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add);
+
+ // A delegate type to be used as the handler routine
+ // for SetConsoleCtrlHandler.
+ public delegate bool HandlerRoutine(CtrlTypes CtrlType);
+
+ // An enumerated type for the control messages
+ // sent to the handler routine.
+ public enum CtrlTypes
+ {
+ CTRL_C_EVENT = 0,
+ CTRL_BREAK_EVENT,
+ CTRL_CLOSE_EVENT,
+ CTRL_LOGOFF_EVENT = 5,
+ CTRL_SHUTDOWN_EVENT
+ }
+
+ ///
+ /// Callback that is called when a console event is raised.
+ ///
+ ///
+ ///
+ private bool ConsoleCtrlCheck(CtrlTypes ctrlType)
+ {
+ // Stop the host and await shutdown.
+ lifeTime.StopAsync(TimeSpan.FromSeconds(100)).ContinueWith(task =>
+ {
+ if (task.IsFaulted)
+ {
+ logger.LogError(task.Exception, "Received failure on shutdown.");
+ }
+ }).Wait();
+ return true;
+ }
+
+ public MoryxHost(IModuleManager moduleManager, IHost lifetTime, ILogger logger)
+ {
+ this.moduleManager = moduleManager;
+ this.lifeTime = lifetTime;
+ this.logger = logger;
+ }
+ public enum MoryxHostState {
+ NotStarted,
+ Starting,
+ Started,
+ Stopping,
+ Stopped
+ }
+
+ public MoryxHostState State {get;private set;}
+ public event EventHandler StateChanged;
+
+
+ public override async Task StartAsync(CancellationToken cancellationToken)
+ {
+ State = MoryxHostState.Starting;
+ StateChanged?.Invoke(this, State);
+ // Only register on windows, because the behavior is os specific
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ SetConsoleCtrlHandler(ConsoleCtrlCheck, true);
+ }
+ moduleManager.StartModules();
+
+ await base.StartAsync(cancellationToken);
+
+ State = MoryxHostState.Started;
+ StateChanged?.Invoke(this, State);
+ }
+ protected override Task ExecuteAsync(CancellationToken stoppingToken)
+ {
+ return Task.CompletedTask;
+ }
+
+ public override async Task StopAsync(CancellationToken cancellationToken)
+ {
+ State = MoryxHostState.Stopping;
+ StateChanged?.Invoke(this, State);
+ moduleManager.StopModules();
+ await base.StopAsync(cancellationToken);
+ State = MoryxHostState.Stopped;
+ StateChanged?.Invoke(this, State);
+ }
+ }
+}