Visualizzazione post con etichetta Angular 2. Mostra tutti i post
Visualizzazione post con etichetta Angular 2. Mostra tutti i post

mercoledì 4 gennaio 2017

Angular 2 & Reactive Programming

Rx Angular 2
Il mio primo approccio con la Programmazione Reattiva (o meglio FRP - Functional Reactive Programming) risale ormai a metà del 2013 quando, dopo aver letto una serie di articoli che descrivevano il paradigma di programmazione, ho deciso di introdurre un'implementazione di tale tecnica per .NET in una nuova release di un sistema MES (Manufacturing Execution System) che ho progettato ed implementato per l’azienda per cui lavoravo all’epoca. La libreria in questione era denominata Rx - Reactive Extensions.

In parole povere, le diverse implementazioni di Rx, consentono di manipolare flussi di dati e/o eventi (Observable) al fine di semplificare notevolmente lo sviluppo di codice asincrono mediante una sottoscrizione, Subscription, alle variazioni di tali flussi.

Tra i vari benefici che si possono avere con l’adozione di tali tecniche, quella che, a mio parere, è quella di maggior pregio, è data dal fatto che una volta creato uno stream di dati, diversi client possono effettuare una sottoscrizione alle variazioni dello stesso ottenendo, a costo zero, un sistema in grado di comunicare in modo broadcast con diversi client.

Le diverse implementazioni del paradigma, comprendono anche una libreria JavaScript denominata RxJS, e viene installata tra i diversi pacchetti a corredo di Angular 2.
Una delle applicazioni che meglio si prestano all’utilizzo della programmazione reattiva in un’applicazione Angular 2 è data dalla fruizione di un servizio REST.
Nei post precedenti abbiamo creato sia un’applicazione client basata su Angular 2 che una Web API sviluppata con ASP.NET Core, ed entrambe hanno trovato posto su Azure.
Riprendendo il post precedente RESTful API con Swagger, e concentrandoci sul dettaglio della lista dei metodi esposti dal servizio, abbiamo:
REST API
Con questi metodi, possiamo pensare alla realizzazione di un’applicazione CRUD finalizzata alla gestione di una piccola biblioteca personale.
I sorgenti dell’intero progetto sono disponibili per la consultazione su github, ed il risultato finale, è una Web Application di azure raggiungibile all’indirizzo http://talking-things.azurewebsites.net/#/library.
Il modulo principale è dato dal componente library che si presenta come segue:
libary-main
ed la cui implementazione è data da:

import { Component, OnInit, ViewChild } from '@angular/core';
import { Subscription } from 'rxjs/Rx';
import { Router } from '@angular/router';
import { environment } from '../../environments/environment';
import { BookStoreService } from '../bookstore.service';
import { Book } from '../models/book';
import { ModalComponent } from '../modal/modal.component';

@Component({
  selector: 'app-library',
  templateUrl: './library.component.html',
  styleUrls: ['./library.component.css'],
  providers: [BookStoreService]
})
export class LibraryComponent implements OnInit {

  title = 'Book Store';

  books: Book[] = [];

  errorMessage: string = '';
  isLoading: boolean = true;

  @ViewChild(ModalComponent) modal: ModalComponent;

  private subscription: Subscription;
  constructor(private _router: Router, private _bookStoreService: BookStoreService) { }

  ngOnInit() {
    this.reloadData();
  }

  reloadData() {
    this._bookStoreService
      .GetAll()
      .subscribe(
      b => this.books = b,
      e => this.errorMessage = e,
      () => this.isLoading = false);
  }

  onNew() {
    console.log("onNew");
    this._router.navigate(['/edit', 'new']);
  }

  onEdit(book: Book) {
    console.log('edit ' + book.id);
    this._router.navigate(['/edit', book.id]);
  }

  onDelete(book) {

    var message: string = 'Delete \'' + book.title + '\'?: ';
    this.modal.Title = 'Warning';
    this.modal.show(message);
    this.subscription = this.modal.observable.subscribe(x => {

      if (x) {
        this._bookStoreService.Delete(book.id).subscribe(
          book => {
            let b = this.books.find(item => item.id === book.id);
            let id = this.books.indexOf(b);
            this.books.splice(id, 1);
            if (!environment.production)
              console.log(JSON.stringify(book));
          },
          error => {
            console.log(error);
          }
        );
      }

      this.subscription.unsubscribe();
    });
  }
}

