.NET 用戶端程式庫 (ADO.NET 資料服務架構)
ADO.NET 資料服務包含 .NET 用戶端程式庫,可供使用 .NET Framework 和 ADO.NET 資料服務的應用程式使用。使用此用戶端程式庫的應用程式會使用資料服務的結果當做 .NET 物件。關聯周遊是由 Common Language Runtime (CLR) 物件所管理。
.NET 用戶端程式庫會使用 HTTP 和 AtomPub 格式。此用戶端程式庫適用於企業網路和網際網路環境。所需的全部資訊就是資料服務的 HTTP 層級連接 (直接或透過 Proxy)。
System.Data.Services.Client
若要使用此用戶端程式庫,請將 System.Data.Services.Client 組件 (Assembly) 的參考加入至您的專案。此用戶端程式庫可用於任何專案類型,包括 Windows Form、Windows Presentation Foundation 和網站專案。
此用戶端程式庫的兩個主要建構是 DataServiceContext
類別 (Class) 和 DataServiceQuery
類別。DataServiceContext
代表含有指定之資料服務的執行階段內容。雖然資料服務沒有狀態 (Stateless),不過內容具有狀態,而且用戶端的狀態會在互動之間維持,以便支援變更管理等功能。
DataServiceQuery
類別代表針對使用 ADO.NET 資料服務 URI 語法所指定之儲存區的查詢。例如,若要以 .NET 物件的形式來執行查詢並取得結果,請使用 C# 中的 foreach
建構或 Visual Basic 中的 For Each
來列舉查詢物件。
若要將資料服務中定義的每個實體表示成 .NET 物件,您必須針對用戶端應用程式定義對應的類別。其中一個選項是手動定義這些類別。另一個選項是下一個標題所說明的 DataSvcUtil.exe 工具。
下列範例將顯示根據 SQL Server 2005 隨附之 AdventureWorks 範例資料庫中的資料,針對 Address
類別手寫的定義。下列範例會使用 Address
實體以及針對此服務執行查詢的小型程式碼區段。傳回之 Address
的屬性會顯示成輸出。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Services.Client;
namespace DataServiceClient
{
public class Address
{
public int AddressID { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public DateTime ModifiedDate { get; set; }
public string PostalCode { get; set; }
public Guid rowguid { get; set; }
public int StateProvinceID { get; set; }
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button_Click(object sender, EventArgs e)
{
DataServiceContext ctx = new
DataServiceContext(new Uri("https://localhost:1492/AdvWksSales.svc/"));
// This example expects the user to enter
// an integer representing AddressID in textBox1.
DataServiceQuery<Address> query =
ctx.CreateQuery<Address>(
"SalesOrderHeader(45678)/Address");
StringBuilder output = new StringBuilder();
foreach (Address address in query)
{
output.Append("Id: " + address.AddressID +
" Line 1: " + address.AddressLine1 + "\r\n");
}
richTextBox1.Text = output.ToString();
}
輸出如下所示。
Id: 70 Address Line1: 1792 Belmont Rd. City: Monroe
使用 DataSvcUtil 工具
雖然手動撰寫這些類別的方法適用於少數類型,不過當資料服務結構描述更複雜時,要維持的類別數目和大小會變得過於複雜,無法手動維持。此時,較佳的選項是使用名為 DataSvcUtil.exe 的程式碼產生工具 (隨附於 ADO.NET 資料服務)。這項工具會根據資料服務定義產生 .NET 類別。
DataSvcUtil.exe 位於 \WINDOWS\Microsoft.NET\Framework\v3.5\ 目錄中。命令列會接受引數:要產生類型之資料服務的基底 URL。例如,如果 Northwind 服務是在位於 https://localhost:1234/Northwind.svc 的 Visual Studio 開發伺服器中執行,要產生類別的命令列就是:
C:\Program Files\Microsoft Visual Studio 9.0\VC>"C:\WINDOWS\Microsoft.NET\Framework\v3.5\DataSvcUtil.exe"
/out:c:\northwind.cs /uri:https://localhost:1365/Northwind.svc
此命令的輸出是 C# 檔案 (您可以使用 /language:VB
參數來產生 Visual Basic 類型),其中針對資料服務中的每個實體類型各包含一個類別。
產生的類別具有代表基本值和關聯的成員,可簡化導覽物件模型的作業。
ADO.NET 資料服務的 LINQ
除了在 DataServiceContext.CreateQuery
的呼叫中查詢資料服務 (如標題「Microsoft 資料 Web 用戶端」底下所示) 以外,.NET 用戶端程式庫支援使用 Language-integrated Query (LINQ) 的資料服務查詢。如需 LINQ 的詳細資訊,請參閱 LINQ to Entities (英文)。此用戶端程式庫會處理將 LINQ 陳述式 (Statement) 對應至目標資料服務中的 URI 以及擷取指定的資源當做 .NET 物件等詳細資料。下列範例將示範如何使用傳回的結果集 (依照公司名稱排序) 來擷取位於倫敦市的所有客戶。
using System;
using System.Data.Services.Client;
using System.Linq;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
NorthwindEntities ctx = new
NorthwindEntities(
new Uri("https://localhost:1365/Northwind.svc"));
var q = from c in ctx.Customers
where c.City == "London"
orderby c.CompanyName
select c;
foreach (var cust in q)
{
Console.WriteLine(cust.CompanyName);
}
}
}
}
附註 |
---|
可以用 LINQ 語法表示的查詢集合會比在資料服務所使用之具像狀態傳輸 (REST) 架構 URI 語法中啟用的查詢集合更廣泛。如果查詢無法對應至目標資料服務中的 URI,就會擲回例外狀況 (Exception)。如需 REST 的詳細資訊,請參閱 REST 服務和語意 (ADO.NET 資料服務架構)。 |
附註 |
---|
這個標題和下列兩個標題中的範例都會使用 Northwind 範例資料庫。您可以從下列網頁下載 Northwind 範例:https://go.microsoft.com/fwlink/?linkid=24758 (英文)。 |
關聯
物件之間的關聯是由 DataServiceContext
類別所追蹤和管理。您可以「立即」或視需要載入相關聯的物件。「立即」和「延遲」載入將在<ADO.NET Entity Framework>文件的<以物件形式查詢資料和為查詢結果定形>(英文) 底下詳細討論。URL 格式則在包含統一 URI 的簡單資料定址配置 (ADO.NET 資料服務架構)中詳細討論。
若要視需要載入相關聯的實體,您可以使用 DataServiceContext
類別的 LoadProperty
方法。下列範例將示範如何延遲載入與 Category
實體相關聯的 Product
實體。
using System;
using System.Data.Services.Client;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
DataServiceContext ctx = new
DataServiceContext(
new Uri("https://localhost:1365/Northwind.svc"));
DataServiceQuery<Categories> categories =
ctx.CreateQuery<Categories>("/Categories");
foreach (Categories c in categories)
{
Console.WriteLine(c.CategoryName);
ctx.LoadProperty(c, "Products");
foreach (Products p in c.Products)
{
Console.WriteLine("\t" + p.ProductName);
}
}
}
}
}
}
在某些案例中,您可能會需要相關聯的物件,而且想要避免擷取這些物件之額外要求的延遲增加。在此情況下,您可以在 URL 內部使用 expand
選項。用戶端程式庫會辨識出結果同時包含最上層實體和相關聯的實體,並且將所有實體具體化成為物件圖形。這就稱為立即載入。雖然立即載入與上一則範例很相似,不過它會在資料服務的單一往返中載入相關的產品。
下列範例會顯示包含與分類相關之產品的 expand 選項。
using System;
using System.Data.Services.Client;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
DataServiceContext ctx = new
DataServiceContext(
new Uri("https://localhost:1365/Northwind.svc"));
// get a single category
DataServiceQuery<Categories> categories =
ctx.CreateQuery<Categories>("/Categories(1)?$expand=Products");
foreach (Categories c in categories)
{
//Console.WriteLine(c.CategoryName);
richTextBox1.Text = c.CategoryName;
foreach (Products p in c.Products)
{
//Console.WriteLine("\t" + p.ProductName);
richTextBox1.Text = richTextBox1.Text +
"\r\n\t" + p.ProductName ;
}
}
}
}
}
更新支援
若要在資料服務中建立新的執行個體 (Instance),請建立 .NET 物件,然後針對所使用的 DataServiceContext
執行個體呼叫 AddObject
,並傳遞此物件和目標實體集,如下列程式碼片段所示。
using System;
using Microsoft.Data.WebClient;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
DataServiceContext ctx = new
DataServiceContext(
new Uri("https://localhost:1365/Northwind.svc"));
Categories cNew = new Categories();
cNew.CategoryName = "NewCategory1";
cNew.Description = "Add Item Test.";
ctx.AddObject("Categories",cNew);
ctx.SaveChanges();
}
}
}
在資料服務中建立或修改實體之後,此服務會傳回實體的全新複本,包括可能已經由於資料庫中的觸發程序或自動產生索引鍵而更新的任何屬性值。用戶端程式庫會自動使用這些新的值來更新 .NET 物件。
若要修改現有的實體執行個體,請先查詢該物件、針對其屬性進行所需的變更,然後呼叫 UpdateObject
方法,以便向用戶端程式庫指出它需要傳送該物件的更新。
附註 |
---|
下列範例會使用由上述程式碼產生工具所建立而且衍生自 |
下列範例會顯示使用 UpdateObject
方法的更新語法。
using System;
using Microsoft.Data.WebClient;
using System.Linq;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
NorthwindEntities ctxN =
new NorthwindEntities(
new Uri("https://localhost:1365/Northwind.svc"));
var c1 = (from c in ctxN.Categories
where c.CategoryName == "NewCategory1"
select c).First();
c1.CategoryName = "UpdatedCategory";
//ctxN.AttachTo("Categories", c1);
ctxN.UpdateObject(c1);
ctxN.SaveChanges();
}
}
}
若要刪除實體執行個體,請針對 DataServiceContext
物件呼叫 Delete
方法。
變更會在 DataServiceContext
執行個體中追蹤,但是不會立即傳送至伺服器。一旦您針對指定的活動完成所需的變更之後,請呼叫 SaveChanges
,以便將所有變更送出至資料服務。
關聯更新
更新基礎結構也可以管理關聯變更。您可以變更 .NET 物件之間的關聯,而且可以讓用戶端程式庫在 HTTP 介面中將這些變更反映成關聯建立或刪除作業。為了說明這點,下列範例會在 Northwind 資料庫中建立 Product
,並將它與現有的 Category
產生關聯。分類和產品會參與一對多關聯。因此,指定的產品具有單一特定分類。下列程式碼將示範如何使用 Add
方法,將 Product
關聯加入至 Category
。
using System;
using Microsoft.Data.WebClient;
using System.Linq;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
NorthwindEntities ctx = new
NorthwindEntities(new Uri(https://localhost:1234/Northwind.svc));
var c1 = (from c in ctx.Categories
where c.CategoryName == "UpdatedCategory"
select c).First();
Products p = new Products();
p.ProductName = "TestProduct";
p.Discontinued = false;
p.QuantityPerUnit = "1";
p.ReorderLevel = 100;
p.UnitPrice = 1.1M;
p.UnitsInStock = 200;
p.UnitsOnOrder = 0;
ctx.AddObject("Products", p);
// Add binding between product and category
p.Categories = c1;
ctx.SetLink(p, "Categories", c1);
ctx.SaveChanges();
Console.ReadKey();
}
}
使用雙向關聯來管理任意物件圖形的修改項目是一項複雜的問題。不過,有一些進階的程式庫 (例如 ADO.NET Entity Framework) 會提供非常豐富而且高度一致的狀態管理員,可用於處理部分具體化的圖形。相較之下,ADO.NET 用戶端程式庫是針對最少使用量所設計,而且只能提供將資料服務作業對應至 .NET 物件所需的基本型別。
下圖將顯示來源和目標實體,以及需要各種關聯更新方法的實體狀態。請遵循水平和垂直軸來找出可呼叫的方法。
目標 → 來源 ↓ |
null |
Added |
Modified |
Deleted |
Unchanged |
Added |
SetLink |
AddLink SetLink |
AddLink SetLink |
N/A |
AddLink SetLink |
Modified |
SetLink |
AddLink SetLink |
AddLink AttachLink DeleteLink SetLink |
DeleteLink |
AddLink AttachLink DeleteLink SetLink |
Deleted |
SetLink |
N/A |
DeleteLink |
DeleteLink |
DeleteLink |
Unchanged |
SetLink |
AddLink |
AddLink AttachLink DeleteLink SetLink |
DeleteLink |
AddLink AttachLink DeleteLink SetLink |
只有當來源和目標都處於未變更狀態時,AttachLink 才能運作。AttachLink 不會保存關聯性。除非所需的結果是 SavingChanges 的呼叫無法儲存連結,否則請勿使用 AddLink。
如果您擁有 Products
與 Catagories
之間的關聯性,而且 Products.Categories
屬性是集合,請使用 objCtx.AddLink(prod, "Categories", c1)
。
如果 Products.Cateories
只是參考,請使用 objCtx.SetLink(prod, "Categories", c1);
處於 Added
狀態之來源實體的 SaveChanges 期間,HTTP POST 包含處於已修改或未變更狀態之其他實體的連結。
AttachLink 方法會建立處於 EntityStates.Unchanged
狀態的連結。這是一項機制,可讓使用者建立由不會傳送至伺服器之內容所追蹤的連結。
用戶端程式庫中的驗證
.NET 用戶端程式庫會使用 HTTP 通訊協定 (Protocol) 的 .NET Framework 支援。最重要的是,當您提供了一組認證時,此架構基礎結構會自動透過 HTTP 處理驗證配置。
根據預設,此用戶端程式庫不會提供任何認證給 HTTP 堆疊。不過,您可以在 DataServiceContext
中設定 Credentials 屬性,以便指向實作 ICredentials
介面的物件。如需認證的詳細資訊,請參閱 WebRequest.Credentials 。
與資料服務的非同步互動
相較於在內部網路中執行的應用程式,Web 應用程式必須設計成可容納用戶端與伺服器之間更高的延遲。使用與伺服器的非同步互動有助於在應用程式等候伺服器的回應時,維持有回應的使用者介面。
在這個版本中,ADO.NET 用戶端程式庫針對 DataServiceContext
類別中許多可用的作業支援非同步作業模式,例如擷取和儲存變更。下列範例將顯示如何在程式碼中使用用戶端程式庫的非同步 API。
using System;
using Microsoft.Data.WebClient;
using System.Linq;
using NorthwindModel;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
NorthwindEntities ctx = new
NorthwindEntities(new Uri(https://localhost:51905/nw.svc));
DataServiceQuery<Customers> q = ctx.Customers;
q.BeginExecute(
delegate(IAsyncResult ar)
{
foreach (Customers c in q.EndExecute(ar))
{
Console.WriteLine(c.CompanyName);
}
},
null);
Console.ReadKey();
}
}
}
另請參閱
概念
HttpWebRequest GET (ADO.NET 資料服務架構)
建立 ADO.NET 資料服務