如何定制Sink扩展.Net Remoting功能
How to Build Custom Sinks to extend the Features of.Net Remoting Framework
关于Channel, Sink (Channel Sink or Message Sink), Sink Chain and Channel Sink Provider等.Net Remoting Framework中一些基本概念,可以参考《信道、接收器、接收链和信道接受提供程序》。这里利用.Net Remoting Framework内置的扩展特性,来定制Remoting流程,满足应用程序的特定需要。
.Net Remoting Framework在Client/Server端同时实现了Formatter Sink和Transport Sink,这是支持Remote Object调用的关键Sink。对Remote Object的每一次调用都会产生消息,这些消息用于Client与Server之间的数据交换。远程调用的每一个消息都经过Client/Server的接受链(Sink Chain)。Sink接受消息并处理消息,并传递消息到Sink Chain的下一个Sink。
其中,Sink Chain中的Formatter Sink用来序列化消息,以适于网络传输;或者反序列化消息,以适于application读取。.Net Remoting缺省支持SOAP Formatter Sink和Binary Formatter Sink,你也可以定制Formatter来扩展Remoting基础结构。
为了测试/编写Custom Sink,首先需要建立一个.Net Remoting Application,包括Client端application和Server端Remote Objects,并且确认运行正确,没有bug。建立Remoting Application的过程就省略了。
下面demo分别在Client或Server端建立定制的Sink,用来记录LOG调用消息,其实就是SOAP消息。
1,定制Sink
下面是Client/Server Custom Sink类图,都实现公共的ILoggingSink接口,其中Enable属性设定是否记录LOG消息,Out属性用来控制消息输出,如Console, File等。
以Client端的Sink为例:
class LoggingClientChannelSink : BaseChannelObjectWithProperties, IClientChannelSink, ILoggingSink
这里LoggingClientChannelSink实现了2个接口:IClientChannelSink, ILoggingSink,同时还继承Abstract Class BaseChannelObjectWithProperties。
注解:
(1)ILoggingSink – 是自定义接口,Client/Server端的Custom Sink都实现该接口。
(2)IClientChannelSink - 是Custom Sink必须实现的接口,IClientChannelSink接口提供了ProcessMessage()方法和NextChannelSink属性等等,是Custom Sink必需的。
(3)BaseChannelObjectWithProperties - Provides a base implementation of a channel object that wants to provide a dictionary interface to its properties. (英文比MSDN的中文好理解)
The derived class only needs to implement the Keys property and this[].
We don’t have to write implementation of the interface from scratch. We can derive our custom channel sinks from an abstract class named BaseChannelObjectWithPropertis. We can use this abstract class to help implementation our custom channel sinks.
下面的ProcessMessage()方法和NextChannelSink属性来自IClientChannelSink接口。通过实现IClientChannelSink接口的ProcessMessage()方法来序列化消息到Console或者File,其中LoggingHelper Class中PrintRequest和PrintResponse分别负责打印Request/Response消息。
public void ProcessMessage(IMessage msg,
ITransportHeaders requestHeaders, Stream requestStream,
out ITransportHeaders responseHeaders, out Stream responseStream)
{
if (_bEnabled)
LoggingHelper.PrintRequest(_output, requestHeaders, ref requestStream);
_nextSink.ProcessMessage(msg, requestHeaders, requestStream,
out responseHeaders, out responseStream);
if (_bEnabled)
LoggingHelper.PrintResponse(_output, responseHeaders, ref responseStream);
} // ProcessMessage
获取客户端接收器链中的下一个客户端信道接收器。
public IClientChannelSink NextChannelSink
{
get { return _nextSink; }
}
2,编写Sink Provider
Client或Server端的Sink Provider分别需要实现IclientChannelSinkProvider和IServerChannelSinkProvider接口。
.Net Remoting Framework实现IClientChannelSinkProvider 的类有:BinaryClientFormatterSinkProvider(为二进制客户端格式化程序接收器提供程序提供实现)和SoapClientFormatterSinkProvider(为客户端格式化程序接收器提供程序提供实现)。
以Client端的Sink Provider实现为例:
Client Sink Provider实现IclientChannelSinkProvider接口,负责创建Client Sink。
public class LoggingClientChannelSinkProvider : IClientChannelSinkProvider
{
private IClientChannelSinkProvider _next = null;
public LoggingClientChannelSinkProvider()
{
}
public LoggingClientChannelSinkProvider(IDictionary properties, ICollection providerData)
{
}
public IClientChannelSink CreateSink(IChannelSender channel, String url,
Object remoteChannelData)
{
IClientChannelSink nextSink = null;
if (_next != null)
{
nextSink = _next.CreateSink(channel, url, remoteChannelData);
if (nextSink == null)
return null;
}
// Create a new LoggingClientChannelSink class instance, passing the next sink in the sink chain as a parameter to the constructor. That enables the LoggingClientChannelSink class to perform its processing and the pass the message data onto the client’s transport sink.
return new LoggingClientChannelSink(nextSink);
}
public IClientChannelSinkProvider Next
{
get { return _next; }
set { _next = value; }
}
} // class LoggingClientChannelSinkProvider
其中Next属性用来获取或设置信道接收器提供程序(Channel Sink Provider)链中的下一个接收器提供程序。
CreateSink()方法用来创建接收器链(Sink Chain),当调用 CreateSink 方法时,它创建自己的信道接收器,将 CreateSink 调用转发给链中的下一个接收器提供程序(如果有),并确保下一个接收器和当前的接收器链接在一起。
3,设置Client/Server端配置文件
为了使用Client/Server Sink Provider,必须在configuration file中进行设置。<clientProviders>和<serverProviders>元素向.Net Remoting Framework提供了加载Channel Sink Provider所必需的类型信息。
这样,当Client/Server application在注册Channel时,读取Configuration file中provider配置信息,并创建Custom Sink,这里为Logging Sink。
(1)Client端配置文件
<channels>
<channel ref="http">
<clientProviders>
<formatter ref="soap" />
<provider type="Logging.LoggingClientChannelSinkProvider, LoggingSink" />
</clientProviders>
</channel>
</channels>
Client端通过RemotingConfiguration.Configure("client.exe.config")装载configuration文件后,Client端的Sink Chain为:
SoapClientFormatterSink –Nextà
LoggingSink –Nextà
HttpClientTransportSink
最后的HttpClientTransportSink缺省由HTTP Channel来实例化。
(2)Server端配置文件
<serverProviders>
<provider ref="wsdl" />
<formatter ref="soap" />
<provider type="Logging.LoggingServerChannelSinkProvider, LoggingSink" />
</serverProviders>
如果在Server端的Configruation File中指定了<serverProviders>元素,而没有显式在<serverProviders>之中SdlChannelSinkProvider,也是没有<provider ref="wsdl" />这一行,wsdl在machine.config配置文件中有定义,就无法通过URL加上“?WSDL”参数来产生WSDL描述,验证Remote Objects部署成功与否。因此,建议在Server configuration file中添加这一行。
根据上面的configuration file,server端的Sink Chain为:
HttpServerTransportSink – next à
SdlChannelSink – next à
SoapSeverFormatterSink – next à
LoggingSink – next à
BinaryServerFormatterSink – next à
DispatchChannelSink
******
Please note that source code is unavailable now. Sorry about that.
请注意:本文不再提供source code.
Reference:
1, MSDN, ChannelSink, ChannelSinkProvider
2, Ingo Rammer, Advanced .Net Remoting-C# Edition
3, Randy Holloway, How to build customer Sink Provider for .Net Remoting, http://www.devx.com/dotnet/Article/16273/1954?pf=true