ActivationServices.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / clr / src / BCL / System / Runtime / Remoting / ActivationServices.cs / 1 / ActivationServices.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
**  File:    ActivationServices.cs 
**
**  Author(s): 
**
**  Purpose:
**
** 
===========================================================*/
namespace System.Runtime.Remoting.Activation { 
 
    using System;
    using System.Security; 
    using System.Threading;
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting;
    using System.Runtime.Remoting.Contexts; 
    using System.Runtime.Remoting.Proxies;
    using System.Runtime.Remoting.Messaging; 
    using System.Runtime.Remoting.Metadata; 
    using System.Collections;
    using System.Reflection; 
    using System.IO;
    using System.Runtime.Serialization;
    using System.Security.Permissions;
    using System.Globalization; 
    using System.Runtime.CompilerServices;
 
    // Implements various activation services 
    internal static class ActivationServices
    { 

        private static IActivator activator = null;

        private static Hashtable _proxyTable = new Hashtable(); 
        private static Type proxyAttributeType = typeof(System.Runtime.Remoting.Proxies.ProxyAttribute);
        private static ProxyAttribute _proxyAttribute = new ProxyAttribute(); 
        [ThreadStaticAttribute()] 
        internal static ActivationAttributeStack _attributeStack;
 
        internal const String ActivationServiceURI = "RemoteActivationService.rem";

        internal const String RemoteActivateKey = "Remote";
        internal const String PermissionKey = "Permission"; 
        internal const String ConnectKey = "Connect";
 
        // < 

 



        //1 private static LocalActivator  localActivator = null; 

        // ActivationListener is the object that listens to incoming 
        // activation requests. It delegates the incoming request to 
        // the local activator.
        //2 private static ActivationListener ActivationListener = null; 

        //3 private static Object staticSyncObject = new Object();
        //4 private static bool bInitializing = false;
 
        // This gets called upon the first attempt to activate
        // anything that is ContextBound or MarshalByRef 
        private static void Startup() 
        {
            DomainSpecificRemotingData remData = Thread.GetDomain().RemotingData; 

            // wait on the lock if a)activation has not been initialized yet
            // or b) activation is being initialized by another thread!
            if ((!remData.ActivationInitialized) 
               || remData.InitializingActivation)
            { 
                Object configLock = remData.ConfigLock; 
                bool fLocked = false;
                RuntimeHelpers.PrepareConstrainedRegions(); 
                try
                {
                    Monitor.ReliableEnter(configLock, ref fLocked);
                    remData.InitializingActivation = true; 
                    // Ensure that some other thread did not complete
                    // the work while we were waiting on the lock. 
                    if (!remData.ActivationInitialized) 
                    {
                        // Startup the activation service 
                        BCLDebug.Trace("REMOTE","Starting up activation service ",Thread.CurrentContext);

                        //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                        // NOTE: This should be the first step in Startup! 
                        // Otherwise activation will recurse, when we try
                        // to create the ActivationListener (which is MarshalByRef) 
                        //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
                        remData.LocalActivator = new LocalActivator();
 
                        // Add the Lifetime service property to the appdomain.
                        // For now we are assuming that this is the only property
                        // If there are more properties, then an existing array
                        // will need to be expanded to add this property 

                        // This is activated in RemotingServices.DomainSpecificRemotingData() 
                        // IContextProperty[] contextProperties = new IContextProperty[1]; 
                        // contextProperties[0] = new System.Runtime.Remoting.LeaseLifeTimeServiceProperty();
                        // Thread.GetDomain().RemotingData.AppDomainContextProperties = contextProperties; 

                        remData.ActivationListener = new ActivationListener();
                        remData.ActivationInitialized = true;
 
                    }
 
                    remData.InitializingActivation = false; 
                } //lock (remData)
                finally 
                {
                    if (fLocked)
                    {
                        Monitor.Exit(configLock); 
                    }
                } 
            } 
        }
 
        private static void InitActivationServices()
        {
            // If activation services has not been loaded do it now and create
            // the instace that will service the activation requests. 
            if (null == activator)
            { 
                activator = GetActivator(); 
                if (null == activator)
                { 
                    Message.DebugOut("Fatal Error... Could not create activator\n");
                    throw new RemotingException(
                        String.Format(
                            CultureInfo.CurrentCulture, Environment.GetResourceString( 
                                "Remoting_BadInternalState_ActivationFailure")));
                } 
            } 
        }
 
