你的位置:首页 > ASP.net教程

[ASP.net教程]十五天精通WCF——第四天 你一定要明白的通信单元Message


  转眼你已经学了三天的wcf了,是不是很好奇wcf在传输层上面到底传递的是个什么鸟毛东西呢???应该有人知道是soap,那soap这叼毛长得是什么

样呢?这一篇我们来揭开答案。。。

 

一:soap到底长成什么样子

  为了能看清soap长的啥样,我可以用强大的Fiddler来监视一下,突然好激动啊!!!

1.Server

 1     static void Main(string[] args) 2     { 3       ServiceHost host = new ServiceHost(typeof(HomeService), new Uri("http://192.168.1.105:19200")); 4  5       host.AddServiceEndpoint(typeof(IHomeService), new BasicHttpBinding(), "HomeServie"); 6  7       //公布元数据 8       host.Description.Behaviors.Add(new ServiceMetadataBehavior() { HttpGetEnabled = true }); 9 10       host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");11 12       host.Open();13 14       Console.WriteLine("服务已经开启。。。");15 16       Console.Read();17     }

2.Client

1       ChannelFactory<IHomeService> factory = new ChannelFactory<IHomeService>(new BasicHttpBinding(), new EndpointAddress("http://192.168.1.105:19200/HomeServie"));2 3       var client = factory.CreateChannel();4 5       client.Update("王八蛋");

 

 

现在我想你大概看清楚了这玩意是个么样子,一个建立在

和”封体”,就是s:Header 和 s:Body,从这个soap中你可以看到它忽略了header,然后我们继续往下看,还记得Update的意思吗???如果你读懂了上一篇,

你应该知道这是一个Action,也就是所谓的input消息。与之对应的就是UpdateResponse这个output消息,对吧,还记得

它就是IHomeService的默认命名空间,对吧。。。

下一个我们关注的是Update这个Action中的<str>这个,你也看得到,这个就是上图中Update方法中的str参数,最后我们来看一下UpdateResponse中

的<UpdateResult

构,看下图:

 

好了,wcf中的soap结构我们也大概了解了一下,不知道有没有引发你对soap更深入的思考呢???

 

二:对soap的更深入思考

  通过fiddler观察,你应该也明白了,不管是客户端还是服务端,wcf的高层封装都是仅仅拿出了Envelope中的body节点,而其他节点对我们来说好像并

没有什么卵用,比如我说的Header节点,这么说来,Header是不是有点浪费呢???那下面有一个问题来了,wcf在底层用什么来构造消息的呢???下面

我们大概找下client端的源码。。。

 

通过上面的图,你现在应该也知道了在.net中其实tmd的就是message构造的,所以我想告诉你的是:既然wcf在底层也是用message来构造的,何不我自己

就来构造message消息呢???岂不美哉???这样我就可以随意操作message,对吧。。。不然wcf这个高层封装的叼毛,对我来说就是一种束缚。。。因

为我已经知道了service公布的wsdl,所以我可以轻松构造message。。。

 

三:用message来调用Server端

  废话不多说,构造message你一定要知道下图中的三点:(input这个Action,契约方式 和 服务地址)。

 

好了,下面我先来构造数据契约,指定服务契约的命名空间 和 Action在Soap中的名称

1   [DataContract(Namespace = "http://tempuri.org/", Name = "Update")]2   class Test3   {4     [DataMember]5     public string str { get; set; }6   }

然后,我把这个数据契约塞到envelope中的body中,如下:

 1       BasicHttpBinding bingding = new BasicHttpBinding(); 2  3       BindingParameterCollection param = new BindingParameterCollection(); 4  5       var u = new Test() { str = "王八蛋" }; 6  7       Message request = Message.CreateMessage(MessageVersion.Soap11, "http://tempuri.org/IHomeService/Update", u); 8  9       IChannelFactory<IRequestChannel> factory = bingding.BuildChannelFactory<IRequestChannel>(param);10 11       factory.Open();12 13       IRequestChannel channel = factory.CreateChannel(new EndpointAddress("http://192.168.1.105:19200/HomeServie"));14 15       channel.Open();16 17       var result = channel.Request(request);18 19       channel.Close();20 21       factory.Close();

接下来,我们跑起来看一下,效果咋样。。。

 

看没看到,这个就是我手工构造的Message,是不是太帅了。。。哈哈,太帅的应该在后面,刚才也说了,既然大家玩的都是Message,而你这个几把wcf却仅仅把

我的message.body拿出来了,那干脆我直接在契约方法中加message岂不是更好么???自由操作Message还有个什么好处呢??当然啦,我可以在Message的

Header中加一些参数token,client的ip地址,client的身份,client的时间等等这些统计信息,对吧。。。这样才是最帅的,好了,说干就干,我们修改下server端的

契约方法,只用来接受Message。

 

server端:

 1   public class HomeService : IHomeService 2   { 3     public Message Update(Message message) 4     { 5       var header = message.Headers; 6  7       var ip = header.GetHeader<string>("ip", string.Empty); 8  9       var currentTime = header.GetHeader<string>("currenttime", string.Empty);10 11       //这个就是牛逼的 统计信息。。。12       Console.WriteLine("客户端的IP=" + ip + " 当前时间=" + currentTime);13 14       return Message.CreateMessage(message.Version, message.Headers.Action + "Response", "等我吃完肯德基,再打死你这个傻逼!!!");15     }16   }

 

client端:

 1 namespace ConsoleApplication1 2 { 3   class Program 4   { 5     static void Main(string[] args) 6     { 7       BasicHttpBinding bingding = new BasicHttpBinding(); 8  9       BindingParameterCollection param = new BindingParameterCollection();10 11       var u = new Test() { str = "王八蛋" };12 13       Message request = Message.CreateMessage(MessageVersion.Soap11, "http://tempuri.org/IHomeService/Update", u);14 15       //在header中追加ip信息16       request.Headers.Add(MessageHeader.CreateHeader("ip", string.Empty, Dns.GetHostByName(Dns.GetHostName()).AddressList[0].ToString()));17       request.Headers.Add(MessageHeader.CreateHeader("currenttime", string.Empty, DateTime.Now));18 19       IChannelFactory<IRequestChannel> factory = bingding.BuildChannelFactory<IRequestChannel>(param);20 21       factory.Open();22 23       IRequestChannel channel = factory.CreateChannel(new EndpointAddress("http://192.168.1.105:19200/HomeServie"));24 25       channel.Open();26 27       var result = channel.Request(request);28 29       channel.Close();30 31       factory.Close();32     }33   }34 35   [DataContract(Namespace = "http://tempuri.org/", Name = "Update")]36   class Test37   {38     [DataMember]39     public string str { get; set; }40   }41 }

 

然后我们用Fiddler监视一下结果:

 

现在一切都如我所愿,好了,我想你也大概明白了这个神奇的message,也不要忘了它就是wcf的基本通信单元,我要去吃肯德基了。。。。。。