Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions src/ElectronNET.API/ElectronNetRuntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@ static ElectronNetRuntime()

internal static int? ElectronProcessId { get; set; }

internal static Func<Task> OnAppReadyCallback { get; set; }

internal static ISocketConnection GetSocket()
{
return RuntimeControllerCore?.Socket;
Expand Down
93 changes: 93 additions & 0 deletions src/ElectronNET.AspNet/API/WebApplicationBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,98 @@ public static WebApplicationBuilder UseElectron(this WebApplicationBuilder build

return builder;
}

/// <summary>
/// Adds Electron.NET support to the current ASP.NET Core application and registers an application-ready callback.
/// </summary>
/// <param name="builder">The <see cref="WebApplicationBuilder"/> to extend.</param>
/// <param name="args">The command-line arguments passed to the process, forwarded to Electron.</param>
/// <param name="onAppReadyCallback">
/// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization.
/// </param>
/// <returns>
/// The same <see cref="WebApplicationBuilder"/> instance to enable fluent configuration.
/// </returns>
/// <example>
/// <code language="csharp">
/// 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();
/// </code>
/// </example>
public static WebApplicationBuilder UseElectron(this WebApplicationBuilder builder, string[] args, Func<string[], Task> onAppReadyCallback)
{
builder.WebHost.UseElectron(args, onAppReadyCallback);

return builder;
}

/// <summary>
/// Adds Electron.NET support to the current ASP.NET Core application and registers an application-ready callback.
/// </summary>
/// <param name="builder">The <see cref="WebApplicationBuilder"/> to extend.</param>
/// <param name="args">The command-line arguments passed to the process, forwarded to Electron.</param>
/// <param name="onAppReadyCallback">
/// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization.
/// </param>
/// <returns>
/// The same <see cref="WebApplicationBuilder"/> instance to enable fluent configuration.
/// </returns>
/// <example>
/// <code language="csharp">
/// 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();
/// </code>
/// </example>
public static WebApplicationBuilder UseElectron(this WebApplicationBuilder builder, string[] args, Func<IServiceProvider, Task> onAppReadyCallback)
{
builder.WebHost.UseElectron(args, onAppReadyCallback);

return builder;
}

/// <summary>
/// Adds Electron.NET support to the current ASP.NET Core application and registers an application-ready callback.
/// </summary>
/// <param name="builder">The <see cref="WebApplicationBuilder"/> to extend.</param>
/// <param name="args">The command-line arguments passed to the process, forwarded to Electron.</param>
/// <param name="onAppReadyCallback">
/// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization.
/// </param>
/// <returns>
/// The same <see cref="WebApplicationBuilder"/> instance to enable fluent configuration.
/// </returns>
/// <example>
/// <code language="csharp">
/// 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();
/// </code>
/// </example>
public static WebApplicationBuilder UseElectron(this WebApplicationBuilder builder, string[] args, Func<IServiceProvider, string[], Task> onAppReadyCallback)
{
builder.WebHost.UseElectron(args, onAppReadyCallback);

return builder;
}
}
}
148 changes: 147 additions & 1 deletion src/ElectronNET.AspNet/API/WebHostBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,154 @@ public static class WebHostBuilderExtensions
/// </example>
public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] args, Func<Task> onAppReadyCallback)
{
ElectronNetRuntime.OnAppReadyCallback = onAppReadyCallback;
builder.ConfigureServices(services =>
{
services.AddSingleton<IAppReadyCallbackResolver>(_ => new AppReadyCallbackResolver(onAppReadyCallback));
});

return UseElectronCore(builder, args);
}

