• [WCF学习笔记] Binding


    [转]我们已经知道,WCF的客户端通过Endpoint来访问WCF服务端的服务,也就是说,WCF Service Provider将WCF service通过Endpoint暴露出来供Service consumer调用。

    而每个Endpoint包含3个主要要素:Address, binding, contract。其中,Address提供了每个Endpoint的唯一地址;Contract具体指定了这个服务提供什么功能,Client和Server交互的输入输入,消息格式,其它约定等。而真正实现了通信功能的则是Binding

     

    WCF中实现通信功能的binding很简单,就两步:

    1. 根据需要,选择/创建合适的binding类型,例如WSHttpBinding,WSDualHttpBinding或NetTcpBinding;或者创建您自定义的binding;(WCF预定义了9种类型供我们选择)
    2. 创建实现binding的Endpoint,可以通过代码实现,或配置文件配置。如果Endpoint是代码实现的,则Endpoint必须要加到ServiceHost实例。

     

    Binding真正实现了连接到Endpoint的通信细节。具体到通信的处理内部,可能很简单,也可能很复杂

    • Transport (传输协议)
    • Encoding (消息编码)
    • Protocol (安全性,可靠消息传递和事务)

     

    Binding类型的选择

    WCF中实现通信功能的binding很简单的原因之一是WCF已经预定义了9种常用的通信类型。那我们实际项目中,如何选择正确的类型?

    1. BasicHttpBinding: 默认关闭security,不支持WS-*,不支持SOAP安全和事务。类似以前的ASPX Web Service,使用HTTP,使用Txt/XML作消息编码。
    2. WSHttpBinding:支持WS-*,支持SOAP安全和事务。支持HTTP和HTTPS。
    3. WSDualHttpBinding:相比WSHttpBinding,支持duplex services - which provides the ability for a service to communicate back to the client via a callback。支持reliable sessions和communication via SOAP intermediaries。
    4. WSFederationHttpBinding:支持WS-Federation protocol,提供良好的可信任的Authentication和授权。
    5. NetTcpBinding:提供安全、可靠的.net到.net的跨主机的TCP通信。支持SOAP安全、事务和可靠性。使用二进制编码。
    6. NetNamedPipeBinding:提供安全、可靠的同主机跨进程的命名管道通信。支持SOAP安全、事务和可靠性。使用二进制编码。
    7. NetMsmqBinding:提供安全、可靠的.net到.net的跨主机的MSMQ通信。使用二进制编码。(可支持disconnected operation不连接的操作)
    8. NetPeerTcpBinding:提供安全的点到点的通信。支持SOAP安全、事务和可靠性。使用二进制编码。
    9. MsmqIntegrationBinding:用来集成legacy的MSMQ和WCF。使用二进制编码。

     

    WCF_Binding_thumb

    其中,已Net开头的类型不具备互操作性,只限于.net到.net平台通信。而其他的则是WebService绑定,具有互操作性。

    下图是选择的建议:

    020308_0348_WCFBindi5

     

    Binding如何实现通信细节 - Channel layer - Channel stacks

    Channel - A channel, is the medium through which messages are exchanged.

    例如,通常的消息收发过程:

    1. 客户端建立一个channel到服务端
    2. 服务端accept客户端的请求,打开一个channel
    3. 客户端通过这个channel发生request消息
    4. 服务端通过这个channel reply应答到客户端

    Channel Stacks - 一连串的channel来处理消息,分别处理消息的安全性、互操作性、消息pattern、消息传输等任务。不管Channel具体完成怎样的功能,他们都可以看成是一个个Message处理器,这包括为了某种需求添加、修改Soap header;压缩整个Message、或者Message body; 对Message进行签名或者加密等等。例如,最底层的transport channel负责消息收发,上面的protocol channels提供通信功能和消息操作等。

    Channel stacks是使用工厂模式创建的。消息发送端创建一个ChannelFactory,在binding的接收端创建一个IChannelListener来侦听incoming message。ChannelFactory创建一个channel stack,用它application就可以用来发消息。IChannelListener收到消息后交给侦听的application,创建channel stack。

     

    Client Channel

    例如一个WCF客户端,使用channel级编程实现步骤:

    1. 创建一个binding
    2. 创建/build一个channel factory
    3. 创建一个channel
    4. 发送请求
    5. 读取应答
    6. 关闭channel对象
    CustomBinding cb = new CustomBinding ();
     
    cb.Elements.Add(new TcpTransportBindingElement());
     
    IChannelFactory<IRequestChannel> cf =
      cb.BuildChannelFactory<IRequestChannel>(new BindingParameterCollection());
     
    cf.Open();
     
    IRequestChannel chnl = cf.CreateChannel(new
        EndpointAddress(“net.tcp//localhost:8000/CoolApp”));
     
    Message reqmess =
      Message.CreateMessage(MessageVersion.Soap12WSAddressing10,
       “http://wrox.com/requestaction”, “Message body data”);
     
    Message repmess = chnl.Request(reqmess);
     
    textbox1.text = “Sending message...”;
     
    string MessageData = repmess.GetBody<string>();
     
    textbox2.text = MessageData;
     
    reqmess.Close();
    repmess.Close();
    chnl.Close();
    cf.Close();

     

    Service Channel

    例如一个WCF服务端,使用channel级编程实现步骤:

    1. 创建一个binding
    2. 创建一个channel listener
    3. 打开channel listener
    4. 读取请求,发送应答
    5. 关闭channel对象
    CustomBinding cb = new CustomBinding();
     
    cb.Elements.Add(new TcpTransportBindingElement());
     
    IChannelListener<IReplyChannel> lis =
      cb.BuildChannelListener<IReplyChannel>(new
        Uri(“net.tcp//localhost:8000/CoolApp”),
          new BindingParameterCollection());
     
    lis.Open();  
     
    IReplyChannel repchnl = lis.AcceptChannel();
     
    repchnl.Open();
     
    RequestContext rc = repchnl.ReceiveRequest();
     
    Message reqmes = rc.RequestMessage;
    Message repmes = Message.CreateMessage(MessageVersion.Soap12WSAddressing10,“”,“”);
     
    rc.Reply(repmes);
     
    reqmes.Close();
    rc.Close();
    repchnl.Close();
    lis.Close();

     

    扩展channel,Extend channel,创建自定义的channel

    有以下几个步骤来创建自定义的channel

    1. 选择合适的MEP (Message Exchange Pattern)
    2. 创建channel factory和listener。Channel listeners是在Server端创建channels用来侦听和收消息,channel factory是在发送端/客户端创建channels用来发消息。
    3. 加上binding element
    4. 处理异常

     

    选择合适的MEP (Message Exchange Pattern),有3种MEP供选择:

    • Datagram: 客户端发一个消息不期望应答。客户端并且也不能保证接受方收到了消息。
    • Request-Response:客户端发一个消息,并收到一个应答。传统的Request-Reply 消息交换模式。
    • Duplex:客户端可以发任意多个消息,并按任意次序收到应答。双向Duplex消息交换模式。

     

    Chanel listeners (收)

    Channel listener在服务端创建Channel,侦听消息,从下层接收消息,把消息放到队列,channel各自从队列拿消息,处理消息,最后通过channel把消息交给上层。

     

    Chanel factories (发)

    Channel factory在发送端/客户端创建channels, 用来发消息。Channels从上层拿到消息,处理消息,然后交给下层。Channel factory也要负责关闭自己创建的channels。

     

    加上binding element,创建IChannelFactory和IChannelListener对象

    一个Binding由BindingElement collection组成, 构成BindingElement collection的元素是一个个的BindingElement。BindingElement的最重要的功能就是创建IChannelFactory和IChannelListener对象。

    //the following code uses the BuildChannelFactory of type IRequestChannel with a TcpTransportBindingElement:
    CustomBinding cb = new CustomBinding();
     
    TcpTransportBindingElement el = new TcpTransportBindingElement();
     
    BindingParameterCollection bpc = new BindingParameterCollection();
     
    BindingContext bc = new BindingContext(cb, bpc);
     
    //Create channel factory
    IChannelFactory<IRequestChannel> factory =
        el.BuildChannelFactory<IRequestChannel>(bc);
     
    factory.Open();
     
    EndpointAddress ea = new
      EndpointAddress(“net.tcp://localhost:8000/CoolChannelApp”);
     
    IRequestChannel reqchan = factory.CreateChannel(ea);
     
    reqchan.Open();
     
    Message request =
       Message.CreateMessage(MessageVersion.Default, “this stuff rocks!”);
     
    Message response = reqchan.Request(request);
     
    textBox1.Text = response.Headers.Action.ToString;
    reqchan.Close();
    factory.Close();

     

    //the following code uses the BuildChannelListener of type IReplyChannel for accepting channels.
    The return value is the IChannelListener of type IChannel from the context:
    CustomBinding cb = new CustomBinding();
     
    TcpTransportBindingElement el = new TcpTransportBindingElement();
     
    BindingParameterCollection bpc = new BindingParameterCollection();
     
    Uri ba = new Uri(“net.tcp://localhost:8000/CoolChannelApp”);
     
    String relativeAddress = “net.tcp://localhost:8000/CoolChannelApp/WCFService”;
     
    BindingContext bc = new BindingContext(cb, bpc, ba, relativeAddress,ListenUriMode.Explicit);
     
    //Create channel listener
    IChannelListenr<IReplyChannel> listen =
       el.BuildChannelListener<IReplyChannel>(bc);
     
    listen.Open();
     
    IReplyChannel repchan = listen.AcceptChannel();
     
    repchan.Open();
     
    RequestContext rc = repchan.ReceiveRequest();
     
    Message message = rc.RequestMessage;
     
    if (message.Headers.Action == “this stuff rocks!”)
    {
       Message replymessage = Message.CreateMessage(MessageVersion.Default, “I KNOW!”);
       rc.Reply(replymessage);
    }
    message.Close();
    repchan.Close();
    listen.Close();

     

  • 相关阅读:
    devexpress toolbar 填充整行宽度
    2. Rust的三板斧 安全,迅速,并发
    1. rust的优点
    谈谈我对sku的理解(3)----页面效果
    谈谈我对sku的理解(2)----数据库设计
    谈谈我对sku的理解(1)
    我眼里的奇酷手机360OS
    Oracle中的wm_concat()函数
    获取java本地系统信息 Properties
    java 获取用户的ip都是 127.0.0.1
  • 原文地址:https://www.cnblogs.com/zmc/p/2434299.html
Copyright © 2020-2023  润新知