[System.ServiceModel] Fix timeout defaulting to 0 seconds
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel / ClientRuntimeChannel.cs
index ea8299a06fe62ae160378f2504f407655669668b..2e2b0d60b0860a432a7a5229b0f1e409a0ab9af2 100644 (file)
@@ -46,9 +46,7 @@ namespace System.ServiceModel.MonoInternal
        {
                ContractDescription Contract { get; }
 
-               OperationContext Context { set; }
-
-               object Process (MethodBase method, string operationName, object [] parameters);
+               object Process (MethodBase method, string operationName, object [] parameters, OperationContext context);
 
                IAsyncResult BeginProcess (MethodBase method, string operationName, object [] parameters, AsyncCallback callback, object asyncState);
 
@@ -69,12 +67,13 @@ namespace System.ServiceModel.MonoInternal
                TimeSpan default_open_timeout, default_close_timeout;
                IChannel channel;
                IChannelFactory factory;
-               OperationContext context;
+               TimeSpan? operation_timeout = null;
+
 
                #region delegates
                readonly ProcessDelegate _processDelegate;
 
-               delegate object ProcessDelegate (MethodBase method, string operationName, object [] parameters);
+               delegate object ProcessDelegate (MethodBase method, string operationName, bool isAsync, ref object [] parameters, OperationContext context);
 
                readonly RequestDelegate requestDelegate;
 
@@ -111,7 +110,6 @@ namespace System.ServiceModel.MonoInternal
 
                        // default values
                        AllowInitializationUI = true;
-                       OperationTimeout = TimeSpan.FromMinutes (1);
 
                        if (contextChannel != null)
                                channel = contextChannel;
@@ -149,10 +147,6 @@ namespace System.ServiceModel.MonoInternal
                        get { return channel as IDuplexChannel; }
                }
 
-               public OperationContext Context {
-                       set { context = value; }
-               }
-
                #region IClientChannel
 
                bool did_interactive_initialization;
@@ -204,7 +198,6 @@ namespace System.ServiceModel.MonoInternal
                                }
                        }
 
-#if !MOONLIGHT
                        public override bool WaitOne (int millisecondsTimeout, bool exitContext)
                        {
                                return WaitHandle.WaitAll (ResultWaitHandles, millisecondsTimeout, exitContext);
@@ -214,7 +207,6 @@ namespace System.ServiceModel.MonoInternal
                        {
                                return WaitHandle.WaitAll (ResultWaitHandles, timeout, exitContext);
                        }
-#endif
                }
 
                class DisplayUIAsyncResult : IAsyncResult
@@ -331,8 +323,17 @@ namespace System.ServiceModel.MonoInternal
                        }
                }
 