/// <summary>
/// Adds Electron.NET support to the current ASP.NET Core web host and registers an application-ready callback.
/// </summary>
/// <param name="builder">The <see cref="IWebHostBuilder"/> to extend.</param>
/// <param name="args">The command-line arguments passed to the process.</param>
/// <param name="onAppReadyCallback">
/// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization.
/// </param>
/// <returns>
/// The same <see cref="IWebHostBuilder"/> instance to enable fluent configuration.
/// </returns>
/// <example>
/// <code language="csharp">
/// 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&lt;Startup&gt;();
/// webBuilder.UseElectron(args, async (processArgs) =>
/// {
/// // Create the main browser window or perform other startup tasks.
/// });
/// })
/// .Build()
/// .Run();
/// }
/// }
/// </code>
/// </example>
public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] args, Func<string[], Task> onAppReadyCallback)
{
builder.ConfigureServices(services =>
{
services.AddSingleton<IAppReadyCallbackResolver>(_ => new AppReadyCallbackResolver(args, onAppReadyCallback));
});

return UseElectronCore(builder, args);
}

/// <summary>
/// Adds Electron.NET support to the current ASP.NET Core web host and registers an application-ready callback.
/// </summary>
/// <param name="builder">The <see cref="IWebHostBuilder"/> to extend.</param>
/// <param name="args">The command-line arguments passed to the process.</param>
/// <param name="onAppReadyCallback">
/// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization.
/// </param>
/// <returns>
/// The same <see cref="IWebHostBuilder"/> instance to enable fluent configuration.
/// </returns>
/// <example>
/// <code language="csharp">
/// 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&lt;Startup&gt;();
/// webBuilder.UseElectron(args, async (serviceProvider) =>
/// {
/// // Create the main browser window or perform other startup tasks.
/// });
/// })
/// .Build()
/// .Run();
/// }
/// }
/// </code>
/// </example>
public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] args, Func<IServiceProvider, Task> onAppReadyCallback)
{
builder.ConfigureServices(services =>
{
services.AddSingleton<IAppReadyCallbackResolver>(provider => new AppReadyCallbackResolver(provider, onAppReadyCallback));
});

return UseElectronCore(builder, args);
}

/// <summary>
/// Adds Electron.NET support to the current ASP.NET Core web host and registers an application-ready callback.
/// </summary>
/// <param name="builder">The <see cref="IWebHostBuilder"/> to extend.</param>
/// <param name="args">The command-line arguments passed to the process.</param>
/// <param name="onAppReadyCallback">
/// An asynchronous callback invoked when the Electron app is ready. Use this to create windows or perform initialization.
/// </param>
/// <returns>
/// The same <see cref="IWebHostBuilder"/> instance to enable fluent configuration.
/// </returns>
/// <example>
/// <code language="csharp">
/// 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&lt;Startup&gt;();
/// webBuilder.UseElectron(args, async (serviceProvider, processArgs) =>
/// {
/// // Create the main browser window or perform other startup tasks.
/// });
/// })
/// .Build()
/// .Run();
/// }
/// }
/// </code>
/// </example>
public static IWebHostBuilder UseElectron(this IWebHostBuilder builder, string[] args, Func<IServiceProvider, string[], Task> onAppReadyCallback)
{
builder.ConfigureServices(services =>
{
services.AddSingleton<IAppReadyCallbackResolver>(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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.Threading.Tasks;

namespace ElectronNET.AspNet.Runtime
{
internal class AppReadyCallbackResolver : IAppReadyCallbackResolver
{
private readonly Func<Task> _callback;

public AppReadyCallbackResolver()
{ }

public AppReadyCallbackResolver(Func<Task> callback)
{
_callback = callback;
}

public AppReadyCallbackResolver(string[] args, Func<string[], Task> callback)
{
if (callback != null)
{
_callback = () => callback.Invoke(args);
}
}

public AppReadyCallbackResolver(IServiceProvider serviceProvider, Func<IServiceProvider, Task> callback)
{
if (callback != null)
{
_callback = () => callback.Invoke(serviceProvider);
}
}

public AppReadyCallbackResolver(IServiceProvider serviceProvider, string[] args, Func<IServiceProvider, string[], Task> callback)
{
if (callback != null)
{
_callback = () => callback.Invoke(serviceProvider, args);
}
}

public bool HasCallback => _callback != null;

public Task Invoke() => _callback?.Invoke() ?? Task.CompletedTask;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Threading.Tasks;

namespace ElectronNET.AspNet.Runtime
{
internal interface IAppReadyCallbackResolver
{
public bool HasCallback { get; }

public Task Invoke();
}
}
Loading