# 跟我一起学WCF(7)——WCF数据契约与序列化详解
## 一、引言
在前面博文介绍到,WCF的契约包括操作契约、数据契约、消息契约和错误契约,前面一篇博文已经结束了操作契约的介绍,接下来自然就是介绍数据契约了。所以本文要分享的内容就是数据契约。
## 二、数据契约的介绍
在WCF中,服务契约定义了可供调用的服务操作方法,而数据契约则是定义了服务端和客户端之间传送的自定义类型,在WCF项目中,必不可少地是传递数据,把客户端需要传递的数据传送到服务中,服务接收到数据再对其进行处理。然而在WCF中,传递的类型必须标记为[DataContractAttribute](http://msdn.microsoft.com/zh-cn/library/system.runtime.serialization.datacontractattribute(v=vs.110).aspx)属性,且只有标记了DataMemberAttribute属性的属性才会被传送。下面代码是一个数据契约使用的示例:
```
1 [DataContract] // 数据契约属性声明
2 public class User
3 {
4 [DataMember(Name = "UserName")]//定义别名
5 public string Name
6 { get; set; }
7 [DataMember]
8 public string Password { get; set; }
9 [DataMember]
10 public string Email { get; set; }
11
12 // 没有[DataMember]声明将不会序列化传送
13 public string Mobile { get; set; }
14
15 public string Test { get; set; }
16 }
```
上面代码在类User上使用了DataContract属性声明,则表明User类是可被WCF序列化程序可识别,并且可被序列化的。但是不是User所有数据成员都可以被需要列,只有声明了DataMemberAttribute的属性才可以被序列化。因此,在上面代码中,不会传输Mobile和Test的任何信息。同时也可以为声明为DataMember的成员定义客户端可见的别名,如DataMember(Name= "UserName"),这样在生成客户端代码时,User类定义的就是UserName属性,而不是在服务中定义的Name属性了。
## 三、序列化的详细介绍
WCF的实现原理沿用了[.NET Remoting](http://www.cnblogs.com/zhili/p/NETRemoting.html)的实现机制,客户端在调用服务公开的服务方法,这个过程必然涉及到数据的传输过程,包括客户端传输相关需要处理的数据给服务或服务传输相关处理后的结果数据给客户端。在数据传输的过程中,自然就需要进行序列化的操作,通过序列化把.NET Object序列化成可保存或传输的形式,然后通过网络协议在网络上进行传递。对于序列化的实现是由序列化器(Serializer)来负责完成的,序列化的实现原理可以理解为通过反射机制分析程序集中对应的类型,然后把对应的类型映射为一个XML的结构。
序列化在.NET Framework相关专题就有所介绍,所以它并不是一个新的概念,相关内容可以参考MSDN:[序列化](http://msdn.microsoft.com/zh-cn/library/7ay27kt9(v=vs.100).aspx)。然而.NET本身的序列化机制在WCF程序中并不适应,所以WCF又提出了新的序列化器。下面分别介绍下.NET 序列化机制和WCF中序列化机制。
## 3.1 .NET序列化机制
在.NET Framework 3.0之前,提供了3中序列化器,序列化器理解为把可序列化的类型序列化成XML的类。这三种序列化器分别是[BinaryFormatter](http://msdn.microsoft.com/zh-cn/library/system.runtime.serialization.formatters.binary.binaryformatter(v=vs.110).aspx)、[SoapFormatter](http://msdn.microsoft.com/zh-cn/library/system.runtime.serialization.formatters.soap.soapformatter(v=vs.110).aspx)和[XmlSerializer](http://msdn.microsoft.com/zh-cn/library/system.xml.serialization.xmlserializer(v=vs.110).aspx)类。下面分别介绍下这3种序列化器。
* BinaryFormatter类:把.NET Object序列化成二进制格式。在这个过程,对象的**公共字段和私有字段**以及类名称(包括类的程序集名),将转换成成字节流。
* SoapFormatter类:把.NET Object序列化成SOAP格式,SOAP是一种轻量、简单的,基于XML的协议。只序列化字段,包括**公共字段和私有字段**。
* XmlSerializer类:该类仅仅序列化**公共字段和属性,**且不保存类型的保真度。
对于这三种序列化机制,BinaryFormatter二进制序列化的优点是:性能高,但是不能跨平台。而SoapFormatter,XmlSerializer的优点是:跨平台、互操作性好,并且可读性强,但是传输性能不及BinaryFormatter。
在.NET原有的序列化机制中,BinaryFormatter和SoapFormatter除了要序列化对象的状态信息外,还会将程序集和版本信息持久化到流中,因为只有这样才能保证对象呗反序列为正确的对象类型副本,这就要求客户端必须拥有原有的.NET 程序集,不能满足跨平台的需求。所以WCF不得不定义自己的序列化机制来满足面向服务的需求。
## 3.2 WCF中序列化机制
在WCF中,提供了专门用来序列化和反序列操作的类,该类就是[DataContractSerializer](http://msdn.microsoft.com/zh-cn/library/system.runtime.serialization.datacontractserializer(v=vs.110).aspx)类。一般而言,WCF会自动选择使用DataContractSerializer来对可序列话数据契约进行序列化,不需要开发者直接调用。WCF除了支持DataContractSerializer类来进行序列化外,还支持另外两种序列化器,这两种序列化器分别为:XMLSerializer(定义在System.XML.Serialization namespace)和[NetDataContractSerializer](http://msdn.microsoft.com/zh-cn/library/system.runtime.serialization.netdatacontractserializer(v=vs.110).aspx) (定义在System.XML.Serialization namespace)。XmlSerializer类不是WCF专用的类,Asp.net Web服务统一使用该类作为序列化器,但XmlSerializer类支持的类少于DataContractSerializer列支持的类型,但它允许对生成的XML进行更多的控制,并且支持更多的XML架构定义语言(XSD)标准。它不需要在可序列化类上有任何声明性的属性。
DataContractSerializer class to serialize data types.">默认情况下,WCF 使用 [DataContractSerializer](http://msdn.microsoft.com/zh-cn/library/system.runtime.serialization.datacontractserializer(v=vs.110).aspx) 类来序列化数据类型。 此序列化程序支持下列类型:
* XmlElement and DateTime, which are treated as primitives.">基元类型(如:整数、字符串和字节数组)以及某些特殊类型(如 [XmlElement](http://msdn.microsoft.com/zh-cn/library/system.xml.xmlelement(v=vs.110).aspx) 和 [DateTime](http://msdn.microsoft.com/zh-cn/library/system.datetime(v=vs.110).aspx))。
* DataContractAttribute attribute).">数据协定类型(用 [DataContractAttribute](http://msdn.microsoft.com/zh-cn/library/system.runtime.serialization.datacontractattribute(v=vs.110).aspx) 属性标记的类型)。
* SerializableAttribute attribute, which include types that implement the ISerializable interface.">用 [SerializableAttribute](http://msdn.microsoft.com/zh-cn/library/system.serializableattribute(v=vs.110).aspx) 属性标记的类型,包括实现 [ISerializable](http://msdn.microsoft.com/zh-cn/library/system.runtime.serialization.iserializable(v=vs.110).aspx) 接口的类型。
* IXmlSerializable interface.">实现 [IXmlSerializable](http://msdn.microsoft.com/zh-cn/library/system.xml.serialization.ixmlserializable(v=vs.110).aspx) 接口的类型。
* 许多常见集合类型,包括许多泛型集合类型。
DataContractSerializer类与NetDataContractSerializer类类似,它们之间主要的区别在于:在使用NetDataContractSerializer进行序列化时,不需要指定序列化的类型,如:
```
NetDataContractSerializer serializer =
new NetDataContractSerializer(); // 不需要明确指定序列化的类型
serializer.WriteObject(writer, p);
// 而使用DataContractSerializer需要明确指定序列化的类型
DataContractSerializer serializer =
new DataContractSerializer(**typeof(Order)**); // 需要明确指定序列化的类型
serializer.WriteObject(writer, p);
```
## 四、WCF数据契约使用例子
介绍了那么多关于数据契约和序列化内容的介绍,下面看看数据契约具体使用的例子。
要使用数据契约,自然第一步是定义数据契约,具体数据契约的定义如下所示:
```
namespace BusinessEntity
{
[DataContract]// 数据契约属性声明
public class User
{
[DataMember(Name = "UserName")]//定义别名
public string Name
{ get; set; }
[DataMember]
public string Password { get; set; }
[DataMember]
public string Email { get; set; }
// 没有[DataMember]声明将不会序列化传送
public string Mobile { get; set; }
public string Test { get; set; }
}
}
```
第二步:定义完数据契约后,接下来就要定义我们的服务契约和服务契约的实现了。具体的实现代码如下所示:
```
// 服务契约
[ServiceContract]
//[ServiceKnownType(typeof(Order))] // 这是为了演示WCF已知类型
public interface IUserValidationService
{
[OperationContract]
bool AddNewUser(User user);
[OperationContract]
User GetUserByName(string name);
// 为了演示已知类型的操作方法
//[OperationContract]
//[ServiceKnownType(typeof(Order))]
//bool AddOrder(OrderBase order);
}
// 服务契约的实现
public class UserValidationService : IUserValidationService
{
public bool AddNewUser(User user)
{
return true;
}
public User GetUserByName(string name)
{
User user = new User { Name = name, Password = "123", Email = "123456@qq.com", Mobile = "13912331245" };
return user;
}
// 演示已知类型的操作方法
//public bool AddOrder(OrderBase order)
//{
// return true;
//}
}
```
对应的配置文件代码为:
```
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="UserServiceBehavior">
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service name="WCFServiceAndHost.UserValidationService" behaviorConfiguration="UserServiceBehavior">
<endpoint address="" binding="wsHttpBinding" contract="WCFServiceAndHost.IUserValidationService"></endpoint>
</service>
</services>
</system.serviceModel>
```
第三步:定义完服务之后,接下来就需要实现我们的客户端来访问服务方法了。首先,通过添加服务引用的方式来生成服务客户端代理类,生成的代理类中,User的定义如下代码所示:
```
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="User", Namespace="http://schemas.datacontract.org/2004/07/BusinessEntity")]
[System.SerializableAttribute()]
public partial class User : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged
{
....
}
```
从上面代码标红的部分可以看出,服务中定义的User只应用了DataContractAttribute属性,但生成的客户端User类中多了一个SerializableAtttribute。对于SerializableAttribute属性的作用与DataContract的作用是一样的,都是标记为该类支持序列化。因为在默认情况下,用户定义的类型并不支持序列化,只有应用了SerializableAttribute或DataContractAttribute属性的,.NET序列化器才能对该类型进行序列化。然而这两者又存在不同, Serializable要求它的所有程序都要支持序列化,如果发现不支持序列化的成员就会抛出异常,即Serializable会把类型的所有成员都进行序列化,如果想某个成员不序列化化,则必须显式标记NoSerialized属性;而DataContract却不同,标记了DataContract属性的类只有标记了DataMember的成员才会被序列化,如果想类型的成员能够序列化,则应该应用DataMember属性。如果某个类型同时应用了DataContract和Serialized属性,如上面代码的User类,此时该类型将会只应用DataContract,即Serialized属性会忽略。我刚开始的疑问是,User类应用这两个属性,因为这两个属性对序列化成员有所区别,当时就纳闷到底是采取那个属性进行序列化的呢?经过查阅资料才发现了上面的结论,更多信息参考:[Serialization in Windows Communication Foundation](http://msdn.microsoft.com/zh-cn/magazine/cc163569(en-us).aspx)。
然后利用该代理类实现对服务操作的调用,具体的实现代码如下所示:
```
namespace Client
{
class Program
{
static void Main(string[] args)
{
UserValidationServiceClient wcfServiceProxy = new UserValidationServiceClient();
User newUser = new User() { UserName = "LearningHard", Email = "123456@qq.com", Password = "123" };
wcfServiceProxy.AddNewUser(newUser);
// 演示已知类型的问题
//Order order = new Order() { ID = Guid.NewGuid(), Date = DateTime.Now, Customer = "customer1", ShipAddress = "Shanghai", TotalPrice = 20.00 };
//wcfServiceProxy.AddOrder(order);
// 获得用户信息
string name = "Learning Hard Client";
User user = wcfServiceProxy.GetUserByName(name);
if (user != null)
{
Console.WriteLine("User Name is: " + user.UserName);
Console.WriteLine("Email is: " + user.Email);
}
Console.WriteLine("Press any key to continue...");
Console.Read();
}
}
}
```
经过上面的三步之后,我们就完成了WCF数据契约的实现。对于服务契约的调用过程是:客户端把相关需要序列化的对象序列化成XML格式,这里的格式与绑定的协议有关,因为上面设置的传输协议为http,所以这里应该序列化成XML格式的数据,然后再通过Http协议进行网络传递到服务,服务程序接收到传输过来的XML格式的数据,则利用DataContractSerializer反序列成User对象作为参数传递给AddNewUser方法;接着服务再把处理的后结果序列化成XML格式数据传递到客户端,客户端接收到服务程序响应的消息再进行反序列成具体的对象类型。对于操作GetUserByName的调用也是类似的。具体的运行结果如下图所示:
![](https://box.kancloud.cn/2016-01-23_56a2eb488d9ed.png)
## 五、已知类型(KnownType)
因为WCF中使用DataContractSerializer进行序列化和反序列化的,由于DataContractSerializer进行序列化和反序列化时,都必须事先确定对象的类型。如果被序列化对象或反序列化生成的对象包含不可知的类型,序列化或反序列化将失败。所以为了保证DataContractSerializer正常的序列化和反序列化,需要将“未知”类型加入DataContractSerializer“已知”类型列表中。例如下面的服务契约:
```
// 服务契约
[ServiceContract]
//[ServiceKnownType(typeof(Order))] // 这是为了演示WCF已知类型
public interface IUserValidationService
{
// 为了演示已知类型的操作方法
[OperationContract]
[ServiceKnownType(typeof(Order))]
bool AddOrder(OrderBase order);
}
```
假如,客户端同时定义了一个Order类:
以下代码能够成功通过编译,但在运行时却会失败:
原因在于我们并没有实际传递对象的引用,而是传递的是对象的XML结构。在上面的例子中,当我们传递的是Order对象而不是OrderBase对象时,服务并不知道它应该反序列为Order对象。
对于上面问题的解决办法就是让DataContractSerializer能够识别Order类型,成为DataContractSerializer的已知类型(Known Type)。DataContractSerializer内部具有一个已知类型的列表,我们需要将Order类型添加到这个列表中。对于已知类型,可以通过两个特性设置:KnownTypeAttribute和ServiceKnownTypeAttribute。KnownTypeAttribute应用于数据契约中,用于设置继承于该数据契约类型的子数据契约,或引用其他的契约类型。ServiceKnownTypeAttribute既可以应用于服务契约的接口和方法上,还可以应用在服务实现的类和方法上,应用在不同的目标元素,决定了定义已知类型的作用范围,下面,通过在基类OrderBase指定了子契约的类型Order:
而ServiceKnownTypeAttribute特性,不仅可以使用在服务契约类型上,还可以应用在服务契约的操作方法上。如果应用在服务契约类型上,则已知类型在所有实现了该契约的服务操作中都有效,即作用范围为服务契约界别的,如果应用于服务契约的操作方法上,则定义的已知类型仅在实现了该契约的服务操作中有效。
```
// 服务契约
[ServiceContract]
[ServiceKnownType(typeof(Order))] // 服务契约级别
public interface IUserValidationService
{
// 为了演示已知类型的操作方法
//[OperationContract]
//[ServiceKnownType(typeof(Order))] // 单个服务操作级别
bool AddOrder(OrderBase order);
}
```
除了通过特性的方式设置已知类型外,还可以通过配置文件的方式来进行指定。已知类型定义在<System.runtime.serialization>配置节点中,可以采用下面的方式来定义:
```
<configuration>
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="BusinessEntity.OrderBase,BusinessEntity.KnownTypes">
<knownType type="BusinessEntity.Order,BusinessEntity.KnownTypes"/>
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
</configuration>
```
## 六、总结
到这里,数据契约的分享就结束。对于这篇博文首先介绍了数据契约和序列化的基本知识,接着介绍了.NET中的序列化机制和WCF中序列化机制,最后完成了一个数据契约的例子。看完本篇文章应该明确几个问题:
1. SerializableAttribute与DataContract异同。
答:相同点:都是标记类型为可序列化类型
不同点:在于序列化的成员不一样,DataContract是Opt-in(明确参与)的方式,即使用DataMember特性明确标识哪些成员需要序列化,而Serializable是Opt-out方式,即使用NoSerializable特性明确标识不参与序列化的成员。
2\. BinartFormatter、DataContractSerializer和XmlSerializer的区别,具体答案见下图和参考下面博文:[XmlSerializer, DataContractSerializer 和 BinaryFormatter区别与用法分析](http://www.cnblogs.com/nankezhishi/archive/2012/05/12/serializationcompare.html)。
![](https://box.kancloud.cn/2016-01-23_56a2eb489f366.png)
好的博文记录:[Create and Consume RESTFul Service in .NET Framework 4.0](http://www.codeproject.com/Articles/255684/Create-and-Consume-RESTFul-Service-in-NET-Framewor)
本文所有源代码下载:[WCFDataContract.zip](http://files.cnblogs.com/zhili/WCFDataContract.zip)
- C# 基础知识系列
- C# 基础知识系列 专题一:深入解析委托——C#中为什么要引入委托
- C# 基础知识系列 专题二:委托的本质论
- C# 基础知识系列 专题三:如何用委托包装多个方法——委托链
- C# 基础知识系列 专题四:事件揭秘
- C# 基础知识系列 专题五:当点击按钮时触发Click事件背后发生的事情
- C# 基础知识系列 专题六:泛型基础篇——为什么引入泛型
- C# 基础知识系列 专题七: 泛型深入理解(一)
- C# 基础知识系列 专题八: 深入理解泛型(二)
- C# 基础知识系列 专题九: 深入理解泛型可变性
- C#基础知识系列 专题十:全面解析可空类型
- C# 基础知识系列 专题十一:匿名方法解析
- C#基础知识系列 专题十二:迭代器
- C#基础知识 专题十三:全面解析对象集合初始化器、匿名类型和隐式类型
- C# 基础知识系列 专题十四:深入理解Lambda表达式
- C# 基础知识系列 专题十五:全面解析扩展方法
- C# 基础知识系列 专题十六:Linq介绍
- C#基础知识系列 专题十七:深入理解动态类型
- 你必须知道的异步编程 C# 5.0 新特性——Async和Await使异步编程更简单
- 全面解析C#中参数传递
- C#基础知识系列 全面解析C#中静态与非静态
- C# 基础知识系列 C#中易混淆的知识点
- C#进阶系列
- C#进阶系列 专题一:深入解析深拷贝和浅拷贝
- C#进阶系列 专题二:你知道Dictionary查找速度为什么快吗?
- C# 开发技巧系列
- C# 开发技巧系列 使用C#操作Word和Excel程序
- C# 开发技巧系列 使用C#操作幻灯片
- C# 开发技巧系列 如何动态设置屏幕分辨率
- C# 开发技巧系列 C#如何实现图片查看器
- C# 开发技巧 如何防止程序多次运行
- C# 开发技巧 实现属于自己的截图工具
- C# 开发技巧 如何使不符合要求的元素等于离它最近的一个元素
- C# 线程处理系列
- C# 线程处理系列 专题一:线程基础
- C# 线程处理系列 专题二:线程池中的工作者线程
- C# 线程处理系列 专题三:线程池中的I/O线程
- C# 线程处理系列 专题四:线程同步
- C# 线程处理系列 专题五:线程同步——事件构造
- C# 线程处理系列 专题六:线程同步——信号量和互斥体
- C# 多线程处理系列专题七——对多线程的补充
- C#网络编程系列
- C# 网络编程系列 专题一:网络协议简介
- C# 网络编程系列 专题二:HTTP协议详解
- C# 网络编程系列 专题三:自定义Web服务器
- C# 网络编程系列 专题四:自定义Web浏览器
- C# 网络编程系列 专题五:TCP编程
- C# 网络编程系列 专题六:UDP编程
- C# 网络编程系列 专题七:UDP编程补充——UDP广播程序的实现
- C# 网络编程系列 专题八:P2P编程
- C# 网络编程系列 专题九:实现类似QQ的即时通信程序
- C# 网络编程系列 专题十:实现简单的邮件收发器
- C# 网络编程系列 专题十一:实现一个基于FTP协议的程序——文件上传下载器
- C# 网络编程系列 专题十二:实现一个简单的FTP服务器
- C# 互操作性入门系列
- C# 互操作性入门系列(一):C#中互操作性介绍
- C# 互操作性入门系列(二):使用平台调用调用Win32 函数
- C# 互操作性入门系列(三):平台调用中的数据封送处理
- C# 互操作性入门系列(四):在C# 中调用COM组件
- CLR
- 谈谈: String 和StringBuilder区别和选择
- 谈谈:程序集加载和反射
- 利用反射获得委托和事件以及创建委托实例和添加事件处理程序
- 谈谈:.Net中的序列化和反序列化
- C#设计模式
- UML类图符号 各种关系说明以及举例
- C#设计模式(1)——单例模式
- C#设计模式(2)——简单工厂模式
- C#设计模式(3)——工厂方法模式
- C#设计模式(4)——抽象工厂模式
- C#设计模式(5)——建造者模式(Builder Pattern)
- C#设计模式(6)——原型模式(Prototype Pattern)
- C#设计模式(7)——适配器模式(Adapter Pattern)
- C#设计模式(8)——桥接模式(Bridge Pattern)
- C#设计模式(9)——装饰者模式(Decorator Pattern)
- C#设计模式(10)——组合模式(Composite Pattern)
- C#设计模式(11)——外观模式(Facade Pattern)
- C#设计模式(12)——享元模式(Flyweight Pattern)
- C#设计模式(13)——代理模式(Proxy Pattern)
- C#设计模式(14)——模板方法模式(Template Method)
- C#设计模式(15)——命令模式(Command Pattern)
- C#设计模式(16)——迭代器模式(Iterator Pattern)
- C#设计模式(17)——观察者模式(Observer Pattern)
- C#设计模式(18)——中介者模式(Mediator Pattern)
- C#设计模式(19)——状态者模式(State Pattern)
- C#设计模式(20)——策略者模式(Stragety Pattern)
- C#设计模式(21)——责任链模式
- C#设计模式(22)——访问者模式(Vistor Pattern)
- C#设计模式(23)——备忘录模式(Memento Pattern)
- C#设计模式总结
- WPF快速入门系列
- WPF快速入门系列(1)——WPF布局概览
- WPF快速入门系列(2)——深入解析依赖属性
- WPF快速入门系列(3)——深入解析WPF事件机制
- WPF快速入门系列(4)——深入解析WPF绑定
- WPF快速入门系列(5)——深入解析WPF命令
- WPF快速入门系列(6)——WPF资源和样式
- WPF快速入门系列(7)——深入解析WPF模板
- WPF快速入门系列(8)——MVVM快速入门
- WPF快速入门系列(9)——WPF任务管理工具实现
- ASP.NET 开发
- ASP.NET 开发必备知识点(1):如何让Asp.net网站运行在自定义的Web服务器上
- ASP.NET 开发必备知识点(2):那些年追过的ASP.NET权限管理
- ASP.NET中实现回调
- 跟我一起学WCF
- 跟我一起学WCF(1)——MSMQ消息队列
- 跟我一起学WCF(2)——利用.NET Remoting技术开发分布式应用
- 跟我一起学WCF(3)——利用Web Services开发分布式应用
- 跟我一起学WCF(3)——利用Web Services开发分布式应用
- 跟我一起学WCF(4)——第一个WCF程序
- 跟我一起学WCF(5)——深入解析服务契约 上篇
- 跟我一起学WCF(6)——深入解析服务契约 下篇
- 跟我一起学WCF(7)——WCF数据契约与序列化详解
- 跟我一起学WCF(8)——WCF中Session、实例管理详解
- 跟我一起学WCF(9)——WCF回调操作的实现
- 跟我一起学WCF(10)——WCF中事务处理
- 跟我一起学WCF(11)——WCF中队列服务详解
- 跟我一起学WCF(12)——WCF中Rest服务入门
- 跟我一起学WCF(13)——WCF系列总结
- .NET领域驱动设计实战系列
- .NET领域驱动设计实战系列 专题一:前期准备之EF CodeFirst
- .NET领域驱动设计实战系列 专题二:结合领域驱动设计的面向服务架构来搭建网上书店
- .NET领域驱动设计实战系列 专题三:前期准备之规约模式(Specification Pattern)
- .NET领域驱动设计实战系列 专题四:前期准备之工作单元模式(Unit Of Work)
- .NET领域驱动设计实战系列 专题五:网上书店规约模式、工作单元模式的引入以及购物车的实现
- .NET领域驱动设计实战系列 专题六:DDD实践案例:网上书店订单功能的实现
- .NET领域驱动设计实战系列 专题七:DDD实践案例:引入事件驱动与中间件机制来实现后台管理功能
- .NET领域驱动设计实战系列 专题八:DDD案例:网上书店分布式消息队列和分布式缓存的实现
- .NET领域驱动设计实战系列 专题九:DDD案例:网上书店AOP和站点地图的实现
- .NET领域驱动设计实战系列 专题十:DDD扩展内容:全面剖析CQRS模式实现
- .NET领域驱动设计实战系列 专题十一:.NET 领域驱动设计实战系列总结