        // Determine whether the current context is ok for the activation.
        private static MarshalByRefObject IsCurrentContextOK(
            Type serverType, Object[] props, bool bNewObj)
        { 
            BCLDebug.Assert(!serverType.IsInterface,"!serverType.IsInterface");
 
            MarshalByRefObject retObj = null; 

            // Initialize activation services if needed. 
            //   (we temporary null out the activation attributes in case
            //    InitActivationServices creates an MBR).
            InitActivationServices();
 
            // Obtain the method info which will create an instance
            // of type RealProxy 
            ProxyAttribute pa = GetProxyAttribute(serverType); 
            BCLDebug.Assert(null != pa, "null != pa");
 
            if (Object.ReferenceEquals(pa, DefaultProxyAttribute))
                retObj = pa.CreateInstanceInternal(serverType);
            else
            { 
                retObj = pa.CreateInstance(serverType);
                // We called a custom proxy attribute .. make sure it is 
                // returning a server of the correct type. 
                if (retObj != null)
                { 
                    // If a transparent proxy is returned we are fine.
                    // If not then the object's type MUST be compatible
                    // with the type we were requested to activate!
                    if (!RemotingServices.IsTransparentProxy(retObj) 
                        && !serverType.IsAssignableFrom(retObj.GetType()))
                    { 
                        throw new RemotingException( 
                            String.Format(
                                CultureInfo.CurrentCulture, Environment.GetResourceString( 
                                    "Remoting_Activation_BadObject"),
                            serverType));
                    }
                } 
            }
            BCLDebug.Assert(null != retObj, "null != retObj"); 
            return retObj; 
        }
 
#if FEATURE_COMINTEROP
        private static MarshalByRefObject CreateObjectForCom(
            Type serverType, Object[] props, bool bNewObj)
        { 
            BCLDebug.Assert(!serverType.IsInterface,"!serverType.IsInterface");
 
            MarshalByRefObject retObj = null; 

            if (PeekActivationAttributes(serverType) != null) 
                throw new NotSupportedException(Environment.GetResourceString("NotSupported_ActivForCom" ));

            // Initialize activation services if needed
            InitActivationServices(); 

            // Obtain the method info which will create an instance 
            // of type RealProxy 
            ProxyAttribute pa = GetProxyAttribute(serverType);
            BCLDebug.Assert(null != pa, "null != pa"); 

            if(pa is ICustomFactory)
            {
                retObj = ((ICustomFactory)pa).CreateInstance(serverType); 
            }
            else 
            { 
                retObj = (MarshalByRefObject)Activator.CreateInstance(serverType, true);
            } 

            BCLDebug.Assert(null != retObj, "null != retObj");
            return retObj;
        } 
#endif // FEATURE_COMINTEROP
 
        // For types with no proxy attribute, we take the default route of 
        // querying attributes if the current context is suitable for
        // activation. 
        private static bool IsCurrentContextOK(Type serverType, Object[] props,
                                               ref ConstructorCallMessage ctorCallMsg)
        {
             //Get callSite attributes 
            Object[] callSiteAttr = PeekActivationAttributes(serverType);
 
            // Clear from the attribute stack 
            if (callSiteAttr != null)
            { 
                PopActivationAttributes(serverType);
            }

            Object[] womAttr = new Object[1]; 
            womAttr[0] = GetGlobalAttribute();
 
            // Get the type context attributes 
            Object[] typeAttr = GetContextAttributesForType(serverType);
 
            // Get the client context (current context)
            Context cliCtx = Thread.CurrentContext;

            // Create a ctorCallMsg with the reqd info 
            ctorCallMsg =
                new ConstructorCallMessage( 
                    callSiteAttr, 
                    womAttr,
                    typeAttr, 
                    serverType);

            // This is the activator that handles activation in *all* cases
            // Based on whether what the activation attributes do.... other 
            // activators may get chained ahead of this one and may take
            // over the activation process... (possibly) delegating to this 
            // only in the last stage. 
            // Note: currently, this does not get used in the same context (MBR)
            // scenarios ... because of the 2-step activation model of JIT. 
            ctorCallMsg.Activator = new ConstructionLevelActivator();


            // Ask all attributes if they are happy with the current context 
            // NOTE: if someone says no, we do not ask the rest of the attributes
            // This is why, womAttr (which is the global activation service 
            // attribute) *must* be the first one we query. 
            bool bCtxOK = QueryAttributesIfContextOK(cliCtx,
                                                     ctorCallMsg, 
                                                     womAttr);
            if (bCtxOK == true)
            {
                bCtxOK = QueryAttributesIfContextOK(cliCtx, 
                                                    ctorCallMsg,
                                                    callSiteAttr); 
                if (bCtxOK == true) 
                {
                    bCtxOK = QueryAttributesIfContextOK(cliCtx, 
                                                        ctorCallMsg,
                                                        typeAttr);
                }
            } 

            return bCtxOK; 
        } 

