十五天精通WCF——第四天 你一定要明白的通信单元Message

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

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

一:soap到底长成什么样子

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

1.Server

static void Main(string[] args)
 {
 ServiceHost host = new ServiceHost(typeof(HomeService), new Uri("http://192.168.1.105:19200"));

 host.AddServiceEndpoint(typeof(IHomeService), new BasicHttpBinding(), "HomeServie");

 //公布元数据
 host.Description.Behaviors.Add(new ServiceMetadataBehavior() { HttpGetEnabled = true });

 host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");

 host.Open();

 Console.WriteLine("服务已经开启。。。");

 Console.Read();
 }

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("王八蛋");


现在我想你大概看清楚了这玩意是个么样子,一个建立在xml上面的一种消息格式,根元素是envelope,我知道这叼毛翻译过来就是“信封”,所以就有了”封头“

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

你应该知道这是一个Action,也就是所谓的input消息。与之对应的就是UpdateResponse这个output消息,对吧,还记得xmlns="http://tempuri.org/">吗?

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


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

的<UpdateResult xmlns:a="http://schemas.datacontract.org/2004/07/MyService,不知道你是否还记得它就是WSDL中关于Student的XSD结

构,看下图:


好了,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 Test
3 {
4 [DataMember]
5 public string str { get; set; }
6 }

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

BasicHttpBinding bingding = new BasicHttpBinding();

 BindingParameterCollection param = new BindingParameterCollection();

 var u = new Test() { str = "王八蛋" };

 Message request = Message.CreateMessage(MessageVersion.Soap11, "http://tempuri.org/IHomeService/Update", u);

 IChannelFactory<IRequestChannel> factory = bingding.BuildChannelFactory<IRequestChannel>(param);

 factory.Open();

 IRequestChannel channel = factory.CreateChannel(new EndpointAddress("http://192.168.1.105:19200/HomeServie"));

 channel.Open();

 var result = channel.Request(request);

 channel.Close();

 factory.Close();

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


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

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

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

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

server端:

public class HomeService : IHomeService
 {
 public Message Update(Message message)
 {
 var header = message.Headers;

 var ip = header.GetHeader<string>("ip", string.Empty);

 var currentTime = header.GetHeader<string>("currenttime", string.Empty);

 //这个就是牛逼的 统计信息。。。
 Console.WriteLine("客户端的IP=" + ip + " 当前时间=" + currentTime);

 return Message.CreateMessage(message.Version, message.Headers.Action + "Response", "等我吃完肯德基,再打死你这个傻逼!!!");
 }
 }

client端:

namespace ConsoleApplication1
{
 class Program
 {
 static void Main(string[] args)
 {
 BasicHttpBinding bingding = new BasicHttpBinding();

 BindingParameterCollection param = new BindingParameterCollection();

 var u = new Test() { str = "王八蛋" };

 Message request = Message.CreateMessage(MessageVersion.Soap11, "http://tempuri.org/IHomeService/Update", u);

 //在header中追加ip信息
 request.Headers.Add(MessageHeader.CreateHeader("ip", string.Empty, Dns.GetHostByName(Dns.GetHostName()).AddressList[0].ToString()));
 request.Headers.Add(MessageHeader.CreateHeader("currenttime", string.Empty, DateTime.Now));

 IChannelFactory<IRequestChannel> factory = bingding.BuildChannelFactory<IRequestChannel>(param);

 factory.Open();

 IRequestChannel channel = factory.CreateChannel(new EndpointAddress("http://192.168.1.105:19200/HomeServie"));

 channel.Open();

 var result = channel.Request(request);

 channel.Close();

 factory.Close();
 }
 }

 [DataContract(Namespace = "http://tempuri.org/", Name = "Update")]
 class Test
 {
 [DataMember]
 public string str { get; set; }
 }
}

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


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

时间: 2024-12-10 23:41:46

十五天精通WCF——第四天 你一定要明白的通信单元Message的相关文章

十五天精通WCF——第六天 你必须要了解的3种通信模式

wcf已经说到第六天了,居然还没有说到这玩意有几种通信模式,惭愧惭愧,不过很简单啦,单向,请求-响应,双工模式,其中的第二种"请求-响应" 模式,这个大家不用动脑子都清楚,这一篇我大概来分析下. 一:"请求-响应"模式 如果你看了我上一篇的博文,你应该非常清楚这种类似"本地调用"的方式,wcf同样也分为"同步"和"异步"两种,不过不管是异步还是同步,最终都逃 不过是"请求-响应"这个事实

十五天精通WCF——第十天 学会用SvcConfigEditor来简化配置

