程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> OData的實際應用-通過開放數據協議構建富Internet應用程序

OData的實際應用-通過開放數據協議構建富Internet應用程序

編輯:關於.NET

在 PDC09 期間,Microsoft WCF 數據服務團隊(以前稱為 ADO.NET 數據服務團隊)首次推出 OData,即開放數據協議。這一消息是在會議第二天的主題演講中宣布的,但實際上 OData 早就開始了。自從 Microsoft .NET Framework 3.5 SP1 中提供 ADO.NET 數據服務以來,熟悉 ADO.NET 數據服務的用戶已經使用 OData 作為數據傳輸協議開發基於資源的應用程序。本文將介紹富 Internet 應用程序 (RIA) 的開發人員如何使用 OData 以及使用 OData 的優勢。

首先,我將回答自 11 月 OData 問世後,我經常被問到的頭號問題。是什麼問題呢?簡單地說,OData 是一種基於資源的 Web 協議,用於查詢和更新數據。OData 定義了使用 HTTP 動詞(PUT、POST、UPDATE 和 DELETE)對資源的操作,並使用標准的 URI 語法識別這些資源。數據將使用 AtomPub 或 JSON 標准通過 HTTP 進行傳輸。對於 AtomPub,OData 協議在標准之上定義了一些約定,以支持查詢和架構信息的交換。

OData 生態系統

在本文中,我將介紹幾個使用或產生 OData 源的產品、框架和 Web 服務。該協議定義了可以操作的資源和方法,以及可以對這些資源執行的操作(GET、PUT、POST、MERGE 和 DELETE,分別對應著讀取、創建、替換、合並和刪除)。

實際上,這表示任何可以使用 OData 協議的客戶端都可以對任何生產者進行操作,沒必要學習服務的編程模型即可針對該服務進行編程,只要選擇編程的目標語言即可。

例如,如果您是 Silverlight 開發人員,學習適用於該平台的 OData 庫,則您可以針對任何 OData 源進行編程。除了適用於 Silverlight 的 OData 庫,您還會發現適用於 Microsoft .NET Framework 客戶端、AJAX、Java、PHP 和 Objective-C 的庫,更多的庫還在不斷推出。此外,Microsoft PowerPivot for Excel 也支持將 OData 源作為將數據導入到其內存中分析引擎的選項。

就像能使用 OData 協議的客戶端可以對任何生產者進行操作一樣,使用 OData 創建的服務或應用程序可以被任何啟用了 OData 的客戶端使用。在創建用於將關系數據公開為 OData 端點(或在 SharePoint 站點、Windows Azure 的表或其他您使用的服務中公開數據)的 Web 服務之後,您可以很輕松地在 .NET Framework 中構建富桌面客戶端,或構建使用相同數據的富 AJAX 網站。

OData 的長期目標是為每種主流技術、編程語言和平台都打造一個 OData 客戶端庫,以便每個客戶端應用程序都可以使用豐富的 OData 源。OData 的生產者和使用者共同構成了 OData“生態系統”。

WCF 數據服務的新功能

作為 .NET Framework 組件的 WCF 數據服務是一個可提供交鑰匙解決方案的框架,用於創建 OData Web 服務。它包括一個客戶端庫,您可以用來構建使用 OData 源的客戶端。WCF 數據服務團隊最近發布了 .NET Framework 3.5 SP1 的更新,引入了一系列將在 .NET Framework 4 中推出的新功能。這是數據服務框架的第二個版本。請訪問 blogs.msdn.com/astoriateam/archive/2010/01/27/data-services-update-for-net-3-5-sp1-available-for-download.aspx,在這裡可以找到相關介紹和下載鏈接。

WCF 數據服務框架不僅僅是針對 RIA 應用程序的協議,而且還適用於高級服務開發人員。它有很多吸引人的功能,例如服務器分頁限制、HTTP 緩存支持、無狀態服務、流支持和可插入的提供程序模型。讓我們來看看吸引大多數 RIA 開發人員的新功能。

