December 21, 2014
Hot Topics:

Building WCF Channels and Bindings

  • May 7, 2007
  • By Jeffrey Juday
  • Send Email »
  • More Articles »

The Listeners

Earlier, you looked at the relationship between the Listener and the Channel. I invite you again to review that section of the article.

As you will see, ChannelListeners are interesting fellows. In your sample, there is a ChannelListener for each Channel in the program. I'll point out the difference between each ChannelLister where appropriate. For simplicity, you'll look at the protocol Channels ChannelListener.

First, the ChannelLister inherits from the ChannelListenerBase class. As you will see, Generics, a new feature in the .NET 2.0 framework, are used throughout the ChannelListener and other classes in WCF. If the syntax is new to you, here is a good whitepaper on the subject: http://msdn2.microsoft.com/en-us/library/ms379564(VS.80).aspx. Below is the ChannelListener class declaration.

class TestTransportChannelListener : ChannelListenerBase<IInputChannel>
   {
      private Uri _uri;
      private EndpointAddress _localAddress;

      public TestTransportChannelListener(TestTransportBindingElement
                                          transportElement,
                                          BindingContext context)
         : base(context.Binding)
      {
         BigHelper.DisplayMessage("Construct " + this.ToString());

         _uri = new Uri(context.ListenUriBaseAddress,
                        context.ListenUriRelativeAddress);

         _localAddress = transportElement.LocalAddress;
      }

As you can see, the first parameter in the constructor is the BindingElement responsible for building the ChannelListener. You'll see more about BindingElements later is this article. You may have also noticed that the ChannelListener stores the ChannelListener from the layer just below in the Channel Stack. You'll learn more about why this is important later in the article.

The ChannelListener is also controlled by the Communication State Machine.

As stated earlier, the ChannelListener is responsible for building Channels. Channel construction happens on the OnAcceptChannel function. Here an example of an OnAcceptChannel function implemented by one of the Protocal Channels.

protected override IInputChannel OnAcceptChannel(TimeSpan timeout)
{
   EndpointAddress address = new EndpointAddress(BigHelper.Uri);

   _innerChannel = _innerChannelListener.AcceptChannel(timeout);

   TestLevel2Channel channel = new TestLevel2Channel(this, address);

   return channel;
}

Below is a graphical depiction of the interactions when calling AcceptChannel.



Click here for a larger image.

As I pointed out in the constructor, _innerChannelListener is the ChannelListener a level lower in the ChannelStack. The ChannelListener stores the Channel from the level below the current Listener and returns a Channel to the level above. The process of storing the Channel below and returning the Channel created by the Listener continues until, at the topmost level, the application gets a reference to the topmost Channel in the stack. A graphical depiction of this appears below. Because there is no level lower than the Transport Channel, the code in the Transport Channel simply creates a Message object.



Click here for a larger image.

The GetProperty function allows other layers of WCF to peruse the Channel Stack. How WCF uses the GetProperty function is beyond the scope of this article.

This brings us to the Binding and the BindingElement.

Binding it all Together

Bindings are composed of BindingElements. As stated earlier, BindingElements build ChannelListeners. In the sample, each BindingElement is responsible for one particular ChannelListener. The most interesting function in the BindingElement is the BuildChannelListener.

public override IChannelListener<TChannel>
   BuildChannelListener<TChannel>(BindingContext context)
{
   if (context == null)
   {
      throw new ArgumentNullException("context");
   }
   if (!CanBuildChannelListener<TChannel>(context))
   {
      throw new ArgumentException(String.Format("Unsupported
         channel type: {0}.", typeof(TChannel).Name));
   }

   BigHelper.DisplayMessage("Build Listener " + this.ToString() +
      " of type " + typeof(TChannel).ToString() );

   return (IChannelListener<TChannel>)(object)new
      TestTransportChannelListener(this, context);
}

As you will see in the next section, WCF reads the Binding and builds the Channel Stack from the Collection of BindingElements.

Invoking the Channel Stack

The code below performs the following actions:

  1. Instantiates a new Binding.
  2. Gets the ChannelListener from the topmost part of the Channel Stack.
  3. Opens the topmost ChannelListener.
  4. Calls AcceptChannel, which in turn, calls OnAcceptChannel on the topmost ChannelListener and returns the topmost Channel.
  5. Opens the topmost Channel.
  6. Calls Receive on the topmost Channel and prints the message returned.
static void Main(string[] args)
{
   TestBinding bind = new TestBinding();
   IChannelListener<IInputChannel> listener;
   IInputChannel channel;
   Message msg;
   BindingParameterCollection parms = new BindingParameterCollection();

   BigHelper.DisplayComment("Tracing...");
   BigHelper.DisplayComment("");

   listener = bind.BuildChannelListener<IInputChannel>(parms);

   listener.Open();

   channel = listener.AcceptChannel();

   channel.Open();

   channel.WaitForMessage(TimeSpan.FromSeconds(3.0));

   msg = channel.Receive();

As you saw earlier, calling AcceptChannel and Receive on the topmost Listener and Channel cascades through the Channel Layers until the Transport layer is reached.

Exploring WCF Channels and Bindings

This article was meant to answer some of your WCF questions regarding Channels and Bindings and to raise more questions. WCF is an immense undertaking within Microsoft, consolidating much of the communication capabilities of the .NET Framework. Many future products will be built upon it. So, as you study WCF, pay attention to the landmarks explored in this article.

Download the Code

Download the source code for this article here.





Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel