创建 Silverlight 应用程序 (WCF Data Services)

重要

Windows Phone 应用程序不支持 Silverlight 的 WCF 数据服务 5.0 客户端库。您必须改用 OData Client Library for Windows Phone(包含在 Windows Phone 7.1 SDK 中)。有关更多信息,请参见 Windows Phone 的开放数据协议 (OData) 概述。目前没有支持 OData v3 的 Windows Phone 客户端库。

Silverlight 的 WCF 数据服务 客户端库生成对支持 OData 协议版本 3 的数据服务的 HTTP 请求,然后将 OData 响应源中的数据转换成客户端上的对象。 客户端库的两大主要类为 DataServiceContext 类和 DataServiceQuery<TElement> 类。 DataServiceContext 类封装针对指定数据服务执行的操作。 基于 OData 的服务是无状态的。 但是,DataServiceContext 类维护客户端上各个数据服务交互之间的实体状态。 这样,客户端可以支持更改跟踪和标识管理等功能。 DataServiceQuery<TElement> 类表示一个针对特定实体集的查询。 有关更多信息,请参见在 .NET Framework 应用程序中使用数据服务 (WCF Data Services)。 有关使用 Northwind 示例数据服务源的应用程序的示例,请参见 Silverlight WCF Data Services 快速入门

备注

使用 Silverlight 的 WCF 数据服务 客户端库时,所有服务请求都是异步进行的。有关更多信息,请参见异步操作(WCF 数据服务)

本主题包含以下各节:

生成客户端数据服务类

可以使用 Visual Studio 中的**“添加服务引用”**对话框添加任何对公开 OData 源的服务的引用。 有关更多信息,请参见生成客户端数据服务类 (WCF Data Services)。 还可以在命令提示符处使用 DataSvcUtil.exe 工具来生成客户端数据服务类。 有关更多信息,请参见如何:手动生成客户端数据服务类(WCF 数据服务)

备注

安装 WCF 数据服务 5.0 版本后,“添加服务引用”工具将自动添加对客户端库 Microsoft.Data.Services.Client.SL.dll 版本的引用,而不是添加对 Silverlight 中包含的 System.Data.Services.Client.dll 版本的引用。如果出于某种原因需要使用早期版本的 Silverlight 客户端,则应手动添加对该客户端库的 Silverlight 版本的引用。有关更多信息,请参见如何:手动生成客户端数据服务类(WCF 数据服务)

访问和更改资源

在基于 Silverlight 的应用程序中,所有针对数据服务的操作都是异步的。 通过使用 DataServiceContextDataServiceQuery<TElement> 类的方法对(分别以 Begin 和 End 开头),可以执行异步操作。 Begin 方法注册一个委托,服务将在操作完成时调用该委托。 应在注册的委托中调用 End 方法以处理来自对完成操作的回调。 在调用 End 方法完成异步操作时,必须从用于开始该操作的那个 DataServiceQuery<TElement>DataServiceContext 实例进行调用。 每个 Begin 方法采用一个 state 参数,该参数可将一个状态对象传递给回调。 此状态对象是以 IAsyncResult 的形式检索的,后者随回调提供,用于调用对应的 End 方法以完成异步操作。 例如,当调用 DataServiceQuery<TElement> 实例上的 BeginExecute 方法时如果提供该实例作为 state 参数,则该 DataServiceQuery<TElement> 实例将以 IAsyncResult 类的形式返回。 随后将使用 DataServiceQuery<TElement> 的这个实例调用 EndExecute 方法以完成查询操作。 有关更多信息,请参见异步操作(WCF 数据服务)

因为 Silverlight 的 WCF 数据服务 客户端库使用网络协议异步访问数据服务,所以必须使用 Dispatcher 类的 BeginInvoke 方法将响应操作正确地封送回基于 Silverlight 的应用程序的主应用程序线程(UI 线程)。 有关更多信息,请参见Synchronizing Data for Multithreading

