对于SOAP来说主要由两部分构成Header和Body,他们两个共同构成了SOAP的信封,通常来说Body保存具体的数据内容,Header保存一些上下文信息或关键信息。比如:在一些情况下,具有这样的要求:当序列化一个对象并生成消息的时候,希望将部分数据成员作为SOAP的报头,部分作为消息的主体。比如说,我们有一个服务操作采用流的方式进行文件的上载,除了以流的方式传输以二进制表示的文件内容外,还需要传输一个额外的基于文件属性的信息,比如文件格式、文件大小等。一般的做法是将传输文件内容的流作为SOAP的主体,将其属性内容作为SOAP的报头进行传递。这样的功能,可以通过定义消息契约来实现。由此可见,MessageContract的主要作用就是给我们提供了自己来操作SOAP的一种方式。
先定义我们所需要的消息协定类。
[MessageContract] public class CarMessage { [MessageBodyMember] public string CarName { get; set; } [MessageBodyMember] public int MakeYear { get; set; } [MessageBodyMember] public string SerType { get; set; } } [MessageContract] public class Person { [MessageHeader] public string Zip { get; set; } [MessageHeader] public string Address { get; set; } [MessageBodyMember] public int Age { get; set; } [MessageBodyMember] public string Name { get; set; } [MessageBodyMember] public string Email { get; set; } } [MessageContract] public class RequestMessage { [MessageHeader] public int maxNum; [MessageBodyMember] public string CheckName; } [MessageContract] public class ResponseMessage { [MessageBodyMember] public string Name; [MessageBodyMember] public int CheckResult; } [ServiceContract] public interface IService { [OperationContract] void PostMessage(CarMessage msg); [OperationContract] Person GetPerson(); [OperationContract] ResponseMessage CheckRenpin(RequestMessage rqmsg); } public class Service : 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(RequestMessage rqmsg) { ResponseMessage respMsg = new ResponseMessage(); Random rand = new Random(); respMsg.CheckResult = rand.Next(rqmsg.maxNum); respMsg.Name = rqmsg.CheckName; return respMsg; } } class Program { static void Main(string[] args) { using (ServiceHost host = new ServiceHost(typeof(Service))) { host.AddServiceEndpoint(typeof(IService), new WSHttpBinding(), "http://127.0.0.1:8888/service1"); ServiceMetadataBehavior behavior = new ServiceMetadataBehavior(); behavior.HttpGetEnabled = true; behavior.HttpGetUrl = new Uri("http://127.0.0.1:8888/service"); //httpGetUrl客户端引用的地址 host.Description.Behaviors.Add(behavior); host.Opened += delegate { Console.WriteLine("服务已启动"); Console.ReadKey(); }; host.Open(); } } }
确认服务器端正常运行后,在客户端添加服务引用。
在客户端生成的代理类中,消息协定和数据协定并不一样了,服务的操作协定和服务器端我们定义的不一样了。用这种方式序列化的实体类不能当作参数直接传递,客户端会把对象的一个参数拆分为多个属性作为参数。
接下来,我们看看消息协定包含数据协定的的例子。
[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; } [ServiceContract] public interface IService { [OperationContract] void SetWorkerInformation(Worker wk); } public class Service : 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); } } class Program { static void Main(string[] args) { using (ServiceHost host = new ServiceHost(typeof(Service))) { host.AddServiceEndpoint(typeof(IService), new WSHttpBinding(), "http://127.0.0.1:8888/service1"); ServiceMetadataBehavior behavior = new ServiceMetadataBehavior(); behavior.HttpGetEnabled = true; behavior.HttpGetUrl = new Uri("http://127.0.0.1:8888/service"); //httpGetUrl客户端引用的地址 host.Description.Behaviors.Add(behavior); host.Opened += delegate { Console.WriteLine("服务已启动"); Console.ReadKey(); }; host.Open(); } } }
客户端调用:
using (ServiceClient client = new ServiceClient() ) { string name = string.Empty; int i = client.CheckRenpin(1, "aa", out name); MessageBox.Show(i+" "+name); ArtistInfo info = new ArtistInfo(); info.ArtistName = "aaa"; info.CreateTime = DateTime.Now; client.SetWorkerInformation(info, 180, "张三", "no1234"); }