Skip to content
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

Add Example for Loading .NET DLL in Node.js and Electron.js #395

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
70 changes: 70 additions & 0 deletions examples/dotnet-dll-into-nodejs/BUILD_DLL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
### Steps to Build a .DLL on macOS Using the .NET CLI

1. **Install the .NET SDK for macOS**:
- Download and install the [.NET SDK](https://dotnet.microsoft.com/download) for macOS.
- After installation, you can verify it by running:

```bash
dotnet --version
```

2. **Create a New Class Library Project**:
- Open the Terminal, navigate to your desired directory, and create a new class library project by running:

```bash
dotnet new classlib -o MyDotNetLibrary
```

- This creates a folder named `MyDotNetLibrary` with a basic class library template.

3. **Edit the Code**:
- Navigate to the project folder and open the generated `Class1.cs` file with your preferred code editor (VS Code, Sublime, etc.):

```bash
cd MyDotNetLibrary
```

- Replace the content with your code:

```csharp
using System;
using NodeApi.DotNet;

namespace MyDotNetLibrary
{
public class MyMathClass
{
public int Add(int a, int b) => a + b;

[JSExport]
public static string SayHello(string name) => $"Hello, {name} from .NET!";
}
}
```

4. **Build the DLL**:
- Build the project to produce the `.dll` file:

```bash
dotnet build
```

- This generates a `.dll` file in the `bin/Debug/net6.0/` directory by default.

5. **Locate the DLL File**:
- You can find `MyDotNetLibrary.dll` in the `bin/Debug/net6.0/` directory within the project folder.

6. **Use the DLL in Node.js**:
- With the `.dll` file ready, you can now load and interact with it in a Node.js application using the `node-api-dotnet` package.

### Example: Loading the DLL in Node.js on macOS

```javascript
import dotnet from 'node-api-dotnet/net6.0';

dotnet.load('path/to/MyDotNetLibrary.dll');

const MyMathClass = dotnet.MyDotNetLibrary.MyMathClass;
const instance = new MyMathClass();
console.log(instance.Add(3, 5)); // Example usage
```
93 changes: 93 additions & 0 deletions examples/dotnet-dll-into-nodejs/ElectronJS/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# ElectronJS

A sample Electron application that demonstrates loading a .NET `.dll` file and interacting with it using the `node-api-dotnet` package. This example allows you to invoke methods from your .NET assembly directly within your Electron app.

## Project Structure

```
ElectronJS
│ ├── main.js # Main process file
│ ├── renderer.js # Renderer process file
│ ├── index.html # Main HTML file
│ ├── MyDotNetLibrary.dll # .NET DLL file to interact with
│ └── package.json # Project configuration file
```

## Prerequisites

1. **Node.js** - Install [Node.js](https://nodejs.org/) (version 14 or higher recommended).
2. **Electron** - Installed via npm.
3. **.NET SDK** - Required to build `.dll` files. Install from [here](https://dotnet.microsoft.com/download).
4. **node-api-dotnet** - Used to load .NET assemblies into Node.js.

## Getting Started

1. **Clone the Repository**:

```bash
git clone <repository_url>
cd ElectronJS
```

2. **Add Your DLL File**:

Make sure your `.NET` library, `MyDotNetLibrary.dll`, is in the project root directory (`MyElectronApp/`).

3. **Install Dependencies**:

```bash
npm install
```

## Project Files

### `main.js`

Handles the main process of Electron, loads the `.dll` file, and sets up IPC communication with the renderer process to handle `.NET` method calls.

### `renderer.js`

Handles interactions from the HTML UI, sends data to the main process, and displays results.

### `index.html`

A simple interface to take input, invoke the .NET function, and display the result.

## Usage

1. **Start the Application**:

```bash
npm start
```

2. **Using the App**:

- Enter two numbers in the input fields.
- Click **"Add Numbers"**.
- The result of the addition (calculated by the .NET method) will appear below the button.

## Sample Code

### Loading the .NET Assembly

In `main.js`, the `.dll` file is loaded using `node-api-dotnet`:

```javascript
const dotnet = require('node-api-dotnet/net6.0');
dotnet.load(path.join(__dirname, 'MyDotNetLibrary.dll'));
```

### Calling a .NET Method from the Renderer

The `renderer.js` file communicates with the main process to call a `.NET` method:

```javascript
const result = await ipcRenderer.invoke('dotnet-add', a, b);
```

## Troubleshooting

- **Electron Version**: Ensure compatibility between `node-api-dotnet` and your Electron version.
- **Path Issues**: Double-check the path to `MyDotNetLibrary.dll`.
- **DLL Compatibility**: Ensure that the `.dll` was built for the same .NET runtime as specified (e.g., `net6.0`).
39 changes: 39 additions & 0 deletions examples/dotnet-dll-into-nodejs/ElectronJS/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Electron + .NET Example</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 20px;
}
button {
margin-top: 10px;
}
</style>
</head>
<body>
<h1>Call .NET Method from Electron</h1>
<input type="number" id="number1" placeholder="Enter first number" />
<input type="number" id="number2" placeholder="Enter second number" />
<button id="addButton">Add Numbers</button>
<p id="result"></p>

<script>
document.getElementById('addButton').addEventListener('click', async () => {
const num1 = parseInt(document.getElementById('number1').value);
const num2 = parseInt(document.getElementById('number2').value);
const resultElement = document.getElementById('result');

try {
const result = await window.myAPI.callDotNet('Add', num1, num2);
resultElement.innerText = `Result: ${result}`;
} catch (error) {
resultElement.innerText = `Error: ${error.message}`;
}
});
</script>
</body>
</html>
55 changes: 55 additions & 0 deletions examples/dotnet-dll-into-nodejs/ElectronJS/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');
const dotnet = require('node-api-dotnet/net8.0'); // Adjust according to your target framework

let mainWindow;

function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
contextIsolation: true, // Protect from context isolation
enableRemoteModule: false,
preload: path.join(__dirname, 'preload.js'), // Preload script
},
});

