{"id":1986,"date":"2020-04-29T13:08:48","date_gmt":"2020-04-29T13:08:48","guid":{"rendered":"https:\/\/cloudsurfers.it\/dev?p=1986"},"modified":"2020-06-23T20:37:03","modified_gmt":"2020-06-23T20:37:03","slug":"creare-unapplicazione-desktop-multipiattaforma-usando-electron-e-net-core","status":"publish","type":"post","link":"https:\/\/cloudsurfers.it\/index.php\/creare-unapplicazione-desktop-multipiattaforma-usando-electron-e-net-core\/","title":{"rendered":"Creare un\u2019applicazione desktop multipiattaforma usando Electron e .NET Core"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1991\" src=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/\/2020\/04\/Header-1.png\" alt=\"Electron love .NET Core\" width=\"1200\" height=\"600\" srcset=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Header-1.png 1200w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Header-1-300x150.png 300w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Header-1-1024x512.png 1024w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Header-1-768x384.png 768w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Header-1-600x300.png 600w\" sizes=\"auto, (max-width: 1200px) 100vw, 1200px\" \/><\/p>\n<p>Una delle prime problematiche che si incontrano nella realizzazione di un applicativo desktop multipiattaforma \u00e8 sicuramente la scelta delle librerie grafiche per la realizzazione dell&#8217;interfaccia.<\/p>\n<p>In questo articolo viene proposto l&#8217;utilizzo di due strumenti: <a href=\"https:\/\/www.electronjs.org\/\"><strong>Electron<\/strong> <\/a>e <strong>.NET Core<\/strong>, rispettivamente, per la gestione del front-end\u00a0il primo e per la gestione della business logic dell&#8217;applicativo il secondo.<\/p>\n<h1>Che cos&#8217;\u00e8 Electron?<\/h1>\n<p><strong>Electron<\/strong>, citando il sito web, \u00e8 un framework per la creazione di applicazioni native con tecnologie web come <em>Javascript<\/em>, <em>HTML<\/em> e <em>CSS<\/em>.<\/p>\n<p>L&#8217;utilizzo di queste tecnologie permette di creare interfacce grafiche veloci, intuitive, piacevoli alla vista e soprattutto, multipiattaforma.<\/p>\n<p>Tanto per rendere l&#8217;idea, <strong>Visual Studio Code<\/strong> \u00e8 basato su <strong>Electron<\/strong>.<\/p>\n<h1>e .NET Core?<\/h1>\n<p>Arrivato alla versione 3, \u00e8 un framework software gratuito e open source per i sistemi operativi Microsoft Windows, MacOS e Linux che consente la creazione di applicazioni Web ASP.NET Core, app da riga di comando, librerie e applicazioni Universal Windows Platform.<\/p>\n<p>Il punto d&#8217;incontro di questi due framework, \u00e8 <strong>Electron CGI<\/strong>, una libreria <em>NodeJs<\/em> rilasciata con licenza <em>MIT<\/em> che permette di stabilire un canale di comunicazione bidirezionale tra l&#8217;applicativo <strong>Electron<\/strong> ed un processo esterno <strong>.NET Core<\/strong> mediante uno scambio di messaggi tramite flussi <em>stdin<\/em> ed <em>stdout<\/em>.<\/p>\n<p>Il risultato finale \u00e8 un matrimonio perfetto, un&#8217;applicativo multipiattaforma che sfrutta tutte le potenzialit\u00e0 della piattaforma <strong>.NET Core<\/strong> insieme a quelle <strong>Electron<\/strong> per l&#8217;interfaccia grafica.<\/p>\n<h1>Strumenti di sviluppo<\/h1>\n<p>Per la realizzazione di questa applicazione di esempio e di questa guida, sono stati utilizzati i seguenti strumenti di sviluppo:<\/p>\n<ul>\n<li><a href=\"https:\/\/visualstudio.microsoft.com\/it\/vs\/\">Visual Studio 2019<\/a>;<\/li>\n<li><a href=\"https:\/\/dotnet.microsoft.com\/download\">.NET Core 3.1<\/a>;<\/li>\n<li><a href=\"https:\/\/code.visualstudio.com\/\">Visual Studio Code;<\/a><\/li>\n<li><a href=\"https:\/\/nodejs.org\/it\/\">Node.js<\/a>.<\/li>\n<\/ul>\n<p><strong>Visual Studio 2019<\/strong> e <strong>Visual Studio Code<\/strong> non sono strettamente necessari in quanto, sia per quanto riguarda <strong>Electron<\/strong>, sia per <strong>.NET Core<\/strong>, si possono creare e gestire progetti anche da riga di comando.<\/p>\n<h1>Il progetto .NET Core<\/h1>\n<p>Una volta aperto <em>VS2019<\/em>, creare un nuovo progetto <strong>App console (.NET Core)<\/strong> selezionando il template che utilizza il linguaggio <em>C#<\/em>:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2004\" src=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/\/2020\/04\/Crea_Progetto_App_Console.png\" alt=\"Creazione progetto console\" width=\"2560\" height=\"706\" srcset=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Crea_Progetto_App_Console.png 2560w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Crea_Progetto_App_Console-300x83.png 300w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Crea_Progetto_App_Console-1024x282.png 1024w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Crea_Progetto_App_Console-768x212.png 768w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Crea_Progetto_App_Console-1536x424.png 1536w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Crea_Progetto_App_Console-2048x565.png 2048w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Crea_Progetto_App_Console-600x165.png 600w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><\/p>\n<p>Successivamente, aggiungere al progetto, il pacchetto <em>Nuget<\/em> <strong>ElectronCgi.DotNet<\/strong>:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2005\" src=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/\/2020\/04\/Installazione_Pacchetto_Nuget.png\" alt=\"Installazione pacchetto Nuget\" width=\"1834\" height=\"840\" srcset=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Installazione_Pacchetto_Nuget.png 1834w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Installazione_Pacchetto_Nuget-300x137.png 300w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Installazione_Pacchetto_Nuget-1024x469.png 1024w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Installazione_Pacchetto_Nuget-768x352.png 768w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Installazione_Pacchetto_Nuget-1536x704.png 1536w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Installazione_Pacchetto_Nuget-600x275.png 600w\" sizes=\"auto, (max-width: 1834px) 100vw, 1834px\" \/><\/p>\n<p>Copiare quindi il codice seguente all&#8217;interno del file <strong>Program.cs<\/strong>:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nusing ElectronCgi.DotNet;\r\nusing System.Timers;\r\n\r\nnamespace ConsoleAppNETCore\r\n{\r\n    class Program\r\n    {\r\n        static void Main(string&#x5B;] args)\r\n        {\r\n            var connection = new ConnectionBuilder()\r\n                .WithLogging()\r\n                .Build();\r\n\r\n            connection.On&lt;string, string&gt;(&quot;getCarManufacturerFromModel&quot;, model =&gt;\r\n            {\r\n                switch (model)\r\n                {\r\n                    case &quot;Punto&quot;:\r\n                    case &quot;Tipo&quot;:\r\n                    case &quot;Bravo&quot;:\r\n                        return &quot;Fiat&quot;;\r\n                    case &quot;Fiesta&quot;:\r\n                    case &quot;Focus&quot;:\r\n                        return &quot;Ford&quot;;\r\n                    case &quot;Corsa&quot;:\r\n                    case &quot;Astra&quot;:\r\n                        return &quot;Opel&quot;;\r\n                    case &quot;Ibiza&quot;:\r\n                    case &quot;Leon&quot;:\r\n                        return &quot;Seat&quot;;\r\n                    default:\r\n                        return &quot;Unknown&quot;;\r\n                }\r\n            });\r\n\r\n            var counter = 0;\r\n\r\n            var timer = new Timer(1000);\r\n            timer.Elapsed += delegate\r\n            {\r\n                connection.Send&lt;int&gt;(&quot;sendCounter&quot;, counter);\r\n                counter++;\r\n            };\r\n            timer.Start();\r\n\r\n            \/\/ In ascolto per le richieste in entrata\r\n            connection.Listen();\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>Esaminiamo ora il codice pi\u00f9 nel dettaglio.<\/p>\n<p>Prima di tutto \u00e8 necessario importare la libreria:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nusing ElectronCgi.DotNet;\r\n<\/pre>\n<p>Successivamente, all&#8217;interno del metodo principale <strong>Main<\/strong>, si inizializza il canale di comunicazione:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar connection = new ConnectionBuilder()\r\n    .WithLogging()\r\n    .Build();\r\n<\/pre>\n<p>Impostiamo poi un messaggio &#8220;<em>in ascolto<\/em>&#8221; che chiamiamo <strong>getCarManufacturerFromModel<\/strong>. Questo, accetta in input una variabile stringa, nel nostro caso il modello di un&#8217;auto, e restituisce in output un&#8217;altra variabile stringa, nel nostro caso la casa costruttrice del modello di auto in ingresso:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nconnection.On&lt;string, string&gt;(&quot;getCarManufacturerFromModel&quot;, model =&gt;\r\n{\r\n    switch (model)\r\n    {\r\n        case &quot;Punto&quot;:\r\n        case &quot;Tipo&quot;:\r\n        case &quot;Bravo&quot;:\r\n            return &quot;Fiat&quot;;\r\n        case &quot;Fiesta&quot;:\r\n        case &quot;Focus&quot;:\r\n            return &quot;Ford&quot;;\r\n        case &quot;Corsa&quot;:\r\n        case &quot;Astra&quot;:\r\n            return &quot;Opel&quot;;\r\n        case &quot;Ibiza&quot;:\r\n        case &quot;Leon&quot;:\r\n            return &quot;Seat&quot;;\r\n        default:\r\n            return &quot;Unknown&quot;;\r\n    }\r\n});\r\n<\/pre>\n<p>Impostiamo anche un <em>Timer<\/em> con un intervallo di un secondo che: aumenta un contatore ed invia un messaggio <strong>sendCounter<\/strong> tramite il canale di comunicazione con al suo interno il contatore progressivo:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar counter = 0; \r\nvar timer = new Timer(1000); \r\ntimer.Elapsed += delegate { \r\n    connection.Send&lt;int&gt;(&quot;sendCounter&quot;, counter); \r\n    counter++; \r\n}; \r\ntimer.Start();\r\n<\/pre>\n<p>Questi due messaggi di esempio ci permetteranno di vedere all&#8217;opera una comunicazione bidirezionale fra questo applicativo <strong>.NET Core<\/strong> e quello che andremo a creare successivamente con <strong>Electron<\/strong>.<\/p>\n<p>Infine, bisogna impostare il canale di comunicazione per iniziare <em>l&#8217;ascolto<\/em> dei messaggi in entrata:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nconnection.Listen();\r\n<\/pre>\n<p>A questo punto non ci resta che compilare il progetto per generare il file .dll e l&#8217;eseguibile .exe dell&#8217;applicativo console.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2007\" src=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/\/2020\/04\/Progetto_NET_Core_Compilato.png\" alt=\"Progetto .NET Core compilato\" width=\"1852\" height=\"1189\" srcset=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Progetto_NET_Core_Compilato.png 1852w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Progetto_NET_Core_Compilato-300x193.png 300w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Progetto_NET_Core_Compilato-1024x657.png 1024w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Progetto_NET_Core_Compilato-768x493.png 768w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Progetto_NET_Core_Compilato-1536x986.png 1536w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Progetto_NET_Core_Compilato-600x385.png 600w\" sizes=\"auto, (max-width: 1852px) 100vw, 1852px\" \/><\/p>\n<h1>Il progetto Electron<\/h1>\n<p>Creare una nuova cartella per il nuovo progetto <strong>Electron<\/strong>, ed al suo interno creare tre file vuoti:<\/p>\n<ul>\n<li>index.html;<\/li>\n<li>main.js;<\/li>\n<li>package.json.<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2008\" src=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/\/2020\/04\/Progetto_ElectronApp.png\" alt=\"Cartella progetto Electron\" width=\"1852\" height=\"1189\" srcset=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Progetto_ElectronApp.png 1852w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Progetto_ElectronApp-300x193.png 300w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Progetto_ElectronApp-1024x657.png 1024w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Progetto_ElectronApp-768x493.png 768w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Progetto_ElectronApp-1536x986.png 1536w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Progetto_ElectronApp-600x385.png 600w\" sizes=\"auto, (max-width: 1852px) 100vw, 1852px\" \/><\/p>\n<p>Aprire quindi la cartella appena creata con <em>VSCODE<\/em> e, tramite il pannello del terminale (<strong>View<\/strong>, <strong>Terminal<\/strong>), lanciare il comando:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nnpm init\r\n<\/pre>\n<p>Questo comando effettua l&#8217;inizializzazione del progetto compilando il file <strong>package.json<\/strong>.<\/p>\n<p>Verr\u00e0 richiesto di impostare alcuni parametri come: il nome pacchetto, la versione, la descrizione, ecc&#8230;.<\/p>\n<p>Quando verr\u00e0 richiesto di impostare il punto d&#8217;ingresso dell&#8217;applicativo (<strong>Entry point<\/strong>), \u00e8 necessario inserire <strong>main.js<\/strong>.<\/p>\n<p>Al termine della procedura si otterr\u00e0 un <strong>package.json<\/strong> di questo tipo:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n{\r\n    &quot;name&quot;: &quot;com.electronapp.example&quot;,\r\n    &quot;version&quot;: &quot;1.0.0&quot;,\r\n    &quot;description&quot;: &quot;Esempio di applicazione Electron + .NET Core&quot;,\r\n    &quot;main&quot;: &quot;main.js&quot;,\r\n    &quot;scripts&quot;: {\r\n        &quot;test&quot;: &quot;echo \\&quot;Error: no test specified\\&quot; &amp;&amp; exit 1&quot;\r\n    },\r\n    &quot;author&quot;: &quot;&quot;,\r\n    &quot;license&quot;: &quot;ISC&quot;\r\n}\r\n<\/pre>\n<p>All&#8217;interno del nodo <strong>scripts<\/strong> bisogna aggiungere la chiave <strong>start<\/strong> come segue, per trasformare l&#8217;applicazione <em>Node<\/em> appena creata in applicazione <strong>Electron<\/strong>:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n&quot;scripts&quot;: {\r\n    &quot;start&quot;: &quot;electron .&quot;,\r\n    &quot;test&quot;: &quot;echo \\&quot;Error: no test specified\\&quot; &amp;&amp; exit 1&quot;\r\n},\r\n<\/pre>\n<p>Proseguire quindi con l&#8217;installazione del pacchetto <strong>Electron<\/strong> all&#8217;interno del progetto con questo comando:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nnpm install --save-dev electron\r\n<\/pre>\n<p>Compilare il file <strong>main.js<\/strong> come segue:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nconst { app, BrowserWindow } = require('electron')\r\n\r\nfunction createWindow () {\r\n    const win = new BrowserWindow({\r\n        width: 800,\r\n        height: 600,\r\n        webPreferences: {\r\n            nodeIntegration: true\r\n        }\r\n    });\r\n\r\n    win.loadFile('index.html');\r\n}\r\n\/\/ Questo metodo viene chiamato quando Electron ha terminato l'inizializzazione\r\napp.whenReady().then(createWindow);\r\n\r\n\/\/ Evento invocato quando tutte le finestre sono chiuse\r\napp.on('window-all-closed', () =&gt; {\r\n    \/\/ Su macOS \u00e8 comune che l'applicazione e la barra men\u00f9\r\n    \/\/ restano attive finch\u00e9 l'utente non esce espressamente tramite i tasti Cmd + Q\r\n    if (process.platform !== 'darwin') {\r\n        app.quit();\r\n    }\r\n});\r\n\r\napp.on('activate', () =&gt; {\r\n    \/\/ Su macOS \u00e8 comune ri-creare la finestra dell'app quando\r\n    \/\/ viene cliccata l'icona sul dock e non ci sono altre finestre aperte.\r\n    if (BrowserWindow.getAllWindows().length === 0) {\r\n        createWindow()\r\n    }\r\n});\r\n<\/pre>\n<p>Le istruzioni sopra permettono di inizializzare l&#8217;applicativo <strong>Electron<\/strong> creando una nuova finestra (<em>BrowserWindow<\/em>) in cui viene caricato il file <strong>index.html<\/strong> che conterr\u00e0 ci\u00f2 che verr\u00e0 renderizzato all&#8217;interno di essa.<\/p>\n<p>Il template mostrato \u00e8 basilare e fornisce gli elementi essenziali per caricare e gestire correttamente la finestra appena creata anche su altri sistemi operativi, come per esempio <em>macOS<\/em>.<\/p>\n<p>Compiliamo ora il file <strong>index.html<\/strong> come segue:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;!DOCTYPE html&gt;\r\n&lt;html&gt;\r\n    &lt;head&gt;\r\n        &lt;meta charset=&quot;UTF-8&quot;&gt;\r\n        &lt;title&gt;Example App&lt;\/title&gt;\r\n        &lt;!-- https:\/\/electronjs.org\/docs\/tutorial\/security#csp-meta-tag --&gt;\r\n        &lt;meta http-equiv=&quot;Content-Security-Policy&quot; content=&quot;script-src 'self' 'unsafe-inline';&quot; \/&gt;\r\n    &lt;\/head&gt;\r\n    &lt;body&gt;\r\n        &lt;h1&gt;Esempio Invio&lt;\/h1&gt;\r\n        &lt;div&gt;\r\n            &lt;input type=&quot;text&quot; placeholder=&quot;Modello auto&quot; \/&gt;\r\n            &lt;button&gt;Invia&lt;\/button&gt;\r\n            &lt;label&gt;Risultato: &lt;\/label&gt;\r\n        &lt;\/div&gt;\r\n        &lt;h1&gt;Esempio Ricezione&lt;\/h1&gt;\r\n        &lt;div&gt;\r\n            &lt;label&gt;Contatore: 0&lt;\/label&gt;\r\n        &lt;\/div&gt;\r\n    &lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/pre>\n<p>Lanciando dal pannello terminale il comando:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nnpm start\r\n<\/pre>\n<p>Verr\u00e0 avviata l&#8217;applicazione:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2012\" src=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/\/2020\/04\/Immagine_Primo_Esempio_App.png\" alt=\"Primo esempio App Electron\" width=\"1325\" height=\"819\" srcset=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Immagine_Primo_Esempio_App.png 1325w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Immagine_Primo_Esempio_App-300x185.png 300w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Immagine_Primo_Esempio_App-1024x633.png 1024w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Immagine_Primo_Esempio_App-768x475.png 768w, https:\/\/cloudsurfers.it\/wp-content\/uploads\/2020\/04\/Immagine_Primo_Esempio_App-600x371.png 600w\" sizes=\"auto, (max-width: 1325px) 100vw, 1325px\" \/><\/p>\n<p>Come si pu\u00f2 vedere l&#8217;applicazione si presenta gi\u00e0 con un menu predefinito ed il nostro codice <em>HTML<\/em> viene renderizzato correttamente.<\/p>\n<h1>Il matrimonio<\/h1>\n<p>Ora non ci resta che &#8220;<em>legare<\/em>&#8221; l&#8217;applicativo console <strong>.NET Core<\/strong> con l&#8217;applicativo <strong>Electron<\/strong>.<\/p>\n<p>Per farlo dobbiamo innanzitutto aggiungere al nostro progetto <em>Electron<\/em> il pacchetto <strong>electron-cgi<\/strong>.<\/p>\n<p>Per farlo possiamo utilizzare il comando:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nnpm install electron-cgi\r\n<\/pre>\n<p>Fatto ci\u00f2, bisogna ora aggiungere le istruzioni per inizializzare ed utilizzare il canale di comunicazione anche da questo applicativo.<\/p>\n<p>Di seguito il file <strong>index.html<\/strong> precedente, con le dovute aggiunte:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;!DOCTYPE html&gt;\r\n&lt;html&gt;\r\n    &lt;head&gt;\r\n        &lt;meta charset=&quot;UTF-8&quot;&gt;\r\n        &lt;title&gt;Example App&lt;\/title&gt;\r\n        &lt;!-- https:\/\/electronjs.org\/docs\/tutorial\/security#csp-meta-tag --&gt;\r\n        &lt;meta http-equiv=&quot;Content-Security-Policy&quot; content=&quot;script-src 'self' 'unsafe-inline';&quot; \/&gt;\r\n    &lt;\/head&gt;\r\n    &lt;body&gt;\r\n        &lt;h1&gt;Esempio Invio&lt;\/h1&gt;\r\n        &lt;div&gt;\r\n            &lt;input id=&quot;inputModello&quot; type=&quot;text&quot; placeholder=&quot;Modello auto&quot; \/&gt;\r\n            &lt;button onclick=&quot;onSendClick()&quot;&gt;Invia&lt;\/button&gt;\r\n            &lt;label id=&quot;labelRisultato&quot;&gt;Risultato: &lt;\/label&gt;\r\n        &lt;\/div&gt;\r\n        &lt;h1&gt;Esempio Ricezione&lt;\/h1&gt;\r\n        &lt;div&gt;\r\n            &lt;label id=&quot;labelContatore&quot;&gt;Contatore: 0&lt;\/label&gt;\r\n        &lt;\/div&gt;\r\n        &lt;script&gt;\r\n            const { ConnectionBuilder } = require('electron-cgi');\r\n            \r\n            const inputModello = document.querySelector(&quot;#inputModello&quot;);\r\n            const labelRisultato = document.querySelector(&quot;#labelRisultato&quot;);\r\n            const labelContatore = document.querySelector(&quot;#labelContatore&quot;);\r\n\r\n            const connection = new ConnectionBuilder()\r\n                .connectTo('dotnet', 'run', '--project', '..\/ConsoleAppNETCore')\r\n                .build();\r\n           \r\n            connection.onDisconnect = () =&gt; {\r\n                console.log('Perdita di connessione al processo .NET');\r\n            };\r\n\r\n            async function onSendClick() {\r\n                const modello = inputModello.value;\r\n                const costruttore = await connection.send('getCarManufacturerFromModel', modello);\r\n                labelRisultato.textContent = `Risultato: ${costruttore}`;\r\n            }\r\n\r\n            connection.on('sendCounter', res =&gt; {\r\n                labelContatore.textContent = `Contatore: ${res}`;\r\n            });\r\n        &lt;\/script&gt;\r\n    &lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/pre>\n<p>Spieghiamo ora il codice un po&#8217; pi\u00f9 nel dettaglio.<\/p>\n<p>La prima cosa da fare, come per il progetto <strong>.NET Core<\/strong>, bisogna inizializzare il canale di comunicazione:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nconst { ConnectionBuilder } = require('electron-cgi');\r\n\r\nconst connection = new ConnectionBuilder()\r\n    .connectTo('dotnet', 'run', '--project', '..\/ConsoleAppNETCore')\r\n    .build();\r\n<\/pre>\n<p>Il metodo <strong>connectTo<\/strong> permette di &#8220;<em>collegarsi<\/em>&#8221; ad un processo esterno <strong>.NET Core<\/strong>.<\/p>\n<p>Il processo esterno pu\u00f2 essere collegato come nell&#8217;esempio sopra tramite la cartella del progetto, oppure, mediante il file .dll o l&#8217;eseguibile .exe compilato.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nconnection.onDisconnect = () =&gt; {\r\n    console.log('Perdita di connessione al processo .NET');\r\n};\r\n<\/pre>\n<p>L&#8217;evento <strong>onDisconnect<\/strong> permette di intercettare una disconnessione, volontaria o in caso di errore, fra il processo esterno <strong>.NET Core<\/strong> e l&#8217;applicativo <strong>Electron<\/strong>.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nasync function onSendClick() {\r\n    const modello = inputModello.value;\r\n    const costruttore = await connection.send('getCarManufacturerFromModel', modello);\r\n    labelRisultato.textContent = `Risultato: ${costruttore}`;\r\n}\r\n<\/pre>\n<p>All&#8217;evento <strong>onclick<\/strong>, sul pulsante <strong>Invia<\/strong>, viene prelevato il valore di input (il modello dell&#8217;auto) e viene inviato il messaggio <strong>getCarManufacturerFromModel<\/strong> all&#8217;interno del canale di comunicazione.<\/p>\n<p>La risposta del messaggio, una variabile stringa contenente la casa costruttrice del modello di auto, viene poi stampata all&#8217;interno di un&#8217;oggetto <em>label<\/em>.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nconnection.on('sendCounter', res =&gt; {\r\n    labelContatore.textContent = `Contatore: ${res}`;\r\n});\r\n<\/pre>\n<p>Infine, intercettando il messaggio <strong>sendCounter<\/strong>, inviato dall&#8217;applicativo console <strong>.NET Core<\/strong> ogni secondo mediante un timer, viene stampato il risultato ricevuto all&#8217;interno della label predisposta.<\/p>\n<p>Il risultato finale \u00e8 il seguente:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2016\" src=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/\/2020\/04\/Risultato_Finale.gif\" alt=\"Risultato finale applicativo\" width=\"1566\" height=\"694\" \/><\/p>\n<h1>E su macOS?<\/h1>\n<p>Su <strong>macOS<\/strong> (dopo aver installato come su <em>Window<\/em> <strong>.NET Core SDK<\/strong>), basta aprire il progetto con <em>VSCODE <\/em>e lanciare il comando:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nnpm install\r\n<\/pre>\n<p>attendere il termine dell&#8217;installazione dei pacchetti e successivamente lanciare:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nnpm start\r\n<\/pre>\n<p>ed ecco il risultato:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2018\" src=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/\/2020\/04\/2020-04-29-14.41.57.gif\" alt=\"Applicativo su macOS\" width=\"1904\" height=\"814\" \/><\/p>\n<h1>Conclusione<\/h1>\n<p>In conclusione, l&#8217;accoppiata <strong>Electron<\/strong> e <strong>.NET Core<\/strong> risulta vincente sotto diversi aspetti:<\/p>\n<ul>\n<li>La portabilit\u00e0 su altri sistemi operativi \u00e8 immediata utilizzando questi due strumenti, come visto per esempio su <strong>macOS<\/strong> nell&#8217;esempio sopra.<\/li>\n<li>Le tecnologie web utilizzate da <strong>Electron<\/strong>: <em>Javascript<\/em>, <em>HTML<\/em> e <em>CSS<\/em> permettono un&#8217;altissima personalizzazione grafica. E&#8217; integrabile per esempio con strumenti come <strong>Bootstrap<\/strong>, oppure <strong>Material<\/strong>.<\/li>\n<li>La community dietro al progetto <strong>Electron<\/strong> \u00e8 molto ampia e la documentazione \u00e8 completa, molte guide sono inoltre in Italiano.<\/li>\n<\/ul>\n<p>L&#8217;esempio presente in questa guida \u00e8 scaricabile a questo <a href=\"https:\/\/cloudsurfers.it\/wp-content\/uploads\/\/2020\/04\/ElectronDotNETCoreAppExample.zip\">link<\/a>.<\/p>\n<h1>Link utili<\/h1>\n<p><a href=\"https:\/\/www.electronjs.org\/docs\/tutorial\/first-app#scrivi-la-tua-prima-app-electron\">https:\/\/www.electronjs.org\/docs\/tutorial\/first-app#scrivi-la-tua-prima-app-electron<\/a><\/p>\n<p><a href=\"https:\/\/www.nuget.org\/packages\/ElectronCgi.DotNet\">https:\/\/www.nuget.org\/packages\/ElectronCgi.DotNet<\/a><\/p>\n<p><a href=\"https:\/\/www.blinkingcaret.com\/2019\/02\/27\/electron-cgi\/\">https:\/\/www.blinkingcaret.com\/2019\/02\/27\/electron-cgi\/<\/a><\/p>\n<p><a href=\"https:\/\/www.blinkingcaret.com\/2019\/11\/27\/electroncgi-a-solution-to-cross-platform-guis-for-net-core\/\">https:\/\/www.blinkingcaret.com\/2019\/11\/27\/electroncgi-a-solution-to-cross-platform-guis-for-net-core\/<\/a><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Una delle prime problematiche che si incontrano nella realizzazione di un applicativo desktop multipiattaforma \u00e8 sicuramente la scelta delle librerie grafiche per la realizzazione dell&#8217;interfaccia.<br \/>\nIn questo articolo viene proposto l&#8217;utilizzo di due strumenti: Electron e .NET Core, rispettivamente, per la gestione della GUI\u00a0e per la gestione della logica dell&#8217;applicativo.<\/p>\n","protected":false},"author":3,"featured_media":1991,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"wds_primary_category":0,"footnotes":""},"categories":[90,91,36],"tags":[94,96,97,95,93,92],"class_list":["post-1986","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net-core","category-electron","category-guide","tag-net-core","tag-app","tag-crossplatform","tag-desktop","tag-dotnet-core","tag-electron"],"_links":{"self":[{"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/posts\/1986","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/comments?post=1986"}],"version-history":[{"count":0,"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/posts\/1986\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/media\/1991"}],"wp:attachment":[{"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/media?parent=1986"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/categories?post=1986"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudsurfers.it\/index.php\/wp-json\/wp\/v2\/tags?post=1986"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}