使用数据协定
“数据协定” 是在服务与客户端之间达成的正式协议,用于以抽象方式描述要交换的数据。 也就是说,为了进行通信,客户端和服务不必共享相同的类型,而只需共享相同的数据协定。 数据协定为每个参数或返回类型精确定义为进行交换而序列化哪些数据(将哪些数据转换为 XML)。
数据协定基本知识
默认情况下,Windows Communication Foundation (WCF) 使用称为数据协定序列化程序的序列化引擎对数据进行序列化和反序列化(与 XML 进行相互转换)。 所有 .NET Framework 基元类型(如整型和字符串型)以及某些被视为基元的类型(如 DateTime 和 XmlElement)无需做其他任何准备工作就可序列化并被视为拥有默认数据协定。 许多 .NET Framework 类型也具有现有数据协定。 有关可序列化类型的完整列表,请参阅 Types Supported by the Data Contract Serializer。
必须为所创建的新复杂类型定义数据协定才能序列化这些类型。 默认情况下, DataContractSerializer 推断数据协定并序列化所有公共可见类型。 类型的所有公共读/写属性和字段均被序列化。 可以使用 IgnoreDataMemberAttribute从序列化中剔除某些成员。 还可以使用 DataContractAttribute 和 DataMemberAttribute 属性显式创建数据协定。 正常情况下可通过将 DataContractAttribute 属性应用到该类型来完成该任务。 可以将此属性应用到类、结构和枚举。 然后必须将 DataMemberAttribute 属性应用到数据协定类型的每个成员,以指示这些成员为数据成员, 即应进行序列化。 有关详细信息,请参阅可序列化类型。
示例
下面的示例演示已经显式应用了 ServiceContractAttribute 和 OperationContractAttribute 属性的服务协定(接口)。 该示例演示基元类型不要求数据协定,而复杂类型却对此有要求。
[ServiceContract]
public interface ISampleInterface
{
// No data contract is required since both the parameter
// and return types are primitive types.
[OperationContract]
double SquareRoot(int root);
// No Data Contract required because both parameter and return
// types are marked with the SerializableAttribute attribute.
[OperationContract]
System.Drawing.Bitmap GetPicture(System.Uri pictureUri);
// The MyTypes.PurchaseOrder is a complex type, and thus
// requires a data contract.
[OperationContract]
bool ApprovePurchaseOrder(MyTypes.PurchaseOrder po);
}
<ServiceContract()> _
Public Interface ISampleInterface
' No data contract is required since both the parameter and return
' types are both primitive types.
<OperationContract()> _
Function SquareRoot(ByVal root As Integer) As Double
' No Data Contract required because both parameter and return
' types are marked with the SerializableAttribute attribute.
<OperationContract()> _
Function GetPicture(ByVal pictureUri As System.Uri) As System.Drawing.Bitmap
' The MyTypes.PurchaseOrder is a complex type, and thus
' requires a data contract.
<OperationContract()> _
Function ApprovePurchaseOrder(ByVal po As MyTypes.PurchaseOrder) As Boolean
End Interface
下面的示例演示如何通过将 MyTypes.PurchaseOrder
和 DataContractAttribute 属性应用于类及其成员来创建 DataMemberAttribute 类型的数据协定。
namespace MyTypes
{
[DataContract]
public class PurchaseOrder
{
private int poId_value;
// Apply the DataMemberAttribute to the property.
[DataMember]
public int PurchaseOrderId
{
get { return poId_value; }
set { poId_value = value; }
}
}
}
Namespace MyTypes
<System.Runtime.Serialization.DataContractAttribute()> _
Public Class PurchaseOrder
Private poId_value As Integer
' Apply the DataMemberAttribute to the property.
<DataMember()> _
Public Property PurchaseOrderId() As Integer
Get
Return poId_value
End Get
Set
poId_value = value
End Set
End Property
End Class
End Namespace
备注
下面的注释提供在创建数据协定时需要考虑的事项:
仅当用于未标记的类型时,才接受 IgnoreDataMemberAttribute 属性。 这包括未使用 DataContractAttribute、 SerializableAttribute、 CollectionDataContractAttribute或 EnumMemberAttribute 属性之一标记的类型,或通过任何其他方式(如 IXmlSerializable)标记为可序列化的类型。
可以将 DataMemberAttribute 属性 (Attribute) 应用于字段和属性 (Property)。
成员可访问性级别(internal、private、protected 或 public)对数据协定无任何影响。
如果将 DataMemberAttribute 属性应用于静态成员,则将忽略该属性。
在序列化期间,为属性数据成员调用 property-get 代码来获取要序列化的属性的值。
在反序列化期间,首先创建一个未初始化的对象,而不在该类型上调用任何构造函数。 然后反序列化所有数据成员。
在反序列化期间,为属性数据成员调用 property-set 代码,将属性设置为要反序列化的值。
对于将要生效的数据协定,它必须能序列化其所有数据成员。 有关可序列化类型的完整列表,请参阅 Types Supported by the Data Contract Serializer。
泛型类型的处理方式与非泛型类型完全相同。 泛型参数无特殊要求。 例如,请注意以下类型:
[DataContract]
public class MyGenericType1<T>
{
// Code not shown.
}
<DataContract()> _
Public Class MyGenericType1(Of T)
' Code not shown.
End Class
无论用于泛型类型参数 (T
) 的类型能否序列化,此类型都可序列化。 因为它必须能序列化所有数据成员,所以下面的类型仅在泛型类型参数也可序列化时才可序列化,如以下代码所示。
[DataContract]
public class MyGenericType2<T>
{
[DataMember]
T theData;
}
<DataContract()> _
Public Class MyGenericType2(Of T)
<DataMember()> _
Dim theData As T
End Class
有关定义数据协定的 WCF 服务的完整代码示例,请参阅 Basic Data Contract 示例。