File: LocalService\MethodMessage.cs
Project: ndp\cdf\src\WF\Activities\System.Workflow.Activities.csproj (System.Workflow.Activities)
#pragma warning disable 1634, 1691
using System;
using System.Diagnostics;
using System.Collections;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Remoting.Messaging;
using System.Workflow.Runtime;
using System.Security.Principal;
using System.Threading;
using System.Globalization;
 
namespace System.Workflow.Activities
{
    internal interface IMethodResponseMessage
    {
        void SendResponse(ICollection outArgs);
        void SendException(Exception exception);
        Exception Exception { get; }
        ICollection OutArgs { get; }
    }
 
    [Serializable]
    internal sealed class MethodMessage : IMethodMessage, IMethodResponseMessage
    {
        [NonSerialized]
        Type interfaceType;
        [NonSerialized]
        string methodName;
        [NonSerialized]
        object[] args;
        [NonSerialized]
        ManualResetEvent returnValueSignalEvent;
 
        object[] clonedArgs;
        LogicalCallContext callContext;
 
        ICollection outArgs;
        Exception exception;
 
        [NonSerialized]
        bool responseSet = false;
 
        Guid callbackCookie;
 
        [NonSerialized]
        MethodMessage previousMessage = null;
 
        static Dictionary<Guid, MethodMessage> staticMethodMessageMap = new Dictionary<Guid, MethodMessage>();
        static Object syncRoot = new Object();
 
        internal MethodMessage(Type interfaceType, string methodName,
                               object[] args, String identity) :
            this(interfaceType, methodName, args, identity, false)
        {
 
        }
 
        internal MethodMessage(Type interfaceType, string methodName,
                               object[] args, String identity, bool responseRequired)
        {
            this.interfaceType = interfaceType;
            this.methodName = methodName;
            this.args = args;
            callContext = GetLogicalCallContext();
 
            if (responseRequired)
                returnValueSignalEvent = new ManualResetEvent(false);
 
            PopulateIdentity(callContext, identity);
            Clone();
        }
 
 
 
        [OnSerializing]
        void OnSerializing(StreamingContext context)
        {
            if (returnValueSignalEvent != null && !responseSet)
            {
                callbackCookie = Guid.NewGuid();
 
                lock (syncRoot)
                {
                    staticMethodMessageMap.Add(callbackCookie, previousMessage ?? this);
                }
            }
        }
 
        [OnDeserialized]
        void OnDeserialized(StreamingContext context)
        {
            if (callbackCookie != Guid.Empty)
            {
                lock (syncRoot)
                {
                    if (staticMethodMessageMap.TryGetValue(callbackCookie, out previousMessage))
                        staticMethodMessageMap.Remove(callbackCookie);
                }
 
                if (previousMessage != null)
                {
                    this.responseSet = previousMessage.responseSet;
                    this.returnValueSignalEvent = previousMessage.returnValueSignalEvent;
                }
            }
 
            callbackCookie = Guid.Empty;
        }
 
        string IMethodMessage.GetArgName(int index)
        {
            throw new NotImplementedException();
        }
 
        object IMethodMessage.GetArg(int argNum)
        {
            return this.clonedArgs[argNum];
        }
 
        string IMethodMessage.Uri
        {
#pragma warning disable 56503
            // not implemented
            get { throw new NotImplementedException(); }
#pragma warning restore 56503
        }
 
        string IMethodMessage.MethodName
        {
            get { return this.methodName; }
        }
 
        string IMethodMessage.TypeName
        {
            get
            {
                return (this.interfaceType.ToString());
            }
        }
 
        object IMethodMessage.MethodSignature
        {
#pragma warning disable 56503
            get { throw new NotImplementedException(); }
#pragma warning restore 56503
        }
 
        object[] IMethodMessage.Args
        {
            get
            {
                return this.clonedArgs;
            }
        }
 
        object Clone()
        {
            object[] clones = new object[this.args.Length];
 
            for (int i = 0; i < this.args.Length; i++)
            {
                clones[i] = Clone(this.args[i]);
            }
            this.clonedArgs = clones;
            return clones;
        }
 
        object Clone(object source)
        {
            if (source == null || source.GetType().IsValueType)
                return source;
 
