The Windows Communication Foundation Channel Layer


In the Windows Communication Foundation, protocols are implemented as channels. Data passes through channels, and the channel arranges the data passing through it in accordance with the protocols that the channel implements:

public interface IChannel : ICommunicationObject, IDisposable {     IChannelManager Manager { get; } }


Channels are communication objects. Communication objects provide methods for being opened and closed:

public interface ICommunicationObject : IDisposable {     CommunicationState State { get; }     event EventHandler Closed;     event EventHandler Closing;     event EventHandler Faulted;     event EventHandler Opened;     event EventHandler Opening;     void Abort();     IAsyncResult BeginClose(         AsyncCallback callback, object state);     IAsyncResult BeginClose(         TimeSpan timeout, AsyncCallback callback, object state);     IAsyncResult BeginOpen(         AsyncCallback callback, object state);     IAsyncResult BeginOpen(         TimeSpan timeout, AsyncCallback callback, object state);     void Close();     void Close(TimeSpan timeout);     void EndClose(IAsyncResult result);     void EndOpen(IAsyncResult result);     void Open();     void Open(TimeSpan timeout); }


The Windows Communication Foundation distinguishes between input channels and output channels. Output channels can send messages:

public interface IOutputChannel : IChannel, ICommunicationObject, IDisposable {     EndpointAddress RemoteAddress { get; }     Uri Via { get; }     IAsyncResult BeginSend(         Message message,         AsyncCallback callback,             object state);     IAsyncResult BeginSend(         Message message,         TimeSpan timeout,         AsyncCallback callback,         object state);     void EndSend(IAsyncResult result);     void Send(Message message);     void Send(Message message, TimeSpan timeout); }


Input channels provide methods for receiving messages from them:

public interface IInputChannel : IChannel, ICommunicationObject, IDisposable {     EndpointAddress LocalAddress { get; }     IAsyncResult BeginReceive(AsyncCallback callback,         object state);     IAsyncResult BeginReceive(TimeSpan timeout,         AsyncCallback callback,         object state);     IAsyncResult BeginTryReceive(TimeSpan timeout,         AsyncCallback callback,         object state);     IAsyncResult BeginWaitForMessage(TimeSpan timeout,         AsyncCallback callback,         object state);     Message EndReceive(IAsyncResult result);     bool EndTryReceive(IAsyncResult result, out Message message);     bool EndWaitForMessage(IAsyncResult result);     Message Receive();     Message Receive(TimeSpan timeout);     bool TryReceive(TimeSpan timeout, out Message message);     bool WaitForMessage(TimeSpan timeout); }


Input channels are retrieved from listeners:

public interface IChannelListener<TChannel> :         IChannelListener,         IChannelManager,         ICommunicationObject,         IDisposable             where TChannel : class, System.ServiceModel.IChannel {     TChannel AcceptChannel();     TChannel AcceptChannel(TimeSpan timeout);     IAsyncResult BeginAcceptChannel(AsyncCallback callback,         object state);     IAsyncResult BeginAcceptChannel(TimeSpan timeout,         AsyncCallback callback, object state);     TChannel EndAcceptChannel(IAsyncResult result); }


Channels are created using channel factories:

public interface IChannelFactory<TChannel> :     IChannelFactory, IChannelManager, ICommunicationObject, IDisposable {     TChannel CreateChannel(EndpointAddress to);     TChannel CreateChannel(string address);     TChannel CreateChannel(Uri address);     TChannel CreateChannel(EndpointAddress to, Filter filter, int priority); }


Channel factories are created by binding elements, which also create listeners:

public abstract class BindingElement {     protected BindingElement();     protected BindingElement(BindingElement other);     public virtual IChannelFactory BuildChannelFactory(         ChannelBuildContext context);     public virtual IChannelFactory<TChannel> BuildChannelFactory<TChannel>(         ChannelBuildContext context);     public virtual IChannelListener<TChannel> BuildChannelListener<TChannel> (         ChannelBuildContext context         ) where TChannel : IChannel     public virtual bool CanBuildChannelFactory<TChannel>(         ChannelBuildContext context);     public virtual bool CanBuildChannelListener<TChannel> (             ChannelBuildContext context         ) where TChannel : IChannel     public abstract BindingElement Clone();     public virtual T GetCapabilities<T>(         IList<BindingElement> lowerBindingElements         ) where T : class;     public abstract ChannelProtectionRequirements GetProtectionRequirements();     public virtual ChannelProtectionRequirements GetProtectionRequirements(         CustomBinding context); }


Binding elements that can create transport protocol channels and transport protocol listeners are transport binding elements:

public interface ITransportBindingElement {     string Scheme { get; } }


Transport protocol listeners use message encoders to assemble the streams of bytes they receive into messages:

public abstract class MessageEncoder {     protected MessageEncoder();     public abstract string ContentType { get; }     public abstract string MediaType { get; }     public abstract MessageVersion MessageVersion { get; }     public virtual bool IsContentTypeSupported(string contentType);     public abstract Message ReadMessage(         ArraySegment<byte> buffer, BufferManager bufferManager);     public abstract Message ReadMessage(         Stream stream, int maxSizeOfHeaders);     public override string ToString();     public abstract void WriteMessage(Message message, Stream stream);     public ArraySegment<byte> WriteMessage(         Message message, int maxMessageSize, BufferManager bufferManager);     public abstract ArraySegment<byte> WriteMessage(         Message message,         int maxMessageSize,         BufferManager bufferManager,         int messageOffset); }


Message encoders are created by message encoder factories:

