Dicembre 2015

Volume 30 numero 13

Il presente articolo è stato tradotto automaticamente.

Punti dati - Aurelia e DocumentDB: storia di un incontro - Parte 2

Da Julie Lerman

Julie LermanIl nuovo framework JavaScript, Aurelia e il database servizio di documenti NoSQL Azure DocumentDB, sono due diverse tecnologie che hanno acquisito ultimamente mio interesse. Nel mese di giugno, esplorato DocumentDB a livello generale (msdn.com/magazine/mt147238). Quindi, nel mese di settembre, mi è sembrata data binding in Aurelia (msdn.com/magazine/mt422580). Che comunque da entrambe le tecnologie, credevo che si desidera combinare i due elementi, utilizzando Aurelia come front-end di un'applicazione e DocumentDB come archivio dati. Mentre la curiosità offre alcuni vantaggi (persistenza), la mia esperienza limitata con queste due nuove tecnologie e i framework JavaScript impostate in generale, mi lungo un numero di tentativi cieco combinarle. Questo era aggravato dal fatto che nessuno aveva fatto questo combinata prima, almeno non pubblicamente. Questi tentativi non riusciti sono stati documentati nel mio articolo di novembre (msdn.com/magazine/mt620011), la prima di questa serie in due parti. Un percorso semplice e ovvio che si è scelto di ignorare consiste nell'utilizzare l'API Web esistente che incapsulati l'interazione con DocumentDB anziché l'API Web lavorato nel mio primo articolo Aurelia. Dopo aver apportato questa scelta perché si è verificato alcun problema in essa contenuti e pertanto non molto divertente.

Infine ho trovato per la decisione di utilizzare una diversa soluzione sul lato server: Node. js. Ecco un esempio esistente che utilizza il SDK di Node. js di DocumentDB e un front-end diversi. Controllato attentamente e condiviso ciò che appreso con l'utente nella seconda metà del mio articolo di novembre. Quindi imposto sulla ricostruzione esempio esperto dalla colonna settembre, ma questa volta con Node. js come my intermediario da Aurelia front-end per DocumentDB. Sono molti i blocchi ostacolo sul piano e stavano molto oltre i problemi relativi ai dati. Avevo carichi del supporto dai membri del gruppo di base Aurelia e soprattutto da Patrick Walters (github.com/pwkad), che ha contribuito non solo verificare era che sfruttano le funzionalità di Aurelia, ma anche indirettamente imposti me ono ulteriore delle competenze personali Git. Mi concentrerò su qui sono le parti della soluzione che comportano l'accesso, l'aggiornamento e l'associazione dei dati. Il file Leggimi fornito con l'esempio scaricabile associato viene illustrato come è possibile configurare il proprio DocumentDB e importare i dati per questa soluzione. Viene inoltre spiegato come configurare i requisiti per eseguire l'esempio.

Architettura della soluzione

In primo luogo, diamo un'occhiata l'architettura complessiva della soluzione, come illustrato nella Figura 1.

La struttura complessiva della soluzione
Figura 1, la struttura complessiva della soluzione

Aurelia è un framework lato client è solo per gestire requisiti lato client, ad esempio il rendering HTML in base alla vista e associazioni a modello di visualizzazione, nonché routing, l'associazione dati e altre attività pertinenti. Si noti che tutto il codice sul lato client può eseguire il debug negli strumenti di sviluppo disponibili nel browser come Internet Explorer e Chrome. Nel percorso della soluzione, tutto il codice sul lato client è la cartella pubblica/app/src, mentre il codice lato server si trova nella cartella radice. Quando il sito Web è in esecuzione, i file sul lato client sono Aurelia per garantire la compatibilità browser siano compilati e distribuiti in una cartella denominata "dist." Questi file sono ciò che viene inviati al client.

