本文章是由機器翻譯。

技術最前線

ASP.NET Ajax 程式庫和 WCF 資料服務

Dino Esposito

下載程式碼範例

它被幾年來,因為 Web 產業需求 AJAX 問世為新的紀元的程式設計繁榮昌盛,開頭,且現在一組功能強大的程式設計的工具可最後供 Web 開發人員:ASP.NET AJAX 程式庫並 WCF 資料服務。 開發人員可以停止依賴瀏覽器以不同的執行階段環境,並從 Web 執行先前已只可能透過智慧型用戶端的墩數。

能夠將遠端的 HTTP 端點的呼叫是許多應用程式會利用現今的常見功能。 這類應用程式使用 Windows Communication Foundation (WCF) 服務來下載 JavaScript 物件表示法 (JSON) 資料流,而且該內容剖析成然後呈現到目前 HTML 文件物件模型 (DOM) 的 JavaScript 物件。 不過,[WCF 服務在伺服器端 — 和 JavaScript 程式碼,在用戶端 — 在不同資料型別強迫您建立兩個不同的物件模型上工作。

您通常需要在伺服器端也就是如何處理中介層,並代表實體上的網域模型。 Entity Framework和 LINQ to SQL 是設計從從頭開始或從現有的資料庫推斷您伺服器端物件模型的兩種絕佳的工具。 有些時候不過,您必須為 WCF 服務呼叫的回應,此資料傳送至用戶端。

其中一個服務導向架構 (SOA) 的最受歡迎的 mantras 會維護您應該永遠轉移資料合約不類別,decoupling 展示和商業層的一部份。 因此您需要另一個完全不同的物件模型:簡報的檢視模式。

常見的問題是偵測,且通訊伺服器資料在用戶端上所發生的任何變更。 溝通只變更可確保最少量的資料可能會跨在網路上傳輸,並對資料庫執行最佳化的資料存取作業。

因此需要資料存取和操作的端對端解決方案。 WCF 資料服務 (之前稱為 ADO.NET 資料服務) 與 ASP.NET AJAX 櫃結合提供全面性的架構,可讓您下載資料、 在其上工作並回到伺服器的更新。 在這篇文章我查看 ASP.NET AJAX JavaScript 元件存取有效的用戶端資料。

簡單地說 WCF 資料服務

背後尖端、 端對端的資料存取解決方案在 WCF Data Services 關鍵概念是您建置伺服器端資料來源,及透過 WCF 服務的特殊類別公開:在 WCF 資料] 服務中。 (您找到 WCF 資料服務的極佳簡介在 2008 年八月版本的 MSDN Magazine ,可以在 msdn.microsoft.com/magazine/cc748663 )。

您通常是先建立商務網域模型使用 Entity Framework 再建立它的周圍的 WCF 服務。 我是使用熟悉的 Northwind 資料庫並處理其資料表的一小部分:客戶] 和 [訂單]。

第一次,建立新的類別庫專案並加入新項目型別 ADO.NET Entity Data Model。 接下來,您編譯專案,並參考新的 ASP.NET 應用程式內從組件。 在將範例程式碼中,我使用 ASP.NET MVC 專案。 您可合併與主控件的 Web 應用程式的 web.config 任何連線字串設定,並新增新的 「 ADO.NET 資料服務 」 項目至 Web 專案。 (舊名稱仍然被使用在 Visual Studio 2008 和 Beta 2 的 Visual Studio 2010)。現在您已經有與資料來源的類別庫和 WCF 資料服務的、 裝載在 ASP.NET 應用程式、 公開給用戶端內容。

在最簡單的情況下,這是您必須要有 WCF 資料服務 」 中的所有程式碼:

public class NorthwindService : DataService<NorthwindEntities>
{
   public static void InitializeService(IDataServiceConfiguration config)
   {
      config.SetEntitySetAccessRule("Customers", EntitySetRights.All);
    }
}

當您繼續進行您的專案,您可能需要實體集合上新增更多的存取規則,而且還 (何不?) 支援的額外服務作業。 WCF 資料服務是一般的 WCF 服務,以 REST 方式消耗。 執行任何動作,因此,阻止您新增一或多個新的服務作業,各表示複雜的查詢] 或 [將複雜的更新等之資料的粗糙作業。 以外,前述的程式碼所示服務會提供用戶端存取沒有限制,作業 Customers 實體集。 這表示您 won’t 是能夠查詢的客戶和訂單,即使訂單的實體集不會存在於模型中的內嵌的實體。 新的存取規則,才能讓用戶端存取的訂單。

直到新 REST 方法加入 WCF 資料服務唯一允許的作業都是泛型建立、 讀取、 更新和刪除 (CRUD) 作業使用臨機操作 URI 格式來表示。 (請參閱以取得更多詳細資料的 msdn.microsoft.com/data/cc668792 在語法上)。URI 格式可以讓應用程式查詢實體、 實體,間周遊的關係並套用任何變更。 每個 CRUD 作業對應到不同的 HTTP 動詞命令:GET 插入的 POST 的查詢 PUT 更新和 DELETE 針對刪除。

取得參考,WCF 資料服務用戶端收到由 datasvcutil.exe 公用程式所建立或無障礙地由 Visual Studio 中加入服務參考精靈所建立的 Proxy 類別。

叫用從智慧型用戶端平台的 WCF 資料服務 couldn’t 會比較容易,是否 Silverlight,Windows 或 Windows Presentation Foundation (WPF)。 相同可以說 ASP.NET 的伺服器端繫結。 根據 JavaScript 和 AJAX 的 Web 用戶端呢?

消耗資料服務透過 ASP.NET AJAX 程式庫

ASP.NET 艾傑克斯程式庫中有兩個相關 WCF 資料服務的 JavaScript 元件:OpenDataServiceProxy 並 OpenDataContext。

OpenDataContext 基本上被為了管理 CRUD 作業從 Web 用戶端內。 它可以被視為 DataServiceContext 類別的 JavaScript 相對。 System.Data.Services.Client 命名空間中定義,DataServiceContext 代表指定的 WCF 資料服務的執行階段環境。 OpenDataContext 追蹤變更所使用的實體,並且可以智慧地產生對後端服務的命令。

OpenDataServiceProxy 類別被作為輕量的額外 Proxy 的 WCF 資料服務。 它基本上會管理唯讀案例,但是可以用來叫用 (Invoke) 公開服務中的其他服務作業。 您初始化 OpenDataServiceProxy 類別,如下所示:

var proxy = new Sys.Data.OpenDataServiceProxy(url);

這個時候類別已啟動且正在執行。 通常需要花更多的時間設定 OpenDataContext 物件。 相關服務連接就不過,它發生類似的方式:

var dataContext = new Sys.Data.OpenDataContext();   
dataContext.set_serviceUri(url);

這兩個類別可用於為資料提供者 DataView。 一個您用取決於您想要做。 如果任何 CRUD 活動有發生透過服務,’re 可能最好將 Proxy。 如果您在用戶端上有邏輯,並想要套用變更前先執行一大堆 CRUD 作業,資料內容是比較好的。 let’s 專注於 OpenDataContext。

使用 OpenDataContext 類別

這裡 ’s 如何建立和初始化 OpenDataContext 類別的執行個體:

<script type="text/javascript">
  var dataContext;
    
  Sys.require([Sys.components.dataView, Sys.components.openDataContext]);

  Sys.onReady(function() {
    dataContext = Sys.create.openDataContext(
      {
         serviceUri: "/NorthwindService.svc",
         mergeOption: Sys.Data.MergeOption.appendOnly
      });

    });
</script>

請注意 Sys.require 函式,若要以動態方式連結擔任目的元件所使用的指令碼檔案的使用。 如果您選擇 Sys.require 方法,唯一需要連結以傳統方式的指令碼檔案是 start.js:

(see code <script src="../../Scripts/MicrosoftAjax/Start.js" 
  type="text/javascript">
</script>

您使用的所有檔案不過,必須都是伺服器上可用或透過 [Microsoft 內容傳遞網路 (CDN) 參考。

尋找預先為 的 圖 2,您可以看到在文件 ’s 準備事件您建立新的執行個體 OpenDataContext 類別。 請注意再次最新的縮寫語法來定義通用的事件的程式碼和通用物件具現化的使用。 OpenDataContext 類別工廠接收服務和一些其他設定的 URL。 這個時候您 ’re 已準備好來使用資料內容作為資料提供者,以在頁面中的某些 DataView UI 元件如 的 圖 1 所示。

圖 1 為資料提供者使用資料內容

<table>
    <tr class="tableHeader">
        <td>ID</td>
        <td>Name</td>
        <td>Contact</td>
    </tr>
    <tbody sys:attach="dataview" 
           class="sys-template"
           dataview:dataprovider="{{ dataContext }}"
           dataview:fetchoperation="Customers"
           dataview:autofetch="true">
         <tr>
             <td>{{ CustomerID }}</td>
             <td>{{ CompanyName }}</td>
             <td>{{ ContactName }}</td> 
         </tr>
     </tbody>
</table>

DataView 元件的執行個體是建立,用來填入它附加至範本。 DataView 提供需要下載透過 WCF 資料服務的資料,並將它繫結至 HTML 範本黏附程式碼。 位置是決定對有關資料来下載? 亦即如何指定查詢字串,為您想要回資料?

DataView 元件的提取作業屬性指示要叫用服務作業的名稱。 如果資料提供者服務的一般 Proxy fetchoperation 屬性會採用公用方法的名稱在服務上。 如果您改到透過 OpenDataContext 類別,fetchoperation 的值被期望的 WCF 資料服務執行階段能夠了解的字串。 它可以是像上述任何運算式:

Customers
Customers('ALFKI')
Customers('ALFKI')?$expand=Orders
Customers('ALFKI')?$expand=Orders&$orderBy=City

如果您只需指定有效的實體集的名稱,取得實體整個清單。 其他關鍵字如 $ 展開,$ orderBy 和 $ 篩選器可讓您包含相關的實體集 (使用內部聯結排序)、 屬性的順序和篩選器傳回布林條件式為主的實體。

您可以撰寫查詢以手動方式做為字串被 respectful 基礎 URI 格式。 或者,您可以使用內建的 OpenDataQueryBuilder JavaScript 物件,如 的 圖 2 所示。

圖 2 使用 AdoNetQueryBuilder 物件

<script type="text/javascript">
    var dataContext;
    var queryObject;   

    Sys.require([Sys.components.dataView, 
                Sys.components.openDataContext]);

    Sys.onReady(function() {
        dataContext = Sys.create.openDataContext(
           {
               serviceUri: "/NorthwindService.svc",
               mergeOption: Sys.Data.MergeOption.appendOnly
           });
        queryObject = new Sys.Data.OpenDataQueryBuilder("Customers");
        queryObject.set_orderby("ContactName");    
        queryObject.set_filter("City eq " + "’London’");  
        queryObject.set_expand("Orders");      
    });
</script>

查詢產生器可以用於建置完整 URL 或只是查詢部份的 URL。 在這種情況下查詢產生器取得設定查詢的實體名稱。 它也提供了一大堆設定任何需要的擴充、 篩選和訂單的屬性。 透過查詢產生器物件設定的準則必須再序列化為有效的查詢字串設定該 fetchoperation 時如下所示:

<tbody sys:attach="dataview" 
       class="sys-template"
       dataview:dataprovider="{{ dataContext }}"
       dataview:fetchoperation="{{ queryObject.toString() }}"
       dataview:autofetch="true">

若要從查詢產生器擷取查詢字串使用 toString 方法。 在將範例程式碼產生的查詢字串是

Customers?$expand=Orders&$filter="City eq 'London'"&$orderby=ContactName

服務傳回複合嵌入客戶人口統計加上一些訂單資訊的物件的集合。 圖 3 顯示輸出。


圖 3 查詢使用 WCF 資料服務的資料

最後一欄中的數字表示已經放置客戶的訂單數目。 因為的 「 $ 展開查詢中的屬性,JSON 資料流包含訂單的陣列。 HTML 範本參照陣列的長度,並且會填入資料行,就像這樣:

<td>{{ Orders.length }}</td>

附註為了要成功地擷取訂單資訊,您應該先交回給 WCF 資料服務的原始程式碼,啟用訂單的實體集的存取:

public static void InitializeService(
  IDataServiceConfiguration config)
{
  config.SetEntitySetAccessRule(
    "Customers", EntitySetRights.All);
  config.SetEntitySetAccessRule(
    "Orders", EntitySetRights.All);
}

let’s 看看它如何運作如果您有更積極的計劃,而想要傳回至服務之前更新用戶端上的資料。

處理更新

圖 4 顯示 HTML 範本的頁面片段,用來為客戶的查詢。 使用者輸入識別碼、 按下按鈕,並取得全新、 可編輯的資料。

圖 4 查詢資料服務

<div id="Demo2">
<table>
   <tr class="tableHeader"><td>Customer ID</td></tr>
   <tr><td>
     <%= Html.TextBox("CustomerID", "ALFKI") %>
     <input type="button" value="Load" onclick="doLoad()" />
   </td></tr>
 </table>
    
 <br /><br />
    
 <table sys:attach="dataview" id="Editor"
       class="sys-template"
       dataview:dataprovider="{{ dataContext }}"
       dataview:autofetch="false">
   <tr>
     <td class="caption">ID</td>
     <td>{{ CustomerID }}</td>
   </tr>
   <tr>
     <td class="caption">Company</td>
     <td>{{ CompanyName }}</td>
   </tr>    
   <tr>            
     <td class="caption">Address</td>
     <td>
        <%=Html.SysTextBox("Address", "{binding Address}")%></td>
   </tr>    
   <tr>       
     <td class="caption">City</td>         
     <td>{{ City }}</td>
    </tr>  
</table>
</div>

載入資料就會發生在要求。 這裡 ’s 負責叫用資料服務的程式碼:

function doLoad() {
  var id = Sys.get("#CustomerID").value;

  // Prepare the query
  var queryObject = new Sys.Data.OpenDataQueryBuilder("Customers");
  queryObject.set_filter("CustomerID eq '" + id + "’");
  var command = queryObject.toString();

  // Set up the DataView
  var dataView = Sys.get("$Editor").component();
  dataView.set_fetchOperation(command);
  dataView.fetchData();

先取得您需要輸入的資料 — 特別,使用者在 [輸入] 欄位中輸入的文字。 接下來,準備查詢使用新的 OpenDataQueryBuilder 物件。 指示 DataView (依序設定為使用 WCF 資料服務) 的最後,下載查詢的資料。

擷取任何資料會顯示使用 ASP.NET AJAX 保證即時的即時繫結更新 (請參閱 的 [圖 5]) 的任何牽涉到 JavaScript 物件程式庫。


圖 5 編輯 Object 本機

[編輯的客戶地址] 文字方塊中定義為:

<td class="caption">Address</td>
<td><%= Html.SysTextBox("Address", "{binding Address}") %></td>

除了 {繫結} 運算式使用,請注意自訂 ASP.NET MVC 中所使用的 HTML Helper。 如果您嘗試在 Web Form 應用程式的內容中使用即時繫結和 AJAX 範本,您可能有類似情況。 那麼還有什麼問題呢?

繫結至工作的資料相關的屬性必須在前端加上 sys:命名空間。 因此,若要將一些文字繫結至文字方塊中,您必須確定發出下列的 HTML 標記:

<input type="text" ... sys:value="{binding Address}" />

在 ASP.NET MVC 與 Web Form brilliantly 可以藉由輸入 HTML 常值來解決問題。 否則,您需要調整的版本所選擇的 ASP.NET 架構提供了工具的輸入 abstracting 項標記:HTML 的協助程式或伺服器控制項。 在特別 ASP.NET MVC 中您可能依靠自訂的 HTML 協助程式,會發出 sys:value] 屬性,如 的 圖 6 所示。

圖 6 的 A 自訂 HTML 協助程式

public static string SysTextBox(this HtmlHelper htmlHelper, 
    string name, 
    string value, 
   IDictionary<string, object> htmlAttributes)
{
    var builder = new TagBuilder("input");
    builder.MergeAttributes(htmlAttributes);
    builder.MergeAttribute("type", "text");
    builder.MergeAttribute("name", name, true);
    builder.MergeAttribute("id", name, true);
    builder.MergeAttribute("sys:value", value, true);
    return builder.ToString(TagRenderMode.SelfClosing);
}

因為它們會發生,而且資料內容物件由追蹤記錄顯示客戶的地址的變更。 請注意這可能只是否您使用資料內容物件為用於呈現 DataView 資料提供者。 這是 OpenDataContext 物件可以為您做相對於先前提到的 OpenDataServiceProxy 物件額外的工作。

您可以在如何儲存變更? 為了確保修改過的差異下載的資料的服務至資料服務,您只需要會叫用 saveChanges 方法資料內容執行個體上。 根據應用程式類型您正在建置,雖然您可能想要新增一些額外的層級的控制項。 比方說,您可以新增 「 認可 」 按鈕會先彙總將要的內容,及會要求使用者確認他們想要儲存暫止的變更。 圖 7 顯示認可按鈕之 JavaScript 程式碼。

圖 7 的 A 認可] 按鈕,以確認變更

function doCommit() {
    var pendingChanges = dataContext.get_hasChanges();
    if (pendingChanges !== true) {
        alert("No pending changes to save.");
        return;
    }

    var changes = dataContext.get_changes();
    var buffer = "";
    for (var i = 0; i < changes.length; i++) {
        ch = changes[i];

      // Function makeReadable just converts the action to readable text
        buffer += makeReadable(ch.action) +
                  " --> " + 
                  ch.item["Address"];
        buffer += "\n";
    }
    if (confirm(buffer))
        dataContext.saveChanges();
}

函式會檢查與目前資料內容,看看是否有任何暫止的變更。 如果是這樣,它會建置偵測到變更的摘要。 資料內容上的 get_changes 方法傳回動作 (插入、 移除或更新) 類型的相關資訊的物件和本機所涉及的物件的陣列中變更。 圖 8 中將顯示當您嘗試認可暫止的變更時,從上述程式碼結果的對話方塊。


圖 8 擱置變更] 偵測到

請注意每次您選取 [新客戶則會失去的前一個變更。 這是因為資料內容是清空,refilled 用其他資料。 保存中有些變更其他物件只是 doesn’t 合理 — 您被改寫資料內容的複製品自己。

用戶端 Proxy 的 WCF 資料服務的強大 doesn’t 顯示真的也透過單一物件的使用者介面中。 在 ASP.NET AJAX 櫃 Beta 套件,您找到一個很好的方法,若要測試這項功能:ImageOrganizer 範例。 不過,我可以給你的我只是延伸一個位元存在的範例是指 gist。 let’s 假設主版詳細資料檢視,而且可以從一位客戶 ’s 檢視切換至下一個不需要離開分頁和 
necessarily 不必儲存變更。 下載發生一次 (或定期),而且它仍會保留在記憶體中的時間,所有使用者介面允許正確追蹤的變更 (請參閱 的 圖 9)。


圖 9 追蹤用戶端變更

插入與刪除

因此遠我只著重更新。 但怎麼插入和刪除動作嗎? 這些有一些稍有差異,需要多一點的工作。 首先,foremost,can’t 依賴資料繫結的變更會套用到所顯示的基礎物件。 您的責任是更新記憶體中集合 (或物件) 您接收到從使用者介面中所使用的資料內容。 為插入,只需要建立適用於顯示物件的新本機執行個體,並將其新增到繫結的集合。 在此時如果您的使用者介面完全資料繫結應該能夠反映變更。 接下來,您必須通知資料內容,新的物件已新增至實體集且需要追蹤保存性。 這裡 ’s 典型您需要附加至 JavaScript 的按鈕,將物件插入的程式碼:

// Create a new local object
var newCustomer = { ID: "DINOE", CompanyName: "...", ... };

// Add it to the collection used for data binding
dataView.get_data().add(newCustomer);

// Inform the data context object
dataContext.insertEntity(newCustomer, "Customers");

移除物件是甚至更簡單。 您從記憶體中集合移除物件,然後在資料內容上呼叫 removeEntity 方法。

var index = customerList.get_selectedIndex();
var customer = dataView.get_data()[index];
dataContext.removeEntity(customer);
imageData.remove(customer);

避免混淆

OpenDataContext 和 DataView 物件合作愉快,但不是應該與彼此相混淆。 OpenDataContext 物件代表用戶端 Proxy 的遠端的 WCF 資料服務。 不過,它 ’s 非常特殊類型的 Proxy。 它會實作 「 工時單位 」 模式用戶端上時它會追蹤所所做的變更任何實體它 helped 的擷取。 資料內容是 DataView 元件的極佳的資料提供者。 呈現是以獨佔方式有關 DataView 元件。 它所提供的範本來輕鬆地,叫用遠端作業的外掛程式,但所 ’s 只是開發人員的設備。 沒有這類 CRUD 和資料管理邏輯屬於 [DataView。

本文 didn’t 深入 WCF 資料服務的複雜性,並 didn’t 碰觸並行處理、 延遲載入和安全性等方面。 它可能 didn’t 討論資料傳輸。 但願,本文可做為如何執行這項重要的事項與 ASP.NET 艾傑克斯程式庫和 WCF 資料服務的最新摘要。 其餘部分是未來的文章的良好追擊。 下次見!

 

Dino Esposito   是即將產生 「 發展 ASP.NET MVC 」 從 Microsoft 按作者,而是 co-author 的 「 Microsoft.NET:架構企業的應用程式 」 (Microsoft 按,2008年)。 根據在義大利,Esposito 是在世界各地的產業活動頻繁演講者簡報。 weblogs.asp.net/despos 在加入他的部落格。

多虧來檢閱本文的下列的技術專家:   Boris Rivers-Moore和提夫 Walther