对象序列化
WCF是通过网络实现远程方法调用的,因此参数,返回值等都需要序列化才能在网络间传输。例如,对于下面的一个服务:
[ServiceContract]
public interface IService1
{
[OperationContract]
Point GetRandomPoint();
}
public class Point
{
public int X { get; set; }
public int Y { get; set; }
}
public class Service1 : IService1
{
public Point GetRandomPoint()
{
var rnd = new Random();
return new Point() { X = rnd.Next(), Y = rnd.Next() };
}
}
可以通过WCF测试客户端查看其数据是如何传输的。
从中我们可以看到,对于返回值Point,是将其序列化成了Xml格式后传递的,在WCF中,默认是通过DataContractSerializer序列化对象的,它可以将对象序列化成XML,我们也可以手动编码实现这一过程。
var point = new Point(){X = 1,Y = 2};
var serializer = new DataContractSerializer(typeof(Point));
serializer.WriteObject(stream, point);
序列化控制
从前面的例子可以看到,即使什么都不干,只要定义了一个对象,DataContractSerializer就能将其序列化。但这个默认的序列化方式是直接根据字段名称来序列化的,很多时候,为了实现更好的版本控制,往往需要我们控制序列化格式。
一个简单的示例如下:
[DataContract]
public class Point
{
[DataMember(Name="PointX")] public int X { get; set; }
[DataMember(Name="PointY")] public int Y { get; set; }
}
实现这个序列化控制后,执行结果为:
从这个例子中可以看到,和传统的XmlSerializer一样,WCF是通过一些Attribute进行序列化控制的,基本方式为:
-
通过 DataContract 标志要序列化的对象
-
通过 DataMember 标志序列化成员,并通过参数控制序列化过程。
当然,其序列化控制手段远远不止这么点,更多信息可以参看MSDN:创建类或结构的基本数据协定。
将对象序列化成Json格式
XML虽然具有良好的可读性,但开销非常大,增大了网络传输负担,对于那些网速不够快的场景则需要开销更小的序列化格式,一种比较常用的开销更小的序列化格式就是Json。
WCF是一个通用的网络传输平台,在WCF中,可以借助DataContractJsonSerializer实现序列化对象为Json格式。例如,对于前面的那个Point结构,可以序列化为如下形式:
{"PointX":1,"PointY":2}
可以看到,DataContract的序列化控制对DataContractJsonSerializer也是生效的,这说明DataContract是一个通用的序列化控制手段,这也是它们叫DataMember这类比较抽象的名字,而不是叫XmlElement之类的具体名字的原因。
要把WCF服务配置成以Json方式传输数据格式,可以参考这篇文章Using WebHttpBinding & JSON Support in WCF。
注意事项
在WCF传输数据时,注意返回的对象类型不能是返回值类型的子类(Stream除外)。拿前面的例子来说,修改代码为:返回一个Point的子类Point3D对象。
public class Point3D : Point
{
public int Z { get; set; }
}
public class Service1 : IService1
{
publicPointGetRandomPoint()
{
var rnd = new Random();
return newPoint3D() { X = rnd.Next(), Y = rnd.Next() };
}
}
这个时候是完全能通过编译并运行的,但是调用函数的时候就会出现如下错误:
这个主要还是传输的数据格式不匹配造成的,WCF中可以使用KnownTypeAttribute标记解决这一问题,具体可以参看MSDN文章数据协定继承,这里就不多介绍了。