NodeServices:dove Javascript e .NET si incontrano dall'altra parte

Questo è stato originariamente pubblicato sul mio blog.

Javascript è ovunque. È nel browser, sul server, e si arrampica attraverso le tue finestre e rapisce la tua gente. E poiché è un linguaggio abbastanza banale da imparare (ma impossibile da padroneggiare), può essere estremamente utile quando vuoi fare qualcosa su il server.

Questo era ed è tuttora il vero fascino di tecnologie come Node.js, tuttavia è abbastanza facile da fare nel regno di .NET. Questo post fornirà una panoramica molto semplice su come indirizzare ed eseguire del codice Javascript arbitrario all'interno di .NET senza mai toccare il browser.

Che cos'è/sono i NodeServices?

Lascerò che il creatore, Steve Sanderson, lo spieghi come segue:

  • NodeServices fornisce un modo rapido e affidabile per il codice .NET di eseguire JavaScript sul server all'interno di un ambiente Node.js. Puoi usarlo per utilizzare funzionalità arbitrarie dai pacchetti NPM in fase di esecuzione nell'app ASP.NET Core.

  • La maggior parte degli sviluppatori di applicazioni non ha bisogno di usarlo direttamente, ma puoi farlo se desideri implementare la tua funzionalità che implica la chiamata del codice Node.js da .NET in fase di esecuzione.

Puoi trovare il progetto stesso anche su GitHub, che va ben oltre la semplice interazione con il solo Node in .NET.

Configurazione di NodeServices

Questo particolare esempio di NodeServices dipende da .NET Core 2.0, che vorrai installare da qui se vuoi seguire. I passaggi possono funziona con le versioni precedenti, ma se riscontri problemi, prova a provare la 2.0.

In questo esempio, creeremo una semplice API Web che si baserà su NodeServices per eseguire alcune operazioni. Quindi, per iniziare, dovremo prima creare un nuovo progetto:

dotnet new webapi

Se non sei un utente della riga di comando, Visual Studio 2017 Update 3 dovrebbe disporre degli strumenti necessari per creare applicazioni .NET Core 2.0 tramite la tradizionale GUI.

Configurazione di NodeServices

Iniziare con NodeServices è semplicissimo. Fondamentalmente devi solo includere il Microsoft.AspNetCore.NodeServices Pacchetto NuGet all'interno dell'applicazione tramite il comando seguente:

dotnet add package Microsoft.AspNetCore.NodeServices

Dovresti quindi vederlo anche nella definizione del tuo progetto:

<ItemGroup>
    <!-- Others omitted for brevity -->
    <PackageReference Include="Microsoft.AspNetCore.NodeServices" Version="2.0.0" />
</ItemGroup>

Quindi, dovrai configurare il middleware necessario per gestire l'utilizzo del servizio all'interno della tua applicazione nel ConfigureServices() metodo del tuo Startup.cs file:

public void ConfigureServices(IServiceCollection services)
{
    // This will configure the NodeServices service
    services.AddNodeServices();
}

Dopo aver configurato i servizi, ora sarai in grado di utilizzare l'inserimento delle dipendenze per gestire l'inserimento di questo nella tua applicazione a livello di controller:

public class ValuesController : Controller
{
        private readonly INodeServices _nodeServices;

        public ExampleController(INodeServices nodeServices)
        {
            _nodeServices = nodeServices;
        }

        // Other actions here
}

O a livello di metodo/azione singolo con [FromServices] attributo:

public async Task<IActionResult> Example([FromServices] INodeServices nodeServices)
{
       // TODO: Cool stuff
}

Ora che abbiamo cablato i servizi dei nodi, diamo un'occhiata a cosa è necessario fare sul lato Javascript per far sì che le due parti giochino bene l'una con l'altra.

Utilizzo effettivo di NodeServices

Poiché chiameremo codice Javascript da .NET, dovremo prima definire il codice effettivo che vogliamo chiamare. Quindi, per iniziare, creeremo una nuova cartella Scripts nella radice del progetto corrente e un nuovo file chiamato Add.js al suo interno :

Questo file Add.js funzionerà come un singolo modulo che esporterà una funzione che verrà chiamata dal nostro codice C#. Per semplicità, inizieremo semplicemente sommando due numeri e restituendo il risultato tramite una richiamata:

