// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
+using System.Collections.Generic;
+using System.Linq;
using System.Reflection;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Threading;
using System.Xml;
-namespace System.ServiceModel
+namespace System.ServiceModel.MonoInternal
{
- internal class DuplexClientRuntimeChannel
+#if DISABLE_REAL_PROXY
+ // FIXME: This is a quick workaround for bug #571907
+ public
+#endif
+ class DuplexClientRuntimeChannel
: ClientRuntimeChannel, IDuplexContextChannel
{
public DuplexClientRuntimeChannel (ServiceEndpoint endpoint,
ChannelFactory factory, EndpointAddress remoteAddress, Uri via)
: base (endpoint, factory, remoteAddress, via)
{
- var cd = ContractDescription.GetContract (endpoint.Contract.CallbackContractType);
- var se = new ServiceEndpoint (cd, factory.Endpoint.Binding, remoteAddress);
- var ed = new EndpointDispatcher (remoteAddress, cd.Name, cd.Namespace);
- ed.InitializeServiceEndpoint (true, null, se);
+ var ed = new EndpointDispatcher (remoteAddress, endpoint.Contract.Name, endpoint.Contract.Namespace);
+ ed.InitializeServiceEndpoint (true, null, endpoint);
Runtime.CallbackDispatchRuntime = ed.DispatchRuntime;
}
IAsyncResult loop_result;
AutoResetEvent loop_handle = new AutoResetEvent (false);
AutoResetEvent finish_handle = new AutoResetEvent (false);
+ AutoResetEvent receive_reply_handle = new AutoResetEvent (false);
protected override void OnOpen (TimeSpan timeout)
{
protected override void OnClose (TimeSpan timeout)
{
- DateTime start = DateTime.Now;
+ DateTime start = DateTime.UtcNow;
base.OnClose (timeout);
loop = false;
- if (!loop_handle.WaitOne (timeout - (DateTime.Now - start)))
+ if (!loop_handle.WaitOne (timeout - (DateTime.UtcNow - start)))
throw new TimeoutException ();
- if (!finish_handle.WaitOne (timeout - (DateTime.Now - start)))
+ if (!finish_handle.WaitOne (timeout - (DateTime.UtcNow - start)))
throw new TimeoutException ();
}
}
}
- void ProcessInput (IInputChannel input, Message message)
+ void ProcessInputCore (IInputChannel input, Message message)
{
- try {
+ bool isReply = message != null && Contract.Operations.Any (od => (od.DeclaringContract.CallbackContractType == od.DeclaringContract.ContractType || !od.InCallbackContract) && od.Messages.Any (md => md.Action == message.Headers.Action));
+ if (isReply) {
+ if (ReplyHandlerQueue.Count > 0) {
+ if (isReply) {
+ var h = ReplyHandlerQueue.Dequeue ();
+ h (message);
+ return;
+ }
+ }
+ }
+
+ if (message.IsFault) {
+ Exception ex;
+ var mf = MessageFault.CreateFault (message, 0x10000);
+ if (FaultConverter.GetDefaultFaultConverter (message.Version).TryCreateException (message, mf, out ex)) // FIXME: get maxMessageSize somehow
+ throw ex;
+ else
+ throw new FaultException (mf);
+ }
+
if (!MessageMatchesEndpointDispatcher (message, Runtime.CallbackDispatchRuntime.EndpointDispatcher))
throw new EndpointNotFoundException (String.Format ("The request message has the target '{0}' with action '{1}' which is not reachable in this service contract", message.Headers.To, message.Headers.Action));
new InputOrReplyRequestProcessor (Runtime.CallbackDispatchRuntime, input).ProcessInput (message);
+ }
+
+ void ProcessInput (IInputChannel input, Message message)
+ {
+ try {
+ ProcessInputCore (input, message);
} catch (Exception ex) {
// FIXME: log it.
Console.WriteLine (ex);
- } finally {
- // unless it is closed by session/call manager, move it back to the loop to receive the next message.
- if (input.State != CommunicationState.Closed)
- ProcessRequestOrInput (input);
}
}
return endpoint.ContractFilter.Match (req);
}
+
+ internal override Message RequestCorrelated (Message msg, TimeSpan timeout, IOutputChannel channel)
+ {
+ DateTime startTime = DateTime.UtcNow;
+ Message ret = null;
+ ManualResetEvent wait = new ManualResetEvent (false);
+ Action<Message> handler = delegate (Message reply) {
+ ret = reply;
+ wait.Set ();
+ };
+ ReplyHandlerQueue.Enqueue (handler);
+ channel.Send (msg, timeout);
+ if (ret == null && !wait.WaitOne (timeout - (DateTime.UtcNow - startTime)))
+ throw new TimeoutException ();
+ return ret;
+ }
+
+ internal Queue<Action<Message>> ReplyHandlerQueue = new Queue<Action<Message>> ();
}
}