一、数据契约

1.使用数据协定可以灵活控制哪些成员应该被客户端识别。

    [DataContract]
public class Employee
{
[DataMember]
public string Name { get; set; }
[DataMember]
public int Age { get; set; }
[DataMember]
public string City { get; set; }
} [ServiceContract]
public interface IService
{
[OperationContract]
Employee GetAEmployee();
} public class MyService : IService
{
public Employee GetAEmployee()
{
return new Employee { Name = "小朋友", Age = };
}
}
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(Service1)))
{
host.AddServiceEndpoint(typeof(IService1), new WSHttpBinding(), "http://127.0.0.1:8888/service1");
ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
behavior.HttpGetEnabled = true;
behavior.HttpGetUrl = new Uri("http://127.0.0.1:8888/service"); //httpGetUrl客户端引用的地址
host.Description.Behaviors.Add(behavior);
host.Opened += delegate
{
Console.WriteLine("服务已启动");
Console.ReadKey();
};
host.Open();
}
}
}

如果把Employee类中的某个成员的DataMember属性去掉,则在客户端代理类中就不会生成该属性

2.数据协定也有隐藏真实身份的作用

    [DataContract(Name = "Worker")]
public class Employee
{
[DataMember(Name = "Worker_Name")]
public string Name { get; set; } [DataMember(Name = "Worker_Age")]
public int Age { get; set; } [DataMember(Name = "Worker_City")]
public string City { get; set; }
}

这样在客户端生成的代理类的成员名称就和服务器端不一样

3.(已知类型),在一些比较复杂的类型无法反序列化(不能识别类型)的时候,就得考虑使用KnownTypeAttribute来标注可能涉及到的外部类型,但如果遇到像泛型这些较为复杂的类型,就要考虑在带数据协定的类中添加一个静态方法,该方法返回Type 的IEnumerable,一般是Type[]就可以了,而在KnownTypeAttribute的构造函数中使用这个方法的名字

[DataContract]
[KnownType("GetKnowTypes")]
public class Student
{
[DataMember]
public string Name;
[DataMember]
public string Phone;
[DataMember]
public AddrInfo Address;
[DataMember]
public object Scores; static Type[] GetKnowTypes()
{
return new Type[] { typeof(Dictionary<string,float>) };
}
}
[DataContract]
public class AddrInfo
{
[DataMember]
public string Province;
[DataMember]
public string City;
[DataMember]
public string DetailAddr;
}
public class MyService : IService
{
public Student GetStudentInfo()
{
Student stu = new Student();
AddrInfo info = new AddrInfo();
info.Province = "广东省";
info.City = "佛山市";
info.DetailAddr = "火星路-300号";
stu.Name = "小陈";
stu.Phone = "";
stu.Address = info;
Dictionary<string, float> m_scores = new Dictionary<string, float>();
m_scores.Add("语文", 97f);
m_scores.Add("英语", 64.5f);
m_scores.Add("数学", 38f);
m_scores.Add("历史", 77.6f);
m_scores.Add("地理", 82.3f);
stu.Scores = m_scores;
return stu;
}
}
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(Service1)))
{
host.AddServiceEndpoint(typeof(IService1), new WSHttpBinding(), "http://127.0.0.1:8888/service1");
ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
behavior.HttpGetEnabled = true;
behavior.HttpGetUrl = new Uri("http://127.0.0.1:8888/service"); //httpGetUrl客户端引用的地址
host.Description.Behaviors.Add(behavior);
host.Opened += delegate
{
Console.WriteLine("服务已启动");
Console.ReadKey();
};
host.Open();
}
} static void Main(string[] args)
{
WS.ServiceClient cli = new WS.ServiceClient();
WS.Student stu = cli.GetStudentInfo();
string msg = "学生姓名:{0}\n联系电话:{1}\n" +
"地址信息:-----------\n" +
"省份:{2}\n" +
"市区:{3}\n" +
"详细地址:{4}";
Console.WriteLine(msg, stu.Name, stu.Phone, stu.Address.Province, stu.Address.City, stu.Address.DetailAddr);
Console.WriteLine("---------------------------------------");
Console.WriteLine("学生成绩单:");
Dictionary<string, float> scores = stu.Scores as Dictionary<string, float>;
foreach (var item in scores)
{
Console.Write("{0}:{1}\n", item.Key, item.Value);
} Console.ReadKey();
}

