ongoing XmlSerializerMessageContractImporter work.
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel / ClientRealProxy.cs
1 //
2 // ClientRealProxy.cs
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2011 Novell, Inc.  http://www.novell.com
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 #if !DISABLE_REAL_PROXY
29 using System;
30 using System.Collections.Generic;
31 using System.Linq;
32 using System.Reflection;
33 using System.Runtime.Remoting;
34 using System.Runtime.Remoting.Messaging;
35 using System.Runtime.Remoting.Proxies;
36 using System.ServiceModel.Channels;
37 using System.ServiceModel.Description;
38 using System.ServiceModel.Dispatcher;
39 using System.ServiceModel.MonoInternal;
40 using System.Threading;
41
42 namespace System.ServiceModel
43 {
44         class ClientRealProxy : RealProxy, IRemotingTypeInfo
45         {
46                 public ClientRealProxy (Type type, IInternalContextChannel channel, bool isDuplex)
47                         : base (type)
48                 {
49                         this.channel = channel;
50 #if NET_2_1
51                         context_channel_type = typeof (IClientChannel);
52 #else
53                         context_channel_type = isDuplex ? typeof (IDuplexContextChannel) : typeof (IClientChannel);
54 #endif
55                 }
56                 
57                 Type context_channel_type;
58                 IInternalContextChannel channel;
59                 Dictionary<object,object[]> saved_params = new Dictionary<object,object[]> ();
60
61                 // It is used for such case that EndProcess() gets invoked
62                 // before storing params is done after BeginProcess().
63                 ManualResetEvent wait = new ManualResetEvent (false);
64
65                 #region IRemotingTypeInfo
66
67                 public virtual string TypeName { get; set; }
68
69                 public virtual bool CanCastTo (Type t, object o)
70                 {
71                         if (t == context_channel_type || context_channel_type.GetInterfaces ().Contains (t))
72                                 return true;
73                         return false;
74                 }
75                 
76                 #endregion
77                 
78                 public override IMessage Invoke (IMessage inputMessage)
79                 {
80                         try {
81                                 return DoInvoke (inputMessage);
82                         } catch (TargetInvocationException ex) {
83                                 if (ex.InnerException != null)
84                                         throw ex.InnerException;
85                                 throw;
86                         }
87                 }
88
89                 IMessage DoInvoke (IMessage inputMessage)
90                 {
91                         var inmsg = (IMethodCallMessage) inputMessage;
92                         var od = channel.Contract.Operations.FirstOrDefault (o => inmsg.MethodBase.Equals (o.SyncMethod) || inmsg.MethodBase.Equals (o.BeginMethod) || inmsg.MethodBase.Equals (o.EndMethod));
93                         if (od == null) {
94                                 // Then IContextChannel methods.
95                                 var ret = inmsg.MethodBase.Invoke (channel, inmsg.InArgs);
96                                 return new ReturnMessage (ret, null, 0, null, inmsg);
97                         } else {
98                                 object [] pl;
99                                 MethodBase method = null;
100                                 List<object> outArgs = null;
101                                 object ret;
102                                 if (inmsg.MethodBase.Equals (od.SyncMethod)) {
103                                         // sync invocation
104                                         pl = new object [inmsg.MethodBase.GetParameters ().Length];
105                                         Array.Copy (inmsg.Args, pl, inmsg.ArgCount);
106                                         ret = channel.Process (inmsg.MethodBase, od.Name, pl);
107                                         method = od.SyncMethod;
108                                 } else if (inmsg.MethodBase.Equals (od.BeginMethod)) {
109                                         // async invocation
110                                         pl = new object [inmsg.ArgCount - 2];
111                                         Array.Copy (inmsg.Args, 0, pl, 0, pl.Length);
112
113                                         ret = channel.BeginProcess (inmsg.MethodBase, od.Name, pl, (AsyncCallback) inmsg.Args [inmsg.ArgCount - 2], inmsg.Args [inmsg.ArgCount - 1]);
114                                         saved_params [ret] = pl;
115
116                                         wait.Set ();
117
118                                 } else {
119                                         var result = (IAsyncResult) inmsg.InArgs [0];
120
121                                         wait.WaitOne ();
122                                         pl = saved_params [result];
123                                         wait.Reset ();
124                                         saved_params.Remove (result);
125                                         ret = channel.EndProcess (inmsg.MethodBase, od.Name, pl, result);
126                                         method = od.BeginMethod;
127                                 }
128                                 
129                                 if (method != null && method.GetParameters ().Any (pi => pi.IsOut))
130                                         return new ReturnMessage (ret, pl, pl.Length, null, inmsg);
131                                 else
132                                         return new ReturnMessage (ret, outArgs != null ? outArgs.ToArray () : null, outArgs != null ? outArgs.Count : 0, null, inmsg);
133                         }
134                 }
135         }
136 }
137 #endif