Il codice lato server dovrebbe essere familiare se avete lo sviluppo Web in Microsoft .NET Framework (in background più vicino al personale). Nell'ambiente .NET, il codebehind da Web Form, i controller e altra logica tradizionalmente viene compilato in DLL che risiedono sul server. Naturalmente, la maggior parte di questo cambia con ASP.NET 5 (che ora l'aspetto più preparati, grazie a lavora su questo particolare progetto). Il mio progetto Aurelia contiene anche codice lato server, ma anche questo è il codice JavaScript tramite Node. js. Questo codice non compilato in una DLL, ma rimane nella propria singoli file. Più importante, non ottenere propagato al client e pertanto viene esposto non facilmente (si tratta, ovviamente, sempre abbastanza dipende misure di sicurezza). Come descritto ora dell'ultima, il motivo Guida per il codice che rimane sul server è la necessità di archiviare le credenziali per l'interazione con DocumentDB. Poiché desidera provare a utilizzare il percorso di Node. js, il SDK menzionato apportate una conversazione con DocumentDB molto più semplice. È stato l'esempio DocumentDB nodo originale affidarsi per alcune nozioni di base su come usare il SDK è di grande aiuto.

Il codice lato server (che farà riferimento a come la mia API) è costituito da quattro componenti principali:

  • Un file api.js che funge da router per garantire il funzioni API facilmente reperibili.
  • Il modulo di base, ninjas.js, contenenti le funzioni API: getNinjas, getNinja e updateDetails.
  • Una classe controller, DocDbDao (chiamato da tali funzioni API) che esegue l'interazione con DocumentDb.
  • Esiste un file di utilità di DocumentDb in grado di verificare il database pertinente e raccolta.

Collegamento dei Client, Server e Cloud

Nel mio esempio Aurelia precedenti, il metodo per ottenere tutti ninjas effettuata una chiamata HTTP diretta a un'API Web ASP.NET che utilizzato Entity Framework e .NET per interagire con un database di SQL Server:

retrieveNinjas() {
  return this.http.createRequest
    ("/ninjas/?page=" + this.currentPage + "&pageSize=100&query=" +
      this.searchEntry)
      .asGet().send().then(response => {
        this.ninjas = response.content;
    });
  }

I risultati sono stati passati a un'associazione della visualizzazione sul lato client e modello di visualizzazione (ninjaList.js e ninjaList.html) che restituisce la pagina visualizzata nel Figura 2.

L'elenco di database del sito Web Aurelia
Figura 2 l'elenco di database del sito Web Aurelia

Nella nuova soluzione, questo metodo, rinominato in getNinjas, a questo punto chiama l'API Node. js sul lato server. Utilizzo di httpClient.fetch più avanzati (bit.ly/1M8EmnY) anziché httpClient questa volta per l'esecuzione della chiamata:

getNinjas(params){
  return this.httpClient.fetch(`/ninjas?q=${params}`)
    .then(response => response.json())
    .then(ninjas => this.ninjas = ninjas);
}

Ho ho configurato httpClient altrove per conoscere l'URL di base.

Si noti che il metodo di recupero è la chiamata a un URI che include il ninjas termine. Ma questo non fa riferimento a mio ninjas.js nell'API sul lato server. La causa potrebbe essere /foo, semplicemente un riferimento casuale che verrà risolto dal router sul lato server. Router sul lato server, che utilizza Express, non Aurelia, poiché Aurelia gestisce solo sul lato client, specifica che le chiamate di api/ninjas indirizzato alla funzione getNinjas del modulo ninjas. Ecco il codice da api.js in cui è definito:

router.get('/api/ninjas', function (request, response) {
  ninjas.getNinjas(req, res);
});

A questo punto la funzione getNinjas (Figura 3) Usa stringa di interpolazione (mzl.la/1fhuSIg) per creare una stringa per rappresentare il SQL per l'esecuzione di query DocumentDB, quindi chiede al controller per eseguire la query e restituire i risultati. Se è stato richiesto un filtro sulla proprietà nome nell'interfaccia utente, aggiungerà una clausola WHERE alla query. La query principale proietta solo le proprietà rilevanti che ho bisogno della pagina, incluso l'ID. (Vedere informazioni sulle query di proiezione DocumentDB in documentdb.com/sql/demo.) La query viene passata al metodo find del controller di docDbDao. Il metodo find, che rimane invariato rispetto all'originale che descritto nella prima parte di questa serie, utilizza il SDK di Node. js con le credenziali archiviate in config. js per eseguire query sul database per il ninjas. getNinjas quindi utilizza tali risultati e li restituisce al client che li ha richiesto. Si noti che anche se la chiamata a DocumentDB di restituire i risultati in formato JSON, è comunque necessario utilizzare in modo esplicito la funzione response.json per passare nuovamente i risultati. In questo modo il chiamante che i risultati sono in formato JSON.

Figura 3, la funzione getNinjas in ninjas.js modulo sul lato Server