初始版本推出之後,用戶最期望的功能之一就是能夠請求集中的實體數量。新的“計數”功能從兩方面滿足了該需求。首先,它讓您只請求計數,即一條查詢可以返回的值的數量。其次,它添加了一個查詢選項,告訴服務當查詢結果是部分集時(例如啟用了服務器分頁),包括集中實體總數的計數。

為了改善從 OData 服務綁定數據時的使用體驗,一種新的類型 DataServiceCollection 已添加到 WCF 數據服務客戶端庫中。該類型實現對其包含的條目的變更跟蹤(通過使用 INotifyPropertyChanged 和 INotifyCollectionChanged 接口)。如果將其綁定到控件(例如 Silverlight 中的 DataGrid),它將跟蹤對象和集合本身的更改。這個新的集合大大簡化了使用接口組件創建 OData 客戶端的過程。

另一項用戶期待的功能是投影查詢結果返回的實體的屬性子集。為此已經添加了 LINQ 支持,這種支持通過 LINQ Select 語句實現。這有兩方面的好處:可以減小 HTTP 查詢響應的大小,還可以減小客戶端方對象的內存占用量。當您針對別人的服務開發客戶端應用程序,而且該服務中每個實體都有很多對客戶端無意義的屬性時,這就特別有用。我將在後文中演示如何使用有很多實體、每個實體又有無數屬性的大型公共服務。示例中的投影非常有用,因為它只包括一個實體上的少數幾個必需的屬性。

為了幫助您了解 OData 生態系統的價值,我們將創建一個 Web 應用程序,讓訪問者浏覽一家虛擬的房地產公司 Contoso Ltd. 的網站,查看其管理的房產銷售清單。

關系數據

Contoso.com 的 Home Finder 應用程序的主要數據源是一個 SQL Server 數據庫,其中包含該公司管理的所有房產的信息,以及為這些房產發布的所有銷售清單(在售的和已售出的)。

借助 .NET Framework 3.5 SP1 中提供的 WCF 數據服務和 ADO.NET 實體框架,很容易將關系數據庫作為 OData 源提供,所需的只是在關系數據上創建實體框架模型。OData 源是基於 HTTP 的,因此您需要一個網站或 Web 服務來托管該服務。

若要在關系數據上創建 OData 源,第一步是在 Visual Studio 2010 中創建 ASP.NET Web 應用程序以托管 OData 服務。在 Visual Studio 中,選擇“文件”|“新建”|“項目”|“ASP.NET Web 應用程序”。這將創建用來托管 OData 源的 Web 服務的框架。

創建並配置 Web 服務後,我們接著創建 OData 源將提供的實體框架數據模型。Visual Studio 提供了“添加新項”向導,幫助您從現有的數據庫自動生成模型,從而讓操作變得很容易。圖 1 顯示了使用“添加新項”向導根據 SQL Server 數據(包含 Contoso 管理的房產和銷售清單)創建的簡單數據模型。

圖 1 關系數據的實體框架數據模型

現在讓我們來創建一個 WCF 數據服務,將此數據模型作為 OData 源提供。Visual Studio 在“添加新項”向導中提供了 WCF 數據服務選項,可幫助您輕松完成此操作。選擇此選項後,Visual Studio 提供了一個代碼文件(在此示例中,此文件稱為 Listings.svc.cs),用於配置數據服務。

圖 2 中的代碼演示了如何定義 WCF 數據服務。Listings 類是提供數據服務的服務類,實現了泛型 DataService<T>。圖 2 中用於定義 DataService<T> 的類型是 ListingsEntities 類型,就是圖 1 中創建的實體框架上下文。由於這個類將接受實體框架上下文,因此這種方法可以快速簡便地啟動並運行用來提供關系數據的 WCF 數據服務。但是 DataService 類並未局限在只是處理實體框架上下文,該類將接受實現 IQueryable 接口的任何 CLR 對象集合。在 .NET Framework 4 中,已添加了針對 WCF 數據服務的新的自定義提供程序模型,以便使用幾乎所有數據源來創建服務。

圖 2 定義 WCF 數據服務

// The ListingsEntities is the Entity Framework Context that the Service exposes
public class Listings : DataService< ListingsEntities >
{
  public static void InitializeService(DataServiceConfiguration config)
  {
   // These lines set the access rights to "Read Only" for both entity sets
   config.SetEntitySetAccessRule("Listings", EntitySetRights.AllRead);
   config.SetEntitySetAccessRule("Properties", EntitySetRights.AllRead);

   // There are currently no service operations in the service 
   config.SetServiceOperationAccessRule("MyServiceOperation", 
    ServiceOperationRights.All);

   config.DataServiceBehavior.MaxProtocolVersion =
    DataServiceProtocolVersion.V2;
  }
}

讓我們再仔細看看圖 2 中的 InitalizeService 方法還進行了什麼操作。此方法為服務將提供的兩個實體集調用 SetEntitySetAccessRule,並且設置對 AllRead 的訪問權限。這告訴服務讓兩個實體集完全可讀,但不允許進行插入、更新或刪除。這是控制對服務的訪問的極佳方法。WCF 數據服務還支持名為“查詢偵聽器”的方法,允許服務作者在每個實體集的基礎上為服務配置更精細的訪問控制。將 Listings.svc 文件設置為項目起始頁,並運行項目。這將打開一個浏覽器窗口並顯示服務文檔,如圖 3 所示。

圖 3 SharePoint 站點的服務文檔

OData URI 約定

服務文檔列出了服務提供的實體集。請記住,您可以使用強大的 URI 語法(是 OData 協議的可選部分)來訪問此服務中的資源。讓我們快速了解一下此服務的 URI 語法。若要訪問每個實體集的源,您需要將實體集的名稱附加到服務的基本 URI 中,例如 http://myhost/Listings.svc/Properties 將指向 Properties 實體集中的一組實體。

還可以使用單個實體的鍵值來指向該實體,例如 URI http://myhost/ Listings.svc/Properties(0) 將指向 ID = 0 的房產。您可以將關系名稱附加到 URI 末尾,以指向此實體與其他實體或實體集的關系,因此 http://myhost/ Listings.svc/Properties(0)/Listings 將指向與 ID = 0 的房產實體相關的一組銷售清單。使用此語法,可以浏覽關系的很多層級。

URI 還定義了很多可以附加到 URI 的查詢選項,以便在一定程度上修改基本查詢,其中每個查詢選項都定義為名稱/值對。例如,附加查詢選項 $top=10 後,就將查詢限制為僅包含結果中的前 10 個實體。圖 4 列出了 URI 語法中所有可用的查詢選項。

圖 4 OData 查詢選項

$top=n 將查詢限制為前 n 個實體。 $skip=n 跳過集中的前 n 個實體。 $inlinecount=allpages 在結果中包含集中所有實體的計數。 $filter=<表達式> 可以用表達式限制查詢返回的結果(例如:$filter=Status eq 'Available' 將結果限制為具有 Status 屬性且此屬性值為 Available 的實體)。 $orderby=<表達式> 按照實體的一組屬性對結果進行排序 $select=<表達式> 指定要返回的實體的屬性子集。 $format 指定要返回的源的格式(ATOM 或 JSON)。此選項在 WCF 數據服務中不受支持。

從 SharePoint 提供數據

在前述部分中,我為您展示了如何提供關系數據庫中存儲的數據,以及房地產網站的房產和銷售清單信息。讓我們假設我還有負責出售房產的代理人信息,但這些數據存儲在 SharePoint 站點中。Microsoft SharePoint 2010 提供了相應功能,可以將所有列表和列表中的文檔作為 OData 源提供。這非常適合該房地產網站,因為這意味著該公司員工輸入的代理人信息可作為 OData 源使用,可以包含在我構建的銷售清單應用程序中。使用 SharePoint 接口負責輸入和更新此數據的用戶不必更改其工作流程來適應我的應用程序。輸入到公司 SharePoint 站點的數據在即將創建的 Listings 應用程序中實時可用。