 	private static void CheckForInfrastructurePermission(Assembly asm) 
	{
	    // Make a security check to ensure that the context attribute
	    // is from a trusted assembly!
 	    if (asm != RemotingServices.s_MscorlibAssembly) 
	    {
 		CodeAccessSecurityEngine.CheckAssembly( 
 		    asm, 
		    RemotingServices.s_RemotingInfrastructurePermission);
 	    } 
	}

        private static bool QueryAttributesIfContextOK(
            Context ctx, IConstructionCallMessage ctorMsg, Object[] attributes) 
        {
            bool bCtxOK = true; 
            if (attributes != null) 
            {
                for (int i=0; i= ActivatorLevel.Context,
                    "activator level must be at least x-context!");
 
                // Check with ActivationServices if we did a "Connect" with
                // a remote server during IsContextOK 
                BCLDebug.Assert( 
                    ActivationServices.CheckIfConnected(remProxy, ctorMsg) == null,
                    "We shouldn't come through this path on a Connect."); 

                // Client context was not approved for activation ...
                // This is the more elaborate (real) activation case i.e.
                // we have to go at least out of the client context to 
                // finish the work.
 
                // Prepare for the handoff to Activation Service 

                // Ask various attributes to contribute properties 
                // The attributes may chain in other activators into
                // the activation chain (to hijack/participate in
                // the activation process).
                ActivationServices.GetPropertiesFromAttributes( 
                    (IConstructionCallMessage)ctorMsg,
                    ctorMsg.CallSiteActivationAttributes); 
 
                ActivationServices.GetPropertiesFromAttributes(
                    ctorMsg, 
                    ((ConstructorCallMessage)ctorMsg).GetWOMAttributes());

                ActivationServices.GetPropertiesFromAttributes(
                    (IConstructionCallMessage)ctorMsg, 
                ((ConstructorCallMessage)ctorMsg).GetTypeAttributes());
 
                // Fetch the client context chain 
                IMessageSink cliCtxChain =
                Thread.CurrentContext.GetClientContextChain(); 

                // Ask the client context chain to take over from here.
                IMethodReturnMessage retMsg =
                    (IMethodReturnMessage) 
                        cliCtxChain.SyncProcessMessage(ctorMsg);
 
                // The return message may not be of type 
                // IConstructionReturnMessage if an exception happens
                // in the sink chains. 
                ctorRetMsg = retMsg as IConstructionReturnMessage;
                if (null == retMsg)
                {
                    throw new RemotingException( 
                        Environment.GetResourceString(
                            "Remoting_Activation_Failed")); 
                } 
                else if (retMsg.Exception != null)
                { 
                    throw retMsg.Exception;
                }
            }
            // Note: PropagateOutParameters is now handled by RealProxy 
            // CallContext from retMsg should be already set by RealProxy
            BCLDebug.Assert( 
                null != ctorRetMsg, 
                "Activate returning null ConstructorReturnMessage");
 
            return ctorRetMsg;
        }

        // This function is called by ActivationServices in case 
        // the activation needs to be within the same appdomain. These
        // are only for ContextBound types. 
        // It is also called to do satisfy remote incoming requests from 
        // the activation services. These could be for both ContextBound
        // and MarshalByRef types. 
        internal static IConstructionReturnMessage DoCrossContextActivation(
            IConstructionCallMessage reqMsg)
        {
            bool bCtxBound = reqMsg.ActivationType.IsContextful; 
            Context serverContext = null;
 
            if (bCtxBound) 
            {
                // If the type is context bound, we need to create 
                // the appropriate context and activate the object inside
                // it.
                // <
 
                // Create a new Context
                serverContext = new Context(); 
 
                // <
 



                ArrayList list = (ArrayList) reqMsg.ContextProperties; 
                Assembly asm = null;
                for (int i=0; i retSize-1) 
                    {
                        IContextAttribute[] newAttr = new IContextAttribute[2*retSize];
                        Array.Copy(
                            retAttr,     // srcArray 
                            0,          // srcIndex
                            newAttr,    // destArray 
                            0,          // destIndex 
                            retSize);   // lengthToCopy
                        retAttr = newAttr; 
                        retSize = retSize*2;
                    }
                    retAttr[numAttr-1] = attr;
                } 
            }
 
            IContextAttribute[] ctxAttr = new IContextAttribute[numAttr]; 
            Array.Copy(retAttr, ctxAttr, numAttr);
            return ctxAttr; 
        }

        // This is called during RS.IsContextOK to check if the new XXX() is configured
        // to do a direct connect, and if it is we Connect to the URL and return 
        // the proxy. In the second stage, when the constructor executes on the proxy
        // we will make sure (in Activate) that there are no CTOR args. 
        internal static Object ConnectIfNecessary(IConstructionCallMessage ctorMsg) 
        {
            // If the type being instantiated is configured for Connect 
            // we would have added its URL as the connect key during
            // LocalActivator::IsContextOK

            // Look for the connect URL 
            String objURL = (String) ctorMsg.Properties[ConnectKey];
            Object proxy = null; 
            if (objURL != null) 
            {
                // Connect to the URL and return the proxy 
                proxy = RemotingServices.Connect(
                                        ctorMsg.ActivationType,
                                        objURL);
            } 

            // If the type is not setup for connecting we return null! 
            return proxy; 
        }
 
        // This is really used to distinguish between proxies for completely
        // within AppDomain activations and the ones from "Connect" during
        // the second stage (RS::Activate)
        // For the former, we have to run constructor etc and for the latter 
        // we have to check that there is no non-defaul CTOR.
        internal static Object CheckIfConnected( 
            RemotingProxy proxy, IConstructionCallMessage ctorMsg) 
        {
            // If we performed a connect, we must have put the URL as 
            // the connectKey in the message.
            String objURL = (String)
                            ctorMsg.Properties[ConnectKey];
            Object tp = null; 

            if (objURL != null) 
            { 
                // We did perform a connect during IsContextOK
                // Just get the TP from RP and return it. 
                tp = (Object)proxy.GetTransparentProxy();
            }
            // We return null if we do not recognize this proxy!
            return tp; 
        }
 
        internal static void PushActivationAttributes(Type serverType, Object[] attributes) 
        {
            // There is one such object per thread 
            if (_attributeStack == null)
            {
                _attributeStack = new ActivationAttributeStack();
            } 
            _attributeStack.Push(serverType, attributes);
        } 
 
        internal static Object[] PeekActivationAttributes(Type serverType)
        { 
            // We can get a peek w/o a prior Push (eg. activation starting
            // with NewObj)
            if (_attributeStack == null)
            { 
                return null;
            } 
            return _attributeStack.Peek(serverType); 
        }
 
