5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2005 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.Collections.ObjectModel;
31 using System.ServiceModel.Channels;
32 using System.ServiceModel.Description;
33 using System.ServiceModel.Dispatcher;
34 using System.ServiceModel.Security;
35 using System.Configuration;
36 using System.ServiceModel.Configuration;
39 namespace System.ServiceModel
41 public abstract class ChannelFactory : CommunicationObject,
42 IChannelFactory, ICommunicationObject, IDisposable
46 ServiceEndpoint service_endpoint;
47 IChannelFactory factory;
48 List<IClientChannel> opened_channels = new List<IClientChannel> ();
50 protected ChannelFactory ()
54 internal IChannelFactory OpenedChannelFactory {
56 if (factory == null) {
57 factory = CreateFactory ();
68 internal List<IClientChannel> OpenedChannels {
69 get { return opened_channels; }
72 public ServiceEndpoint Endpoint {
73 get { return service_endpoint; }
76 public ClientCredentials Credentials {
77 get { return Endpoint.Behaviors.Find<ClientCredentials> (); }
80 protected internal override TimeSpan DefaultCloseTimeout {
81 get { return Endpoint.Binding.CloseTimeout; }
84 protected internal override TimeSpan DefaultOpenTimeout {
85 get { return Endpoint.Binding.OpenTimeout; }
88 protected virtual void ApplyConfiguration (string endpointConfig)
90 if (endpointConfig == null)
95 // It should automatically use XmlXapResolver
96 var cfg = new SilverlightClientConfigLoader ().Load (XmlReader.Create ("ServiceReferences.ClientConfig"));
98 SilverlightClientConfigLoader.ServiceEndpointConfiguration se = null;
99 if (endpointConfig == "*")
100 se = cfg.GetServiceEndpointConfiguration (Endpoint.Contract.Name);
102 se = cfg.GetServiceEndpointConfiguration (endpointConfig);
104 if (se.Binding != null && Endpoint.Binding == null)
105 Endpoint.Binding = se.Binding;
107 Console.WriteLine ("WARNING: Configured binding not found in configuration {0}", endpointConfig);
108 if (se.Address != null && Endpoint.Address == null)
109 Endpoint.Address = se.Address;
111 Console.WriteLine ("WARNING: Configured endpoint address not found in configuration {0}", endpointConfig);
112 } catch (Exception) {
114 Console.WriteLine ("WARNING: failed to load endpoint configuration for {0}", endpointConfig);
118 string contractName = Endpoint.Contract.ConfigurationName;
119 ClientSection client = ConfigUtil.ClientSection;
120 ChannelEndpointElement endpoint = null;
122 foreach (ChannelEndpointElement el in client.Endpoints) {
123 if (el.Contract == contractName && (endpointConfig == el.Name || endpointConfig == "*")) {
124 if (endpoint != null)
125 throw new InvalidOperationException (String.Format ("More then one endpoint matching contract {0} was found.", contractName));
130 if (endpoint == null)
131 throw new InvalidOperationException (String.Format ("Client endpoint configuration '{0}' was not found in {1} endpoints.", endpointConfig, client.Endpoints.Count));
134 var binding = String.IsNullOrEmpty (endpoint.Binding) ? null : ConfigUtil.CreateBinding (endpoint.Binding, endpoint.BindingConfiguration);
135 var contractType = ConfigUtil.GetTypeFromConfigString (endpoint.Contract, NamedConfigCategory.Contract);
136 if (contractType == null)
137 throw new ArgumentException (String.Format ("Contract '{0}' was not found", endpoint.Contract));
138 var contract = String.IsNullOrEmpty (endpoint.Contract) ? Endpoint.Contract : ContractDescription.GetContract (contractType);
140 if (!String.IsNullOrEmpty (endpoint.Kind)) {
141 var se = ConfigUtil.ConfigureStandardEndpoint (contract, endpoint);
142 if (se.Binding == null)
143 se.Binding = binding;
144 if (se.Address == null && se.Binding != null) // standard endpoint might have empty address
145 se.Address = new EndpointAddress (endpoint.Address);
146 if (se.Binding == null && se.Address != null) // look for protocol mapping
147 se.Binding = ConfigUtil.GetBindingByProtocolMapping (se.Address.Uri);
149 service_endpoint = se;
151 if (binding == null && endpoint.Address != null) // look for protocol mapping
152 Endpoint.Binding = ConfigUtil.GetBindingByProtocolMapping (endpoint.Address);
155 if (Endpoint.Binding == null)
156 Endpoint.Binding = ConfigUtil.CreateBinding (endpoint.Binding, endpoint.BindingConfiguration);
157 if (Endpoint.Address == null)
158 Endpoint.Address = new EndpointAddress (endpoint.Address);
160 if (endpoint.BehaviorConfiguration != "")
161 ApplyBehavior (endpoint.BehaviorConfiguration);
166 private void ApplyBehavior (string behaviorConfig)
168 BehaviorsSection behaviorsSection = ConfigUtil.BehaviorsSection;
169 EndpointBehaviorElement behaviorElement = behaviorsSection.EndpointBehaviors [behaviorConfig];
171 foreach (BehaviorExtensionElement el in behaviorElement) {
172 IEndpointBehavior behavior = (IEndpointBehavior) el.CreateBehavior ();
173 Endpoint.Behaviors.Remove (behavior.GetType ());
174 Endpoint.Behaviors.Add (behavior);
179 protected virtual IChannelFactory CreateFactory ()
181 bool isOneWay = true; // check OperationDescription.IsOneWay
182 foreach (var od in Endpoint.Contract.Operations)
188 BindingParameterCollection pl = CreateBindingParameters ();
190 // the assumption on the type of created channel could
191 // be wrong, but would mostly fit the actual
192 // requirements. No books have explained how it is done.
195 switch (Endpoint.Contract.SessionMode) {
196 case SessionMode.Required:
197 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexSessionChannel> (pl))
198 return Endpoint.Binding.BuildChannelFactory<IDuplexSessionChannel> (pl);
200 case SessionMode.Allowed:
201 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
202 return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
203 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexSessionChannel> (pl))
204 return Endpoint.Binding.BuildChannelFactory<IDuplexSessionChannel> (pl);
207 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
208 return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
212 if (Endpoint.Contract.CallbackContractType != null)
213 throw new InvalidOperationException ("The binding does not support duplex channel types that the contract requies for CallbackContractType.");
216 switch (Endpoint.Contract.SessionMode) {
217 case SessionMode.Required:
218 if (Endpoint.Binding.CanBuildChannelFactory<IOutputSessionChannel> (pl))
219 return Endpoint.Binding.BuildChannelFactory<IOutputSessionChannel> (pl);
220 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexSessionChannel> (pl))
221 return Endpoint.Binding.BuildChannelFactory<IDuplexSessionChannel> (pl);
223 case SessionMode.Allowed:
224 if (Endpoint.Binding.CanBuildChannelFactory<IOutputChannel> (pl))
225 return Endpoint.Binding.BuildChannelFactory<IOutputChannel> (pl);
226 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
227 return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
228 goto case SessionMode.Required;
230 if (Endpoint.Binding.CanBuildChannelFactory<IOutputChannel> (pl))
231 return Endpoint.Binding.BuildChannelFactory<IOutputChannel> (pl);
232 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
233 return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
237 // both OneWay and non-OneWay contracts fall into here.
239 switch (Endpoint.Contract.SessionMode) {
240 case SessionMode.Required:
241 if (Endpoint.Binding.CanBuildChannelFactory<IRequestSessionChannel> (pl))
242 return Endpoint.Binding.BuildChannelFactory<IRequestSessionChannel> (pl);
244 case SessionMode.Allowed:
245 if (Endpoint.Binding.CanBuildChannelFactory<IRequestChannel> (pl))
246 return Endpoint.Binding.BuildChannelFactory<IRequestChannel> (pl);
247 if (Endpoint.Binding.CanBuildChannelFactory<IRequestSessionChannel> (pl))
248 return Endpoint.Binding.BuildChannelFactory<IRequestSessionChannel> (pl);
251 if (Endpoint.Binding.CanBuildChannelFactory<IRequestChannel> (pl))
252 return Endpoint.Binding.BuildChannelFactory<IRequestChannel> (pl);
256 throw new InvalidOperationException (String.Format ("The binding does not support any of the channel types that the contract '{0}' allows.", Endpoint.Contract.Name));
259 BindingParameterCollection CreateBindingParameters ()
261 BindingParameterCollection pl =
262 new BindingParameterCollection ();
264 ContractDescription cd = Endpoint.Contract;
266 pl.Add (ChannelProtectionRequirements.CreateFromContract (cd));
269 foreach (IEndpointBehavior behavior in Endpoint.Behaviors)
270 behavior.AddBindingParameters (Endpoint, pl);
275 protected abstract ServiceEndpoint CreateDescription ();
277 void IDisposable.Dispose ()
282 public T GetProperty<T> () where T : class
284 if (OpenedChannelFactory != null)
285 return OpenedChannelFactory.GetProperty<T> ();
289 protected void EnsureOpened ()
291 if (Endpoint == null)
292 throw new InvalidOperationException ("A service endpoint must be configured for this channel factory");
293 if (Endpoint.Contract == null)
294 throw new InvalidOperationException ("A service Contract must be configured for this channel factory");
295 if (Endpoint.Binding == null)
296 throw new InvalidOperationException ("A Binding must be configured for this channel factory");
298 if (State != CommunicationState.Opened)
302 protected void InitializeEndpoint (
303 string endpointConfigurationName,
304 EndpointAddress remoteAddress)
306 InitializeEndpoint (CreateDescription ());
307 if (remoteAddress != null)
308 service_endpoint.Address = remoteAddress;
309 ApplyConfiguration (endpointConfigurationName);
312 protected void InitializeEndpoint (Binding binding,
313 EndpointAddress remoteAddress)
315 InitializeEndpoint (CreateDescription ());
317 service_endpoint.Binding = binding;
318 if (remoteAddress != null)
319 service_endpoint.Address = remoteAddress;
322 protected void InitializeEndpoint (ServiceEndpoint endpoint)
324 if (endpoint == null)
325 throw new ArgumentNullException ("endpoint");
326 service_endpoint = endpoint;
329 protected override void OnAbort ()
331 if (OpenedChannelFactory != null)
332 OpenedChannelFactory.Abort ();
335 Action<TimeSpan> close_delegate;
336 Action<TimeSpan> open_delegate;
339 protected override IAsyncResult OnBeginClose (
340 TimeSpan timeout, AsyncCallback callback, object state)
342 if (close_delegate == null)
343 close_delegate = new Action<TimeSpan> (OnClose);
344 return close_delegate.BeginInvoke (timeout, callback, state);
347 protected override IAsyncResult OnBeginOpen (
348 TimeSpan timeout, AsyncCallback callback, object state)
350 if (open_delegate == null)
351 open_delegate = new Action<TimeSpan> (OnClose);
352 return open_delegate.BeginInvoke (timeout, callback, state);
355 protected override void OnEndClose (IAsyncResult result)
357 if (close_delegate == null)
358 throw new InvalidOperationException ("Async close operation has not started");
359 close_delegate.EndInvoke (result);
362 protected override void OnEndOpen (IAsyncResult result)
364 if (open_delegate == null)
365 throw new InvalidOperationException ("Async close operation has not started");
366 open_delegate.EndInvoke (result);
369 protected override void OnClose (TimeSpan timeout)
371 DateTime start = DateTime.Now;
372 foreach (var ch in opened_channels.ToArray ())
373 ch.Close (timeout - (DateTime.Now - start));
374 if (OpenedChannelFactory != null)
375 OpenedChannelFactory.Close (timeout - (DateTime.Now - start));
378 protected override void OnOpen (TimeSpan timeout)
382 protected override void OnOpening ()
385 OpenedChannelFactory = CreateFactory ();
388 protected override void OnOpened ()
391 OpenedChannelFactory.Open ();
397 interface UninitializedContract
400 void ItShouldReallyGone ();