圖 5 顯示了簡單的 SharePoint 門戶,房地產代理人可用來記錄和更新其聯系信息。

圖 5 代理人信息的 SharePoint 站點

在 SharePoint 系統中安裝適用於 .NET Framework 3.5 SP1 的 ADO.NET 數據服務更新後,對於每個將清單數據作為 OData 源提供的站點來說,將有一個新的 HTTP 端點可以使用。由於 OData 源要使用 HTTP 進行訪問,因此使用 Internet Explorer 即可查看。圖 6 顯示了 SharePoint 中代理人清單的源。

圖 6 SharePoint 代理人服務的代理人源

使用來自 OGDI 的參考數據

默認情況下,OData 源將為源返回 ATOM 表示形式,當從 Web 浏覽器訪問時,結果將是 ATOM 源。如果請求的接受標頭改為“application/json”,結果將是 JSON 源形式的相同數據。

圖 6 中的源以代表一組實體的 <feed> 元素開始。每個源中包含了一組 <entry> 元素,每個元素都代表源中的一個實體(前三個實體元素已折疊,以便在一個屏幕中顯示整個源)。

在此示例中,實體有一個已定義的並發標記,因此源中的每個實體都有一個 etag 屬性。當對所請求的實體進行變更時,數據服務使用 etag 標記來強制執行並發檢查。每個實體都使用 <entry> 標記進行了格式化,並且由一組鏈接組成。這些鏈接包含編輯實體時用到的鏈接以及實體的關系。每個關系鏈接都指向另一個實體或一組實體(分別稱為引用屬性和導航屬性)。每個 <entry> 元素還包括一個 <m:properties> 元素,其中包含實體的基元類型和復雜類型屬性;屬性值由實體的屬性名稱和該屬性的值組成。

Open Government Data Initiative (OGDI) 是構建在 Microsoft Windows Azure 平台上的一項服務,方便政府部門發布各種各樣的公開數據。OGDI 項目提供了一個入門工具包,政府部門可以使用它來提供其數據。例如埃得蒙頓市已使用該入門工具包來提供其政府數據,ogdisdk.cloudapp.net 的一項服務提供了包含華盛頓特區的各種數據的數據集。另一個示例是 Microsoft Codename“Dallas”項目,旨在幫助任何擁有數據集的用戶簡便地將數據作為 Web 服務提供。此項目也構建在 Windows Azure 平台上,使用 OData 來提供數據。這些都是要提供大量參考數據以便進一步由 Web 應用程序使用的高端服務示例。正如我將演示的,當這些服務使用 OData 提供其數據時,通過各種應用程序來使用這些數據是非常簡單的。

如前所述,OGDI 網站提供有關華盛頓特區的可用公開數據。Contoso 的房地產應用程序用於浏覽該區域的銷售清單,當用戶查看特定的區域時,如果可以使用針對該區域的此類參考數據,將非常有幫助。當我為示例應用程序創建客戶端時,我將演示如何包含來自 OGDI 網站的 OData 源,作為應用程序的數據源之一。

其他 OData 生產者

截至目前,我已經展示了從 SQL Server、SharePoint 和網絡上一般的 OData 服務獲得數據的示例,但還有更多選擇存在。基於雲計算的 Windows Azure 平台具有一個表服務,可以提供 Windows Azure 表中存儲的數據,而其 API 是使用 OData 構建的。如前所述,Microsoft Dallas 項目是一個數據市場,可查找和查詢 Dallas 服務提供的數據,而該服務使用 OData 協議提供其數據。OData 的生產者並不僅限於 Microsoft 產品,IBM 最近宣布其 WebSphere eXtreme Scale 7.0 產品現在也支持 OData 協議。

Silverlight 客戶端

