The Sender: Channel Factories

Channel factories are the means by which the sender creates channels. They share many similarities with channel listeners, but by virtue of the fact that they reside on the sender, they do not have responsibility for listening for incoming connections. Rather than passively waiting for an incoming connection and then creating a channel in response to that connection, they simply create a channel on demand via a CreateChannel method. Like channel listeners, channel factories are grouped according to the functionality of the channel they create.

In practice, this means that each transport channel will have a channel factory associated with it, as will the different WS-* protocol channels. As with channel listeners, user code does not directly instantiate a channel factory; that job is reserved for a Binding (as you’ll see in Chapter 8). Like channel listeners, channel factories subclass the ChannelManagerBase type. The rest of their type hierarchy, however, is different. In this section, we will investigate the different types in the channel factory hierarchy and then continue our DelegatorChannel example by creating a custom channel factory.

The IChannelFactory Interface

All channel factories implement the IChannelFactory interface. This interface implements the ICommunicationObject interface and thus serves as a way to enforce the state machine you should now be familiar with. The IChannelFactory interface also forces types that implement it to expose a query mechanism similar to the one in channels and channel listeners, as shown here:

 public interface IChannelFactory : ICommunicationObject {       T GetProperty<T>() where T: class; }

The IChannelFactory<TChannel> Interface

All channel factories implement the IChannelFactory<TChannel> interface as well. The IChannelFactory<TChannel> interface implements the IChannelFactory interface, so it is more commonly used than the IChannelFactory interface. The IChannelFactory<TChannel> interface defines two members that return a channel, as shown here:

 public interface IChannelFactory<TChannel> : IChannelFactory {       TChannel CreateChannel(EndpointAddress to);       TChannel CreateChannel(EndpointAddress to, Uri via); }

Notice the CreateChannel method with two parameters. The parameters are of type EndpointAddress and Uri. At run time, the to parameter is used as the EndpointAddress serialized into the Message, and the via parameter is used as the address that the channel will try to reach. These values of the via argument can be different from the Uri in the to argument when you want to send the message to one address and have that messaging participant forward the message to another messaging participant (as shown in Chapter 2, “Service Orientation”).

The ChannelFactoryBase Type

