FrakenApp #1: Part 2, Communicating with Electron

FrakenApp #1: Part 2, Communicating with Electron

Calling Electron

After poking around, I found that the way to communicate between .NET and Electron is through TCP; there is even a project Electron.net that uses an embedded ASP.NET Core application and communicates with the Electron app through the IPC bridge.

Later on, we talked about adding some UI to the existing WPF app at work, and they also spoke of a plan to port the app to the Web at some future date. My first thought was that it would be easier to prototype the UI in a browser than fight the WPF/XAML. Then I thought that they could write the new UI with JavaScript in Electron and somehow link it to the exiting WPF app. Then I came across this as I was Googling during the Teams Meeting: Electron APP and classic windows APP integration.

This blog entry does the same essential thing as Electron.net, but simpler. I like that I can see the guts. I took the code and adapted it into phone-home-electron (Phone Home App), I traded the Chuck Norris theme for E.T.

The .NET Phone Booth

On the .NET Side, I found C# TCP Server on CodeProject. I downloaded the source code, which includes a test app called "TCP Server Simulator" and I used that to communicate with the Electron app.

I put this first because the Electron app below does not have any error checking, and you will want to have this running before you launch it.

Since this runs on .NET Framework 4, it probably won't make it to the end of the road, but it gives me a .NET app to send messages back and forth with the Electron app.

What's Going On

Electron has two processes, the main and the renderer, that communicates through Inter-Process Communication (IPC). In my app (Phone Home App), the main process stands between the renderer and the outside world (i.e., the .NET app somewhere else).

main.js (excerpts)

Declarations

// # ip address for the socket
// TCP Server Simulator should be on this computer
const HOST = 'localhost'; on this computer
// # port number for the socket
// TCP Server Simulator uses 3001 by default
const PORT = 3001;

const {
    app,
    BrowserWindow,
    ipcMain         // Inter Process Communication module for the main process
} = require('electron');
const net = require('net');

Then we need to open open a connection with home

// 1. Create a connection with home
const client = new net.Socket();
client.connect(PORT, HOST, function () {
    console.log('CONNECTED TO: ' + HOST + ':' + PORT);
    // Write a message to the socket as soon as the client is connected, 
    // the server will receive it as message from the client 
    client.write('Line Opened');
});

Listen for messages from the outside world and relay them to the renderer.

// 2. Listen for data from home and send it to mainWindow (the renderer process),
client.on('data', function (data) {
    console.log('DATA: ' + data);
    mainWindow.webContents.send('received-data', '' + data);
    // Prove that I can close the app from outside
    if ('' + data == 'hangup'){
        console.log('bye');
        app.quit();
    }
});

Listen for messages from the renderer and relay them to the outside world.

// 3. relay data from mainWindow (the renderer process) to home.
ipcMain.on('phoneHome', function (event) {
    client.write('phoneHome');
});

We use client to send and receive data from the outside world, mainWindow.webContents to send data to the renderer, and ipcMain to receive data from the renderer.

index.html (excerpt)

<script>
    $(document).ready(function () {
        // Inter Process Communication module for the renderer process
        const ipcRenderer = require('electron').ipcRenderer;

        // Recieves data from the main process
        ipcRenderer.on('received-data', function (evt, message) {
            $("#received-data-content").append(message + "<br \>");
        });

        // Sends data back to the main process
        // when the phoneHome button is clicked
        $("#phoneHome").click(function (event) {
            ipcRenderer.send('phoneHome');
        });
    });
</script>

Working together

ep-02-electron-and-notnet.PNG

Since I didn't write much error checking, you will need to launch TCP Server Simulator before launching the Phone Home App.

  1. Launch TCP Server Simulator.

  2. Launch Phone Home App. If you got this off my GitHub, don't forget to install dependencies before you launch.

  3. When you launch the Phone Home App - notice that "Line Opened" appears in TCP Server Simulator's Log textbox.

  4. Enter some text in TCP Server Simulator's "Broadcast Text" textbox and click "Send" - notice that it appears under "Incoming Calls" in the Phone Home App.

  5. Click the "Phone Home" button in the Phone Home App - notice that "Line Opened" appears in TCP Server Simulator's Log textbox.

  6. Enter "hangup" (exactly as shown, lower case, no spaces, no enter) in TCP Server Simulator's "Broadcast Text" textbox and click "Send" - notice that the Phone Home App shuts down.

  7. You can relaunch Phone Home App to experiment further.

Progress in the FrakenApp #1 project

What I have

  • An Electron app that can communicate with a .NET app (which I didn't even have to write).
  • I can control the Electron app from the .NET app (just send the command "hangup" and the Electron app closes).

What's still missing

  • No Oracle.
  • Using .NET Framework, not .NET Core.
  • Using JavaScript, not TypeScript.
  • Using JQuery, not React.js.
  • Not actually building the Electron App; I'm running it from VS Code.
  • Didn't even touch the Mac.

The Code

The code is available on my GitHub as Frakenapp-01 or the Release for this article.