Channel sinks are the means by which messages are passed back and forth between the client and server. A channel sink can be an alternative way to achieve the same end. But sinks are not limited to that single function. The HTTP and TCP channels, provided by .NET, have two default sinks in the sink chain-a formatter and a transport sink. The formatter converts an IMessage into a stream, while the transporter streams the data across the wire. Each does a discrete unit of work and hands the result to the next sink in the chain.
The .NET Framework does not restrict the number of links in a sink chain. The sink chain can be viewed as a functional linked list, rather than a linked list of data. Depending on the problem domain, one to many sinks are plugged into a channel's chain, with each sink addressing a single task. This may include logging, security functions, encryption, or any other task that is required on the route from the transparent proxy to the remote object. To become a member of a sink chain, certain criteria must be met.
All channels are divided into senders and receivers. Receivers are generally servers, while senders are clients. Channel sinks can be seen in the same light. They are connected to a channel by a sink provider, either a System.Runtime.Remoting.Channels.IClientChannelSinkProvider or an IServerChannelSinkProvider.
Listing 25.28: ClientSinkProvider.vb
Imports System.Runtime.Remoting.Channels
Public Class ClientSinkProvider
Implements IClientChannelSinkProvider
Private m_next As IClientChannelSinkProvider = Nothing
Public Sub New()
End Sub
Public Sub New(ByVal props As IDictionary, ByVal provider As ICollection)
End Sub
Public Function CreateSink(ByVal sender As IChannelSender, ByVal url As String, ByVal channelData As Object) As
IClientChannelSink
Dim sink As IClientChannelSink = Nothing
If m_next IsNot Nothing Then
sink = m_next.CreateSink(sender, url, channelData)
End If
If sink IsNot Nothing Then
sink = New ClientSink(sink)
End If
Return (sink)
End Function
Public Property [Next]() As IClientChannelSinkProvider
Get
Return (m_next)
End Get
Set(ByVal value As IClientChannelSinkProvider)
m_next = value
End Set
End Property
End Class
Deriving from the IClientChannelSinkProvider interface, described in Listing 25.28, requires implementing the CreateSink method and the Next property. The server provider code, not shown, in ServerSinkProvider.vb is the same, except for an additional method, GetChannelData(), which has a System.Runtime.Remoting.Channels.IChannelDataStore parameter.
Notice in CreateSink() that if there is a next provider, its CreateSink() is called before the current provider instantiates its sink. In other words, the last provider is the first to create an actual sink and starts the process where the sinks are chained together. It is also evident that as soon as the provider creates its sink, it could be a candidate for disposal, as it has no knowledge of the sink once instantiation is complete.
The order in which providers are attached to a channel determines the order of the sink chain. On the server, the first sink must be the transport sink, and the last must the formatter sink. On the client the order is reversed. If the order is incorrect, results are unpredictable! Sink providers are attached to a channel via a configuration file or programmatically. The order of creation will be clearer with some example code. (See Listing 25.29.)
Listing 25.29: SinkClient.cs
Dim channelData As New Hashtable()
Dim properties As New Hashtable()
Dim providerData As New ArrayList()
Dim clientProvider As ClientSinkProvider = Nothing
Dim serverProvider As ServerSinkProvider = Nothing
Dim clientFormatter As SoapClientFormatterSinkProvider = Nothing
Dim serverFormatter As SoapServerFormatterSinkProvider = Nothing
Dim http As MyHttpChannel = Nothing
clientFormatter = New SoapClientFormatterSinkProvider(properties, providerData)
clientProvider = New ClientSinkProvider(properties, providerData)
clientFormatter.[Next] = clientProvider
serverProvider = New ServerSinkProvider(properties, providerData)
serverFormatter = New SoapServerFormatterSinkProvider(properties, providerData)
serverProvider.[Next] = serverFormatter
http = New MyHttpChannel(channelData, clientFormatter, serverProvider)
The client creates the SOAP formatter and then the customized provider, which is assigned to the clientFormatter.Next property. The server's order of creation and assignment is reversed. Because MyHttpChannel inherits from HttpChannel, both sender and receiver sinks are required. During construction of the channel, the transport sinks are created and placed in the appropriate position in their respective chains.
Listing 25.30: Shared.config
<?xml version="1.0" ?>
<configuration>
<system.runtime.remoting>
<channels>
<channel id="http"
type="CustomSinkLib.MyHttpChannel, CustomSinkLib">
</channel>
</channels>
<channelSinkProviders>
<clientProviders>
<formatter id="soap"
type="System.Runtime.Remoting.Channels.SoapClientFormatterSinkProvider,System.Runtime.Remoting"/>
<provider id="custom" type="CustomSinkLib.ClientSinkProvider, CustomSinkLib"/>
</clientProviders>
<serverProviders>
<formatter id="soap"
type="System.Runtime.Remoting.Channels.SoapServerFormatterSinkProvider,System.Runtime.Remoting"/>
<provider id="custom" type="CustomSinkLib.ServerSinkProvider, CustomSinkLib"/>
</serverProviders>
</channelSinkProviders>
</system.runtime.remoting>
</configuration>
The server and client configuration files are shown in Listings 25.31 and 25.32, while a common configuration file is shown in Figure 25.30. The server's provider is listed ahead of the formatter. Not shown, but present nonetheless, is the transporter. The Http and Tcp namespaces supply a client transport sink provider and transport sink as private classes in System.Runtime.Remoting.dll. It is worth noting that the Http and Tcp servers don't have a transport sink provider, simply a transport sink, which has the variable name transportSink.
Listing 25.31: SinkServerExe.exe.config
<?xml version="1.0" ?>
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown type="SimpleObjectForSinkLib.SimpleObject, SimpleObjectForSinkLib"
mode="Singleton" objectUri="Simple"/>
</service>
<channels>
<channel ref="http" port="1234">
<serverProviders>
<provider ref="custom"/>
<formatter ref="soap"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
Conclusion
Hope this article would have helped you in understanding Channel Sinks in VB.NET. Remaining part of this article you will see in my next article.