namespace ElectronNET.API { using System; using System.Diagnostics; using System.IO; using System.Threading.Tasks; using ElectronNET.AspNet; using ElectronNET.AspNet.Runtime; using ElectronNET.Runtime; using ElectronNET.Runtime.Data; using ElectronNET.Runtime.Helpers; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; /// /// Provides extension methods for to enable Electron.NET /// integration in ASP.NET Core applications (including Razor Pages) using the WebHost-based hosting model. /// /// /// Call this extension during web host configuration (for example, inside ConfigureWebHostDefaults in Program.cs) /// to wire up Electron with any command-line arguments and an optional application-ready callback. /// public static class WebHostBuilderExtensions { /// /// 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 () => /// { /// // 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(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 Environment.SetEnvironmentVariable("ELECTRON_RUN_AS_NODE", null); var webPort = ElectronNetRuntime.AspNetWebPort ?? 0; // In packaged mode, static content is deployed alongside the app binaries, so we must // point content root to the process base directory. In unpackaged/watch scenarios we // keep the default project content root to preserve live reload behavior. var isPackagedStartup = ElectronNetRuntime.StartupMethod == StartupMethod.PackagedElectronFirst || ElectronNetRuntime.StartupMethod == StartupMethod.PackagedDotnetFirst; // For port 0 (dynamic port assignment), Kestrel requires binding to specific IP (127.0.0.1) not localhost var host = webPort == 0 ? "127.0.0.1" : "localhost"; if (isPackagedStartup) { builder = builder.UseContentRoot(AppDomain.CurrentDomain.BaseDirectory) .UseUrls($"http://{host}:{webPort}"); } else { builder = builder.UseUrls($"http://{host}:{webPort}"); } builder = builder.ConfigureServices((context, services) => { services.AddTransient(); services.AddSingleton(); switch (ElectronNetRuntime.StartupMethod) { case StartupMethod.PackagedElectronFirst: case StartupMethod.UnpackedElectronFirst: services.AddSingleton(); break; case StartupMethod.PackagedDotnetFirst: case StartupMethod.UnpackedDotnetFirst: services.AddSingleton(); break; default: throw new ArgumentOutOfRangeException(); } }); return builder; } } }