Message翻译成中文,相信各位不陌生,是啊,就是消息,在WCF中也有消息这玩意儿,不知道你怎么去理解它。反正俺的理解,就像我们互发短信一个道理,通讯的双方就是服务器与客户端,说白了吧,就是二者之间的通信。

我们知道一个WCF服务,先是定义服务协定,而服务协定中会有若干个服务操作协定(OperationContract),是这样吧?而所谓的操作协定,就是一个方法。

于是,我的结论出来了,客户端与服务器端通信,每调用一回操作协定就相当于发送/接收一条消息,你干脆理解为一个OperationContract就是一条Message,哈,这样应该好接受了吧。

之前的文章中,我们吹了修改SOAP头相关的技术,而我们今天要说的Message其实也是序列化为SOAP的,反正这一切都和SOAP有关。可能 你会问,如果我不懂SOAP的具体知识,那我使用Message会遇到困难吗?明确Tell you,不会,你看下文我给各位准备的例子就知道了,我们不懂SOAP也可以耍Message的,就像我们不懂如果种水稻但也会做饭一个道理。

消息协定可以使用我们更灵活地封装自定义消息。既然我们可以把操作协定的一次调用看作是一条消息,那么,就可能出现下面三种情况:

a:只接收消息,但不进行回答;

b:只回复消息不接收输入消息;

c:既接收输入消息,同时发送回复消息。

先定义我们所需要的消息协定类。

 
    [MessageContract]
public class CarMessage
{
[MessageBodyMember]
public string CarName;
[MessageBodyMember]
public int MakeYear;
[MessageBodyMember]
public string SerType;
} [MessageContract]
public class Person
{
[MessageHeader]
public string Zip { get; set; }
[MessageHeader]
public string Address; [MessageBodyMember]
public int Age { get; set; }
[MessageBodyMember]
public string Name { get; set; }
[MessageBodyMember]
public string Email { get; set; }
} #region 输入输出消息协定
[MessageContract]
public class RequrestMessage
{
[MessageHeader]
public int maxNum;
[MessageBodyMember]
public string CheckName;
} [MessageContract]
public class ResponseMessage
{
[MessageBodyMember]
public string Name;
[MessageBodyMember]
public int CheckResult;
}
#endregion

我们看到,消息协定的定义和数据协定很像,也是先写一个类,然后附加MessageContractAttribute,而对于类的成员(字段或属 性,不管是公共的还是私有的)可以附加MessageHeaderAttribute或MessageBodyMemberAttribute。

其实,MessageHeaderAttribute与MessageBodyMemberAttribute并没有根本的区别,只是一个是消息头,一个是消息正文罢了,这只是针对SOAP消息而言。

接着,定义服务协定和服务器类。

    [ServiceContract]
public interface IService
{
[OperationContract]
void PostMessage(CarMessage msg); [OperationContract]
Person GetPerson(); [OperationContract]
ResponseMessage CheckRenpin(RequrestMessage rqmsg);
} public class MyService : IService
{
public void PostMessage(CarMessage msg)
{
Console.WriteLine("车子名字:{0}", msg.CarName);
} public Person GetPerson()
{
Person ps = new Person();
ps.Name = "鸟人";
ps.Age = 107;
ps.Email = "nb@niube.com";
ps.Zip = "990";
ps.Address = "非洲";
return ps;
}
public ResponseMessage CheckRenpin(RequrestMessage rqmsg)
{
ResponseMessage respMsg = new ResponseMessage();
Random rand = new Random();
respMsg.CheckResult = rand.Next(rqmsg.maxNum);
respMsg.Name = rqmsg.CheckName;
return respMsg;
}
}
 

