技术开发 频道

Silverlight 3 RIA服务与ADO.NET集成

  【IT168专稿】ADO.NET数据服务是随同微软.NET框架3.5 SP1的推出一同正式发行的一个框架,主要目的是为了简化数据中心型Web服务开发。ADO.NET数据服务框架,提供了一套完整的库,还有集成于Visual Studio中的工具,以及一套定义良好的模式,从而使得以服务方式基于数据模型级提供相关CRUD操作变得与简单的HTTP操作一样得容易。

  ADO.NET数据服务定义了一个协议,用于与基于HTTP以及当前流行的AtomPub和JSON标准的数据服务进行通信。除了支持这些标准之处, ADO.NET数据服务协议还定义了数据承载的格式及资源的寻址模式。由于它的开放与可互操作设计,各种各样的客户端和服务器已开始接纳ADO.NET数据服务协议。总之,基于ADO.NET数据服务,无论是在开发者方面还是在应用者方面都正在不断壮大。

  从多方面来看,ADO.NET数据服务协议模拟了微软.NET RIA服务应用程序中客户端与服务器端层间的通信技术。微软的目标是进一步密切这两种技术间的协同操作,从而使得.NET RIA服务可以使用与ADO.NET数据服务一样的协议。这样一来,对两种技术都有所收益:微软.NET RIA服务应用程序都能够与ADO.NET数据服务的相关内容进行交互(利用现有的客户端技术及开发工具),基于ADO.NET数据服务的服务也能够利用.NET RIA服务提供的业务逻辑模式,丰富的UI控件以及端对端的开发经验。

  根据微软提供的消息,目前上述两种技术间的协作仍处于发展阶段。就目前情况,我们可以实现这两种技术的如下协作开发:

  (1) 扩展现有的微软.NET RIA服务应用程序—通过添加一个ADO.NET数据服务端点,以支持基于ADO.NET数据服务协议的交互操作。

  (2) 使用微软.NET RIA服务模式扩展现有的ADO.NET数据服务以添加业务逻辑支持。

  本文中的示例仅提供针对上述第一种情况的应用展示,即如何把ADO.NET数据服务端点添加一个现有的微软.NET RIA服务应用程序中。另外,由于目前上述两种技术的交互仍处于发展阶段,所以在实际开发环境下还不推荐使用这种解决方案。

  1.创建Silverlight 3示例工程

  (1)打开Visual Studio 2008,选择“文件|新建|项目”菜单命令,打开“新建项目”对话框。

  (2)选择“Silverlight Application”模板,创建一个Silverlight 3项目,并命名为ProductsWithDataService。

  (3)单点“确定”按钮,进入到下一步以选择silverlight应用的宿主网站。从“web project type”下拉列表框中选择“ASP.NET Web Application Project”。选中对话框中最下面的“Enable .NET RIA Services”复选按钮,这样便把RIA框架支持添加到当前解决方案中。

  至此,我们创建了两个工程:

  (1) ProductsWithDataService—此工程中包含了Silverlight代码,这个工程称为客户端工程,这是我们创建的应用程序的客户端层。

  (2) ProductsWithDataService.Web—此工程中包含了ASP.NET web应用程序代码,这个工程称为服务器端工程,这是我们创建的应用程序的中间层。

  至此,一个基本的集成了.NET RIA Services的Silverlight 3示例工程框架生成完毕。

  2.在Web工程上添加ADO.NET实体数据模型

  (1)右键单击web工程ProductsWithDataService.Web,在弹出菜单中选择“添加|新建项”命令。在随后出现的“添加新项”对话框中选择“ADO.NET Entity Data Model”模板,命名为AdventureWorks.edmx,最后单击“添加”按钮退出。

  【提示】为了读者调试方便,我们使用微软提供的SQL Server 2008示例数据库AdventureWorks。在服务器资源管理器中添加AdventureWorks示例数据库连接的操作在此不再赘述,而是直接假设用户创建好了这一连接。

  (2)在随后的ADO.NET实体数据模型向导中,选择“从数据库生成”并单击“下一步”按钮。

  (3)在接下来的“选择您的数据连接”对话框中,选择已有的AdventureWorks数据库连接,并勾选最下方的“将Web.config中的实体连接设置另存为”复选按钮,并改名为AdventureWorks2008Entities。

  (4)在接下来的“选择数据库对象”对话框中,仅选择一个表格Product并输入模型命名空间为AdventureWorks2008Model。最后单击“完成”按钮退出ADO.NET实体数据模型,并保存生成的文件。

  (3)最后,选择菜单“生成|重新生成解决方案”。

  3.使用域服务封装业务逻辑

  (1)仍然右键单击web工程ProductsWithDataService.Web,在弹出菜单中选择“添加|新建项”命令。在随后出现的“添加新项”对话框中选择“Domain Service Classes”模板添加一个域服务,输入名称ProductsDomain.csl,最后单击“添加”按钮退出。

  (2)在随后出现的“Add New Domain Service Class”对话框。在对话框中选择Product实体,并确保选择了“Enable Editing”复选按钮。最后,再选择对话框最下部的“Generate associated classes for metadata”复选按钮,以保证在元数据中生成相关联的类。

  (3)最后,选择菜单“生成|重新生成解决方案”。

  随后打开的ProductsDomain服务类自动生成了针对Product实体集的基本CRUD操作的雏形(换句话说,在实际开发中,我们可以添加自定义的逻辑来重构这里的查询,插入,更新以及删除操作)。而且注意到,因为在上面我们勾选了“Enable client access”复选按钮,所以系统自动在类ProductsDomain的前面添加了一个[EnableClientAccess]属性;这意味着,此类将把自己的方法暴露给客户层使用。

  至此,我们已经搭起一个基本的Silverlight应用的服务器端框架。接下来,我们讨论Silverlight用户界面相关编程。

  4.Silverlight用户界面及基本后台代码编程

  其实,从分层角度来看,就客户端Silverlight项目这边来看,也可进一步分为若干子层。例如,.xaml文件可看作最上面的展示层,相应的后台代码文件.xaml.cs则又是一层。

  (一)XAML设计

  Silverlight 3项目自动生成的主页面文件为MainPage.xaml。现在,打开此文件,并输入如下标记代码:

<UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"  x:Class="ProductsWithDataService.MainPage"
    xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d
="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc
="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable
="d" d:DesignWidth="Auto" d:DesignHeight="Auto">
  
<Grid x:Name="LayoutRoot">
    
<Grid.RowDefinitions>
        
<RowDefinition Height="1*" />
        
<RowDefinition Height="20" />
    
</Grid.RowDefinitions>
    
<data:DataGrid x:Name="productGrid" AutoGenerateColumns="true" Grid.Row="0" />
</Grid>
</UserControl>

  上面的XAML代码非常简单,不再赘述。

  相应的后台代码文件MainPage.xaml.cs的内容如下所示:  

//……(省略默认命名空间引用)
//下面是新添加的命名空间引用
using ProductsWithDataService.Web;
using System.Windows.Ria.Data;
namespace ProductsWithDataService
{
    
public partial class MainPage : UserControl
    {
        ProductsDomain _domain
= new ProductsDomain();
        
public MainPage()
        {
            InitializeComponent();
            this._domain.Load(this._domain.GetProductQuery());
            this.productGrid.ItemsSource
= _domain.Products;
        }
    }
}

  注意,上面代码仅实现了基本的产品信息数据查询与加载,不再赘述。

  现在运行应用程序,你将得到如下所示的快照:

  上面的代码仅仅通过一个网格控件显示所有表格数据。

  接下来,我们将在前面界面中添加一个“保存”按钮,以便当用户更改完网格控件中的数据后,可以通过它保存到服务器端。

  返回到文件MainPage.xaml中,紧接着DataGrid控件下部添加如下代码:

<StackPanel Grid.Row="1" Orientation="Horizontal">
<Button Content="保存修改结果" Click="SaveChanges_Click" />
</StackPanel>

  下面给出的是相应于上面保存按钮的Click事件处理器函数:

