2 // generic ClientBase.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2005-2006 Novell, Inc. http://www.novell.com
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
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;
38 namespace System.ServiceModel
40 [MonoTODO ("It somehow rejects classes, but dunno how we can do that besides our code wise.")]
41 public abstract class ClientBase<TChannel> :
45 ICommunicationObject where TChannel : class
47 static InstanceContext initialContxt = new InstanceContext (null);
49 ChannelFactory<TChannel> factory;
50 IClientChannel inner_channel;
52 protected delegate IAsyncResult BeginOperationDelegate (object[] inValues, AsyncCallback asyncCallback, object state);
53 protected delegate object[] EndOperationDelegate (IAsyncResult result);
55 protected ClientBase ()
56 : this (initialContxt)
60 protected ClientBase (string endpointConfigurationName)
61 : this (initialContxt, endpointConfigurationName)
65 protected ClientBase (Binding binding, EndpointAddress remoteAddress)
66 : this (initialContxt, binding, remoteAddress)
70 protected ClientBase (string endpointConfigurationName, EndpointAddress remoteAddress)
71 : this (initialContxt, endpointConfigurationName, remoteAddress)
75 protected ClientBase (string endpointConfigurationName, string remoteAddress)
76 : this (initialContxt, endpointConfigurationName, remoteAddress)
80 protected ClientBase (InstanceContext instance)
81 : this (instance, "*")
85 protected ClientBase (InstanceContext instance, string endpointConfigurationName)
88 throw new ArgumentNullException ("instanceContext");
89 if (endpointConfigurationName == null)
90 throw new ArgumentNullException ("endpointConfigurationName");
92 Initialize (instance, endpointConfigurationName, null);
95 protected ClientBase (InstanceContext instance,
96 string endpointConfigurationName, EndpointAddress remoteAddress)
99 throw new ArgumentNullException ("instanceContext");
100 if (endpointConfigurationName == null)
101 throw new ArgumentNullException ("endpointConfigurationName");
102 if (remoteAddress == null)
103 throw new ArgumentNullException ("remoteAddress");
105 Initialize (instance, endpointConfigurationName, remoteAddress);
108 protected ClientBase (InstanceContext instance,
109 string endpointConfigurationName, string remoteAddress)
111 if (instance == null)
112 throw new ArgumentNullException ("instanceContext");
113 if (remoteAddress == null)
114 throw new ArgumentNullException ("endpointAddress");
115 if (endpointConfigurationName == null)
116 throw new ArgumentNullException ("endpointConfigurationName");
118 Initialize (instance, endpointConfigurationName, new EndpointAddress (remoteAddress));
121 protected ClientBase (InstanceContext instance,
122 Binding binding, EndpointAddress remoteAddress)
124 if (instance == null)
125 throw new ArgumentNullException ("instanceContext");
127 throw new ArgumentNullException ("binding");
128 if (remoteAddress == null)
129 throw new ArgumentNullException ("remoteAddress");
131 Initialize (instance, binding, remoteAddress);
135 protected ClientBase (ServiceEndpoint endpoint)
136 : this (null, endpoint)
140 protected ClientBase (InstanceContext instance, ServiceEndpoint endpoint)
141 : this (instance, new ChannelFactory<TChannel> (endpoint))
146 internal ClientBase (ChannelFactory<TChannel> factory)
147 : this (null, factory)
151 internal ClientBase (InstanceContext instance, ChannelFactory<TChannel> factory)
153 // FIXME: use instance
154 ChannelFactory = factory;
157 internal virtual void Initialize (InstanceContext instance,
158 string endpointConfigurationName, EndpointAddress remoteAddress)
160 // FIXME: use instance
161 ChannelFactory = new ChannelFactory<TChannel> (endpointConfigurationName, remoteAddress);
164 internal virtual void Initialize (InstanceContext instance,
165 Binding binding, EndpointAddress remoteAddress)
167 // FIXME: use instance
168 ChannelFactory = new ChannelFactory<TChannel> (binding, remoteAddress);
171 public ChannelFactory<TChannel> ChannelFactory {
172 get { return factory; }
175 factory.OwnerClientBase = this;
179 public ClientCredentials ClientCredentials {
180 get { return ChannelFactory.Credentials; }
183 public ServiceEndpoint Endpoint {
184 get { return factory.Endpoint; }
187 public IClientChannel InnerChannel {
189 if (inner_channel == null)
190 inner_channel = (IClientChannel) (object) CreateChannel ();
191 return inner_channel;
195 protected TChannel Channel {
196 get { return (TChannel) (object) InnerChannel; }
199 public CommunicationState State {
200 get { return inner_channel != null ? inner_channel.State : CommunicationState.Created; }
205 InnerChannel.Abort ();
210 InnerChannel.Close ();
213 public void DisplayInitializationUI ()
215 InnerChannel.DisplayInitializationUI ();
218 protected T GetDefaultValueForInitialization<T> ()
223 //IAsyncResult delegate_async;
225 void RunCompletedCallback (SendOrPostCallback callback, InvokeAsyncCompletedEventArgs args)
230 // this ensure the "dirty" work is done in mscorlib and "frees" this assembly from any [SC] or [SSC] code
231 Mono.MoonlightHelper.RunOnMainThread (callback, args);
235 protected void InvokeAsync (BeginOperationDelegate beginOperationDelegate,
236 object [] inValues, EndOperationDelegate endOperationDelegate,
237 SendOrPostCallback operationCompletedCallback, object userState)
239 if (beginOperationDelegate == null)
240 throw new ArgumentNullException ("beginOperationDelegate");
241 if (endOperationDelegate == null)
242 throw new ArgumentNullException ("endOperationDelegate");
243 //if (delegate_async != null)
244 // throw new InvalidOperationException ("Another async operation is in progress");
246 AsyncCallback cb = delegate (IAsyncResult ar) {
247 object [] results = null;
248 Exception error = null;
249 bool cancelled = false; // FIXME: fill it in case it is cancelled
251 results = endOperationDelegate (ar);
252 } catch (Exception ex) {
256 if (operationCompletedCallback != null)
257 RunCompletedCallback (operationCompletedCallback, new InvokeAsyncCompletedEventArgs (results, error, cancelled, userState));
258 } catch (Exception ex) {
259 //Console.WriteLine ("Exception during operationCompletedCallback" + ex);
262 //Console.WriteLine ("System.ServiceModel.ClientBase<TChannel>: web service invocation is successfully done (operationCompletedCallback may not be).");
264 begin_async_result = beginOperationDelegate (inValues, cb, userState);
266 IAsyncResult begin_async_result;
269 void IDisposable.Dispose ()
274 protected virtual TChannel CreateChannel ()
276 return ChannelFactory.CreateChannel ();
281 InnerChannel.Open ();
284 #region ICommunicationObject implementation
286 IAsyncResult ICommunicationObject.BeginOpen (
287 AsyncCallback callback, object state)
289 return InnerChannel.BeginOpen (callback, state);
292 IAsyncResult ICommunicationObject.BeginOpen (
293 TimeSpan timeout, AsyncCallback callback, object state)
295 return InnerChannel.BeginOpen (timeout, callback, state);
298 void ICommunicationObject.EndOpen (IAsyncResult result)
300 InnerChannel.EndOpen (result);
303 IAsyncResult ICommunicationObject.BeginClose (
304 AsyncCallback callback, object state)
306 return InnerChannel.BeginClose (callback, state);
309 IAsyncResult ICommunicationObject.BeginClose (
310 TimeSpan timeout, AsyncCallback callback, object state)
312 return InnerChannel.BeginClose (timeout, callback, state);
315 void ICommunicationObject.EndClose (IAsyncResult result)
317 InnerChannel.EndClose (result);
320 void ICommunicationObject.Close (TimeSpan timeout)
322 InnerChannel.Close (timeout);
325 void ICommunicationObject.Open (TimeSpan timeout)
327 InnerChannel.Open (timeout);
330 event EventHandler ICommunicationObject.Opening {
331 add { InnerChannel.Opening += value; }
332 remove { InnerChannel.Opening -= value; }
334 event EventHandler ICommunicationObject.Opened {
335 add { InnerChannel.Opened += value; }
336 remove { InnerChannel.Opened -= value; }
338 event EventHandler ICommunicationObject.Closing {
339 add { InnerChannel.Closing += value; }
340 remove { InnerChannel.Closing -= value; }
342 event EventHandler ICommunicationObject.Closed {
343 add { InnerChannel.Closed += value; }
344 remove { InnerChannel.Closed -= value; }
346 event EventHandler ICommunicationObject.Faulted {
347 add { InnerChannel.Faulted += value; }
348 remove { InnerChannel.Faulted -= value; }
353 protected class InvokeAsyncCompletedEventArgs : AsyncCompletedEventArgs
355 internal InvokeAsyncCompletedEventArgs (object [] results, Exception error, bool cancelled, object userState)
356 : base (error, cancelled, userState)
361 public object [] Results { get; private set; }
369 class ChannelBase<T> : IClientChannel, IOutputChannel, IRequestChannel where T : class
371 ServiceEndpoint endpoint;
372 ChannelFactory factory;
373 ClientRuntimeChannel inner_channel;
375 protected ChannelBase (ClientBase<T> client)
376 : this (client.Endpoint, client.ChannelFactory)
380 internal ChannelBase (ServiceEndpoint endpoint, ChannelFactory factory)
382 this.endpoint = endpoint;
383 this.factory = factory;
386 internal ClientRuntimeChannel Inner {
388 if (inner_channel == null)
389 inner_channel = new ClientRuntimeChannel (endpoint, factory, endpoint.Address, null);
390 return inner_channel;
395 protected object Invoke (string methodName, object [] args)
397 var cd = endpoint.Contract;
398 var od = cd.Operations.Find (methodName);
400 throw new ArgumentException (String.Format ("Operation '{0}' not found in the service contract '{1}' in namespace '{2}'", methodName, cd.Name, cd.Namespace));
401 return Inner.Process (od.SyncMethod, methodName, args);
405 protected IAsyncResult BeginInvoke (string methodName, object [] args, AsyncCallback callback, object state)
407 var cd = endpoint.Contract;
408 var od = cd.Operations.Find (methodName);
410 throw new ArgumentException (String.Format ("Operation '{0}' not found in the service contract '{1}' in namespace '{2}'", methodName, cd.Name, cd.Namespace));
411 return Inner.BeginProcess (od.BeginMethod, methodName, args, callback, state);
414 protected object EndInvoke (string methodName, object [] args, IAsyncResult result)
416 var cd = endpoint.Contract;
417 var od = cd.Operations.Find (methodName);
419 throw new ArgumentException (String.Format ("Operation '{0}' not found in the service contract '{1}' in namespace '{2}'", methodName, cd.Name, cd.Namespace));
420 return Inner.EndProcess (od.EndMethod, methodName, args, result);
423 #region ICommunicationObject
425 IAsyncResult ICommunicationObject.BeginClose (AsyncCallback callback, object state)
427 return Inner.BeginClose (callback, state);
430 IAsyncResult ICommunicationObject.BeginClose (TimeSpan timeout, AsyncCallback callback, object state)
432 return Inner.BeginClose (timeout, callback, state);
435 void ICommunicationObject.Close ()
440 void ICommunicationObject.Close (TimeSpan timeout)
442 Inner.Close (timeout);
445 IAsyncResult ICommunicationObject.BeginOpen (AsyncCallback callback, object state)
447 return Inner.BeginOpen (callback, state);
450 IAsyncResult ICommunicationObject.BeginOpen (TimeSpan timeout, AsyncCallback callback, object state)
452 return Inner.BeginOpen (timeout, callback, state);
455 void ICommunicationObject.Open ()
460 void ICommunicationObject.Open (TimeSpan timeout)
462 Inner.Open (timeout);
465 void ICommunicationObject.Abort ()
470 void ICommunicationObject.EndClose (IAsyncResult result)
472 Inner.EndClose (result);
475 void ICommunicationObject.EndOpen (IAsyncResult result)
477 Inner.EndOpen (result);
480 CommunicationState ICommunicationObject.State {
481 get { return Inner.State; }
484 event EventHandler ICommunicationObject.Opened {
485 add { Inner.Opened += value; }
486 remove { Inner.Opened -= value; }
489 event EventHandler ICommunicationObject.Opening {
490 add { Inner.Opening += value; }
491 remove { Inner.Opening -= value; }
494 event EventHandler ICommunicationObject.Closed {
495 add { Inner.Closed += value; }
496 remove { Inner.Closed -= value; }
499 event EventHandler ICommunicationObject.Closing {
500 add { Inner.Closing += value; }
501 remove { Inner.Closing -= value; }
504 event EventHandler ICommunicationObject.Faulted {
505 add { Inner.Faulted += value; }
506 remove { Inner.Faulted -= value; }
511 #region IClientChannel
513 public bool AllowInitializationUI {
514 get { return Inner.AllowInitializationUI; }
515 set { Inner.AllowInitializationUI = value; }
518 public bool DidInteractiveInitialization {
519 get { return Inner.DidInteractiveInitialization; }
523 get { return Inner.Via; }
526 public IAsyncResult BeginDisplayInitializationUI (
527 AsyncCallback callback, object state)
529 return Inner.BeginDisplayInitializationUI (callback, state);
532 public void EndDisplayInitializationUI (
535 Inner.EndDisplayInitializationUI (result);
538 public void DisplayInitializationUI ()
540 Inner.DisplayInitializationUI ();
543 public void Dispose ()
548 public event EventHandler<UnknownMessageReceivedEventArgs> UnknownMessageReceived {
549 add { Inner.UnknownMessageReceived += value; }
550 remove { Inner.UnknownMessageReceived -= value; }
555 #region IContextChannel
558 public bool AllowOutputBatching {
559 get { return Inner.AllowOutputBatching; }
561 set { Inner.AllowOutputBatching = value; }
565 public IInputSession InputSession {
566 get { return Inner.InputSession; }
569 public EndpointAddress LocalAddress {
570 get { return Inner.LocalAddress; }
574 public TimeSpan OperationTimeout {
575 get { return Inner.OperationTimeout; }
576 set { Inner.OperationTimeout = value; }
580 public IOutputSession OutputSession {
581 get { return Inner.OutputSession; }
584 public EndpointAddress RemoteAddress {
585 get { return Inner.RemoteAddress; }
589 public string SessionId {
590 get { return Inner.SessionId; }
595 #region IRequestChannel
597 IAsyncResult IRequestChannel.BeginRequest (Message message, AsyncCallback callback, object state)
599 return ((IRequestChannel) this).BeginRequest (message, endpoint.Binding.SendTimeout, callback, state);
602 IAsyncResult IRequestChannel.BeginRequest (Message message, TimeSpan timeout, AsyncCallback callback, object state)
604 return Inner.BeginRequest (message, timeout, callback, state);
607 Message IRequestChannel.EndRequest (IAsyncResult result)
609 return Inner.EndRequest (result);
612 Message IRequestChannel.Request (Message message)
614 return ((IRequestChannel) this).Request (message, endpoint.Binding.SendTimeout);
617 Message IRequestChannel.Request (Message message, TimeSpan timeout)
619 return Inner.Request (message, timeout);
622 EndpointAddress IRequestChannel.RemoteAddress {
623 get { return endpoint.Address; }
626 Uri IRequestChannel.Via {
632 #region IOutputChannel
634 IAsyncResult IOutputChannel.BeginSend (Message message, AsyncCallback callback, object state)
636 return ((IOutputChannel) this).BeginSend (message, endpoint.Binding.SendTimeout, callback, state);
639 IAsyncResult IOutputChannel.BeginSend (Message message, TimeSpan timeout, AsyncCallback callback, object state)
641 return Inner.BeginSend (message, timeout, callback, state);
644 void IOutputChannel.EndSend (IAsyncResult result)
646 Inner.EndSend (result);
649 void IOutputChannel.Send (Message message)
651 ((IOutputChannel) this).Send (message, endpoint.Binding.SendTimeout);
654 void IOutputChannel.Send (Message message, TimeSpan timeout)
656 Inner.Send (message, timeout);
661 IExtensionCollection<IContextChannel> IExtensibleObject<IContextChannel>.Extensions {
662 get { return Inner.Extensions; }
665 TProperty IChannel.GetProperty<TProperty> ()
667 return Inner.GetProperty<TProperty> ();