-               [MonoTODO]
-               public TimeSpan OperationTimeout { get; set; }
+               public TimeSpan OperationTimeout {
+                       get {
+                               if (!this.operation_timeout.HasValue) {
+                                       this.operation_timeout = DefaultCommunicationTimeouts.Instance.ReceiveTimeout;
+                               }
+                               return this.operation_timeout.Value;
+                       }
+                       set {
+                               this.operation_timeout = value;
+                       }
+               }
 
                public IOutputSession OutputSession {
                        get {
@@ -447,41 +448,49 @@ namespace System.ServiceModel.MonoInternal
 
                public IAsyncResult BeginProcess (MethodBase method, string operationName, object [] parameters, AsyncCallback callback, object asyncState)
                {
-                       if (context != null)
-                               throw new InvalidOperationException ("another operation is in progress");
-                       context = OperationContext.Current;
-
-                       return _processDelegate.BeginInvoke (method, operationName, parameters, callback, asyncState);
+                       var p = parameters;
+                       var retval = _processDelegate.BeginInvoke (method, operationName, true, ref p, OperationContext.Current, callback, asyncState);
+                       if (p != parameters)
+                               throw new InvalidOperationException ();
+                       return retval;
                }
 
                public object EndProcess (MethodBase method, string operationName, object [] parameters, IAsyncResult result)
                {
-                               
                        if (result == null)
                                throw new ArgumentNullException ("result");
                        if (parameters == null)
                                throw new ArgumentNullException ("parameters");
-                       // FIXME: the method arguments should be verified to be 
-                       // identical to the arguments in the corresponding begin method.
-                       object asyncResult = _processDelegate.EndInvoke (result);
-                       context = null;
-                       return asyncResult;
+
+                       object[] p = parameters;
+                       var retval = _processDelegate.EndInvoke (ref p, result);
+                       if (p == parameters)
+                               return retval;
+
+                       if (p.Length != parameters.Length)
+                               throw new InvalidOperationException ();
+                       Array.Copy (p, parameters, p.Length);
+                       return retval;
+               }
+
+               public object Process (MethodBase method, string operationName, object [] parameters, OperationContext context)
+               {
+                       var p = parameters;
+                       var retval = Process (method, operationName, false, ref p, context);
+                       if (p != parameters)
+                               throw new InvalidOperationException ();
+                       return retval;
                }
 
-               public object Process (MethodBase method, string operationName, object [] parameters)
+               object Process (MethodBase method, string operationName, bool isAsync, ref object [] parameters, OperationContext context)
                {
                        var previousContext = OperationContext.Current;
                        try {
                                // Inherit the context from the calling thread
-                               if (this.context != null) 
-                                       OperationContext.Current = this.context;
+                               OperationContext.Current = context;
 
-                               return DoProcess (method, operationName, parameters);
+                               return DoProcess (method, operationName, isAsync, ref parameters, context);
                        } catch (Exception ex) {
-#if MOONLIGHT // just for debugging
-                               Console.Write ("Exception in async operation: ");
-                               Console.WriteLine (ex);
-#endif
                                throw;
                        } finally {
                                // Reset the context before the thread goes back into the pool
@@ -489,7 +498,7 @@ namespace System.ServiceModel.MonoInternal
                        }
                }
 
-               object DoProcess (MethodBase method, string operationName, object [] parameters)
+               object DoProcess (MethodBase method, string operationName, bool isAsync, ref object [] parameters, OperationContext context)
                {
                        if (AllowInitializationUI)
                                DisplayInitializationUI ();
@@ -499,9 +508,9 @@ namespace System.ServiceModel.MonoInternal
                                Open ();
 
                        if (!od.IsOneWay)
-                               return Request (od, parameters);
+                               return Request (od, isAsync, ref parameters, context);
                        else {
-                               Output (od, parameters);
+                               Output (od, parameters, context);
                                return null;
                        }
                }
@@ -519,17 +528,17 @@ namespace System.ServiceModel.MonoInternal
                        return od;
                }
 
-               void Output (OperationDescription od, object [] parameters)
+               void Output (OperationDescription od, object [] parameters, OperationContext context)
                {
                        ClientOperation op = runtime.Operations [od.Name];
-                       Send (CreateRequest (op, parameters), OperationTimeout);
+                       Send (CreateRequest (op, parameters, context), OperationTimeout);
                }
 
-               object Request (OperationDescription od, object [] parameters)
+               object Request (OperationDescription od, bool isAsync, ref object [] parameters, OperationContext context)
                {
                        ClientOperation op = runtime.Operations [od.Name];
                        object [] inspections = new object [runtime.MessageInspectors.Count];
-                       Message req = CreateRequest (op, parameters);
+                       Message req = CreateRequest (op, parameters, context);
 
                        for (int i = 0; i < inspections.Length; i++)
                                inspections [i] = runtime.MessageInspectors [i].BeforeSendRequest (ref req, this);
@@ -545,14 +554,12 @@ namespace System.ServiceModel.MonoInternal
                                                Type detailType = typeof (ExceptionDetail);
                                                var freader = fault.GetReaderAtDetailContents ();
                                                DataContractSerializer ds = null;
-#if !NET_2_1
                                                foreach (var fci in op.FaultContractInfos)
                                                        if (res.Headers.Action == fci.Action || fci.Serializer.IsStartObject (freader)) {
                                                                detailType = fci.Detail;
                                                                ds = fci.Serializer;
                                                                break;
                                                        }
-#endif
                                                if (ds == null)
                                                        ds = new DataContractSerializer (detailType);
                                                var detail = ds.ReadObject (freader);
@@ -568,10 +575,15 @@ namespace System.ServiceModel.MonoInternal
                        for (int i = 0; i < inspections.Length; i++)
                                runtime.MessageInspectors [i].AfterReceiveReply (ref res, inspections [i]);
 
-                       if (op.DeserializeReply)
-                               return op.Formatter.DeserializeReply (res, parameters);
-                       else
+                       if (!op.DeserializeReply)
                                return res;
+
+                       if (isAsync && od.EndMethod != null) {
+                               var endParams = od.EndMethod.GetParameters ();
+                               parameters = new object [endParams.Length - 1];
+                       }
+
+                       return op.Formatter.DeserializeReply (res, parameters);
                }
 
                #region Message-based Request() and Send()
@@ -623,7 +635,7 @@ namespace System.ServiceModel.MonoInternal
                }
                #endregion
 
-               Message CreateRequest (ClientOperation op, object [] parameters)
+               Message CreateRequest (ClientOperation op, object [] parameters, OperationContext context)
                {
                        MessageVersion version = message_version;
                        if (version == null)