e dal servizio BookStoreService, cuore del vero interfacciamento con il servizio REST:

import { Injectable } from '@angular/core';
import { Http, Response, Headers } from '@angular/http';
import { Observable } from 'rxjs/Rx';

import { Book } from './models/book';

import { environment } from '../environments/environment';

@Injectable()
export class BookStoreService {
    private baseUrl: string;

    constructor(private _http: Http) {
        this.baseUrl = environment.bookStoreApi.server + environment.bookStoreApi.apiUrl + '/books/';
    }

    GetAll(): Observable<Book[]> {

        if (!environment.production)
            console.log(this.baseUrl);

        let books$ = this._http.get(this.baseUrl, { headers: this.GetHeaders() })
            .map(mapBooks)
            .catch(handleError);

        return books$;
    }

    public GetById = (id: string): Observable<Book> => {
        let books$ = this._http.get(this.baseUrl + id, { headers: this.GetHeaders() })
            .map(response => response.json())
            .catch(handleError);
        return books$;
    }

    public Create = (book: Book): Observable<any> => {
        let book$ = this._http.post(this.baseUrl, book, { headers: this.GetHeaders() })            
            .catch(handleError);

        return book$;
    }

    public Update = (id: string, book: Book): Observable<any> => {
        let book$ = this._http.put(this.baseUrl + id, book, { headers: this.GetHeaders() })
            .catch(handleError);

        return book$;
    }

    public Delete = (id: string): Observable<Book> => {
        let book$ = this._http.delete(this.baseUrl + id)
            .catch(handleError);

        return book$;
    }

    private GetHeaders() {
        let headers = new Headers();

        headers.append('Accept', 'application/json');

        return headers;
    }
}

function mapBooks(response: Response): Book[] {
    return response.json().map(toBook);
}

function toBook(r: any): Book {
    if (!environment.production)
        console.log('toBook: ' + JSON.stringify(r));

    let book = <Book>({
        id: r.id,
        title: r.title,
        authors: r.authors,
        publicationYear: r.publicationYear,
        isAvailable: r.isAvailable
    });

    if (!environment.production)
        console.log('Parsed book: ', book);

    return book;
}

function handleError(error: Response) {
    return Observable.throw(error || 'Server error');
}

Per avere un’idea di come l’utilizzo della FRP abbia reso più agevole la gestione della programmazione asincrona focalizziamo la nostra attenzione sul metodo GetAll() che ritorna uno stream Observable


    GetAll(): Observable<Book[]> {

        if (!environment.production)
            console.log(this.baseUrl);

        let books$ = this._http.get(this.baseUrl, { headers: this.GetHeaders() })
            .map(mapBooks)
            .catch(handleError);

        return books$;
    }

ed al quale il componente library effettua una sottoscrizione mediante il metodo subscribe:
     this._bookStoreService
      .GetAll()
      .subscribe(
      b => this.books = b,
      e => this.errorMessage = e,
      () => this.isLoading = false);

In modo analogo vengono implementate le interfacce verso gli altri metodi esposti dal servizio REST.
Facile e pulito…

Enjoy


mercoledì 7 dicembre 2016

Integrazione Continua su Azure con git e azure-cli (parte II)


Node.jsMicorsoft AzureAngular 2






Continuiamo la precedente nota su Integrazione Continua su Azure con git e azure-cli, nella quale ho illustrato una possibile procedura per l’implementazione di un ambiente di sviluppo per l’integrazione continua su Microsoft Azure. In quell’occasione il progetto pubblicato implementava sia la gestione del front-end (sviluppato in quell’occasione con un’applicazione Angular 2), che il back-end (implementato con ASP.NET Core) implementata su host IIS.

In questo post concentreremo la nostra attenzione solo sulla pubblicazione di una Web App Angular 2 implementata con Node.js. A tal fine ci avvarremo di angular-cli, un set di strumenti in linea di comando per lo sviluppo di un'app Angular 2.

angular-cli

Creazione della Web App

