演练:在 ASP.NET 应用程序中使用域服务
ASP.NET 提供了可供数据绑定控件(如 GridView 控件)使用的 DomainSourceControl 控件,用来访问数据库,并支持用户执行创建、读取、更新和删除 (CRUD) 等操作。
值得注意的一个要点是:域服务支持您将您的应用程序从特定的数据库模型中分离。这样做的优点是:您可以将重点放在业务逻辑以及创建可轻松移植到不同模型的代码上。
WCF RIA Services 域服务提供了一种用于编写应用程序逻辑的模式,该业务逻辑在服务器上运行并控制针对数据的查询、更改和自定义操作。它还通过将 Silverlight 客户端与 ASP.NET 服务器应用程序集成,提供了对常见任务(如数据验证、身份验证)和角色的端到端支持。
本演练演示如何通过使用 RIA Services 域服务从 ASP.NET 网页访问数据库。尽管本演练描述的是 ASP.NET 中的域服务,但该服务的使用并不仅限于 ASP.NET 应用程序。本演练不涉及 ASP.NET 服务器与 Silverlight 客户端应用程序的集成。
本演练包含以下过程:
创建 ASP.NET Web 应用程序
使用域服务
测试域服务
必备条件
本演练和 RIA Services 文档中提供的其他演练除了要求正确安装和配置 WCF RIA Services 和 WCF RIA Services 工具包外,还要求正确安装和配置几个必备程序,如 Visual Studio 2010 以及 Silverlight Developer Runtime 和 SDK。它们还要求安装和配置具有高级服务的 SQL Server 2008 R2 Express,并安装 AdventureWorks OLTP 和 LT 数据库。
WCF RIA Services 的必备条件节点中的主题提供有关如何满足这些前提条件的详细说明。在执行本演练前请按照那里提供的说明操作,以确保在执行本 RIA Services 演练时遇到的问题最少。
创建 ASP.NET Web 应用程序
若要使用域服务,您必须创建能与数据库交互的 ASP.NET Web 应用程序。以下是您必须执行的步骤:
创建 Web 应用程序。这将为域服务提供使用环境。
向该应用程序添加数据库。这将支持您为您的 Web 应用程序选择数据库。
创建数据库模型。创建包含作为 CLR 类型的数据库实体的模型。域服务将使用这些类型与该数据库进行交互。您可以使用 ADO.NET 实体框架或 LINQ to SQL 数据模型。
下面的过程演示如何创建 ASP.NET Web 应用程序。
创建 ASP.NET Web 应用程序
在 Visual Studio 2010 中,依次单击**“文件”菜单、“新建”和“项目”**。
将显示**“新建项目”**对话框。
在**“已安装的模板”下,展开“Visual C#”或“Visual Basic”,然后选择“Web”**。
在模板列表中,选择**“ASP.NET 空 Web 应用程序”**。
将项目命名为 UsingDomainService,指定一个位置,然后单击**“确定”**。
生成应用程序。
下面的过程演示如何向该应用程序添加数据库。此数据库包含您要访问以进行显示和编辑的表。
向 Web 应用程序添加数据库
在**“解决方案资源管理器”中,右击项目名称,依次单击“添加”、“添加 ASP.NET 文件夹”和“App_Data”**。
这会将 App_Data 文件夹添加到项目中。
右击 App_Data 文件夹,依次单击**“添加”和“现有项”**。
将显示**“添加现有项”**对话框。
指定 AdventureWorksLT 数据库文件 (AdventureWorksLT_Data.mdf) 的位置。
下图显示了**“添加现有项”**对话框。
单击**“添加”**。
这将创建项目中数据库文件的副本。有关更多信息,请参见如何:使用 .MDF 文件连接到 AdventureWorksLT 数据库。
下面的过程演示如何创建包含表示数据库表的类的数据模型。在本演练中,您将使用 ADO.NET 实体框架数据模型。但是,您可以改用 LINQ to SQL 数据模型。
创建数据模型
在**“解决方案资源管理器”中,右击项目名称,然后依次单击“添加”和“新建项”**。
将显示**“添加新项”**对话框。
在**“已安装的模板”下,选择“数据”**。
在模板列表中,选择**“ADO.NET 实体数据模型”**。
将数据库模型命名为 AdventureWorksLT.edmx,然后单击**“添加”**。
将显示**“实体数据模型向导”**。
在**“选择模型内容”屏幕上,选择“从数据库生成”**。
下图显示了**“选择模型内容”**对话框。
单击**“下一步”**。
在**“选择您的数据连接”屏幕上的“应用程序连接数据库应使用哪个数据连接?”**下,从下拉列表中选择“AdventureWorksLT_Data.mdf”。
确保选中了**“将 Web.config 中的实体连接设置另存为:”**复选框。可以保留默认的连接字符串名称。
下图显示了**“选择您的数据连接”**对话框。
单击**“下一步”**。
该向导将显示一页,您可以从该页中指定要包括在模型中的数据库对象。
在**“选择数据库对象”屏幕上,选择“表”**节点以选择数据库中的所有表。
下图显示了**“选择数据库对象”**对话框。
确保选中**“在模型中加入外键列”**复选框。可以保留默认模型命名空间。
单击**“完成”**。
将显示 ADO.NET 实体数据模型设计器。您已经创建了一个表示 AdventureWorksLT 数据库的数据模型。
关闭该设计器。
生成应用程序。
生成操作将使 AdventureWorksLT_DataEntities 上下文类可用于下一过程中的域服务。
使用域服务
此过程描述为了在 ASP.NET 应用程序中使用域服务而必须执行的步骤。这些步骤包括:
向项目添加域服务类。这将创建支持您的应用程序执行 CRUD 数据库操作的类,而且非常重要的是,该操作可支持您包括您自己的业务逻辑。此类在服务器或中间层上操作。
创建业务逻辑。在域服务类中加入您的代码(业务逻辑)。
声明 DomainDataSource 控件。您需要在页标记中进行声明,以便用户能与数据库交互。此控件在客户端或表示层上操作。
下面的过程演示如何向项目添加域数据服务。
向项目添加域服务类
在**“解决方案资源管理器”中,右击项目名称,然后依次单击“添加”和“新建项”**。
在**“已安装的模板”下,选择“Web”**。
在模板列表中,选择**“域服务类”**。
将文件命名为 AdventureWorksDomainService.cs 或 AdventureWorksDomainService.vb,然后单击**“添加”**。
将显示**“添加新的域服务类”对话框。“域服务类名:”**框包含您指定的名称。
选中**“启用客户端访问”**复选框。
在**“可用的 DataContexts/ObjectContexts:”下拉列表中,选择“AdventureWorksLT_DataEntities (实体框架)”。如果该下拉列表为空,则您未生成应用程序。退出“添加新的域服务类”**对话框,生成该应用程序,然后重复前面的步骤。
在**“实体”列表中,选择“产品”**表。
针对**“产品”表,选中“启用编辑”**复选框。
选中**“为元数据生成关联类”**复选框。
下图显示了**“添加新的域服务类”**对话框。
单击**“确定”**。
将创建
AdventureWorksDomainService
类和相关元数据文件。该类包含允许执行数据库 CRUD 操作的方法。您可以修改该类和元数据文件以包含您的业务逻辑。下一个过程将显示一个简单示例。请注意,项目引用已更新以包含所需的程序集,并且 Web.config 文件已更新以包含所有需要的配置元素。在**“文件”菜单上单击“全部保存”**。
下面的过程演示如何自定义 AdventureWorksDomainService
类和相关的元数据文件以包括您的业务逻辑。尽管该自定义过程非常简单,但通过它您可以了解您能够进行的修改。
创建业务逻辑
在**“解决方案资源管理器”**中,打开 AdventureWorksDomainService.cs 或 AdventureWorksDomainService.vb 文件。
修改
UpdateProduct
方法以包括ListPrice
字段的验证逻辑,如下面的代码所示:此外,使用当前日期更新ModifiedDate
字段。public void UpdateProduct(Product currentProduct) { if ((currentProduct.EntityState == EntityState.Detached)) { // Custom logic: set a lower limit for the price. if (currentProduct.ListPrice < 5) throw new ValidationException("The list price must be >= 5."); this.ObjectContext.Products.AttachAsModified(currentProduct, this.ChangeSet.GetOriginal(currentProduct)); // Custom logic: set the date to the current value. currentProduct.ModifiedDate = DateTime.Today; } }
Public Sub UpdateProduct(ByVal currentProduct As Product) If (currentProduct.EntityState = EntityState.Detached) Then ' Custom logic: set a lower limit for the price. If currentProduct.ListPrice < 5 Then Throw New ValidationException("The list price must be >= 5.") End If Me.ObjectContext.Products.AttachAsModified(currentProduct, _ Me.ChangeSet.GetOriginal(currentProduct)) ' Custom logic: set the date to the current value. currentProduct.ModifiedDate = DateTime.Today End If End Sub
如果验证失败,将引发异常,并向要对用户显示的页面发送一条错误消息。
修改
GetProducts
方法,为实体框架设置正常工作所需的排序逻辑,如下面的代码所示。public IQueryable<Product> GetProducts() { return this.ObjectContext.Products.OrderBy(p => p.ProductID); }
Public Function GetProducts() As IQueryable(Of Product) Return Me.ObjectContext.Products.OrderBy(Function(p) p.ProductID) End Function
保存并关闭文件。
在**“解决方案资源管理器”**中,打开 AdventureWorksDomainService.metadata.cs 或 AdventureWorksDomainService.metadata.vb 文件。
向
Color
数据字段实体添加 Required 特性,如下面的代码所示。利用此特性,您可以强制该数据字段不为空(数据库允许为空)。如果用户输入空字符串,则将引发错误。
[Required(AllowEmptyStrings=false, ErrorMessage="Color is required")] public string Color{ get; set; }
<Required(AllowEmptyStrings:=False, ErrorMessage:="Color is required")> _ Public Property Color As String
保存并关闭该元数据文件。
生成应用程序。
下面的过程演示如何在页标记中声明 DomainDataSource 控件,以便用户可与数据库交互。
在页中声明 DomainDataSource 控件
在**“解决方案资源管理器”中,右击项目名称,然后依次单击“添加”和“新建项”**。
在**“已安装的模板”下单击“Web”**。
在模板列表中,选择**“Web 窗体”**。
将该文件命名为 Default.aspx,然后单击**“添加”**。
在**“设计”**视图中打开 Default.aspx。
从**“工具箱”的“常规”或“数据”**组中,将一个 DomainDataSource 控件添加到该页上。
将显示 DomainDataSource,同时打开**“DomainDataSource 任务”**菜单。
如果未列出该控件,则单击**“工具”菜单,然后单击“选择工具箱项”。在“选择工具箱项”对话框中,单击“.NET Framework 组件”选项卡,选中“DomainDataSource”复选框,然后单击“确定”**。
在**“DomainDataSource 任务”菜单上,单击“配置数据源”**。
此时将显示**“配置数据源”**向导。
在**“选择域服务”屏幕中,从“域服务类型:”**列表中选择您创建的类
UsingDomainService.AdventureWorksDomainService
。下图显示了**“选择域服务”**屏幕。
单击**“下一步”**。
在**“配置数据访问”**屏幕上,选择
IQueryable<Product> GetProducts()
方法。选中**“启用插入”复选框、“启用更新”复选框和“启用删除”**复选框。
下图显示了**“配置数据访问”**屏幕。
单击**“完成”**。
从“工具箱”的**“数据”**选项卡中,向该页中添加一个 GridView 控件。
将显示 GridView,同时打开**“GridView 任务”**菜单。
在**“GridView 任务”菜单中,从“选择数据源”列表中选择“DomainDataSource1”**。
这是您在此前的步骤中创建的 DomainDataSource 控件的 ID。
在**“GridView 任务”菜单中,单击“编辑列”**。
将显示**“字段”**对话框。
清除**“自动生成字段”**复选框。
在**“选定的字段:”窗格中删除“Name”、“Color”、“ListPrice”和“ModifiedDate”**以外的所有其他字段。
单击**“确定”**。
或者,在**“GridView 任务”**菜单中,通过选中各复选框相应启用分页、排序和选择功能。
保存该文件,然后切换到**“源”**视图。
选择 GridView。
在“属性”窗口中,将 DataKeyNames 属性设置为由所有未显示的列构成的以下逗号分隔列表:ProductID, ProductNumber, StandardCost,Size, Weight,ProductCategoryID, ProductModelID, SellStartDate, SellEndDate, DiscontinuedDate, ThumbNailPhotoFileName, rowguid。
这是 DomainDataSource 控件执行 CRUD 操作所需的。
将 AutoGenerateEditButton 属性设置为 True,以支持编辑和删除表行。
在“源”视图中,将 Columns 元素替换为以下标记。
通过使用自定义模板,此标记支持先对 Color 和 ListPrice 数据字段值进行验证,然后再在回发时将这些值发送到服务器。它还创建一个删除 LinkButton 控件,该控件会在删除行之前询问用户权限。
<Columns> <asp:TemplateField> <ItemTemplate> <asp:LinkButton ID="LinkButton1" CommandName="Delete" Text="Delete" ForeColor="#333333" OnClientClick='return confirm("Are you sure you want to delete this row?");'/> </ItemTemplate> </asp:TemplateField> <asp:CommandField ShowSelectButton="True" /> <asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" /> <asp:TemplateField> <HeaderTemplate>Color</HeaderTemplate> <ItemTemplate> <%# Eval("Color") %> </ItemTemplate> <EditItemTemplate> <asp:TextBox ID="ColorID" Text='<%# Bind("Color") %>'/> <cc1:DomainValidator ID="DomainValidator2" DataField="Color"/> </EditItemTemplate> </asp:TemplateField> <asp:TemplateField> <HeaderTemplate>ListPrice</HeaderTemplate> <ItemTemplate> <%# Eval("ListPrice")%> </ItemTemplate> <EditItemTemplate> <asp:TextBox ID="ListPriceID" Text='<%# Bind("ListPrice") %>'/> <cc1:DomainValidator ID="DomainValidator3" DataField="ListPrice"/> </EditItemTemplate> </asp:TemplateField> <asp:BoundField DataField="ModifiedDate" HeaderText="ModifiedDate" SortExpression="ModifiedDate" /> </Columns>
在 GridView 控件之前,添加以下标记以支持显示验证错误:
<asp:ValidationSummary ID="ValidationSummary1" /> <cc1:DomainValidator ControlToValidate="GridView1"/>
保存 Default.aspx 文件。
生成应用程序。
测试域服务
此过程说明如何通过使用 GridView 控件来测试该域服务的功能。此过程验证以下内容:
通过自定义业务逻辑与数据库交互的操作能按预期工作。
ASP.NET 执行用户对数据库字段所做的更改。
ASP.NET 显示自定义逻辑生成的错误消息。
测试域服务
在**“解决方案资源管理器”中,右击 Default.aspx 页,然后选择“在浏览器中查看”**。
浏览器中显示一个页面,其中显示 Product 表。
在任意行上,单击**“编辑”**,然后通过输入小于 5 的值来修改 ListPrice 列的值。
在同一行上,单击**“更新”**。
将显示自定义错误,指明该字段必须大于或等于 5。
在同一行上,为 ListPrice 列输入大于 5 的值。
在同一行上,单击**“更新”**。
ASP.NET 将更新数据库中的 ListPrice 和 ModifiedDate 数据字段。
在任意行上,单击**“编辑”**,然后通过输入一个空字符串来修改 Color 列的值。
在同一行上,单击**“更新”**。
ASP.NET 将显示自定义验证错误。
在同一行上,为 Color 列输入空字符串之外的值。
在同一行上,单击**“更新”**。
ASP.NET 将更新数据库中的 Color 和 ModifiedDate 数据字段。