使用[ServiceKnownType(typeof(Order))]放在服务契约上,使用[KnownType(typeof(Order))]放在数据契约上

[ServiceContract]
[ServiceKnownType(typeof(Order))]//可以放到这里
public interface IService1
{
[OperationContract]
//[ServiceKnownType(typeof(Order))]也可以放到这里
void AddOrder(OrderBase order);
}
[DataContract]
// [KnownType(typeof(Order))]也可以放到这里
public abstract class OrderBase
{
[DataMember]
public Guid ID { get; set; } [DataMember]
public DateTime Date { get; set; } [DataMember]
public string Customer { get; set; } [DataMember]
public string ShipAddress { get; set; }
}
[DataContract]
public class Order : OrderBase
{
[DataMember]
public double TotalPrice { get; set; }
} public class Service1 : IService1
{
public void AddOrder(OrderBase order)
{
Console.WriteLine(order.Customer);
}
} public class Program
{
static void Main(string[] args)
{
using (Service1Client client = new Service1Client())
{
Order order = new Order() { Customer = "yxl" };
client.AddOrder(order); }
Console.ReadKey();
}
}

如果不标识ServiceKnownType或KnownType,客户端将不会生成Order类

二、序列化

1.NET序列化机制

  在.NET Framework 3.0之前,提供了3中序列化器,序列化器理解为把可序列化的类型序列化成XML的类。这三种序列化器分别是BinaryFormatter、SoapFormatter和XmlSerializer类。下面分别介绍下这3种序列化器。

  • BinaryFormatter类:把.NET Object序列化成二进制格式。在这个过程,对象的公共字段和私有字段以及类名称(包括类的程序集名),将转换成成字节流。
  • SoapFormatter类:把.NET Object序列化成SOAP格式,SOAP是一种轻量、简单的,基于XML的协议。只序列化字段,包括公共字段和私有字段
  • XmlSerializer类:该类仅仅序列化公共字段和属性,且不保存类型的保真度。

  对于这三种序列化机制,BinaryFormatter二进制序列化的优点是:性能高,但是不能跨平台。而SoapFormatter,XmlSerializer的优点是:跨平台、互操作性好,并且可读性强,但是传输性能不及BinaryFormatter。

原有的格式化器需要将类型的程序集及版本控制信息持久化到流中,以保证对象被反序列化为正确的类型,这种方式一定程度上妨碍面向服务交互。原因如下:BinaryFormatter和SoapFormatter具备类型保真,它们要求其所在程序集、版本等信息必须完全一致,如果不同则视为是不同类型的对象,这就要求客户端必须拥有原有的.NET 程序集。面向服务的交互方式应该更倾向于平台无关,并最大限度的解耦,因此这2个格式化器显然与WCF有些不搭。再看XmlSerializer格式化器,在功能上与DataContractSerializer格式器类似,但是为何没有使用XmlSerializer格式器而是引人新格式器,我的理解如下:在SOA服务的构建过程中,提倡契约优先的构建原则,也就是说我们应该优先构建契约后构建具体的代码,在构建过程中并不考虑其具体的序列化过程。(契约优先相对于代码优先在设计层面具有更高的抽象程度,降低了服务设计与平台的耦合度,因此我更倾向于契约优先的开发顺序。)此外,XmlSerializer为如何将数据表示成XML提供了精确的控制,DataContractSerializer则提供了较少的控制,所以DataContractSerializer的序列化过程是可预知的,容易优化,所以它与XmlSerializer相比有更好的性能(我查到的数字是提升了约10%)。  

2.WCF中序列化机制