查询资源

利用 Silverlight 的 WCF 数据服务 客户端库,可以使用熟悉的 .NET Framework 编程模式针对 OData 数据服务执行查询,包括使用 语言集成查询 (LINQ) 查询。 当调用 DataServiceQuery<TElement>DataServiceContext 上的 BeginExecute 方法时,客户端库将查询或统一资源标识符 (URI) 转换为 HTTP GET 请求消息。 该客户端库接收相应的响应消息并将该消息转换为客户端数据服务类的实例。 DataServiceQuery<TElement> 所属的 DataServiceContext 跟踪这些类。 有关更多信息,请参见如何:执行异步数据服务查询(WCF 数据服务)

在某些方案中,不仅知道查询返回的源中的实体数,还要知道实体集中实体的总数,这一点非常有帮助。 调用 DataServiceQuery<TElement> 上的 IncludeTotalCount 方法可请求在查询结果中包含集中实体的总数。 在这种情况下,返回的 QueryOperationResponse<T>TotalCount 属性返回集中实体的总数。 还此外,还可以使用 AddQueryOption 方法向查询添加 OData 支持的任何其他查询选项。 有关更多信息,请参见查询数据服务(WCF 数据服务)

LINQ 查询

因为 DataServiceQuery<TElement> 类实现 LINQ 定义的 IQueryable<T> 接口,所以 Silverlight 的 WCF 数据服务 客户端库可以将针对实体集数据的 LINQ 查询转换为一个 URI,该 URI 表示针对数据服务资源计算的查询表达式。 例如,下面的 LINQ 查询返回的源是使用 CustomerID 属性值筛选的 Order 实体集合,此属性值是用户在 customerId 文本框中输入的。

' Define a query that returns orders for a give customer.
Dim query = From orderByCustomer In context.Orders _
                Where orderByCustomer.Customer.CustomerID = _
                Me.customerId.Text _
                Select orderByCustomer
// Define a query that returns orders for a give customer.
var query = from orderByCustomer in context.Orders
            where orderByCustomer.Customer.CustomerID == this.customerId.Text
            select orderByCustomer;

加载延迟的内容

默认情况下,WCF 数据服务 会限制查询返回的数据量。 不过,如果需要,您可以从该数据服务显式加载其他数据,包括相关实体、分页响应数据以及二进制数据流。 执行查询时,仅返回所处理实体集中的实体。 例如,当针对 Northwind 数据服务的某个查询返回 Customers 实体时,默认情况下不会返回相关的 Orders 实体,即使 Customers 和 Orders 之间存在关系也是如此。 相关实体可与原始查询(预先加载)一起加载,也可逐个加载(显式加载)。 有关更多信息,请参见加载延迟的内容(WCF 数据服务)。 当使用 Silverlight 客户端和 DataServiceCollection<T> 时,可通过调用 LoadAsync 加载导航属性相关实体的集合。

提示

在确定相关实体的加载模式时,需考虑在消息大小和数据服务请求数之间权衡性能。

如果在数据服务中启用了分页,当返回的条目数超过分页限制时,必须从数据服务显式加载后续数据页。 因为无法提前确定何时进行分页,建议使 Silverlight 客户端应用程序能够对分页 OData 源进行正确处理。 有关如何处理分页响应的示例,请参见如何:将数据服务数据绑定到控件(Silverlight 客户端)查询数据服务(WCF 数据服务)

查询投影

投影在OData 中提供了一种机制,可通过指定仅在响应中返回实体的某些属性来减少查询返回的源中的数据量。 有关更多信息,请参见 OData:Select 系统查询选项 ($select)。 可以使用 select 子句(在 Visual Basic 中为 Select)将投影子句添加到 LINQ 查询。 可以将返回的实体数据投影到客户端上的实体类型或非实体类型。 对非实体类型所做的更改无法保存到数据服务。 例如,下面的 LINQ 查询将 Customer 数据投影到客户端上一个新的 CustomerAddress 实体类型中。

