使用WCFRIA服务从服务器公开数据
立即解锁
发布时间: 2025-08-13 02:53:24 阅读量: 19 订阅数: 25 

### 使用 WCF RIA 服务从服务器公开数据
#### 1. 元数据类
元数据类允许我们在不修改实体类本身的情况下为实体添加属性,这在代码生成实体且重新生成会重新创建实体类时非常有用。元数据类通过实体类上指向它的属性与实体关联。通常,为避免修改实体类来应用此属性,会为实体创建部分类并将属性应用于该部分类。
以 `Product` 实体的元数据类为例,其文件名通常为 `<DomainServiceName>.metadata.cs`。该文件包含一个扩展 `Product` 实体的部分类,目的是应用 `MetadataType` 属性来指定对应的元数据类。示例代码如下:
```csharp
[MetadataTypeAttribute(typeof(Product.ProductMetadata))]
public partial class Product
{
internal sealed class ProductMetadata
{
// Field definitions (removed for the purposes of brevity)
}
}
```
`MetadataType` 属性的构造函数参数需要关联的元数据类的类型。这里将 `Product` 类中的 `ProductMetadata` 类与之关联,提供了实体类和元数据类之间的链接,RIA 服务利用此链接将两者关联起来。虽然不一定要使用嵌套类作为元数据类,但 RIA 服务默认创建的元数据类是嵌套类。我们可以将元数据类视为实际的实体类,并为其添加所需的属性。
元数据类向导创建的元数据类包含一个公共字段,代表关联实体上的每个属性,我们可以根据需要为这些字段添加属性。
#### 2. 控制客户端实体生成
在某些情况下,我们可能不希望 RIA 服务代码生成的客户端项目中的实体与服务器项目中的实体相同。例如,实体中的某些属性(如密码、图像、计算属性、信用卡号等)不应传输到客户端或对客户端可见。下面介绍如何自定义客户端实体的生成以及从服务器传输到客户端的数据。
##### 2.1 包含/排除属性
可以使用 `Include` 或 `Exclude` 属性(位于 `System.ServiceModel.DomainServices.Server` 命名空间)来明确指定某个属性是否在客户端创建。默认情况下,实体上返回简单类型(如 `string`、`int` 和 `bool`)或预定义的一组复杂类型(如字节数组)的所有公共属性将自动在客户端实体中创建(除非应用了 `Exclude` 属性)。但其他复杂值(如通过外键关系与每个请求实体关联的实体集合)在实体传输时不会传输到客户端,客户端对应的实体上也不会创建提供关联的集合属性。
##### 2.2 包含/排除关联实体
默认情况下,当请求 `Product` 实体(或实体集合)时,每个 `Product` 实体的产品库存实体集合不会在客户端项目中返回或访问。不过,我们可以明确指定这些关联的产品库存实体应与产品实体一起返回给客户端,并在客户端的 `Product` 实体上创建一个属性来访问它们。
要实现这一点,需要进行两处更改:
- **在域服务的查询操作中**:在返回产品集合的查询操作中,需要从实体框架请求检索与每个产品实体关联的产品库存记录。示例代码如下:
```csharp
public IQueryable<Product> GetProducts()
{
return ObjectContext.Products.Include("ProductInventory");
}
```
可以链式调用多个 `Include` 方法来包含更多关联实体。
- **在产品实体的元数据类中**:用 `Include` 属性修饰 `ProductInventory` 字段,以表明它应包含在客户端项目生成的实体中(由于它是复杂属性,默认情况下不会包含)。示例代码如下:
```csharp
[Include]
public EntityCollection<ProductInventory> ProductInventory;
```
这个属性表示 `Product` 实体和 `ProductInventory` 实体之间的关联。RIA 服务需要知道这两个实体之间的关系,通常使用 `Association` 属性来实现。如果返回的是实体模型中的实体,该属性通常已经应用于该属性。但在公开表示模型类型时,需要显式修饰表示实体关系的属性。
#### 3. 使关联实体可编辑
如果要使 `ProductInventory` 实体可更新,需要在 `ProductService` 域服务中为 `ProductInventory` 实体创建插入、更新和删除操作。否则,在 Silverlight 客户端尝试插入、更新或删除库存实体集合中的实体时会抛出异常。
另一种方法是使用 `Composition` 属性将实体关联配置为组合层次结构。这样,当子实体之一更新时,父实体将被标记为已更新,并且在执行更新操作时,所有子实体(无论是否已修改)都会被发送回服务器,将父实体和子实体视为一个单元。然后可以在父实体的更新操作中处理子实体的更新,而无需为子实体单独设置更新操作。
`ExternalReference` 属性用于与 `Association` 属性配合使用,指定关联关系中的相关实体不应在客户端创建。这是因为 RIA 服务只允许从单个域服务公开一个实体。如果已经从另一个域服务公开了相关实体,编译应用程序时会收到错误消息 “Entity types cannot be shared across DomainServices”,因为它试图在客户端创建相同的实体两次。用 `ExternalReference` 属性修饰表示关联的属性可以防止域服务公开相关实体,从而避免此问题。
#### 4. 验证
RIA 服务试图解决的一个重要问题是验证逻辑需要在服务器和客户端都编写和执行。在两个地方编写相同的逻辑不仅会导致代码和工作量的重复,而且逻辑很容易不同步。在两个地方执行验证逻辑很重要,因为我们既希望有响应式的用户界面(无需等待服务器告知用户输入无效),又希望在服务器上验证数据,因为不能保证数据来自我们自己的客户端应用程序,且其规则可能被绕过。
RIA 服务通过允许在服务器上的实体上定义验证逻辑,并在生成客户端项目中的相应实体时自动应用相同的验证属性,解决了这个问题。我们只需在一个位置编写和维护验证逻辑,并且通过客户端项目中实体的代码生成保持同步。
##### 4.1 预定义验证属性
可以通过属性(来自 `System.ComponentModel.DataAnnotations` 命名空间)为属性应用一些基本的验证规则,包括:
| 属性 | 描述 |
| ---- | ---- |
| `Required` | 指定属性必须有值(即非空),默认情况下字符串不能为空,但可以使用 `AllowEmptyStrings` 属性禁用此行为。 |
| `Range` | 指定属性允许的最小值和最大值。 |
| `StringLength` | 设置字符串属性允许的最小和最大字符数。默认构造函数接受最大长度(默认最小长度为 0 个字符),也可以
0
0
复制全文
相关推荐