在WCF中,提供了专门用来序列化和反序列操作的类,该类就是DataContractSerializer类。一般而言,WCF会自动选择使用DataContractSerializer来对可序列话数据契约进行序列化,不需要开发者直接调用。WCF除了支持DataContractSerializer类来进行序列化外,还支持另外两种序列化器,这两种序列化器分别为:XMLSerializer(定义在System.XML.Serialization namespace)和NetDataContractSerializer (定义在System.XML.Serialization namespace)。XmlSerializer类不是WCF专用的类,Asp.net Web服务统一使用该类作为序列化器,但XmlSerializer类支持的类少于DataContractSerializer列支持的类型,但它允许对生成的XML进行更多的控制,并且支持更多的XML架构定义语言(XSD)标准。它不需要在可序列化类上有任何声明性的属性。

  默认情况下,WCF 使用 DataContractSerializer 类来序列化数据类型。 此序列化程序支持下列类型:

  • 基元类型(如:整数、字符串和字节数组)以及某些特殊类型(如 XmlElement 和 DateTime)。
  • 数据协定类型(用 DataContractAttribute 属性标记的类型)。
  • 用 SerializableAttribute 属性标记的类型,包括实现 ISerializable 接口的类型。
  • 实现 IXmlSerializable 接口的类型。
  • 许多常见集合类型,包括许多泛型集合类型。

  DataContractSerializer类与NetDataContractSerializer类类似,它们之间主要的区别在于:在使用NetDataContractSerializer进行序列化时,不需要指定序列化的类型,如:

NetDataContractSerializer serializer =
new NetDataContractSerializer(); // 不需要明确指定序列化的类型
serializer.WriteObject(writer, p); // 而使用DataContractSerializer需要明确指定序列化的类型
DataContractSerializer serializer =
new DataContractSerializer(typeof(Order)); // 需要明确指定序列化的类型
serializer.WriteObject(writer, p);

SerializableAttribute与DataContract异同。

相同点:都是标记类型为可序列化类型

不同点:在于序列化的成员不一样,DataContract是Opt-in(明确参与)的方式,即使用DataMember特性明确标识哪些成员需要序列化,而Serializable是Opt-out方式,即使用NoSerializable特性明确标识不参与序列化的成员。

我个人意见,DataContractSerializable就用在它应该用的地方吧,如果不是用WCF,还是不要用它了,它的序列化结果有一些微软专属的东西。对于来自网络的松散Xml接口数据,XmlSerializer是不二之选。如果想把对象完整地保存下来(数据与状态),同时又不需要被人看。那就用BinaryFormatter吧,SerializableAttribute默认是使用BinaryFormatter序列化的。

