从零开始学WCF(8)Message类
来源:互联网 发布:淘宝秒杀无门槛券技巧 编辑:程序博客网 时间:2024/05/16 11:01
Message类概述
Message类是WCF的基本类。
客户端与服务之间的所有通信最终都会产生要进行发送和接收的Message实例。
通常不会与Message类直接进行交互。相反,需要使用WCF服务模型构造(如数据协定、消息协定和操作协定)来描述传入消息和传出消息。
在以下情况下可能需要使用Message类:
1) 需要一种替代方式来创建传出的消息内容(例如:从磁盘上的文件直接创建消息),而不是序列化.NET Framework对象。
2) 需要一种替代方式来使用传入的消息内容(例如:需要将XSLT转换应用于原始的XML内容),而不是反序列化成为.NET Framework对象。
3) 无论消息内容怎样都需要使用常规方式来处理消息(例如,在生成路由器、负载平衡器或发布-订阅系统时对消息进行路由或转发)。
在操作中使用Message类
可以将Message类用作操作的输入参数和/或操作的返回值。只要在操作中的任何位置使用了Message,就必须遵守以下限制:
1) 操作不能具有任何out或ref参数。
2) 不能有一个以上的input参数。如果该参数存在,其类型必须为Message或消息协定。
3) 返回类型必须为void、Message或消息协定类型。
创建简单消息
1. Message类提供了静态CrateMessage工厂方法
1) 所有CreateMessage重载都采用了一个类型为MessageVersion的版本参数,该参数只是要用于消息的SOAP和WS-Addressing版本。如果要使用与传入消息相同的协议版本,则可以使用OperationContext实例(从Current属性获取)上的IncomingMessageVersion属性。
2) 大多数CreateMessage重载还具有一个字符串参数,该参数只是要用于消息的SOAP操作。
3) 可以将版本设置为None以金庸SOAP信封生成;消息将仅包含正文。
2. 另一种重载采用一个附加的Object参数;此重载所创建的消息的正文是给定对象的序列化表示。
从XML读取器创建消息
有些CreateMessage重载采用一个XmlReader或一个XmlDictionaryReader而不是对象作为正文。
创建错误消息
可以使用某些CreateMessage重载创建SOAP错误信息。其中一个最简单的重载采用一个用于描述错误的MessageFault对象作为参数。
DEMO
1) 新建一个WCF Service Application——“Video8.Demo1.XmlReader”,删除默认生成的服务后,添加WCF Service——“CalculatorService”,在WCF服务接口中定义WCF服务,定义Message
using System;using System.Collections.Generic;using System.Linq;using System.Runtime.Serialization;using System.ServiceModel;using System.Text;using System.ServiceModel.Channels;namespace Video8.Demo1.XmlReader{ // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "ICalculatorService" in both code and config file together. [ServiceContract(Namespace = "http://Video8.Demo1.XmlReader")] public interface ICalculatorService { [OperationContract] Message Sum(Message request); [OperationContract] Message GetFirst(); //[OperationContract] //Message GetData(); //[OperationContract] //Message GetDataStream(); //[OperationContract] //Message GetDataFault(); }}
2) 在CalculatorService中实现ICalculatorService这个WCF服务类:
using System;using System.Collections.Generic;using System.Linq;using System.Runtime.Serialization;using System.ServiceModel;using System.Text;using System.ServiceModel.Channels;using System.Xml;using System.IO;using System.Globalization;namespace Video8.Demo1.XmlReader{ // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "CalculatorService" in code, svc and config file together. public class CalculatorService : ICalculatorService { public Message Sum(Message request) { int sum = 0; string text = ""; //以读取器的方式拿到Message内容 System.Xml.XmlReader body = request.GetReaderAtBodyContents(); //循环获取Messagebody里的值 while (body.Read()) { text = body.ReadString().Trim(); if (text.Length > 0) { sum += Convert.ToInt32(text, CultureInfo.InvariantCulture); } } body.Close(); //由于这个是有传入消息,就可以使用request.Version来获得SOAP协议的版本了 Message response = Message.CreateMessage(request.Version, "http://Video8.Demo1.XmlReader/ICalculatorService/SumResponse", sum); return response; } public Message GetFirst() { //创建一个最简单的消息,首先获得当前上下文传入的Message版本,由于是没有传入消息所以要使用上下文来获取Message版本信息 MessageVersion ver = OperationContext.Current.IncomingMessageVersion; //使用静态方法创建Message,http会序列化成客户端的ReplyActionAttribute属性内容 return Message.CreateMessage(ver, "http://Video8.Demo1.XmlReader/ICalculatorService/GetFirstResponse"); } }}
3) 配置Web.config信息:
<?xml version="1.0" encoding="utf-8" ?><configuration> <system.serviceModel> <services> <service name="Video8.Demo1.XmlReader.CalculatorService" behaviorConfiguration="CalculatorServiceBehavior"> <endpoint address="" binding="wsHttpBinding" bindingConfiguration="PortSharingBinding" contract="Video8.Demo1.XmlReader.ICalculatorService"/> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="CalculatorServiceBehavior"> <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment --> <serviceMetadata httpGetEnabled="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="true"/> </behavior> </serviceBehaviors> </behaviors> <bindings> <wsHttpBinding> <binding name="PortSharingBinding"> <security mode="None"/> </binding> </wsHttpBinding> </bindings> </system.serviceModel> </configuration>
4) 部署配置到IIS上后,创建客户端应用程序Client,添加该WCF服务,打开Reference.cs客户端代理类可以看到这里生成的GetFirst()方法标记了ReplyAction="http://Video8.Demo1.XmlReader/ICalculatorService/GetFirstResponse"这个正式我们在服务端使用了return Message.CreateMessage(ver, "http://Video8.Demo1.XmlReader/ICalculatorService/GetFirstResponse");而自动生成的ReplayAction。
[System.ServiceModel.OperationContractAttribute(Action="http://Video8.Demo1.XmlReader/ICalculatorService/GetFirst", ReplyAction="http://Video8.Demo1.XmlReader/ICalculatorService/GetFirstResponse")] System.ServiceModel.Channels.Message GetFirst();
5) 然后再Main方法中进行测试:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel.Channels;namespace Client{ class Program { static void Main(string[] args) { ServiceReference1.CalculatorServiceClient client = new ServiceReference1.CalculatorServiceClient(); Message Replay1 = client.GetFirst(); Console.WriteLine(Replay1.ToString()); client.Close(); Console.ReadKey(); } }}
6) 运行一下该客户端程序,在客户端生成一个新的消息Replay1,然后我们打印出来可以看到,这是一个空的消息类,只有信封信息。
7) 然后我们在WCF服务里增加Sum方法,在ICalculatorService里增加:
using System;using System.Collections.Generic;using System.Linq;using System.Runtime.Serialization;using System.ServiceModel;using System.Text;using System.ServiceModel.Channels;namespace Video8.Demo1.XmlReader{ // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "ICalculatorService" in both code and config file together. [ServiceContract(Namespace = "http://Video8.Demo1.XmlReader")] public interface ICalculatorService { [OperationContract] Message Sum(Message request); [OperationContract] Message GetFirst(); //[OperationContract] //Message GetData(); //[OperationContract] //Message GetDataStream(); //[OperationContract] //Message GetDataFault(); }}
8) 在CalculatorService类里实现WCF服务接口
using System;using System.Collections.Generic;using System.Linq;using System.Runtime.Serialization;using System.ServiceModel;using System.Text;using System.ServiceModel.Channels;using System.Xml;using System.IO;using System.Globalization;namespace Video8.Demo1.XmlReader{ // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "CalculatorService" in code, svc and config file together. public class CalculatorService : ICalculatorService { public Message Sum(Message request) { int sum = 0; string text = ""; //以读取器的方式拿到Message内容 System.Xml.XmlReader body = request.GetReaderAtBodyContents(); //循环获取Messagebody里的值 while (body.Read()) { text = body.ReadString().Trim(); if (text.Length > 0) { sum += Convert.ToInt32(text, CultureInfo.InvariantCulture); } } body.Close(); //由于这个是有传入消息,就可以使用request.Version来获得SOAP协议的版本了 Message response = Message.CreateMessage(request.Version, "http://Video8.Demo1.XmlReader/ICalculatorService/SumResponse", sum); return response; } public Message GetFirst() { //创建一个最简单的消息,首先获得当前上下文传入的Message版本,由于是没有传入消息所以要使用上下文来获取Message版本信息 MessageVersion ver = OperationContext.Current.IncomingMessageVersion; //使用静态方法创建Message,http会序列化成客户端的ReplyActionAttribute属性内容 return Message.CreateMessage(ver, "http://Video8.Demo1.XmlReader/ICalculatorService/GetFirstResponse"); } }}
9) 编译发布到IIS上后,更新客户端的服务代理类。更新后可以看到在Reference.cs这个代理类里,已经有Sum方法了,注意这里的ReplayAction也是在服务端指定的。
[System.ServiceModel.OperationContractAttribute(Action="http://Video8.Demo1.XmlReader/ICalculatorService/Sum", ReplyAction="http://Video8.Demo1.XmlReader/ICalculatorService/SumResponse")] System.ServiceModel.Channels.Message Sum(System.ServiceModel.Channels.Message request);
10) 然后再Main方法中进行测试:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel.Channels;using System.ServiceModel;namespace Client{ class Program { static void Main(string[] args) { ServiceReference1.CalculatorServiceClient client = new ServiceReference1.CalculatorServiceClient(); Message Replay1 = client.GetFirst(); Console.WriteLine(Replay1.ToString()); Console.WriteLine("————————————————"); using (new OperationContextScope(client.InnerChannel)) { //定义一个数组 int[] values = { 1, 2, 3, 4, 5 }; //生成一个Message对象,用于传入参数使用, //Message版本为当前上下文的输出信息的标头的版本信息,Message的action要与代理类调用该方法的action要一致。 //然后再传入values作为Message的参数 Message request = Message.CreateMessage(OperationContext.Current.OutgoingMessageHeaders.MessageVersion, "http://Video8.Demo1.XmlReader/ICalculatorService/Sum", values); //调用服务端sum方法,传入参数为上面生成的消息实例 Message replay = client.Sum(request); //Console.WriteLine(replay.ToString()); int sum = replay.GetBody<int>(); Console.WriteLine("Sum(1,2,3,4,5)={0}", sum); client.Close(); } Console.ReadKey(); } }}
11) 测试结果计算出了sum的值,这就是传入一个Message类型的参数后,在返回一个Message类型的参数。
12) 我们在来试试如何从一个对象类型来创建一个消息。在ICalculatorService里增加新的接口GetData:
using System;using System.Collections.Generic;using System.Linq;using System.Runtime.Serialization;using System.ServiceModel;using System.Text;using System.ServiceModel.Channels;namespace Video8.Demo1.XmlReader{ // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "ICalculatorService" in both code and config file together. [ServiceContract(Namespace = "http://Video8.Demo1.XmlReader")] public interface ICalculatorService { [OperationContract] Message Sum(Message request); [OperationContract] Message GetFirst(); //从一个对象来创建一个消息 [OperationContract] Message GetData(); //[OperationContract] //Message GetDataStream(); //[OperationContract] //Message GetDataFault(); }}
13) 添加一个消息协定Person类,用于在消息中使用:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Runtime.Serialization;using System.ServiceModel;namespace Video8.Demo1.XmlReader{ [MessageContract] public class Person { [MessageBodyMember] public string name; [MessageBodyMember] public int age; }}
14) 在CalculatorService里实现新增的WCF服务。
using System;using System.Collections.Generic;using System.Linq;using System.Runtime.Serialization;using System.ServiceModel;using System.Text;using System.ServiceModel.Channels;using System.Xml;using System.IO;using System.Globalization;namespace Video8.Demo1.XmlReader{ // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "CalculatorService" in code, svc and config file together. public class CalculatorService : ICalculatorService { public Message Sum(Message request) { int sum = 0; string text = ""; //以读取器的方式拿到Message内容 System.Xml.XmlReader body = request.GetReaderAtBodyContents(); //循环获取Messagebody里的值 while (body.Read()) { text = body.ReadString().Trim(); if (text.Length > 0) { sum += Convert.ToInt32(text, CultureInfo.InvariantCulture); } } body.Close(); //由于这个是有传入消息,就可以使用request.Version来获得SOAP协议的版本了 Message response = Message.CreateMessage(request.Version, "http://Video8.Demo1.XmlReader/ICalculatorService/SumResponse", sum); return response; } public Message GetFirst() { //创建一个最简单的消息,首先获得当前上下文传入的Message版本,由于是没有传入消息所以要使用上下文来获取Message版本信息 MessageVersion ver = OperationContext.Current.IncomingMessageVersion; //使用静态方法创建Message,http会序列化成客户端的ReplyActionAttribute属性内容 return Message.CreateMessage(ver, "http://Video8.Demo1.XmlReader/ICalculatorService/GetFirstResponse"); } //从一个对象类型来创建消息 public Message GetData() { Person p = new Person(); p.name = "wang"; p.age = 20; //服务端使用OperationContext.Current.IncomingMessageVersion来获取Message版本 //客户端使用OperationContext.Current.OutgoingMessageHeaders.MessageVersion来获取Message版本。 MessageVersion ver = OperationContext.Current.IncomingMessageVersion; //返回一个静态生成的Message实例,参数为版本信心;action;Person类的参数实例p。 return Message.CreateMessage(ver, "http://Video8.Demo1.XmlReader/ICalculatorService/GetDataResponse", p); } }}
15) 部署到IIS上后,更新client端的WCF服务。可以打开客户端代理类Reference.cs来看到,已经生成了我们添加的方法GetData,该方法的ReplayAction就是我们在WCF服务端定义的参数。
[System.ServiceModel.OperationContractAttribute(Action="http://Video8.Demo1.XmlReader/ICalculatorService/GetData", ReplyAction="http://Video8.Demo1.XmlReader/ICalculatorService/GetDataResponse")] System.ServiceModel.Channels.Message GetData();
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel;namespace Client{ [MessageContract] public class Person { [MessageBodyMember] public string name; [MessageBodyMember] public int age; }}
17) 这里还要注意的是要把客户端项目Client里的命名空间都改成与服务器端的命名空间一致:namespace Video8.Demo1.XmlReader
这样就可以进行在Main方法中测试了:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel.Channels;using System.ServiceModel;namespace Video8.Demo1.XmlReader{ class Program { static void Main(string[] args) { ServiceReference1.CalculatorServiceClient client = new ServiceReference1.CalculatorServiceClient(); Message Replay1 = client.GetFirst(); Console.WriteLine(Replay1.ToString()); Console.WriteLine("————————————————"); using (new OperationContextScope(client.InnerChannel)) { //定义一个数组 int[] values = { 1, 2, 3, 4, 5 }; //生成一个Message对象,用于传入参数使用, //Message版本为当前上下文的输出信息的标头的版本信息,Message的action要与代理类调用该方法的action要一致。 //然后再传入values作为Message的参数 Message request = Message.CreateMessage(OperationContext.Current.OutgoingMessageHeaders.MessageVersion, "http://Video8.Demo1.XmlReader/ICalculatorService/Sum", values); //调用服务端sum方法,传入参数为上面生成的消息实例 Message replay = client.Sum(request); //Console.WriteLine(replay.ToString()); int sum = replay.GetBody<int>(); Console.WriteLine("Sum(1,2,3,4,5)={0}", sum); Console.WriteLine("————————————————"); //GetData方法的调用 Message reply1 = client.GetData(); Console.WriteLine(reply1.ToString()); //获取GetBody类后转换成Person类赋值给Person类的实例p Person p = reply1.GetBody<Person>(); Console.WriteLine(p.name + " " + p.age); client.Close(); } Console.ReadKey(); } }}
18) 运行结果如下:可以看到在客户端调用该WCF服务后,获得了一个Message类,该Message类是由一个对象类型来创建的。
19) 我们添加一个xml文件来让Message读取后返回给客户端,首先在服务端项目里添加一个xml文件“myfile.xml”,然后再ICalculatorService里添加一个WCF服务接口:
//从一个XML文件读取创建一个消息 [OperationContract] Message GetDataStream();
20) 实现该WCF服务:
public Message GetDataStream() { FileStream stream = new FileStream(@"E:\开发知识\9. WCF\从零开始学WCF系列\DEMO\Video8.Demo1.XmlReader\Video8.Demo1.XmlReader\myfile.xml", FileMode.Open); //xml读取器来创建一个从没有file读取内容的读取器 XmlDictionaryReader xdr = XmlDictionaryReader.CreateTextReader(stream, new XmlDictionaryReaderQuotas()); MessageVersion ver = OperationContext.Current.IncomingMessageVersion; return Message.CreateMessage(ver, "http://Video8.Demo1.XmlReader/ICalculatorService/GetDataStreamResponse", xdr); }
21) 编译WCF服务后,更新到IIS上,在client项目里进行更新Service Reference。然后再Main方法里加入测试代码:
//从服务端的XML文件里读取Message Message reply2 = client.GetDataStream(); Console.WriteLine(reply2.ToString()); Console.WriteLine("+++++++++++++++++++"); //把从服务器端读取过来的Message存在客户端本地XML里 FileStream stream = new FileStream(@"C:\log.xml", FileMode.Create); XmlDictionaryWriter xdw = XmlDictionaryWriter.CreateTextWriter(stream); reply2.WriteBodyContents(xdw); Console.WriteLine("+++++++++++++++++++"); reply2.WriteBody(xdw); Console.WriteLine("+++++++++++++++++++"); reply2.WriteMessage(xdw); xdw.Flush();
运行结果如下:
22) 下一步我们来测试一下,如何从服务器端通过Message传递一个Fault错误消息给客户端,这里要注意的是所传递的Fault也是一个Message类,他并不是一个异常信息,所以无法在客户端中通过Catch来捕获。先在ICalculatorService里添加一个接口:
//把一个Fault创建成消息传递给客户端 [OperationContract] Message GetDataFault();
23) 实现该接口:
public Message GetDataFault() { //创建一个FaultCode实例,用来承载所要传递的Fault FaultCode fc = new FaultCode("Receiver"); MessageVersion ver = OperationContext.Current.IncomingMessageVersion; //重载CreateMessage(版本,FaultCode实例,错误原因信息,action); return Message.CreateMessage(ver, fc, "Bad data", "http://Video8.Demo1.XmlReader/ICalculatorService/GetDataFaultResponse"); }
24) 编译该WCF服务后,部署到IIS上,然后再client客户端更新Service Reference。在Main方法中加入测试代码:
//把从服务器端传过来的Message类型的Fault读取出来,这里虽然使用Try Catch,但是是无法补货到的,对于客户端来说 //Fault也只是一个Message而已。 try { Message reply3 = client.GetDataFault(); Console.WriteLine(reply3.ToString()); } catch (Exception ex) { Console.WriteLine(ex.ToString()); }运行结果如下:
源代码: http://download.csdn.net/detail/eric_k1m/6402289
提取消息正文数据
Message类支持多种从其正文提取信息的方式。他们可以分为以下几类:
1) 将整个消息正文一次性写出到XML编写器(例如:XmlDictionaryWriter)。这称为“写入消息”。
2) 将XML读取器放在消息正文上。这使的可以在以后根据需要逐段访问消息正文。这成为“读取消息”。
3) 可以将整个消息(包括它的正文)复制到类型为MessageBuffer的内存中缓冲区。这成为“复制消息”。
写入消息
WriteBodyContents方法将给定Message实例的正文内容写出到给定XML编写器。
WriteBody方法进行相同的操作,不同之处在于该方法将正文内容封装在适当的包装元素(如<soap:body>)中。
最后,WriteMessage写出整个消息,包括SOAP包装信封和标头。
需要记住的是,如果SOAP被禁用(Version为MessageVersion.None),则所有这三个方法都进行相同的操作:仅仅写出消息正文内容。
所谓的写入消息是指把XML类型的文件也好流也好,通过服务器端提供的Message类(该实例中已经有XML文件或流文件)的写出到客户端的FileStream里去。
读取消息
读取消息是指把Message类中的消息读取出来,以供使用。
读取消息正文的主要方式是调用 GetReaderAtBodyContents
使用GetBody方法还可以将消息正文作为类型化对象进行访问。GetBody<T>() T类是已知的类就可以读取到对象中去。
将消息复制到缓冲区中
通过调用CreateBufferedCopy在内存中缓冲整个消息(包括正文)。
缓冲区作为一个MessageBuffer实例返回。可以通过几种方式访问缓冲区的数据。主要方式是调用CreateMessage以便从缓冲区创建Message实例。
访问消息缓冲区内容的另一种方式是使用WriteMessage将缓冲区的内容写出到流中。
DEMO
1) “写入消息”的测试;该Demo也使用上面的Demo,只是在客户端Main方法中,使用如下测试:
//从服务端的XML文件里读取Message Message reply2 = client.GetDataStream(); Console.WriteLine(reply2.ToString()); Console.WriteLine("+++++++++++++++++++"); //把从服务器端读取过来的Message存在客户端本地XML里 FileStream stream = new FileStream(@"C:\log.xml", FileMode.Create); XmlDictionaryWriter xdw = XmlDictionaryWriter.CreateTextWriter(stream); //只把MessageBody里的内容写入到xml文件里 reply2.WriteBodyContents(xdw); Console.WriteLine("+++++++++++++++++++"); //把body标记和body内部的内容一起写入到xml文件里 reply2.WriteBody(xdw); Console.WriteLine("+++++++++++++++++++"); //把整个消息都写入到xml文件里,包括标头,正文等全部信息。 reply2.WriteMessage(xdw); xdw.Flush(); Console.WriteLine("————————————————");
2) “读取消息”的方式,也是一样在客户端Main方法中:
//GetData方法的调用 Message reply1 = client.GetData(); Console.WriteLine(reply1.ToString()); //获取GetBody类后转换成Person类赋值给Person类的实例p Person p = reply1.GetBody<Person>(); Console.WriteLine(p.name + " " + p.age); Console.WriteLine("————————————————");
3) “写入到缓冲区”
//把Message写入到缓冲区 Message reply4 = client.GetDataStream(); //把消息拷贝进缓冲区,并设置该缓冲区大小为65536 MessageBuffer mb = reply4.CreateBufferedCopy(65536); //从缓冲区里的消息写入到XML文件里 FileStream st = new FileStream(@"C:\test\log.xml", FileMode.Append); mb.WriteMessage(st); //使用缓冲区.WriteMessage()方法写入到XML文件 st.Flush();
访问其他消息部分
该类提供了各种属性,以便访问除正文内容以外的其他与消息有关的信息。但是,一旦关闭了消息,将无法调用这些属性:
1) Headers属性表示消息标头。
2) Properties属性表示消息属性,这些属性是附加到消息的命名数据段,且通常不会在发送消息时发出。
3) Version属性指示与消息相关联的SOAP和WS-Addressing版本;如果禁用了SOAP,则该属性为None。
4) IsFault属性在消息为SOAP错误消息时返回true。
5) IsEmpty属性在消息为空时返回true。
DEMO
也是在之前我们所创建的DEMO之上来测试,在客户端Main方法中添加:
//访问消息的其他部分 Message reply5 = client.GetData(); //打印出整个消息 Console.WriteLine(reply5.ToString()); Console.WriteLine("+++++++++++++++++++"); //使用Message的Headers属性循环访问该Message的Header foreach (MessageHeaderInfo mhi in reply5.Headers) { Console.WriteLine(mhi.Name); //输出Header的Name }
输出的结果:
以上所有DEMO源代码: http://download.csdn.net/detail/eric_k1m/6402559
- 从零开始学WCF(8)Message类
- 从零开始学WCF(1)WCF概述
- 从零开始学WCF(3)配置服务
- 从零开始学WCF(4)承载服务
- 从零开始学WCF(5)生成客户端
- 从零开始学WCF(6)数据协定
- 从零开始学WCF(7)消息协定
- 从零开始学WCF(10)序列化
- 从零开始学WCF(12)详解传输
- 从零开始学WCF(13)事务
- 从零开始学WCF(14)WCF安全性概述
- 从零开始学WCF(2)设计和实现服务协定
- 从零开始学WCF(9)会话、实例化和并发
- 从零开始学WCF(11)大型数据和流
- 从零开始学android<Message消息机制.四十二.>
- 第80章、Handle-Message-Looper消息机制之一(从零开始学Android)
- 第81章、Handle-Message-Looper消息机制之二(从零开始学Android)
- 跟我一起从零开始学WCF系列课程
- Qt中验证器的使用
- 系统学习hive programming,第五章,操作数据
- Spring3.0的Junit测试
- 安卓全局变量的使用方法
- 指定形式字符串转化以及字符串编码转换
- 从零开始学WCF(8)Message类
- linux驱动程序开发环境配置
- poj 1062
- 如何编写出高效的数据库连接池(附带完整代码C#和Java实现)
- white-space
- nbu(wins下)统一备份脚本
- 王石在纽约接受本报专访,畅谈自己的留学生涯以及对企业家与公民责任的看法
- JS VLC插件
- http请求和http响应详细解析