如何创建使用 POCO 定义的实体的域服务
本主题说明如何使用 WCF RIA Services 来创建使用纯旧式 CLR 对象 (POCO) 的域服务。本主题旨在说明如何构造非常基本的基于 POCO 的 RIA Services 应用程序,该应用程序将专门说明在该过程的不同步骤中使用 RIA Services 工具(向导和对话框)时会发生的具体情况。从 POCO 提供的数据可用于从后端数据库上的依赖项中释放应用程序,以便用于可移植性或数据安全性,或者用于测试目的。具有 POCO 定义的实体的 RIA Services 完全支持自动生成的客户端代码,就像对于 Linq to SQL 或 Linq to 实体框架一样。实际上,RIA Services 对数据源而言是不可知的,因此,该 POCO 类可以在以后由从某个其他源(例如数据库)访问数据的组件替换,而无需更改该域服务本身。
本文介绍的过程除了要求 WCF RIA Services 之外,还要求若干必备程序,例如 Visual Studio 2010 和 Silverlight Developer 运行时及 SDK。但 WCF RIA Services 工具包不是必需的。有关满足上述各必备程序的详细说明,请参见WCF RIA Services 的必备条件节点内的主题。在继续此操作指南主题之前,请按照此处提供的说明安装所需的程序,以确保您尽可能少地遇到问题。
创建 RIA Services 解决方案
通过依次选择**“文件”、“新建”和“项目”**,在 Visual Studio 2010 中创建新的 RIA Services 项目。
此时将出现**“新建项目”**对话框。
从**“已安装的模板”的“Silverlight”组中选择“Silverlight 应用程序”**模板,然后将新项目命名为 RIAServicesPocoExample。
单击**“确定”**。
此时将出现**“新建 Silverlight 应用程序”**对话框。
选中对话框底部附近的**“启用 WCF RIA Services”**复选框。选中此复选框可在客户端项目和服务器项目之间创建 RIA Services 链接。为了启用此连接,此工具添加了对客户端项目的以下引用:
System.ComponentModel.DataAnnotations
System.Runtime.Serialization
System.ServiceModel.dll
System.ServiceModel.DomainServices.Client
System.ServiceModel.DomainServices.Client.Web
System.ServiceModel.Web.Extensions
System.Windows.Browser
单击**“确定”**创建解决方案。
该解决方案包含两个项目:一个客户端项目和一个服务器项目。
RIAServicesPocoExample:包含用于创建表示层的 Silverlight 代码的客户端项目。
RIAServicesPocoExample.Web:包含中间层代码服务器项目。
创建域服务
右击服务器项目,依次选择**“添加”和“新建项”**。
在类别列表中,选择**“Web”,然后选择“域服务类”**模板。
将类命名为 SovereignDomainService.cs(或 SovereignDomainService.vb)。
单击**“添加”**。
此时将出现**“添加新的域服务类”**对话框。
确保选中**“启用客户端访问”**框。
请注意,**“可用 DataContext/ObjectContext 类”的下拉菜单上的唯一可用选项是“<空域服务类>”实体,并且您无法选中“为元数据生成关联类”**复选框,因为没有可用于将服务与之关联的数据上下文。
单击**“确定”**。
此向导执行若干工作。它使用关联的特性和
using
语句在一个新的 SovereignDomainService.cs (or SovereignDomainService.vb) 文件中生成一个空的SovereignDomainService
类。它还将对服务项目和配置元素的四个程序集引用添加到 Web.config 文件。为观察此情况,如果 SovereignDomainService.cs(或 SovereignDomainService.vb)文件尚未自动打开,则打开该文件。请注意,此文件具有以下特征:
using
语句已添加:using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server
SovereignDomainService
类派生自 DomainService 类,后者是 RIA Services 框架中的抽象基类。这是在 RIA Services 中公开的所有域服务的基类。SovereignDomainService
类用 EnableClientAccessAttribute 特性进行标记,以便指示它对客户端层可见。
请注意,以下引用已由向导添加到服务项目:
System.ComponentModel.DataAnnotations
System.Runtime.Serialization
System.ServiceModel.DomainServices.Hosting
System.ServiceModel.DomainServices.Server
最后,打开 Web.config 文件并检查向导已添加的新元素。
<configuration> <system.webServer> <modules runAllManagedModulesForAllRequests="true"> <add name="DomainServiceModule" preCondition="managedHandler" type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> </modules> <validation validateIntegratedModeConfiguration="false" /> </system.webServer> <system.web> <httpModules> <add name="DomainServiceModule" type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> </httpModules> <compilation debug="true" targetFramework="4.0" /> </system.web> <system.serviceModel> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" /> </system.serviceModel> </configuration>
除了针对 .NET Framework 4.0 的配置元素外,上述每个元素都已由**“添加新的域服务类”**对话框添加。这些元素实现不同的 Internet Information Server (IIS) 承载和 ASP.NET 选项。
该向导在 IIS 7 承载所要求的
<system.webserver>
部分中添加一个<modules>
元素。该向导在 IIS 6 承载所要求的
system.web
部分中添加<httpModules>
元素的<add>
元素。RIA Services 域服务是 Windows Communication Foundation (WCF) 服务,并且在与 ASP.NET 一起承载时需要承载在 ASP.NET 兼容模式下。此要求不能在代码中设置并且必须在 Web.config 文件中指定。通过在
<system.serviceModel>
部分的<ServiceHostingEnvironment>
元素中将aspNetCompatibilityEnabled
属性设置为 true,启用 ASP.NET 兼容模式。
添加 POCO 类
此过程描述如何向 RIA Services 框架指出 POCO 类要用作实体类型。实体类型向应用程序的数据模型提供数据结构,并且每个实体类型都需要具有唯一的实体键。数据的结构由其包含的属性集指定。通过委托一个或一组属性(这些属性必须为每个实体对象都提供一个唯一名称,该名称将该实体对象与相同类型的其他实体区分开来),提供实体键。这通常是通过使用元数据的某种形式的变体指定的。此过程通过将
[Key]
特性应用于某一属性来执行此操作,实际上该操作就是应用一个特性,该特性指示 RIA Services 框架该 POCO 类的实例是实体对象。打开 SovereignDomainSevice.cs 文件。
在 RIAServicesPocoExample.Web 命名空间范围内的无存根
SovereignDomainService
类之下,为Sovereign
类添加以下代码:public class Sovereign { [Key] public int UniqueId { get; set; } public string Name { get; set; } public string House { get; set; } public string Dominion { get; set; } public int ReignStart { get; set; } public int ReignEnd { get; set; } public string Sobriquet { get; set; } }
在本示例中,
UniqueId
属性是为Sovereign
类型的每个实体对象提供唯一名称的实体键。[Key]
特性在 System.ComponentModel.DataAnnotations 程序集中定义,该程序集已添加到服务器项目,该项目为包含它的相应命名空间具有using
语句。该实体键也可以在元数据文件中或以其他方式指定,但直接在 POCO 类中指出实体键是一种十分简便的方式。将
FetchSovereigns()
方法添加到返回Sovereign
实例的列表的Sovereign
类:public List<Sovereign> FetchSovereigns() { List<Sovereign> sovereignList = new List<Sovereign> { new Sovereign() {UniqueId = 1, Name = "John", House = "Plantagenet", Dominion = "Angevin Empire", ReignStart = 1167, ReignEnd = 1216, Sobriquet = "Lackland" }, new Sovereign() {UniqueId = 2, Name = "Charles", House = "Stuart", Dominion = "England, Scotland, & Ireland", ReignStart = 1625, ReignEnd = 1649, Sobriquet = "The Martyr" }, new Sovereign() {UniqueId = 3, Name = "William", House = "Dunkeld", Dominion = "Scotland", ReignStart = 1165, ReignEnd = 1249, Sobriquet = "The Lion" }, new Sovereign() {UniqueId = 4, Name = "Elizabeth", House = "Tudor", Dominion = "England", ReignStart = 1555, ReignEnd = 1609, Sobriquet = "The Virgin Queen" }, new Sovereign() {UniqueId = 5, Name = "Ivan", House = "Vasilyevich", Dominion = "Russia", ReignStart = 1533, ReignEnd = 1584, Sobriquet = "The Terrible" }, new Sovereign() {UniqueId = 6, Name = "Charles", House = "Valois", Dominion = "France", ReignStart = 1380, ReignEnd = 1422, Sobriquet = "The Mad" } }; return sovereignList; }
定义域服务
此过程描述如何在可从客户端访问的域服务中创建一个查询,以便从 POCO 定义的实体中检索数据。RIA Services 框架需要知道其哪些方法要在客户端上可用作查询以及是否存在用于实现此目的的命名约定。以
Get
开头并且返回IEnumerable<EntityType>
或IQueryable<EntityType>
的方法名称由 RIA Services 框架作为查询识别。提示: IQueryable 派生自 IEnumerable。将 IEnumerable 用于内存中集合(例如,我们的 POCO 定义的实体)并且在访问 SQL 数据库之类的基础或远程数据源时使用 IQueryable。 将
GetSovereign()
方法添加到SovereignDomainService
类。public IEnumerable<Sovereign> GetSovereigns() { Sovereign sovereign = new Sovereign(); return sovereign.FetchSovereigns(); }
这将从集合中返回所有 sovereign 实体。但是,通常我们仅想要返回实体的子集。为阐明这一点,修改此查询以便只从列表中返回在中世纪统治国家的君主,即
sovereign.ReignEnd
<= 1500。下面的代码实现此目的:public IEnumerable<Sovereign> GetSovereignsByReignEnd(int ReignedBefore) { Sovereign sovereign = new Sovereign(); return sovereign.FetchSovereigns().Where<Sovereign>(p => p.ReignEnd <= 1500); }
生成 (Ctrl+Shift+B) 解决方案以便创建自动生成的客户端代理代码。
在**“解决方案资源管理器”中,选择 RIAServicesPocoExample 客户端项目并且单击窗口顶部的“显示所有文件”**图标,然后在 Generated_Code 文件夹中检查 RIAServicesPocoExample.Web.g.cs 文件。检查此文件中自动生成的代码并且注意以下项:
从 WebContextBase 类派生的
WebContext
类将生成并用于管理应用程序上下文。将为域服务所公开的实体生成派生自 Entity 类的
Sovereign
类。客户端项目中的Sovereign
实体类匹配服务器上的Sovereign
实体。将生成派生自 DomainContext 类的
SovereignDomainContext
类。此类具有一个名为GetSovereignsByReignEndQuery
的方法,该方法对应于域服务中创建的查询方法。
在 Silverlight 客户端中显示查询结果
打开 MainPage.xaml。
从左侧的**“工具箱”**中,将 DataGrid 控件拖动到 XAML 视图中的 Grid 元素内。
从**“工具箱”拖动“DataGrid”**控件将导致命名空间
using System.Windows.Controls
语句添加到 MainPage.xaml.cs 文件,并且导致对 System.Windows.Controls.Data 和 System.Windows.Controls.Data.Input 程序集的引用自动添加到客户端项目。警告: 如果添加 DataGrid 而不从“工具箱”拖动它,则必须将对程序集的引用添加到客户端项目,并手动将 using 语句添加到代码隐藏文件中。 将
AutoGeneratedColums
的值更改为 True,将DataGrid
元素命名为SovereignGrid
,并调整Height
和Width
,如下面的 XAML 所示。<Grid x:Name="LayoutRoot" Background="White"> <sdk:DataGrid AutoGenerateColumns="True" Height="200" HorizontalAlignment="Left" Margin="157,86,0,0" Name="SovereignGrid" VerticalAlignment="Top" Width="600" /> </Grid>
打开 MainPage.xaml.cs 文件。
向
using
(C#) 或Imports
(Visual Basic) 添加两个语句:using RIAServicesPocoExample.Web;
和using System.ServiceModel.DomainServices.Client;
。RIAServicesPocoExample.Web 命名空间是一个包含为 RIAServicesPocoExample.Web.g.cs(或 RIAServicesPocoExample.Web.g.vb)中的客户端项目生成的代码的命名空间。
若要实例化
SovereignDomainContext
,请在MainPage
类中添加代码行private SovereignDomainContext _sovereignContext = new SovereignDomainContext();
。通过调用包含 LoadOperation 的
GetSovereignsQuery
方法检索客户实体:LoadOperation<Sovereign> loadOp = this._sovereignContext.Load(this._sovereignContext.GetSovereignsByReignEndQuery(1500));
。使用
SovereignGrid.ItemsSource = loadOp.Entities;
将加载的实体绑定到 DataGrid。总之,MainPage.xaml.cs 文件此时应包含以下代码:
//Namespaces added using RIAServicesPocoExample.Web; using System.ServiceModel.DomainServices.Client; namespace RIAServicesPocoExample { public partial class MainPage : UserControl { private SovereignDomainContext _sovereignContext = new SovereignDomainContext(); public MainPage() { InitializeComponent(); LoadOperation<Sovereign> loadOp = this._sovereignContext.Load(this._sovereignContext.GetSovereignsByReignEndQuery(1500)); SovereignGrid.ItemsSource = loadOp.Entities; } } }
运行 (F5) 该应用程序。
您应该在浏览器中看到该表,表中仅显示中世纪(其统治在公元 1500 年前结束)君主的属性(以字母顺序显示)。