STATO DELL´ ARTE SULLO SVILUPPO DI APPLICAZIONI WEB (QUALI TECNOLOGIE SCEGLIERE)


Di solito non amo scrivere del mio lavoro, l´informatica, visto che ne sono immerso per 10 ore al giorno e non vedo l´ora di staccare dall´argomento, ma voglio prendere spunto da due piccoli test che mi sono stati richiesti, per descrivere lo stato dell´arte della programmazione web ad oggi anno 2021.
Premessa storica:
iniziamo con un piccolo ripasso storico e torniamo negli anni 2000/2010 dove a predominare lo sviluppo web era la tecnologia ed il linguaggio Java, ambiente di sviluppo e tool gratuito, multipiattaforma, che permetteva in accoppiata con il database Mysql la creazione di una multi tipologia di sviluppo software, dalle applicazioni desktop a quelle web. Un passo indietro invece rimaneva Microsoft rispetto a Java che proponeva tools di sviluppo a pagamento e funzionanti solo su sistemi proprietari.
Ma negli ultimi 8 anni è cambiato tutto. Microsoft ha accelerato lo sviluppo dei suoi prodotti ed attualmente propone tool di sviluppo open e free, multipiattaforma, in grado di soddisfare ogni tipologia di sviluppo sia lato back-end che lato front-end mentre Java sembra subire una battuta d´arresto per quanto riguarda l´ambiente di sviluppo lato front-end grazie ad ambienti alternativi basati principalmente su framework javascript.
Nel frattempo nasceva l´ambiente di sviluppo Nodejs, un ambiente di sviluppo Client/Server basato su framework javascript che permette di sviluppare applicazioni multipiattaforma, open e free in grado di soddisfare ogni tipologia di sviluppo software. Negli ultimi anni le applicazioni web, visto la possibilità di poter separare gli ambienti di back-end e front end e di poter far colloquiare tranquillamente le due parti anche se create con linguaggi e strumenti diversi, sono sviluppate in ambiente misto. La parte di back end realizzata in dotnet core oppure java services mentre la parte di front end realizzata in ambiente nodejs con framework javascript quali React, Angular e Vue citando i tre più utilizzati nel mondo del front-end.
Nodejs dà la possibilità anche di sviluppare con un unico linguaggio, il javascript, tutta la parte di front-end e
di back-end. Lo stesso dicasi di Microsoft che con Blazor ed un un unico linguaggio di programmazione, il C# dà la possibilità di sviluppare il back-end, ed il front-end.
La domanda viene spontanea......ma quale è il miglior tool di sviluppo di applicazioni web?
La risposta è......dipende dal tipo di web application da realizzare.
Dimostrerò questa risposta creando dei piccoli progetti di test realizzati con tecnologie diverse ma che attengono sempre alla stessa risoluzione di un problema analizzando quando è meglio utilizzare una tecnologia piuttosto che un´altra.

CREAZIONE APPLICAZIONE WEB
I test a me sottoposti da risolvere con linguaggio di programmazione erano due:
Test 01:
Viene fornita una frase. Si chiede di invertire l’intera frase invertendo per prima cosa le singole parole che la compongono. Ad esempio, data la frase: ´I love California´, l’algoritmo deve restituire: ´California love I´.

Test 02:
Viene fornito un array non ordinato di numeri interi ed un secondo numero “x”.
Si tratta di verificare se esistono due valori nell´array tali che la loro somma dia come risultato “X”
Ad esempio dato l’array [2, 4, 1, 9, 7] ed il numero x = 9 l’algoritmo deve restituire True in quanto 2 + 7 = 9
Ad esempio dato l’array [2, 4, 1, 9, 7] ed il numero x = 122 l’algoritmo deve restituire False in quanto non esistono due numeri nell’array la cui somma sia 122