module.exports = function(a, b, callback) { 
  let result = a + b;
  callback(result); 
};

Tornando al lato .NET delle cose, possiamo configurare il nostro servizio in modo che punti al nostro nuovo file Javascript usando il InvokeAsync<T>() metodo, che prevede il percorso del file richiamato e un tipo per indicare il tipo restituito previsto:

public async Task<long> Add(int x = 11, int y = 31)
{
    return await _nodeServices.InvokeAsync<long>("Scripts/Add.js", x, y);
}

Dopo aver eseguito l'applicazione e aver raggiunto l'endpoint, vedrai rapidamente il risultato atteso e che nessun Javascript lato client è stato danneggiato durante la creazione della risposta:

Ora, se hai familiarità con Javascript, allora sai che può fare tutti i tipi di pazzi cose, specialmente quando usi funzioni davvero pericolose come eval() . Creeremo un altro file chiamato Eval.js da aggiungere alla nostra cartella Scripts esistente che assomiglia a questa:

module.exports = function (callback, x) {
    let result = eval(x);
    callback(null, result);
};

A scopo dimostrativo, creiamo un altro metodo che accetti del testo arbitrario e lo valuti all'interno del nostro controller dell'API Web:

public async Task<string> Eval(string expression = "6 * 7")
{
    return await _nodeServices.InvokeAsync<string>("Scripts/Eval.js", expression);
}

Possiamo vederlo in azione di seguito:

NodeServices brilla davvero in scenari in cui potresti non essere in grado di trovare il pacchetto NuGet perfetto che stai cercando, ma ne esiste uno su npm o da qualche altra parte nel vasto ecosistema Javascript. Prendi semplicemente il codice di cui hai bisogno o scarica il pacchetto npm stesso (insieme alle sue dipendenze richieste) e usalo come ti aspetteresti.

Vediamo come potrebbe funzionare qualcosa del genere se decidiamo di utilizzare un pacchetto npm di fantasia per generare codici QR utilizzando un po' di testo. Innanzitutto, dovremo installare il pacchetto npm appropriato:

npm install qr-image

Ancora una volta:se non sei un fan della riga di comando, puoi scaricarlo direttamente dal sorgente su GitHub o utilizzando un altro gestore di pacchetti a tua scelta.

Una volta scaricato il pacchetto QR, puoi creare un nuovo file nella cartella Scripts chiamato QR.js. Dato che ora siamo in un mondo Node, dovrai solo collegare le dipendenze appropriate tramite un require() istruzione che punta al tuo pacchetto e aggiungi il codice seguente:

let qr = require('./qr-image');
module.exports = function (callback, text) {
    var result = qr.imageSync(text, { type: 'png' });

    var data = [];
    result.forEach(i => {
        data.push(i);
    });

    callback(null, data);
};

Questo fa quanto segue:

  • Prepara il nostro pacchetto QR per l'uso.
  • Utilizza i dati della stringa passati per generare un'immagine del codice QR.
  • Legge i dati dell'immagine in un byte[] che il nostro codice C# consumerà.

A questo punto, possiamo scrivere il metodo corrispondente con la nostra API:

public async Task<IActionResult> QR(string text = "42")
{
    var data = await _nodeServices.InvokeAsync<byte[]>("Scripts/QR.js", text);
    return File(data, "image/png");
}

E quando utilizziamo quel metodo, vediamo che i valori ritornano come previsto:

Questa è davvero solo la punta dell'iceberg, ma dimostra quanto sia facile integrare l'intero ecosistema dei nodi all'interno di .NET per creare tutti i tipi di applicazioni.

Provaci!

Come accennato in precedenza nel post, gli ecosistemi npm e Node sono enormi e ci sono tonnellate di pacchetti utili che ora puoi estrarre e integrare facilmente nelle tue applicazioni ASP.NET.

Se non vuoi seguire tutti questi passaggi a mano, sentiti libero di estrarre il codice da questa demo o dai un'occhiata anche agli esempi aggiuntivi di Steve Sanderson trovati nel repository NodeServices:

  • Guarda questi esempi su GitHub
  • Guarda gli esempi di Steve Sanderson su GitHub