From 98b421c552691c8333a29151a843bcc8f5118b93 Mon Sep 17 00:00:00 2001 From: Denny09310 Date: Tue, 18 Nov 2025 09:48:23 +0100 Subject: [PATCH 1/3] feat: added startup options for UseElectron --- .../ElectronAppLifetimeEvents.cs | 43 +++++++++++ src/ElectronNET.API/ElectronNetOptions.cs | 20 ++++++ src/ElectronNET.API/ElectronNetRuntime.cs | 6 ++ .../API/WebHostBuilderExtensions.cs | 33 ++++++++- .../RuntimeControllerAspNetBase.cs | 71 +++++++++++++++++++ src/ElectronNET.WebApp/Program.cs | 29 +++++--- 6 files changed, 191 insertions(+), 11 deletions(-) create mode 100644 src/ElectronNET.API/ElectronAppLifetimeEvents.cs create mode 100644 src/ElectronNET.API/ElectronNetOptions.cs diff --git a/src/ElectronNET.API/ElectronAppLifetimeEvents.cs b/src/ElectronNET.API/ElectronAppLifetimeEvents.cs new file mode 100644 index 00000000..f6a52209 --- /dev/null +++ b/src/ElectronNET.API/ElectronAppLifetimeEvents.cs @@ -0,0 +1,43 @@ +namespace ElectronNET +{ + using System; + using System.Threading.Tasks; + + /// + /// Represents callbacks that are invoked during different phases of the Electron application + /// lifetime. These callbacks allow consumers to hook into the startup sequence more + /// granularly than the existing single callback. Callbacks return + /// enabling asynchronous work to be awaited before the next phase of the Electron runtime + /// commences. + /// + public class ElectronAppLifetimeEvents + { + /// + /// Gets or sets the callback that is invoked once the Electron process and socket bridge + /// have been established but before the Electron ready event has been + /// acknowledged. Use this hook to register custom protocols or perform other + /// initialization that must occur prior to the ready event. + /// + public Func OnBeforeReady { get; set; } = () => Task.CompletedTask; + + /// + /// Gets or sets the callback that is invoked when the Electron ready event is + /// fired. Use this hook to create browser windows or perform post-ready initialization. + /// + public Func OnReady { get; set; } = () => Task.CompletedTask; + + /// + /// Gets or sets the callback that is invoked when the Electron process is about to quit. + /// This maps to the will-quit event in Electron and can be used to perform + /// graceful shutdown logic. The default implementation does nothing. + /// + public Func OnWillQuit { get; set; } = () => Task.CompletedTask; + + /// + /// Gets or sets the callback that is invoked when the Electron process has fully + /// terminated. This can be used for cleanup tasks. The default implementation does + /// nothing. + /// + public Func OnQuit { get; set; } = () => Task.CompletedTask; + } +} \ No newline at end of file diff --git a/src/ElectronNET.API/ElectronNetOptions.cs b/src/ElectronNET.API/ElectronNetOptions.cs new file mode 100644 index 00000000..e25d2422 --- /dev/null +++ b/src/ElectronNET.API/ElectronNetOptions.cs @@ -0,0 +1,20 @@ +namespace ElectronNET +{ + /// + /// Provides configuration options for Electron.NET. Consumers can assign + /// an instance of to the + /// property to hook into the Electron application lifecycle. Additional + /// configuration properties can be added to this class in future versions without + /// breaking existing consumers. + /// + public class ElectronNetOptions + { + /// + /// Gets or sets the collection of lifecycle callbacks. The default value is + /// an instance of with no-op + /// implementations. Assigning a new instance or modifying individual + /// callbacks allows consumers to customize the startup sequence. + /// + public ElectronAppLifetimeEvents Events { get; set; } = new ElectronAppLifetimeEvents(); + } +} \ No newline at end of file diff --git a/src/ElectronNET.API/ElectronNetRuntime.cs b/src/ElectronNET.API/ElectronNetRuntime.cs index 78d976e8..5b822d66 100644 --- a/src/ElectronNET.API/ElectronNetRuntime.cs +++ b/src/ElectronNET.API/ElectronNetRuntime.cs @@ -49,6 +49,12 @@ static ElectronNetRuntime() internal static Func OnAppReadyCallback { get; set; } + /// + /// Global configuration options for the Electron.NET runtime, including + /// lifecycle events that can be configured from the ASP.NET host builder. + /// + public static ElectronNetOptions Options { get; set; } = new ElectronNetOptions(); + internal static SocketIoFacade GetSocket() { return RuntimeControllerCore?.Socket; diff --git a/src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs b/src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs index c6078365..0fe8f805 100644 --- a/src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs +++ b/src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs @@ -3,6 +3,7 @@ using System; using System.IO; using System.Threading.Tasks; + using ElectronNET; using ElectronNET.AspNet; using ElectronNET.AspNet.Runtime; using ElectronNET.Runtime; @@ -57,9 +58,39 @@ public static class WebHostBuilderExtensions /// } /// /// + [Obsolete("This method is deprecated. Please use the overload with the configure parameter")] public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] args, Func onAppReadyCallback) { - ElectronNetRuntime.OnAppReadyCallback = onAppReadyCallback; + if (onAppReadyCallback == null) + { + throw new ArgumentNullException(nameof(onAppReadyCallback)); + } + + // Backwards compatible overload – wraps the single callback into the new options model. + return UseElectron(builder, args, options => + { + options.Events.OnReady = onAppReadyCallback; + }); + } + + /// + /// Adds Electron.NET support to the current ASP.NET Core web host with granular lifecycle + /// configuration. The provided allows registration of callbacks + /// for different phases of the Electron runtime. + /// + public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] args, Action configure) + { + if (configure == null) + { + throw new ArgumentNullException(nameof(configure)); + } + + var options = new ElectronNetOptions(); + configure(options); + ElectronNetRuntime.Options = options; + + // Preserve behaviour of the original API by mapping OnReady to the legacy callback. + ElectronNetRuntime.OnAppReadyCallback = options.Events?.OnReady; var webPort = PortHelper.GetFreePort(ElectronNetRuntime.AspNetWebPort ?? ElectronNetRuntime.DefaultWebPort); ElectronNetRuntime.AspNetWebPort = webPort; diff --git a/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetBase.cs b/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetBase.cs index 65487df8..879e0ba3 100644 --- a/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetBase.cs +++ b/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetBase.cs @@ -2,6 +2,7 @@ { using System; using System.Threading.Tasks; + using ElectronNET; using ElectronNET.API; using ElectronNET.Common; using ElectronNET.Runtime.Controllers; @@ -81,9 +82,22 @@ protected void HandleStopped() (this.aspNetLifetimeAdapter.IsNullOrStopped())) { this.TransitionState(LifetimeState.Stopped); + + // Everything is fully stopped – fire the OnQuit callback. + Task.Run(this.RunQuitCallback); } } + /// + /// Invoked when ASP.NET lifetime enters Stopping (ApplicationStopping). + /// We only trigger the OnWillQuit callback here; the actual state + /// transition to Stopping is handled in . + /// + protected void HandleStopping() + { + Task.Run(this.RunWillQuitCallback); + } + protected abstract override Task StopCore(); private void SocketBridge_Ready(object sender, EventArgs e) @@ -108,10 +122,67 @@ private void AspNetLifetimeAdapter_Stopped(object sender, EventArgs e) private void AspNetLifetimeAdapter_Stopping(object sender, EventArgs e) { + this.HandleStopping(); + } + + private async Task RunWillQuitCallback() + { + var events = ElectronNetRuntime.Options?.Events; + var handler = events?.OnWillQuit; + + if (handler == null) + { + return; + } + + try + { + await handler().ConfigureAwait(false); + } + catch (Exception ex) + { + Console.WriteLine("Exception while executing OnWillQuit callback.\n" + ex); + // We are already stopping; no need to call this.Stop() here. + } + } + + private async Task RunQuitCallback() + { + var events = ElectronNetRuntime.Options?.Events; + var handler = events?.OnQuit; + + if (handler == null) + { + return; + } + + try + { + await handler().ConfigureAwait(false); + } + catch (Exception ex) + { + Console.WriteLine("Exception while executing OnQuit callback.\n" + ex); + } } private async Task RunReadyCallback() { + var events = ElectronNetRuntime.Options?.Events; + if (events?.OnBeforeReady != null) + { + try + { + await events.OnBeforeReady().ConfigureAwait(false); + } + catch (Exception ex) + { + Console.WriteLine("Exception while executing OnBeforeReady callback. Stopping...\n" + ex); + this.Stop(); + return; + } + } + if (ElectronNetRuntime.OnAppReadyCallback == null) { Console.WriteLine("Warning: Non OnReadyCallback provided in UseElectron() setup."); diff --git a/src/ElectronNET.WebApp/Program.cs b/src/ElectronNET.WebApp/Program.cs index d3a36968..e5d0f6fb 100644 --- a/src/ElectronNET.WebApp/Program.cs +++ b/src/ElectronNET.WebApp/Program.cs @@ -5,6 +5,7 @@ namespace ElectronNET.WebApp { + using System; using System.Threading.Tasks; using ElectronNET.API.Entities; @@ -23,20 +24,28 @@ public static IWebHostBuilder CreateWebHostBuilder(string[] args) .UseStartup(); } - public static async Task ElectronBootstrap() + private static void ElectronBootstrap(ElectronNetOptions options) { - //AddDevelopmentTests(); - - var browserWindow = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions + options.Events = new() { - Width = 1152, - Height = 940, - Show = false - }); + OnBeforeReady = async () => + { + Console.WriteLine("Firing before ready callback!"); + }, + OnReady = async () => + { + var window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions + { + Width = 1152, + Height = 940, + Show = false + }); - await browserWindow.WebContents.Session.ClearCacheAsync(); + await window.WebContents.Session.ClearCacheAsync(); - browserWindow.OnReadyToShow += () => browserWindow.Show(); + window.OnReadyToShow += window.Show; + } + }; } private static void AddDevelopmentTests() From 03c9b9912e489dda9ed17b41438894a989561337 Mon Sep 17 00:00:00 2001 From: Denny09310 Date: Tue, 18 Nov 2025 11:25:43 +0100 Subject: [PATCH 2/3] feat: added WebApplicationBuilder overload, removed Obsolete attribute, removed static OnAppReadyCallback in favor of Events.OnReady --- src/ElectronNET.API/ElectronNetRuntime.cs | 2 -- .../API/WebApplicationBuilderExtensions.cs | 13 ++++++++++++- .../API/WebHostBuilderExtensions.cs | 8 ++------ .../Controllers/RuntimeControllerAspNetBase.cs | 4 ++-- src/ElectronNET.WebApp/Program.cs | 2 +- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/ElectronNET.API/ElectronNetRuntime.cs b/src/ElectronNET.API/ElectronNetRuntime.cs index 5b822d66..4e979221 100644 --- a/src/ElectronNET.API/ElectronNetRuntime.cs +++ b/src/ElectronNET.API/ElectronNetRuntime.cs @@ -47,8 +47,6 @@ static ElectronNetRuntime() internal static int? ElectronProcessId { get; set; } - internal static Func OnAppReadyCallback { get; set; } - /// /// Global configuration options for the Electron.NET runtime, including /// lifecycle events that can be configured from the ASP.NET host builder. diff --git a/src/ElectronNET.AspNet/API/WebApplicationBuilderExtensions.cs b/src/ElectronNET.AspNet/API/WebApplicationBuilderExtensions.cs index 0283bea1..59247a5f 100644 --- a/src/ElectronNET.AspNet/API/WebApplicationBuilderExtensions.cs +++ b/src/ElectronNET.AspNet/API/WebApplicationBuilderExtensions.cs @@ -40,7 +40,18 @@ public static class WebApplicationBuilderExtensions /// public static WebApplicationBuilder UseElectron(this WebApplicationBuilder builder, string[] args, Func onAppReadyCallback) { - builder.WebHost.UseElectron(args, onAppReadyCallback); + return UseElectron(builder, options => + { + options.Events = new() + { + OnReady = onAppReadyCallback + }; + }); + } + + public static WebApplicationBuilder UseElectron(this WebApplicationBuilder builder, Action configure) + { + builder.WebHost.UseElectron(configure); return builder; } diff --git a/src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs b/src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs index 0fe8f805..dd643bbf 100644 --- a/src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs +++ b/src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs @@ -58,7 +58,6 @@ public static class WebHostBuilderExtensions /// } /// /// - [Obsolete("This method is deprecated. Please use the overload with the configure parameter")] public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] args, Func onAppReadyCallback) { if (onAppReadyCallback == null) @@ -67,7 +66,7 @@ public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] } // Backwards compatible overload – wraps the single callback into the new options model. - return UseElectron(builder, args, options => + return UseElectron(builder, options => { options.Events.OnReady = onAppReadyCallback; }); @@ -78,7 +77,7 @@ public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] /// configuration. The provided allows registration of callbacks /// for different phases of the Electron runtime. /// - public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] args, Action configure) + public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, Action configure) { if (configure == null) { @@ -89,9 +88,6 @@ public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] configure(options); ElectronNetRuntime.Options = options; - // Preserve behaviour of the original API by mapping OnReady to the legacy callback. - ElectronNetRuntime.OnAppReadyCallback = options.Events?.OnReady; - var webPort = PortHelper.GetFreePort(ElectronNetRuntime.AspNetWebPort ?? ElectronNetRuntime.DefaultWebPort); ElectronNetRuntime.AspNetWebPort = webPort; diff --git a/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetBase.cs b/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetBase.cs index 879e0ba3..66189a79 100644 --- a/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetBase.cs +++ b/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetBase.cs @@ -183,7 +183,7 @@ private async Task RunReadyCallback() } } - if (ElectronNetRuntime.OnAppReadyCallback == null) + if (events.OnReady == null) { Console.WriteLine("Warning: Non OnReadyCallback provided in UseElectron() setup."); return; @@ -191,7 +191,7 @@ private async Task RunReadyCallback() try { - await ElectronNetRuntime.OnAppReadyCallback().ConfigureAwait(false); + await events.OnReady().ConfigureAwait(false); } catch (Exception ex) { diff --git a/src/ElectronNET.WebApp/Program.cs b/src/ElectronNET.WebApp/Program.cs index e5d0f6fb..f064a92d 100644 --- a/src/ElectronNET.WebApp/Program.cs +++ b/src/ElectronNET.WebApp/Program.cs @@ -20,7 +20,7 @@ public static IWebHostBuilder CreateWebHostBuilder(string[] args) { return WebHost.CreateDefaultBuilder(args) .ConfigureLogging((hostingContext, logging) => { logging.AddConsole(); }) - .UseElectron(args, ElectronBootstrap) + .UseElectron(ElectronBootstrap) .UseStartup(); } From 2b227bba6fb852f0d5982cdbee263237cdc440d9 Mon Sep 17 00:00:00 2001 From: Denny09310 <50493437+Denny09310@users.noreply.github.com> Date: Wed, 19 Nov 2025 09:18:49 +0100 Subject: [PATCH 3/3] Refactor runtime host initialization --- docs/GettingStarted/ASP.Net.md | 4 +- docs/GettingStarted/Console-App.md | 3 +- docs/Using/Startup-Methods.md | 4 +- src/ElectronNET.API/API/HybridSupport.cs | 10 +-- src/ElectronNET.API/API/WindowManager.cs | 6 +- src/ElectronNET.API/Bridge/BridgeConnector.cs | 4 +- src/ElectronNET.API/ElectronNetRuntime.cs | 61 ------------------- .../RuntimeControllerDotNetFirst.cs | 13 ++-- .../RuntimeControllerElectronFirst.cs | 7 ++- src/ElectronNET.API/Runtime/ElectronHost.cs | 57 +++++++++++++++++ .../Runtime/ElectronHostDefaults.cs | 13 ++++ .../Runtime/ElectronHostEnvironment.cs | 18 ++++++ .../Runtime/Helpers/LaunchOrderDetector.cs | 6 +- .../Runtime/Helpers/UnpackagedDetector.cs | 7 ++- src/ElectronNET.API/Runtime/IElectronHost.cs | 38 ++++++++++++ src/ElectronNET.API/Runtime/StartupManager.cs | 38 +++++++----- .../API/WebHostBuilderExtensions.cs | 11 ++-- .../RuntimeControllerAspNetBase.cs | 9 +-- .../RuntimeControllerAspNetDotnetFirst.cs | 12 ++-- .../RuntimeControllerAspNetElectronFirst.cs | 8 ++- src/ElectronNET.ConsoleApp/Program.cs | 3 +- .../ElectronFixture.cs | 8 ++- .../Controllers/CrashHangController.cs | 7 ++- .../Controllers/WindowsController.cs | 4 +- 24 files changed, 225 insertions(+), 126 deletions(-) delete mode 100644 src/ElectronNET.API/ElectronNetRuntime.cs create mode 100644 src/ElectronNET.API/Runtime/ElectronHost.cs create mode 100644 src/ElectronNET.API/Runtime/ElectronHostDefaults.cs create mode 100644 src/ElectronNET.API/Runtime/ElectronHostEnvironment.cs create mode 100644 src/ElectronNET.API/Runtime/IElectronHost.cs diff --git a/docs/GettingStarted/ASP.Net.md b/docs/GettingStarted/ASP.Net.md index 953a6410..3c7b36ee 100644 --- a/docs/GettingStarted/ASP.Net.md +++ b/docs/GettingStarted/ASP.Net.md @@ -88,11 +88,11 @@ public class Program #### ASP.NET Port -If you want to launch a specific URL, you can retrieve the actual ASP.NET port from the new `ElectronNetRuntime` static class, for example: +If you want to launch a specific URL, you can retrieve the actual ASP.NET port from `ElectronHostEnvironment.Current`, for example: ```csharp await browserWindow.WebContents - .LoadURLAsync($"http://localhost:{ElectronNetRuntime.AspNetWebPort}/mypage.html"); + .LoadURLAsync($"http://localhost:{ElectronNET.Runtime.ElectronHostEnvironment.Current.AspNetWebPort}/mypage.html"); ``` ### 4. Alternative: IWebHostBuilder Setup diff --git a/docs/GettingStarted/Console-App.md b/docs/GettingStarted/Console-App.md index 4a006713..48da298f 100644 --- a/docs/GettingStarted/Console-App.md +++ b/docs/GettingStarted/Console-App.md @@ -71,6 +71,7 @@ Here's a complete console application example: using System; using System.Threading.Tasks; using ElectronNET.API.Entities; +using ElectronNET.Runtime; namespace MyElectronApp @@ -78,7 +79,7 @@ public class Program { public static async Task Main(string[] args) { - var runtimeController = ElectronNetRuntime.RuntimeController; + var runtimeController = ElectronHostEnvironment.Current.RuntimeController; try { diff --git a/docs/Using/Startup-Methods.md b/docs/Using/Startup-Methods.md index 1c684839..f6cdee6a 100644 --- a/docs/Using/Startup-Methods.md +++ b/docs/Using/Startup-Methods.md @@ -106,7 +106,7 @@ app.Run(); // Program.cs public static async Task Main(string[] args) { - var runtimeController = ElectronNetRuntime.RuntimeController; + var runtimeController = ElectronNET.Runtime.ElectronHostEnvironment.Current.RuntimeController; await runtimeController.Start(); await runtimeController.WaitReadyTask; @@ -189,7 +189,7 @@ ElectronNET.Core automatically manages process lifecycle: Access runtime controller for advanced scenarios: ```csharp -var runtime = ElectronNetRuntime.RuntimeController; +var runtime = ElectronNET.Runtime.ElectronHostEnvironment.Current.RuntimeController; // Wait for Electron to be ready await runtime.WaitReadyTask; diff --git a/src/ElectronNET.API/API/HybridSupport.cs b/src/ElectronNET.API/API/HybridSupport.cs index a84641e7..e59de8ec 100644 --- a/src/ElectronNET.API/API/HybridSupport.cs +++ b/src/ElectronNET.API/API/HybridSupport.cs @@ -1,7 +1,9 @@ -namespace ElectronNET.API +namespace ElectronNET.API { + using ElectronNET.Runtime; + /// - /// + /// /// public static class HybridSupport { @@ -15,8 +17,8 @@ public static bool IsElectronActive { get { - return ElectronNetRuntime.RuntimeController != null; + return ElectronHostEnvironment.Current.RuntimeController != null; } } } -} \ No newline at end of file +} diff --git a/src/ElectronNET.API/API/WindowManager.cs b/src/ElectronNET.API/API/WindowManager.cs index 20a6b193..76ba767b 100644 --- a/src/ElectronNET.API/API/WindowManager.cs +++ b/src/ElectronNET.API/API/WindowManager.cs @@ -1,5 +1,6 @@ using ElectronNET.API.Entities; using ElectronNET.API.Serialization; +using ElectronNET.Runtime; using System; using System.Collections.Generic; using System.Linq; @@ -117,9 +118,10 @@ public async Task CreateWindowAsync(BrowserWindowOptions options, } }); - if (loadUrl.Equals("http://localhost", StringComparison.OrdinalIgnoreCase) && ElectronNetRuntime.AspNetWebPort.HasValue) + var host = ElectronHostEnvironment.Current; + if (loadUrl.Equals("http://localhost", StringComparison.OrdinalIgnoreCase) && host.AspNetWebPort.HasValue) { - loadUrl = $"{loadUrl}:{ElectronNetRuntime.AspNetWebPort}"; + loadUrl = $"{loadUrl}:{host.AspNetWebPort}"; } // Workaround Windows 10 / Electron Bug diff --git a/src/ElectronNET.API/Bridge/BridgeConnector.cs b/src/ElectronNET.API/Bridge/BridgeConnector.cs index 3c06b430..7aedb11f 100644 --- a/src/ElectronNET.API/Bridge/BridgeConnector.cs +++ b/src/ElectronNET.API/Bridge/BridgeConnector.cs @@ -2,13 +2,15 @@ // ReSharper disable once CheckNamespace namespace ElectronNET.API { + using ElectronNET.Runtime; + internal static class BridgeConnector { public static SocketIoFacade Socket { get { - return ElectronNetRuntime.GetSocket(); + return ElectronHostEnvironment.Current.GetSocket(); } } } diff --git a/src/ElectronNET.API/ElectronNetRuntime.cs b/src/ElectronNET.API/ElectronNetRuntime.cs deleted file mode 100644 index 4e979221..00000000 --- a/src/ElectronNET.API/ElectronNetRuntime.cs +++ /dev/null @@ -1,61 +0,0 @@ -namespace ElectronNET -{ - using ElectronNET.API; - using ElectronNET.Runtime; - using ElectronNET.Runtime.Controllers; - using ElectronNET.Runtime.Data; - using System; - using System.Collections.Immutable; - using System.Threading.Tasks; - - public static class ElectronNetRuntime - { - internal static StartupManager StartupManager; - - internal const int DefaultSocketPort = 8000; - internal const int DefaultWebPort = 8001; - internal const string ElectronPortArgumentName = "electronPort"; - internal const string ElectronPidArgumentName = "electronPID"; - - /// Initializes the class. - static ElectronNetRuntime() - { - StartupManager = new StartupManager(); - StartupManager.Initialize(); - } - - public static string ElectronExtraArguments { get; set; } - - public static int? ElectronSocketPort { get; internal set; } - - public static int? AspNetWebPort { get; internal set; } - - public static StartupMethod StartupMethod { get; internal set; } - - public static DotnetAppType DotnetAppType { get; internal set; } - - public static string ElectronExecutable { get; internal set; } - - public static ImmutableList ProcessArguments { get; internal set; } - - public static BuildInfo BuildInfo { get; internal set; } - - public static IElectronNetRuntimeController RuntimeController => RuntimeControllerCore; - - // The below properties are non-public - internal static RuntimeControllerBase RuntimeControllerCore { get; set; } - - internal static int? ElectronProcessId { get; set; } - - /// - /// Global configuration options for the Electron.NET runtime, including - /// lifecycle events that can be configured from the ASP.NET host builder. - /// - public static ElectronNetOptions Options { get; set; } = new ElectronNetOptions(); - - internal static SocketIoFacade GetSocket() - { - return RuntimeControllerCore?.Socket; - } - } -} \ No newline at end of file diff --git a/src/ElectronNET.API/Runtime/Controllers/RuntimeControllerDotNetFirst.cs b/src/ElectronNET.API/Runtime/Controllers/RuntimeControllerDotNetFirst.cs index 70591674..2299d15c 100644 --- a/src/ElectronNET.API/Runtime/Controllers/RuntimeControllerDotNetFirst.cs +++ b/src/ElectronNET.API/Runtime/Controllers/RuntimeControllerDotNetFirst.cs @@ -38,15 +38,16 @@ internal override SocketIoFacade Socket protected override Task StartCore() { - var isUnPacked = ElectronNetRuntime.StartupMethod.IsUnpackaged(); - var electronBinaryName = ElectronNetRuntime.ElectronExecutable; - var args = string.Format("{0} {1}", ElectronNetRuntime.ElectronExtraArguments, Environment.CommandLine).Trim(); - this.port = ElectronNetRuntime.ElectronSocketPort; + var host = ElectronHostEnvironment.InternalHost; + var isUnPacked = host.StartupMethod.IsUnpackaged(); + var electronBinaryName = host.ElectronExecutable; + var args = string.Format("{0} {1}", host.ElectronExtraArguments, Environment.CommandLine).Trim(); + this.port = host.ElectronSocketPort; if (!this.port.HasValue) { - this.port = PortHelper.GetFreePort(ElectronNetRuntime.DefaultSocketPort); - ElectronNetRuntime.ElectronSocketPort = this.port; + this.port = PortHelper.GetFreePort(ElectronHostDefaults.DefaultSocketPort); + host.ElectronSocketPort = this.port; } Console.Error.WriteLine("[StartCore]: isUnPacked: {0}", isUnPacked); diff --git a/src/ElectronNET.API/Runtime/Controllers/RuntimeControllerElectronFirst.cs b/src/ElectronNET.API/Runtime/Controllers/RuntimeControllerElectronFirst.cs index fdb458f0..8f091ac9 100644 --- a/src/ElectronNET.API/Runtime/Controllers/RuntimeControllerElectronFirst.cs +++ b/src/ElectronNET.API/Runtime/Controllers/RuntimeControllerElectronFirst.cs @@ -36,14 +36,15 @@ internal override SocketIoFacade Socket protected override Task StartCore() { - this.port = ElectronNetRuntime.ElectronSocketPort; + var host = ElectronHostEnvironment.InternalHost; + this.port = host.ElectronSocketPort; if (!this.port.HasValue) { throw new Exception("No port has been specified by Electron!"); } - if (!ElectronNetRuntime.ElectronProcessId.HasValue) + if (!host.ElectronProcessId.HasValue) { throw new Exception("No electronPID has been specified by Electron!"); } @@ -54,7 +55,7 @@ protected override Task StartCore() this.socketBridge.Stopped += this.SocketBridge_Stopped; this.socketBridge.Start(); - this.electronProcess = new ElectronProcessPassive(ElectronNetRuntime.ElectronProcessId.Value); + this.electronProcess = new ElectronProcessPassive(host.ElectronProcessId.Value); this.electronProcess.Ready += this.ElectronProcess_Ready; this.electronProcess.Stopped += this.ElectronProcess_Stopped; diff --git a/src/ElectronNET.API/Runtime/ElectronHost.cs b/src/ElectronNET.API/Runtime/ElectronHost.cs new file mode 100644 index 00000000..a45ead5f --- /dev/null +++ b/src/ElectronNET.API/Runtime/ElectronHost.cs @@ -0,0 +1,57 @@ +namespace ElectronNET.Runtime +{ + using System.Collections.Immutable; + using ElectronNET.Runtime.Controllers; + using ElectronNET.Runtime.Data; + + /// + /// Default implementation of that keeps track of the + /// runtime state shared between the Electron.NET CLI bootstrapper and ASP.NET + /// applications. + /// + public sealed class ElectronHost : IElectronHost + { + private readonly StartupManager startupManager; + + public ElectronHost() + { + this.Options = new ElectronNetOptions(); + this.startupManager = new StartupManager(this); + this.startupManager.Initialize(); + } + + public string ElectronExtraArguments { get; set; } + + public int? ElectronSocketPort { get; set; } + + public int? AspNetWebPort { get; set; } + + public StartupMethod StartupMethod { get; set; } + + public DotnetAppType DotnetAppType { get; set; } + + public string ElectronExecutable { get; set; } + + public ImmutableList ProcessArguments { get; set; } + + public BuildInfo BuildInfo { get; set; } + + public IElectronNetRuntimeController RuntimeController => this.RuntimeControllerCore; + + public int? ElectronProcessId { get; set; } + + public ElectronNetOptions Options { get; private set; } + + internal RuntimeControllerBase RuntimeControllerCore { get; set; } + + public SocketIoFacade GetSocket() + { + return this.RuntimeControllerCore?.Socket; + } + + public void ApplyOptions(ElectronNetOptions options) + { + this.Options = options ?? new ElectronNetOptions(); + } + } +} diff --git a/src/ElectronNET.API/Runtime/ElectronHostDefaults.cs b/src/ElectronNET.API/Runtime/ElectronHostDefaults.cs new file mode 100644 index 00000000..c0eb865c --- /dev/null +++ b/src/ElectronNET.API/Runtime/ElectronHostDefaults.cs @@ -0,0 +1,13 @@ +namespace ElectronNET.Runtime +{ + /// + /// Provides shared default values for the Electron.NET runtime host. + /// + public static class ElectronHostDefaults + { + public const int DefaultSocketPort = 8000; + public const int DefaultWebPort = 8001; + public const string ElectronPortArgumentName = "electronPort"; + public const string ElectronPidArgumentName = "electronPID"; + } +} diff --git a/src/ElectronNET.API/Runtime/ElectronHostEnvironment.cs b/src/ElectronNET.API/Runtime/ElectronHostEnvironment.cs new file mode 100644 index 00000000..86130c69 --- /dev/null +++ b/src/ElectronNET.API/Runtime/ElectronHostEnvironment.cs @@ -0,0 +1,18 @@ +namespace ElectronNET.Runtime +{ + using System; + + /// + /// Provides access to the singleton instance that is + /// used across the application. Consumers can resolve the same instance from + /// dependency injection via services.AddSingleton(ElectronHostEnvironment.Current). + /// + public static class ElectronHostEnvironment + { + private static readonly Lazy LazyHost = new(() => new ElectronHost()); + + public static IElectronHost Current => LazyHost.Value; + + internal static ElectronHost InternalHost => LazyHost.Value; + } +} diff --git a/src/ElectronNET.API/Runtime/Helpers/LaunchOrderDetector.cs b/src/ElectronNET.API/Runtime/Helpers/LaunchOrderDetector.cs index 203fb476..eb32ae84 100644 --- a/src/ElectronNET.API/Runtime/Helpers/LaunchOrderDetector.cs +++ b/src/ElectronNET.API/Runtime/Helpers/LaunchOrderDetector.cs @@ -38,7 +38,8 @@ public static bool CheckIsLaunchedByDotNet() private static bool? CheckIsDotNetStartup1() { - var hasPortArg = ElectronNetRuntime.ProcessArguments.Any(e => e.Contains(ElectronNetRuntime.ElectronPortArgumentName, StringComparison.OrdinalIgnoreCase)); + var host = ElectronHostEnvironment.InternalHost; + var hasPortArg = host.ProcessArguments.Any(e => e.Contains(ElectronHostDefaults.ElectronPortArgumentName, StringComparison.OrdinalIgnoreCase)); if (hasPortArg) { return false; @@ -50,7 +51,8 @@ public static bool CheckIsLaunchedByDotNet() private static bool? CheckIsDotNetStartup2() { - var hasPidArg = ElectronNetRuntime.ProcessArguments.Any(e => e.Contains(ElectronNetRuntime.ElectronPidArgumentName, StringComparison.OrdinalIgnoreCase)); + var host = ElectronHostEnvironment.InternalHost; + var hasPidArg = host.ProcessArguments.Any(e => e.Contains(ElectronHostDefaults.ElectronPidArgumentName, StringComparison.OrdinalIgnoreCase)); if (hasPidArg) { return false; diff --git a/src/ElectronNET.API/Runtime/Helpers/UnpackagedDetector.cs b/src/ElectronNET.API/Runtime/Helpers/UnpackagedDetector.cs index f5c5f549..3e1e22b8 100644 --- a/src/ElectronNET.API/Runtime/Helpers/UnpackagedDetector.cs +++ b/src/ElectronNET.API/Runtime/Helpers/UnpackagedDetector.cs @@ -44,7 +44,7 @@ public static bool CheckIsUnpackaged() private static bool? CheckUnpackaged1() { - var cfg = ElectronNetRuntime.BuildInfo.BuildConfiguration; + var cfg = ElectronHostEnvironment.InternalHost.BuildInfo.BuildConfiguration; if (cfg != null) { if (cfg.Equals("Debug", StringComparison.OrdinalIgnoreCase)) @@ -90,14 +90,15 @@ public static bool CheckIsUnpackaged() private static bool? CheckUnpackaged4() { - var isUnpackaged = ElectronNetRuntime.ProcessArguments.Any(e => e.Contains("unpacked", StringComparison.OrdinalIgnoreCase)); + var host = ElectronHostEnvironment.InternalHost; + var isUnpackaged = host.ProcessArguments.Any(e => e.Contains("unpacked", StringComparison.OrdinalIgnoreCase)); if (isUnpackaged) { return true; } - var isPackaged = ElectronNetRuntime.ProcessArguments.Any(e => e.Contains("dotnetpacked", StringComparison.OrdinalIgnoreCase)); + var isPackaged = host.ProcessArguments.Any(e => e.Contains("dotnetpacked", StringComparison.OrdinalIgnoreCase)); if (isPackaged) { return false; diff --git a/src/ElectronNET.API/Runtime/IElectronHost.cs b/src/ElectronNET.API/Runtime/IElectronHost.cs new file mode 100644 index 00000000..10ab2f00 --- /dev/null +++ b/src/ElectronNET.API/Runtime/IElectronHost.cs @@ -0,0 +1,38 @@ +namespace ElectronNET.Runtime +{ + using System.Collections.Immutable; + using ElectronNET.Runtime.Controllers; + using ElectronNET.Runtime.Data; + + /// + /// Represents the mutable runtime state for the Electron.NET host. Consumers can + /// resolve this interface from dependency injection to inspect the current + /// startup mode, configured ports and the active runtime controller. + /// + public interface IElectronHost + { + string ElectronExtraArguments { get; set; } + + int? ElectronSocketPort { get; set; } + + int? AspNetWebPort { get; set; } + + StartupMethod StartupMethod { get; set; } + + DotnetAppType DotnetAppType { get; set; } + + string ElectronExecutable { get; set; } + + ImmutableList ProcessArguments { get; set; } + + BuildInfo BuildInfo { get; set; } + + IElectronNetRuntimeController RuntimeController { get; } + + int? ElectronProcessId { get; set; } + + ElectronNetOptions Options { get; } + + SocketIoFacade GetSocket(); + } +} diff --git a/src/ElectronNET.API/Runtime/StartupManager.cs b/src/ElectronNET.API/Runtime/StartupManager.cs index 125b6dee..9cf85a7c 100644 --- a/src/ElectronNET.API/Runtime/StartupManager.cs +++ b/src/ElectronNET.API/Runtime/StartupManager.cs @@ -11,11 +11,18 @@ internal class StartupManager { + private readonly ElectronHost host; + + public StartupManager(ElectronHost host) + { + this.host = host ?? throw new ArgumentNullException(nameof(host)); + } + public void Initialize() { try { - ElectronNetRuntime.BuildInfo = this.GatherBuildInfo(); + this.host.BuildInfo = this.GatherBuildInfo(); } catch (Exception ex) { @@ -25,19 +32,18 @@ public void Initialize() this.CollectProcessData(); this.SetElectronExecutable(); + this.host.StartupMethod = this.DetectAppTypeAndStartup(); + Console.WriteLine((string)("Evaluated StartupMethod: " + this.host.StartupMethod)); - ElectronNetRuntime.StartupMethod = this.DetectAppTypeAndStartup(); - Console.WriteLine((string)("Evaluated StartupMethod: " + ElectronNetRuntime.StartupMethod)); - - if (ElectronNetRuntime.DotnetAppType != DotnetAppType.AspNetCoreApp) + if (this.host.DotnetAppType != DotnetAppType.AspNetCoreApp) { - ElectronNetRuntime.RuntimeControllerCore = this.CreateRuntimeController(); + this.host.RuntimeControllerCore = this.CreateRuntimeController(); } } private RuntimeControllerBase CreateRuntimeController() { - switch (ElectronNetRuntime.StartupMethod) + switch (this.host.StartupMethod) { case StartupMethod.PackagedDotnetFirst: case StartupMethod.UnpackedDotnetFirst: @@ -79,29 +85,29 @@ private void CollectProcessData() { var argsList = Environment.GetCommandLineArgs().ToImmutableList(); - ElectronNetRuntime.ProcessArguments = argsList; + this.host.ProcessArguments = argsList; - var portArg = argsList.FirstOrDefault(e => e.Contains(ElectronNetRuntime.ElectronPortArgumentName, StringComparison.OrdinalIgnoreCase)); + var portArg = argsList.FirstOrDefault(e => e.Contains(ElectronHostDefaults.ElectronPortArgumentName, StringComparison.OrdinalIgnoreCase)); if (portArg != null) { var parts = portArg.Split('=', StringSplitOptions.TrimEntries); if (parts.Length > 1 && int.TryParse(parts[1], NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out var result)) { - ElectronNetRuntime.ElectronSocketPort = result; + this.host.ElectronSocketPort = result; Console.WriteLine("Use Electron Port: " + result); } } - var pidArg = argsList.FirstOrDefault(e => e.Contains(ElectronNetRuntime.ElectronPidArgumentName, StringComparison.OrdinalIgnoreCase)); + var pidArg = argsList.FirstOrDefault(e => e.Contains(ElectronHostDefaults.ElectronPidArgumentName, StringComparison.OrdinalIgnoreCase)); if (pidArg != null) { var parts = pidArg.Split('=', StringSplitOptions.TrimEntries); if (parts.Length > 1 && int.TryParse(parts[1], NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out var result)) { - ElectronNetRuntime.ElectronProcessId = result; + this.host.ElectronProcessId = result; Console.WriteLine("Electron Process ID: " + result); } @@ -110,7 +116,7 @@ private void CollectProcessData() private void SetElectronExecutable() { - string executable = ElectronNetRuntime.BuildInfo.ElectronExecutable; + string executable = this.host.BuildInfo.ElectronExecutable; if (string.IsNullOrEmpty(executable)) { throw new Exception("AssemblyMetadataAttribute 'ElectronExecutable' could not be found!"); @@ -121,7 +127,7 @@ private void SetElectronExecutable() executable += ".exe"; } - ElectronNetRuntime.ElectronExecutable = executable; + this.host.ElectronExecutable = executable; } private BuildInfo GatherBuildInfo() @@ -162,7 +168,7 @@ private BuildInfo GatherBuildInfo() if (isAspNet?.Length > 0 && bool.TryParse(isAspNet, out var isAspNetActive) && isAspNetActive) { - ElectronNetRuntime.DotnetAppType = DotnetAppType.AspNetCoreApp; + this.host.DotnetAppType = DotnetAppType.AspNetCoreApp; } if (isSingleInstance?.Length > 0 && bool.TryParse(isSingleInstance, out var isSingleInstanceActive) && isSingleInstanceActive) @@ -176,7 +182,7 @@ private BuildInfo GatherBuildInfo() if (httpPort?.Length > 0 && int.TryParse(httpPort, out var port)) { - ElectronNetRuntime.AspNetWebPort = port; + this.host.AspNetWebPort = port; } } diff --git a/src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs b/src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs index dd643bbf..1aa9280b 100644 --- a/src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs +++ b/src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs @@ -86,10 +86,12 @@ public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, Action(); services.AddSingleton(); + services.AddSingleton(host); - switch (ElectronNetRuntime.StartupMethod) + switch (host.StartupMethod) { case StartupMethod.PackagedElectronFirst: case StartupMethod.UnpackedElectronFirst: diff --git a/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetBase.cs b/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetBase.cs index 66189a79..bc9ba3bb 100644 --- a/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetBase.cs +++ b/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetBase.cs @@ -5,6 +5,7 @@ using ElectronNET; using ElectronNET.API; using ElectronNET.Common; + using ElectronNET.Runtime; using ElectronNET.Runtime.Controllers; using ElectronNET.Runtime.Data; using ElectronNET.Runtime.Services.SocketBridge; @@ -21,7 +22,7 @@ protected RuntimeControllerAspNetBase(AspNetLifetimeAdapter aspNetLifetimeAdapte this.aspNetLifetimeAdapter.Stopping += this.AspNetLifetimeAdapter_Stopping; this.aspNetLifetimeAdapter.Stopped += this.AspNetLifetimeAdapter_Stopped; - ElectronNetRuntime.RuntimeControllerCore = this; + ElectronHostEnvironment.InternalHost.RuntimeControllerCore = this; } internal override SocketBridgeService SocketBridge => this.socketBridge; @@ -127,7 +128,7 @@ private void AspNetLifetimeAdapter_Stopping(object sender, EventArgs e) private async Task RunWillQuitCallback() { - var events = ElectronNetRuntime.Options?.Events; + var events = ElectronHostEnvironment.InternalHost.Options?.Events; var handler = events?.OnWillQuit; if (handler == null) @@ -148,7 +149,7 @@ private async Task RunWillQuitCallback() private async Task RunQuitCallback() { - var events = ElectronNetRuntime.Options?.Events; + var events = ElectronHostEnvironment.InternalHost.Options?.Events; var handler = events?.OnQuit; if (handler == null) @@ -168,7 +169,7 @@ private async Task RunQuitCallback() private async Task RunReadyCallback() { - var events = ElectronNetRuntime.Options?.Events; + var events = ElectronHostEnvironment.InternalHost.Options?.Events; if (events?.OnBeforeReady != null) { try diff --git a/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetDotnetFirst.cs b/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetDotnetFirst.cs index 4c762915..5eaedad0 100644 --- a/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetDotnetFirst.cs +++ b/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetDotnetFirst.cs @@ -3,6 +3,7 @@ using System; using System.Threading.Tasks; using ElectronNET.Common; + using ElectronNET.Runtime; using ElectronNET.Runtime.Data; using ElectronNET.Runtime.Helpers; using ElectronNET.Runtime.Services.ElectronProcess; @@ -20,15 +21,16 @@ public RuntimeControllerAspNetDotnetFirst(AspNetLifetimeAdapter aspNetLifetimeAd protected override Task StartCore() { - var isUnPacked = ElectronNetRuntime.StartupMethod.IsUnpackaged(); - var electronBinaryName = ElectronNetRuntime.ElectronExecutable; + var host = ElectronNET.Runtime.ElectronHostEnvironment.InternalHost; + var isUnPacked = host.StartupMethod.IsUnpackaged(); + var electronBinaryName = host.ElectronExecutable; var args = Environment.CommandLine; - this.port = ElectronNetRuntime.ElectronSocketPort; + this.port = host.ElectronSocketPort; if (!this.port.HasValue) { - this.port = PortHelper.GetFreePort(ElectronNetRuntime.DefaultSocketPort); - ElectronNetRuntime.ElectronSocketPort = this.port; + this.port = PortHelper.GetFreePort(ElectronHostDefaults.DefaultSocketPort); + host.ElectronSocketPort = this.port; } this.electronProcess = new ElectronProcessActive(isUnPacked, electronBinaryName, args, this.port.Value); diff --git a/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetElectronFirst.cs b/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetElectronFirst.cs index c9eb0697..0c6be056 100644 --- a/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetElectronFirst.cs +++ b/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetElectronFirst.cs @@ -2,6 +2,7 @@ { using System; using System.Threading.Tasks; + using ElectronNET.Runtime; using ElectronNET.Runtime.Data; using ElectronNET.Runtime.Services.ElectronProcess; @@ -18,21 +19,22 @@ public RuntimeControllerAspNetElectronFirst(AspNetLifetimeAdapter aspNetLifetime protected override Task StartCore() { - this.port = ElectronNetRuntime.ElectronSocketPort; + var host = ElectronHostEnvironment.InternalHost; + this.port = host.ElectronSocketPort; if (!this.port.HasValue) { throw new Exception("No port has been specified by Electron!"); } - if (!ElectronNetRuntime.ElectronProcessId.HasValue) + if (!host.ElectronProcessId.HasValue) { throw new Exception("No electronPID has been specified by Electron!"); } this.CreateSocketBridge(this.port!.Value); - this.electronProcess = new ElectronProcessPassive(ElectronNetRuntime.ElectronProcessId.Value); + this.electronProcess = new ElectronProcessPassive(host.ElectronProcessId.Value); this.electronProcess.Stopped += this.ElectronProcess_Stopped; this.electronProcess.Start(); diff --git a/src/ElectronNET.ConsoleApp/Program.cs b/src/ElectronNET.ConsoleApp/Program.cs index 858473cc..22f98105 100644 --- a/src/ElectronNET.ConsoleApp/Program.cs +++ b/src/ElectronNET.ConsoleApp/Program.cs @@ -1,4 +1,5 @@ using ElectronNET.API; +using ElectronNET.Runtime; namespace ElectronNET.WebApp { @@ -10,7 +11,7 @@ public class Program { public static async Task Main(string[] args) { - var runtimeController = ElectronNetRuntime.RuntimeController; + var runtimeController = ElectronHostEnvironment.Current.RuntimeController; try { diff --git a/src/ElectronNET.IntegrationTests/ElectronFixture.cs b/src/ElectronNET.IntegrationTests/ElectronFixture.cs index cfaf8df2..4457a3be 100644 --- a/src/ElectronNET.IntegrationTests/ElectronFixture.cs +++ b/src/ElectronNET.IntegrationTests/ElectronFixture.cs @@ -4,6 +4,7 @@ namespace ElectronNET.IntegrationTests using System.Reflection; using ElectronNET.API; using ElectronNET.API.Entities; + using ElectronNET.Runtime; // Shared fixture that starts Electron runtime once [SuppressMessage("ReSharper", "MethodHasAsyncOverload")] @@ -19,8 +20,9 @@ public async Task InitializeAsync() AppDomain.CurrentDomain.SetData("ElectronTestAssembly", Assembly.GetExecutingAssembly()); Console.WriteLine("[ElectronFixture] Acquire RuntimeController"); - var runtimeController = ElectronNetRuntime.RuntimeController; - ElectronNetRuntime.ElectronExtraArguments = "--no-sandbox"; + var host = ElectronHostEnvironment.Current; + var runtimeController = host.RuntimeController; + host.ElectronExtraArguments = "--no-sandbox"; Console.Error.WriteLine("[ElectronFixture] Starting Electron runtime..."); await runtimeController.Start(); @@ -55,7 +57,7 @@ public async Task InitializeAsync() public async Task DisposeAsync() { - var runtimeController = ElectronNetRuntime.RuntimeController; + var runtimeController = ElectronHostEnvironment.Current.RuntimeController; Console.Error.WriteLine("[ElectronFixture] Stopping Electron runtime..."); await runtimeController.Stop(); await runtimeController.WaitStoppedTask; diff --git a/src/ElectronNET.WebApp/Controllers/CrashHangController.cs b/src/ElectronNET.WebApp/Controllers/CrashHangController.cs index e298dede..c75addf3 100644 --- a/src/ElectronNET.WebApp/Controllers/CrashHangController.cs +++ b/src/ElectronNET.WebApp/Controllers/CrashHangController.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Mvc; using ElectronNET.API; using ElectronNET.API.Entities; +using ElectronNET.Runtime; namespace ElectronNET.WebApp.Controllers { @@ -12,7 +13,8 @@ public IActionResult Index() { Electron.IpcMain.On("process-crash", async (args) => { - string viewPath = $"http://localhost:{ElectronNetRuntime.AspNetWebPort}/crashhang/processcrash"; + var host = ElectronHostEnvironment.Current; + string viewPath = $"http://localhost:{host.AspNetWebPort}/crashhang/processcrash"; var browserWindow = await Electron.WindowManager.CreateWindowAsync(viewPath); browserWindow.WebContents.OnCrashed += async (killed) => @@ -38,7 +40,8 @@ public IActionResult Index() Electron.IpcMain.On("process-hang", async (args) => { - string viewPath = $"http://localhost:{ElectronNetRuntime.AspNetWebPort}/crashhang/processhang"; + var host = ElectronHostEnvironment.Current; + string viewPath = $"http://localhost:{host.AspNetWebPort}/crashhang/processhang"; var browserWindow = await Electron.WindowManager.CreateWindowAsync(viewPath); browserWindow.OnUnresponsive += async () => diff --git a/src/ElectronNET.WebApp/Controllers/WindowsController.cs b/src/ElectronNET.WebApp/Controllers/WindowsController.cs index eb037af1..5ef06dd1 100644 --- a/src/ElectronNET.WebApp/Controllers/WindowsController.cs +++ b/src/ElectronNET.WebApp/Controllers/WindowsController.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc; using ElectronNET.API; using ElectronNET.API.Entities; +using ElectronNET.Runtime; namespace ElectronNET.WebApp.Controllers { @@ -11,7 +12,8 @@ public IActionResult Index() { if (HybridSupport.IsElectronActive) { - string viewPath = $"http://localhost:{ElectronNetRuntime.AspNetWebPort}/windows/demowindow"; + var host = ElectronHostEnvironment.Current; + string viewPath = $"http://localhost:{host.AspNetWebPort}/windows/demowindow"; Electron.IpcMain.On("new-window", async (args) => {