mainWindow.loadFile('index.html');

// Open the DevTools (optional)
// mainWindow.webContents.openDevTools();
}

// IPC to load the .dll and call a method
ipcMain.handle('call-dotnet', async (event, methodName, ...args) => {
try {
// Load the .dll
dotnet.load(path.join(__dirname, '../MyDotNetLibrary/bin/Debug/net8.0/MyDotNetLibrary.dll'));

// Access the class and method
const MyMathClass = dotnet.MyDotNetLibrary.MyMathClass;
const instance = new MyMathClass();

// Call the method dynamically
const result = await instance[methodName](...args);
return result;
} catch (error) {
console.error('Error calling .NET method:', error);
throw error;
}
});

app.whenReady().then(createWindow);

app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});

app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
18 changes: 18 additions & 0 deletions examples/dotnet-dll-into-nodejs/ElectronJS/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "electronjs",
"version": "1.0.0",
"description": "Sample Electron app with .NET DLL integration",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"electron": "^33.0.2"
},
"dependencies": {
"node-api-dotnet": "^0.8.16"
}
}
6 changes: 6 additions & 0 deletions examples/dotnet-dll-into-nodejs/ElectronJS/preload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const { contextBridge, ipcRenderer } = require('electron');

// Expose the callDotNet method to the renderer process
contextBridge.exposeInMainWorld('myAPI', {
callDotNet: (methodName, ...args) => ipcRenderer.invoke('call-dotnet', methodName, ...args),
});
10 changes: 10 additions & 0 deletions examples/dotnet-dll-into-nodejs/ElectronJS/renderer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const { ipcRenderer } = require('electron');

document.getElementById('addButton').addEventListener('click', async () => {
const a = parseInt(document.getElementById('inputA').value);
const b = parseInt(document.getElementById('inputB').value);

// Call .NET Add method via main process
const result = await ipcRenderer.invoke('dotnet-add', a, b);
document.getElementById('result').innerText = `Result: ${result}`;
});
Binary file not shown.
11 changes: 11 additions & 0 deletions examples/dotnet-dll-into-nodejs/MyDotNetLibrary/Class1.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace MyDotNetLibrary
{
public class MyMathClass
{
public int Add(int a, int b) => a + b;

public static string SayHello(string name) => $"Hello, {name} from .NET!";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>
18 changes: 18 additions & 0 deletions examples/dotnet-dll-into-nodejs/NodeJS/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# dotnet-dll-into-nodejs

## Pre-requisuite

1. Install donnet sdk v8 or anyone and try to set that into the `index.js`

## Usage

### Step - 1 Install dependencies
```sh
npm i
```

### Step - 2 Run the app

```sh
node .
```
7 changes: 7 additions & 0 deletions examples/dotnet-dll-into-nodejs/NodeJS/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const dotnet = require("node-api-dotnet/net8.0");
const path = require("path");
dotnet.load(path.join(__dirname, "../MyDotNetLibrary/bin/Debug/net8.0/MyDotNetLibrary.dll"));

const MyMathClass = dotnet.MyDotNetLibrary.MyMathClass;
const instance = new MyMathClass();
console.log(instance.Add(3, 5)); // Example usage
15 changes: 15 additions & 0 deletions examples/dotnet-dll-into-nodejs/NodeJS/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "mydotnetlibrary",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"node-api-dotnet": "^0.8.16"
}
}
Loading