The Labs \ Source Viewer \ SSCLI \ System.Runtime.Remoting.Messaging \ AsyncReplySink

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. //
  16. // Remoting terminator sinks for sink chains along a remoting call.
  17. // There is only one static instance of each of these exposed through
  18. // the MessageSink property.
  19. //
  20. namespace System.Runtime.Remoting.Messaging
  21. {
  22.    
  23.     using System;
  24.     using System.Threading;
  25.     using System.Runtime.InteropServices;
  26.     using System.Runtime.Remoting.Activation;
  27.     using System.Runtime.Remoting.Channels;
  28.     using System.Runtime.Remoting.Contexts;
  29.     using System.Collections;
  30.     using System.Globalization;
  31.     // Methods shared by all terminator sinks.
  32.     //
  33.     [Serializable()]
  34.     internal class InternalSink
  35.     {
  36. /*
  37.         *  Checks the replySink param for NULL and type.
  38.         *  If the param is good, it returns NULL.
  39.         *  Else it returns a Message with the relevant exception.
  40.         */       
  41.         static internal IMessage ValidateMessage(IMessage reqMsg)
  42.         {
  43.             IMessage retMsg = null;
  44.             if (reqMsg == null) {
  45.                 retMsg = new ReturnMessage(new ArgumentNullException("reqMsg"), null);
  46.             }
  47.             return retMsg;
  48.         }
  49.        
  50. /*
  51.         *  This check is performed only for client & server context
  52.         *  terminator sinks and only on the Async path.
  53.         * 
  54.         */       
  55.         static internal IMessage DisallowAsyncActivation(IMessage reqMsg)
  56.         {
  57.             if (reqMsg is IConstructionCallMessage) {
  58.                
  59.                     /*reqMsg*/                return new ReturnMessage(new RemotingException(Environment.GetResourceString("Remoting_Activation_AsyncUnsupported")), null);
  60.             }
  61.             return null;
  62.         }
  63.        
  64.         static internal Identity GetIdentity(IMessage reqMsg)
  65.         {
  66.             Identity id = null;
  67.            
  68.             if (reqMsg is IInternalMessage) {
  69.                 id = ((IInternalMessage)reqMsg).IdentityObject;
  70.             }
  71.             else if (reqMsg is InternalMessageWrapper) {
  72.                 id = (Identity)((InternalMessageWrapper)reqMsg).GetIdentityObject();
  73.             }
  74.            
  75.             // Try the slow path if the identity has not been obtained yet
  76.             if (null == id) {
  77.                 string objURI = GetURI(reqMsg);
  78.                
  79.                 id = IdentityHolder.ResolveIdentity(objURI);
  80.                
  81.                 // An object could get disconnected on another thread while a call is in progress
  82.                 if (id == null) {
  83.                     throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_ServerObjectNotFound"), objURI));
  84.                 }
  85.             }
  86.            
  87.             return id;
  88.         }
  89.        
  90.         static internal ServerIdentity GetServerIdentity(IMessage reqMsg)
  91.         {
  92.             ServerIdentity srvID = null;
  93.             bool bOurMsg = false;
  94.             string objURI = null;
  95.            
  96.             IInternalMessage iim = reqMsg as IInternalMessage;
  97.             if (iim != null) {
  98.                 Message.DebugOut("GetServerIdentity.ServerIdentity from IInternalMessage\n");
  99.                 srvID = ((IInternalMessage)reqMsg).ServerIdentityObject;
  100.                 bOurMsg = true;
  101.             }
  102.             else if (reqMsg is InternalMessageWrapper) {
  103.                 srvID = (ServerIdentity)((InternalMessageWrapper)reqMsg).GetServerIdentityObject();
  104.             }
  105.            
  106.             // Try the slow path if the identity has not been obtained yet
  107.             if (null == srvID) {
  108.                 Message.DebugOut("GetServerIdentity.ServerIdentity from IMethodCallMessage\n");
  109.                 objURI = GetURI(reqMsg);
  110.                 Identity id = IdentityHolder.ResolveIdentity(objURI);
  111.                 if (id is ServerIdentity) {
  112.                     srvID = (ServerIdentity)id;
  113.                    
  114.                     // Cache the serverIdentity in the message
  115.                     if (bOurMsg) {
  116.                         iim.ServerIdentityObject = srvID;
  117.                     }
  118.                 }
  119.             }
  120.            
  121.             return srvID;
  122.         }
  123.        
  124.         // Retrieve the URI either via a method call or through
  125.         // a dictionary property.
  126.         static internal string GetURI(IMessage msg)
  127.         {
  128.             string uri = null;
  129.            
  130.             IMethodMessage mm = msg as IMethodMessage;
  131.             if (mm != null) {
  132.                 uri = mm.Uri;
  133.             }
  134.             else {
  135.                 IDictionary prop = msg.Properties;
  136.                 if (null != prop) {
  137.                     uri = (string)prop["__Uri"];
  138.                 }
  139.             }
  140.            
  141.             return uri;
  142.         }
  143.     }
  144.    
  145.    
  146.     //
  147.     // Terminator sink for server envoy message sink chain. This delegates
  148.     // to the client context chain for the call.
  149.     //
  150.    
  151. /* package scope */   
  152.     [Serializable()]
  153.     internal class EnvoyTerminatorSink : InternalSink, IMessageSink
  154.     {
  155.         private static EnvoyTerminatorSink messageSink;
  156.         private static object staticSyncObject = new object();
  157.        
  158.         static internal IMessageSink MessageSink {
  159.             get {
  160.                 if (messageSink == null) {
  161.                     EnvoyTerminatorSink tmpSink = new EnvoyTerminatorSink();
  162.                     lock (staticSyncObject) {
  163.                         if (messageSink == null) {
  164.                             messageSink = tmpSink;
  165.                         }
  166.                     }
  167.                 }
  168.                 return messageSink;
  169.             }
  170.         }
  171.        
  172.         public virtual IMessage SyncProcessMessage(IMessage reqMsg)
  173.         {
  174.             Message.DebugOut("---------------------------Envoy Chain Terminator: SyncProcessMessage");
  175.             IMessage errMsg = ValidateMessage(reqMsg);
  176.             if (errMsg != null) {
  177.                 return errMsg;
  178.             }
  179.             // Validate returns null if the reqMsg is okay!
  180.             return Thread.CurrentContext.GetClientContextChain().SyncProcessMessage(reqMsg);
  181.         }
  182.        
  183.         public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink)
  184.         {
  185.             Message.DebugOut("---------------------------Envoy Chain Terminator: AsyncProcessMessage");
  186.             IMessageCtrl msgCtrl = null;
  187.             IMessage errMsg = ValidateMessage(reqMsg);
  188.            
  189.             if (errMsg != null) {
  190.                 // Notify replySink of error if we can
  191.                 if (replySink != null) {
  192.                     replySink.SyncProcessMessage(errMsg);
  193.                 }
  194.             }
  195.             else {
  196.                 msgCtrl = Thread.CurrentContext.GetClientContextChain().AsyncProcessMessage(reqMsg, replySink);
  197.             }
  198.             return msgCtrl;
  199.         }
  200.        
  201.         public IMessageSink NextSink {
  202. // We are the terminal sink of this chain
  203.             get { return null; }
  204.         }
  205.        
  206.     }
  207.    
  208.    
  209.     //
  210.     // Terminator sink for client context message sink chain. This delegates
  211.     // to the appropriate channel sink for the call.
  212.     //
  213.     //
  214.    
  215. /* package scope */   
  216.     internal class ClientContextTerminatorSink : InternalSink, IMessageSink
  217.     {
  218.         private static ClientContextTerminatorSink messageSink;
  219.         private static object staticSyncObject = new object();
  220.        
  221.         static internal IMessageSink MessageSink {
  222.             get {
  223.                 if (messageSink == null) {
  224.                     ClientContextTerminatorSink tmpSink = new ClientContextTerminatorSink();
  225.                     lock (staticSyncObject) {
  226.                         if (messageSink == null) {
  227.                             messageSink = tmpSink;
  228.                         }
  229.                     }
  230.                 }
  231.                 return messageSink;
  232.             }
  233.         }
  234.        
  235.         static internal object SyncProcessMessageCallback(object[] args)
  236.         {
  237.             IMessage reqMsg = (IMessage)args[0];
  238.             IMessageSink channelSink = (IMessageSink)args[1];
  239.            
  240.             return channelSink.SyncProcessMessage(reqMsg);
  241.         }
  242.        
  243.         public virtual IMessage SyncProcessMessage(IMessage reqMsg)
  244.         {
  245.             Message.DebugOut("+++++++++++++++++++++++++ CliCtxTerminator: SyncProcessMsg");
  246.             IMessage errMsg = ValidateMessage(reqMsg);
  247.            
  248.             if (errMsg != null) {
  249.                 return errMsg;
  250.             }
  251.            
  252.             Context ctx = Thread.CurrentContext;
  253.            
  254.                 // bCliSide
  255.                 // bStart
  256.                 // bAsync
  257.             bool bHasDynamicSinks = ctx.NotifyDynamicSinks(reqMsg, true, true, false, true);
  258.             // bNotifyGlobals
  259.             IMessage replyMsg;
  260.             if (reqMsg is IConstructionCallMessage) {
  261.                     /*bServerSide*/                errMsg = ctx.NotifyActivatorProperties(reqMsg, false);
  262.                 if (errMsg != null) {
  263.                     return errMsg;
  264.                 }
  265.                
  266.                 replyMsg = ((IConstructionCallMessage)reqMsg).Activator.Activate((IConstructionCallMessage)reqMsg);
  267.                 BCLDebug.Assert(replyMsg is IConstructionReturnMessage, "bad ctorRetMsg");
  268.                     /*bServerSide*/                errMsg = ctx.NotifyActivatorProperties(replyMsg, false);
  269.                 if (errMsg != null) {
  270.                     return errMsg;
  271.                 }
  272.             }
  273.             else {
  274.                 replyMsg = null;
  275.                 ChannelServices.NotifyProfiler(reqMsg, RemotingProfilerEvent.ClientSend);
  276.                
  277.                 object[] args = new object[] {null, null};
  278.                
  279.                 IMessageSink channelSink = GetChannelSink(reqMsg);
  280.                
  281.                 // Forward call to the channel.
  282.                 args[0] = reqMsg;
  283.                 args[1] = channelSink;
  284.                
  285.                 InternalCrossContextDelegate xctxDel = new InternalCrossContextDelegate(SyncProcessMessageCallback);
  286.                
  287.                 // Move to default context unless we are going through
  288.                 // the cross-context channel
  289.                 if (channelSink != CrossContextChannel.MessageSink) {
  290.                     replyMsg = (IMessage)Thread.CurrentThread.InternalCrossContextCallback(Context.DefaultContext, xctxDel, args);
  291.                 }
  292.                 else {
  293.                     replyMsg = (IMessage)xctxDel(args);
  294.                 }
  295.                
  296.                 ChannelServices.NotifyProfiler(replyMsg, RemotingProfilerEvent.ClientReceive);
  297.             }
  298.            
  299.            
  300.             if (bHasDynamicSinks) {
  301.                     // bCliSide
  302.                     // bStart
  303.                     // bAsync
  304.                 ctx.NotifyDynamicSinks(reqMsg, true, false, false, true);
  305.                 // bNotifyGlobals
  306.             }
  307.            
  308.             return replyMsg;
  309.         }
  310.        
  311.         static internal object AsyncProcessMessageCallback(object[] args)
  312.         {
  313.             IMessage reqMsg = (IMessage)args[0];
  314.             IMessageSink replySink = (IMessageSink)args[1];
  315.             IMessageSink channelSink = (IMessageSink)args[2];
  316.            
  317.             return channelSink.AsyncProcessMessage(reqMsg, replySink);
  318.         }
  319.        
  320.         public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink)
  321.         {
  322.             Message.DebugOut("+++++++++++++++++++++++++ CliCtxTerminator: AsyncProcessMsg");
  323.             IMessage errMsg = ValidateMessage(reqMsg);
  324.             IMessageCtrl msgCtrl = null;
  325.             if (errMsg == null) {
  326.                 errMsg = DisallowAsyncActivation(reqMsg);
  327.             }
  328.            
  329.             if (errMsg != null) {
  330.                 if (replySink != null) {
  331.                     replySink.SyncProcessMessage(errMsg);
  332.                 }
  333.             }
  334.             else {
  335.                 // If active, notify the profiler that an asynchronous remoting call is being made.
  336.                 if (RemotingServices.CORProfilerTrackRemotingAsync()) {
  337.                     Guid g;
  338.                    
  339.                     RemotingServices.CORProfilerRemotingClientSendingMessage(out g, true);
  340.                    
  341.                     if (RemotingServices.CORProfilerTrackRemotingCookie())
  342.                         reqMsg.Properties["CORProfilerCookie"] = g;
  343.                    
  344.                     // Only wrap the replySink if the call wants a reply
  345.                     if (replySink != null) {
  346.                         // Now wrap the reply sink in our own so that we can notify the profiler of
  347.                         // when the reply is received. Upon invocation, it will notify the profiler
  348.                         // then pass control on to the replySink passed in above.
  349.                         IMessageSink profSink = new ClientAsyncReplyTerminatorSink(replySink);
  350.                        
  351.                         // Replace the reply sink with our own
  352.                         replySink = profSink;
  353.                     }
  354.                 }
  355.                
  356.                 Context cliCtx = Thread.CurrentContext;
  357.                
  358.                 // Notify dynamic sinks that an Async call started
  359.                     // bCliSide
  360.                     // bStart
  361.                     // bAsync
  362.                 cliCtx.NotifyDynamicSinks(reqMsg, true, true, true, true);
  363.                 // bNotifyGlobals
  364.                 // Intercept the async reply to force the thread back
  365.                 // into the client-context before it executes further
  366.                 // and to notify dynamic sinks
  367.                 if (replySink != null) {
  368.                     replySink = new AsyncReplySink(replySink, cliCtx);
  369.                 }
  370.                
  371.                 object[] args = new object[] {null, null, null};
  372.                 InternalCrossContextDelegate xctxDel = new InternalCrossContextDelegate(AsyncProcessMessageCallback);
  373.                
  374.                 IMessageSink channelSink = GetChannelSink(reqMsg);
  375.                
  376.                 // Forward call to the channel.
  377.                 args[0] = reqMsg;
  378.                 args[1] = replySink;
  379.                 args[2] = channelSink;
  380.                
  381.                 // Move to default context unless we are going through
  382.                 // the cross-context channel
  383.                 if (channelSink != CrossContextChannel.MessageSink) {
  384.                     msgCtrl = (IMessageCtrl)Thread.CurrentThread.InternalCrossContextCallback(Context.DefaultContext, xctxDel, args);
  385.                 }
  386.                 else {
  387.                     msgCtrl = (IMessageCtrl)xctxDel(args);
  388.                 }
  389.             }
  390.             return msgCtrl;
  391.         }
  392.        
  393.         public IMessageSink NextSink {
  394. // We are the terminal sink of this chain
  395.             get { return null; }
  396.         }
  397.        
  398.         // Find the next chain (or channel) sink to delegate to.
  399.         private IMessageSink GetChannelSink(IMessage reqMsg)
  400.         {
  401.             Identity id = GetIdentity(reqMsg);
  402.             return id.ChannelSink;
  403.         }
  404.     }
  405.    
  406.     internal class AsyncReplySink : IMessageSink
  407.     {
  408.        
  409.         IMessageSink _replySink;
  410.         // original reply sink that we are wrapping
  411.         Context _cliCtx;
  412.         // the context this call emerged from
  413.         internal AsyncReplySink(IMessageSink replySink, Context cliCtx)
  414.         {
  415.             _replySink = replySink;
  416.             _cliCtx = cliCtx;
  417.         }
  418.        
  419.         static internal object SyncProcessMessageCallback(object[] args)
  420.         {
  421.             IMessage reqMsg = (IMessage)args[0];
  422.             IMessageSink replySink = (IMessageSink)args[1];
  423.            
  424.             // Call the dynamic sinks to notify that the async call
  425.             // has completed
  426.                 // this is the async reply
  427.                 // bCliSide
  428.                 // bStart
  429.                 // bAsync
  430.             Thread.CurrentContext.NotifyDynamicSinks(reqMsg, true, false, true, true);
  431.             // bNotifyGlobals
  432.             // call the original reply sink now that we have moved
  433.             // to the correct client context
  434.             return replySink.SyncProcessMessage(reqMsg);
  435.         }
  436.        
  437.         public virtual IMessage SyncProcessMessage(IMessage reqMsg)
  438.         {
  439.             // we just switch back to the old context before calling
  440.             // the next replySink
  441.             IMessage retMsg = null;
  442.             if (_replySink != null) {
  443.                 object[] args = new object[] {reqMsg, _replySink};
  444.                 InternalCrossContextDelegate xctxDel = new InternalCrossContextDelegate(SyncProcessMessageCallback);
  445.                
  446.                 retMsg = (IMessage)Thread.CurrentThread.InternalCrossContextCallback(_cliCtx, xctxDel, args);
  447.             }
  448.             return retMsg;
  449.         }
  450.        
  451.         public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink)
  452.         {
  453.             throw new NotSupportedException();
  454.         }
  455.        
  456.         public IMessageSink NextSink {
  457.             get { return _replySink; }
  458.         }
  459.     }
  460.    
  461.    
  462.    
  463.    
  464.     //
  465.     // Terminator sink for server context message sink chain. This delegates
  466.     // to the appropriate object sink chain for the call.
  467.     //
  468.     //
  469.    
  470. /* package scope */   
  471.     [Serializable()]
  472.     internal class ServerContextTerminatorSink : InternalSink, IMessageSink
  473.     {
  474.         private static ServerContextTerminatorSink messageSink;
  475.         private static object staticSyncObject = new object();
  476.        
  477.         static internal IMessageSink MessageSink {
  478.             get {
  479.                 if (messageSink == null) {
  480.                     ServerContextTerminatorSink tmpSink = new ServerContextTerminatorSink();
  481.                     lock (staticSyncObject) {
  482.                         if (messageSink == null) {
  483.                             messageSink = tmpSink;
  484.                         }
  485.                     }
  486.                 }
  487.                 return messageSink;
  488.             }
  489.         }
  490.        
  491.         public virtual IMessage SyncProcessMessage(IMessage reqMsg)
  492.         {
  493.             Message.DebugOut("+++++++++++++++++++++++++ SrvCtxTerminator: SyncProcessMsg");
  494.             IMessage errMsg = ValidateMessage(reqMsg);
  495.             if (errMsg != null) {
  496.                 return errMsg;
  497.             }
  498.            
  499.            
  500.             Context ctx = Thread.CurrentContext;
  501.             IMessage replyMsg;
  502.             if (reqMsg is IConstructionCallMessage) {
  503.                     /*bServerSide*/                errMsg = ctx.NotifyActivatorProperties(reqMsg, true);
  504.                 if (errMsg != null) {
  505.                     return errMsg;
  506.                 }
  507.                
  508.                 replyMsg = ((IConstructionCallMessage)reqMsg).Activator.Activate((IConstructionCallMessage)reqMsg);
  509.                 BCLDebug.Assert(replyMsg is IConstructionReturnMessage, "bad ctorRetMsg");
  510.                     /*bServerSide*/                errMsg = ctx.NotifyActivatorProperties(replyMsg, true);
  511.                 if (errMsg != null) {
  512.                     return errMsg;
  513.                 }
  514.             }
  515.             else {
  516.                 // Pass call on to the server object specific chain
  517.                 MarshalByRefObject obj = null;
  518.                 try {
  519.                     replyMsg = GetObjectChain(reqMsg, out obj).SyncProcessMessage(reqMsg);
  520.                 }
  521.                 finally {
  522.                     IDisposable iDis = null;
  523.                     if (obj != null && ((iDis = (obj as IDisposable)) != null)) {
  524.                         iDis.Dispose();
  525.                     }
  526.                 }
  527.             }
  528.            
  529.             return replyMsg;
  530.         }
  531.        
  532.         public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink)
  533.         {
  534.             Message.DebugOut("+++++++++++++++++++++++++ SrvCtxTerminator: SyncProcessMsg");
  535.             IMessageCtrl msgCtrl = null;
  536.             IMessage errMsg = ValidateMessage(reqMsg);
  537.            
  538.             if (errMsg == null) {
  539.                 errMsg = DisallowAsyncActivation(reqMsg);
  540.             }
  541.            
  542.             if (errMsg != null) {
  543.                 if (replySink != null) {
  544.                     replySink.SyncProcessMessage(errMsg);
  545.                 }
  546.             }
  547.             else {
  548.                 MarshalByRefObject obj;
  549.                 IMessageSink nextChain = GetObjectChain(reqMsg, out obj);
  550.                 IDisposable iDis;
  551.                 if (obj != null && ((iDis = (obj as IDisposable)) != null)) {
  552.                     DisposeSink dsink = new DisposeSink(iDis, replySink);
  553.                     replySink = dsink;
  554.                 }
  555.                 msgCtrl = nextChain.AsyncProcessMessage(reqMsg, replySink);
  556.                
  557.             }
  558.             return msgCtrl;
  559.         }
  560.        
  561.         public IMessageSink NextSink {
  562. // We are the terminal sink of this chain
  563.             get { return null; }
  564.         }
  565.        
  566.         internal virtual IMessageSink GetObjectChain(IMessage reqMsg, out MarshalByRefObject obj)
  567.         {
  568.             ServerIdentity srvID = GetServerIdentity(reqMsg);
  569.             return srvID.GetServerObjectChain(out obj);
  570.         }
  571.     }
  572.    
  573.     internal class DisposeSink : IMessageSink
  574.     {
  575.         IDisposable _iDis;
  576.         IMessageSink _replySink;
  577.         internal DisposeSink(IDisposable iDis, IMessageSink replySink)
  578.         {
  579.             _iDis = iDis;
  580.             _replySink = replySink;
  581.         }
  582.        
  583.         public virtual IMessage SyncProcessMessage(IMessage reqMsg)
  584.         {
  585.             IMessage replyMsg = null;
  586.             try {
  587.                 if (_replySink != null) {
  588.                     replyMsg = _replySink.SyncProcessMessage(reqMsg);
  589.                 }
  590.             }
  591.             finally {
  592.                 // call dispose on the object now!
  593.                 _iDis.Dispose();
  594.             }
  595.             return replyMsg;
  596.         }
  597.        
  598.         public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink)
  599.         {
  600.             throw new NotSupportedException();
  601.         }
  602.         public IMessageSink NextSink {
  603.             get { return _replySink; }
  604.         }
  605.     }
  606.    
  607.    
  608.     //
  609.     // Terminator sink for the server object sink chain. This should
  610.     // be just replaced by the dispatcher sink.
  611.     //
  612.    
  613. /* package scope */   
  614.     [Serializable()]
  615.     internal class ServerObjectTerminatorSink : InternalSink, IMessageSink
  616.     {
  617.         internal StackBuilderSink _stackBuilderSink;
  618.         internal ServerObjectTerminatorSink(MarshalByRefObject srvObj)
  619.         {
  620.             _stackBuilderSink = new StackBuilderSink(srvObj);
  621.         }
  622.        
  623.        
  624.         public virtual IMessage SyncProcessMessage(IMessage reqMsg)
  625.         {
  626.             Message.DebugOut("+++++++++++++++++++++++++ SrvObjTerminator: SyncProcessMsg\n");
  627.             IMessage errMsg = ValidateMessage(reqMsg);
  628.             if (errMsg != null) {
  629.                 return errMsg;
  630.             }
  631.            
  632.             ServerIdentity srvID = GetServerIdentity(reqMsg);
  633.            
  634.             BCLDebug.Assert(null != srvID, "null != srvID");
  635.             ArrayWithSize objectSinks = srvID.ServerSideDynamicSinks;
  636.             if (objectSinks != null) {
  637.                     // bCliSide
  638.                     // bStart
  639.                 DynamicPropertyHolder.NotifyDynamicSinks(reqMsg, objectSinks, false, true, false);
  640.                 // bAsync
  641.             }
  642.            
  643.             Message.DebugOut("ServerObjectTerminator.Invoking method on object\n");
  644.            
  645.             // Pass call on to the server object specific chain
  646.             BCLDebug.Assert(null != _stackBuilderSink, "null != _stackBuilderSink");
  647.            
  648.             IMessage replyMsg;
  649.            
  650.             IMessageSink serverAsSink = _stackBuilderSink.ServerObject as IMessageSink;
  651.             if (serverAsSink != null)
  652.                 replyMsg = serverAsSink.SyncProcessMessage(reqMsg);
  653.             else
  654.                 replyMsg = _stackBuilderSink.SyncProcessMessage(reqMsg);
  655.            
  656.             if (objectSinks != null) {
  657.                     // bCliSide
  658.                     // bStart
  659.                 DynamicPropertyHolder.NotifyDynamicSinks(replyMsg, objectSinks, false, false, false);
  660.                 // bAsync
  661.             }
  662.             return replyMsg;
  663.         }
  664.        
  665.         public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink)
  666.         {
  667.             IMessageCtrl msgCtrl = null;
  668.             IMessage errMsg = ValidateMessage(reqMsg);
  669.            
  670.             if (errMsg != null) {
  671.                 if (replySink != null) {
  672.                     replySink.SyncProcessMessage(errMsg);
  673.                 }
  674.             }
  675.             else {
  676.                 // Pass call on to the server object specific chain
  677.                 IMessageSink serverAsSink = _stackBuilderSink.ServerObject as IMessageSink;
  678.                 if (serverAsSink != null)
  679.                     msgCtrl = serverAsSink.AsyncProcessMessage(reqMsg, replySink);
  680.                 else
  681.                     msgCtrl = _stackBuilderSink.AsyncProcessMessage(reqMsg, replySink);
  682.             }
  683.             return msgCtrl;
  684.         }
  685.        
  686.         public IMessageSink NextSink {
  687. // We are the terminal sink of this chain
  688.             get { return null; }
  689.         }
  690.        
  691.     }
  692.    
  693.    
  694.     //
  695.     // Terminator sink used for profiling so that we can intercept asynchronous
  696.     // replies on the client side.
  697.     //
  698.    
  699. /* package scope */   
  700.     internal class ClientAsyncReplyTerminatorSink : IMessageSink
  701.     {
  702.         internal IMessageSink _nextSink;
  703.        
  704.         internal ClientAsyncReplyTerminatorSink(IMessageSink nextSink)
  705.         {
  706.             BCLDebug.Assert(nextSink != null, "null IMessageSink passed to ClientAsyncReplyTerminatorSink ctor.");
  707.             _nextSink = nextSink;
  708.         }
  709.        
  710.         public virtual IMessage SyncProcessMessage(IMessage replyMsg)
  711.         {
  712.             // If this class has been brought into the picture, then the following must be true.
  713.             BCLDebug.Assert(RemotingServices.CORProfilerTrackRemoting(), "CORProfilerTrackRemoting returned false, but we're in AsyncProcessMessage!");
  714.             BCLDebug.Assert(RemotingServices.CORProfilerTrackRemotingAsync(), "CORProfilerTrackRemoting returned false, but we're in AsyncProcessMessage!");
  715.            
  716.             Guid g = Guid.Empty;
  717.            
  718.             // If GUID cookies are active, then we try to get it from the properties dictionary
  719.             if (RemotingServices.CORProfilerTrackRemotingCookie()) {
  720.                 object obj = replyMsg.Properties["CORProfilerCookie"];
  721.                
  722.                 if (obj != null) {
  723.                     g = (Guid)obj;
  724.                 }
  725.             }
  726.            
  727.             // Notify the profiler that we are receiving an async reply from the server-side
  728.             RemotingServices.CORProfilerRemotingClientReceivingReply(g, true);
  729.            
  730.             // Now that we've done the intercepting, pass the message on to the regular chain
  731.             return _nextSink.SyncProcessMessage(replyMsg);
  732.         }
  733.        
  734.         public virtual IMessageCtrl AsyncProcessMessage(IMessage replyMsg, IMessageSink replySink)
  735.         {
  736.             // Since this class is only used for intercepting async replies, this function should
  737.             // never get called. (Async replies are synchronous, ironically)
  738.             BCLDebug.Assert(false, "ClientAsyncReplyTerminatorSink.AsyncProcessMessage called!");
  739.            
  740.             return null;
  741.         }
  742.        
  743.         public IMessageSink NextSink {
  744.             get { return _nextSink; }
  745.         }
  746.        
  747.         // Do I need a finalize here?
  748.     }
  749. }

Developer Fusion