private void SaveChanges_Click(object sender, RoutedEventArgs e)
{
    SubmitOperation submitOp
= this._domain.SubmitChanges();
    submitOp.Completed
+= delegate
    {
        
if (submitOp.Error == null)
        {
            MessageBox.Show(
"已经成功保存到服务器端。");
        }
        
else
        {
            MessageBox.Show(
string.Format("发生保存错误: {0}", submitOp.Error.ToString()));
        }
    };
}

    现在,重新构建并运行应用程序。之后,在网格中修改某个数据,并单击保存按钮,然后再试着刷新示例页面并使数据重新加载,你会注意到上面的修改的确被保存到了服务端。

  至此,我们已经拥有了一个具备基本功能的应用程序。接下来,我们可以基于微软.NET RIA服务提供的机制进一步丰富这个应用程序。例如,在实体类型上添加校验属性及定制校验代码,或者提供基于DataPager和DataForm等控件的更丰富的用户接口,等等。但是,我们的兴趣点不在于此。

  从下一节开始,我们将讨论如何把一个ADO.NET数据服务接口添加到现有的应用程序中。

  5.添加ADO.NET数据服务

  至此,我们的示例应用程序的客户端和服务器已经可以利用.NET RIA服务的现有机制进行通信了。

  在本节中,我们将增加一个ADO.NET数据服务,并将分析ADO.NET数据服务协议的传输情况。下面,我们将修改客户端层以便使用ADO.NET数据服务协议。

  为了把ADO.NET数据服务添加到应用程序中,请执行下列步骤:

  (1) 右键单击解决方案资源管理器中的ProductsWithDataService.Web项目,选择“添加—新项目”。

  (2)  在“添加新项目”对话框中,选择“Domain ADO.NET Data Service”,将它命名为ProductsDataService.svc,然后单击“添加”按钮,如下图所示。

  这将把ADO.NET数据服务的框架添加到项目中,并将打开ProductsDataService.cs文件,其中已经包含了基本的支持服务的代码。

  为了使ADO.NET数据服务正确运行,我们需要对系统自动生成的服务代码作一些修改。首先,我们需要把服务与一个数据源关联起来。在本例中,我们将使用我们的域名服务类—ProductsDomain,作为数据源。ProductsDomain提供了针对Product实体集的CRUD方法支持。通过配置ADO.NET数据服务工作于ProductsDomain类中,我们将把这些CRUD方法暴露为遵循ADO.NET数据服务协议的HTTP操作。

  在配置完数据源后,我们还必须指定服务的访问控制规则。在本文例子中,我们将开放服务的完全的读/写访问支持。在实际应用开发中,则应当更谨慎地控制访问权限。

  接下来,请继续遵循下面的步骤实现把ADO.NET数据服务与类ProductsDomain相关联,并且配置好Product实体集以支持读/写访问:

  (3) 打开ProductsDataService.svc.cs文件,注意到服务类ProductsDataService派生自DataService,而且在系统自动生成的代码中,泛型参数T已不存在,代之以TODO注释—提示你加以修改(其实Visual Studio语法感知也已经提示你了—下面的“错误提示”窗口中显示语法错误:“应输入类型”,见下图):

  

public class ProductsDataService : DataService< /* TODO: put your data source class name here */ >, IServiceProvider

  (4) 使用前面创建的域服务类ProductsDomain取代上面的TODO注释部分。其中,服务类的声明应当类似于下面形式:  

public class ProductsDataService : DataService, IServiceProvider

  (5) 在InitializeService()方法中,你会注意到还有一个TODO注释。现在,你使用下面代码取代注释中的内容:

