# 數據點 - Aurelia 與 DocumentDB 結合: 結合之旅(第 2 部分)
通過?[Julie Lerman](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Julie+Lerman)?|2015 年 12 月 |?[獲取代碼](http://download.microsoft.com/download/D/5/4/D54647CC-A404-4374-B7EF-E469FB5136B9/Code_Lerman.DataPoints1215.zip)

新的 JavaScript 框架、 Aurelia 和 NoSQL 文檔數據庫服務,Azure DocumentDB 是最近捕獲我感興趣的兩個不同的技術。在 6 月,我探討了較高層面的 DocumentDB ([msdn.com/magazine/mt147238](http://msdn.com/magazine/mt147238))。然后,在 9 月份,我玩游戲與 Aurelia 中的數據綁定 ([msdn.com/magazine/mt422580](http://msdn.com/magazine/mt422580))。通過這兩種技術仍好奇,我認為我希望將這兩個組合在一起,作為應用程序和 DocumentDB 的前端 Aurelia 用作數據存儲區。雖然我的好奇心給我帶來了一定的優勢 (持久性),我有限的經驗與這兩種新技術,以及 JavaScript 框架一般情況下,設置我沿多個這樣的困境之中嘗試地結合使用。沒有人最初執行之前此組合的事實后情況已變得更糟 — 至少不公開。我在 11 月的專欄中記錄這些失敗的嘗試 ([msdn.com/magazine/mt620011](http://msdn.com/magazine/mt620011)),則這兩篇系列文章的第一個。所選的要跳過的一條淺顯路徑是使用我包裝與 DocumentDB 來代替我在我第一 Aurelia 篇文章中從事 Web API 進行交互的現有 Web API。在其中沒有挑戰性因所做選擇此選項,并因此不內容相當有趣。
我最后來到決定使用另一種服務器端解決方案: Node.js。沒有使用 DocumentDB Node.js SDK 和一個不同的前端的現有示例。我仔細檢查并共享我學到什么與您在我在 11 月的專欄的第二部分中。然后我將有關重新從 9 月列中,我專家的示例創建這次使用作為從 Aurelia 前端到 DocumentDB 我充當中介的 Node.js。各種錯誤很多,而且它們遠遠超出與數據相關的問題了。我必須支持從 Aurelia 核心團隊的成員,尤其是從 Patrick Walters 加載 ([github.com/pwkad](http://github.com/pwkad)),用戶不僅可以幫助您確認我已充分利用 Aurelia 功能,但也會間接迫使我進一步 hone 到我的 Git 技能。我將關注這里是涉及訪問、 更新和將數據綁定解決方案的各個部分。附帶了隨附的可下載示例的自述文件說明了如何設置您自己 DocumentDB 并導入此解決方案的數據。它還說明了如何設置運行該示例的要求。
## 解決方案體系結構
首先,讓我們看一看此解決方案的整體體系結構,如中所示?圖 1。
?
圖 1 此解決方案的整體結構
Aurelia 是客戶端框架,因此就在這里只是為了處理客戶端的要求,如呈現的 HTML,取決于視圖和視圖模型配對,以及路由、 數據綁定和其他相關任務。(請注意所有客戶端代碼可以在瀏覽器,如 Internet Explorer 和 Chrome 中可用的開發人員工具中進行調試。) 在解決方案的路徑中,所有客戶端代碼是在公共/應用程序/src 文件夾中,服務器端代碼時的根文件夾中。當運行該 Web 站點時,客戶端文件編譯通過 Aurelia 以確保瀏覽器兼容性,且分發到一個名為"dist."文件夾 這些文件是發送到客戶端獲取的內容。
服務器端代碼應熟悉如果您曾在 Microsoft.NET Framework (更接近于我自己背景) 中的 Web 開發。在.NET 環境中,從 web 窗體、 控制器和其他邏輯代碼隱藏是傳統上編譯為 Dll 存在于服務器。當然,大部分內容更改與 ASP.NET 5 (其中我現在感覺更準備好,謝謝到處理此特定項目)。我的 Aurelia 項目還包含服務器端代碼,但即便是這樣,通過 Node.js 的 JavaScript 代碼。此代碼不編譯為 DLL,但仍保留在其自己單獨的文件。更重要的是,它不會下推至客戶端并因此不容易公開 (這是,當然,總是非常依賴于安全措施)。如我所述最后一次,他們希望將停留在服務器的代碼的推動原因是我需要一種方法來存儲我的憑據用于與 DocumentDB 交互。因為我想要試用 Node.js 路徑,上述 SDK 進行對話,與 DocumentDB 容易得多。我必須依靠有關如何使用 SDK 的一些基本知識的原始 DocumentDB 節點示例是一個巨大幫助。
我的服務器端代碼 (其中我將稱它為我的 API) 由四個關鍵要素組成:
* 可以輕松地找到充當路由器以確保我的 API 函數 api.js 文件。
* 我的核心模塊、 ninjas.js,其中包含的 API 函數: getNinjas getNinja 和 updateDetails。
* 控制器類中,執行與 DocumentDb 交互的 DocDbDao (由這些 API 函數調用)。
* 知道如何確保相關數據庫和集合的 DocumentDb 實用程序文件存在。
## 綁定客戶端、 服務器和云
在我早期 Aurelia 示例中,要獲取所有 ninjas 的方法進行直接的 HTTP 調用到.NET 和實體框架進行交互與 SQL Server 數據庫使用的 ASP.NET Web API:
~~~
retrieveNinjas() {
? return this.http.createRequest
??? ("/ninjas/?page=" + this.currentPage + "&pageSize=100&query=" +
????? this.searchEntry)
????? .asGet().send().then(response => {
??????? this.ninjas = response.content;
??? });
? }
~~~
已將結果傳遞給客戶端一側視圖和視圖模型 (ninjaList.js 和 ninjaList.html),會輸出中顯示的頁面對?圖 2。

圖 2 中我 Aurelia 的網站的專家列表
在新的解決方案中,這種方法,重命名為 getNinjas,現在我的服務器端 Node.js API 調用。我使用更高級的 httpClient.fetch ([bit.ly/1M8EmnY](http://bit.ly/1M8EmnY)) 而不是 httpClient 這次進行調用:
~~~
getNinjas(params){
? return this.httpClient.fetch(`/ninjas?q=${params}`)
??? .then(response => response.json())
??? .then(ninjas => this.ninjas = ninjas);
}
~~~
我已配置在其他地方 httpClient 須知的基 URL。
請注意,我提取的方法調用包括術語 ninjas 的 URI。但是,這不指在服務器端 API 中我 ninjas.js。這可能是 /foo — 只是將我的服務器端路由器的解析的隨機的引用。我的服務器端路由器 (它使用明確的、 不 Aurelia,因為 Aurelia 只處理客戶端) 指定對 api/ninjas 的調用將路由到 ninjas 模塊 getNinjas 函數。下面是從 api.js 定義此代碼:
~~~
router.get('/api/ninjas', function (request, response) {
? ninjas.getNinjas(req, res);
});
~~~
現在我 getNinjas 函數 (圖 3) 使用字符串插值 (mzl.la/1fhuSIg) 以生成一個字符串來表示用于查詢 DocumentDB、 SQL 然后詢問用戶要執行查詢并返回結果的控制器。如果名稱屬性的篩選器已請求在 UI 中,我將追加到查詢的 WHERE 子句。主查詢投影只我需要將相關屬性頁上,包括此 id。(有關在 DocumentDB 投影查詢的詳細信息請參閱?[documentdb.com/sql/demo](http://documentdb.com/sql/demo)。) 查詢傳遞到 docDbDao 控制器的查找方法。Find 方法,這是我在本系列的第一部分所述的原始相比并無變化,使用 Node.js SDK 以及 config.js 中存儲的憑據來查詢 ninjas 的數據庫。然后,getNinjas 接受這些結果,并將它們返回到請求它們的客戶端。請注意,盡管對 DocumentDB 的調用不作為 JSON 返回結果,但我仍然需要顯式使用 response.json 函數將返回的結果傳遞。這會提醒調用方,則結果是 JSON 格式。
圖 3 在 ninjas.js 服務器端模塊 getNinjas 函數
~~~
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);
??? }
? })
},
~~~
## 編輯請求的客戶端的響應
正如您可以看到在?圖 2, ,就可以通過單擊鉛筆圖標編輯專家。下面是我都構建在頁標記中的鏈接:
~~~
<a href="#/ninjas/${ninja.id}" class=
? "btn btn-default btn-sm">
? <span class="glyphicon glyphicon-pencil" />
</a>
~~~
通過單擊我的第一行,其 ID 恰好是"1",編輯圖標中,我將獲得此 URL:
~~~
http://localhost:9000/app/#/ninjas/1
~~~
在 app.js 的客戶端上使用 Aurelia 路由功能,我已指定在請求此 URL 模式時,它應然后調用編輯模塊,id 中給編輯視圖模型的激活方法作為參數傳遞,指示通配符 (* Id):
~~~
{ route: 'ninjas/*Id', moduleId: 'edit', title:'Edit Ninja' },
~~~
編輯是指與 edit.html 視圖成對出現的客戶端 edit.js 模塊。然后,我編輯的模塊的激活函數名為 retrieveNinja,傳入的請求 Id 本模塊中調用其他函數:
~~~
retrieveNinja(id) {
? return this.httpClient.fetch(`/ninjas/${id}`)
??? .then(response => response.json())
??? .then(ninja => this.ninja = ninja);
}
~~~
## 將編輯請求傳遞到服務器端 API
同樣,我使用 httpClient.fetch 請求 api/ninjas / [id] (在我事例 api/ninjas/1) 從 API。服務器端路由器說,這種模式的請求到達時,它應將路由到 ninjas 模塊 getNinja 函數。下面是什么該路由將如下所示:
~~~
router.get('/api/ninjas/:id', function(request, response) {
? ninjas.getNinja(request, response);
});
~~~
GetNinja 方法然后另一個向發出請求 docDbDao 控制器上,這次是打開 getItem 函數,可從 DocumentDb 獲取專家數據。結果是我的 DocumentDB 數據庫中存儲的 JSON 文檔中所示?圖 4:
圖 4 文檔我請求,存儲在 DocumentDb Ninjas 收藏
~~~
{
? "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
}
~~~
## 將結果傳遞回客戶端
此 JSON 對象返回給 ninjas.getNinja 函數,然后將其返回給調用方,在此情況下 edit.js 模塊在客戶端。然后,Aurelia 將 edit.js 綁定到 edit.html 模板,并將輸出一個頁面,它設計用于顯示此關系圖中。
編輯視圖允許用戶修改的數據的四個部分: 專家的名稱和出生日期 (這兩個字符串),clan (下拉列表) 和專家是否 Oniwaban 中提供服務。Clan 下拉列表中使用一種特殊的 Web 組件調用的自定義元素。自定義元素規范的 Aurelia 實現是唯一的。因為我正在使用該功能來綁定數據,并且這是一個數據列,我將向您展示如何執行該操作。
## 數據綁定與 Aurelia 自定義元素
類似于其他視圖和視圖模型對 Aurelia 中的,自定義元素標記的視圖和視圖模型的邏輯組成。圖 5?顯示的第三個文件涉及 clans.js,它提供 clans 的列表。
圖 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"
};
~~~
此元素 (dropdown.html) 的視圖使用的啟動"選擇"元素,我仍將視為一個下拉列表:
~~~
<template>
? <select value.bind="selectedClan">
??? <option repeat.for="clan of clans" model.bind="clan.name">${clan.name}</option>
? </select>
</template>
~~~
請注意 value.bind 和 repeat.for,它應是如果您閱讀我以前的專欄,在數據綁定與 Aurelia 所熟悉。在 select 元素內的選項將綁定到 clans.js 中定義的 clan 模型,然后顯示 clan 名稱。我 Clans 對象非常簡單,因為具有名稱和代碼中 (這是在此示例中額外),我可以簡單地使用 value.bind 存在。但是,我將堅持使用 model.bind,因為它是一種更好的我記住模式。
Dropdown.js 模塊連線具有 clans,標記中所示?圖 6。
圖 6 自定義元素中 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();
? }
}
~~~
此外,自定義元素就可以讓我在我的編輯視圖使用很多簡單標記:
~~~
<dropdown selected-clan.two-way="ninja.Clan"></dropdown>
~~~
請注意,我正在使用以下兩個 Aurelia 特定功能。首先,我的屬性稱為 selectedClan 在視圖模型,但選擇 clan 在標記中。Aurelia 約定,基于 HTML 的必要性屬性來為小寫,是使所有自定義屬性的導出名稱小寫和斷字,因此其結果應為駝峰式大小寫字母的開始位置的連字符。其次,而不 value.bind,我顯式使用雙向綁定,此處這樣 clan 將重新綁定到專家所選內容更改時。
更重要的是,我可以非常輕松地重復使用我在其他視圖中的自定義元素。在本例中,它只需提供可讀性,因此,多個可維護性。但在大型應用程序,重復使用的標記和邏輯是很大的收益。
## 將編輯推回 DocumentDB
我的標記是讀取關系圖中的設備的兩個參數,并顯示它們。為了簡潔起見,我將編輯另一天將設備的數據。
現在工作的最后一位是將備份的更改傳遞給 API 并將它們發送到 DocumentDB。這會觸發與保存按鈕。
保存按鈕的標記使用另一個 Aurelia 范例,click.delegate—which 使用 JavaScript 事件委托,從而使我能夠委托給存儲操作 edit.js 中定義的函數。
保存工作中, 所示?圖 7, ,創建一個新對象,ninjaRoot,使用從 getNinja,這是在其中定義的專家屬性相關的屬性,然后綁定到標記中,這樣就允許用戶從瀏覽器進行更新。
圖 7 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');
? });
}
~~~
保存然后使用現在應該很熟悉 httpClient.fetch 請求調用 udpateDetails API URL,然后將傳入的 ninjaRoot 對象作為正文。此外,請注意,我指定的這作為 post 方法,不具有 get。API 路由器告知 Node.js 可將路由到 ninjas 模塊的 updateDetails 方法。
~~~
router.post('/api/updateDetails', function(request,response){
? ninjas.updateDetails(request,response);
});
~~~
現在讓我們看一下 ninjas.js 中的服務器端 updateDetails 方法:
~~~
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);
??? }
? })
},
~~~
我提取存儲在請求正文和專家變量,然后將該變量傳遞到控制器的 updateItem 方法的集 ninjaRoot。作為?圖 8?所示,我修改 updateItem 有點以來第一部分我的文章以適應我專家的類型。
圖 8 updateItem 方法中 docDbDao 控制器使用說到 DocumentDB Node.js SDK
~~~
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 文檔使用 id 從數據庫進行檢索、 更新該文檔的相關屬性,然后使用 SDK DocumentDBClient.replaceDocument 方法將更改推送到我的 Azure DocumentDB 數據庫。回調提醒我的操作已完成。通過 updateDetails 方法,它將返回到調用該 API 的客戶端模塊返回 200 響應代碼,然后記下該回調。如果您回顧一下 save 方法的客戶端,您會注意到其回調將路由到 ninjaList。因此更新已成功發布,是顯示給用戶的 ninjas 的原始列表頁。向專家剛剛已更改的任何編輯都將在該列表中可見。
## 我們是否 Ninjas 尚未?
此解決方案將使我的困難和死胡同原來的虛空到。在我的核心目標能夠 Aurelia 交談 DocumentDB 數據庫時,我還想要使用這些技術來利用它們帶來的好處。這意味著無需理解這么多世界物流的 JavaScript、 管理節點安裝,請使用 Visual Studio Code 第一次由于它可以進行調試 Node.js 和甚至更多地了解 DocumentDB。盡管有可能想要在甚至像我這樣一個簡單的示例中執行操作的許多其他課題,本文應為您提供的操作的運行方式從一端到另一個基本的了解。
請記住的重要一點是,DocumentDB — 像任何 NoSQL 數據庫 — 適用于大容量數據。它是不經濟有效的小小位的數據,如我在我的示例中使用。不過,若要瀏覽的功能與數據庫連接和交互數據時,大量的數據不是必需的因此五個對象 sufficed。
* * *
Julie Lerman?*是 Microsoft MVP、.NET 導師和顧問,住在佛蒙特州的山區。您可以在全球的用戶組和會議中看到她對數據訪問和其他 .NET 主題的演示。她的博客網址?[thedatafarm.com /blog](http://thedatafarm.com/blog)?和代碼優先和 DbContext 版,均出自 O'Reilly Media 以及是 《 Programming Entity Framework 》 的作者。請關注她的 Twitter:?[@julielerman](https://twitter.com/@julielerman)?并查看其 Pluralsight 課程,網址?[juliel.me /ps-videos](http://juliel.me/PS-Videos)。*
- 介紹
- Visual Studio - 用于 Web 開發的新式工具: Grunt 和 Gulp
- 新員工 - 放長錢釣大魚
- Microsoft Azure - Azure Service Fabric 和微服務體系結構
- 數據點 - Aurelia 與 DocumentDB 結合: 結合之旅(第 2 部分)
- 游戲開發 - Babylon.js: 構建 Web 基本游戲
- 測試運行 - 面向 .NET 開發者的 Spark 簡介
- Xamarin - 使用 Xamarin.Forms 構建跨平臺用戶體驗
- 孜孜不倦的程序員 - 如何成為 MEAN: 快速輸入
- Microsoft Azure - Azure、Web API 和 Redis 如何有助于加快數據交付
- 必備 .NET - 設計 C# 7
- 新式應用 - 需要了解的 Windows 10 應用開發概念
- 別讓我打開話匣子 - 重構高等教育
- 編者注 - 再見 Kenny