Channel factories indirectly subclass the ChannelFactoryBase abstract type. Conceptually, the purpose of this type is similar to the purpose of the ChannelListenerBase type used in channel listeners. In other words, the ChannelListenerBase type provides a means to customize the default time-outs for opening, closing, sending, and receiving messages. The ChannelFactoryBase object model is shown here:

 public abstract class ChannelFactoryBase : ChannelManagerBase,                                            IChannelFactory {   protected ChannelFactoryBase();   protected ChannelFactoryBase(IDefaultCommunicationTimeouts timeouts);   // IChannelFactory implementation   public virtual T GetProperty<T>() where T: class;   // CommunicationObject implementation   protected override void OnAbort();   protected override IAsyncResult OnBeginClose(TimeSpan timeout,                                                AsyncCallback callback,                                                Object state);   protected override void OnClose(TimeSpan timeout);   protected override void OnEndClose(IAsyncResult result);   protected override TimeSpan DefaultCloseTimeout { get; }   protected override TimeSpan DefaultOpenTimeout { get; }   // ChannelManagerBase implementation   protected override TimeSpan DefaultReceiveTimeout { get; }   protected override TimeSpan DefaultSendTimeout { get; } }

The ChannelFactoryBase<TChannel> Type

The ChannelFactoryBase<TChannel> type subclasses the ChannelFactoryBase type and implements the IChannelFactory<TChannel> interface. It serves as a base type for channel factories. Furthermore, the implementation in this type maintains references to and exerts control over the state of the channels it creates. (Recall the “The Concept of a Channel Manager” section earlier in this chapter.) The ChannelFactoryBase<TChannel> object model is shown here:

 public abstract class ChannelFactoryBase<TChannel> : ChannelFactoryBase,     IChannelFactory<TChannel> {   // calls the other constructor, passing null as argument   protected ChannelFactoryBase();   // creates an object that manages the channels   protected ChannelFactoryBase(IDefaultCommunicationTimeouts timeouts);   // IChannelFactory<TChannel> implementation   public TChannel CreateChannel(EndpointAddress address);   public TChannel CreateChannel(EndpointAddress address, Uri via);   // Extensibility point for IChannelFactory<TChannel> implementation   protected abstract TChannel OnCreateChannel(EndpointAddress address, Uri via);   // CommunicationObject implementation: changes state   // of the channels it has created   protected override void OnAbort();   protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state);   protected override void OnClose(TimeSpan timeout);   protected override void OnEndClose(IAsyncResult result);   // helper method that checks the State to see if the   // channel factory can create channels (CommunicationState.Opened)   protected void ValidateCreateChannel(); }

The ChannelFactoryBase<TChannel> constructor instantiates an object that maintains a reference to each of the channels that the ChannelFactoryBase<TChannel> creates. When a ChannelFactoryBase<TChannel> object closes or aborts, the object that is referencing the created channels ensures that the channels proceed through their state machine along with the ChannelFactoryBase<TChannel> object. The code that ensures that these state changes occur is located in the CommunicationObject implementation in the ChannelFactoryBase<TChannel> type.

Another interesting facet of the ChannelFactoryBase<TChannel> type is the ValidateCreateChannel method. This method simply ensures that the State of the object is CommunicationState.Opened. If the state is not CommunicationState.Opened, the method throws an InvalidOperationException. Both of the CreateChannel methods use this method as a means to ensure that the channel factory is in the appropriate point in the state machine.

Building a Custom Channel Factory

Now that you’ve seen the types that play important roles in channel factories, let’s create a channel factory that continues our DelegatorChannel example. Like the DelegatorChannelListener<TShape> example earlier in this chapter, our channel factory must be able to create DelegatorChannel channels of any shape. As a result, our channel factory needs to be generic, as shown here:

 internal sealed class DelegatorChannelFactory<TShape> :     ChannelFactoryBase<TShape> {   // reference the next channel factory in the stack   IChannelFactory<TShape> _innerFactory;   // the String to print to the console   String _consolePrefix = "FACTORY: DelegatorChannelFactory";   // ctor that builds the next channel factory in the stack,   // then assigns the _innerFactory member variable   internal DelegatorChannelFactory(BindingContext context) {     PrintHelper.Print(_consolePrefix, "ctor");     this._innerFactory = context.BuildInnerChannelFactory<TShape>();   }   // instantiates and returns a DelegatorChannel that   // references another channel   private TShape WrapChannel(TShape innerChannel) {     if(innerChannel == null) {       throw new ArgumentNullException("innerChannel cannot be null",         "innerChannel");     }     if(typeof(TShape) == typeof(IOutputChannel)) {       return (TShape)(Object) new DelegatorOutputChannel<IOutputChannel>         (this, (IOutputChannel)innerChannel, "SEND");     }     if(typeof(TShape) == typeof(IRequestChannel)) {       return (TShape)(Object) new DelegatorRequestChannel         (this, (IRequestChannel)innerChannel, "SEND");     }     if(typeof(TShape) == typeof(IDuplexChannel)) {       return (TShape)(Object) new DelegatorDuplexChannel         (this, (IDuplexChannel)innerChannel, "SEND");     }     if(typeof(TShape) == typeof(IOutputSessionChannel)) {       return (TShape)(Object) new DelegatorOutputSessionChannel         (this, (IOutputSessionChannel)innerChannel, "SEND");     }     if(typeof(TShape) == typeof(IRequestSessionChannel)) {       return (TShape)(Object) new DelegatorRequestSessionChannel         (this, (IRequestSessionChannel)innerChannel, "SEND");     }     if(typeof(TShape) == typeof(IDuplexSessionChannel)) {       return (TShape)(Object) new DelegatorDuplexSessionChannel         (this, (IDuplexSessionChannel)innerChannel, "SEND");     }     // cannot wrap this channel     throw new ArgumentException(String.Format("invalid channel shape       passed:{0}", innerChannel.GetType()));   }   // uses the _innerFactory member variable to build a channel   // then wraps it and returns the wrapped channel   protected override TShape OnCreateChannel(EndpointAddress address,     Uri via) {     // create and return the channel     PrintHelper.Print(_consolePrefix, "OnCreateChannel");     TShape innerChannel = this._innerFactory.CreateChannel(address, via);     return WrapChannel(innerChannel);   }   protected override IAsyncResult OnBeginOpen(TimeSpan timeout,                                               AsyncCallback callback,                                               Object state) {     PrintHelper.Print(_consolePrefix, "OnBeginChannel");     return this._innerFactory.BeginOpen(timeout, callback, state);   }   protected override void OnAbort() {     base.OnAbort();     PrintHelper.Print(_consolePrefix, "OnAbort");   }   protected override void OnClose(TimeSpan timeout) {     base.OnClose(timeout);     PrintHelper.Print(_consolePrefix, "OnClose");   }   protected override void OnEndOpen(IAsyncResult result) {     PrintHelper.Print(_consolePrefix, "OnEndOpen");     this._innerFactory.EndOpen(result);   }   protected override void OnOpen(TimeSpan timeout) {     PrintHelper.Print(_consolePrefix, "OnOpen");     this._innerFactory.Open(timeout);   }   public override T GetProperty<T>() {     PrintHelper.Print(_consolePrefix, "GetProperty<" + typeof(T).Name +       ">");     return this._innerFactory.GetProperty<T>();   } }

Conceptually, the DelegatorChannelFactory<TShape> type is very similar to the DelegatorChannelListener<TShape> type definition. It defines a private method named WrapChannel that wraps a channel in a DelegatorChannel of a specified shape and returns it. It also defines several methods that delegate state transitions to the _innerFactory member variable.

Inside Windows Communication Foundation
Inside Windows Communication Foundation (Pro Developer)
ISBN: 0735623066
EAN: 2147483647
Year: 2007
Pages: 106
Authors: Justin Smith

Similar book on Amazon
Learning WCF: A Hands-on Guide
Learning WCF: A Hands-on Guide
Essential Windows Communication Foundation (WCF): For .NET Framework 3.5
Essential Windows Communication Foundation (WCF): For .NET Framework 3.5
Programming WCF Services: Mastering WCF and the Azure AppFabric Service Bus
Programming WCF Services: Mastering WCF and the Azure AppFabric Service Bus
Microsoft  Windows  Communication Foundation Step by Step (Step By Step Developer Series)
Microsoft Windows Communication Foundation Step by Step (Step By Step Developer Series) © 2008-2017.
If you may any questions please contact us: