[mcs] Replace NET_2_1 by MOBILE
[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                         this.isDuplex = isDuplex;
51                 }
52
53                 bool isDuplex;
54                 IInternalContextChannel channel;
55                 Dictionary<object,object[]> saved_params = new Dictionary<object,object[]> ();
56
57                 // It is used for such case that EndProcess() gets invoked
58                 // before storing params is done after BeginProcess().
59                 ManualResetEvent wait = new ManualResetEvent (false);
60
61                 #region IRemotingTypeInfo
62
63                 public virtual string TypeName { get; set; }
64
65                 static bool CanCastTo<T> (Type type)
66                 {
67                         return typeof (T) == type || typeof (T).GetInterfaces ().Contains (type);
68                 }
69
70                 public virtual bool CanCastTo (Type t, object o)
71                 {
72                         if (CanCastTo<IClientChannel> (t))
73                                 return true;
74 #if !MOBILE
75                         if (isDuplex && CanCastTo<IDuplexContextChannel> (t))
76                                 return true;
77 #endif
78                         return false;
79                 }
80                 
81                 #endregion
82                 
83                 public override IMessage Invoke (IMessage inputMessage)
84                 {
85                         try {
86                                 return DoInvoke (inputMessage);
87                         } catch (TargetInvocationException ex) {
88                                 if (ex.InnerException != null)
89                                         throw ex.InnerException;
90                                 throw;
91                         }
92                 }
93
94                 IMessage DoInvoke (IMessage inputMessage)
95                 {
96                         var inmsg = (IMethodCallMessage) inputMessage;
97                         var od = channel.Contract.Operations.FirstOrDefault (o => inmsg.MethodBase.Equals (o.SyncMethod) || inmsg.MethodBase.Equals (o.BeginMethod) || inmsg.MethodBase.Equals (o.EndMethod));
98                         if (od == null) {
99                                 // Then IContextChannel methods.
100                                 var ret = inmsg.MethodBase.Invoke (channel, inmsg.InArgs);
101                                 return new ReturnMessage (ret, null, 0, null, inmsg);
102                         } else {
103                                 object [] pl;
104                                 MethodBase method = null;
105                                 List<object> outArgs = null;
106                                 object ret;
107                                 if (inmsg.MethodBase.Equals (od.SyncMethod)) {
108                                         // sync invocation
109                                         pl = new object [inmsg.MethodBase.GetParameters ().Length];
110                                         Array.Copy (inmsg.Args, pl, inmsg.ArgCount);
111                                         ret = channel.Process (inmsg.MethodBase, od.Name, pl, OperationContext.Current);
112                                         method = od.SyncMethod;
113                                 } else if (inmsg.MethodBase.Equals (od.BeginMethod)) {
114                                         // async invocation
115                                         pl = new object [inmsg.ArgCount - 2];
116                                         Array.Copy (inmsg.Args, 0, pl, 0, pl.Length);
117
118                                         ret = channel.BeginProcess (inmsg.MethodBase, od.Name, pl, (AsyncCallback) inmsg.Args [inmsg.ArgCount - 2], inmsg.Args [inmsg.ArgCount - 1]);
119                                         saved_params [ret] = pl;
120
121                                         wait.Set ();
122
123                                 } else {
124                                         var result = (IAsyncResult) inmsg.InArgs [0];
125
126                                         wait.WaitOne ();
127                                         pl = saved_params [result];
128                                         wait.Reset ();
129                                         saved_params.Remove (result);
130                                         ret = channel.EndProcess (inmsg.MethodBase, od.Name, pl, result);
131                                         method = od.BeginMethod;
132                                 }
133                                 
134                                 if (method != null && method.GetParameters ().Any (pi => pi.IsOut || pi.ParameterType.IsByRef))
135                                         return new ReturnMessage (ret, pl, pl.Length, null, inmsg);
136                                 else
137                                         return new ReturnMessage (ret, outArgs != null ? outArgs.ToArray () : null, outArgs != null ? outArgs.Count : 0, null, inmsg);
138                         }
139                 }
140         }
141 }
142 #endif