剩下的就是对服务主机的一些设置,这个每次都一样的了。

        static void Main(string[] args)
{
// 服务器基址
Uri baseAddress = new Uri("http://localhost:1378/services");
// 声明服务器主机
using (ServiceHost host = new ServiceHost(typeof(MyService), baseAddress))
{
// 添加绑定和终结点
WSHttpBinding binding = new WSHttpBinding();
host.AddServiceEndpoint(typeof(IService), binding, "/test");
// 添加服务描述
host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
try
{
// 打开服务
host.Open();
Console.WriteLine("服务已启动。");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadKey();
}
}

确认服务器端正常运行后,在客户端添加服务引用。
在客户端生成的代理类中,消息协定和数据协定并不一样了,服务的操作协定和服务器端我们定义的不一样了。

我们看到,在服务器端定义的消息协定类,在客户端代码中,类的成员都被拆开了。这样就得出这样一个结论:

作为操作协定的输入消息协定(作为参数)封装了操作方法的所有in参数;作为操作协定的返回值的消息协定(return)封装了out参数和返回值。

接下来,我们看看包含数据协定的消息协定的例子。

    #region 包含数据协定的消息协定
[DataContract]
public class ArtistInfo
{
[DataMember]
public string ArtistName;
[DataMember]
public DateTime CreateTime;
} [MessageContract]
public class Worker
{
[MessageHeader]
public ArtistInfo WorkerArtist;
[MessageBodyMember]
public string WorkerName;
[MessageBodyMember]
public string WorkerNo;
[MessageBodyMember]
public int WorkerAge;
}
#endregion

消息协定的类是Worker,但Worker的WorkerArtist字段是一个数据协定类ArtistInfo。

然后我们在服务协定上再加一个方法。

[ServiceContract]
    public interface IService
    {
        ........
        [OperationContract]
        void SetWorkerInformation(Worker wk);
    }

public class MyService : IService
    {
        .............
        public void SetWorkerInformation(Worker wk)
        {
            Console.WriteLine("工作名字:{0}",wk.WorkerName);
            ArtistInfo info = wk.WorkerArtist;
            Console.WriteLine("工人作品创建时间:{0}", info.CreateTime.ToString("yyyy-MM-dd HH:mm:ss"));
            Console.WriteLine("工人作品名字:{0}", info.ArtistName);
        }
    }

现在,在客户端来测试一下SetWorkerInformation方法。

        static void Main(string[] args)
{
WS.ServiceClient cl = new WS.ServiceClient(); WS.ArtistInfo info = new WS.ArtistInfo
{
ArtistName = "高级垃圾",
CreateTime = new DateTime(2018, 7, 17)
};
cl.SetWorkerInformation(info, 180, "老妖", "NB-117"); Console.ReadKey();
}

由于方法返回void,因为在客户调用方法后,控制台窗口是一片空白,我们主要观察服务器端的控制台窗口是否输出了相关的内容。

这表明调用成功了。

对于消息协定什么时候使用,你看看吧,啥时候需要就毫不犹豫地用吧,这个显然要比Message类好用,毕竟Message类也有一些莫名的Bug,也不知道是不是我的bug。在流传输模式下使用消息协定来封装是不错的选择。

而对于消息头的消息正文,这个没有什么严格的规定的,不信你试试。一般的原则可以是,类似附加信息之类的可以用作头部,比较重要的信息作为正文。你不妨试试,无论你的成员定义为头部还是正文,在代码调用是看不什么根本区别。

传说中的WCF(8):玩转消息协定的更多相关文章

  1. WCF初探-19:WCF消息协定

    WCF消息协定概述 在生成 WCF应用程序时,开发人员通常会密切关注数据结构和序列化问题,而不必关心携带数据的消息结构. 对于这些应用程序,为参数或返回值创建数据协定的过程很简单.但是,有时完全控制 ...

  2. WCF学习心得------(七)消息协定

    第七章 消息协定 7.1 消息协定概述 通常情况下,在定义消息的架构时只使用数据协定就足够,但是有时需要精确控制如何将类型映射到通过网络传输的SOAP消息.对于这种情况,通常解决方案是插入自定义的SO ...

  3. 传说中的WCF(10):消息拦截与篡改

    我们知道,在WCF中,客户端对服务操作方法的每一次调用,都可以被看作是一条消息,而且,可能我们还会有一个疑问:如何知道客户端与服务器通讯过 程中,期间发送和接收的SOAP是什么样子.当然,也有人是通过 ...

  4. 传说中的WCF:消息拦截与篡改

    我们知道,在WCF中,客户端对服务操作方法的每一次调用,都可以被看作是一条消息,而且,可能我们还会有一个疑问:如何知道客户端与服务器通讯过程中,期间发送和接收的SOAP是什么样子.当然,也有人是通过借 ...

  5. WCF基础之消息协定

    通常定义消息的架构,使用数据协定就够了,但是有时必须将类型精确映射到soap消息,方法两种:1.插入自定义soap标头:2.另一种是定义消息的头和正文的安全属性.消息协定通过MessageContra ...

  6. 我们一起学习WCF 第五篇数据协定和消息协定

    A:数据协定(“数据协定”是在服务与客户端之间达成的正式协议,用于以抽象方式描述要交换的数据. 也就是说,为了进行通信,客户端和服务不必共享相同的类型,而只需共享相同的数据协定. 数据协定为每个参数或 ...

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

    在我们玩wcf的时候,都会潜意识的觉得wcf就是通过soap协议交换消息的,并且可以在basic,tcp,msmq等等绑定中任意切换, 牛逼的一塌糊涂,但是呢,如果说哪一天wcf不再使用soap协议, ...

  8. 传说中的WCF(9):流与文件传输

    在使用Socket/TCP来传输文件,弄起来不仅会有些复杂,而且较经典的“粘包”问题有时候会让人火冒七丈.如果你不喜欢用Socket来传文件,不妨试试WCF,WCF的流模式传输还是相当强大和相当实用的 ...

  9. [老老实实学WCF] 第十篇 消息通信模式(下) 双工

    老老实实学WCF 第十篇 消息通信模式(下) 双工 在前一篇的学习中,我们了解了单向和请求/应答这两种消息通信模式.我们知道可以通过配置操作协定的IsOneWay属性来改变模式.在这一篇中我们来研究双 ...

随机推荐

  1. IOS中 如何去除Tabview里面cell之间的下划线

    可以利用Tabview的separatorStyle属性来设置,选择其中的UITableViewCellSeparatorStyleNone 即可去除cell之间的下划线 self.tableView ...

  2. linux下安装protobuf教程+示例(详细)

    (.pb.h:9:42: fatal error: google/protobuf/stubs/common.h: No such file or directory 看这个就应该知道是没有找到头文件 ...

  3. OC学习心得【适合初学者】

    一.类和对象 1.OC语言是C语言的扩充,并且OC是iOS和OS X操作系统的编程语言. ①具备完善的面向对象特性: 封装:将现实世界中存在的某个客体的属性与行为绑定在一起,并放置在一个逻辑单元内 继 ...

  4. UITableView设置cell为不可选?

    本文选自StackOverflow(简称:SOF)精选问答汇总系列文章之一,本系列文章将为读者分享国外最优质的精彩问与答,供读者学习和了解国外最新技术.本文将为读者讲解UITableView如何设置单 ...

  5. 团队开发(NABC)

    特点:这是一个手机软件,能通过通讯录录入生日信息 N(Need需求):现在在交际圈中需要记住越来越多朋友的生日信息 A(Approach做法):由一个简单的闹钟为基础,添加与生日相关的功能,最终实现 ...

  6. C/C++常用头文件及函数汇总

    转自: C/C++常用头文件及函数汇总 C/C++头文件一览 C #include <assert.h> //设定插入点#include <ctype.h> //字符处理#in ...

  7. Linux 硬盘分区、分区、删除分区、格式化、挂载、卸载

    Linux 虽然一直都有在玩,但是对硬盘操作确实不是很熟悉今天有空,就整理了下. 1,创建分区 先查看下是否有磁盘没有分区 fdisk -l 其中第一个框和第二个框,是已经分好区的磁盘,第三个硬盘没有 ...

  8. 我是如何基于angular+requirejs+node做SPA项目架构的

    本文章已经录制视频,地址是:http://v.youku.com/v_show/id_XODI3MjYyODI0.html 前端这两年技术飞速发展,各种优秀框架层出不穷.本文不是讨论各框架的比较,也不 ...

  9. Testing Multi-Tenancy on a Local Machine

    If you are running locally and do not have a domain to map, you can edit your\Windows\System32\drive ...

  10. HDU 5597 GTW likes function 欧拉函数

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5597 题意: http://bestcoder.hdu.edu.cn/contests/contes ...