Contoso 的房地產查找應用程序現在使用 ASP.NET Web 服務來提供 SQL Server 中的關系數據(有關該公司管理的房地產銷售清單和房產的數據);使用 SharePoint 站點來管理有關公司代理人的數據;使用政府 Web 服務來提供公司推廣的房產所在地區的數據。我要將所有這些數據源合並到一個 Silverlight 應用程序中,用有意義的方式來處理這些數據。

在 Silverlight 3 中,Silverlight SDK 中包含了一個 WCF 數據服務客戶端庫,使得 Silverlight 應用程序可以更容易地與啟用了 OData 的服務通信。為此,在 Visual Studio 的 Silverlight 項目中,右鍵單擊該項目,選擇“添加服務引用”。這將引導您完成創建服務引用的過程。服務引用的主要輸入是要從 Silverlight 應用程序引用的服務的 URI。圖 7 顯示了向 OGDI 示例服務添加服務引用的示例。

圖 7 向 OGDI 示例服務添加服務引用

服務引用向導將創建一個客戶端上下文類,用於與數據服務進行交互。該客戶端上下文從客戶端編程模型提取出與 HTTP 和 URI 相關的細節,使客戶端開發人員只需考慮 C# 類和 XAML。該客戶端上下文還包括一個 LINQ 提供程序實現,因此也支持對代理執行 LINQ 查詢。“添加服務引用”向導還將生成一組客戶端代理類,用於鏡像由被引用的服務提供的類型。創建 OGDI 服務引用後,我還將創建對已創建的 SharePoint 和 Listings 服務的服務引用。此代碼顯示了如何創建用於與這三個 OData 服務進行交互的上下文:

// OGDI service context
OGDIService.dcDataService OGDIService =
  new dcDataService(new Uri(OGDIServiceURI));

// SharePoint service context
AgentsReference.AgentsDataContext agentsService =
  new AgentsReference.AgentsDataContext(new Uri(sharepointServiceURI));

// Listings Service context
ListingReference.ListingsEntities listingsService =
  new ListingReference.ListingsEntities(new Uri(listingsServiceURI));

圖 8 顯示了 Silverlight 房地產 Home Finder 應用程序的梗概。此應用程序將托管在 SharePoint 中,以方便習慣了使用 SharePoint 環境的現有用戶。

圖 8 Contoso Home Finder

圖 9 包含了用於查詢銷售清單服務的代碼,以及將結果綁定到 Home Finder Silverlight 應用程序頂部表格中的代碼。

圖 9 創建客戶端代理上下文

private void getListings()
{
  DataServiceCollection<Listing> listings = new
   DataServiceCollection<Listing>();

  listingsGrid.ItemsSource = listings;

  var query = from listing in
        listingsService.Listings.Expand("Property")
        select listing;
  listings.LoadAsync(query);
}

圖 9 中的代碼創建了被跟蹤的集合 DataServiceCollection,並將該集合綁定到主銷售清單表格的 ItemsSource 屬性。由於此集合實現了變更跟蹤,因此對表格中任何條目的更改都將自動反映在銷售清單集合的實體上。通過調用銷售清單服務上下文的 BeginSaveChanges 方法,表格中的更改可保存到服務中。

在 Silverlight 中,所有的網絡調用都是異步的,因此使用 WCF 數據服務客戶端庫對服務執行的任何操作都需要對操作進行初始調用,然後編寫獨立的回調方法,並傳遞到該方法以處理異步調用的結果。為了改進這種異步調用,DataServiceCollection 類添加了一個方法 LoadAsync,由其執行所有處理異步回調函數的工作並將結果加載到集合中。

在 圖 9 的代碼中,在調用 LoadAsync 之前將集合綁定到表格,因此在異步調用完成之前,值不會加載到集合中。當結果從服務返回時,集合將會引發集合更改事件,表格將捕獲這些事件,並在異步調用完成時顯示結果。

