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> :
43 ICommunicationObject where TChannel : class
45 static InstanceContext initialContxt = new InstanceContext (null);
47 ChannelFactory<TChannel> factory;
48 IClientChannel inner_channel;
50 protected delegate IAsyncResult BeginOperationDelegate (object[] inValues, AsyncCallback asyncCallback, object state);
51 protected delegate object[] EndOperationDelegate (IAsyncResult result);
53 protected ClientBase ()
54 : this (initialContxt)
58 protected ClientBase (string endpointConfigurationName)
59 : this (initialContxt, endpointConfigurationName)
63 protected ClientBase (Binding binding, EndpointAddress remoteAddress)
64 : this (initialContxt, binding, remoteAddress)
68 protected ClientBase (string endpointConfigurationName, EndpointAddress remoteAddress)
69 : this (initialContxt, endpointConfigurationName, remoteAddress)
73 protected ClientBase (string endpointConfigurationName, string remoteAddress)
74 : this (initialContxt, endpointConfigurationName, remoteAddress)
78 protected ClientBase (InstanceContext instance)
79 : this (instance, "*")
83 protected ClientBase (InstanceContext instance, string endpointConfigurationName)
86 throw new ArgumentNullException ("instanceContext");
87 if (endpointConfigurationName == null)
88 throw new ArgumentNullException ("endpointConfigurationName");
90 Initialize (instance, endpointConfigurationName, null);
93 protected ClientBase (InstanceContext instance,
94 string endpointConfigurationName, EndpointAddress remoteAddress)
97 throw new ArgumentNullException ("instanceContext");
98 if (endpointConfigurationName == null)
99 throw new ArgumentNullException ("endpointConfigurationName");
100 if (remoteAddress == null)
101 throw new ArgumentNullException ("remoteAddress");
103 Initialize (instance, endpointConfigurationName, remoteAddress);
106 protected ClientBase (InstanceContext instance,
107 string endpointConfigurationName, string remoteAddress)
109 if (instance == null)
110 throw new ArgumentNullException ("instanceContext");
111 if (remoteAddress == null)
112 throw new ArgumentNullException ("endpointAddress");
113 if (endpointConfigurationName == null)
114 throw new ArgumentNullException ("endpointConfigurationName");
116 Initialize (instance, endpointConfigurationName, new EndpointAddress (remoteAddress));
119 protected ClientBase (InstanceContext instance,
120 Binding binding, EndpointAddress remoteAddress)
122 if (instance == null)
123 throw new ArgumentNullException ("instanceContext");
125 throw new ArgumentNullException ("binding");
126 if (remoteAddress == null)
127 throw new ArgumentNullException ("remoteAddress");
129 Initialize (instance, binding, remoteAddress);
133 protected ClientBase (ServiceEndpoint endpoint)
134 : this (null, endpoint)
138 protected ClientBase (InstanceContext instance, ServiceEndpoint endpoint)
139 : this (instance, new ChannelFactory<TChannel> (endpoint))
144 internal ClientBase (ChannelFactory<TChannel> factory)
145 : this (null, factory)
149 internal ClientBase (InstanceContext instance, ChannelFactory<TChannel> factory)
151 // FIXME: use instance
152 ChannelFactory = factory;
155 internal virtual void Initialize (InstanceContext instance,
156 string endpointConfigurationName, EndpointAddress remoteAddress)
158 // FIXME: use instance
159 ChannelFactory = new ChannelFactory<TChannel> (endpointConfigurationName, remoteAddress);
162 internal virtual void Initialize (InstanceContext instance,
163 Binding binding, EndpointAddress remoteAddress)
165 // FIXME: use instance
166 ChannelFactory = new ChannelFactory<TChannel> (binding, remoteAddress);
169 public ChannelFactory<TChannel> ChannelFactory {
170 get { return factory; }
173 factory.OwnerClientBase = this;
177 public ClientCredentials ClientCredentials {
178 get { return ChannelFactory.Credentials; }
181 public ServiceEndpoint Endpoint {
182 get { return factory.Endpoint; }
185 public IClientChannel InnerChannel {
187 if (inner_channel == null)
188 inner_channel = (IClientChannel) (object) CreateChannel ();
189 return inner_channel;
193 protected TChannel Channel {
194 get { return (TChannel) (object) InnerChannel; }
197 public CommunicationState State {
198 get { return inner_channel != null ? inner_channel.State : CommunicationState.Created; }
203 InnerChannel.Abort ();
208 InnerChannel.Close ();
211 public void DisplayInitializationUI ()
213 InnerChannel.DisplayInitializationUI ();
216 protected T GetDefaultValueForInitialization<T> ()
221 //IAsyncResult delegate_async;
223 void RunCompletedCallback (SendOrPostCallback callback, InvokeAsyncCompletedEventArgs args)
228 protected void InvokeAsync (BeginOperationDelegate beginOperationDelegate,
229 object [] inValues, EndOperationDelegate endOperationDelegate,
230 SendOrPostCallback operationCompletedCallback, object userState)
232 if (beginOperationDelegate == null)
233 throw new ArgumentNullException ("beginOperationDelegate");
234 if (endOperationDelegate == null)
235 throw new ArgumentNullException ("endOperationDelegate");
236 //if (delegate_async != null)
237 // throw new InvalidOperationException ("Another async operation is in progress");
239 AsyncCallback cb = delegate (IAsyncResult ar) {
240 object [] results = null;
241 Exception error = null;
242 bool cancelled = false; // FIXME: fill it in case it is cancelled
244 results = endOperationDelegate (ar);
245 } catch (Exception ex) {
249 if (operationCompletedCallback != null)
250 RunCompletedCallback (operationCompletedCallback, new InvokeAsyncCompletedEventArgs (results, error, cancelled, userState));
251 } catch (Exception ex) {
252 //Console.WriteLine ("Exception during operationCompletedCallback" + ex);
255 //Console.WriteLine ("System.ServiceModel.ClientBase<TChannel>: web service invocation is successfully done (operationCompletedCallback may not be).");
257 begin_async_result = beginOperationDelegate (inValues, cb, userState);
259 IAsyncResult begin_async_result;
261 void IDisposable.Dispose ()
266 protected virtual TChannel CreateChannel ()
268 return ChannelFactory.CreateChannel ();
273 InnerChannel.Open ();
276 #region ICommunicationObject implementation
278 IAsyncResult ICommunicationObject.BeginOpen (
279 AsyncCallback callback, object state)
281 return InnerChannel.BeginOpen (callback, state);
284 IAsyncResult ICommunicationObject.BeginOpen (
285 TimeSpan timeout, AsyncCallback callback, object state)
287 return InnerChannel.BeginOpen (timeout, callback, state);
290 void ICommunicationObject.EndOpen (IAsyncResult result)
292 InnerChannel.EndOpen (result);
295 IAsyncResult ICommunicationObject.BeginClose (
296 AsyncCallback callback, object state)
298 return InnerChannel.BeginClose (callback, state);
301 IAsyncResult ICommunicationObject.BeginClose (
302 TimeSpan timeout, AsyncCallback callback, object state)
304 return InnerChannel.BeginClose (timeout, callback, state);
307 void ICommunicationObject.EndClose (IAsyncResult result)
309 InnerChannel.EndClose (result);
312 void ICommunicationObject.Close (TimeSpan timeout)
314 InnerChannel.Close (timeout);
317 void ICommunicationObject.Open (TimeSpan timeout)
319 InnerChannel.Open (timeout);
322 event EventHandler ICommunicationObject.Opening {
323 add { InnerChannel.Opening += value; }
324 remove { InnerChannel.Opening -= value; }
326 event EventHandler ICommunicationObject.Opened {
327 add { InnerChannel.Opened += value; }
328 remove { InnerChannel.Opened -= value; }
330 event EventHandler ICommunicationObject.Closing {
331 add { InnerChannel.Closing += value; }
332 remove { InnerChannel.Closing -= value; }
334 event EventHandler ICommunicationObject.Closed {
335 add { InnerChannel.Closed += value; }
336 remove { InnerChannel.Closed -= value; }
338 event EventHandler ICommunicationObject.Faulted {
339 add { InnerChannel.Faulted += value; }
340 remove { InnerChannel.Faulted -= value; }
345 protected class InvokeAsyncCompletedEventArgs : AsyncCompletedEventArgs
347 internal InvokeAsyncCompletedEventArgs (object [] results, Exception error, bool cancelled, object userState)
348 : base (error, cancelled, userState)
353 public object [] Results { get; private set; }
361 class ChannelBase<T> : IClientChannel, IOutputChannel, IRequestChannel where T : class
363 ServiceEndpoint endpoint;
364 ChannelFactory factory;
365 ClientRuntimeChannel inner_channel;
367 protected ChannelBase (ClientBase<T> client)
368 : this (client.Endpoint, client.ChannelFactory)
372 internal ChannelBase (ServiceEndpoint endpoint, ChannelFactory factory)
374 this.endpoint = endpoint;
375 this.factory = factory;
378 internal ClientRuntimeChannel Inner {
380 if (inner_channel == null)
381 inner_channel = new ClientRuntimeChannel (endpoint, factory, endpoint.Address, null);
382 return inner_channel;
386 protected object Invoke (string methodName, object [] args)
388 var cd = endpoint.Contract;
389 var od = cd.Operations.Find (methodName);
391 throw new ArgumentException (String.Format ("Operation '{0}' not found in the service contract '{1}' in namespace '{2}'", methodName, cd.Name, cd.Namespace));
392 return Inner.Process (od.SyncMethod, methodName, args);
395 protected IAsyncResult BeginInvoke (string methodName, object [] args, AsyncCallback callback, object state)
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.BeginProcess (od.BeginMethod, methodName, args, callback, state);
404 protected object EndInvoke (string methodName, object [] args, IAsyncResult result)
406 var cd = endpoint.Contract;
407 var od = cd.Operations.Find (methodName);
409 throw new ArgumentException (String.Format ("Operation '{0}' not found in the service contract '{1}' in namespace '{2}'", methodName, cd.Name, cd.Namespace));
410 return Inner.EndProcess (od.EndMethod, methodName, args, result);
413 #region ICommunicationObject
415 IAsyncResult ICommunicationObject.BeginClose (AsyncCallback callback, object state)
417 return Inner.BeginClose (callback, state);
420 IAsyncResult ICommunicationObject.BeginClose (TimeSpan timeout, AsyncCallback callback, object state)
422 return Inner.BeginClose (timeout, callback, state);
425 void ICommunicationObject.Close ()
430 void ICommunicationObject.Close (TimeSpan timeout)
432 Inner.Close (timeout);
435 IAsyncResult ICommunicationObject.BeginOpen (AsyncCallback callback, object state)
437 return Inner.BeginOpen (callback, state);
440 IAsyncResult ICommunicationObject.BeginOpen (TimeSpan timeout, AsyncCallback callback, object state)
442 return Inner.BeginOpen (timeout, callback, state);
445 void ICommunicationObject.Open ()
450 void ICommunicationObject.Open (TimeSpan timeout)
452 Inner.Open (timeout);
455 void ICommunicationObject.Abort ()
460 void ICommunicationObject.EndClose (IAsyncResult result)
462 Inner.EndClose (result);
465 void ICommunicationObject.EndOpen (IAsyncResult result)
467 Inner.EndOpen (result);
470 CommunicationState ICommunicationObject.State {
471 get { return Inner.State; }
474 event EventHandler ICommunicationObject.Opened {
475 add { Inner.Opened += value; }
476 remove { Inner.Opened -= value; }
479 event EventHandler ICommunicationObject.Opening {
480 add { Inner.Opening += value; }
481 remove { Inner.Opening -= value; }
484 event EventHandler ICommunicationObject.Closed {
485 add { Inner.Closed += value; }
486 remove { Inner.Closed -= value; }
489 event EventHandler ICommunicationObject.Closing {
490 add { Inner.Closing += value; }
491 remove { Inner.Closing -= value; }
494 event EventHandler ICommunicationObject.Faulted {
495 add { Inner.Faulted += value; }
496 remove { Inner.Faulted -= value; }
501 #region IClientChannel
503 public bool AllowInitializationUI {
504 get { return Inner.AllowInitializationUI; }
505 set { Inner.AllowInitializationUI = value; }
508 public bool DidInteractiveInitialization {
509 get { return Inner.DidInteractiveInitialization; }
513 get { return Inner.Via; }
516 public IAsyncResult BeginDisplayInitializationUI (
517 AsyncCallback callback, object state)
519 return Inner.BeginDisplayInitializationUI (callback, state);
522 public void EndDisplayInitializationUI (
525 Inner.EndDisplayInitializationUI (result);
528 public void DisplayInitializationUI ()
530 Inner.DisplayInitializationUI ();
533 public void Dispose ()
538 public event EventHandler<UnknownMessageReceivedEventArgs> UnknownMessageReceived {
539 add { Inner.UnknownMessageReceived += value; }
540 remove { Inner.UnknownMessageReceived -= value; }
545 #region IContextChannel
548 public bool AllowOutputBatching {
549 get { return Inner.AllowOutputBatching; }
551 set { Inner.AllowOutputBatching = value; }
555 public IInputSession InputSession {
556 get { return Inner.InputSession; }
559 public EndpointAddress LocalAddress {
560 get { return Inner.LocalAddress; }
564 public TimeSpan OperationTimeout {
565 get { return Inner.OperationTimeout; }
566 set { Inner.OperationTimeout = value; }
570 public IOutputSession OutputSession {
571 get { return Inner.OutputSession; }
574 public EndpointAddress RemoteAddress {
575 get { return Inner.RemoteAddress; }
579 public string SessionId {
580 get { return Inner.SessionId; }
585 #region IRequestChannel
587 IAsyncResult IRequestChannel.BeginRequest (Message message, AsyncCallback callback, object state)
589 return ((IRequestChannel) this).BeginRequest (message, endpoint.Binding.SendTimeout, callback, state);
592 IAsyncResult IRequestChannel.BeginRequest (Message message, TimeSpan timeout, AsyncCallback callback, object state)
594 return Inner.BeginRequest (message, timeout, callback, state);
597 Message IRequestChannel.EndRequest (IAsyncResult result)
599 return Inner.EndRequest (result);
602 Message IRequestChannel.Request (Message message)
604 return ((IRequestChannel) this).Request (message, endpoint.Binding.SendTimeout);
607 Message IRequestChannel.Request (Message message, TimeSpan timeout)
609 return Inner.Request (message, timeout);
612 EndpointAddress IRequestChannel.RemoteAddress {
613 get { return endpoint.Address; }
616 Uri IRequestChannel.Via {
622 #region IOutputChannel
624 IAsyncResult IOutputChannel.BeginSend (Message message, AsyncCallback callback, object state)
626 return ((IOutputChannel) this).BeginSend (message, endpoint.Binding.SendTimeout, callback, state);
629 IAsyncResult IOutputChannel.BeginSend (Message message, TimeSpan timeout, AsyncCallback callback, object state)
631 return Inner.BeginSend (message, timeout, callback, state);
634 void IOutputChannel.EndSend (IAsyncResult result)
636 Inner.EndSend (result);
639 void IOutputChannel.Send (Message message)
641 ((IOutputChannel) this).Send (message, endpoint.Binding.SendTimeout);
644 void IOutputChannel.Send (Message message, TimeSpan timeout)
646 Inner.Send (message, timeout);
651 IExtensionCollection<IContextChannel> IExtensibleObject<IContextChannel>.Extensions {
652 get { return Inner.Extensions; }
655 TProperty IChannel.GetProperty<TProperty> ()
657 return Inner.GetProperty<TProperty> ();