Merge pull request #4453 from lambdageek/bug-49721
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel / ClientBase.cs
1 //
2 // generic ClientBase.cs
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2005-2006 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.ComponentModel;
31 using System.Reflection;
32 using System.ServiceModel.Channels;
33 using System.ServiceModel.Description;
34 using System.ServiceModel.Dispatcher;
35 using System.Threading;
36 using System.ServiceModel.MonoInternal;
37
38 namespace System.ServiceModel
39 {
40         [MonoTODO ("It somehow rejects classes, but dunno how we can do that besides our code wise.")]
41         public abstract class ClientBase<TChannel> :
42                 IDisposable,
43                 ICommunicationObject where TChannel : class
44         {
45                 static InstanceContext initialContxt = new InstanceContext (null);
46
47                 ChannelFactory<TChannel> factory;
48                 IClientChannel inner_channel;
49
50                 protected delegate IAsyncResult BeginOperationDelegate (object[] inValues, AsyncCallback asyncCallback, object state);
51                 protected delegate object[] EndOperationDelegate (IAsyncResult result);
52
53                 protected ClientBase ()
54                         : this (initialContxt)
55                 {
56                 }
57
58                 protected ClientBase (string endpointConfigurationName)
59                         : this (initialContxt, endpointConfigurationName)
60                 {
61                 }
62
63                 protected ClientBase (Binding binding, EndpointAddress remoteAddress)
64                         : this (initialContxt, binding, remoteAddress)
65                 {
66                 }
67
68                 protected ClientBase (string endpointConfigurationName, EndpointAddress remoteAddress)
69                         : this (initialContxt, endpointConfigurationName, remoteAddress)
70                 {
71                 }
72
73                 protected ClientBase (string endpointConfigurationName, string remoteAddress)
74                         : this (initialContxt, endpointConfigurationName, remoteAddress)
75                 {
76                 }
77
78                 protected ClientBase (InstanceContext callbackInstance)
79                         : this (callbackInstance, "*")
80                 {
81                 }
82
83                 protected ClientBase (InstanceContext callbackInstance, string endpointConfigurationName)
84                 {
85                         if (callbackInstance == null)
86                                 throw new ArgumentNullException ("instanceContext");
87                         if (endpointConfigurationName == null)
88                                 throw new ArgumentNullException ("endpointConfigurationName");
89
90                         Initialize (callbackInstance, endpointConfigurationName, null);
91                 }
92
93                 protected ClientBase (InstanceContext callbackInstance,
94                         string endpointConfigurationName, EndpointAddress remoteAddress)
95                 {
96                         if (callbackInstance == null)
97                                 throw new ArgumentNullException ("instanceContext");
98                         if (endpointConfigurationName == null)
99                                 throw new ArgumentNullException ("endpointConfigurationName");
100                         if (remoteAddress == null)
101                                 throw new ArgumentNullException ("remoteAddress");
102
103                         Initialize (callbackInstance, endpointConfigurationName, remoteAddress);
104                 }
105
106                 protected ClientBase (InstanceContext callbackInstance,
107                         string endpointConfigurationName, string remoteAddress)
108                 {
109                         if (callbackInstance == null)
110                                 throw new ArgumentNullException ("instanceContext");
111                         if (remoteAddress == null)
112                                 throw new ArgumentNullException ("endpointAddress");
113                         if (endpointConfigurationName == null)
114                                 throw new ArgumentNullException ("endpointConfigurationName");
115
116                         Initialize (callbackInstance, endpointConfigurationName, new EndpointAddress (remoteAddress));
117                 }
118
119                 protected ClientBase (InstanceContext callbackInstance,
120                         Binding binding, EndpointAddress remoteAddress)
121                 {
122                         if (callbackInstance == null)
123                                 throw new ArgumentNullException ("instanceContext");
124                         if (binding == null)
125                                 throw new ArgumentNullException ("binding");
126                         if (remoteAddress == null)
127                                 throw new ArgumentNullException ("remoteAddress");
128
129                         Initialize (callbackInstance, binding, remoteAddress);
130                 }
131
132                 protected ClientBase (ServiceEndpoint endpoint)
133                         : this (null, endpoint)
134                 {
135                 }
136
137                 protected ClientBase (InstanceContext callbackInstance, ServiceEndpoint endpoint)
138                         : this (callbackInstance, new ChannelFactory<TChannel> (endpoint))
139                 {
140                 }
141
142                 internal ClientBase (ChannelFactory<TChannel> factory)
143                         : this (null, factory)
144                 {
145                 }
146
147                 internal ClientBase (InstanceContext instance, ChannelFactory<TChannel> factory)
148                 {
149                         // FIXME: use instance
150                         ChannelFactory = factory;
151                 }
152
153                 internal virtual void Initialize (InstanceContext instance,
154                         string endpointConfigurationName, EndpointAddress remoteAddress)
155                 {
156                         // FIXME: use instance
157                         ChannelFactory = new ChannelFactory<TChannel> (endpointConfigurationName, remoteAddress);
158                 }
159
160                 internal virtual void Initialize (InstanceContext instance,
161                         Binding binding, EndpointAddress remoteAddress)
162                 {
163                         // FIXME: use instance
164                         ChannelFactory = new ChannelFactory<TChannel> (binding, remoteAddress);
165                 }
166
167                 public ChannelFactory<TChannel> ChannelFactory {
168                         get { return factory; }
169                         internal set {
170                                 factory = value;
171                                 factory.OwnerClientBase = this;
172                         }
173                 }
174
175                 public ClientCredentials ClientCredentials {
176                         get { return ChannelFactory.Credentials; }
177                 }
178
179                 public ServiceEndpoint Endpoint {
180                         get { return factory.Endpoint; }
181                 }
182
183                 public IClientChannel InnerChannel {
184                         get {
185                                 if (inner_channel == null)
186                                         inner_channel = (IClientChannel) (object) CreateChannel ();
187                                 return inner_channel;
188                         }
189                 }
190
191                 protected TChannel Channel {
192                         get { return (TChannel) (object) InnerChannel; }
193                 }
194
195                 public CommunicationState State {
196                         get { return inner_channel != null ? inner_channel.State : CommunicationState.Created; }
197                 }
198
199                 public void Abort ()
200                 {
201                         InnerChannel.Abort ();
202                 }
203
204                 public void Close ()
205                 {
206                         InnerChannel.Close ();
207                 }
208
209                 public void DisplayInitializationUI ()
210                 {
211                         InnerChannel.DisplayInitializationUI ();
212                 }
213
214                 protected T GetDefaultValueForInitialization<T> ()
215                 {
216                         return default (T);
217                 }
218
219                 //IAsyncResult delegate_async;
220
221                 void RunCompletedCallback (SendOrPostCallback callback, InvokeAsyncCompletedEventArgs args)
222                 {
223                         callback (args);
224                 }
225
226                 protected void InvokeAsync (BeginOperationDelegate beginOperationDelegate,
227                         object [] inValues, EndOperationDelegate endOperationDelegate,
228                         SendOrPostCallback operationCompletedCallback, object userState)
229                 {
230                         if (beginOperationDelegate == null)
231                                 throw new ArgumentNullException ("beginOperationDelegate");
232                         if (endOperationDelegate == null)
233                                 throw new ArgumentNullException ("endOperationDelegate");
234                         //if (delegate_async != null)
235                         //      throw new InvalidOperationException ("Another async operation is in progress");
236
237                         AsyncCallback cb = delegate (IAsyncResult ar) {
238                                 object [] results = null;
239                                 Exception error = null;
240                                 bool cancelled = false; // FIXME: fill it in case it is cancelled
241                                 try {
242                                         results = endOperationDelegate (ar);
243                                 } catch (Exception ex) {
244                                         error = ex;
245                                 }
246                                 try {
247                                         if (operationCompletedCallback != null)
248                                                 RunCompletedCallback (operationCompletedCallback, new InvokeAsyncCompletedEventArgs (results, error, cancelled, userState));
249                                 } catch (Exception ex) {
250                                         //Console.WriteLine ("Exception during operationCompletedCallback" + ex);
251                                         throw;
252                                 }
253                                 //Console.WriteLine ("System.ServiceModel.ClientBase<TChannel>: web service invocation is successfully done (operationCompletedCallback may not be).");
254                         };
255                         begin_async_result = beginOperationDelegate (inValues, cb, userState);
256                 }
257                 IAsyncResult begin_async_result;
258
259                 void IDisposable.Dispose ()
260                 {
261                         Close ();
262                 }
263
264                 protected virtual TChannel CreateChannel ()
265                 {
266                         return ChannelFactory.CreateChannel ();
267                 }
268
269                 public void Open ()
270                 {
271                         InnerChannel.Open ();
272                 }
273
274                 #region ICommunicationObject implementation
275
276                 IAsyncResult ICommunicationObject.BeginOpen (
277                         AsyncCallback callback, object state)
278                 {
279                         return InnerChannel.BeginOpen (callback, state);
280                 }
281
282                 IAsyncResult ICommunicationObject.BeginOpen (
283                         TimeSpan timeout, AsyncCallback callback, object state)
284                 {
285                         return InnerChannel.BeginOpen (timeout, callback, state);
286                 }
287
288                 void ICommunicationObject.EndOpen (IAsyncResult result)
289                 {
290                         InnerChannel.EndOpen (result);
291                 }
292
293                 IAsyncResult ICommunicationObject.BeginClose (
294                         AsyncCallback callback, object state)
295                 {
296                         return InnerChannel.BeginClose (callback, state);
297                 }
298
299                 IAsyncResult ICommunicationObject.BeginClose (
300                         TimeSpan timeout, AsyncCallback callback, object state)
301                 {
302                         return InnerChannel.BeginClose (timeout, callback, state);
303                 }
304
305                 void ICommunicationObject.EndClose (IAsyncResult result)
306                 {
307                         InnerChannel.EndClose (result);
308                 }
309
310                 void ICommunicationObject.Close (TimeSpan timeout)
311                 {
312                         InnerChannel.Close (timeout);
313                 }
314
315                 void ICommunicationObject.Open (TimeSpan timeout)
316                 {
317                         InnerChannel.Open (timeout);
318                 }
319
320                 event EventHandler ICommunicationObject.Opening {
321                         add { InnerChannel.Opening += value; }
322                         remove { InnerChannel.Opening -= value; }
323                 }
324                 event EventHandler ICommunicationObject.Opened {
325                         add { InnerChannel.Opened += value; }
326                         remove { InnerChannel.Opened -= value; }
327                 }
328                 event EventHandler ICommunicationObject.Closing {
329                         add { InnerChannel.Closing += value; }
330                         remove { InnerChannel.Closing -= value; }
331                 }
332                 event EventHandler ICommunicationObject.Closed {
333                         add { InnerChannel.Closed += value; }
334                         remove { InnerChannel.Closed -= value; }
335                 }
336                 event EventHandler ICommunicationObject.Faulted {
337                         add { InnerChannel.Faulted += value; }
338                         remove { InnerChannel.Faulted -= value; }
339                 }
340
341                 #endregion
342
343                 protected class InvokeAsyncCompletedEventArgs : AsyncCompletedEventArgs
344                 {
345                         internal InvokeAsyncCompletedEventArgs (object [] results, Exception error, bool cancelled, object userState)
346                                 : base (error, cancelled, userState)
347                         {
348                                 Results = results;
349                         }
350
351                         public object [] Results { get; private set; }
352                 }
353
354                 protected internal
355                 class ChannelBase<T> : IClientChannel, IOutputChannel, IRequestChannel where T : class
356                 {
357                         ServiceEndpoint endpoint;
358                         ChannelFactory factory;
359                         ClientRuntimeChannel inner_channel;
360
361                         protected ChannelBase (ClientBase<T> client)
362                                 : this (client.Endpoint, client.ChannelFactory)
363                         {
364                         }
365
366                         internal ChannelBase (ServiceEndpoint endpoint, ChannelFactory factory)
367                         {
368                                 this.endpoint = endpoint;
369                                 this.factory = factory;
370                         }
371
372                         internal ClientRuntimeChannel Inner {
373                                 get {
374                                         if (inner_channel == null)
375                                                 inner_channel = new ClientRuntimeChannel (endpoint, factory, endpoint.Address, null);
376                                         return inner_channel;
377                                 }
378                         }
379
380                         protected object Invoke (string methodName, object [] args)
381                         {
382                                 var cd = endpoint.Contract;
383                                 var od = cd.Operations.Find (methodName);
384                                 if (od == null)
385                                         throw new ArgumentException (String.Format ("Operation '{0}' not found in the service contract '{1}' in namespace '{2}'", methodName, cd.Name, cd.Namespace));
386                                 return Inner.Process (od.SyncMethod, methodName, args, OperationContext.Current);
387                         }
388
389                         protected IAsyncResult BeginInvoke (string methodName, object [] args, AsyncCallback callback, object state)
390                         {
391                                 var cd = endpoint.Contract;
392                                 var od = cd.Operations.Find (methodName);
393                                 if (od == null)
394                                         throw new ArgumentException (String.Format ("Operation '{0}' not found in the service contract '{1}' in namespace '{2}'", methodName, cd.Name, cd.Namespace));
395                                 return Inner.BeginProcess (od.BeginMethod, methodName, args, callback, state);
396                         }
397
398                         protected object EndInvoke (string methodName, object [] args, IAsyncResult result)
399                         {
400                                 var cd = endpoint.Contract;
401                                 var od = cd.Operations.Find (methodName);
402                                 if (od == null)
403                                         throw new ArgumentException (String.Format ("Operation '{0}' not found in the service contract '{1}' in namespace '{2}'", methodName, cd.Name, cd.Namespace));
404                                 return Inner.EndProcess (od.EndMethod, methodName, args, result);
405                         }
406
407                         #region ICommunicationObject
408
409                         IAsyncResult ICommunicationObject.BeginClose (AsyncCallback callback, object state)
410                         {
411                                 return Inner.BeginClose (callback, state);
412                         }
413
414                         IAsyncResult ICommunicationObject.BeginClose (TimeSpan timeout, AsyncCallback callback, object state)
415                         {
416                                 return Inner.BeginClose (timeout, callback, state);
417                         }
418
419                         void ICommunicationObject.Close ()
420                         {
421                                 Inner.Close ();
422                         }
423
424                         void ICommunicationObject.Close (TimeSpan timeout)
425                         {
426                                 Inner.Close (timeout);
427                         }
428
429                         IAsyncResult ICommunicationObject.BeginOpen (AsyncCallback callback, object state)
430                         {
431                                 return Inner.BeginOpen (callback, state);
432                         }
433
434                         IAsyncResult ICommunicationObject.BeginOpen (TimeSpan timeout, AsyncCallback callback, object state)
435                         {
436                                 return Inner.BeginOpen (timeout, callback, state);
437                         }
438
439                         void ICommunicationObject.Open ()
440                         {
441                                 Inner.Open ();
442                         }
443
444                         void ICommunicationObject.Open (TimeSpan timeout)
445                         {
446                                 Inner.Open (timeout);
447                         }
448
449                         void ICommunicationObject.Abort ()
450                         {
451                                 Inner.Abort ();
452                         }
453
454                         void ICommunicationObject.EndClose (IAsyncResult result)
455                         {
456                                 Inner.EndClose (result);
457                         }
458
459                         void ICommunicationObject.EndOpen (IAsyncResult result)
460                         {
461                                 Inner.EndOpen (result);
462                         }
463
464                         CommunicationState ICommunicationObject.State {
465                                 get { return Inner.State; }
466                         }
467
468                         event EventHandler ICommunicationObject.Opened {
469                                 add { Inner.Opened += value; }
470                                 remove { Inner.Opened -= value; }
471                         }
472
473                         event EventHandler ICommunicationObject.Opening {
474                                 add { Inner.Opening += value; }
475                                 remove { Inner.Opening -= value; }
476                         }
477
478                         event EventHandler ICommunicationObject.Closed {
479                                 add { Inner.Closed += value; }
480                                 remove { Inner.Closed -= value; }
481                         }
482
483                         event EventHandler ICommunicationObject.Closing {
484                                 add { Inner.Closing += value; }
485                                 remove { Inner.Closing -= value; }
486                         }
487
488                         event EventHandler ICommunicationObject.Faulted {
489                                 add { Inner.Faulted += value; }
490                                 remove { Inner.Faulted -= value; }
491                         }
492
493                         #endregion
494
495                         #region IClientChannel
496
497                         public bool AllowInitializationUI {
498                                 get { return Inner.AllowInitializationUI; }
499                                 set { Inner.AllowInitializationUI = value; }
500                         }
501
502                         public bool DidInteractiveInitialization {
503                                 get { return Inner.DidInteractiveInitialization; }
504                         }
505
506                         public Uri Via {
507                                 get { return Inner.Via; }
508                         }
509
510                         public IAsyncResult BeginDisplayInitializationUI (
511                                 AsyncCallback callback, object state)
512                         {
513                                 return Inner.BeginDisplayInitializationUI (callback, state);
514                         }
515
516                         public void EndDisplayInitializationUI (
517                                 IAsyncResult result)
518                         {
519                                 Inner.EndDisplayInitializationUI (result);
520                         }
521
522                         public void DisplayInitializationUI ()
523                         {
524                                 Inner.DisplayInitializationUI ();
525                         }
526
527                         public void Dispose ()
528                         {
529                                 Inner.Dispose ();
530                         }
531
532                         public event EventHandler<UnknownMessageReceivedEventArgs> UnknownMessageReceived {
533                                 add { Inner.UnknownMessageReceived += value; }
534                                 remove { Inner.UnknownMessageReceived -= value; }
535                         }
536
537                         #endregion
538
539                         #region IContextChannel
540
541                         [MonoTODO]
542                         public bool AllowOutputBatching {
543                                 get { return Inner.AllowOutputBatching; }
544
545                                 set { Inner.AllowOutputBatching = value; }
546                         }
547
548                         [MonoTODO]
549                         public IInputSession InputSession {
550                                 get { return Inner.InputSession; }
551                         }
552
553                         public EndpointAddress LocalAddress {
554                                 get { return Inner.LocalAddress; }
555                         }
556
557                         [MonoTODO]
558                         public TimeSpan OperationTimeout {
559                                 get { return Inner.OperationTimeout; }
560                                 set { Inner.OperationTimeout = value; }
561                         }
562
563                         [MonoTODO]
564                         public IOutputSession OutputSession {
565                                 get { return Inner.OutputSession; }
566                         }
567
568                         public EndpointAddress RemoteAddress {
569                                 get { return Inner.RemoteAddress; }
570                         }
571
572                         [MonoTODO]
573                         public string SessionId {
574                                 get { return Inner.SessionId; }
575                         }
576
577                         #endregion
578
579                         #region IRequestChannel
580
581                         IAsyncResult IRequestChannel.BeginRequest (Message message, AsyncCallback callback, object state)
582                         {
583                                 return ((IRequestChannel) this).BeginRequest (message, endpoint.Binding.SendTimeout, callback, state);
584                         }
585
586                         IAsyncResult IRequestChannel.BeginRequest (Message message, TimeSpan timeout, AsyncCallback callback, object state)
587                         {
588                                 return Inner.BeginRequest (message, timeout, callback, state);
589                         }
590
591                         Message IRequestChannel.EndRequest (IAsyncResult result)
592                         {
593                                 return Inner.EndRequest (result);
594                         }
595
596                         Message IRequestChannel.Request (Message message)
597                         {
598                                 return ((IRequestChannel) this).Request (message, endpoint.Binding.SendTimeout);
599                         }
600
601                         Message IRequestChannel.Request (Message message, TimeSpan timeout)
602                         {
603                                 return Inner.Request (message, timeout);
604                         }
605
606                         EndpointAddress IRequestChannel.RemoteAddress {
607                                 get { return endpoint.Address; }
608                         }
609
610                         Uri IRequestChannel.Via {
611                                 get { return Via; }
612                         }
613
614                         #endregion
615
616                         #region IOutputChannel
617
618                         IAsyncResult IOutputChannel.BeginSend (Message message, AsyncCallback callback, object state)
619                         {
620                                 return ((IOutputChannel) this).BeginSend (message, endpoint.Binding.SendTimeout, callback, state);
621                         }
622
623                         IAsyncResult IOutputChannel.BeginSend (Message message, TimeSpan timeout, AsyncCallback callback, object state)
624                         {
625                                 return Inner.BeginSend (message, timeout, callback, state);
626                         }
627
628                         void IOutputChannel.EndSend (IAsyncResult result)
629                         {
630                                 Inner.EndSend (result);
631                         }
632
633                         void IOutputChannel.Send (Message message)
634                         {
635                                 ((IOutputChannel) this).Send (message, endpoint.Binding.SendTimeout);
636                         }
637
638                         void IOutputChannel.Send (Message message, TimeSpan timeout)
639                         {
640                                 Inner.Send (message, timeout);
641                         }
642
643                         #endregion
644
645                         IExtensionCollection<IContextChannel> IExtensibleObject<IContextChannel>.Extensions {
646                                 get { return Inner.Extensions; }
647                         }
648
649                         TProperty IChannel.GetProperty<TProperty> ()
650                         {
651                                 return Inner.GetProperty<TProperty> ();
652                         }
653                 }
654         }
655 }