原文:十五天精通WCF--第十天 学会用SvcConfigEditor来简化配置        我们在玩wcf项目的时候,都是自己手工编写system.serviceModel下面的配置,虽然在webconfig中做wcf的服务配置的时候,vs提供大多 数的代码提示,但对于不太熟悉服务配置的小鸟们来说,有些困难,而且一些服务配置也容易遗漏,大多情况下,我们都是copy一份服务配置,然 后在服务配置上面修修改改,对吧...其实呢,.net给我们提供了一个强大的scvconfigeditor这个工具

十五天精通WCF——第八天 对“绑定”的最后一点理解

原文:十五天精通WCF--第八天 对"绑定"的最后一点理解 转眼已经中断10几天没有写博客了,也不是工作太忙,正好碰到了端午节,然后最近看天津台的爱情保卫战入迷了...太好看了,一直都是回味无穷...而且 涂磊老师话说的真是tmd的经典,然后就这样耽搁了,好了,话不多说,这篇我们看看binding中最后一点需要知道的东西.   一:信道栈 我在之前的文章中多次提到信道栈,不知道大家对它的概念是否有了解,其实想想也还是蛮简单的,既然是栈,那么这个栈肯定就不止一个元素了,对吧,第二个 的话

十五天精通WCF——第三天 client如何知道server提供的功能清单

原文:十五天精通WCF--第三天 client如何知道server提供的功能清单  通常我们去大保健的时候,都会找姑娘问一下这里能提供什么服务,什么价格,这时候可能姑娘会跟你口述一些服务或者提供一份服务清单,这样的话大 家就可以做到童嫂无欺,这样一份活生生的例子,在wcf中同样是一个道理,只有client了解service能提供哪些功能,client才可以根据server提供的功能进行 消费,那问题来了,service怎么把功能提供给client进行选择呢???这个就是我这一篇要聊的wsdl(w

十五天精通WCF——第二天 告别烦恼的config配置

原文:十五天精通WCF--第二天 告别烦恼的config配置   经常搞wcf的基友们肯定会知道,当你的应用程序有很多的"服务引用"的时候,是不是有一种疯狂的感觉...从一个环境迁移到另外一个环境,你需要改变的 endpoint会超级tmd的多,简直就是搞死了人...好了,这篇我们来看看如何最小化配置.   一:精简service的config配置 就像上一篇的代码一样,我的service端的config配置如下: 1 <?xml version="1.0"

十五天精通WCF——第十二天 说说wcf中的那几种序列化

原文:十五天精通WCF--第十二天 说说wcf中的那几种序列化 我们都知道wcf是由信道栈组成的,在我们传输的参数走到传输信道层之前,先需要经过序列化的过程,也就是将参数序列化为message,这篇 我们就来说说这里的序列化,蛮有意思的,可能初学者也明白,在wcf中默认的序列化是DataContractSerializer,确实是这样,不过wcf在信道中 其实不仅仅支持DataContractSerializer,它还支持其他类型的序列化,比如XmlSerializer,NetDataContr

十五天精通WCF——第十三天 用WCF来玩Rest

在我们玩wcf的时候,都会潜意识的觉得wcf就是通过soap协议交换消息的,并且可以在basic,tcp,msmq等等绑定中任意切换, 牛逼的一塌糊涂,但是呢,如果说哪一天wcf不再使用soap协议,而是采用json格式的字符串,是不是有一点颠覆你对wcf的认识的??? 从传统意义上说,wcf是非常重量级的,很明白的一个例子就是太多太多的配置,尤其是Behavior的配置,而且behavior对wcf来说又是重 中之重,它对wcf的扩展和性能又是最重要的,可恨的是wcf在binding,beha

十五天精通WCF——第十四天 一起聊聊FaultException

 我们在玩web编程的时候,可能你会不经意的见到一些http500的错误,我想你应该不会陌生的,原因你应该也知道,服务器异常嘛, 这时候clr会把这个未处理的异常抛给iis并且包装成http500的错误返回到客户端,就比如下面这样.     从这张图中,我故意输入了xss字符,然后的然后,web程序自爆异常,其实我想表达的意思就是,虽然说web程序抛异常了,但不代表iis就 挂了,所以iis还是需要给客户端做出反馈,这就有了http header,和body信息,同样的道理,wcf的服务器异常机

十五天精通WCF——第一天 三种Binding让你KO80%的业务

转眼wcf技术已经出现很多年了,也在.net界混的风生水起,同时.net也是一个高度封装的框架,作为在wcf食物链最顶端的我们所能做的任务已经简单的不能再简单了, 再简单的话马路上的大妈也能写wcf了,好了,wcf最基本的概念我们放在后面慢慢分析,下面我们来看看神奇的3个binding如何KO我们实际场景中的80%的业务场景. 一:basicHttpBinding 作为入门第一篇,也就不深入谈谈basic中的信道栈中那些啥东西了,你只需要知道有ABC三个要素,注意不是姨妈巾哦,如果需要详细了解,