Seguendo le istruzioni riportate dal sito creiamo una Web App Angular 2 con angular-cli.
  1. In primo luogo installiamo sul nostro sistema angular-cli:
  2. $ npm install -g angular-cli
  3. Quindi creiamo la nostra Web App:
  4. $ ng new my-a2-app
  5. Personalizziamone il contenuto, modificando:
    • il file app.component.ts
  6. import { Component } from '@angular/core';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      title = 'my angular 2 app!';
      sign = 'Maurizio Attanasi';
      year = '2016';
    }
    • il file app.component.html
  7. Avviamo il server in locale con il comando
  8. $ ng serve
    ng-serve-terminal
    localhost-run.
  9. Aggiungiamo nella directory root del progetto il file .deployment che configurerà la directory di avvio del progetto, e contenente le righ che seguono:
[config]
project = dist

Preparazione e pubblicazione della Web App su azure

  1. Utilizzando le funzionalità di azure-cli viste nel post precedente, creiamo la Web App
  2. $ azure site create my-a2-app --git --gitusername ***
  3. Aggiorniamo le modifiche del repository locale, eseguiamo il commit ed infine eseguiamo il push verso il repository remoto di azure
$ git add .
$ git commit -m "Initial commit"
$ git push azure master
Se la è andata a buon fine, la nostra shell di comando sarà simile a quella seguente
azure-deployment-terminal
Ulteriore conferma dell’avvenuta pubblicazione possiamo averla navigando il portale di azure al percoso my-a2-app > Deployment options
azure-deployment-options
Ed infine, raggiungendo l’indirizzo http://my-a2-app.azurewebsites.net/
azure-run
Enjoy


lunedì 28 novembre 2016

Integrazione Continua su Azure con git e azure-cli

In un precedente post (Integrazione Continua con Visual Studio Team Service) avevo condiviso il link ad un tutorial che illustrava il servizio di Continuous Integration offerto da Visual Studio Team Services. In questa nota riporterò gli step necessari ad ottenere un risultato analogo
per la pubblicazione su una Web Application su Azure sfruttando git come sistema di versioning, e azure-cli, un’interfaccia della riga di comando di Azure.
Gli strumenti necessari per raggiungere il nostro fine sono:
  • node.js (del quale utilizzeremo il gestore dei pacchetti, npm, per l’installazione, tra l’altro, di angular-cli);
  • git;
  • azure-cli;
  • un account Azure valido (anche un free trial);
Data la natura degli strumenti sopra elencati, la procedura che andremo a descrivere vale per tutti i sistemi operativi per i quali tali strumenti sono disponibili, e quindi Windows, Linux e osX/macOS.
In primo luogo verifichiamo che sul sistema sia installato Node.js eseguendo su una shell di comando
bash-3.2$ node --version
v7.2.0
Nel caso in cui Node.js non sia presente sul sistema procederemo alla sua installazione seguendo le istruzioni presenti sul sito.
Allo stesso modo verifichiamo la presenza sul nostro sistema di git
bash-3.2$ git --version
git version 2.9.3 (Apple Git-75)
e azure-cli
bash-3.2$ azure --version
0.10.7 (node: 7.2.0)
Nel caso in cui questo pacchetto non sia presente sul sistema, utilizzeremo npm per la sua installazione
npm install -g azure-cli
Preparati gli strumenti necessari, procediamo alla realizzazione di una Web Application ed alla sua pubblicazione su Azure.
  1. Login
    Per eseguire il login dalla linea di comando di azure, eseguiamo:
$ azure login
e seguiamo le istruzioni riportate nella risposta
azure login
2. Impostazione Gestione servizi di Azure (asm)
Per abilitare i comandi della modalità Service Management dell’interfaccia della riga di comando di Azure, eseguire il comando.
bash-3.2$ azure config mode asm
  1. Impostazione dell’utente per la pubblicazione
    Per impostare nome utente e password per la pubblicazione della Web Application, eseguire il comando:
azure site deployment user set --username <username> --pass <password>

Creazione della Web Application

Tra le varie possibilità disponibili, (html, asp.net, Node.js, …), realizzeremo una Web Application faremo con l’ultima nata delle tecnologie ASP.NET:
ASP.NET Core.
Verifichiamo la presenza dell’sdk sul nostro sistema con il comando
bash-3.2$ dotnet --version
1.0.0-preview2-1-003177
Nel caso in cui .net non sia presente, seguiamo le istruzioni
relative al sistema operativo di nostro interesse.