Dim query = From c In context.Customers _
                    Where c.Country = "Germany" _
                    Select New CustomerAddress With
                        {.CustomerID = c.CustomerID, _
                         .Address = c.Address, _
                         .City = c.City, _
                         .PostalCode = c.PostalCode, _
                         .Country = c.Country _
                        }
var query = from c in context.Customers
            where c.Country == "Germany"
            select new CustomerAddress
            {
                CustomerID = c.CustomerID,
                Address = c.Address,
                City = c.City,
                PostalCode = c.PostalCode,
                Country = c.Country
            };

重要

保存对投影的类型所进行的更新时,数据服务中可能会发生数据丢失。有关更多信息,请参见 WCF 数据服务 客户端文档中的投影注意事项

有关更多信息,请参见如何:投影数据服务查询结果(Silverlight 客户端)

修改资源和保存更改

通过手动执行 DataServiceContext 上的以下方法,可使客户端跟踪您报告的实体更改:

客户端利用这些方法可跟踪已添加和删除的实体以及您对属性值或对实体实例之间关系的更改。 使用**“添加服务引用”**对话框生成客户端数据服务类时,还在生成的 DataServiceContext 类中为每个实体创建 AddTo 方法。 使用这些方法可以将新的实体实例添加到实体集中,并将添加操作报告给上下文。 当调用 BeginSaveChangesEndSaveChanges 方法时,这些跟踪的更改将异步发送回数据服务。

使用 AddObject 方法或适当的 AddTo 方法添加新实体时,不会自动定义新实体和相关实体之间的任何关系。 可创建和更改实体实例之间的关系,并让客户端库在数据服务中反映这些更改。 实体之间的关系在模型中定义为关联,DataServiceContext 在上下文中以链接对象的形式跟踪每个关系。 WCF 数据服务 提供 DataServiceContext 类的下列方法以创建、修改和删除这些链接:

有关更多信息,请参见更新数据服务 (WCF Data Services)

使用二进制数据

OData 定义一种机制,用于访问自己所属实体之外的二进制数据。 这样,OData 服务可以公开大型二进制数据,使其作为属于媒体链接项的媒体资源。 Silverlight 的 WCF 数据服务 客户端可使用来自 OData 服务的媒体资源作为二进制流。 若要访问该二进制流,请调用跟踪作为媒体链接项实体的 DataServiceContext 实例上的 BeginGetReadStream 方法。 当在回调返回的 DataServiceContext 实例上调用 EndGetReadStream 方法时,此异步方法返回一个 DataServiceStreamResponse 对象。 同样,当调用 SetSaveStream 方法时,以及调用 BeginSaveChangesEndSaveChanges 方法后,会将媒体资源发送到 OData 服务。 有关更多信息,请参见如何:访问流形式的二进制数据(Silverlight 客户端)

数据绑定

Silverlight 的 WCF 数据服务 客户端支持使用 DataServiceCollection<T> 类将数据绑定到控件上。 此类继承自 ObservableCollection<T>,表示一个动态数据集合,在添加项或移除项时,此集合将提供通知。 这些通知使 DataServiceContext 能够自动跟踪更改,您不必显式调用更改跟踪方法。 DataServiceCollection<T> 是基于 DataServiceQuery<TElement> 定义的。 此查询在执行时提供集合的对象。

LoadAsync 方法用来异步执行查询,并将结果加载到集合。 此方法可确保将结果封送到正确的线程,您无需使用 Dispatcher。 使用 DataServiceCollection<T> 的实例进行数据绑定时,客户端确保 DataServiceContext 跟踪的对象保持与绑定 UI 元素中的数据同步。 您无需手动向 DataServiceContext 报告绑定集合中实体的更改。 有关更多信息,请参见如何:将数据服务数据绑定到控件(Silverlight 客户端)

跨域执行