getNinjas: function (request, response) {
  var self = this;
  var q = '';
  if (request.query.q != "undefined" && req.query.q > "") {
    q= `WHERE CONTAINS(ninja.Name,'${req.query.q}')`;
  }
  var querySpec = {
    query:
   `SELECT ninja.id, ninja.Name,ninja.ServedInOniwaban,
     ninja.DateOfBirth FROM ninja ${q}`
  };
  self.docDbDao.find(querySpec, function (err, items) {
    if (err) {
      // TODO: err handling
    } else {
      response.json(items);
    }
  })
},

Risposta sul lato client a una richiesta di modifica

Come si può vedere nella Figura 2, quindi è possibile modificare un database facendo clic sull'icona a forma di matita. Di seguito è riportato un collegamento che arricchiscono nel markup della pagina:

<a href="#/ninjas/${ninja.id}" class=
  "btn btn-default btn-sm">
  <span class="glyphicon glyphicon-pencil" />
</a>

Facendo clic sull'icona di modifica per la prima riga, il cui ID è "1", viene visualizzato questo URL:

http://localhost:9000/app/#/ninjas/1

Utilizza la funzionalità di routing Aurelia sul lato client in App. js, è stato specificato che quando viene richiesto questo modello di URL, deve quindi chiamare il modulo di modifica e passare l'id per il metodo activate del modello di visualizzazione modifica come un parametro, indicato per il carattere jolly (* Id):

{ route: 'ninjas/*Id', moduleId: 'edit', title:'Edit Ninja' },

Modifica fa riferimento al modulo che viene associato con la visualizzazione edit.html edit.js sul lato client. La funzione di attivazione del mio modulo modifica quindi chiama un'altra funzione in questo modulo denominato retrieveNinja, passando l'Id richiesta:

retrieveNinja(id) {
  return this.httpClient.fetch(`/ninjas/${id}`)
    .then(response => response.json())
    .then(ninja => this.ninja = ninja);
}

Passare la richiesta di modifica all'API sul lato Server

Anche in questo caso si utilizzi httpClient.fetch per richiedere api/ninjas / [id] (nel mio caso api/ninjas/1) dell'API. Il router sul lato server afferma che, quando viene ricevuta una richiesta con questo modello, deve indirizzare alla funzione getNinja del modulo ninjas. Ecco il routing di un aspetto analogo al seguente:

router.get('/api/ninjas/:id', function(request, response) {
  ninjas.getNinja(request, response);
});

Il metodo getNinja quindi effettua un'altra richiesta al controller di docDbDao, questa volta per la funzione getItem, per ottenere i dati di database da DocumentDb. I risultati sono documenti JSON archiviati in database DocumentDB, come illustrato nella Figura 4:

Figura 4 il documento di richiesta, che viene archiviato nella raccolta Ninjas DocumentDb

{
  "id": "1",
  "Name": "Kacy Catanzaro",
  "ServedInOniwaban": false,
  "Clan": "American Ninja Warriors",
  "Equipment": [
    {
      "EquipmentName": "Muscles",
      "EquipmentType": "Tool"
    },
    {
      "EquipmentName": "Spunk",
      "EquipmentType": "Tool"
    }
  ],
  "DateOfBirth": "1/14/1990",
  "DateCreated": "2015-08-10T20:35:09.7600000",
  "DateModified": 1444152912328
}

Passare i risultati al Client

Questo oggetto JSON viene restituito alla funzione ninjas.getNinja, che quindi lo restituisce al chiamante, in questo caso il modulo edit.js sul client. Aurelia quindi associa edit.js al modello di edit.html e visualizza una pagina, che è progettata per visualizzare il grafico.

La visualizzazione di modifica consente agli utenti di modificare i quattro tipi di dati: nome e la data di nascita (stringhe), l'esperto clan (un elenco a discesa) e se il database fornito in Oniwaban. L'elenco a discesa Clan utilizza un tipo speciale di componenti Web chiamato un elemento personalizzato. L'implementazione di Aurelia della specifica di elemento personalizzato è univoco. Poiché sto utilizzando tale funzionalità per associare i dati e si tratta di una colonna di dati, illustrerò come che viene eseguita.

Associare i dati a un elemento personalizzato Aurelia

Come altre coppie di modello di visualizzazione in Aurelia e visualizzazione, un elemento personalizzato è composta da una visualizzazione per il markup e un modello di visualizzazione per la logica. Figura 5 indica il terzo file è coinvolto, clans.js, che fornisce un elenco di clans.