重温WCF之数据契约和序列化(四)的更多相关文章

  1. 重温WCF之数据契约中使用枚举(转载)(十一)

    转载地址:http://www.zhuli8.com/wcf/EnumMember.html 枚举类型的定义总是支持序列化的.当我们定义一个新的枚举时,不必应用DataContract特性,就可以在数 ...

  2. 跟我一起学WCF(7)——WCF数据契约与序列化详解

    一.引言 在前面博文介绍到,WCF的契约包括操作契约.数据契约.消息契约和错误契约,前面一篇博文已经结束了操作契约的介绍,接下来自然就是介绍数据契约了.所以本文要分享的内容就是数据契约. 二.数据契约 ...

  3. WCF分布式开发步步为赢(7):WCF数据契约与序列化

    本节继续学习WCF分布式开发步步为赢(7):WCF数据契约与序列化.数据契约是WCF应用程序开发中一个重要的概念,毫无疑问实现客户端与服务端数据契约的传递中序列化是非常重要的步骤.那么序列化是什么?为 ...

  4. WCF之数据契约

    从抽象层面看,WCF能够托管CLR类型(接口和类)并将它们公开为服务,也能够以本地CLR接口和类的方式使用服务.然而,CLR类型却属于.NET的特定技术.由于面向服务的一个核心原则就是在跨越服务边界时 ...

  5. WCF中数据契约之已知类型的几种公开方式

    WCF中传输的数据不想传统的面向对象编程,它只传递了一些对象的属性,但是自身并不知道自己属于什么对象,所以,他没有子类和父类的概念,因而也就没有Is-a的关系,所以在WCF中,如果想维持这种继承关系, ...

  6. WCF 之 数据契约

    前面几篇讲的都只能传递string类型的简单参数,数据契约就是用来解决如传递一个带有多个属性的Class类型的对象的. WCF推荐使用数据契约的方式实现数据的序列化.这部分的内容很好理解但是很重要,先 ...

  7. 重温WCF之消息契约(MessageContract)(六)

    对于SOAP来说主要由两部分构成Header和Body,他们两个共同构成了SOAP的信封,通常来说Body保存具体的数据内容,Header保存一些上下文信息或关键信息.比如:在一些情况下,具有这样的要 ...

  8. WCF技术剖析之十四:泛型数据契约和集合数据契约(下篇)

    原文:WCF技术剖析之十四:泛型数据契约和集合数据契约(下篇) [爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道<天天山海经>为此录制的节目视频(苏州话)]]在.NE ...

  9. WCF技术剖析之十二:数据契约(Data Contract)和数据契约序列化器(DataContractSerializer)

    原文:WCF技术剖析之十二:数据契约(Data Contract)和数据契约序列化器(DataContractSerializer) [爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济 ...

随机推荐

  1. OpenCV成长之路(10):视频的处理

    视频中包含的信息量要远远大于图片,对视频的处理分析也越来越成为计算机视觉的主流,而本质上视频是由一帧帧的图像组成,所以视频处理最终还是要归结于图像处理,但在视频处理中,有更多的时间维的信息可以利用.本 ...

  2. 2016年10月24日--HTML常用标签

    body的属性: bgcolor                页面背景色 background             背景壁纸.图片 text                     文字颜色 t ...

  3. ndk学习10: linux文件系统

    画了一天的思维导图,好累啊 一.概述 二.文件IO 三.缓冲区输入输出 四.高级IO 五.文件和目录 来自为知笔记(Wiz)

  4. 【IDEA】IDEA 如何设置编辑器字体大小

    intellij idea 如何更改编辑器文本字体和大小   换上了intellij idea之后,第一件事就是想要改变下文字字体,因为在我这个27寸的2k分辨率的屏幕上,文字显然太小了. intel ...

  5. [k]css盒模型

    box-sizing :  content-box || border-box || inherit 1.content-box:此值为其默认值.元素的宽度/高度(width/height)等于元素边 ...

  6. Unity3d 残影效果(狂拽炫酷叼炸天)

    效果图,真的很叼啊 我根据别人的改进了一版,支持MeshFilter上的Mesh(需要确保Mesh的Read/Write是开启的否则不能正常工作) 非常感谢原作者给提供思路.http://blog.c ...

  7. ACM/ICPC 之 DFS范例(ZOJ2412-ZOJ1008)

    通过几道例题简单阐述一下DFS的相关题型 ZOJ2412-Farm Irrigation 直观的DFS题型,稍加变化,记录好四个方向上的通路就能够做出来 题目和接水管类似,问最少要灌溉几次,即求解最少 ...

  8. winrt 真正的绑定任意命令

    下载codeplex上的winrttrigger开源控件 Winrt.Tirgger.EventTrigger trigger = new Winrt.Tirgger.EventTrigger();  ...

  9. Match:Cyclic Nacklace(KMP的next数组的高级应用)(HDU 3746)

    串珠子 题目大意:给定一个字串,要你找到如果要使之成为循环串,在末尾需要的最小的字数(只能添加字符,不能删减字符) 首先联动一下之前做过的动态规划问题POJ 3280,当然了3280这一题是用的LD, ...

  10. Match:Blue Jeans(POJ 3080)

    DNA序列 题目大意:给你m串字符串,要你找最长的相同的连续字串 这题暴力kmp即可,注意要按字典序排序,同时,是len<3才输出no significant commonalities #in ...