Silverlight 可以访问单独域中承载的服务。 必须通过在服务器部署跨域策略文件来显式启用这种访问。 此功能包含在 Silverlight 客户端 HTTP 实现中。

备注

在允许 Silverlight 客户端跨域访问 Web 服务前,需要了解重要的安全注意事项。有关更多信息,请参见 HTTP Communication and Security with Silverlight

对于大多数数据服务请求,Silverlight 的 WCF 数据服务 客户端使用 XMLHTTP 实现。 但是,当 WCF 数据服务 客户端检测到跨域请求时,它自动切换为使用 Silverlight 客户端 HTTP 实现。

备注

仅当 HttpStack 属性设置为 Auto 时,客户端才会自动切换为 HTTP 实现。

有关如何配置数据服务以允许 Silverlight 应用程序发起跨域请求,请参见文章 Using the ADO.NET Data Services Silverlight Client in X-Domain and Out-of-Browser Scenarios(在 X-Domain 和浏览器外方案中使用 ADO.NET Data Services Silverlight 客户端)。 支持跨域执行是 Silverlight 4 的新增功能。

浏览器外执行

您可以对 Silverlight 应用程序进行配置,以便用户从其承载网页安装这些应用程序并在浏览器外部运行。 Silverlight 的 WCF 数据服务 客户端支持浏览器外执行。 当 WCF 数据服务 客户端检测到应用程序在浏览器外部运行时,它自动切换为使用 Silverlight 客户端 HTTP 实现。 跨域执行时也会发生此行为,但是不需要跨域策略文件。 有关更多信息,请参见Out-of-Browser Support

客户端身份验证

默认情况下,Silverlight 的 WCF 数据服务 客户端使用与 Web 浏览器相同的凭据向数据服务提出请求,并由 Web 浏览器管理身份验证。 但是,如果需要跨域请求才能访问数据服务或当 Silverlight 应用程序在 Web 浏览器外部运行时,可以在提出请求时指定提供的凭据。 在这些情况下,客户端自动使用 Silverlight 客户端 HTTP 实现提出请求,并使用默认凭据进行身份验证。 但是,如果 UseDefaultCredentials 属性设置为 false,在向数据服务进行身份验证时,客户端将使用分配给 Credentials 属性的 ICredentials

备注

用户凭据应仅在执行过程中请求并且不应缓存。必须始终安全地存储凭据。

通过要求应用程序使用 Silverlight 客户端 HTTP 实现,也可以提供凭据。 为此,必须将 HttpStack 属性的值设置为 ClientHttp。 下面的代码确保在访问数据服务时使用执行过程中用户提交的凭据。

' Select the client HTTP stack and set the credentials.
context.HttpStack = HttpStack.ClientHttp
context.UseDefaultCredentials = False
context.Credentials = _
    New NetworkCredential(userName, password, domain)
// Select the client HTTP stack and set the credentials.
context.HttpStack = HttpStack.ClientHttp;
context.UseDefaultCredentials = false;
context.Credentials = 
    new NetworkCredential(userName, password, domain);

当未使用 Silverlight 客户端 HTTP 实现时,如果将 UseDefaultCredentials 属性的值设置为 false,执行过程中会引发异常。 如果 UseDefaultCredentials 的值为 true,即使设置了 Credentials 属性,也会使用默认凭据。

备注

使用基本和摘要式身份验证发送的数据不会加密,因此攻击者会看到数据。此外,基本身份验证凭据(用户名和密码)是以明文形式发送的,会被截取。

有关更多信息,请参见如何:为数据服务请求指定客户端凭据(Silverlight 客户端)。 有关如何从 Silverlight 应用程序访问使用 ASP.NET 窗体身份验证的数据服务的示例,请参见文章 Using the ADO.NET Data Services Silverlight Client Library in X-Domain and Out-of-Browser Scenarios – II (Forms Authentication) (在 X-Domain 和浏览器外运行方案中使用 ADO.NET Data Services Silverlight 客户端库 – II(窗体身份验证))。