remotingproxy.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / Runtime / Remoting / remotingproxy.cs / 1305376 / 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 
    [System.Security.SecurityCritical]  // auto-generated 
    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 RuntimeType s_typeofObject = (RuntimeType)typeof(System.Object);
        private static RuntimeType s_typeofMarshalByRefObject = (RuntimeType)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
        [System.Security.SecurityCritical]
        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.[....];
                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 [....], 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.[....])) 
            {
                // 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( 
                   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.[....]: 
                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 InvalidOperationException( 
                    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. [....] 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
        { 
            [System.Security.SecurityCritical]
            get
            {
                return GetProxiedType().FullName; 
            }
 
            [System.Security.SecurityCritical] 
            set
            { 
                throw new NotSupportedException();
            }
        }
 
#if FEATURE_COMINTEROP
        // interop methods 
        [System.Security.SecurityCritical] 
        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; 
        }
 
        [System.Security.SecurityCritical]
        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
        [System.Security.SecurityCritical] 
        public bool CanCastTo(Type castType, Object o)
        {
            if (castType == null)
                throw new ArgumentNullException("castType"); 

            RuntimeType rtType = castType as RuntimeType; 
            if (rtType == null) 
                throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"));
 
            bool fCastOK = false;

            // The identity should be non-null
            BCLDebug.Assert(null != IdentityObject,"null != IdentityObject"); 

            Message.DebugOut("CheckCast for identity " + IdentityObject.GetType()); 
 
            if ((rtType == s_typeofObject) ||
                (rtType == 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 " + rtType); 
                IRemotingTypeInfo typeInfo = oRef.TypeInfo;
                if(null != typeInfo) 
                {
                    fCastOK = typeInfo.CanCastTo(rtType, oTP);
                    if (!fCastOK && typeInfo.GetType()==typeof(TypeInfo) && oRef.IsWellKnown() )
                    { 
                        fCastOK = CanCastToWK(rtType);
                    } 
                } 
                else
                { 
                    if (oRef.IsObjRefLite())
                    {
                        // we should do a dynamic cast across the network
                        fCastOK = MarshalByRefObject.CanCastToXmlTypeHelper(rtType, (MarshalByRefObject)o); 
                    }
                } 
            } 
            // This is a well known object which does not have a backing ObjRef
            else 
            {
                fCastOK = CanCastToWK(rtType);
            }
            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;

        [System.Security.SecurityCritical]  // auto-generated 
        public AgileAsyncWorkerItem(IMethodCallMessage message, AsyncResult ar, Object target)
        { 
            _message = new MethodCall(message); 
            _ar = ar;
            _target = target; 
        }

        [System.Security.SecurityCritical]  // auto-generated
        public static void ThreadPoolCallBack(Object o) 
        {
            ((AgileAsyncWorkerItem) o).DoAsyncCall(); 
        } 

 
        [System.Security.SecurityCritical]  // auto-generated
        public void DoAsyncCall()
        {
            (new StackBuilderSink(_target)).AsyncProcessMessage(_message, _ar); 
        }
    } 
 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK