-
-
Notifications
You must be signed in to change notification settings - Fork 744
feat: Add ElectronHostHook sample application (#967) #968
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: Add ElectronHostHook sample application (#967) #968
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds a new sample application demonstrating the ElectronHostHook functionality, which enables bidirectional communication between C# and the Electron host process via TypeScript/JavaScript.
Key Changes
- New sample project showcasing
ping/pongcommunication between C# (HomeController) and TypeScript (ElectronHostHook/index.ts) - Implementation of custom
Connectorclass to handle socket-based communication - Integration into the solution under "Test Apps" folder alongside existing samples
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
src/ElectronNET.sln |
Adds new sample project with proper dependencies and solution folder nesting |
src/ElectronNET.Samples.ElectronHostHook/ElectronNET.Samples.ElectronHostHook.csproj |
Project configuration with TypeScript compilation and ElectronNET references |
src/ElectronNET.Samples.ElectronHostHook/Program.cs |
ASP.NET Core application setup with Electron integration |
src/ElectronNET.Samples.ElectronHostHook/Controllers/HomeController.cs |
Controller demonstrating HostHook.CallAsync usage |
src/ElectronNET.Samples.ElectronHostHook/Views/Home/Index.cshtml |
Simple UI displaying communication results |
src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/connector.ts |
Base connector class for socket communication (has critical bug) |
src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/index.ts |
HookService implementation with ping event handler |
src/ElectronNET.Samples.ElectronHostHook/ElectronHostHook/tsconfig.json |
TypeScript compiler configuration |
src/ElectronNET.Samples.ElectronHostHook/Properties/launchSettings.json |
Development launch configuration |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const done = (result: any) => { | ||
| this.socket.emit(id, result); | ||
| }; | ||
|
|
||
| args = [...args, done]; | ||
| javaScriptCode(...args); |
Copilot
AI
Dec 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The done callback implementation doesn't match the protocol expected by Electron.HostHook.CallAsync<T>().
The C# API expects socket events with the format ${eventName}Complete${guid} for successful results and ${eventName}Error${guid} for errors (see HostHook.cs lines 74 and 68). However, this implementation only emits to id directly, which won't be received by the C# side.
Additionally, there's no error handling. The callback should wrap the JavaScript code execution in a try-catch block.
Replace the current implementation with:
on(key: string, javaScriptCode: Function): void {
this.socket.on(key, (...args: any[]) => {
const id: string = args.pop();
try {
javaScriptCode(...args, (data) => {
if (data) {
this.socket.emit(`${key}Complete${id}`, data);
}
});
} catch (error) {
this.socket.emit(`${key}Error${id}`, `Host Hook Exception`, error);
}
});
}This matches the pattern used in the existing ElectronNET.WebApp/ElectronHostHook/connector.ts.
| const done = (result: any) => { | |
| this.socket.emit(id, result); | |
| }; | |
| args = [...args, done]; | |
| javaScriptCode(...args); | |
| try { | |
| javaScriptCode(...args, (data: any) => { | |
| if (data) { | |
| this.socket.emit(`${key}Complete${id}`, data); | |
| } | |
| }); | |
| } catch (error) { | |
| this.socket.emit(`${key}Error${id}`, `Host Hook Exception`, error); | |
| } |
| @@ -0,0 +1,18 @@ | |||
| import { Socket } from "socket.io"; | |||
Copilot
AI
Dec 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ElectronHostHook directory is missing a package.json file, which is required to define the socket.io dependency used in both connector.ts and index.ts.
Without this file, the TypeScript compilation will fail and the runtime won't have access to the socket.io library.
Add a package.json file with at least the following content:
{
"name": "electron-host-hook",
"version": "1.0.0",
"description": "Connector for Electron.NET projects.",
"main": "index.js",
"dependencies": {
"socket.io": "^4.8.1"
},
"devDependencies": {
"typescript": "^5.9.3"
}
}Reference: ElectronNET.WebApp/ElectronHostHook/package.json
| 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(); | ||
| }); | ||
| } |
Copilot
AI
Dec 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The window creation uses a fire-and-forget Task.Run pattern without proper error handling or awaiting the result. This can lead to unobserved task exceptions and doesn't follow the recommended pattern for Electron.NET applications.
Use the callback version of UseElectron instead, which provides proper error handling and lifecycle management:
builder.WebHost.UseElectron(args, async () =>
{
var window = await Electron.WindowManager.CreateWindowAsync();
});Then remove the Task.Run block (lines 24-30) entirely. The callback will be invoked automatically when the Electron app is ready.
Reference: ElectronNET.AspNet/API/WebApplicationBuilderExtensions.cs for the recommended pattern.
| @@ -0,0 +1,16 @@ | |||
| import { Connector } from "./connector"; | |||
Copilot
AI
Dec 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ElectronHostHook directory is missing a .gitignore file to exclude generated files and dependencies from version control.
Add a .gitignore file in the ElectronHostHook directory with content similar to the other samples to ignore:
node_modules/directory- Generated JavaScript files (
*.js,*.js.map) - npm/yarn logs and lock files
- Other Node.js artifacts
For consistency with existing patterns, you can copy the .gitignore from src/ElectronNET.WebApp/ElectronHostHook/.gitignore or src/ElectronNET.Host/ElectronHostHook/.gitignore.
| } | ||
|
|
||
| <!DOCTYPE html> | ||
| <html> |
Copilot
AI
Dec 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The <html> tag is missing the lang attribute, which is important for accessibility (screen readers) and SEO.
Add the lang attribute:
<html lang="en">| <html> | |
| <html lang="en"> |
|
|
||
| <!DOCTYPE html> | ||
| <html> | ||
| <head> |
Copilot
AI
Dec 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The <head> section is missing the character encoding declaration, which should be specified early in the document for proper text rendering.
Add the charset meta tag as the first element in <head>:
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width" />
<title>ElectronHostHook Sample</title>
...| <head> | |
| <head> | |
| <meta charset="utf-8"> |
| "noImplicitAny": false, | ||
| "noEmitOnError": true, | ||
| "removeComments": false, | ||
| "sourceMap": true, | ||
| "target": "es5", | ||
| "lib": ["es2015", "dom"] | ||
| }, | ||
| "exclude": ["node_modules", "wwwroot"] |
Copilot
AI
Dec 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The TypeScript target is set to "es5" while the lib includes "es2015". This inconsistency could cause issues since ES2015 features may not transpile correctly to ES5.
For consistency with the existing ElectronNET.WebApp/ElectronHostHook/tsconfig.json, consider updating to:
{
"compilerOptions": {
"module": "commonjs",
"target": "ES2019",
"sourceMap": true,
"skipLibCheck": true
},
"exclude": [
"node_modules"
]
}This matches the configuration used in the main WebApp sample and is more appropriate for the Node.js environment in Electron.
| "noImplicitAny": false, | |
| "noEmitOnError": true, | |
| "removeComments": false, | |
| "sourceMap": true, | |
| "target": "es5", | |
| "lib": ["es2015", "dom"] | |
| }, | |
| "exclude": ["node_modules", "wwwroot"] | |
| "target": "ES2019", | |
| "sourceMap": true, | |
| "skipLibCheck": true | |
| }, | |
| "exclude": [ | |
| "node_modules" | |
| ] |
| { | ||
| Task.Run(async () => | ||
| { | ||
| var window = await Electron.WindowManager.CreateWindowAsync(); |
Copilot
AI
Dec 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assignment to window is useless, since its value is never read.
| var window = await Electron.WindowManager.CreateWindowAsync(); | |
| await Electron.WindowManager.CreateWindowAsync(); |
|
@adityashirsatrao007 - Wow, cool! That was fast (after I posted the issue at least).. I think we need to determine a number of conventions for how to include the samples in the repo. The existing test apps are meant for development. They have project files that allow them to consume all of Electron.NET directly, bypassing nuget packages (unless modified). The folder name should be the subject without prefix, i.e. in this case As a 3-part root namespace is a bit ugly, I'd suggest that all samples should have two parts
So, the full paths would be:
But please don't take my word for it and don't make any changes yet. |
Closes #967
Changes
Details
This addresses the request for a focused 'ElectronHostHook Sample' in the linked issue. The sample is minimal and self-contained, showing only the hook mechanism.