From b00adcbd387f1c356d6ce6f52b8f484b19dc5e12 Mon Sep 17 00:00:00 2001 From: Aditya Date: Sun, 7 Dec 2025 22:57:35 +0530 Subject: [PATCH] feat: Add ElectronHostHook sample application (#967) --- .../Controllers/HomeController.cs | 21 +++++++++++ .../ElectronHostHook/connector.ts | 18 ++++++++++ .../ElectronHostHook/index.ts | 16 +++++++++ .../ElectronHostHook/tsconfig.json | 12 +++++++ ...lectronNET.Samples.ElectronHostHook.csproj | 36 +++++++++++++++++++ .../Program.cs | 35 ++++++++++++++++++ .../Properties/launchSettings.json | 12 +++++++ .../Views/Home/Index.cshtml | 24 +++++++++++++ src/ElectronNET.sln | 11 ++++++ 9 files changed, 185 insertions(+) create mode 100644 src/ElectronNET.Samples.ElectronHostHook/Controllers/HomeController.cs create mode 100644 src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/connector.ts create mode 100644 src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/index.ts create mode 100644 src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/tsconfig.json create mode 100644 src/ElectronNET.Samples.ElectronHostHook/ElectronNET.Samples.ElectronHostHook.csproj create mode 100644 src/ElectronNET.Samples.ElectronHostHook/Program.cs create mode 100644 src/ElectronNET.Samples.ElectronHostHook/Properties/launchSettings.json create mode 100644 src/ElectronNET.Samples.ElectronHostHook/Views/Home/Index.cshtml diff --git a/src/ElectronNET.Samples.ElectronHostHook/Controllers/HomeController.cs b/src/ElectronNET.Samples.ElectronHostHook/Controllers/HomeController.cs new file mode 100644 index 0000000..10c1059 --- /dev/null +++ b/src/ElectronNET.Samples.ElectronHostHook/Controllers/HomeController.cs @@ -0,0 +1,21 @@ +using ElectronNET.API; +using Microsoft.AspNetCore.Mvc; + +namespace ElectronNET.Samples.ElectronHostHook.Controllers +{ + public class HomeController : Controller + { + public async Task Index() + { + string message = "Electron not active"; + if (HybridSupport.IsElectronActive) + { + // Call the HostHook defined in ElectronHostHook/index.ts + var result = await Electron.HostHook.CallAsync("ping", "Hello from C#"); + message = $"Sent 'Hello from C#', Received: '{result}'"; + } + + return View("Index", message); + } + } +} diff --git a/src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/connector.ts b/src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/connector.ts new file mode 100644 index 0000000..ed776ad --- /dev/null +++ b/src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/connector.ts @@ -0,0 +1,18 @@ +import { Socket } from "socket.io"; + +export class Connector { + constructor(private socket: Socket, public app: any) { + } + + on(key: string, javaScriptCode: Function): void { + this.socket.on(key, (...args: any[]) => { + const id: string = args.pop(); + const done = (result: any) => { + this.socket.emit(id, result); + }; + + args = [...args, done]; + javaScriptCode(...args); + }); + } +} diff --git a/src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/index.ts b/src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/index.ts new file mode 100644 index 0000000..54b69c9 --- /dev/null +++ b/src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/index.ts @@ -0,0 +1,16 @@ +import { Connector } from "./connector"; +import { Socket } from "socket.io"; + +export class HookService extends Connector { + constructor(socket: Socket, public app: any) { + super(socket, app); + } + + onHostReady(): void { + // execute your own JavaScript Host logic here + this.on("ping", (msg, done) => { + console.log("Received ping from C#:", msg); + done("pong: " + msg); + }); + } +} diff --git a/src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/tsconfig.json b/src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/tsconfig.json new file mode 100644 index 0000000..fbf08f2 --- /dev/null +++ b/src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "module": "commonjs", + "noImplicitAny": false, + "noEmitOnError": true, + "removeComments": false, + "sourceMap": true, + "target": "es5", + "lib": ["es2015", "dom"] + }, + "exclude": ["node_modules", "wwwroot"] +} diff --git a/src/ElectronNET.Samples.ElectronHostHook/ElectronNET.Samples.ElectronHostHook.csproj b/src/ElectronNET.Samples.ElectronHostHook/ElectronNET.Samples.ElectronHostHook.csproj new file mode 100644 index 0000000..70eb436 --- /dev/null +++ b/src/ElectronNET.Samples.ElectronHostHook/ElectronNET.Samples.ElectronHostHook.csproj @@ -0,0 +1,36 @@ + + + true + + + + + + net8.0 + OutOfProcess + AspNetCoreModule + false + commonjs + true + ElectronHostHook/tsconfig.json + true + true + + + + + + + + + + + + + + + + + + + diff --git a/src/ElectronNET.Samples.ElectronHostHook/Program.cs b/src/ElectronNET.Samples.ElectronHostHook/Program.cs new file mode 100644 index 0000000..241221e --- /dev/null +++ b/src/ElectronNET.Samples.ElectronHostHook/Program.cs @@ -0,0 +1,35 @@ +using ElectronNET.API; + +namespace ElectronNET.Samples.ElectronHostHook +{ + public class Program + { + public static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + + builder.WebHost.UseElectron(args); + builder.Services.AddElectron(); + builder.Services.AddControllersWithViews(); + + var app = builder.Build(); + + app.UseStaticFiles(); + app.UseRouting(); + + app.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); + + if (HybridSupport.IsElectronActive) + { + Task.Run(async () => + { + var window = await Electron.WindowManager.CreateWindowAsync(); + }); + } + + app.Run(); + } + } +} diff --git a/src/ElectronNET.Samples.ElectronHostHook/Properties/launchSettings.json b/src/ElectronNET.Samples.ElectronHostHook/Properties/launchSettings.json new file mode 100644 index 0000000..d4c4b1e --- /dev/null +++ b/src/ElectronNET.Samples.ElectronHostHook/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "ElectronNET.Samples.ElectronHostHook": { + "commandName": "Project", + "launchBrowser": false, + "applicationUrl": "http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/ElectronNET.Samples.ElectronHostHook/Views/Home/Index.cshtml b/src/ElectronNET.Samples.ElectronHostHook/Views/Home/Index.cshtml new file mode 100644 index 0000000..142d015 --- /dev/null +++ b/src/ElectronNET.Samples.ElectronHostHook/Views/Home/Index.cshtml @@ -0,0 +1,24 @@ +@model string +@{ + Layout = null; +} + + + + + + ElectronHostHook Sample + + + +

ElectronHostHook Sample

+

This sample demonstrates bidirectional communication between C# and the Electron Host process.

+ +
+ Result: @Model +
+ + diff --git a/src/ElectronNET.sln b/src/ElectronNET.sln index 6cadc12..ef64ab1 100644 --- a/src/ElectronNET.sln +++ b/src/ElectronNET.sln @@ -62,6 +62,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ElectronNET.IntegrationTest EndProject Project("{54A90642-561A-4BB1-A94E-469ADEE60C69}") = "ElectronNET.Host", "ElectronNET.Host\ElectronNET.Host.esproj", "{1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElectronNET.Samples.ElectronHostHook", "ElectronNET.Samples.ElectronHostHook\ElectronNET.Samples.ElectronHostHook.csproj", "{B8D65F3A-7E54-4632-9F1C-46679237B312}" + ProjectSection(ProjectDependencies) = postProject + {1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6} = {1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6} + {8860606D-6847-F22A-5AED-DF4E0984DD24} = {8860606D-6847-F22A-5AED-DF4E0984DD24} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -105,6 +111,10 @@ Global {1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6}.Release|Any CPU.ActiveCfg = Release|Any CPU {1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6}.Release|Any CPU.Build.0 = Release|Any CPU {1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6}.Release|Any CPU.Deploy.0 = Release|Any CPU + {B8D65F3A-7E54-4632-9F1C-46679237B312}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B8D65F3A-7E54-4632-9F1C-46679237B312}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B8D65F3A-7E54-4632-9F1C-46679237B312}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B8D65F3A-7E54-4632-9F1C-46679237B312}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -120,6 +130,7 @@ Global {06CAADC7-DE5B-47B4-AB2A-E9501459A2D1} = {D36CDFFD-3438-42E4-A7FF-88BA19AC4964} {AE877E48-6B44-63C2-8EA0-DB58D096B553} = {75129C45-FC6F-41B0-A485-07F4A7E031ED} {1C5FD66E-A1C6-C436-DF7C-3ECE4FEDDFE6} = {1BB6F634-2831-4496-83A6-BC6761DCEC8D} + {B8D65F3A-7E54-4632-9F1C-46679237B312} = {EDCBFC49-2AEE-4BAF-9368-4409298C52FC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {81A62E71-9E04-4EFE-AD5C-23165375F8EF}