博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

WCF 信道 源码反射

Posted on 2012-08-02 21:22  qianyz  阅读(253)  评论(0编辑  收藏  举报

介绍信道栈的时候我说信道栈具有两个必要的信道,其中一个是用于消息编码、解码的消息编码信道,另一个是用于消息发送/接收的传输信道,当时我们只是为了方便说迷宫信道栈对消息的处理流程,而且很多WCF的书籍和资料上说信道栈的时候也采用这样的说法,其实这种说法是不对的,实际上并不存在消息编码信道,用于创建消息编码信道的信道监听器和信道国内钢厂自然也不存在。在整个绑定模型中,与消息编码相关的至于消息编码绑定元素、

一般来说,绑定元素的主要目的是创建信道监听器和信道工厂,最后使用他们创建相应的信道对消息的相应的处理,但是消息编码绑定元素确是个例外,在他的BulidChannelListener<TChannel>和BulidChannelFactory<Tchannel>中,仅仅是将自己添加到当前的绑定上下文(BindingContext)中.

在创建传输信道的时候,会从绑定上下文中获取消息编码绑定元素,并调用气CreateMessageEncoderFactory得到形影的消息编码器工厂,传输信道户利用该消息编码器工厂创建消息变那么其在发送前和接收后对消息纪念性编码和解码,也就是说,消息的编码和解码最终是通过传输新年到完成的。

 

TextMessageEncodingBindingElement :源码如下

public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context) where TChannel: class, IChannel
{
    return base.InternalBuildChannelListener<TChannel>(context);//调用了基类的方法 
}
internal IChannelListener<TChannel> InternalBuildChannelListener<TChannel>(BindingContext context) where TChannel: class, IChannel
{
    if (context == null)
    {
        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("context"));
    }
    context.BindingParameters.Add(this);//将该绑定元素添加到集合中去
    return context.BuildInnerChannelListener<TChannel>();//调用了下一个bindingelement的创建

在传输通道中是这样调用的
HttpTransportBindingElement
public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context) where TChannel: class, IChannel
{
    if (context == null)
    {
        throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
    }
    if (!this.CanBuildChannelListener<TChannel>(context))
    {
        throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("TChannel", SR.GetString("CouldnTCreateChannelForChannelType2", new object[] { context.Binding.Name, typeof(TChannel) }));
    }
    HttpChannelListener listener = new HttpChannelListener(this, context);  //创建的一个新的监听器,
AspNetEnvironment.Current.ApplyHostedContext(listener, context); return (IChannelListener<TChannel>) listener; }
 HttpChannelListener(this, context);里面的部分源码如下
 Collection<MessageEncodingBindingElement> collection = context.BindingParameters.FindAll<MessageEncodingBindingElement>();//找到编码bindingelement
    if (collection.Count > 1)
    {
        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("MultipleMebesInParameters")));
    }
    if (collection.Count == 1)
    {
        this.messageEncoderFactory = collection[0].CreateMessageEncoderFactory();//掉用了CreateMessageEncoderFactory创建了编码解码工厂
        context.BindingParameters.Remove<MessageEncodingBindingElement>();//删除掉
    }
    else
    {
        this.messageEncoderFactory = defaultMessageEncoderFactory;
    }



其他的消息解码编码的bindingelement在调用BuildChannelListener<TChannel>()的时候会将自己的加入到bindingcontext的paramcollect中
然后调用bindingcontext.BuildInnerChannelListener<TChannel>();创建下一个传输通道,而在传输通道中会使用编码/解码元素来创建编码解码工厂
====================================================================================================================
====================================================================================================================
一般的信道栈会在当前信道的内部保存底层信道的引用通常做法是
在bindingelement.BuildChannelListener<TChannel>(BindingContext context)
{
new channelListener(context)
}
而在new  channelListener(context)内部会

  //先把底层的listener创建
innerlistener=context.BuildInnerChannelListener()创建下一个信道,从而形成信道栈
//在初始化自己的

//////////////////////////////////////////////////////
在channelListener.AcceptChannle()
{
channel= this.innerListern.AcceptChannel();//先从底层接收一个
return new warp(this,channel)//包装下,同时创建自己的channel然后返回
}

具体可以反射下OneWayBindingElement 来看下大概的源代码
OneWayBindingElement :

public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context) where TChannel: class, IChannel
{
    if (context == null)
    {
        throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
    }
    if (typeof(TChannel) != typeof(IInputChannel))
    {
        throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("TChannel", SR.GetString("ChannelTypeNotSupported", new object[] { typeof(TChannel) }));
    }
    if (context.CanBuildInnerChannelListener<IDuplexChannel>())
    {
        return (IChannelListener<TChannel>) new DuplexOneWayChannelListener(this, context);
    }
    if (context.CanBuildInnerChannelListener<IDuplexSessionChannel>())
    {
        return (IChannelListener<TChannel>) new DuplexSessionOneWayChannelListener(this, context);
    }
    if (!context.CanBuildInnerChannelListener<IReplyChannel>())
    {
        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("OneWayInternalTypeNotSupported", new object[] { context.Binding.Name })));
    }
    return (IChannelListener<TChannel>) new ReplyOneWayChannelListener(this, context);
}

 

new ReplyOneWayChannelListener(this, context)内部就会调用 innerChannelListener=context.BuildInnerChannelListener<IReplyChannel>()来创建内部的ChannelListener