Ref parameter was not covered by ParameterInfo.IsOut. Fixed bug #696784.
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel / ServiceRuntimeChannel.cs
1 //
2 // ServiceRuntimeChannel.cs
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2007 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 using System;
29 using System.Collections.Generic;
30 using System.Reflection;
31 using System.ServiceModel.Channels;
32 using System.ServiceModel.Description;
33 using System.ServiceModel.Dispatcher;
34 using System.ServiceModel.MonoInternal;
35
36 namespace System.ServiceModel.MonoInternal
37 {
38 #if DISABLE_REAL_PROXY
39         // FIXME: this is a (similar) workaround for bug 571907.
40         public
41 #endif
42         class DuplexServiceRuntimeChannel : ServiceRuntimeChannel, IDuplexContextChannel, IInternalContextChannel
43         {
44                 public DuplexServiceRuntimeChannel (IChannel channel, DispatchRuntime runtime)
45                         : base (channel, runtime)
46                 {
47                         if (channel == null)
48                                 throw new ArgumentNullException ("channel");
49                         // setup callback ClientRuntimeChannel.
50                         var crt = runtime.CallbackClientRuntime;
51                         if (crt == null)
52                                 throw new InvalidOperationException ("The DispatchRuntime does not have CallbackClientRuntime");
53                         contract = ContractDescriptionGenerator.GetCallbackContract (runtime.Type, crt.CallbackClientType);
54                         client = new ClientRuntimeChannel (crt, contract, this.DefaultOpenTimeout, this.DefaultCloseTimeout, channel, null,
55                                                            runtime.ChannelDispatcher.MessageVersion, this.RemoteAddress, null);
56                 }
57
58                 ClientRuntimeChannel client;
59                 ContractDescription contract;
60
61                 public override bool AllowOutputBatching {
62                         get { return client.AllowOutputBatching; }
63                         set { client.AllowOutputBatching = value; }
64                 }
65
66                 public override TimeSpan OperationTimeout {
67                         get { return client.OperationTimeout; }
68                         set { client.OperationTimeout = value; }
69                 }
70
71                 public bool AutomaticInputSessionShutdown {
72                         get { throw new NotImplementedException (); }
73                         set { throw new NotImplementedException (); }
74                 }
75
76                 public InstanceContext CallbackInstance { get; set; }
77
78                 public ContractDescription Contract {
79                         get { return contract; }
80                 }
81
82                 Action<TimeSpan> session_shutdown_delegate;
83
84                 public void CloseOutputSession (TimeSpan timeout)
85                 {
86                         throw new NotImplementedException ();
87                 }
88
89                 public IAsyncResult BeginCloseOutputSession (TimeSpan timeout, AsyncCallback callback, object state)
90                 {
91                         if (session_shutdown_delegate == null)
92                                 session_shutdown_delegate = new Action<TimeSpan> (CloseOutputSession);
93                         return session_shutdown_delegate.BeginInvoke (timeout, callback, state);
94                 }
95
96                 public void EndCloseOutputSession (IAsyncResult result)
97                 {
98                         session_shutdown_delegate.EndInvoke (result);
99                 }
100
101                 // proxy base implementation.
102
103                 public IAsyncResult BeginProcess (MethodBase method, string operationName, object [] parameters, AsyncCallback callback, object asyncState)
104                 {
105                         return client.BeginProcess (method, operationName, parameters, callback, asyncState);
106                 }
107
108                 public object EndProcess (MethodBase method, string operationName, object [] parameters, IAsyncResult result)
109                 {
110                         return client.EndProcess (method, operationName, parameters, result);
111                 }
112
113                 public object Process (MethodBase method, string operationName, object [] parameters)
114                 {
115                         return client.Process (method, operationName, parameters);
116                 }
117         }
118
119         // Its lifetime is per-session.
120         // InputOrReplyRequestProcessor's lifetime is per-call.
121 #if DISABLE_REAL_PROXY
122         // FIXME: this is a (similar) workaround for bug 571907.
123         public
124 #endif
125         class ServiceRuntimeChannel : CommunicationObject, IServiceChannel, IDisposable
126         {
127                 IExtensionCollection<IContextChannel> extensions;
128                 readonly IChannel channel;
129                 readonly DispatchRuntime runtime;
130
131                 public ServiceRuntimeChannel (IChannel channel, DispatchRuntime runtime)
132                 {
133                         this.channel = channel;
134                         this.runtime = runtime;
135                 }
136
137                 void OnChannelClose (object o, EventArgs e)
138                 {
139                         Close ();
140                 }
141
142                 #region IContextChannel
143
144                 [MonoTODO]
145                 public virtual bool AllowOutputBatching { get; set; }
146
147                 public IInputSession InputSession {
148                         get {
149                                 var ch = channel as ISessionChannel<IInputSession>;
150                                 if (ch != null)
151                                         return ch.Session;
152                                 var dch = channel as ISessionChannel<IDuplexSession>;
153                                 return dch != null ? dch.Session : null;
154                         }
155                 }
156
157                 public EndpointAddress LocalAddress {
158                         get {
159                                 if (channel is IReplyChannel)
160                                         return ((IReplyChannel) channel).LocalAddress;
161                                 if (channel is IInputChannel)
162                                         return ((IInputChannel) channel).LocalAddress;
163                                 return null;
164                         }
165                 }
166
167                 [MonoTODO]
168                 public virtual TimeSpan OperationTimeout { get; set; }
169
170                 public IOutputSession OutputSession {
171                         get {
172                                 var dch = channel as ISessionChannel<IDuplexSession>;
173                                 return dch != null ? dch.Session : null;
174                         }
175                 }
176
177                 public EndpointAddress RemoteAddress {
178                         get {
179                                 if (channel is IDuplexChannel)
180                                         return ((IDuplexChannel) channel).RemoteAddress;
181                                 return null;
182                         }
183                 }
184
185                 public string SessionId {
186                         get { return InputSession != null ? InputSession.Id : null; }
187                 }
188
189                 #endregion
190
191                 // CommunicationObject
192                 protected internal override TimeSpan DefaultOpenTimeout {
193                         get { return runtime.ChannelDispatcher.DefaultOpenTimeout; }
194                 }
195
196                 protected internal override TimeSpan DefaultCloseTimeout {
197                         get { return runtime.ChannelDispatcher.DefaultCloseTimeout; }
198                 }
199
200                 protected override void OnAbort ()
201                 {
202                         channel.Abort ();
203                 }
204
205                 Action<TimeSpan> close_delegate;
206
207                 protected override IAsyncResult OnBeginClose (
208                         TimeSpan timeout, AsyncCallback callback, object state)
209                 {
210                         if (close_delegate == null)
211                                 close_delegate = new Action<TimeSpan> (OnClose);
212                         return close_delegate.BeginInvoke (timeout, callback, state);
213                 }
214
215                 protected override void OnEndClose (IAsyncResult result)
216                 {
217                         close_delegate.EndInvoke (result);
218                 }
219
220                 protected override void OnClose (TimeSpan timeout)
221                 {
222                         channel.Closing -= OnChannelClose;
223                 }
224
225                 protected override IAsyncResult OnBeginOpen (
226                         TimeSpan timeout, AsyncCallback callback, object state)
227                 {
228                         return channel.BeginOpen (timeout, callback, state);
229                 }
230
231                 protected override void OnEndOpen (IAsyncResult result)
232                 {
233                         channel.EndOpen (result);
234                 }
235
236                 protected override void OnOpen (TimeSpan timeout)
237                 {
238                         if (channel.State == CommunicationState.Created)
239                                 channel.Open (timeout);
240                 }
241
242                 // IChannel
243                 public T GetProperty<T> () where T : class
244                 {
245                         return channel.GetProperty<T> ();
246                 }
247
248                 // IExtensibleObject<IContextChannel>
249                 public IExtensionCollection<IContextChannel> Extensions {
250                         get {
251                                 if (extensions == null)
252                                         extensions = new ExtensionCollection<IContextChannel> (this);
253                                 return extensions;
254                         }
255                 }
256
257                 public Uri ListenUri {
258                         get { return runtime.ChannelDispatcher.Listener.Uri; }
259                 }
260
261                 #region IDisposable Members
262
263                 public void Dispose ()
264                 {
265                         Close ();
266                 }
267
268                 #endregion
269         }
270 }