public static void InitializeService(IDataServiceConfiguration config) {

  config.SetEntitySetAccessRule(
"*", EntitySetRights.All);

  config.SetServiceOperationAccessRule(
"*", ServiceOperationRights.All);

  }

  至此,我们就有了一个ADO.NET数据服务。此服务把从域服务类返回的数据暴露为一组可使用URI寻址的资源并且使用我们在类ProductsDomain中实现的CRUD方法映射HTTP方法。

  在下面的步骤中,我们来试用一下上面创建的数据服务,以更好地理解这种功能及相应的传输格式。

  6.观察运行结果(1)

  现在,重新构建并运行示例工程。

  在浏览器中,请导航到ProductsDataService.svc(预览此文件即可)。结果如下图所示:

  注意到,图中显示了服务文档及基于AtomPub标准显示的内容。这个文档指出,我们拥有一个且仅有一个名字为Product的集合,而且可以通过一个同名字(Product)的相对的URL进行访问。

  接下来,我们进行的第二个试验是把上面的URL更改为http://localhost:1623/ProductsDataService.svc/Product/,然后按回车。

 

  如果再试用下面几种URL:

  http://localhost:1623/ProductsDataService.svc/Product(1)/或者http://localhost:1623/ProductsDataService.svc/Product(1)/Name,则浏览器提示是打开或是另存储相应的文件,选择使用浏览器打开,则显示的是第一个实体对应字段内容,或第一个实体Name字段的名称。

  在上面每一种查询情况下,ADO.NET数据服务都生成了一个对于ProductsDomain类方法GetProduct()的调用。

  注意,上面表达的URI格式都是ADO.NET数据服务协议中特别规定的。因此,任何理解这种协议的客户端都能够访问ProductsDomain类提供的数据。

  上面举例仅是ADO.NET数据服务查询的极其简单的情形,其实ADO.NET数据服务还能够使用JSON串行化数据,以及读/写访问(使用HTTP POST,PUT和DELETE方法)服务器端数据。MSDN中提供了有关ADO.NET数据服务的非常细致的介绍,在此不再赘述。

  7.从客户端访问ADO.NET数据服务协议

  在上一节中,我们已经成功地把一个ADO.NET数据服务添加到我们的应用程序中,并且简单地从浏览器中分析了数据服务的调用方式。但是,到目前为止,Silverlight应用程序的客户端部分还没法与这种服务基于ADO.NET数据服务协议进行通信。在这一节,我们将修改现有的Silverlight客户端应用程序使之能够使用上述新式协议。

  使用ADO.NET数据服务协议需要修改系统自动生成的客户端ProductsDomain类。然后,微软.NET RIA服务会基于我们在服务器端创建的域服务类ProductsDomain而自动生成客户端类ProductsDomain。通过对服务器端的DomainService类修饰以特殊属性,我们便能指示微软.NET RIA服务生成需要的客户端代码,于是可以基于此代码进一步使用ADO.NET数据服务协议。然后,我们仅需要对Silverlight代码作一些简单的修改便可以使用这种新生成的客户端类了。下面给出上述描述的具体实现步骤:

  (1)打开ProductsWithDataService.Web工程中的ProductsDomain.cs文件。

  (2)添加如下命名空间引用:

  (3) 然后把下列属性添加到类ProductsDomain声明之前,紧接着现有的 [EnableClientAccess]属性的下面:  

[DomainIdentifier("Atom", CodeProcessor = typeof(AtomCodeProcessor))]

  (4) 在解决方案资源管理器中,右单击客户端应用程序ProductsWithDataService,并选择“添加引用”菜单项。

  (5) 在随后的“添加引用”对话框中单击“浏览”选项卡,导航到%ProgramFiles%\Microsoft SDKs\RIA Services\v1.0\Libraries\Silverlight目录下,并选择下列如下两个程序集:

  a. System.Windows.Ria.Atom.dll

  b. System.Data.Services.Client.Protocol.dll

  (6) 重新生成解决方案。此时,你应当发现一些构建错误,这是因为前面我们应用Atom DomainIdentifier属性后由微软.NET RIA服务自动生成的客户端类与我们最初书写的代码不一致所导致的。

  下面,我们将修正上述错误:

  (7) 打开MainPage.xaml.cs文件,添加如下命名空间引用:  

using System.Windows.Browser;
using System.Data.Services.Client.Protocol;

  (8) 修改MainPage类中的_domain成员为如下形式:  

ProductsDomain _domain = new ProductsDomain( new AtomDomainClient( new Uri(HtmlPage.Document.DocumentUri, "ProductsDataService.svc")));

  8.观察运行结果(2)

  现在,重新生成解决方案,并运行应用程序。

  此时,你会注意到程序运行正常,而且在功能上如前面并无两样。但是,其区别在于,所有的“区别”并不为我们所知—一切是由系统自动为我们生成的。通过第八节中的操作,一个Silverlight客户端就能够使用ADO.NET数据服务协议“直接”与数据服务进行通信了。数据服务会自动把它接收到的HTTP请求翻译成针对ProductsDomain类中的适当的CRUD方法调用。

  9.小结

  在本文中,我们首先概括分析了微软.NET RIA服务与ADO.NET数据服务两个子框架交互的重要意义,然后通过一个简单的例子讨论了把ADO.NET数据服务集成到一个Silverlight 3 RIA应用程序中所涉及到的步骤及注意的问题。但是,根据微软提示,本文中两种框架的交互方案仍处于发展阶段,所以,尚不能把它作为一种成熟的方案应用于实际开发环境下。有兴趣的读者可基于本文提示对上述问题作进一步探讨

0
相关文章