Yeoman

Per semplificare l’implementazione della web app utilizzeremo Yeoman, il set di strumenti per la creazione di progetti web già visto in un precedente post.
In primo luogo procederemo all’installazione del generator necessario alla realizzazione di un progetto .net Core con il comando
$ sudo npm install -g generator-aspnet
Procediamo quindi alla creazione del nostro progetto creando la seguente gerarchia di directories:
$ mkdir CloudWorkbenchWebApplication
$ mkdir CloudWorkbenchWebApplication/src
$ mkdir CloudWorkbenchWebApplication/test
$ cd CloudWorkbenchWebApplication/
Nella cartella root del nostro progetto, creiamo il file global.json
che conterrà il seguente oggetto json
{
  "projects": [ "src", "test" ],
  "sdk": {
    "version": "1.0.0-preview2-1-003177"
  }
}
Spostandoci nella cartella src, eseguiamo il comando
$ yo aspnet
in risposta al quale verrà avviata una procedura guidata per la creazione del nostro progetto
yo aspnet
Selezionando la voce Empty Web Application, e, in seguito assegnando il nome CloudWorkbenchWebApplication,
verrà creata l’infrastruttura di una semplice Web Application ASP.NET Core.
Spostandoci nella cartella appena creata (CloudWorkbenchWebApplication), eseguiamo in sequenza i comandi
dotnet restore
dotnet run
dotnet run
In questo modo abbiamo avviato, sulla nostra macchina un Web Server che risponderà all’indirizzo riportato (nel nostro caso http://localhost:5000/).
Avviando un browser e puntando all’indirizzo di cui sopra avremo:
Local Run
Et voilà, abbiamo la nostra Web Application!

Creazione del repository git

Tornando nella directory root del nostro progetto (quella contenente la cartelle src e test ed il file global.json),
1. creiamo il repository git
$ git init
  1. aggiungiamo tutti i files e le cartelle create
$ git add .
  1. eseguiamo il primo commit
$ git commit -m "Initial commit"

Creazione della Web Application su Azure

Mediante la linea di comando di azure, creiamo la nostra web application
 azure site create <app_name> --git --gitusername <username>
dove app_name è il nome che assegneremo alla web application, e username è il nome utente impostato nel passaggio precedente.
site creation
Selezioniamo il server sul quale pubblicheremo la nostra applicazione (nel nostro caso 3. West Europe).
Al termine dell’operazione, accedendo al portale di Azure, avremo, tra le risorse disponibili, quella appena creata
azure portal
Visualizzando i dettagli della nostra App, abbiamo
azure site detail
e, selezionando il pulsante Browse siamo in grado di visualizzare la web app appena creata (anche se vuota).
site-browse

Pubblicazione della web application

Siamo pronti per eseguire il primo push verso il repository azure creato in precedenza.
A tal fine eseguiamo il comando
$ git push azure master
Oltre che copiare i file dal nostro repository locale al site di azure, il processo avvierà le operazioni di restore e build dell’applicazione, ed infine alla pubblicazione dell’app.
Se l’operazione è andata a buon fine, ricaricando il browser all’indirizzo precedente, abbiamo:
published-site
Et voilà ancora!!! Abbiamo ottenuto il risultato voluto, ovvero siamo riusciti a pubblicare la nostra web application raggiungibile all'indirizzo http://cloud-workbench.azurewebsites.net/ utilizzando git e la linea di comando di azure.

Configurazione versione di Node.js

Poiché la web application che abbiamo appena creato sarà il punto di partenza per una serie prove per verificare le potenzialità di Azure per le applicazioni IoT, per provare Angular 2 in combinazione con .net core, ed altro ancora, facciamo un ulteriore passaggio per aggiornare la versione di Node.js di della nostra app azure con quella installata sul nostro sistema di sviluppo (la 7.2.0, come abbiamo visto all’inizio del post).
Tra gli Application Settings della nostra Web App individuiamo la chiave WEBSITE_NODE_DEFAULT_VERSION e modifichiamone il valore a 7.2.0, come illustrato nell’immagine seguente.
application-settings.
Salvando le modifiche effettuate il sito verrà riavviato e, se non ci sono problemi, ricaricando la pagina otterremo ancora il nostro Hello World.

Enjoy