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 contract = String.IsNullOrEmpty (endpoint.Contract) ? Endpoint.Contract : ContractDescription.GetContract (ConfigUtil.GetTypeFromConfigString (endpoint.Contract));
137 if (!String.IsNullOrEmpty (endpoint.Kind)) {
138 var se = ConfigUtil.ConfigureStandardEndpoint (contract, endpoint);
139 if (se.Binding == null)
140 se.Binding = binding;
141 if (se.Address == null && se.Binding != null) // standard endpoint might have empty address
142 se.Address = new EndpointAddress (endpoint.Address);
143 if (se.Binding == null && se.Address != null) // look for protocol mapping
144 se.Binding = ConfigUtil.GetBindingByProtocolMapping (se.Address.Uri);
146 service_endpoint = se;
148 if (binding == null && endpoint.Address != null) // look for protocol mapping
149 Endpoint.Binding = ConfigUtil.GetBindingByProtocolMapping (endpoint.Address);
152 if (Endpoint.Binding == null)
153 Endpoint.Binding = ConfigUtil.CreateBinding (endpoint.Binding, endpoint.BindingConfiguration);
154 if (Endpoint.Address == null)
155 Endpoint.Address = new EndpointAddress (endpoint.Address);
157 if (endpoint.BehaviorConfiguration != "")
158 ApplyBehavior (endpoint.BehaviorConfiguration);
163 private void ApplyBehavior (string behaviorConfig)
165 BehaviorsSection behaviorsSection = ConfigUtil.BehaviorsSection;
166 EndpointBehaviorElement behaviorElement = behaviorsSection.EndpointBehaviors [behaviorConfig];
168 foreach (BehaviorExtensionElement el in behaviorElement) {
169 IEndpointBehavior behavior = (IEndpointBehavior) el.CreateBehavior ();
170 Endpoint.Behaviors.Remove (behavior.GetType ());
171 Endpoint.Behaviors.Add (behavior);
176 protected virtual IChannelFactory CreateFactory ()
178 bool isOneWay = true; // check OperationDescription.IsOneWay
179 foreach (var od in Endpoint.Contract.Operations)
185 BindingParameterCollection pl = CreateBindingParameters ();
187 // the assumption on the type of created channel could
188 // be wrong, but would mostly fit the actual
189 // requirements. No books have explained how it is done.
192 switch (Endpoint.Contract.SessionMode) {
193 case SessionMode.Required:
194 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexSessionChannel> (pl))
195 return Endpoint.Binding.BuildChannelFactory<IDuplexSessionChannel> (pl);
197 case SessionMode.Allowed:
198 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
199 return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
200 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexSessionChannel> (pl))
201 return Endpoint.Binding.BuildChannelFactory<IDuplexSessionChannel> (pl);
204 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
205 return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
209 if (Endpoint.Contract.CallbackContractType != null)
210 throw new InvalidOperationException ("The binding does not support duplex channel types that the contract requies for CallbackContractType.");
213 switch (Endpoint.Contract.SessionMode) {
214 case SessionMode.Required:
215 if (Endpoint.Binding.CanBuildChannelFactory<IOutputSessionChannel> (pl))
216 return Endpoint.Binding.BuildChannelFactory<IOutputSessionChannel> (pl);
217 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexSessionChannel> (pl))
218 return Endpoint.Binding.BuildChannelFactory<IDuplexSessionChannel> (pl);
220 case SessionMode.Allowed:
221 if (Endpoint.Binding.CanBuildChannelFactory<IOutputChannel> (pl))
222 return Endpoint.Binding.BuildChannelFactory<IOutputChannel> (pl);
223 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
224 return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
225 goto case SessionMode.Required;
227 if (Endpoint.Binding.CanBuildChannelFactory<IOutputChannel> (pl))
228 return Endpoint.Binding.BuildChannelFactory<IOutputChannel> (pl);
229 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
230 return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
234 // both OneWay and non-OneWay contracts fall into here.
236 switch (Endpoint.Contract.SessionMode) {
237 case SessionMode.Required:
238 if (Endpoint.Binding.CanBuildChannelFactory<IRequestSessionChannel> (pl))
239 return Endpoint.Binding.BuildChannelFactory<IRequestSessionChannel> (pl);
241 case SessionMode.Allowed:
242 if (Endpoint.Binding.CanBuildChannelFactory<IRequestChannel> (pl))
243 return Endpoint.Binding.BuildChannelFactory<IRequestChannel> (pl);
244 if (Endpoint.Binding.CanBuildChannelFactory<IRequestSessionChannel> (pl))
245 return Endpoint.Binding.BuildChannelFactory<IRequestSessionChannel> (pl);
248 if (Endpoint.Binding.CanBuildChannelFactory<IRequestChannel> (pl))
249 return Endpoint.Binding.BuildChannelFactory<IRequestChannel> (pl);
253 throw new InvalidOperationException (String.Format ("The binding does not support any of the channel types that the contract '{0}' allows.", Endpoint.Contract.Name));
256 BindingParameterCollection CreateBindingParameters ()
258 BindingParameterCollection pl =
259 new BindingParameterCollection ();
261 ContractDescription cd = Endpoint.Contract;
263 pl.Add (ChannelProtectionRequirements.CreateFromContract (cd));
265 foreach (IEndpointBehavior behavior in Endpoint.Behaviors)
266 behavior.AddBindingParameters (Endpoint, pl);
272 protected abstract ServiceEndpoint CreateDescription ();
274 void IDisposable.Dispose ()
279 public T GetProperty<T> () where T : class
281 if (OpenedChannelFactory != null)
282 OpenedChannelFactory.GetProperty<T> ();
286 protected void EnsureOpened ()
288 if (Endpoint == null)
289 throw new InvalidOperationException ("A service endpoint must be configured for this channel factory");
290 if (Endpoint.Contract == null)
291 throw new InvalidOperationException ("A service Contract must be configured for this channel factory");
292 if (Endpoint.Binding == null)
293 throw new InvalidOperationException ("A Binding must be configured for this channel factory");
295 if (State != CommunicationState.Opened)
299 protected void InitializeEndpoint (
300 string endpointConfigurationName,
301 EndpointAddress remoteAddress)
303 InitializeEndpoint (CreateDescription ());
304 if (remoteAddress != null)
305 service_endpoint.Address = remoteAddress;
306 ApplyConfiguration (endpointConfigurationName);
309 protected void InitializeEndpoint (Binding binding,
310 EndpointAddress remoteAddress)
312 InitializeEndpoint (CreateDescription ());
314 service_endpoint.Binding = binding;
315 if (remoteAddress != null)
316 service_endpoint.Address = remoteAddress;
319 protected void InitializeEndpoint (ServiceEndpoint endpoint)
321 if (endpoint == null)
322 throw new ArgumentNullException ("endpoint");
323 service_endpoint = endpoint;
326 protected override void OnAbort ()
328 if (OpenedChannelFactory != null)
329 OpenedChannelFactory.Abort ();
332 Action<TimeSpan> close_delegate;
333 Action<TimeSpan> open_delegate;
336 protected override IAsyncResult OnBeginClose (
337 TimeSpan timeout, AsyncCallback callback, object state)
339 if (close_delegate == null)
340 close_delegate = new Action<TimeSpan> (OnClose);
341 return close_delegate.BeginInvoke (timeout, callback, state);
344 protected override IAsyncResult OnBeginOpen (
345 TimeSpan timeout, AsyncCallback callback, object state)
347 if (open_delegate == null)
348 open_delegate = new Action<TimeSpan> (OnClose);
349 return open_delegate.BeginInvoke (timeout, callback, state);
352 protected override void OnEndClose (IAsyncResult result)
354 if (close_delegate == null)
355 throw new InvalidOperationException ("Async close operation has not started");
356 close_delegate.EndInvoke (result);
359 protected override void OnEndOpen (IAsyncResult result)
361 if (open_delegate == null)
362 throw new InvalidOperationException ("Async close operation has not started");
363 open_delegate.EndInvoke (result);
366 protected override void OnClose (TimeSpan timeout)
368 DateTime start = DateTime.Now;
369 foreach (var ch in opened_channels.ToArray ())
370 ch.Close (timeout - (DateTime.Now - start));
371 if (OpenedChannelFactory != null)
372 OpenedChannelFactory.Close (timeout - (DateTime.Now - start));
375 protected override void OnOpen (TimeSpan timeout)
379 protected override void OnOpening ()
382 OpenedChannelFactory = CreateFactory ();
385 protected override void OnOpened ()
388 OpenedChannelFactory.Open ();
394 interface UninitializedContract
397 void ItShouldReallyGone ();