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.ObjectModel;
30 using System.ServiceModel.Channels;
31 using System.ServiceModel.Description;
32 using System.ServiceModel.Dispatcher;
33 using System.ServiceModel.Security;
34 using System.Configuration;
35 using System.ServiceModel.Configuration;
38 namespace System.ServiceModel
40 public abstract class ChannelFactory : CommunicationObject,
41 IChannelFactory, ICommunicationObject, IDisposable
45 ServiceEndpoint service_endpoint;
46 IChannelFactory factory;
48 protected ChannelFactory ()
52 internal IChannelFactory OpenedChannelFactory {
54 if (factory == null) {
55 factory = CreateFactory ();
66 public ServiceEndpoint Endpoint {
67 get { return service_endpoint; }
70 public ClientCredentials Credentials {
71 get { return Endpoint.Behaviors.Find<ClientCredentials> (); }
74 protected internal override TimeSpan DefaultCloseTimeout {
75 get { return Endpoint.Binding.CloseTimeout; }
78 protected internal override TimeSpan DefaultOpenTimeout {
79 get { return Endpoint.Binding.OpenTimeout; }
82 protected virtual void ApplyConfiguration (string endpointConfig)
84 if (endpointConfig == null)
89 // It should automatically use XmlXapResolver
90 var cfg = new SilverlightClientConfigLoader ().Load (XmlReader.Create ("ServiceReferences.ClientConfig"));
92 SilverlightClientConfigLoader.ServiceEndpointConfiguration se = null;
93 if (endpointConfig == "*")
94 se = cfg.GetServiceEndpointConfiguration (Endpoint.Contract.Name);
96 se = cfg.GetServiceEndpointConfiguration (endpointConfig);
98 if (se.Binding != null && Endpoint.Binding == null)
99 Endpoint.Binding = se.Binding;
101 Console.WriteLine ("WARNING: Configured binding not found in configuration {0}", endpointConfig);
102 if (se.Address != null && Endpoint.Address == null)
103 Endpoint.Address = se.Address;
105 Console.WriteLine ("WARNING: Configured endpoint address not found in configuration {0}", endpointConfig);
106 } catch (Exception) {
108 Console.WriteLine ("WARNING: failed to load endpoint configuration for {0}", endpointConfig);
112 string contractName = Endpoint.Contract.ConfigurationName;
113 ClientSection client = ConfigUtil.ClientSection;
114 ChannelEndpointElement res = null;
115 foreach (ChannelEndpointElement el in client.Endpoints) {
116 if (el.Contract == contractName && (endpointConfig == el.Name || endpointConfig == "*")) {
118 throw new InvalidOperationException (String.Format ("More then one endpoint matching contract {0} was found.", contractName));
124 throw new InvalidOperationException (String.Format ("Client endpoint configuration '{0}' was not found in {1} endpoints.", endpointConfig, client.Endpoints.Count));
126 if (Endpoint.Binding == null)
127 Endpoint.Binding = ConfigUtil.CreateBinding (res.Binding, res.BindingConfiguration);
128 if (Endpoint.Address == null)
129 Endpoint.Address = new EndpointAddress (res.Address);
131 if (res.BehaviorConfiguration != "")
132 ApplyBehavior (res.BehaviorConfiguration);
137 private void ApplyBehavior (string behaviorConfig)
139 BehaviorsSection behaviorsSection = ConfigUtil.BehaviorsSection;
140 EndpointBehaviorElement behaviorElement = behaviorsSection.EndpointBehaviors [behaviorConfig];
142 foreach (BehaviorExtensionElement el in behaviorElement) {
143 IEndpointBehavior behavior = (IEndpointBehavior) el.CreateBehavior ();
144 Endpoint.Behaviors.Remove (behavior.GetType ());
145 Endpoint.Behaviors.Add (behavior);
150 protected virtual IChannelFactory CreateFactory ()
152 bool isOneWay = true; // check OperationDescription.IsOneWay
153 foreach (var od in Endpoint.Contract.Operations)
159 BindingParameterCollection pl = CreateBindingParameters ();
161 // the assumption on the type of created channel could
162 // be wrong, but would mostly fit the actual
163 // requirements. No books have explained how it is done.
166 switch (Endpoint.Contract.SessionMode) {
167 case SessionMode.Required:
168 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexSessionChannel> (pl))
169 return Endpoint.Binding.BuildChannelFactory<IDuplexSessionChannel> (pl);
171 case SessionMode.Allowed:
172 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
173 return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
174 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexSessionChannel> (pl))
175 return Endpoint.Binding.BuildChannelFactory<IDuplexSessionChannel> (pl);
178 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
179 return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
183 if (Endpoint.Contract.CallbackContractType != null)
184 throw new InvalidOperationException ("The binding does not support duplex channel types that the contract requies for CallbackContractType.");
187 switch (Endpoint.Contract.SessionMode) {
188 case SessionMode.Required:
189 if (Endpoint.Binding.CanBuildChannelFactory<IOutputSessionChannel> (pl))
190 return Endpoint.Binding.BuildChannelFactory<IOutputSessionChannel> (pl);
192 case SessionMode.Allowed:
193 if (Endpoint.Binding.CanBuildChannelFactory<IOutputChannel> (pl))
194 return Endpoint.Binding.BuildChannelFactory<IOutputChannel> (pl);
195 goto case SessionMode.Required;
197 if (Endpoint.Binding.CanBuildChannelFactory<IOutputChannel> (pl))
198 return Endpoint.Binding.BuildChannelFactory<IOutputChannel> (pl);
202 // both OneWay and non-OneWay contracts fall into here.
204 switch (Endpoint.Contract.SessionMode) {
205 case SessionMode.Required:
206 if (Endpoint.Binding.CanBuildChannelFactory<IRequestSessionChannel> (pl))
207 return Endpoint.Binding.BuildChannelFactory<IRequestSessionChannel> (pl);
209 case SessionMode.Allowed:
210 if (Endpoint.Binding.CanBuildChannelFactory<IRequestChannel> (pl))
211 return Endpoint.Binding.BuildChannelFactory<IRequestChannel> (pl);
212 if (Endpoint.Binding.CanBuildChannelFactory<IRequestSessionChannel> (pl))
213 return Endpoint.Binding.BuildChannelFactory<IRequestSessionChannel> (pl);
216 if (Endpoint.Binding.CanBuildChannelFactory<IRequestChannel> (pl))
217 return Endpoint.Binding.BuildChannelFactory<IRequestChannel> (pl);
221 throw new InvalidOperationException (String.Format ("The binding does not support any of the channel types that the contract '{0}' allows.", Endpoint.Contract.Name));
224 BindingParameterCollection CreateBindingParameters ()
226 BindingParameterCollection pl =
227 new BindingParameterCollection ();
229 ContractDescription cd = Endpoint.Contract;
231 pl.Add (ChannelProtectionRequirements.CreateFromContract (cd));
233 foreach (IEndpointBehavior behavior in Endpoint.Behaviors)
234 behavior.AddBindingParameters (Endpoint, pl);
240 protected abstract ServiceEndpoint CreateDescription ();
242 void IDisposable.Dispose ()
247 public T GetProperty<T> () where T : class
249 if (OpenedChannelFactory != null)
250 OpenedChannelFactory.GetProperty<T> ();
254 protected void EnsureOpened ()
256 if (Endpoint == null)
257 throw new InvalidOperationException ("A service endpoint must be configured for this channel factory");
258 if (Endpoint.Address == null)
259 throw new InvalidOperationException ("An EndpointAddress must be configured for this channel factory");
260 if (Endpoint.Contract == null)
261 throw new InvalidOperationException ("A service Contract must be configured for this channel factory");
262 if (Endpoint.Binding == null)
263 throw new InvalidOperationException ("A Binding must be configured for this channel factory");
265 if (State != CommunicationState.Opened)
269 protected void InitializeEndpoint (
270 string endpointConfigurationName,
271 EndpointAddress remoteAddress)
273 InitializeEndpoint (CreateDescription ());
274 if (remoteAddress != null)
275 service_endpoint.Address = remoteAddress;
276 ApplyConfiguration (endpointConfigurationName);
279 protected void InitializeEndpoint (Binding binding,
280 EndpointAddress remoteAddress)
282 InitializeEndpoint (CreateDescription ());
284 service_endpoint.Binding = binding;
285 if (remoteAddress != null)
286 service_endpoint.Address = remoteAddress;
289 protected void InitializeEndpoint (ServiceEndpoint endpoint)
291 if (endpoint == null)
292 throw new ArgumentNullException ("endpoint");
293 service_endpoint = endpoint;
296 protected override void OnAbort ()
298 if (OpenedChannelFactory != null)
299 OpenedChannelFactory.Abort ();
302 Action<TimeSpan> close_delegate;
303 Action<TimeSpan> open_delegate;
306 protected override IAsyncResult OnBeginClose (
307 TimeSpan timeout, AsyncCallback callback, object state)
309 if (close_delegate == null)
310 close_delegate = new Action<TimeSpan> (OnClose);
311 return close_delegate.BeginInvoke (timeout, callback, state);
314 protected override IAsyncResult OnBeginOpen (
315 TimeSpan timeout, AsyncCallback callback, object state)
317 if (open_delegate == null)
318 open_delegate = new Action<TimeSpan> (OnClose);
319 return open_delegate.BeginInvoke (timeout, callback, state);
322 protected override void OnEndClose (IAsyncResult result)
324 if (close_delegate == null)
325 throw new InvalidOperationException ("Async close operation has not started");
326 close_delegate.EndInvoke (result);
329 protected override void OnEndOpen (IAsyncResult result)
331 if (open_delegate == null)
332 throw new InvalidOperationException ("Async close operation has not started");
333 open_delegate.EndInvoke (result);
336 protected override void OnClose (TimeSpan timeout)
338 if (OpenedChannelFactory != null)
339 OpenedChannelFactory.Close (timeout);
342 protected override void OnOpen (TimeSpan timeout)
346 protected override void OnOpening ()
349 OpenedChannelFactory = CreateFactory ();
352 protected override void OnOpened ()
355 OpenedChannelFactory.Open ();
361 interface UninitializedContract
364 void ItShouldReallyGone ();