Creating the Custom Sink Provider
To start, you'll need to build a class that can save message contents to a file using the serialized stream format accessible through the implementation of the IClientChannelSink interface. The reason for using the IClientChannelSink interface is that it provides the required functions and properties for client channel sinks, and by implementing this interface you can customize your own sinks. This interface defines a
ProcessMessage method that you can use to extend the message sink and serialize the message contents to the file system (see the ClientSinkSerializer class in
Listing 3). To implement this custom sink, you need to create a sink provider class that implements IClientSinkProvider. In the
CreateSink member function of IClientSinkProvider, use the following lines of code:
public IClientChannelSink CreateSink
(IChannelSender channel, string url, object remoteChannelData)
{
IClientChannelSink next = _nextProvider.CreateSink
(channel, url, remoteChannelData);
return new ClientSinkSerializer(next);
}
The preceding code returns a new ClientSinkSerializer class instance, passing the next sink in the sink chain as a parameter to the constructor. That enables the ClientSinkSerializer class to perform its processing and then pass the message data onto the client's transport sink.
You can apply serialization sink techniques similar to those shown in this article to enable message compression, message level encryption, message logging, and other useful functions.
|
|
To make use of the client sink provider, you must configure the remoting client application using a configuration file entry so the application can programmatically register the message sink provider. The application uses the channel definition parameters defined in the client application's configuration file to create the sink on the client as soon as it registers the channel. Here's a sample configuration file excerpt:
<configuration>
<system.runtime.remoting>
<application>
<channels>
<channel ref="http">
<clientProviders>
<formatter ref="soap" />
<provider type=
"SerializationSink.ClientSinkSerializerProvider,
SerializationSink" />
</clientProviders>
</channel>
</channels>
<client>
<wellknown type="RemotingServer.RSExample, RSExample"
url="http://localhost/RemotingExample/RSExample.soap" />
</client>
</application>
</system.runtime.remoting>
</configuration>
The
element contains the defined channel properties, including the definition of the
element and its nested
element, which has attributes for the message sink provider types and assembly names. In addition, the
element defines the formatter type and channel type for communications, which are
SOAP and
Http respectively in this example. When the client application is configured to use the sink provider, the message contents will be serialized to a file prior to the invocation of the remoting server method. The data captured from the
responseStream when calling the
GetHelloWorld method is the following:
<SOAP-ENV:Envelope
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0"
SOAP-ENV:encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<i2:GetHelloWorld id="ref-1"
xmlns:i2=
"http://schemas.microsoft.com/clr/nsassem/RemotingInterface.
IRemotingExample/RemotingInterface">
</i2:GetHelloWorld>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The message is in a SOAP formatas expected based on the configuration of the client and the remoting server. The body of the SOAP message specifies the remoting server method being invoked,
GetHelloWorld.
The extensibility of the .NET remoting framework, including the use of custom sink providers for client applications consuming remoting services, lets you leverage the base plumbing of the remoting infrastructure to build custom applications, tweaking behavior as needed. You can use similar remoting extension techniques to develop custom formatters and add customization to remoting transports, meaning you can take advantage of different serialization formats and transport mechanisms for your remoting applications. You can apply serialization sink techniques similar to those shown in this article to enable message compression, message level encryption, message logging, and other useful functions. In addition, using the configuration support provided for remoting applications lets you take advantage of the extensibility features and the "plug-in" architecture long after developing and deploying the core application components.