internal virtual IMessage InternalInvoke(
IMethodCallMessage reqMcmMsg, bool useDispatchMessage, int callType)
{
Message reqMsg = reqMcmMsg as Message;
if ((reqMsg == null) && (callType != Message.Sync))
{
// Only the synchronous call type is supported for messages that
// aren't of type Message.
throw new RemotingException(
Environment.GetResourceString("Remoting_Proxy_InvalidCallType"));
}
IMessage retMsg = null;
Thread currentThread = Thread.CurrentThread;
// pick up call context from the thread
LogicalCallContext cctx = currentThread.GetLogicalCallContext();
Identity idObj = IdentityObject;
ServerIdentity serverID = idObj as ServerIdentity;
if ((null != serverID) && idObj.IsFullyDisconnected())
{
throw new ArgumentException(
String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_ServerObjectNotFound"), reqMcmMsg.Uri));
}
// Short-circuit calls to Object::GetType and Object::GetHashCode
MethodBase mb = reqMcmMsg.MethodBase;
if(_getTypeMethod == mb)
{
// Time to load the true type of the remote object....
Type t = GetProxiedType();
return new ReturnMessage(t, null, 0, cctx, reqMcmMsg);
}
if (_getHashCodeMethod == mb)
{
int hashCode = idObj.GetHashCode();
return new ReturnMessage(hashCode, null, 0, cctx, reqMcmMsg);
}
// check for channel sink
if (idObj.ChannelSink == null)
{
IMessageSink chnlSink = null;
IMessageSink envoySink = null;
// If channelSink is null try to Create them again
// the objref should be correctly fixed up at this point
if(!idObj.ObjectRef.IsObjRefLite())
{
RemotingServices.CreateEnvoyAndChannelSinks(null, idObj.ObjectRef, out chnlSink, out envoySink);
}
else
{
RemotingServices.CreateEnvoyAndChannelSinks(idObj.ObjURI, null, out chnlSink, out envoySink);
}
// Set the envoy and channel sinks in a thread safe manner
RemotingServices.SetEnvoyAndChannelSinks(idObj, chnlSink, envoySink);
// If the channel sink is still null then throw
if(idObj.ChannelSink == null)
{
throw new RemotingException(
Environment.GetResourceString("Remoting_Proxy_NoChannelSink"));
}
}
// Set the identity in the message object
IInternalMessage iim = (IInternalMessage)reqMcmMsg;
iim.IdentityObject = idObj;
if (null != serverID)
{
Message.DebugOut("Setting serveridentity on message \n");
iim.ServerIdentityObject = serverID;
}
else
{
// We need to set the URI only for identities that
// are not the server identities. The uri is used to
// dispatch methods for objects outside the appdomain.
// Inside the appdomain (xcontext case) we dispatch
// by getting the server object from the server identity.
iim.SetURI(idObj.URI);
}
Message.DebugOut("InternalInvoke. Dispatching based on class type\n");
AsyncResult ar = null;
switch (callType)
{
case Message.Sync:
Message.DebugOut("RemotingProxy.Invoke Call: SyncProcessMsg\n");
BCLDebug.Assert(!useDispatchMessage,"!useDispatchMessage");
bool bSkipContextChain = false;
Context currentContext = currentThread.GetCurrentContextInternal();
IMessageSink nextSink = idObj.EnvoyChain;
// if we are in the default context, there can be no
// client context chain, so we can skip the intermediate
// calls if there are no envoy sinks
if (currentContext.IsDefaultContext)
{
if (nextSink is EnvoyTerminatorSink)
{
bSkipContextChain = true;
// jump directly to the channel sink
nextSink = idObj.ChannelSink;
}
}
retMsg = CallProcessMessage(nextSink,
reqMcmMsg,
idObj.ProxySideDynamicSinks,
currentThread,
currentContext,
bSkipContextChain);
break;
case Message.BeginAsync:
case Message.BeginAsync | Message.OneWay:
// For async calls we clone the call context from the thread
// This is a limited clone (we dont deep copy the user data)
cctx = (LogicalCallContext) cctx.Clone();
iim.SetCallContext(cctx);
ar = new AsyncResult(reqMsg);
InternalInvokeAsync(ar, reqMsg, useDispatchMessage, callType);
Message.DebugOut("Propagate out params for BeginAsync\n");
retMsg = new ReturnMessage(ar, null, 0, null/*cctx*/, reqMsg);
break;
case Message.OneWay:
// For async calls we clone the call context from the thread
// This is a limited clone (we dont deep copy the user data)
cctx = (LogicalCallContext) cctx.Clone();
iim.SetCallContext(cctx);
InternalInvokeAsync(null, reqMsg, useDispatchMessage, callType);
retMsg = new ReturnMessage(null, null, 0, null/*cctx*/, reqMcmMsg);
break;
case (Message.EndAsync | Message.OneWay):
retMsg = new ReturnMessage(null, null, 0, null/*cctx*/, reqMcmMsg);
break;
case Message.EndAsync:
// For endAsync, we merge back the returned callContext
// into the thread's callContext
retMsg = RealProxy.EndInvokeHelper(reqMsg, true);
break;
}
return retMsg;
}