從數據表格選擇銷售清單後,需要查詢 SharePoint 站點以獲取管理該清單的代理人的信息。在此應用程序體系結構中,需要進行第二次查詢,因為銷售清單類型和代理人類型的數據源是相互獨立的,二者之間沒有明顯的關系(如果從模型的角度考慮,此示例涉及兩個完全獨立的模型,模型之間的關系是由客戶端創建並施加的虛擬關系)。

圖 10 顯示了在給定代理人姓名的情況下,如何查詢 SharePoint 服務以獲取代理人實體。從 OGDI 數據中查詢 Home Finder 頁面底部圖表中的鄰居信息時,使用了相似的代碼序列。到目前為止的代碼僅演示了 Silverlight 客戶端的查詢功能,但此客戶端並不僅限於查詢,而是提供了豐富的功能,可以將更改從客戶端寫回服務。

圖 10 執行異步查詢

private void GetAgentData(string agentName)
{
   var query = agentsService.Agents.Where(a => a.FullName == agentName) as
     DataServiceQuery;

   query.BeginExecute(
     AgentQueryCallBack, query);
}

private void AgentQueryCallBack(IAsyncResult result)
{
   Dispatcher.BeginInvoke(() =>
   {
     var queryResult = result.AsyncState as DataServiceQuery<AgentsItem>;
     if (queryResult != null)
     {
       var agents = queryResult.EndExecute(result);
       this.grdAgent.DataContext = agents.First();
     }
   });
}

PowerPivot 中的 OData

PowerPivot 是新的內存中商業智能工具,是 Microsoft Excel 2010 的加載項。有關詳細信息,請訪問 powerpivot.com。該工具支持從數據源導入大型數據集,並執行復雜的數據分析和報告。PowerPivot 可從多種不同的數據源導入數據,包括直接從 OData 源導入。PowerPivot 的“從數據源”選項(如圖 11 所示)可以使用 OData 服務端點作為要導入的源的位置。

圖 11 PowerPivot 從 OData 源導入

圖 12 顯示了根據 OGDI 的華盛頓特區數據源中的犯罪率統計信息摘要繪制的圖表。

圖 12 來自 OData 源的 PowerPivot 圖表

圖 12 中的圖表與前述示例中房地產應用程序使用的數據集相同,顯示了各個區所有數據的摘要。我建議您下載 PowerPivot for Excel 2010,並從位於 ogdi.cloudapp.net/v1/dc 的 OGDI 站點導入數據,體驗一下如何快捷地對這些數據進行豐富的數據分析。

Open Data Protocol Visualizer

對於創建應用程序的外部開發人員來說,盡管其應用程序使用由 OGDI 數據服務提供的數據,但該服務從本質上講是一個“黑箱”。幸運的是 OGDI 服務使用 OData 協議提供其數據,因此不需要了解該服務的內部細節,就能與此服務進行交互。該服務的編程模型是 OData 協議。服務端點描述了數據形式,正如我在上文所述,這就是您與該服務交互所需的全部內容。但是,查看服務中數據的形式並更好地了解服務各部分之間的關系,通常會很有幫助。Open Data Protocol Visualizer 由此應運而生。在 Visual Studio 2010 中,從“工具”|“擴展管理器”菜單項可以調用此程序。圖 13 顯示了該可視化工具的兩個視圖,視圖中顯示的是 OGDI 服務的結構。

圖 13 上部的視圖顯示了整個服務,下部的視圖進行了放大,只顯示了四個框。該可視化工具將實體集表現為框,實體之間的關系用連接框的線條表示。從圖 13 上部的視圖中可以清楚地看到,OGDI 服務完全是扁平的,不包含任何關系,因為各個框之間沒有連接的線條。這只是 OGDI 服務的特點,大多數 OData 服務都不是這樣的。下部的視圖特別顯示了服務中的四個實體集。只需查看該視圖,您就能確定服務提供了有關消防站、小學入學率、透析診所和政府機關位置的數據,以及這些類型的屬性和鍵。

圖 13 OGDI 示例服務的 Open Data Visualizer 視圖

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved