internal IMessageSink GetServerObjectChain(out MarshalByRefObject obj)
{
obj = null;
// NOTE: Lifetime relies on the Identity flags for
// SingleCall and Singleton being set by the time this getter
// is called.
if (!this.IsSingleCall())
{
// This is the common case
if (_serverObjectChain == null)
{
bool fLocked = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
Monitor.ReliableEnter(this, ref fLocked);
if(_serverObjectChain == null)
{
MarshalByRefObject srvObj =
(MarshalByRefObject)
this.TPOrObject;
_serverObjectChain =
_srvCtx.CreateServerObjectChain(
srvObj);
}
}
finally
{
if (fLocked)
{
Monitor.Exit(this);
}
}
}
BCLDebug.Assert( null != _serverObjectChain,
"null != _serverObjectChain");
return _serverObjectChain;
}
else
{
// ---------- SINGLE CALL WKO --------------
// In this case, we are expected to provide
// a fresh server object for each dispatch.
// Since the server object chain is object
// specific, we must create a fresh chain too.
// We must be in the correct context for this
// to succeed.
BCLDebug.Assert(Thread.CurrentContext==_srvCtx,
"Bad context mismatch");
MarshalByRefObject srvObj = null;
IMessageSink objChain = null;
if (_tpOrObject != null && _firstCallDispatched == 0 && Interlocked.CompareExchange(ref _firstCallDispatched, 1, 0) == 0)
{
// use the instance of server object created to
// set up the pipeline.
srvObj = (MarshalByRefObject) _tpOrObject;
objChain = _serverObjectChain;
if (objChain == null)
{
objChain = _srvCtx.CreateServerObjectChain(srvObj);
}
}
else
{
// For singleCall we create a fresh object & its chain
// on each dispatch!
srvObj = (MarshalByRefObject)
Activator.CreateInstance((Type)_srvType, true);
// make sure that object didn't Marshal itself.
// (well known objects should live up to their promise
// of exporting themselves through exactly one url)
String tempUri = RemotingServices.GetObjectUri(srvObj);
if (tempUri != null)
{
throw new RemotingException(
String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString(
"Remoting_WellKnown_CtorCantMarshal"),
this.URI));
}
// Set the identity depending on whether we have the server
// or proxy
if(!RemotingServices.IsTransparentProxy(srvObj))
{
#if _DEBUG
Identity idObj = srvObj.__RaceSetServerIdentity(this);
#else
srvObj.__RaceSetServerIdentity(this);
#endif
#if _DEBUG
BCLDebug.Assert(idObj == this, "Bad ID state!" );
BCLDebug.Assert(idObj == MarshalByRefObject.GetIdentity(srvObj), "Bad ID state!" );
#endif
}
else
{
RealProxy rp = null;
rp = RemotingServices.GetRealProxy(srvObj);
BCLDebug.Assert(null != rp, "null != rp");
// #if _DEBUG
// Identity idObj = (ServerIdentity) rp.SetIdentity(this);
// #else
rp.IdentityObject = this;
// #endif
}
// Create the object chain and return it
objChain = _srvCtx.CreateServerObjectChain(srvObj);
}
// This is passed out to the caller so that for single-call
// case we can call Dispose when the incoming call is done
obj = srvObj;
return objChain;
}
}