            ICloneable clone = source as ICloneable;
            if (clone != null)
                return clone.Clone();
 
            BinaryFormatter formatter = new BinaryFormatter();
            System.IO.MemoryStream stream = new System.IO.MemoryStream(1024);
            try
            {
                formatter.Serialize(stream, source);
            }
            catch (SerializationException e)
            {
                throw new InvalidOperationException(SR.GetString(SR.Error_EventArgumentSerializationException), e);
            }
            stream.Position = 0;
            object cloned = formatter.Deserialize(stream);
            return cloned;
        }
 
        int IMethodMessage.ArgCount
        {
            get { return this.clonedArgs.Length; }
        }
 
        bool IMethodMessage.HasVarArgs
        {
#pragma warning disable 56503
            get { throw new NotImplementedException(); }
#pragma warning restore 56503
        }
 
        LogicalCallContext IMethodMessage.LogicalCallContext
        {
            get { return callContext; }
        }
 
        MethodBase IMethodMessage.MethodBase
        {
#pragma warning disable 56503
            get { throw new NotImplementedException(); }
#pragma warning restore 56503
        }
 
        IDictionary System.Runtime.Remoting.Messaging.IMessage.Properties
        {
#pragma warning disable 56503
            get { throw new NotImplementedException(); }
#pragma warning restore 56503
        }
 
        void PopulateIdentity(LogicalCallContext callContext, String identity)
        {
            callContext.SetData(IdentityContextData.IdentityContext, new IdentityContextData(identity));
        }
 
        static LogicalCallContext singletonCallContext;
        static Object syncObject = new Object();
 
        static LogicalCallContext GetLogicalCallContext()
        {
            lock (syncObject)
            {
                if (singletonCallContext == null)
                {
                    CallContextProxy contextProxy = new CallContextProxy(typeof(IDisposable));
                    IDisposable disposable = (IDisposable)contextProxy.GetTransparentProxy();
                    disposable.Dispose();
                    singletonCallContext = contextProxy.CallContext;
                }
                return singletonCallContext.Clone() as LogicalCallContext;
            }
        }
 
        #region IMethodResponseMessage implementation
 
        internal IMethodResponseMessage WaitForResponseMessage()
        {
            // todo wait for certain timeout
            this.returnValueSignalEvent.WaitOne();
            this.returnValueSignalEvent = null;
            return this;
        }
 
        public void SendResponse(ICollection outArgs)
        {
            if (this.returnValueSignalEvent == null)
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.GetString(SR.Error_WorkflowInstanceDehydratedBeforeSendingResponse)));
 
            if (!this.responseSet)
            {
                this.OutArgs = outArgs;
                this.returnValueSignalEvent.Set();
                this.responseSet = true;
            }
        }
 
        public void SendException(Exception exception)
        {
            if (this.returnValueSignalEvent == null)
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.GetString(SR.Error_WorkflowInstanceDehydratedBeforeSendingResponse)));
 
            if (!this.responseSet)
            {
                this.Exception = exception;
                this.returnValueSignalEvent.Set();
                this.responseSet = true;
            }
        }
 
        public Exception Exception
        {
            get
            {
                return this.exception;
            }
            private set
            {
                if (previousMessage != null)
                    previousMessage.Exception = value;
 
                this.exception = value;
            }
        }
 
        public ICollection OutArgs
        {
            get
            {
                return this.outArgs;
            }
            private set
            {
                if (previousMessage != null)
                    previousMessage.OutArgs = value;
 
                this.outArgs = value;
            }
        }
        #endregion
 
        private sealed class CallContextProxy : System.Runtime.Remoting.Proxies.RealProxy
        {
            LogicalCallContext callContext;
 
            internal LogicalCallContext CallContext
            {
                get
                {
                    return callContext;
                }
            }
 
            internal CallContextProxy(Type proxiedType)
                : base(proxiedType)
            {
 
            }
 
            public override System.Runtime.Remoting.Messaging.IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage msg)
            {
                IMethodCallMessage methodCallMessage = msg as IMethodCallMessage;
                this.callContext = methodCallMessage.LogicalCallContext.Clone() as LogicalCallContext;
                return new ReturnMessage(null, null, 0, methodCallMessage.LogicalCallContext, methodCallMessage);
            }
        }
    }
}