Code:
/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / clr / src / BCL / System / Runtime / Remoting / remotingproxy.cs / 1 / remotingproxy.cs
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** File: RemotingProxy.cs
**
**
** Purpose: Defines the general purpose remoting proxy
**
**
===========================================================*/
namespace System.Runtime.Remoting.Proxies {
using System.Threading;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Channels;
using System;
using MethodInfo = System.Reflection.MethodInfo;
using MethodBase = System.Reflection.MethodBase;
using System.Globalization;
// Remoting proxy
internal class RemotingProxy : RealProxy, IRemotingTypeInfo
{
// Static Fields
private static MethodInfo _getTypeMethod = typeof(System.Object).GetMethod("GetType");
private static MethodInfo _getHashCodeMethod = typeof(System.Object).GetMethod("GetHashCode");
private static Type s_typeofObject = typeof(System.Object);
private static Type s_typeofMarshalByRefObject = typeof(System.MarshalByRefObject);
//*******************WARNING******************************************
// If you change the names of these fields then change the corresponding
// names in remoting.cpp
//*******************************************************************
private ConstructorCallMessage _ccm;
private int _ctorThread;
// Constructor
public RemotingProxy(Type serverType)
: base(serverType)
{
}
private RemotingProxy()
{
// Prevent anyone from creating a blank instance of a proxy
// without the underlying server type
}
internal int CtorThread
{
get
{
return _ctorThread;
}
set
{
//NOTE : the assert below is correct for activated objects.
//But for a connected object (where new XXX() does a Connect()
//the InternalActivate codepath may execute twice .. since
//we would be returning the same proxy for multiple calls to
//new XXX() & JIT would try to execute the default .ctor on
//the returned proxy.
//BCLDebug.Assert(_ctorThread == 0, "ctorThread already set??");
_ctorThread = value;
}
}
// This is used when a TP is called with SyncProcessMessage
internal static IMessage CallProcessMessage(IMessageSink ms,
IMessage reqMsg,
ArrayWithSize proxySinks,
Thread currentThread,
Context currentContext,
bool bSkippingContextChain)
{
// Notify Dynamic Sinks: CALL starting
if (proxySinks != null)
{
DynamicPropertyHolder.NotifyDynamicSinks(
reqMsg,
proxySinks,
true, // bCliSide
true, // bStart
false); // bAsync
}
bool bHasDynamicSinks = false;
if (bSkippingContextChain)
{
// this would have been done in the client context terminator sink
bHasDynamicSinks =
currentContext.NotifyDynamicSinks(reqMsg,
true, // bCliSide
true, // bStart
false, // bAsync
true); // bNotifyGlobals
ChannelServices.NotifyProfiler(reqMsg, RemotingProfilerEvent.ClientSend);
}
if (ms == null)
{
throw new RemotingException(
Environment.GetResourceString(
"Remoting_Proxy_NoChannelSink"));
}
IMessage retMsg = ms.SyncProcessMessage(reqMsg);
if (bSkippingContextChain)
{
// this would have been done in the client context terminator sink
ChannelServices.NotifyProfiler(retMsg, RemotingProfilerEvent.ClientReceive);
if (bHasDynamicSinks)
{
currentContext.NotifyDynamicSinks(
retMsg,
true, // bCliSide
false, // bStart
false, // bAsync
true); // bNotifyGlobals
}
}
IMethodReturnMessage mrm = retMsg as IMethodReturnMessage;
if (retMsg == null || mrm == null)
{
throw new RemotingException(
Environment.GetResourceString("Remoting_Message_BadType"));
}
// notify DynamicSinks: CALL returned
if (proxySinks != null)
{
DynamicPropertyHolder.NotifyDynamicSinks(
retMsg,
proxySinks,
true, // bCliSide
false, // bStart
false); // bAsync
}
return retMsg;
}
// Implement Invoke
public override IMessage Invoke(IMessage reqMsg)
{
// Dispatch based on whether its a constructor call
// or a method call
IConstructionCallMessage ccm = reqMsg as IConstructionCallMessage;
if(ccm != null)
{
// Activate
return InternalActivate(ccm);
}
else
{
// Handle regular method calls
// Check that the initialization has completed
if(!Initialized)
{
// This covers the case where an object may call out
// on another object passing its "this" pointer during its
// .ctor.
// The other object attempting to call on the this pointer
// (in x-context case) would be calling on a proxy not
// marked fully initialized.
// <
// Let the original constructor thread go through but
// throw for other threads.
if (CtorThread == Thread.CurrentThread.GetHashCode())
{
ServerIdentity srvId = IdentityObject as ServerIdentity;
BCLDebug.Assert(
srvId != null
&&
((ServerIdentity)IdentityObject).ServerContext != null,
"Wrap may associate with wrong context!");
// If we are here, the server object passed itself
// out to another x-context object during the .ctor
// That guy is calling us back. Let us call Wrap()
// earlier than usual so that envoy & channel sinks
// get set up!
// <
RemotingServices.Wrap(
(ContextBoundObject) this.UnwrappedServerObject);
}
else
{
// Throw an exception to indicate that we are
// calling on a proxy while the constructor call
// is still running.
throw new RemotingException(Environment.GetResourceString("Remoting_Proxy_InvalidCall"));
}
}
// Dispatch
int callType = Message.Sync;
Message msg = reqMsg as Message;
if (msg != null)
{
callType = msg.GetCallType();
}
return InternalInvoke((IMethodCallMessage)reqMsg, false, callType);
}
} // Invoke
// This is called for all remoted calls on a TP except Ctors
// The method called may be Sync, Async or OneWay(special case of Async)
// In the Async case we come here for both BeginInvoke & EndInvoke
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;
}
// This is called from InternalInvoke above when someone makes an
// Async (or a one way) call on a TP
internal void InternalInvokeAsync(IMessageSink ar, Message reqMsg,
bool useDispatchMessage, int callType)
{
IMessageCtrl cc = null;
Identity idObj = IdentityObject;
ServerIdentity serverID = idObj as ServerIdentity;
MethodCall cpyMsg= new MethodCall(reqMsg);
IInternalMessage iim = ((IInternalMessage)cpyMsg);
// Set the identity in the message object
iim.IdentityObject = idObj;
if (null != serverID)
{
Message.DebugOut("Setting SrvID on deser msg\n");
iim.ServerIdentityObject = serverID;
}
if (useDispatchMessage)
{
Message.DebugOut(
"RemotingProxy.Invoke: Calling AsyncDispatchMessage\n");
BCLDebug.Assert(ar != null,"ar != null");
BCLDebug.Assert( (callType & Message.BeginAsync) != 0,
"BeginAsync flag not set!");
Message.DebugOut("Calling AsynDispatchMessage \n");
cc = ChannelServices.AsyncDispatchMessage(
cpyMsg,
((callType & Message.OneWay) != 0)
? null : ar);
}
else if (null != idObj.EnvoyChain)
{
Message.DebugOut("RemotingProxy.Invoke: Calling AsyncProcessMsg on the envoy chain\n");
cc = idObj.EnvoyChain.AsyncProcessMessage(
cpyMsg,
((callType & Message.OneWay) != 0)
? null : ar);
}
else
{
// Channel sink cannot be null since it is the last sink in
// the client context
// Assert if Invoke is called without a channel sink
BCLDebug.Assert(false, "How did we get here?");
throw new ExecutionEngineException(
Environment.GetResourceString("Remoting_Proxy_InvalidState"));
}
if ((callType & Message.BeginAsync) != 0)
{
if ((callType & Message.OneWay) != 0)
{
ar.SyncProcessMessage(null);
}
}
}
// New method for activators.
// This gets called during remoting intercepted activation when
// JIT tries to run a constructor on a TP (which remoting gave it
// in place of an actual uninitialized instance of the expected type)
private IConstructionReturnMessage InternalActivate(IConstructionCallMessage ctorMsg)
{
// Remember the hashcode of the constructor thread.
CtorThread = Thread.CurrentThread.GetHashCode();
IConstructionReturnMessage ctorRetMsg = ActivationServices.Activate(this, ctorMsg);
// Set the flag to indicate that the object is initialized
// Note: this assert is not valid for WKOs
//BCLDebug.Assert(!Initialized, "Proxy marked as initialized before activation call completed");
Initialized = true;
return ctorRetMsg;
}
// Invoke for case where call is in the same context as the server object
// (This special static method is used for AsyncDelegate-s ... this is called
// directly from the EE)
private static void Invoke(Object NotUsed, ref MessageData msgData)
{
Message m = new Message();
m.InitFields(msgData);
Object thisPtr = m.GetThisPtr();
Delegate d;
if ((d = thisPtr as Delegate) != null)
{
// <
RemotingProxy rp = (RemotingProxy)
RemotingServices.GetRealProxy(d.Target);
if (rp != null)
{
rp.InternalInvoke(m, true, m.GetCallType());
}
else
{
int callType = m.GetCallType();
AsyncResult ar;
switch (callType)
{
case Message.BeginAsync:
case Message.BeginAsync | Message.OneWay:
// pick up call context from the thread
m.Properties[Message.CallContextKey] =
CallContext.GetLogicalCallContext().Clone();
ar = new AsyncResult(m);
AgileAsyncWorkerItem workItem =
new AgileAsyncWorkerItem(
m,
((callType & Message.OneWay) != 0) ?
null : ar, d.Target);
ThreadPool.QueueUserWorkItem(
new WaitCallback(
AgileAsyncWorkerItem.ThreadPoolCallBack),
workItem);
if ((callType & Message.OneWay) != 0)
{
ar.SyncProcessMessage(null);
}
m.PropagateOutParameters(null, ar);
break;
case (Message.EndAsync | Message.OneWay):
return;
case Message.EndAsync:
// This will also merge back the call context
// onto the thread that called EndAsync
RealProxy.EndInvokeHelper(m, false);
break;
default:
BCLDebug.Assert(
false,
"Should never be here. Sync delegate code for agile object ended up in remoting");
break;
}
}
}
else
{
// Static invoke called with incorrect this pointer ...
throw new RemotingException(
Environment.GetResourceString(
"Remoting_Default"));
}
}
internal ConstructorCallMessage ConstructorMessage
{
get
{
return _ccm;
}
set
{
_ccm = value;
}
}
//
// IRemotingTypeInfo interface
//
// Obtain the fully qualified name of the type that the proxy represents
public String TypeName
{
get
{
return GetProxiedType().FullName;
}
set
{
throw new NotSupportedException();
}
}
#if FEATURE_COMINTEROP
// interop methods
public override IntPtr GetCOMIUnknown(bool fIsBeingMarshalled)
{
IntPtr pUnk = IntPtr.Zero;
Object otp = GetTransparentProxy();
bool fIsXProcess = RemotingServices.IsObjectOutOfProcess(otp);
if (fIsXProcess)
{
// we are in a different process
if (fIsBeingMarshalled)
{
// we need to go to the server to get the real IUnknown
pUnk = MarshalByRefObject.GetComIUnknown((MarshalByRefObject)otp);
}
else
{
// create an IUnknown here
pUnk = MarshalByRefObject.GetComIUnknown((MarshalByRefObject)otp);
}
}
else
{
bool fIsXAppDomain = RemotingServices.IsObjectOutOfAppDomain(otp);
// we are in the same proces, ask the object for its IUnknown
if (fIsXAppDomain)
{
// do an appdomain switch
pUnk = ((MarshalByRefObject)otp).GetComIUnknown(fIsBeingMarshalled);
}
else
{
// otherwise go ahead and create a CCW here
pUnk = MarshalByRefObject.GetComIUnknown((MarshalByRefObject)otp);
}
}
return pUnk;
}
public override void SetCOMIUnknown(IntPtr i)
{
// for now ignore this
}
#endif // FEATURE_COMINTEROP
// Check whether we can cast the transparent proxy to the given type
public bool CanCastTo(Type castType, Object o)
{
bool fCastOK = false;
// The identity should be non-null
BCLDebug.Assert(null != IdentityObject,"null != IdentityObject");
Message.DebugOut("CheckCast for identity " + IdentityObject.GetType());
if ((castType == s_typeofObject) ||
(castType == s_typeofMarshalByRefObject))
{
return true;
}
// Get the objref of the proxy
ObjRef oRef = IdentityObject.ObjectRef;
// If the object ref is non-null then check against the type info
// stored in the it
if (null != oRef)
{
Object oTP = GetTransparentProxy();
// Check that there is a matching type in the server object
// hierarchy represented in the objref
Message.DebugOut("Calling CanCastTo for type " + castType);
IRemotingTypeInfo typeInfo = oRef.TypeInfo;
if(null != typeInfo)
{
fCastOK = typeInfo.CanCastTo(castType, oTP);
if (!fCastOK && typeInfo.GetType()==typeof(TypeInfo) && oRef.IsWellKnown() )
{
fCastOK = CanCastToWK(castType);
}
}
else
{
if (oRef.IsObjRefLite())
{
// we should do a dynamic cast across the network
fCastOK = MarshalByRefObject.CanCastToXmlTypeHelper(castType, (MarshalByRefObject)o);
}
}
}
// This is a well known object which does not have a backing ObjRef
else
{
fCastOK = CanCastToWK(castType);
}
return fCastOK;
}
// WellKnown proxies we always allow casts to interfaces, and allow
// casting down a single branch in the type hierarchy (both are on good
// faith. The calls are failed on server side if a bogus cast is done)
bool CanCastToWK(Type castType)
{
Message.DebugOut( "CheckCast for well known objects and type " + castType);
bool fCastOK = false;
// Check whether the type to which we want to cast is
// compatible with the current type
if(castType.IsClass)
{
fCastOK = GetProxiedType().IsAssignableFrom(castType);
}
else
{
// NOTE: we are coming here also for x-context proxies
// when unmanaged code cannot determine if the cast is not
// okay <
if (!(IdentityObject is ServerIdentity))
{
BCLDebug.Assert(
IdentityObject.URI != null,
"Bad WellKnown ID");
// Always allow interface casts to succeed. If the
// interface is not supported by the well known object
// then we will throw an exception when the interface
// is invoked.
fCastOK = true;
}
}
return fCastOK;
}
}
internal class AgileAsyncWorkerItem
{
private IMethodCallMessage _message;
private AsyncResult _ar;
private Object _target;
public AgileAsyncWorkerItem(IMethodCallMessage message, AsyncResult ar, Object target)
{
_message = new MethodCall(message);
_ar = ar;
_target = target;
}
public static void ThreadPoolCallBack(Object o)
{
((AgileAsyncWorkerItem) o).DoAsyncCall();
}
public void DoAsyncCall()
{
(new StackBuilderSink(_target)).AsyncProcessMessage(_message, _ar);
}
}
}
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- TextViewBase.cs
- Baml2006KnownTypes.cs
- DataTableNewRowEvent.cs
- TextInfo.cs
- ItemChangedEventArgs.cs
- ColumnHeaderConverter.cs
- KnownBoxes.cs
- Vector3DAnimation.cs
- SqlWorkflowPersistenceService.cs
- XmlUnspecifiedAttribute.cs
- DiscoveryVersion.cs
- DocumentViewerConstants.cs
- RegexStringValidatorAttribute.cs
- ServiceEndpointCollection.cs
- CompModSwitches.cs
- CrossContextChannel.cs
- ProfileService.cs
- _Connection.cs
- PageAsyncTaskManager.cs
- x509store.cs
- WebDisplayNameAttribute.cs
- FontFamily.cs
- ExpressionNode.cs
- RelationshipManager.cs
- FormParameter.cs
- LogEntrySerializer.cs
- Validator.cs
- Rule.cs
- SessionStateContainer.cs
- XmlSchemaInferenceException.cs
- AnonymousIdentificationSection.cs
- WindowsAltTab.cs
- CoTaskMemSafeHandle.cs
- ContextMenuAutomationPeer.cs
- EventRoute.cs
- EmptyEnumerator.cs
- WebCategoryAttribute.cs
- SendMessageRecord.cs
- XmlSchemaCollection.cs
- WorkflowCreationContext.cs
- DataServiceRequestException.cs
- MessageFilterException.cs
- DataGridViewRowPrePaintEventArgs.cs
- CustomTypeDescriptor.cs
- TextFormatter.cs
- Automation.cs
- ReferenceCountedObject.cs
- MemberNameValidator.cs
- LazyTextWriterCreator.cs
- WebConfigurationHost.cs
- DelegatingMessage.cs
- serverconfig.cs
- RemoteDebugger.cs
- HttpMethodAttribute.cs
- FrameAutomationPeer.cs
- Attributes.cs
- LocalBuilder.cs
- ReachPageContentSerializerAsync.cs
- DependencyPropertyConverter.cs
- SizeFConverter.cs
- FocusChangedEventArgs.cs
- LineVisual.cs
- LinkConverter.cs
- TrustLevelCollection.cs
- DataBindingExpressionBuilder.cs
- ISSmlParser.cs
- FormatVersion.cs
- documentation.cs
- CheckBoxBaseAdapter.cs
- TextEvent.cs
- HScrollBar.cs
- ManagedWndProcTracker.cs
- ContentDesigner.cs
- CheckBoxBaseAdapter.cs
- CodeGroup.cs
- PropertyNames.cs
- XhtmlBasicPageAdapter.cs
- PartialList.cs
- FixUp.cs
- TargetConverter.cs
- WebScriptMetadataMessageEncoderFactory.cs
- VerticalConnector.xaml.cs
- InvokeProviderWrapper.cs
- SQLBinaryStorage.cs
- RegexCaptureCollection.cs
- XmlDataSourceView.cs
- SimpleRecyclingCache.cs
- BitmapEditor.cs
- ClientProtocol.cs
- DataPagerCommandEventArgs.cs
- ConfigUtil.cs
- PackageDigitalSignature.cs
- FontFamily.cs
- SamlAuthorizationDecisionStatement.cs
- JsonFormatReaderGenerator.cs
- xmlglyphRunInfo.cs
- WebReference.cs
- AnnotationService.cs
- TreeNode.cs
- _TransmitFileOverlappedAsyncResult.cs