Figura 5 Clans.js

export function getClans(){
  var clans = [], propertyName;
  for(propertyName in clansObject) {
    if (clansObject.hasOwnProperty(propertyName)) {
      clans.push({ code: clansObject[propertyName], name: propertyName });
    }
  }
  return clans;
}
var clansObject = {
  "American Ninja Warriors": "anj",
  "Vermont Clan": "vc",
  "Turtles": "t"
};

La visualizzazione di questo elemento (dropdown.html) usa un Bootstrap elemento "select", che ancora considerato come un elenco a discesa:

<template>
  <select value.bind="selectedClan">
    <option repeat.for="clan of clans" model.bind="clan.name">${clan.name}</option>
  </select>
</template>

Si noti il value.bind e repeat.for, che dovrebbe essere familiare se si legge il mio precedente articolo sull'associazione dati con Aurelia. Le opzioni all'interno dell'elemento select associare al modello di clan definito in clans.js e quindi visualizzare il nome clan. Poiché l'oggetto Clans è semplice, con solo un nome e il codice, ovvero estranei in questo esempio, potrei semplicemente utilizzare value.bind non esiste. Ma mi atterrò con model.bind perché è un modello migliore per me da ricordare.

Il modulo dropdown.js collega il markup con clans, come illustrato nella Figura 6.

Figura 6 codice elemento personalizzato per il modello in Dropdown.js

import $ from 'jquery';
import {getClans} from '../clans';
import {bindable} from 'aurelia-framework';
export class Dropdown {
  @bindable selectedClan;
  attached() {
    $(this.dropdown).dropdown();
  }
  constructor() {
    this.clans = getClans();
  }
}

Inoltre, l'elemento personalizzato rende possibile usare molto più semplice markup nella visualizzazione my modifica:

<dropdown selected-clan.two-way="ninja.Clan"></dropdown>

Si noti che si sono utilizzando due caratteristiche specifiche Aurelia qui. In primo luogo, la proprietà viene chiamato selectedClan nel modello di visualizzazione, ma selezionato clan nel markup. La convenzione Aurelia, in base alle necessità dell'HTML per gli attributi devono essere in minuscolo, consiste nell'apportare tutte le proprietà personalizzate dell'esportazione nomi minuscole e trattino, in modo che si prevede che trattino per essere in lettere maiuscole/minuscole camel iniziano. In secondo luogo, anziché value.bind, in modo esplicito utilizzo associazione bidirezionale qui in modo di clan verrà riassociati per il database quando cambia la selezione.

Più importante, in modo molto semplice riutilizzare l'elemento personalizzato nelle altre visualizzazioni. In questo caso, ma fornisce semplicemente maggiore leggibilità e, pertanto, più la gestibilità. Ma in applicazioni di grandi dimensioni, il riutilizzo del codice e logica è un grande vantaggio.

Push Back modifiche a DocumentDB

Il markup stia leggendo le due porzioni di apparecchiature nel grafico e visualizzarli. Per brevità, lascio la modifica dei dati di apparecchiature in un altro giorno.

L'ultima parte del lavoro è ora per trasferire le modifiche di backup per l'API e inviarli a DocumentDB. Questa azione viene attivata con il pulsante Salva.

Il markup per il pulsante Salva utilizza un altro paradigma Aurelia, click.delegate—which viene utilizzata la delega di eventi JavaScript, consentendo di delegare l'azione di salvataggio funzione definita in edit.js.

Funzione di salvataggio, illustrato nella Figura 7, crea un nuovo oggetto, ninjaRoot, utilizzando le proprietà rilevanti dalla proprietà di database che è stata definita in getNinja, che viene quindi associato al markup, consentendo all'utente di aggiornare il browser.

Figura 7, la funzione ninjas.save

save() {
  this.ninjaRoot = {
    Id: this.ninja.id,
    ServedInOniwaban: this.ninja.ServedInOniwaban,
    Clan: this.ninja.Clan,
    Name: this.ninja.Name,
    DateOfBirth: this.ninja.DateOfBirth
  };
  return this.httpClient.fetch('/updateDetails', {
    method: 'post',
    body: json(this.ninjaRoot)
  }).then(response => {this.router.navigate('ninjaList');
  });
}

