WCF技术内幕 第3章 (1)

第3章 消息交换模式、拓扑和编排

3.1 消息交换模式

消息交换模式是“描述消息参与者之间交换消息的模板”。

在面向服务的世界里通常有三种类型的消息交换模式:数据报,请求/应答和双工。


数据报交换模式

数据报消息交换模式表示一个单向的消息发送,或者即发即弃的消息发送。如果需要应答数据报,就需要发送者和接收者之间建立一个新的连接来应答数据报。

数据报消息交换模式使用WSDL语言描述为一个包含wsdl:input和没有wsdl:output元素的操作。


数据报和WCF契约:

契约定义方法的返回值类型是void和ContractAttribute属性的IsOneWay属性值为True。
在WCF里,唯一避免回复消息的方法就是在操作属性里设置IsOneWay属性。默认值为false,这个设置让操作默认使用请求/应答消息交换模式。

//契约
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace WcfServiceApp2
{
    [ServiceContract(Name="OneWayContract", Namespace="http://andersoft.com/OneWayContract")]
    public interface IOneWayContract
    {
        [OperationContract(
            Name="GetData", 
            Action="urn:GetData", 
            IsOneWay=true)]
        void GetData(Message message);
    }
}

//Service实例

using System;
using System.IO;
using System.ServiceModel.Channels;
using System.Xml;


namespace WcfServiceApp2
{
    public class OneWayService : IOneWayContract
    {
        public void GetData(Message message)
        {
            Console.WriteLine("Received a new message...");

            FileStream fs = new FileStream("Message.xml", FileMode.Create);
            XmlDictionaryWriter xdw = XmlDictionaryWriter.CreateTextWriter(fs, System.Text.Encoding.UTF8, false);
            xdw.Close();
        }
    }
}

//Host代理端 监听Service
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using WcfServiceApp2;

namespace ServiceHostApp
{
    class Program
    {
        static void Main(string[] args)
        {
            BindingElement[] bindingElements = new BindingElement[3];
            bindingElements[0] = new TextMessageEncodingBindingElement();
            bindingElements[1] = new OneWayBindingElement();
            bindingElements[2] = new HttpTransportBindingElement();

            Binding binding = new CustomBinding(bindingElements);

            ServiceHost svc = new ServiceHost(typeof(OneWayService));
            svc.AddServiceEndpoint(typeof(IOneWayContract), binding, new Uri("http://localhost:1234/OneWayContract"));

            svc.Open();

            Console.WriteLine("Service is ready...");
            Console.ReadKey();
        }
    }
}

//发送端,发送数据报
using System;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Xml;
using WcfServiceApp2;

namespace SenderApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Press Enter when the sender is ready...");
            Console.ReadKey();

            BindingElement[] bindingElements = new BindingElement[3];
            bindingElements[0] = new TextMessageEncodingBindingElement();
            bindingElements[1] = new OneWayBindingElement();
            bindingElements[2] = new HttpTransportBindingElement();

            CustomBinding binding = new CustomBinding(bindingElements);
            EndpointAddress endpointAddress = new EndpointAddress(new Uri("http://localhost:1234/OneWayContract"));
           
            ChannelFactory<IOneWayContract> cf = new ChannelFactory<IOneWayContract>(binding, endpointAddress);
            IOneWayContract oc = cf.CreateChannel();

            Message ms = GenerateMessage();
            ms.Headers.Action = "urn:GetData";

            Console.WriteLine("Send Message...");
            oc.GetData(ms);
        }

        //先与Writer写入流中,然后流的当前位置归0,与Reader去读流
        private static Message GenerateMessage()
        {
            MemoryStream ms=new MemoryStream();
            
            XmlDictionaryWriter writer=XmlDictionaryWriter.CreateTextWriter(ms,System.Text.Encoding.UTF8);
            writer.WriteStartElement("WCF.OneWay");
            writer.WriteElementString("Sender", "Anders");
            writer.WriteElementString("Receive", "Anders");
            writer.WriteElementString("IsReply", "False");
            writer.WriteEndElement();

            writer.Flush();
            ms.Position=0;

            XmlDictionaryReader reader=XmlDictionaryReader.CreateTextReader(ms, XmlDictionaryReaderQuotas.Max);

            return Message.CreateMessage(MessageVersion.Soap12WSAddressing10, string.Empty, reader);
        }
    }
}

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
  <s:Header>
    <a:Action s:mustUnderstand="1">urn:GetData</a:Action>
    <a:To s:mustUnderstand="1">http://localhost:1234/OneWayContract</a:To>
  </s:Header>
  <s:Body>
    <WCF.OneWay>
      <Sender>Anders</Sender>
      <Receive>Anders</Receive>
      <IsReply>False</IsReply>
    </WCF.OneWay>
  </s:Body>
</s:Envelope>

//另外的一个监听端,监听数据报,只与service的address一样,其他选项没有关系
using System;
using System.ServiceModel.Channels;

namespace ReceiverApp
{
    class Program
    {
        static void Main(string[] args)
        {
            BindingElement[] bindingElements = new BindingElement[3];
            bindingElements[0] = new TextMessageEncodingBindingElement();
            bindingElements[1] = new OneWayBindingElement();
            bindingElements[2] = new HttpTransportBindingElement();

            CustomBinding binding = new CustomBinding(bindingElements);
            IChannelListener<IInputChannel> listener = binding.BuildChannelListener<IInputChannel>(
                new Uri("http://localhost:1234/OneWayContract"), 
                new BindingElementCollection());

            listener.Open();

            IInputChannel inputChannel = listener.AcceptChannel();
            inputChannel.Open();
            Message message = inputChannel.Receive();

            Console.WriteLine(message.Headers.Action); //urn:GetData

            message.Close();
            inputChannel.Close();
            listener.Close();

            Console.ReadKey();
        }
    }
}

HTTP和数据报消息交换模式

在WCF里,通过HTTP发送数据报,再通过HTTP发送数据时,回复是一个HTTP202应答代码。HTTP202状态码的定义是:请求已经被处理,但处理还没结束。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值