Come ogni programma moderno ho scomposto le parti in back-end e front-end. Questa separazione ha diversi vantaggi. Il primo è la possibilità di sviluppare le due parti con due team diversi in momenti diversi senza fasarsi. Inoltre i due team hanno la possibilità di interagire con la tecnologia back-end che meglio gli aggrada. Quindi il primo step è stato di creare un servizio web api rest con Microsoft dotnet versione 3.1 utilizzando il linguaggio C#. Ho voluto utilizzare questa tecnologia poichè per la parte front-end, più avanti, dimostrerò come sarà possibile creare back-end e front-end con un unico linguaggio, il C# appunto. Per lo sviluppo sia della parte back-end che front-end utilizzerò lo strumento Visual Studio Code che è multipiattaforma e gratuito ed attualmente lo strumento più utilizzato per lo sviluppo software. I miei test li ho eseguiti su una macchina con sistema operativo windows ma li avrei potuti realizzare su macchina Linux (al netto della procedura di installazione degli applicativi) sempre seguendo gli stessi passaggi.

CREAZIONE BACK-END
La prima cosa da fare è installare SDK core net versione 3.1 eseguendo il download dal sito microsoft (https://dotnet.microsoft.com/download/dotnet/3.1 il link del download) e visual studio Code (https://code.visualstudio.com/download).
Installare le extensions di visual studio code, nelle figure sottostanti potete vedere le extensions da me installate per poter utilizzare VSS Code in maniera completa per sviluppare un applicazione web, creazione back-end, creazione front-end, accesso e manipolazione dati al database e gestione del versioning.


Creiamo una cartella locale che chiameremo c:\test\test_be ed apriamo Visual Studio Code posizionandoci sulla cartella test. Apriamo una finestra Terminal da VS Code e verifichiamo che il dotnet sia correntemente installato con il seguente command: dotnet --version
Creiamo un nuovo progetto web api con il command: dotnet new webapi 
Questo comando mi genera tramite un template una struttura di progetto web api per la generazione di servizi web
con un service di esempio denominato WeatherForecast. 
Questo servizio è configurato anche per essere visto su un server con certificato, cosa che noi attualmente non
vogliamo fare perchè vogliamo rimanere sempre nella nostra rete interna di test. Per far questo sotto la cartella Properties aprire il file LaunchSettings.json e cancellare la dicitura https://localhost:5001 nel parametro applicationUrl. 
Lanciare il server dotnet con il command dotnet run da terminal, aprire il browser ed inserire il seguente indirizzo 
http://localhost:5000/weatherforecast ed appariranno i dati risultanti della chiamata al servizio di esempio installato con il template posizionato nel file  weatherforecastController.cs sotto la cartella Controllers.
Dalla cartella Controllers cancelliamo il file del servizio di esempio WeatherForecast, cancelliamo anche il file nella root WeatherForecast.cs. Nella cartella Controllers aggiungiamo i due files relativi ai servizi dei nostri due esercizi
che chiameremo CheckSumController.cs e ReversePhraseController.cs (tasto destro sulla cartella, new file per la creazione) con all´interno i due listati di codice C# riportati qui sotto:

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Web.Http.Cors;

namespace test_be.Controllers
{
    [Route("[controller]")]
    [ApiController]
    public class CheckSumController : ControllerBase
    {
        /// <summary>
        /// 
        /// </summary>
        /// Check sum numbers
        /// <returns></returns>
        [EnableCors(origins"http://localhost:5000/CheckSum"headers"*"methods"*")]
        [HttpPost]
        public async Task<ActionResult<string>> Post([FromBodyParSearch check)
        {
            // Initializing variables
            string retVal = "KO";
            List<intNumbers = check.Numbers;
            int Number = Convert.ToInt32(check.Number);
            int CountNumbers = Numbers.Count;
            int DecrNumbers = CountNumbers;
            int DecrNumbersList = CountNumbers;
            int FirstNumber = 0;
            int LastNumber = 0;
            int Start = 0;

            if (check == null || check.Number==null)
                return NotFound("No data inserted");

            // Loop inside all numbers to take all values with decrement
            while (DecrNumbersList >= 1)
            {
                // loop inside numbers
                for (int Count = StartCount <= DecrNumbers - 1Count = Count + 1)
                {
                    // check is the first number of looping
                    if (Count == Start)
                    {
                        FirstNumber = Numbers[Count];
                    }
                    else
                    {
                        LastNumberNumbers[Count];
                        // sum the two numbers
                        if ((FirstNumber + LastNumber) == Number)
                        {
                            retVal = "OK";
                            DecrNumbers = 1;
                            break// exit controller
                        }
                    }
                }

                if (DecrNumbers == 1)
                {
                    break;
                }
                else
                {
                    DecrNumbersList = DecrNumbersList - 1;
                    Start = Start + 1;
                }                            
            }

            return Ok(retVal);
        }


        /// <summary>
        /// Input object
        /// </summary>
        public class ParSearch
        {
            public List<intNumbers { getset; }
            public string Number { getset; }
        }

    }
}

using Microsoft.AspNetCore.Mvc;
using System;
using System.Web.Http.Cors;

namespace test_be.Controllers
{
    /// <summary>
    /// Reverse the input phrase 
    /// </summary>
    [Route("[controller]")]
    [ApiController]
    public class ReversePhraseController : ControllerBase
    {
        [EnableCors(origins"http://localhost:5000/ReversePhrase"headers"*"methods"*")]
        [HttpGet("{phrase}")]
        public IActionResult Get(string phrase)
        {
            // split phrase for each word
            string[] WordsPhrase = phrase.Split(new[] { " " }, StringSplitOptions.None);
            string ReverseResult = string.Empty;

            // create a new phrase with inverted words position
            for (int CountWords = WordsPhrase.Length - 1CountWords >= 0CountWords--)
            {
                ReverseResult += WordsPhrase[CountWords] + " ";
            }

            // delete last space
            ReverseResult = ReverseResult.Substring(0ReverseResult.Length - 1);

            // return data
            return Ok(ReverseResult);
        }
    }
}

Aprire il file Startup.cs cancellare il vecchio codice ed inserire il codice sottostante:
Verificare che nel file di progetto testbe.csproj vi sia il seguente codice:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
     <PackageReference Include="Microsoft.AspNet.WebApi.Cors" Version="5.2.7" />
  </ItemGroup>

</Project>

I nostri due servizi sono pronti e funzionanti.
Per eseguire un veloce test basterà lanciare il server dotnet run e da browser http://localhost:5000/ReversePhrase/ciao come stai per testare il servizio ReversePhase che opererà un´operazione di get. Il servizio CheckSum lo testeremo tramite interfaccia di front-end.
Siccome lo scopo di questo articolo non è imparare a programmare non mi dilungherò sulla logica del codice e nemmeno sul linguaggio di programmazione ma evidenzierò solo spunti.
Il servizio CheckSum è un servizio che eseguirà un operazione di Post, in ingresso i dati saranno presi dal body della pagina e memorizzati in una struttura rappresentata da una lista di numeri interi ed una stringa che rappresenterà il numero da confrontare. In uscita avrà una risposta di servizio andato a buon fine con un messaggio di Ok o Ko nei casi in cui la somma di due qualsiasi dei numeri dell´array sia uguale al numero da confrontare.
Il servizio ReversePhase eseguirà un operazione di Get, in ingresso una stringa con la frase da rovesciare ed in uscita 
una stringa con la frase rovesciata. In testa ai servizi è stato abilitato il CORS, abilitare il CORS significa abilitare il browser su quel server (in questo caso abilitare il server dotnet in locale sulla porta 5000) a ricevere chiamate da altri server. Come vedremo più avanti le chiamate ai nostri servizi verranno effettuate da altri server attivi su altre porte, per dotnet sono server esterni e quindi devono essere abilitati. In casi reali e non cosi semplici per accedere ai servizi servirebbe un´abilitazione.

CREAZIONE FRONT END
creeremo tre applicativi di front-end con tre linguaggi e tecnologie diverse, front-end con react, angular e Blazor.
Tutte le tecnologie hanno una parte di gestione comune. Tutte sono basate sulla creazione di componenti
che possono reinderizzati all´ interno del codice html. 

Creazione front-end con React
React è stato creato da Facebook e sono un´insieme di librerie javascript che ci permettono tramite linguaggio 
javascript di creare interfacce di front-end molto ´reattive´ per quanto riguarda il cambiamento degli stati degli oggetti 
all´interno di una pagina internet, o nei suoi segmenti. Per questa peculiarità nelle applicazioni SPA (single page application) o in applicativi con 2 o 3 livelli di pagine risulta la scelta di front-end più performante e con massima ottimizzazione del codice.Per creare front-end con React però si deve avere un´ottima conoscenza del linguaggio javascript, react è controindicato per la crezione di applicativi complessi multipagina e che hanno una forte interazione
con i dati in special modo con applicativi gestionali con molte operazioni di tipo CRUD.
React funziona sotto ambiente nodejs quindi la prima cosa da fare per la creazione del nostro front-end sarà
installare nodejs sul nostro pc, possiamo fare il download di nodejs da questo link: https://nodejs.org/it/download/
in seconda battuta dovremmo installare yarn il package manager di facebook un po´ più completo rispetto a quello standard installato con nodejs cioè npm. Aprire VS Code, aprire una finestra terminal e scrivere il seguente command per installare yarn: npm install --global yarn.
nella cartella c:\test eseguiremo il comando che ci permetterà di creare nella cartella test_fe_react l´applicativo base scheletro da template in react per poter risolvere il nostro front-end: npx create-react-app testfereact
eseguiamo il server node e lanciamo la nostra applicazione con il comando yarn start
Per il nostro esempio dovremo installare una libreria javascript denominata axios che ci permetterà
di inserire gli oggetti necessari per eseguire chiamate Rest verso un servizio.
Per far ciò da terminal dobbiamo eseguire il seguente command:npm install react-axios
Creare sotto la cartella src il file CheckSum.js con all´interno il seguente codice:

import React, { Component } from ´react´;
import axios from ´axios´;

class CheckSum extends Component {
   constructor(props){
     super(props);
     this.state = {
        numbertocheck´´,
        numbertoreport ´´,
    }
  }

  handleChange = event => {
    this.setState({ numbertocheckevent.target.value });
  }

  handleSubmit = event => {
    event.preventDefault();
    const sumNumbers = [156, -127];
    const url = "http://localhost:5000/CheckSum/";
   
axios({
    method´post´,
    urlurl,
    headers: {},    
    data: {
      numberssumNumbers,
      numberthis.state.numbertocheck, // This is the body part
    }
  }).then(res => {
    const warning=res.data;
    this.setState({ numbertoreportwarning});
  })   

}
  render() {
    return (
      <div>
        <hr />  
        <label>Exercize 2</label> 
        <br />    
        <label>
          Numbers list:
        </label>
        <p><input type="text" id="n1" name="n1" value="15"/></p>
        <p><input type="text" id="n2" name="n2" value="6"/></p>
        <p><input type="text" id="n3" name="n3" value="-1"/></p>
        <p><input type="text" id="n4" name="n4" value="2"/></p>
        <p><input type="text" id="n5" name="n5" value="7"/></p>
      <form onSubmit={this.handleSubmit}>
        <label>
          Check sum:
          <input type="text" name="numbertocheck" onChange={this.handleChange} />
        </label>
        <button type="submit">Add</button>
      </form>
      <p>{this.state.numbertoreport}</p>
    </div>
    );
  }
}

export default CheckSum;

Creare sotto la cartella src il file ReversePhrase.js con all´interno il seguente codice:

import React, { Component } from ´react´;
import axios from ´axios´;

// FE Reverse phrase
class ReversePhrase extends Component {
   constructor(props){
     super(props);
     this.state = {
      reversephase´´,
    }
  }

  handleChange = event => {
    this.setState({ nameevent.target.value });
  }

  handleSubmit = event => {
    event.preventDefault();    
    const url = "http://localhost:5000/ReversePhrase/" + this.state.name;

    axios.get(url)
      .then(res => {
        console.log(res.data);
        this.setState({ reversephaseres.data });
      })
      
  }
  render() {
    return (
      <div>
      <form onSubmit={this.handleSubmit}>
      <label>Exercise 1</label>
      <br />
        <label>
          Reverse phrase:
          <input type="text" name="phrase" onChange={this.handleChange} />
        </label>
        <button type="submit">Add</button>
      </form>
      <p>{this.state.reversephase}</p>
    </div>
    );
  }
}

export default ReversePhrase;

Cancellare il contenuto del file app.js ed inserire il codice sottostante:

import ´./App.css´;
import ReversePhrase from ´./ReversePhrase´;
import CheckSum from ´./CheckSum´;

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <ReversePhrase></ReversePhrase>
        <CheckSum></CheckSum>
        </header>
    </div>   
  );
}

export default App;


Inizializzare il front-end con il command: yarn start, si aprirà il browser sul seguente link:
localhost:3000  .A questo punto aprire il backend ed inizializzarlo aprendo VS Code con il codice del back-end ed il comando dotnet run.
A questo punto il front-end react è pronto per funzionare. Facendo il punto tecnico in evidenza è la semplicità sia della struttura sia della scrittura dell´implementazione del codice che risulta semplice veloce ed intuitivo.
I componenti che è possibile richiamare ed inserire nel listato html non sono altro che classi javascript definite all´interno di file. Il codice sorgente risulta stringato e pulito.
Il primo componente React è sempre app.js, all´ interno abbiamo inserito i componenti che abbiamo
importato con la definizione di import dei loro file. Nel caso di costruzioni di applicativi complessi con React ci si aiuta con template già preimpostati (ad esempio boilerplate) che ci aiutano nell´elaborazione dell´intelaiatura della struttura.

Creazione front-end con Angular
Per la creazione del front-end in Angular, quindi in linguaggio Typescript (linguaggio che viene tradotto poi in javascript) dobbiamo sempre aprire una finestra terminal con VS Code e posizionandoci nella cartella c:\test digitare i seguenti comandi:
npm install -g @angular/cli  per installare Angular
ng new testfeangular per creare da template una nuova applicazione Angular
A questo punto apriamo VS Code nella cartella c:\test\test_fe_angular ed lanciamo il server nodejs con la nostra applicazione tramite il command ng serve
Richiamando il browser all´ indirizzo http://localhost:4200 potremo vedere la nostra applicazione template.
Ora dobbiamo creare i nostri due componenti, checksum e reversephrase coi i comandi:
ng generate component checksum
ng generate component reversephrase
Il sistema mi creerà due cartelle checksum e reversephrase in cui sono contenuti gli scheletri dei componenti.
Apriamo il file  checksum.ts, cancelliamo il contenuto ed inseriamo il codice sottostante:

