internal virtual IMessageSink GetClientContextChain()
{
Message.DebugOut("Context::GetClientContextChain: IN _ctxID =" + _ctxID + Environment.NewLine);
if (_clientContextChain == null)
{
Message.DebugOut("Context::GetClientContextChain: _clientContextChain == null, creating chain" + Environment.NewLine);
// a bare chain would have just this one sink.
IMessageSink newClientContextChain = ClientContextTerminatorSink.MessageSink;
// now loop over properties to add some real sinks.
// Note that for the client chain we go through the properties
// in the reverse order as compared to the server chain.
// Thus if a lock was taken as the last action of an incoming
// call, it is released as the first action of an outgoing call.
Object prop = null;
int iSink = 0;
while (iSink < _numCtxProps)
{
Message.DebugOut("Context::GetClientContextChain: checking property " +
_ctxProps[iSink].Name + Environment.NewLine);
// see if this property wants to contribute a ClientContextSink
// we have to start chaining in the reverse order
prop = _ctxProps[iSink];
IContributeClientContextSink sink = prop as IContributeClientContextSink;
if (null != sink)
{
Message.DebugOut("Context::GetClientContextChain: calling GetClientContextSink on " +
_ctxProps[iSink].Name + Environment.NewLine);
// yes, chain the sink ahead of the chain of sinks constructed so far.
newClientContextChain = sink.GetClientContextSink(newClientContextChain);
if (newClientContextChain == null)
{
throw new RemotingException(
Environment.GetResourceString(
"Remoting_Contexts_BadProperty"));
}
}
iSink++;
}
// now check if we raced and set appropriately
lock (this)
{
if (_clientContextChain==null)
{
_clientContextChain = newClientContextChain;
}
// else the chain we created should get GC-ed.
}
}
return _clientContextChain;
}