扩展.NET remoting通道接收器的方法
扩展.NET remoting通道接收器的方法
1. 远程对象代理,消息接收器的概念
当客户端发起一个远程调用后,透明代理为该远程调用生成一个 IMessage 对象,并将它传给实际代理。之后,实际代理会查询特定远程对象相关的配置信息,再决定加载哪些消息接收器来处理该远程调用。代理把IMessage对象传给消息接收器来处理该远程调用。
实际代理至少需要加载两个消息接收器。
1. 格式转换接收器(binary和soap),负责将IMessage对象序列化为数据流,最终再由网络传送出去。
2. 传送接收器(http和tcp),负责把数据流输送到目的地或远程服务器。
PS透明对象和真实对象的关系
Activator.GetObject()和Activator.CreateInstance()返回给客户一个代理对象。实际上得到两个代理对象,透明代理和真实代理。透明代理像远程对象,它执行远程对象的所有公共方法,这些方法调用真实对象的Invoke()方法,传送包含方法调用的消息。
消息流动:
--call-->【透明对象】--IMessage-->【实际代理】--IMessage2-->【消息接收器】(在一个调用中,编码>>自定义前期操作>>传送到远端>>收到应答>>自定操作后续操作>>解码)
参与对象:
RealProxy,IMessage,IClientChannelSink
2. 消息接收器实现
类1. 实现 IClientChannelSinkProvider 接口,为远程处理消息从其流过的客户端信道创建客户端信道接收器。
类2.
继承 BaseChannelSinkWithProperties,提供希望向其属性公开字典接口的信道接收器的基实现。
实现 IClientChannelSink 接口,为客户端信道接收器提供所需的函数和属性。同步调用,消息是通过其ProcessMessage()接口中流动(调用流动:被调用,做完前期工作,然后调用下一个槽位;返回流:下一个槽位对象的ProcessMessage方法调用返回后,当前槽对象继续做后续工作然后返回,让栈中的下一位继续处理。最终在对象中来回流动一次把结果返回给代理)。
Channel:信道/通道
Sink:接收器
BaseChannelSinkWithProperties
BaseChannelWithProperties
BaseChannelSinkWithProperties/BaseChannelWithProperties --> BaseChannelObjectWithProperties --> IDictionary
BaseChannelObjectWithProperties 是 BaseChannelWithProperties 和 BaseChannelSinkWithProperties 的基类。
BaseChannelWithProperties 和 BaseChannelSinkWithProperties 可用作提供已命名属性的信道和信道接收器的基类。
BaseChannelObjectWithProperties 处理向信道对象请求其属性的复杂任务。
其中BaseChannelWithProperties对properties作了重写,以遍律服务端或客户端的所有信道接收器.
IChannelSinkBase
IChannelSinkBase:为信道接收器提供基接口.提供IDictionary Properties属性, 获取可以通过其访问接收器的属性的字典.
IClientChannelSink
IClientChannelSink --> IChannelSinkBase:为客户端信道接收器提供所需的函数和属性.
信道接收器提供插件点,该插件点允许访问流过该信道的基础消息,还允许访问传输机制用来将消息发送到远程对象的流。信道接收器在信道接收器提供程序链中链接在一起,在消息被序列化并传输之前,所有信道消息都流过该接收器链。
IServerChannelSink
IServerChannelSink --> IChannelSinkBase:提供用于安全和传输接收器的方法.
信道接收器提供插件点,该插件点允许访问流过该信道的基础消息,还允许访问传输机制用来将消息发送到远程对象的流。信道接收器在信道接收器提供程序链中链接在一起,并且所有信道消息在被序列化和传输之前都要流过此接收器链。
IChannel
IChannel:为跨远程处理边界的消息提供管道。
远程处理边界可以是 Context、AppDomain、进程或计算机。应用程序只能使用信道来跨越这些边界。这些交叉可以是入站和出站的。信道可以在终结点上侦听入站消息,向终结点发送出站消息,或同时进行这两种操作。这在运行库中提供一个可扩展性点,以便插入各种协议,即使运行库可能并不在信道的另一端。
运行库对象可用于表示广泛丰富的语义和实体集。信道提供可扩展性点以将消息在特定协议间来回转换。如果信道的两端都有运行库,则将在两个端点之间建立一个虚拟信道,以连接边界两侧的客户端和服务器接收器链。
信道的客户端部分位于客户端上下文接收器链的末尾。信道的服务器部分位于服务器上下文接收器链的起点。使用 IMessageSink 接口将消息传送到客户端信道,消息通过该信道,然后被服务器信道接收。服务器信道将消息传送到第一个服务器上下文接收器。
信道必须公开 IChannel 接口,该接口提供信息性的属性,例如 ChannelName 和 ChannelPriority 属性。可以使用 ChannelServices.RegisterChannel 方法注册信道。
IChannelSender
IChannelSender --> IChannel:为发送方信道提供所需的函数和属性。
IChannelReceiver
IChannelReceiver --> IChannel:为接收器信道提供所需的函数和属性。
IClientChannelSinkProvider
IClientChannelSinkProvider:为远程处理消息从其流过的客户端信道创建客户端信道接收器。
信道接收器通过 IClientChannelSinkProvider 接口的实现连接到客户端信道。所有远程处理客户端信道均提供以 IClientChannelSinkProvider 为参数的构造函数。
信道接收器提供程序存储在一个链中,在向信道构造函数传递外部信道接收器提供程序之前,用户负责将所有的信道接收器提供程序链接在一起。为此,IClientChannelSinkProvider 提供了名为 Next 的属性。
在一个配置文件中指定了多个信道接收器提供程序后,远程处理基础结构将这些提供程序按它们在配置文件中的顺序链接起来。在 RemotingConfiguration.onfigure 调用过程中创建信道时,将创建信道接收器提供程序。
IServerChannelSinkProvider
IServerChannelSinkProvider:为远程处理消息从其流过的服务器信道创建服务器信道接收器。
信道接收器通过 IServerChannelSinkProvider 接口的实现连接到服务器信道。所有远程处理服务器信道均提供以 IServerChannelSinkProvider 为参数的构造函数。
信道接收器提供程序存储在一个链中,在向信道构造函数传递外部信道接收器提供程序之前,用户负责将所有的信道接收器提供程序链接在一起。为此,IServerChannelSinkProvider 提供了名为 Next 的属性。
在一个配置文件中指定了多个信道接收器提供程序后,远程处理基础结构将这些提供程序按它们在配置文件中的顺序链接起来。在 RemotingConfiguration.Configure 调用的过程中,信道接收器提供程序和信道同时创建。
在生成 IMethodCallMessage 之后,.NET Framework 搜索注册信道的列表以查找一个可以处理该调用的信道。一旦找到适当的信道之后,便从该信道检索信道接收器,并将 IMethodCallMessage 转发到接收器以进行处理。
usingSystem.Runtime.Remoting;
usingSystem.Runtime.Remoting.Channels;
usingSystem.Runtime.Remoting.Messaging;
usingSystem.IO;
usingSAF.Configuration;
usingSystem.Configuration;
usingSystem.Collections;
usingSystem.Threading;
namespaceSAF.Cryptography
{
///<summary>
///CryptoRemotingServerSinkrepresentstheremotingsinkontheserver.
///Itenablesthesecuredatatransmittedvia.NETremoting
///</summary>
publicclassCryptoRemotingServerSink:BaseChannelSinkWithProperties,IServerChannelSink
{
privateIServerChannelSinknext;
privatestaticConfigurationManagercm=(ConfigurationManager)ConfigurationSettings.GetConfig("Framework");
privatestaticCryptographyConfigurationcc=cm.CryptographyConfig;
privateCryptoRemotingSinkHelperhelper=newCryptoRemotingSinkHelper();
privateconststringsinkType="ServerSink";
publicCryptoRemotingServerSink()
{
}
///<summary>
///ProcessMessagedecryptsthedatastreamandforwarditthetarget
///serverobjectandencryptsthereturnvalue
///</summary>
///<paramname="sinkStack">channelsinkobject</param>
///<paramname="requestMsg">IMessageobject</param>
///<paramname="transportHeaders">transportheaderobject</param>
///<paramname="targetStream">requreststream</param>
///<paramname="responseMsg">outputparameterscontainingresponsemessage</param>
///<paramname="responseHeaders">outputparametercontainingtheresponseheader</param>
///<paramname="responseStream">outputparametercontainingtheresponsestream</param>
///<returns></returns>
publicServerProcessingProcessMessage(
IServerChannelSinkStacksinkStack,IMessagerequestMsg,ITransportHeaderstransportHeaders,StreamtargetStream,
outIMessageresponseMsg,outITransportHeadersresponseHeaders,outStreamresponseStream)
{
//extracttheidentityinformationfromtheheader
stringidentity=transportHeaders["Identity"].ToString();
LocalDataStoreSlotdataSlot=null;
//createanthreaddataslot
dataSlot=Thread.GetNamedDataSlot("Identity");
//addtheidentityinformatiointothedataslotonthethreadsothat
//serverobjectcandeterminewhomadetherequest.
Thread.SetData(dataSlot,identity);
//Pushthisontothesinkstack
sinkStack.Push(this,null);
//decrypttherequeststream
StreamdecryptedStream=helper.DecryptStream(identity,sinkType,transportHeaders,targetStream);
ServerProcessingprocessingResult;
//passthedecryptedrequesttonextsinkofthechain
processingResult=next.ProcessMessage(
sinkStack,requestMsg,transportHeaders,decryptedStream,
outresponseMsg,outresponseHeaders,outresponseStream);
//encryptetheresponsestream.
StreamencryptedStream=helper.EncryptStream(identity,sinkType,responseHeaders,responseStream);
stringserverIdentity=cc.GetServerSinkIndentity();
responseHeaders["Identity"]=serverIdentity;
responseStream=encryptedStream;
returnprocessingResult;
}
publicvoidAsyncProcessResponse(
IServerResponseChannelSinkStacksinkStack,objectstate,IMessagemsg,ITransportHeadersheaders,Streamstream)
{
thrownewRemotingException("AsyncProcessRequestisnotenabledyet");
}
publicCryptoRemotingServerSink(IServerChannelSinknextSink)
{
next=nextSink;
}
publicStreamGetResponseStream(
IServerResponseChannelSinkStacksinkStack,objectstate,IMessagemsg,ITransportHeadersheaders)
{
//notimplemented,sinceonlyformattersinkneedtocallthismethod
returnnull;
}
publicIServerChannelSinkNextChannelSink
{
get{returnnext;}
}
}
///<summary>
///providerclassfortheserversinkclass
///</summary>
publicclassCryptoRemotingServerSinkProvider:IServerChannelSinkProvider
{
privateIServerChannelSinkProvidernext;
publicCryptoRemotingServerSinkProvider(IDictionaryproperties,ICollectionproviderData)
{
}
publicIServerChannelSinkProviderNext
{
get{returnnext;}
set{next=value;}
}
publicvoidGetChannelData(IChannelDataStorechannelData)
{
}
///<summary>
///factorymethodthatcreatetheconcretecorrespondingserversinkobject
///</summary>
///<paramname="channel">Thechannelforwhichtocreatethechannelsinkchain.</param>
///<returns>newlycreatedCryptoRemotingServerSinkobject</returns>
publicIServerChannelSinkCreateSink(IChannelReceiverchannel)
{
IServerChannelSinknextSink;
nextSink=next.CreateSink(channel);
returnnewCryptoRemotingServerSink(nextSink);
}
}
}
<system.runtime.remoting>
<application>
<client>
<wellknown
type="Test.BusinessLibrary.SampleBusiness,Test.BusinessLibrary"
url="http://localhost:4000/SampleBusiness.rem"
/>
</client>
<channels>
<channelref="http">
<clientProviders>
<formatterref="binary"/>