public abstract class MessageEncoderFactory {     protected MessageEncoderFactory();     public abstract MessageEncoder Encoder { get; }     public abstract MessageVersion MessageVersion { get; }     public virtual MessageEncoder CreateSessionEncoder(); }


Message encoder factories are created by binding elements that are message encoding binding elements:

public interface IMessageEncodingBindingElement {     AddressingVersion AddressingVersion { get; }     MessageEncoderFactory CreateMessageEncoderFactory(); }


Bindings are composed of a collection of binding elements, exactly one of which must be a transport binding element, and one or more of which must be message encoding binding elements:

public class CustomBinding :     Binding,     ISecurityCapabilities,     IBindingManualAddressing {     public CustomBinding();     public CustomBinding(Binding binding);     public CustomBinding(IEnumerable<BindingElement> bindingElements);     public CustomBinding(params BindingElement[] bindingElements);     public CustomBinding(string configurationName);     public CustomBinding(         string name,         string ns,         params BindingElement[] bindingElements);     public BindingElementCollection Elements { get; }     public override string Scheme { get; }     public override BindingElementCollection CreateBindingElements();     protected void Initialize();     protected override void OnApplyConfiguration(string configurationName); }


A service is made available by adding an endpoint for that service to a service host, an endpoint being a unique address, and a service contract together with a binding:

public class ServiceHost : ServiceHostBase {     protected ServiceHost();     public ServiceHost(object serviceInstance, params Uri[] baseAddresses);     public ServiceHost(Type serviceType, params Uri[] baseAddresses);     public ServiceAuthorization Authorization { get; }     public ServiceCredentials Credentials { get; }     public virtual ServiceDescription Description { get; }     public virtual ReflectedContractCollection ReflectedContracts { get; }     public virtual Type ServiceType { get; }     public virtual object SingletonInstance { get; }     public ServiceEndpoint AddServiceEndpoint(         Type implementedContract, Binding binding, string address);     public ServiceEndpoint AddServiceEndpoint(         Type implementedContract, Binding binding, Uri addressUri);     protected void Initialize();     protected virtual void OnApplyConfiguration(ServiceElement serviceSection);     protected override void OnClose(TimeSpan timeout);     protected virtual void OnCreateDescription();     protected override void OnCreateListeners();     protected override void OnEndClose(IAsyncResult result);     protected void ReleasePerformanceCounters(); }


Service hosts are communication objects, which, as shown earlier, provide methods for being opened and closed:

public abstract class ServiceHostBase :     CommunicationObject, IExtensibleObject<ServiceHostBase> {     protected ServiceHostBase(params Uri[] baseAddresses);     protected ServiceHostBase(UriSchemeKeyedCollection baseAddresses);     public UriSchemeKeyedCollection BaseAddresses { get; }     public TimeSpan CloseTimeout { get; set; }     protected override TimeSpan DefaultCloseTimeout { get; }     protected override TimeSpan DefaultOpenTimeout { get; }     public EndpointListenerCollection EndpointListeners { get; }     public IExtensionCollection<ServiceHostBase> Extensions { get; }     public TimeSpan OpenTimeout { get; set; }     public event EventHandler<UnknownMessageReceivedEventArgs>       UnknownMessageReceived;     protected override void OnAbort();     protected override IAsyncResult OnBeginClose(         TimeSpan timeout, AsyncCallback callback, object state);     protected override IAsyncResult OnBeginOpen(     TimeSpan timeout, AsyncCallback callback, object state);     protected override void OnClose(TimeSpan timeout);     protected abstract void OnCreateListeners();     protected override void OnEndClose(IAsyncResult result);     protected override void OnEndOpen(IAsyncResult result);     protected virtual void OnInitialize();     protected override void OnOpen(TimeSpan timeout); }


When the host of a service is opened, it uses the elements of each service's binding to create listeners. That process is actually undertaken on behalf of the service host by an element of the Windows Communication Foundation called the ServiceDescription, which creates, in effect, a description of the service from the specifications constituted by the address, the binding, and the contract. During the process, the characteristics of the contract are compared with the capabilities of the binding elements. For example, if the contract describes a message exchange pattern by which the service will be replying directly to requests from its clients, the communication protocols specified in the bindings must accommodate such a pattern. The binding elements' generic CanBuildChannelListener<TChannel>() method assists the ServiceDescription in comparing the capabilities of the listeners implied by the binding with the definition of the contract.

After the description of the service is complete, the Windows Communication Foundation's Dispatcher takes over. It calls the methods of the listener created from the first binding element's listener factory to retrieve an input channel, from which it will read messages that it will pass on to the code of the service. That listener in turn calls the methods of the listener created from the next binding element's listener factory to retrieve an input channel, and so on, until the request for an input channel reaches a listener that implements a transport protocol. That listener will listen for messages, typically using a socket. When a message arrives, the listener does two things. First, it uses the message encoder that must have been specified among the elements of the service's binding to assemble the bytes it has received from the socket into a coherent message. Then, it creates an input channel if it has not done so already, adds the message to that channel, and passes the input channel to the listener that requested it.

After some reflection on all of the foregoing, it should become apparent that adding support for an additional transport protocol to the Windows Communication Foundation really means adding a new transport binding element to the Channel Layer. That transport binding element would provide channel factories for creating transport channels that support the protocol. The new binding element would also provide listeners that support the protocol. With the new transport binding element, one could create a binding for a service endpoint that could send and receive messages via the transport protocol.




Presenting Microsoft Communication Foundation. Hands-on.
Microsoft Windows Communication Foundation: Hands-on
ISBN: 0672328771
EAN: 2147483647
Year: 2006
Pages: 132

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net