import { ComponentOnInit } from ´@angular/core´;
import { HttpClient } from ´@angular/common/http´;
import { Injectable } from ´@angular/core´;
import { Observable } from "rxjs";

@Component({
  selector: ´checksum´,
  templateUrl: ´./checksum.component.html´,
  styleUrls: [´./checksum.component.css´]
})

@Injectable()
export class CheckSumComponent implements OnInit {
  resp:any;
  
  constructor(private httpHttpClient) { 
  }

  ngOnInit(): void {
  }

  getAll(number:string): Observable<any>
  {     
      let inputvaluesParSearch = { Numbers: [157, -142], Number:number };    
      this.http.post<string>(´http://localhost:5000/CheckSum´inputvalues, {responseType: ´text´ as ´json´ })
     .subscribe(data => {this.resp = data;})  
      console.log(this.resp);
      return this.resp;  
  }

}

interface ParSearch {
  Numbers: Array<number>;
  Number: string;
}


Apriamo il file  checksum.html, cancelliamo il contenuto ed inseriamo il codice sottostante:

<div>
    <hr />  
    <label>Exercize 2</label> 
    <br />    
    <label>
      Numbers list:
    </label>
    <p><input type="text" id="n1" name="n1" value="15"/></p>
    <p><input type="text" id="n2" name="n2" value="6"/></p>
    <p><input type="text" id="n3" name="n3" value="-1"/></p>
    <p><input type="text" id="n4" name="n4" value="2"/></p>
    <p><input type="text" id="n5" name="n5" value="7"/></p>
    <div>
      <label for="new-hero">Number to check: </label>
      <input type="text" id="new-hero" #numberName />
      <button class="add-button" (click)="getAll(numberName.value);">
        Add
      </button>
      <p>{{resp}}</p>
      </div>
    </div>


Apriamo il file  reversephrase.ts, cancelliamo il contenuto ed inseriamo il codice sottostante:

import { ComponentOnInit } from ´@angular/core´;
import { HttpClient } from ´@angular/common/http´;
import { Injectable } from ´@angular/core´;
import { Observable } from "rxjs";

@Component({
  selector: ´reversephrase´,
  templateUrl: ´./reversephrase.component.html´,
  styleUrls: [´./reversephrase.component.css´]
})

@Injectable()
export class ReversePhraseComponent implements OnInit {
  resp:any;
  constructor(private httpHttpClient) { }

  ngOnInit(): void {
  }

  getAll(phrasetoreverse:string): Observable<any>
  {     
      this.http.get<string>(´http://localhost:5000/ReversePhrase/´ + phrasetoreverse, {responseType: ´text´ as ´json´ } )
     .subscribe(data => {this.resp = data;})  
      console.log(this.resp);
      return this.resp;  
  }


}


Apriamo il file  reversephrase.component.html, cancelliamo il contenuto ed inseriamo il codice sottostante:

<div>
    <hr />  
    <label>Exercize 1</label> 
    <br />    
    <div>
      <label>Insert phrase to reverse: </label>
      <input type="text" id="inputPhrase" #inputPhrase />
      <button class="add-button" (click)="getAll(inputPhrase.value);">
        Add
      </button>
      <p>{{resp}}</p>
      </div>
    </div>



Apriamo il file  app.module.ts, cancelliamo il contenuto ed inseriamo il codice sottostante:

import { NgModule } from ´@angular/core´;
import { BrowserModule } from ´@angular/platform-browser´;
import { HttpClientModule } from ´@angular/common/http´;
import { AppRoutingModule } from ´./app-routing.module´;
import { AppComponent } from ´./app.component´;
import { CheckSumComponent } from ´./checksum/checksum.component´;
import { ReversePhraseComponent } from ´./reversephrase/reversephrase.component´;
@NgModule({
  declarations: [
    AppComponent,
    CheckSumComponent,
    ReversePhraseComponent,
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }


Apriamo il file  app.component.html, cancelliamo il contenuto ed inseriamo il codice sottostante:


<div role="main">
  <reversephrase></reversephrase>
  <checksum></checksum>
</div>
<router-outlet></router-outlet>


eseguire il server nodes con angular con il comando ng serve e vedere il risultato del nostro lavoro.
richiamare il back end ed eseguirlo per poter testare il nostro front-end.
Nel caso di Angular rispetto a React ho voluto mettere in evidenza la creazione di interfacce dati
che ho utilizzato per dare in pasto al servizio del back-end, peculiarità del linguaggio Typescript che in questo caso si comporta come un linguaggio ad alto livello e quindi più strutturato rispetto a javascript.
Come con React anche qui abbiamo un architettura a componenti che possiamo richiamare all´ interno dell´ html.

Creazione Front-end con Blazor
Blazor è la nuova architettura di sviluppo front-end di Microsoft. E´ una tecnologia molto recente ed è derivata dalla precedente architettura MVC fatta da pagine Razor. Blazor si contraddistingue per essere un architettura a componenti che possono essere inseriti all´ interno del codice html come tag ne più ne meno come React e Angular con la differenza che si interfaccia con il linguaggio C#, linguaggio di alto livello.
Apriamo VS Code e posizionamoci nella cartella c:\test, apriamo una sessione terminal e scriviamo il seguente
comando:dotnet new blazorwasm -o testfeblazor.
Dotnet creerà il progetto scheletro da template con all´ interno una struttura di esempio già funzionante.
eseguire il comando dotnet run per eseguire l´applicazione di front-end, aprire il browser all´ indirizzo localhost:5000 per vedere l´applicazione.
Posizionarsi sulla cartella Pages del progetto e creare un nuovo file chiamato CheckSum.razor ed un file 
ReversePhrase.razor ed inserire rispettivamente le seguenti righe di codice:

@page "/checksum"
@using System.Net.Http
@inject HttpClient Http

<h1>Check Sum</h1>
<div>
    <hr />
    <label>Exercise 2</label>
    <br />
    <label>
        Numbers list:
    </label>
    <p><input type="text" id="n1" name="n1" value="15" /></p>
    <p><input type="text" id="n2" name="n2" value="6" /></p>
    <p><input type="text" id="n3" name="n3" value="-1" /></p>
    <p><input type="text" id="n4" name="n4" value="2" /></p>
    <p><input type="text" id="n5" name="n5" value="7" /></p>
    <form>
        <label>
            Check sum:
            <input type="text" @oninput="NumberToCheck" />

        </label>
        <button type="button" @onclick=@(args => OnInitializedAsync())>Add</button>
    </form>
    @if (@OKKO != "")
    {
        <label>The sum numbers is: @OKKO</label>
    }
    <p></p>
</div>

@code {

    public string CheckNumber { getset; }
    public string OKKO = "";

    private void NumberToCheck(ChangeEventArgs e)
    {
        CheckNumber = e.Value.ToString();
    }


    protected override async Task OnInitializedAsync()
    {
        List<intNumbersToCheck = new List<int>();
        NumbersToCheck.Add(15);
        NumbersToCheck.Add(6);
        NumbersToCheck.Add(-1);
        NumbersToCheck.Add(2);
        NumbersToCheck.Add(7);

        var addItem = new { Numbers = NumbersToCheckNumber = CheckNumber };
        var response = await Http.PostAsJsonAsync("http://localhost:5000/CheckSum"addItem);

        string data = await response.Content.ReadAsStringAsync();
        string result = data.ToString();
        if (result == "OK" || result == "KO")
            OKKO = result;
        else
            OKKO = string.Empty;

@page "/reversephrase"
@using System.Net.Http
@inject HttpClient Http

<h1>Reverse Phrase</h1>

<div>
    <hr />
    <label>Exercise 1</label>
    <br />

    <form>
        <label>
            Insert phrase:
            <input type="text" @oninput="PhraseToReverse" />

        </label>
        <button type="button" @onclick=@(args => OnInitializedAsync())>Add</button>
    </form>

    <label>Reverse phrase is: @OKKO</label>

    <p></p>
</div>


@code {
    public string CheckPhrase { getset; }
    public string OKKO = "";

    private void PhraseToReverse(ChangeEventArgs e)
    {
        CheckPhrase = e.Value.ToString();
    }

    protected override async Task OnInitializedAsync()
    {
        if (CheckPhrase == string.Empty || CheckPhrase==null)
            return;

        var response = await Http.GetStringAsync("http://localhost:5000/ReversePhrase/" + CheckPhrase);

        string result = response.ToString();

        OKKO = result;

    }

}


Nella cartella Shared cancellare il contenuto del file NavMenu ed inserire il codice sotto riportato:

<div class="top-row pl-4 navbar navbar-dark">
    <a class="navbar-brand" href="">testfeblazor</a>
    <button class="navbar-toggler" @onclick="ToggleNavMenu">
        <span class="navbar-toggler-icon"></span>
    </button>
</div>

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
    <ul class="nav flex-column">
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="reversephrase">
                <span class="oi oi-plus" aria-hidden="true"></span> Reverse phrase
            </NavLink>
        </li>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="checksum">
                <span class="oi oi-list-rich" aria-hidden="true"></span> Check Sum
            </NavLink>
        </li>
    </ul>
</div>

@code {
    private bool collapseNavMenu = true;

    private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;

    private void ToggleNavMenu()
    {
        collapseNavMenu = !collapseNavMenu;
    }
}


Nella cartella Properties modificare il file lauchSettings.json nella riga del setting ´applicationUrl´
ed inserire la seguente stringa:

 "applicationUrl": "http://localhost:5200",

questo per cambiare porta del front-end sulla porta 5200 che altrimenti andrebbe in conflitto con la porta 5000 
del back-end.
eseguire il front-end con il comando dotnet run ed il back-end con lo stesso comando e testare l´applicativo.
Nell´ esempio il componente razor viene richiamato come pagina, ma lo stesso è possibile inserirlo all´ interno
di html come tag. Il componente razor è simile al componente React solo che il linguaggio di riferimento è C#.

CONCLUSIONI
Cosa sceglierei per il back-end
per quanto riguarda la tecnologia di back-end mi sento di dire che in questo momento se dovessi iniziare un progetto nuovo userei sicuramente dotnet di Microsoft. In questi ultimi due anni è diventata una tecnologia matura stabile e completa, fino ad un paio di anni fa avrei sicuramente scelto l´architettura a servizi Java, ma dopo ormai tre anni in cui ho utilizzato dotnet in maniera intensiva su vari sistemi operativi e con progetti di vario tipo ho testato che è una 
tecnologia ormai rodata e da preferire rispetto a java. Nodejs lato server invece secondo il mio parere in questo momento non è cosi´ stabile e completa come dotnet, inoltre,per esperienza personale il server nodejs in alcuni casi oltre a non rilevarsi stabile mi sembra che utilizzi più risorse e mi sembra meno ottimizzato rispetto a dotnet. Spesso si sviluppa software che viene installato su hardware poco performante e quindi la scelta del motore di back-end più performante diviene una scelta primaria.

Cosa sceglierei per il front-end
Per quanto riguarda la tecnologia di front-end nel caso si dovesse sviluppare un´applicazione di tipo SPA (come ad esempio tipo facebook, twitter ecc.....o qualcosa di simile) senza ombra di dubbio React è la tecnologia migliore per la sua ottima e semplice gestione dello stato della pagina.
Se dovessi invece creare un front-end di un applicativo che in parte sia una SPA ma con più livelli di routing di pagina e con forte interazione ai dati, o per un applicativo gestionale web  e che lo sviluppo sia interamente slegato dal back-end allora sceglierei Angular.
Quando utilizzare Blazor? Blazor in realtà si presta ad essere utilizzato più o meno nelle stesse situazioni di Angular. La scelta di Blazor al posto di Angular è sicuramente da preferire nel caso ad esempio di un porting di un applicativo creato in MVC oppure su porting di applicativi con vecchia tecnologia microsoft (ad esempio webform).
Oppure nel caso in cui ci si ritrovi a creare un front-end e nel team di sviluppo non ho sviluppatori con esperienza adeguata con Javascript ma con un ottimo background con il linguaggio C#.
Altro caso potrebbe l´ uniformità della tecnologia di utilizzo, un unico ambiente, un unico linguaggio.
Per vedere le differenze tra Blazor ed Angular e loro utilizzo vi rimando ai bellissimi articoli di Michele Aponte a questo indirizzo https://blexin.com/it/blog/blazor-vs-angular-quale-scegliere-prima-parte/  e https://blexin.com/it/blog/blazor-vs-angular-quale-scegliere-seconda-parte/

A questo punto mi sorge spontanea una domanda: quale database utilizzare per un´applicazione web?
La mia risposta è univoca. 
PostgreSQL come database principale, SqlLite come database di appoggio per i dati di configurazione.
Postgresql oltre ad essere gratuito, performante, stabile e multipiattaforma ed essere supportato da tutte le piattaforme software ha anche delle specifiche tecniche avanzate rispetto ad altri database con le stesse caratteristiche. Un esempio è la gestione del lock dei dati, gestito a livello riga (e non a livello tabella come altri db) ed altre caratteristiche che a mio parere ne fanno attualmente il database migliore per lo sviluppo.

Una copia dei sorgenti del progetto descritto in questo articolo li potete trovare a questo indirizzo:

TEST.ZIP