        internal static void PopActivationAttributes(Type serverType)
        {
            BCLDebug.Assert(_attributeStack != null, "Pop w/o a prior Set()?");
            _attributeStack.Pop(serverType); 
        }
    } // class ActivationServices 
 

    // This is the local activation helper and also the Attribute 
    // that gets queried about every activation
    internal class LocalActivator: ContextAttribute, IActivator
    {
        internal LocalActivator() 
            : base(ActivationServices.ActivationServiceURI)
        { 
 
        }
 
        // ---------------------------------------------------------------
        // ContextAttribute functionality
        // ---------------------------------------------------------------
 
        // IContextAttribute::IsContextOK
        // This will check if a type is configured for remote activation ... 
        // We return 'false' for IsContextOK if it is. 
        public override bool IsContextOK(
            Context ctx, IConstructionCallMessage ctorMsg) 
        {

            // If the app is not using config mechanism, we don't want
            // to intercept activation. 
            if (RemotingConfigHandler.Info == null)
            { 
                return true; 
            }
 
            // check if this type is configured for connect
            // (instead of remote activate)
            WellKnownClientTypeEntry wkte =
                RemotingConfigHandler.IsWellKnownClientType( 
                    ctorMsg.ActivationType);
            String typeURL = (wkte == null ? null : wkte.ObjectUrl); 
 
            if (typeURL != null)
            { 
                // this type does have a direct uri, we will try to connect
                // to it during the activate call. Cache it in the message.
                ctorMsg.Properties[ActivationServices.ConnectKey] = typeURL;
                return false; 
            }
            else 
            { 
                ActivatedClientTypeEntry acte =
                    RemotingConfigHandler.IsRemotelyActivatedClientType( 
                        ctorMsg.ActivationType);

                String appURL = null;
 
                if (acte == null)
                { 
                    // This is the case where the config file had no entry for this type. 
                    // We should check the callsite attributes for a URL
                    Object[] callsiteAttributes = ctorMsg.CallSiteActivationAttributes; 
                    if(null != callsiteAttributes)
                    {
                        for(int i = 0; i < callsiteAttributes.Length; i++)
                        { 
                            UrlAttribute attr = callsiteAttributes[i] as UrlAttribute;
                            if(null != attr) 
                            { 
                                appURL = attr.UrlValue;
                            } 
                        }
                    }

                    if(appURL == null) 
                    {
                        // We don't really care about intercepting the activation in this case. 
                        return true; 
                    }
                } 
                else
                {
                    appURL = acte.ApplicationUrl;
                } 

                // Generate the URL of the remote activator 
                String activatorURL = null; 
                if (!appURL.EndsWith("/", StringComparison.Ordinal))
                    activatorURL = appURL + "/" + ActivationServices.ActivationServiceURI; 
                else
                    activatorURL = appURL + ActivationServices.ActivationServiceURI;

                // Mark a flag for remote activation 
                // (caching the url of the activation svc of the remote server)
                ctorMsg.Properties[ActivationServices.RemoteActivateKey] = activatorURL; 
                return false; 
            }
        } 

        // IContextAttribute::GetPropertiesForNewContext
        public override void GetPropertiesForNewContext(
            IConstructionCallMessage ctorMsg) 
        {
            BCLDebug.Log("ActivationSvc:GlobalAttrib::GetPropForNewCtx"); 
            // This is called during RS::Activate .. when we are sure that 
            // activation is at least x-context and this is a real activation
            // instead of a spoofed connect underneath the "new". 
            BCLDebug.Assert(ctorMsg!=null, "ctorMsg null?");
            if (ctorMsg.Properties.Contains(ActivationServices.RemoteActivateKey))
            {
                // Means we did want to intercept activation! 
                String remActivatorURL = (String)
                    ctorMsg.Properties[ActivationServices.RemoteActivateKey]; 
 
                AppDomainLevelActivator activator =
                    new AppDomainLevelActivator(remActivatorURL); 
                // Chain ourselves at the end of the AppDomainLevel activators
                BCLDebug.Assert(
                        ctorMsg.Activator != null,
                        "Should have at least x-context activator"); 
                IActivator curr = ctorMsg.Activator;
 
                if (curr.Level < ActivatorLevel.AppDomain) 
                {
                    // Common case .. .only x-context activator(s) in chain 
                    activator.NextActivator = curr;
                    ctorMsg.Activator = activator;
                }
                else if (curr.NextActivator == null) 
                {
                    // Only one activator but not ContextLevel ... 
                    // We go at the end of the chain 
                    curr.NextActivator = activator;
                } 
                else
                {
                    // We will have to walk the chain till the end of the last
                    // AD activator and plug ourselves in. 
                    while (curr.NextActivator.Level >= ActivatorLevel.AppDomain)
                    { 
                        curr = curr.NextActivator; 
                    }
                    BCLDebug.Assert( 
                        curr.NextActivator.Level.Equals(ActivatorLevel.Context),
                        "bad ordering of activators!");
                    activator.NextActivator = curr.NextActivator;
                    curr.NextActivator = activator; 
                }
            } 
        } 

        // --------------------------------------------------------------- 
        // IActivator functionality
        // ----------------------------------------------------------------
        //IActivator::NextActivator
        public virtual IActivator NextActivator 
        {
            // We are a singleton internal infrastructure object. 
            get { return null; } 
            // Don't allow a set either.
            set { throw new InvalidOperationException();} 
        }

        //IActivator::ActivatorLevel
        public virtual ActivatorLevel Level 
        {
            get {return ActivatorLevel.AppDomain;} 
        } 

        private static MethodBase GetMethodBase(IConstructionCallMessage msg) 
        {
            MethodBase mb = msg.MethodBase;
            if(null == mb)
            { 
                BCLDebug.Trace("REMOTE", "Method missing w/name ", msg.MethodName);
                    throw new RemotingException( 
                        String.Format( 
                            CultureInfo.CurrentCulture, Environment.GetResourceString(
                                "Remoting_Message_MethodMissing"), 
                            msg.MethodName,
                            msg.TypeName));
            }
 
            return mb;
        } 
 
        //IActivator::Activate
[System.Runtime.InteropServices.ComVisible(true)] 
        public virtual IConstructionReturnMessage Activate(
            IConstructionCallMessage ctorMsg)
        {
            // This is where the activation service hooks in to activation 
            // requests. We get called as the activation message is recognized
            // by the ClientContextTerminatorSink & routed to us. 
            // 
            // NOTE: This gets called for both purely within appDomain activation
            // and 'real' remote activation scenarios as the request goes out of 
            // the client context.
            // It also gets called as an incoming remote call is routed to the
            // local activator by the remote activator object.
            // 
            BCLDebug.Log("Activation Services:: new Activate()");
            if (ctorMsg == null) 
            { 
                throw new ArgumentNullException("ctorMsg");
            } 

            // Check if we have marked this activation to go remote
            if (ctorMsg.Properties.Contains(ActivationServices.RemoteActivateKey))
            { 
                //DBG Console.WriteLine("Attempting remote activation!");
 
                return DoRemoteActivation(ctorMsg); 
            }
            else 
            {
                // We must be in either a pure cross context activation or
                // a remote incoming activation request (in which case we
                // already checked the permission to create an instance of 
                // this type).
                if (ctorMsg.Properties.Contains(ActivationServices.PermissionKey)) 
                { 
                    Type activationType = ctorMsg.ActivationType;
 
                    // We are on the server end of a real remote activation
                    // Create a local attribute that contributes the context
                    // properties requested by the remote request
                    Object[] attr = null; 
                    if (activationType.IsContextful)
                    { 
                    IList cp = ctorMsg.ContextProperties; 
                    if (cp != null && cp.Count > 0)
                    { 
                        RemotePropertyHolderAttribute rph = new RemotePropertyHolderAttribute(cp);
                        attr = new Object[1];
                        attr[0] = rph;
                    } 
                    }
                    MethodBase mb = GetMethodBase(ctorMsg); 
                    RemotingMethodCachedData methodCache = 
                                            InternalRemotingServices.GetReflectionCachedData(mb);
                    Object[] args = Message.CoerceArgs(ctorMsg, methodCache.Parameters); 

                    Object server = Activator.CreateInstance(
                        activationType,
                        args, 
                        attr);
 
                    // check to see if we need to do redirection 
                    if (RemotingServices.IsClientProxy(server))
                    { 
                        // The wellknown type is remoted so we must wrap the proxy
                        // with a local object.

                        // The redirection proxy masquerades as an object of the appropriate 
                        // type, and forwards incoming messages to the actual proxy.
                        RedirectionProxy redirectedProxy = 
                            new RedirectionProxy((MarshalByRefObject)server, activationType); 
                        RemotingServices.MarshalInternal(redirectedProxy, null, activationType);
 
                        server = redirectedProxy;
                    }

                    return ActivationServices.SetupConstructionReply( 
                        server, ctorMsg, null);
                } 
                else 
                {
                    BCLDebug.Log("Attempting X-Context activation!"); 
                    // delegate to the Activator in the message
                    return ctorMsg.Activator.Activate(ctorMsg);
                }
            } 
        }
 
 
        // This is called by the local activator during an outgoing activation
        // request. 
        internal static IConstructionReturnMessage DoRemoteActivation(
            IConstructionCallMessage ctorMsg)
        {
            BCLDebug.Assert(ctorMsg != null, "Null ctorMsg"); 

            // < 
 

 

            // <

 

            BCLDebug.Log("Attempting Connection to remote activation service"); 
            IActivator remActivator = null; 
            String remActivatorURL = (String)
                ctorMsg.Properties[ActivationServices.RemoteActivateKey]; 
            try
            {
                remActivator = (IActivator)
                    RemotingServices.Connect( 
                        typeof(System.Runtime.Remoting.Activation.IActivator),
                        remActivatorURL); 
 
            }
            catch (Exception e) 
            {
                throw new RemotingException(
                    String.Format(
                        CultureInfo.CurrentCulture, Environment.GetResourceString( 
                            "Remoting_Activation_ConnectFailed"),
                        e)); 
            } 
            // Remove the remote activate key as its purpose is served.
            ctorMsg.Properties.Remove(ActivationServices.RemoteActivateKey); 

            // Delegate the work to the remote activator
            return remActivator.Activate(ctorMsg);
        } 

    }// class LocalActivator 
 
    // This is the object that listens to activation requests
    internal class ActivationListener:MarshalByRefObject, IActivator 
    {
        // Override lifetime services to make this object live forever...
        public override Object InitializeLifetimeService()
        { 
           return null;
        } 
 
        //IActivator::NextActivator
        public virtual IActivator NextActivator 
        {
            // We are a singleton internal infrastructure object.
            get { return null; }
            // Don't allow a set either. 
            set { throw new InvalidOperationException();}
        } 
 
        //IActivator::ActivatorLevel
        public virtual ActivatorLevel Level 
        {
            get {return ActivatorLevel.AppDomain;}
        }
 
        //IActivator::Activate
[System.Runtime.InteropServices.ComVisible(true)] 
        public virtual IConstructionReturnMessage Activate( 
            IConstructionCallMessage ctorMsg)
        { 
            BCLDebug.Log("ActivationListener: received new activation request!");
            if (ctorMsg == null || RemotingServices.IsTransparentProxy(ctorMsg))
            {
                throw new ArgumentNullException("ctorMsg"); 
            }
 
            // Add the permission key which distinguishes pure-cross context activation from 
            // a remote request (both of which go through DoCrossContextActivation)
            ctorMsg.Properties[ActivationServices.PermissionKey] = "allowed"; 

            // Check to make sure that this activation type has been allowed.
            String activationTypeName = ctorMsg.ActivationTypeName;
            if (!RemotingConfigHandler.IsActivationAllowed(activationTypeName)) 
            {
                throw new RemotingException( 
                    String.Format( 
                        CultureInfo.CurrentCulture, Environment.GetResourceString(
                            "Remoting_Activation_PermissionDenied"), 
                        ctorMsg.ActivationTypeName));
            }

            Type activationType = ctorMsg.ActivationType; 
            if (activationType == null)
            { 
                throw new RemotingException( 
                    String.Format(
                        CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_BadType"), 
                        ctorMsg.ActivationTypeName));
            }

            // Delegate to the local activator for further work 
            return ActivationServices.GetActivator().Activate(ctorMsg);
        } 
 

    }   // class ActivationListener 


    // This is a lightweight object to help with the activation
    // at the appDomain level ... it delegates its work to 
    // ActivationServices.LocalActivator ... which is a heavy
    // object we can't afford to carry around in the ActivatorChain 
    // (since it may get Serialized/Deserialized) 
    // <
 
    internal class AppDomainLevelActivator : IActivator
    {
        IActivator m_NextActivator;
 
        // Do we need this?
        String m_RemActivatorURL; 
 
        internal AppDomainLevelActivator(String remActivatorURL)
        { 
            BCLDebug.Assert(remActivatorURL!=null,"Bad activator URL");
            m_RemActivatorURL = remActivatorURL;
        }
 
        internal AppDomainLevelActivator(SerializationInfo info, StreamingContext context) {
            if (info==null) 
            { 
                throw new ArgumentNullException("info");
            } 
            m_NextActivator = (IActivator) info.GetValue("m_NextActivator",typeof(IActivator));
        }

        //IActivator::NextActivator 
        public virtual IActivator NextActivator
        { 
            get { return m_NextActivator; } 
            set { m_NextActivator = value; }
        } 

        //IActivator::ActivatorLevel
        public virtual ActivatorLevel Level
        { 
            get { return ActivatorLevel.AppDomain; }
        } 
 
        //IActivator::Activate
[System.Runtime.InteropServices.ComVisible(true)] 
        public virtual IConstructionReturnMessage Activate(
            IConstructionCallMessage ctorMsg)
        {
            // This function will get invoked when the ClientContextTerminator sink 
            // notices that an activation request message is passed to it ... it
            // will route the message to the Activator present inside the ctorMsg 
            // (which happens to be us in this case!) 

            // remove ourselves from the Activator chain 
            ctorMsg.Activator = m_NextActivator;
            return ActivationServices.GetActivator().Activate(ctorMsg);
        }
    } 

    // This is a lightweight object to help with the activation 
    // at the context level ... 
    [Serializable]
    internal class ContextLevelActivator : IActivator 
    {
        IActivator m_NextActivator;
        internal ContextLevelActivator()
        { 
            m_NextActivator = null;
        } 
 
        internal ContextLevelActivator(SerializationInfo info, StreamingContext context)
        { 
            if (info==null)
            {
                throw new ArgumentNullException("info");
            } 
            m_NextActivator = (IActivator) info.GetValue("m_NextActivator",typeof(IActivator));
        } 
 
        //IActivator::NextActivator
        public virtual IActivator NextActivator 
        {
            get { return m_NextActivator; }
            set { m_NextActivator = value; }
        } 

        //IActivator::ActivatorLevel 
        public virtual ActivatorLevel Level 
        {
            get { return ActivatorLevel.Context; } 
        }

        //IActivator::Activate
[System.Runtime.InteropServices.ComVisible(true)] 
        public virtual IConstructionReturnMessage Activate(
            IConstructionCallMessage ctorMsg) 
        { 
            // remove ourselves from the Activator chain
            ctorMsg.Activator = ctorMsg.Activator.NextActivator; 

            // Delegate to remoting services to do the hard work.
            // This will create a context, enter it, run through
            // the context sink chain & then delegate to the nex 
            // activator inside the ctorMsg (quite likely to be
            // the default ConstructionLevelActivator) 
            return ActivationServices.DoCrossContextActivation(ctorMsg); 
        }
    } 

    // This is a lightweight object to help with the activation
    // at the appDomain level ... it delegates its work to
    // ActivationServices.LocalActivator ... which is a heavy 
    // object we can't afford to carry around in the ActivatorChain
    // (since it may get Serialized/Deserialized) 
    [Serializable] 
    internal class ConstructionLevelActivator : IActivator
    { 
        internal ConstructionLevelActivator()
        {

        } 

 
        //IActivator::NextActivator 
        public virtual IActivator NextActivator
        { 
            // The construction level activator is a terminating activator
            get { return null; }
            // Throw if someone attempts a set
            set { throw new InvalidOperationException(); } 
        }
 
        //IActivator::ActivatorLevel 
        public virtual ActivatorLevel Level
        { 
            get { return ActivatorLevel.Construction; }
        }

        //IActivator::Activate 
[System.Runtime.InteropServices.ComVisible(true)]
        public virtual IConstructionReturnMessage Activate( 
            IConstructionCallMessage ctorMsg) 
        {
            // This function will get invoked when the ClientContextTerminator sink 
            // notices that an activation request message is passed to it ... it
            // will route the message to the Activator present inside the ctorMsg
            // (which happens to be us in this case!)
 
            // remove ourselves from the Activator chain
            ctorMsg.Activator = ctorMsg.Activator.NextActivator; 
            return ActivationServices.DoServerContextActivation(ctorMsg); 
        }
    } 

    // This acts as a pseudo call site attribute and transfers
    // the context properties carried in from a remote activation request
    // to the server side activation 
    internal class RemotePropertyHolderAttribute : IContextAttribute
    { 
        IList _cp;      // incoming list of context properties 
        internal RemotePropertyHolderAttribute(IList cp)
        { 
            _cp = cp;
            BCLDebug.Assert(cp != null && cp.Count > 0,"Bad _cp?");
        }
[System.Runtime.InteropServices.ComVisible(true)] 
        public virtual bool IsContextOK(Context ctx, IConstructionCallMessage msg)
        { 
            // The fact that we got instantiated means some remote activation 
            // has contributed non-default context properties to the ctorMsg
            return false; 
        }


        // properties are collected in order from callsite, wom & type 
        // attributes ... so we get a first shot at adding properties
[System.Runtime.InteropServices.ComVisible(true)] 
        public virtual void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg) 
        {
            for (int i=0; i<_cp.Count; i++) 
            {
                // Just cycle through the list and add the properties to
                // the construction message.
                // We will throw at a later stage if any of these do not 
                // implement IContextProperty
                ctorMsg.ContextProperties.Add(_cp[i]); 
            } 
        }
    } 

    // Note: One instance of this class is setup per thread that comes to
    // managed remoting for activation of MBR types. All access to methods
    // is by design single-threaded. (Each thread is working on its own object). 

    // In the case of Activator.CreateInstance ... that API does the Push & 
    // Remoting does a Pop() as soon as it has picked up the attributes from 
    // the threadStatic. The CreateInstance API itself does a Pop() too in
    // a try-finally. (So this does not work very well if the infrastructure 
    // creates an instance of the same MBR type as the outer type being created.
    // However, to minimize code churn this is the least risky fix we can do.
    // The full fix would be to pass activationAttributes into the VM through
    // reflection code and have the VM pass them over to remoting which will 
    // then hand them over to managed remoting helpers. This will also involve
    // adding attributes as an additional parameter to 
    // ProxyAttribute.CreateInstance() public method. 

    internal class ActivationAttributeStack 
    {
        Object[] activationTypes;
        Object[] activationAttributes;
        int freeIndex; 
        internal ActivationAttributeStack()
        { 
            activationTypes = new Object[4]; 
            activationAttributes = new Object[4];
            freeIndex = 0; 
        }

        internal void Push(Type typ, Object[] attr)
        { 
            BCLDebug.Assert(typ!=null, "typ != null");
            BCLDebug.Assert(attr!=null, "attr != null"); 
 
            if (freeIndex == activationTypes.Length)
            { 
                // Need to grow our arrays ... this will be exceedingly rare
                Object[] newTypes = new Object[activationTypes.Length * 2];
                Object[] newAttr = new Object[activationAttributes.Length * 2];
                BCLDebug.Assert(newAttr.Length == newTypes.Length,"These should be in sync!"); 
                Array.Copy(activationTypes, newTypes, activationTypes.Length);
                Array.Copy(activationAttributes, newAttr, activationAttributes.Length); 
                activationTypes = newTypes; 
                activationAttributes = newAttr;
            } 
            activationTypes[freeIndex] = typ;
            activationAttributes[freeIndex] = attr;
            freeIndex++;
        } 

        internal Object[] Peek(Type typ) 
        { 
            BCLDebug.Assert(typ!=null, "typ != null");
            if (freeIndex == 0 || activationTypes[freeIndex-1] != typ) 
            {
                return null;
            }
            return (Object[])activationAttributes[freeIndex-1]; 
        }
 
        // Note: Read the comments above .. you can have 2 pops for the same 
        // push. We also count on infrastructure code not activating
        // the same type as the caller causing a recursive activation. 
        internal void Pop(Type typ)
        {
            BCLDebug.Assert(typ!=null, "typ != null");
            if (freeIndex != 0 && activationTypes[freeIndex-1] == typ) 
            {
                freeIndex--; 
                // Clear the popped entry 
                activationTypes[freeIndex] = null;
                activationAttributes[freeIndex] = null; 
            }
        }
    }
}//namespace
                        

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