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 callbackInstance)
79 : this (callbackInstance, "*")
83 protected ClientBase (InstanceContext callbackInstance, string endpointConfigurationName)
85 if (callbackInstance == null)
86 throw new ArgumentNullException ("instanceContext");
87 if (endpointConfigurationName == null)
88 throw new ArgumentNullException ("endpointConfigurationName");
90 Initialize (callbackInstance, endpointConfigurationName, null);
93 protected ClientBase (InstanceContext callbackInstance,
94 string endpointConfigurationName, EndpointAddress remoteAddress)
96 if (callbackInstance == null)
97 throw new ArgumentNullException ("instanceContext");
98 if (endpointConfigurationName == null)
99 throw new ArgumentNullException ("endpointConfigurationName");
100 if (remoteAddress == null)
101 throw new ArgumentNullException ("remoteAddress");
103 Initialize (callbackInstance, endpointConfigurationName, remoteAddress);
106 protected ClientBase (InstanceContext callbackInstance,
107 string endpointConfigurationName, string remoteAddress)
109 if (callbackInstance == null)
110 throw new ArgumentNullException ("instanceContext");
111 if (remoteAddress == null)
112 throw new ArgumentNullException ("endpointAddress");
113 if (endpointConfigurationName == null)
114 throw new ArgumentNullException ("endpointConfigurationName");
116 Initialize (callbackInstance, endpointConfigurationName, new EndpointAddress (remoteAddress));
119 protected ClientBase (InstanceContext callbackInstance,
120 Binding binding, EndpointAddress remoteAddress)
122 if (callbackInstance == null)
123 throw new ArgumentNullException ("instanceContext");
125 throw new ArgumentNullException ("binding");
126 if (remoteAddress == null)
127 throw new ArgumentNullException ("remoteAddress");
129 Initialize (callbackInstance, binding, remoteAddress);
132 protected ClientBase (ServiceEndpoint endpoint)
133 : this (null, endpoint)
137 protected ClientBase (InstanceContext callbackInstance, ServiceEndpoint endpoint)
138 : this (callbackInstance, new ChannelFactory<TChannel> (endpoint))
142 internal ClientBase (ChannelFactory<TChannel> factory)
143 : this (null, factory)
147 internal ClientBase (InstanceContext instance, ChannelFactory<TChannel> factory)
149 // FIXME: use instance
150 ChannelFactory = factory;
153 internal virtual void Initialize (InstanceContext instance,
154 string endpointConfigurationName, EndpointAddress remoteAddress)
156 // FIXME: use instance
157 ChannelFactory = new ChannelFactory<TChannel> (endpointConfigurationName, remoteAddress);
160 internal virtual void Initialize (InstanceContext instance,
161 Binding binding, EndpointAddress remoteAddress)
163 // FIXME: use instance
164 ChannelFactory = new ChannelFactory<TChannel> (binding, remoteAddress);
167 public ChannelFactory<TChannel> ChannelFactory {
168 get { return factory; }
171 factory.OwnerClientBase = this;
175 public ClientCredentials ClientCredentials {
176 get { return ChannelFactory.Credentials; }
179 public ServiceEndpoint Endpoint {
180 get { return factory.Endpoint; }
183 public IClientChannel InnerChannel {
185 if (inner_channel == null)
186 inner_channel = (IClientChannel) (object) CreateChannel ();
187 return inner_channel;
191 protected TChannel Channel {
192 get { return (TChannel) (object) InnerChannel; }
195 public CommunicationState State {
196 get { return inner_channel != null ? inner_channel.State : CommunicationState.Created; }
201 InnerChannel.Abort ();
206 InnerChannel.Close ();
209 public void DisplayInitializationUI ()
211 InnerChannel.DisplayInitializationUI ();
214 protected T GetDefaultValueForInitialization<T> ()
219 //IAsyncResult delegate_async;
221 void RunCompletedCallback (SendOrPostCallback callback, InvokeAsyncCompletedEventArgs args)
226 protected void InvokeAsync (BeginOperationDelegate beginOperationDelegate,
227 object [] inValues, EndOperationDelegate endOperationDelegate,
228 SendOrPostCallback operationCompletedCallback, object userState)
230 if (beginOperationDelegate == null)
231 throw new ArgumentNullException ("beginOperationDelegate");
232 if (endOperationDelegate == null)
233 throw new ArgumentNullException ("endOperationDelegate");
234 //if (delegate_async != null)
235 // throw new InvalidOperationException ("Another async operation is in progress");
237 AsyncCallback cb = delegate (IAsyncResult ar) {
238 object [] results = null;
239 Exception error = null;
240 bool cancelled = false; // FIXME: fill it in case it is cancelled
242 results = endOperationDelegate (ar);
243 } catch (Exception ex) {
247 if (operationCompletedCallback != null)
248 RunCompletedCallback (operationCompletedCallback, new InvokeAsyncCompletedEventArgs (results, error, cancelled, userState));
249 } catch (Exception ex) {
250 //Console.WriteLine ("Exception during operationCompletedCallback" + ex);
253 //Console.WriteLine ("System.ServiceModel.ClientBase<TChannel>: web service invocation is successfully done (operationCompletedCallback may not be).");
255 begin_async_result = beginOperationDelegate (inValues, cb, userState);
257 IAsyncResult begin_async_result;
259 void IDisposable.Dispose ()
264 protected virtual TChannel CreateChannel ()
266 return ChannelFactory.CreateChannel ();
271 InnerChannel.Open ();
274 #region ICommunicationObject implementation
276 IAsyncResult ICommunicationObject.BeginOpen (
277 AsyncCallback callback, object state)
279 return InnerChannel.BeginOpen (callback, state);
282 IAsyncResult ICommunicationObject.BeginOpen (
283 TimeSpan timeout, AsyncCallback callback, object state)
285 return InnerChannel.BeginOpen (timeout, callback, state);
288 void ICommunicationObject.EndOpen (IAsyncResult result)
290 InnerChannel.EndOpen (result);
293 IAsyncResult ICommunicationObject.BeginClose (
294 AsyncCallback callback, object state)
296 return InnerChannel.BeginClose (callback, state);
299 IAsyncResult ICommunicationObject.BeginClose (
300 TimeSpan timeout, AsyncCallback callback, object state)
302 return InnerChannel.BeginClose (timeout, callback, state);
305 void ICommunicationObject.EndClose (IAsyncResult result)
307 InnerChannel.EndClose (result);
310 void ICommunicationObject.Close (TimeSpan timeout)
312 InnerChannel.Close (timeout);
315 void ICommunicationObject.Open (TimeSpan timeout)
317 InnerChannel.Open (timeout);
320 event EventHandler ICommunicationObject.Opening {
321 add { InnerChannel.Opening += value; }
322 remove { InnerChannel.Opening -= value; }
324 event EventHandler ICommunicationObject.Opened {
325 add { InnerChannel.Opened += value; }
326 remove { InnerChannel.Opened -= value; }
328 event EventHandler ICommunicationObject.Closing {
329 add { InnerChannel.Closing += value; }
330 remove { InnerChannel.Closing -= value; }
332 event EventHandler ICommunicationObject.Closed {
333 add { InnerChannel.Closed += value; }
334 remove { InnerChannel.Closed -= value; }
336 event EventHandler ICommunicationObject.Faulted {
337 add { InnerChannel.Faulted += value; }
338 remove { InnerChannel.Faulted -= value; }
343 protected class InvokeAsyncCompletedEventArgs : AsyncCompletedEventArgs
345 internal InvokeAsyncCompletedEventArgs (object [] results, Exception error, bool cancelled, object userState)
346 : base (error, cancelled, userState)
351 public object [] Results { get; private set; }
355 class ChannelBase<T> : IClientChannel, IOutputChannel, IRequestChannel where T : class
357 ServiceEndpoint endpoint;
358 ChannelFactory factory;
359 ClientRuntimeChannel inner_channel;
361 protected ChannelBase (ClientBase<T> client)
362 : this (client.Endpoint, client.ChannelFactory)
366 internal ChannelBase (ServiceEndpoint endpoint, ChannelFactory factory)
368 this.endpoint = endpoint;
369 this.factory = factory;
372 internal ClientRuntimeChannel Inner {
374 if (inner_channel == null)
375 inner_channel = new ClientRuntimeChannel (endpoint, factory, endpoint.Address, null);
376 return inner_channel;
380 protected object Invoke (string methodName, object [] args)
382 var cd = endpoint.Contract;
383 var od = cd.Operations.Find (methodName);
385 throw new ArgumentException (String.Format ("Operation '{0}' not found in the service contract '{1}' in namespace '{2}'", methodName, cd.Name, cd.Namespace));
386 return Inner.Process (od.SyncMethod, methodName, args, OperationContext.Current);
389 protected IAsyncResult BeginInvoke (string methodName, object [] args, AsyncCallback callback, object state)
391 var cd = endpoint.Contract;
392 var od = cd.Operations.Find (methodName);
394 throw new ArgumentException (String.Format ("Operation '{0}' not found in the service contract '{1}' in namespace '{2}'", methodName, cd.Name, cd.Namespace));
395 return Inner.BeginProcess (od.BeginMethod, methodName, args, callback, state);
398 protected object EndInvoke (string methodName, object [] args, IAsyncResult result)
400 var cd = endpoint.Contract;
401 var od = cd.Operations.Find (methodName);
403 throw new ArgumentException (String.Format ("Operation '{0}' not found in the service contract '{1}' in namespace '{2}'", methodName, cd.Name, cd.Namespace));
404 return Inner.EndProcess (od.EndMethod, methodName, args, result);
407 #region ICommunicationObject
409 IAsyncResult ICommunicationObject.BeginClose (AsyncCallback callback, object state)
411 return Inner.BeginClose (callback, state);
414 IAsyncResult ICommunicationObject.BeginClose (TimeSpan timeout, AsyncCallback callback, object state)
416 return Inner.BeginClose (timeout, callback, state);
419 void ICommunicationObject.Close ()
424 void ICommunicationObject.Close (TimeSpan timeout)
426 Inner.Close (timeout);
429 IAsyncResult ICommunicationObject.BeginOpen (AsyncCallback callback, object state)
431 return Inner.BeginOpen (callback, state);
434 IAsyncResult ICommunicationObject.BeginOpen (TimeSpan timeout, AsyncCallback callback, object state)
436 return Inner.BeginOpen (timeout, callback, state);
439 void ICommunicationObject.Open ()
444 void ICommunicationObject.Open (TimeSpan timeout)
446 Inner.Open (timeout);
449 void ICommunicationObject.Abort ()
454 void ICommunicationObject.EndClose (IAsyncResult result)
456 Inner.EndClose (result);
459 void ICommunicationObject.EndOpen (IAsyncResult result)
461 Inner.EndOpen (result);
464 CommunicationState ICommunicationObject.State {
465 get { return Inner.State; }
468 event EventHandler ICommunicationObject.Opened {
469 add { Inner.Opened += value; }
470 remove { Inner.Opened -= value; }
473 event EventHandler ICommunicationObject.Opening {
474 add { Inner.Opening += value; }
475 remove { Inner.Opening -= value; }
478 event EventHandler ICommunicationObject.Closed {
479 add { Inner.Closed += value; }
480 remove { Inner.Closed -= value; }
483 event EventHandler ICommunicationObject.Closing {
484 add { Inner.Closing += value; }
485 remove { Inner.Closing -= value; }
488 event EventHandler ICommunicationObject.Faulted {
489 add { Inner.Faulted += value; }
490 remove { Inner.Faulted -= value; }
495 #region IClientChannel
497 public bool AllowInitializationUI {
498 get { return Inner.AllowInitializationUI; }
499 set { Inner.AllowInitializationUI = value; }
502 public bool DidInteractiveInitialization {
503 get { return Inner.DidInteractiveInitialization; }
507 get { return Inner.Via; }
510 public IAsyncResult BeginDisplayInitializationUI (
511 AsyncCallback callback, object state)
513 return Inner.BeginDisplayInitializationUI (callback, state);
516 public void EndDisplayInitializationUI (
519 Inner.EndDisplayInitializationUI (result);
522 public void DisplayInitializationUI ()
524 Inner.DisplayInitializationUI ();
527 public void Dispose ()
532 public event EventHandler<UnknownMessageReceivedEventArgs> UnknownMessageReceived {
533 add { Inner.UnknownMessageReceived += value; }
534 remove { Inner.UnknownMessageReceived -= value; }
539 #region IContextChannel
542 public bool AllowOutputBatching {
543 get { return Inner.AllowOutputBatching; }
545 set { Inner.AllowOutputBatching = value; }
549 public IInputSession InputSession {
550 get { return Inner.InputSession; }
553 public EndpointAddress LocalAddress {
554 get { return Inner.LocalAddress; }
558 public TimeSpan OperationTimeout {
559 get { return Inner.OperationTimeout; }
560 set { Inner.OperationTimeout = value; }
564 public IOutputSession OutputSession {
565 get { return Inner.OutputSession; }
568 public EndpointAddress RemoteAddress {
569 get { return Inner.RemoteAddress; }
573 public string SessionId {
574 get { return Inner.SessionId; }
579 #region IRequestChannel
581 IAsyncResult IRequestChannel.BeginRequest (Message message, AsyncCallback callback, object state)
583 return ((IRequestChannel) this).BeginRequest (message, endpoint.Binding.SendTimeout, callback, state);
586 IAsyncResult IRequestChannel.BeginRequest (Message message, TimeSpan timeout, AsyncCallback callback, object state)
588 return Inner.BeginRequest (message, timeout, callback, state);
591 Message IRequestChannel.EndRequest (IAsyncResult result)
593 return Inner.EndRequest (result);
596 Message IRequestChannel.Request (Message message)
598 return ((IRequestChannel) this).Request (message, endpoint.Binding.SendTimeout);
601 Message IRequestChannel.Request (Message message, TimeSpan timeout)
603 return Inner.Request (message, timeout);
606 EndpointAddress IRequestChannel.RemoteAddress {
607 get { return endpoint.Address; }
610 Uri IRequestChannel.Via {
616 #region IOutputChannel
618 IAsyncResult IOutputChannel.BeginSend (Message message, AsyncCallback callback, object state)
620 return ((IOutputChannel) this).BeginSend (message, endpoint.Binding.SendTimeout, callback, state);
623 IAsyncResult IOutputChannel.BeginSend (Message message, TimeSpan timeout, AsyncCallback callback, object state)
625 return Inner.BeginSend (message, timeout, callback, state);
628 void IOutputChannel.EndSend (IAsyncResult result)
630 Inner.EndSend (result);
633 void IOutputChannel.Send (Message message)
635 ((IOutputChannel) this).Send (message, endpoint.Binding.SendTimeout);
638 void IOutputChannel.Send (Message message, TimeSpan timeout)
640 Inner.Send (message, timeout);
645 IExtensionCollection<IContextChannel> IExtensibleObject<IContextChannel>.Extensions {
646 get { return Inner.Extensions; }
649 TProperty IChannel.GetProperty<TProperty> ()
651 return Inner.GetProperty<TProperty> ();