zoukankan      html  css  js  c++  java
  • [转]十五天精通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("王八蛋");
    复制代码

    现在我想你大概看清楚了这玩意是个么样子,一个建立在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中,如下:

    复制代码
     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 Test
    37     {
    38         [DataMember]
    39         public string str { get; set; }
    40     }
    41 }
    复制代码

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

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

  • 相关阅读:
    基于 Web 的 Go 语言 IDE
    基于 Web 的 Go 语言 IDE
    语音芯片选型
    干簧管
    51单片机或PLC驱动3.5寸至52寸的数字TFTLCD屏、VGA接口显示器、电视机
    为什么做网线水晶头必须按照颜色顺序?
    51地图接口
    labview多个并行循环同时退出
    TCP和UDP的区别
    IMAQ Flatten Image to String VI的参数设置对比
  • 原文地址:https://www.cnblogs.com/go-jzg/p/6281837.html
Copyright © 2011-2022 走看看