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