WCF能够托管CLR类型,客户端能传递和处理CLR类型的数据(如:string和int),但是如果我们自己定义的类型(如:声明的Customer类)。其实WCF的传递CLR自己类型时,是因为已经把它序列化成了xml信息集,而我们自己定义的类型则需要自己去显示的声明序列化。
序列化
.net的序列化。.net是通过反射机制(
反射机制参考文档)自动实现对象的序列化与反序列化。首先.net能够捕获对象每个字段的值,然后进行序列化,反序列化时,.net创建一个对应类型的新的对象,读取持久化的值,然后设置字段的值。.net对象状态的序列化到Stream中。
我们自定义的类或者结构是不支持序列化的,因此如果我们的类是否要序列化是需要类的开发者来指定的。如果需要支持序列化的话,我们可以在类或者结构上添加Serializable属性。
如:
[Serializable]
public class Customer
{
...
}
但是如果添加了Serializable就要求类型的成员也要支持序列化的,不然会抛出异常,但是我们可以通过在成员上添加NonSerizlized属性来说明这个成员不需要序列化。
格式器
.net为序列化和反序列化提供了两种格式器:
1.BinaruFormatter:将类型序列化为二进制格式。
2.SoapFormatter:格式成SOAP特定的XML格式。
但是这两者都要将类型的程序集以及版本控制信息持久化到Stream中,而面向服务要求参与者都能拥有类型程序集,所以如果用这两种格式就必须要去共享Stream,这样肯定不是我们理想的。从而有了WCF格式器。
WCF的格式器:DataContractSerializer,是能够共享数据契约的。WCF数据进行序列化时,WCF一般会自己调用DataContractSerializer来序列的,不需要我们去指定的。同时我们也可以用DataContractSerializer进行Stream的序列化。
数据契约特性
Serializable要求类型的所有的成员都是可以序列化的,而且不支持类型名跟成员名的别名,这样我们就没法明确指定哪些成员是要放到数据契约中的。然而WCF数据契约特性DataContract很好的解决了这些问题。
DataContract Attribute 是在命名空间System.Runtime.Serialization中的,是可以在Enum、Struct、Class上标识的。拥有成员Name,Namespace。而当我们在一个class或者struct上使用时,wcf是不会序列化类型的成员的。如:
[DataContract]
public class Emloyee
{
public string _firstName;
public string _lastName;
}
Employee里面的成员_firstName,_lastName是不会去序列化的,所以我们还必须去显示的指定需要序列化的成员。
DataMember Attribute是用来指定需要序列化类型的成员。DataMember的成员:
IsRequried:序列化时是否必须要赋值;
Name:指定成员的别名;
Order:指定序列化后的排列位置。
我们看一个例子Customer.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
namespace HenllyeeDataContract
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
[DataContract(Name="Customer",Namespace="HenllyeeDataContract")]
public class Customer
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Fileds#region Fileds
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private string _firstName;
private string _lastName;
private int _age;
private decimal _salary;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
#endregion
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Attributes#region Attributes
[DataMember(Name="FirstName",IsRequired=false,Order=0)]
public string FirstName
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return this._firstName; }
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ this._firstName = value; }
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
[DataMember(Name = "LastName", IsRequired = false, Order = 1)]
public string LastName
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return this._lastName; }
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ this._lastName = value; }
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
[DataMember(Name = "Age", IsRequired = false, Order = 2)]
public int Age
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return this._age; }
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ this._age = value; }
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
[DataMember(Name = "Salary", IsRequired = false, Order = 3)]
public decimal Salary
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return this._salary; }
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ this._salary = value; }
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
#endregion
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
上面我们定义了一个数据契约,将DataMember属性定义在几个属性上(建议定义在属性上,不要定义在字段上)。
服务契约为:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
namespace HenllyeeServiceContract
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
[ServiceContract(Name="CustomerManagerService",Namespace="http://Henllyee.cnblogs.com/2008/06/29")]
public interface ICustomerManager
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// Save customer's info
/// </summary>
/// <param name="customer">the customer's object</param>
[OperationContract(Name="SaveCustomerInfo",Action="http://Henllyee.cnblogs.com/2008/06/29/CustomerManagerService/SaveCustomer",
ReplyAction = "http://Henllyee.cnblogs.com/2008/06/29/CustomerManagerService/SaveCustomerResponse")]
void SaveCustomer(HenllyeeDataContract.Customer customer);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// Get customer's info
/// </summary>
/// <returns>a customer</returns>
[OperationContract(Name = "GetCustomerInfo", Action = "http://Henllyee.cnblogs.com/2008/06/29/CustomerManagerService/GetCustomer",
ReplyAction = "http://Henllyee.cnblogs.com/2008/06/29/CustomerManagerService/GetCustomerResponse")]
HenllyeeDataContract.Customer GetCustomer();
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
服务契约里面具体实现:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
namespace HenllyeeServiceContract
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class CustomerManager:ICustomerManager
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
fileds#region fileds
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private HenllyeeDataContract.Customer _customer;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
#endregion
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Members#region Members
public void SaveCustomer(HenllyeeDataContract.Customer customer)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
_customer = customer;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public HenllyeeDataContract.Customer GetCustomer()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return this._customer;
}
#endregion
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
主机的实现就不在次给出了。
然后我们在客户端添加服务引用,即可以了。我们在客户端可以看到导入的数据契约:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="Customer", Namespace="HenllyeeDataContract")]
[System.SerializableAttribute()]
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
public partial class Customer : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged
{
[System.NonSerializedAttribute()]
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string FirstNameField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string LastNameField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private int AgeField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private decimal SalaryField;
[global::System.ComponentModel.BrowsableAttribute(false)]
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public System.Runtime.Serialization.ExtensionDataObject ExtensionData
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{
return this.extensionDataField;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{
this.extensionDataField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public string FirstName
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{
return this.FirstNameField;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if ((object.ReferenceEquals(this.FirstNameField, value) != true))
{
this.FirstNameField = value;
this.RaisePropertyChanged("FirstName");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public string LastName
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{
return this.LastNameField;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if ((object.ReferenceEquals(this.LastNameField, value) != true))
{
this.LastNameField = value;
this.RaisePropertyChanged("LastName");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute(Order=2)]
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public int Age
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{
return this.AgeField;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if ((this.AgeField.Equals(value) != true))
{
this.AgeField = value;
this.RaisePropertyChanged("Age");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute(Order=3)]
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public decimal Salary
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{
return this.SalaryField;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if ((this.SalaryField.Equals(value) != true))
{
this.SalaryField = value;
this.RaisePropertyChanged("Salary");
}
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
protected void RaisePropertyChanged(string propertyName)
{
System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if ((propertyChanged != null))
{
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}
我们可以看到字段后面都加上了Field后缀。
要注意的一点是:即使我们将DataMember定义在私有的字段或者私有属性上面,导入的定义中,原来的私有字段或私有属性都会被重新定义成了公有字段跟公有属性。
文件下载地址:
https://files.cnblogs.com/henllyee/DataContract.rar