Salvare quindi utilizza il httpClient.fetch adesso familiare per richiedere un URL di API denominato udpateDetails e passare l'oggetto ninjaRoot come corpo. Si noti inoltre che sto specificando questo come un metodo post, non un'operazione get. Il router API indica Node. js per indirizzare il metodo updateDetails del modulo ninjas.

router.post('/api/updateDetails', function(request,response){
  ninjas.updateDetails(request,response);
});

Ora esaminiamo il metodo sul lato server updateDetails in ninjas.js:

updateDetails: function (request,response) {
  var self = this;
  var ninja = request.body;
  self.docDbDao.updateItem(ninja, function (err) {
    if (err) {
      throw (err);
    } else {
      response.send(200);
    }
  })
},

Deve essere estratto il ninjaRoot archiviati nel corpo della richiesta e set che a una variabile di database, quindi passare tale variabile nel metodo updateItem del controller. Come Figura 8 illustrato, ho modificato leggermente updateItem poiché nella prima parte del mio articolo per il tipo di database.

Figura 8, il metodo updateItem in docDbDao Controller Usa il SDK di Node. js per parlare con DocumentDB

updateItem: function (item, callback) {
  var self = this;
  self.getItem(item.Id, function (err, doc) {
    if (err) {
      callback(err);
    } else {
      doc.Clan=item.Clan;
      doc.Name=item.Name;
      doc.ServedInOniwaban=item.ServedInOniwaban;
      doc.DateOfBirth=item.DateOfBirth;
      doc.DateModified=Date.now();
      self.client.replaceDocument(doc._self, doc, function (err, replaced) {
        if (err) {
          callback(err);
        } else {
          callback(null, replaced);
        }
      });
    }
  });
},

UpdateItem recupera il documento dal database utilizzando l'id, aggiorna le proprietà rilevanti del documento e quindi utilizza il metodo DocumentDBClient.replaceDocument SDK per effettuare il push della modifica del database Azure DocumentDB. Un callback avvisa l'utente fino al completamento dell'operazione. Il callback viene quindi indicato dal metodo updateDetails, che restituisce un codice di 200 risposta al modulo client che ha chiamato l'API. Se si osserva il lato client metodo save, si noterà che il callback instrada a ninjaList. Pertanto, quando l'aggiornamento è stato registrato correttamente, viene visualizzata con la pagina di elenco originale di ninjas. Tutte le modifiche per il database appena modificato sarà visibile nell'elenco.

Siamo Ninjas ancora?

Questa soluzione mi ha generato in un vuoto di difficoltà e termina in messaggi non recapitabili. Sebbene l'obiettivo principale è quello di far Aurelia di comunicare con il database di DocumentDB, desideravo inoltre utilizzare queste tecnologie in modo da sfruttare i vantaggi. Ciò ha significato dover comprendere così tante cose nel mondo JavaScript, gestire le installazioni di nodo, utilizzare Visual Studio Code per la prima volta a causa di capacità per il debug di Node. js e ulteriori informazioni su DocumentDB. Sebbene esistano molte altre cose, che è possibile eseguire anche un esempio semplice come il mio, in questo articolo dovrebbe fornire una conoscenza di base del funzionano delle operazioni da un'estremità a altra.

Un punto importante da tenere presente è che DocumentDB, come qualsiasi database NoSQL, è progettato per grandi volumi di dati. Non è conveniente per piccoli poco bit di dati, ad esempio possibile utilizzare nel mio esempio. Ma per esplorare le funzionalità di connessione al database e l'interazione con i dati, grandi quantità di dati non erano necessari, in modo da cinque oggetti sufficed.


Julie Lerman è un Microsoft MVP, mentore e consulente .NET che risiede nel Vermont. È possibile trovare le sue presentazioni relative all'accesso ai dati e altri argomenti su .NET in occasioni di conferenze che si tengono in tutto il mondo. Anna blog all'indirizzo thedatafarm.com ed è autore di "Programming Entity Framework" nonché edizioni DbContext e Code First, tutto da o ' Reilly Media. Seguirla su Twitter: @julielerman e vedere i corsi proprio Pluralsight PS/juliel.me-video.

Grazie all'esperto tecnica seguente per la revisione di questo articolo: Patrick Walters
Patrick Walters è stata una parte della community di sviluppatori Aurelia eccezionali che desiderano offrire un orecchio per domande sul canale gitter Aurelia ufficiale.