2 // ClientRuntimeChannel.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 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.Reflection;
30 using System.ServiceModel.Channels;
31 using System.ServiceModel.Description;
32 using System.ServiceModel.Dispatcher;
33 using System.ServiceModel.Security;
35 namespace System.ServiceModel
43 class ClientRuntimeChannel
44 : CommunicationObject, IClientChannel
46 ClientRuntime runtime;
47 ChannelFactory factory;
48 IRequestChannel request_channel;
49 IOutputChannel output_channel;
50 readonly ProcessDelegate _processDelegate;
52 delegate object ProcessDelegate (MethodBase method, string operationName, object [] parameters);
54 public ClientRuntimeChannel (ClientRuntime runtime,
55 ChannelFactory factory)
57 this.runtime = runtime;
58 this.factory = factory;
59 _processDelegate = new ProcessDelegate (Process);
62 public ClientRuntime Runtime {
63 get { return runtime; }
66 #region IClientChannel
69 public bool AllowInitializationUI {
70 get { throw new NotImplementedException (); }
71 set { throw new NotImplementedException (); }
75 public bool DidInteractiveInitialization {
76 get { throw new NotImplementedException (); }
80 get { return runtime.Via; }
84 public IAsyncResult BeginDisplayInitializationUI (
85 AsyncCallback callback, object state)
87 throw new NotImplementedException ();
91 public void EndDisplayInitializationUI (
94 throw new NotImplementedException ();
98 public void DisplayInitializationUI ()
100 throw new NotImplementedException ();
103 public void Dispose ()
108 public event EventHandler<UnknownMessageReceivedEventArgs> UnknownMessageReceived;
112 #region IContextChannel
115 public bool AllowOutputBatching {
116 get { throw new NotImplementedException (); }
117 set { throw new NotImplementedException (); }
121 public IInputSession InputSession {
122 get { throw new NotImplementedException (); }
126 public EndpointAddress LocalAddress {
127 get { throw new NotImplementedException (); }
131 public TimeSpan OperationTimeout {
132 get { throw new NotImplementedException (); }
133 set { throw new NotImplementedException (); }
137 public IOutputSession OutputSession {
138 get { throw new NotImplementedException (); }
142 public EndpointAddress RemoteAddress {
143 get { throw new NotImplementedException (); }
147 public string SessionId {
148 get { throw new NotImplementedException (); }
153 // CommunicationObject
154 protected internal override TimeSpan DefaultOpenTimeout {
155 get { return factory.DefaultOpenTimeout; }
158 protected internal override TimeSpan DefaultCloseTimeout {
159 get { return factory.DefaultCloseTimeout; }
162 protected override void OnAbort ()
167 protected override IAsyncResult OnBeginClose (
168 TimeSpan timeout, AsyncCallback callback, object state)
170 return factory.BeginClose (timeout, callback, state);
173 protected override void OnEndClose (IAsyncResult result)
175 factory.EndClose (result);
178 protected override void OnClose (TimeSpan timeout)
180 factory.Close (timeout);
183 protected override IAsyncResult OnBeginOpen (
184 TimeSpan timeout, AsyncCallback callback, object state)
186 throw new SystemException ("INTERNAL ERROR: this should not be called (or not supported yet)");
189 protected override void OnEndOpen (IAsyncResult result)
193 protected override void OnOpen (TimeSpan timeout)
198 public T GetProperty<T> () where T : class
200 return factory.GetProperty<T> ();
203 // IExtensibleObject<IContextChannel>
205 public IExtensionCollection<IContextChannel> Extensions {
206 get { throw new NotImplementedException (); }
209 #region Request/Output processing
211 public IAsyncResult BeginProcess (MethodBase method, string operationName, object [] parameters) {
212 object [] param = new object [parameters.Length - 2];
213 for (int i = 0; i < param.Length; i++)
214 param [i] = parameters [i];
215 return _processDelegate.BeginInvoke (method, operationName, param, (AsyncCallback) parameters [parameters.Length - 2], parameters [parameters.Length - 1]);
218 public object EndProcess (MethodBase method, string operationName, object [] parameters) {
219 return _processDelegate.EndInvoke ((IAsyncResult) parameters [0]);
222 public object Process (MethodBase method, string operationName, object [] parameters)
224 OperationDescription od = SelectOperation (method, operationName, parameters);
226 return Request (od, parameters);
228 Output (od, parameters);
233 OperationDescription SelectOperation (MethodBase method, string operationName, object [] parameters)
236 if (Runtime.OperationSelector != null)
237 operation = Runtime.OperationSelector.SelectOperation (method, parameters);
239 operation = operationName;
240 OperationDescription od = factory.Endpoint.Contract.Operations.Find (operation);
242 throw new Exception (String.Format ("OperationDescription for operation '{0}' was not found in its internally-generated contract.", operation));
246 BindingParameterCollection CreateBindingParameters ()
248 BindingParameterCollection pl =
249 new BindingParameterCollection ();
251 ContractDescription cd = factory.Endpoint.Contract;
253 pl.Add (ChannelProtectionRequirements.CreateFromContract (cd));
255 foreach (IEndpointBehavior behavior in factory.Endpoint.Behaviors)
256 behavior.AddBindingParameters (factory.Endpoint, pl);
262 void SetupOutputChannel ()
264 if (output_channel != null)
266 BindingParameterCollection pl =
267 CreateBindingParameters ();
268 bool session = false;
269 switch (factory.Endpoint.Contract.SessionMode) {
270 case SessionMode.Required:
271 session = factory.Endpoint.Binding.CanBuildChannelFactory<IOutputSessionChannel> (pl);
273 throw new InvalidOperationException ("The contract requires session support, but the binding does not support it.");
275 case SessionMode.Allowed:
276 session = !factory.Endpoint.Binding.CanBuildChannelFactory<IOutputChannel> (pl);
280 EndpointAddress address = factory.Endpoint.Address;
281 Uri via = Runtime.Via;
284 IChannelFactory<IOutputSessionChannel> f =
285 factory.Endpoint.Binding.BuildChannelFactory<IOutputSessionChannel> (pl);
287 output_channel = f.CreateChannel (address, via);
289 IChannelFactory<IOutputChannel> f =
290 factory.Endpoint.Binding.BuildChannelFactory<IOutputChannel> (pl);
292 output_channel = f.CreateChannel (address, via);
295 output_channel.Open ();
298 void SetupRequestChannel ()
300 if (request_channel != null)
303 BindingParameterCollection pl =
304 CreateBindingParameters ();
305 bool session = false;
306 switch (factory.Endpoint.Contract.SessionMode) {
307 case SessionMode.Required:
308 session = factory.Endpoint.Binding.CanBuildChannelFactory<IRequestSessionChannel> (pl);
310 throw new InvalidOperationException ("The contract requires session support, but the binding does not support it.");
312 case SessionMode.Allowed:
313 session = !factory.Endpoint.Binding.CanBuildChannelFactory<IRequestChannel> (pl);
317 EndpointAddress address = factory.Endpoint.Address;
318 Uri via = Runtime.Via;
321 IChannelFactory<IRequestSessionChannel> f =
322 factory.Endpoint.Binding.BuildChannelFactory<IRequestSessionChannel> (pl);
324 request_channel = f.CreateChannel (address, via);
326 IChannelFactory<IRequestChannel> f =
327 factory.Endpoint.Binding.BuildChannelFactory<IRequestChannel> (pl);
329 request_channel = f.CreateChannel (address, via);
332 request_channel.Open ();
335 void Output (OperationDescription od, object [] parameters)
337 SetupOutputChannel ();
339 ClientOperation op = runtime.Operations [od.Name];
340 Output (CreateRequest (op, parameters));
343 object Request (OperationDescription od, object [] parameters)
345 SetupRequestChannel ();
347 ClientOperation op = runtime.Operations [od.Name];
348 object [] inspections = new object [runtime.MessageInspectors.Count];
349 Message req = CreateRequest (op, parameters);
351 for (int i = 0; i < inspections.Length; i++)
352 inspections [i] = runtime.MessageInspectors [i].BeforeSendRequest (ref req, this);
354 Message res = Request (req);
356 MessageFault fault = MessageFault.CreateFault (res, runtime.MaxFaultSize);
357 if (fault.HasDetail && fault is MessageFault.SimpleMessageFault) {
358 MessageFault.SimpleMessageFault simpleFault = fault as MessageFault.SimpleMessageFault;
359 object detail = simpleFault.Detail;
360 Type t = detail.GetType ();
361 Type faultType = typeof (FaultException<>).MakeGenericType (t);
362 object [] constructorParams = new object [] { detail, fault.Reason, fault.Code, fault.Actor };
363 FaultException fe = (FaultException) Activator.CreateInstance (faultType, constructorParams);
367 // given a MessageFault, it is hard to figure out the type of the embedded detail
368 throw new FaultException(fault);
372 for (int i = 0; i < inspections.Length; i++)
373 runtime.MessageInspectors [i].AfterReceiveReply (ref res, inspections [i]);
375 if (op.DeserializeReply)
376 return op.GetFormatter ().DeserializeReply (res, parameters);
381 Message Request (Message msg)
383 return request_channel.Request (msg, factory.Endpoint.Binding.SendTimeout);
386 void Output (Message msg)
388 output_channel.Send (msg, factory.Endpoint.Binding.SendTimeout);
391 Message CreateRequest (ClientOperation op, object [] parameters)
393 MessageVersion version = factory.Endpoint.Binding.MessageVersion;
395 version = MessageVersion.Default;
397 if (op.SerializeRequest)
398 return op.GetFormatter ().SerializeRequest (
399 version, parameters);
401 return (Message) parameters [0];