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