diff --git a/src/ElectronNET.API/ElectronNetRuntime.cs b/src/ElectronNET.API/ElectronNetRuntime.cs index 3a285c4b..97fa2ed1 100644 --- a/src/ElectronNET.API/ElectronNetRuntime.cs +++ b/src/ElectronNET.API/ElectronNetRuntime.cs @@ -50,8 +50,6 @@ static ElectronNetRuntime() internal static int? ElectronProcessId { get; set; } - internal static Func OnAppReadyCallback { get; set; } - internal static ISocketConnection GetSocket() { return RuntimeControllerCore?.Socket; diff --git a/src/ElectronNET.AspNet/API/WebApplicationBuilderExtensions.cs b/src/ElectronNET.AspNet/API/WebApplicationBuilderExtensions.cs index 0283bea1..7a68fd64 100644 --- a/src/ElectronNET.AspNet/API/WebApplicationBuilderExtensions.cs +++ b/src/ElectronNET.AspNet/API/WebApplicationBuilderExtensions.cs @@ -44,5 +44,98 @@ public static WebApplicationBuilder UseElectron(this WebApplicationBuilder build return builder; } + + /// + /// Adds Electron.NET support to the current ASP.NET Core application and registers an application-ready callback. + /// + /// The to extend. + /// The command-line arguments passed to the process, forwarded to Electron. + /// + /// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization. + /// + /// + /// The same instance to enable fluent configuration. + /// + /// + /// + /// var builder = WebApplication.CreateBuilder(args) + /// .UseElectron(args, async (processArgs) => + /// { + /// // Create the main browser window or perform other startup tasks. + /// }); + /// + /// var app = builder.Build(); + /// app.MapRazorPages(); + /// app.Run(); + /// + /// + public static WebApplicationBuilder UseElectron(this WebApplicationBuilder builder, string[] args, Func onAppReadyCallback) + { + builder.WebHost.UseElectron(args, onAppReadyCallback); + + return builder; + } + + /// + /// Adds Electron.NET support to the current ASP.NET Core application and registers an application-ready callback. + /// + /// The to extend. + /// The command-line arguments passed to the process, forwarded to Electron. + /// + /// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization. + /// + /// + /// The same instance to enable fluent configuration. + /// + /// + /// + /// var builder = WebApplication.CreateBuilder(args) + /// .UseElectron(args, async (serviceProvider) => + /// { + /// // Create the main browser window or perform other startup tasks. + /// }); + /// + /// var app = builder.Build(); + /// app.MapRazorPages(); + /// app.Run(); + /// + /// + public static WebApplicationBuilder UseElectron(this WebApplicationBuilder builder, string[] args, Func onAppReadyCallback) + { + builder.WebHost.UseElectron(args, onAppReadyCallback); + + return builder; + } + + /// + /// Adds Electron.NET support to the current ASP.NET Core application and registers an application-ready callback. + /// + /// The to extend. + /// The command-line arguments passed to the process, forwarded to Electron. + /// + /// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization. + /// + /// + /// The same instance to enable fluent configuration. + /// + /// + /// + /// var builder = WebApplication.CreateBuilder(args) + /// .UseElectron(args, async (serviceProvider, processArgs) => + /// { + /// // Create the main browser window or perform other startup tasks. + /// }); + /// + /// var app = builder.Build(); + /// app.MapRazorPages(); + /// app.Run(); + /// + /// + public static WebApplicationBuilder UseElectron(this WebApplicationBuilder builder, string[] args, Func onAppReadyCallback) + { + builder.WebHost.UseElectron(args, onAppReadyCallback); + + return builder; + } } } \ No newline at end of file diff --git a/src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs b/src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs index 553ffda1..2812474f 100644 --- a/src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs +++ b/src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs @@ -61,8 +61,154 @@ public static class WebHostBuilderExtensions /// public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] args, Func onAppReadyCallback) { - ElectronNetRuntime.OnAppReadyCallback = onAppReadyCallback; + builder.ConfigureServices(services => + { + services.AddSingleton(_ => new AppReadyCallbackResolver(onAppReadyCallback)); + }); + + return UseElectronCore(builder, args); + } + + /// + /// Adds Electron.NET support to the current ASP.NET Core web host and registers an application-ready callback. + /// + /// The to extend. + /// The command-line arguments passed to the process. + /// + /// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization. + /// + /// + /// The same instance to enable fluent configuration. + /// + /// + /// + /// using Microsoft.AspNetCore.Hosting; + /// using Microsoft.Extensions.Hosting; + /// using ElectronNET.API; + /// + /// public class Program + /// { + /// public static void Main(string[] args) + /// { + /// Host.CreateDefaultBuilder(args) + /// .ConfigureWebHostDefaults(webBuilder => + /// { + /// webBuilder.UseStartup<Startup>(); + /// webBuilder.UseElectron(args, async (processArgs) => + /// { + /// // Create the main browser window or perform other startup tasks. + /// }); + /// }) + /// .Build() + /// .Run(); + /// } + /// } + /// + /// + public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] args, Func onAppReadyCallback) + { + builder.ConfigureServices(services => + { + services.AddSingleton(_ => new AppReadyCallbackResolver(args, onAppReadyCallback)); + }); + + return UseElectronCore(builder, args); + } + + /// + /// Adds Electron.NET support to the current ASP.NET Core web host and registers an application-ready callback. + /// + /// The to extend. + /// The command-line arguments passed to the process. + /// + /// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization. + /// + /// + /// The same instance to enable fluent configuration. + /// + /// + /// + /// using Microsoft.AspNetCore.Hosting; + /// using Microsoft.Extensions.Hosting; + /// using ElectronNET.API; + /// + /// public class Program + /// { + /// public static void Main(string[] args) + /// { + /// Host.CreateDefaultBuilder(args) + /// .ConfigureWebHostDefaults(webBuilder => + /// { + /// webBuilder.UseStartup<Startup>(); + /// webBuilder.UseElectron(args, async (serviceProvider) => + /// { + /// // Create the main browser window or perform other startup tasks. + /// }); + /// }) + /// .Build() + /// .Run(); + /// } + /// } + /// + /// + public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] args, Func onAppReadyCallback) + { + builder.ConfigureServices(services => + { + services.AddSingleton(provider => new AppReadyCallbackResolver(provider, onAppReadyCallback)); + }); + + return UseElectronCore(builder, args); + } + + /// + /// Adds Electron.NET support to the current ASP.NET Core web host and registers an application-ready callback. + /// + /// The to extend. + /// The command-line arguments passed to the process. + /// + /// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization. + /// + /// + /// The same instance to enable fluent configuration. + /// + /// + /// + /// using Microsoft.AspNetCore.Hosting; + /// using Microsoft.Extensions.Hosting; + /// using ElectronNET.API; + /// + /// public class Program + /// { + /// public static void Main(string[] args) + /// { + /// Host.CreateDefaultBuilder(args) + /// .ConfigureWebHostDefaults(webBuilder => + /// { + /// webBuilder.UseStartup<Startup>(); + /// webBuilder.UseElectron(args, async (serviceProvider, processArgs) => + /// { + /// // Create the main browser window or perform other startup tasks. + /// }); + /// }) + /// .Build() + /// .Run(); + /// } + /// } + /// + /// + public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] args, Func onAppReadyCallback) + { + builder.ConfigureServices(services => + { + services.AddSingleton(provider => new AppReadyCallbackResolver(provider, args, onAppReadyCallback)); + }); + + return UseElectronCore(builder, args); + } + private static IWebHostBuilder UseElectronCore(IWebHostBuilder builder, string[] args) + { // no matter how this is set - let's unset to prevent Electron not starting as expected // e.g., VS Code sets this env variable, but this will cause `require("electron")` to not // work as expected, see issue #952 diff --git a/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetBase.cs b/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetBase.cs index b7d2f338..f214e8a3 100644 --- a/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetBase.cs +++ b/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetBase.cs @@ -17,13 +17,15 @@ internal abstract class RuntimeControllerAspNetBase : RuntimeControllerBase { private readonly IServer server; private readonly AspNetLifetimeAdapter aspNetLifetimeAdapter; + private readonly IAppReadyCallbackResolver callbackResolver; private readonly IElectronAuthenticationService authenticationService; private SocketBridgeService socketBridge; - protected RuntimeControllerAspNetBase(IServer server, AspNetLifetimeAdapter aspNetLifetimeAdapter, IElectronAuthenticationService authenticationService = null) + protected RuntimeControllerAspNetBase(IServer server, AspNetLifetimeAdapter aspNetLifetimeAdapter, IAppReadyCallbackResolver callbackResolver, IElectronAuthenticationService authenticationService = null) { this.server = server; this.aspNetLifetimeAdapter = aspNetLifetimeAdapter; + this.callbackResolver = callbackResolver; this.authenticationService = authenticationService; this.aspNetLifetimeAdapter.Ready += this.AspNetLifetimeAdapter_Ready; this.aspNetLifetimeAdapter.Stopping += this.AspNetLifetimeAdapter_Stopping; @@ -130,15 +132,15 @@ private void AspNetLifetimeAdapter_Stopping(object sender, EventArgs e) private async Task RunReadyCallback() { - if (ElectronNetRuntime.OnAppReadyCallback == null) + if (!callbackResolver.HasCallback) { - Console.WriteLine("Warning: Non OnReadyCallback provided in UseElectron() setup."); + Console.WriteLine("Warning: No OnReadyCallback provided in UseElectron() setup."); return; } try { - await ElectronNetRuntime.OnAppReadyCallback().ConfigureAwait(false); + await callbackResolver.Invoke().ConfigureAwait(false); } catch (Exception ex) { diff --git a/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetDotnetFirst.cs b/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetDotnetFirst.cs index 7a94732a..615e7d34 100644 --- a/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetDotnetFirst.cs +++ b/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetDotnetFirst.cs @@ -14,7 +14,7 @@ internal class RuntimeControllerAspNetDotnetFirst : RuntimeControllerAspNetBase { private ElectronProcessBase electronProcess; - public RuntimeControllerAspNetDotnetFirst(IServer server, AspNetLifetimeAdapter aspNetLifetimeAdapter, IElectronAuthenticationService authenticationService = null) : base(server, aspNetLifetimeAdapter, authenticationService) + public RuntimeControllerAspNetDotnetFirst(IServer server, AspNetLifetimeAdapter aspNetLifetimeAdapter, IAppReadyCallbackResolver callbackResolver, IElectronAuthenticationService authenticationService = null) : base(server, aspNetLifetimeAdapter, callbackResolver, authenticationService) { } diff --git a/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetElectronFirst.cs b/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetElectronFirst.cs index 757507d0..a377fcca 100644 --- a/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetElectronFirst.cs +++ b/src/ElectronNET.AspNet/Runtime/Controllers/RuntimeControllerAspNetElectronFirst.cs @@ -11,7 +11,7 @@ internal class RuntimeControllerAspNetElectronFirst : RuntimeControllerAspNetBas { private ElectronProcessBase electronProcess; - public RuntimeControllerAspNetElectronFirst(IServer server, AspNetLifetimeAdapter aspNetLifetimeAdapter, IElectronAuthenticationService authenticationService = null) : base(server, aspNetLifetimeAdapter, authenticationService) + public RuntimeControllerAspNetElectronFirst(IServer server, AspNetLifetimeAdapter aspNetLifetimeAdapter, IAppReadyCallbackResolver callbackResolver, IElectronAuthenticationService authenticationService = null) : base(server, aspNetLifetimeAdapter, callbackResolver, authenticationService) { } diff --git a/src/ElectronNET.AspNet/Runtime/Services/AppReadyCallbackResolver.cs b/src/ElectronNET.AspNet/Runtime/Services/AppReadyCallbackResolver.cs new file mode 100644 index 00000000..67b16494 --- /dev/null +++ b/src/ElectronNET.AspNet/Runtime/Services/AppReadyCallbackResolver.cs @@ -0,0 +1,46 @@ +using System; +using System.Threading.Tasks; + +namespace ElectronNET.AspNet.Runtime +{ + internal class AppReadyCallbackResolver : IAppReadyCallbackResolver + { + private readonly Func _callback; + + public AppReadyCallbackResolver() + { } + + public AppReadyCallbackResolver(Func callback) + { + _callback = callback; + } + + public AppReadyCallbackResolver(string[] args, Func callback) + { + if (callback != null) + { + _callback = () => callback.Invoke(args); + } + } + + public AppReadyCallbackResolver(IServiceProvider serviceProvider, Func callback) + { + if (callback != null) + { + _callback = () => callback.Invoke(serviceProvider); + } + } + + public AppReadyCallbackResolver(IServiceProvider serviceProvider, string[] args, Func callback) + { + if (callback != null) + { + _callback = () => callback.Invoke(serviceProvider, args); + } + } + + public bool HasCallback => _callback != null; + + public Task Invoke() => _callback?.Invoke() ?? Task.CompletedTask; + } +} diff --git a/src/ElectronNET.AspNet/Runtime/Services/IAppReadyCallbackResolver.cs b/src/ElectronNET.AspNet/Runtime/Services/IAppReadyCallbackResolver.cs new file mode 100644 index 00000000..7fc84942 --- /dev/null +++ b/src/ElectronNET.AspNet/Runtime/Services/IAppReadyCallbackResolver.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; + +namespace ElectronNET.AspNet.Runtime +{ + internal interface IAppReadyCallbackResolver + { + public bool HasCallback { get; } + + public Task Invoke(); + } +}