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 switch (Endpoint.Contract.SessionMode) {
203 case SessionMode.Required:
204 if (Endpoint.Binding.CanBuildChannelFactory<IRequestSessionChannel> (pl))
205 return Endpoint.Binding.BuildChannelFactory<IRequestSessionChannel> (pl);
207 case SessionMode.Allowed:
208 if (Endpoint.Binding.CanBuildChannelFactory<IRequestChannel> (pl))
209 return Endpoint.Binding.BuildChannelFactory<IRequestChannel> (pl);
210 if (Endpoint.Binding.CanBuildChannelFactory<IRequestSessionChannel> (pl))
211 return Endpoint.Binding.BuildChannelFactory<IRequestSessionChannel> (pl);
214 if (Endpoint.Binding.CanBuildChannelFactory<IRequestChannel> (pl))
215 return Endpoint.Binding.BuildChannelFactory<IRequestChannel> (pl);
219 throw new InvalidOperationException ("The binding does not support any of the channel types that the contract allows.");
222 BindingParameterCollection CreateBindingParameters ()
224 BindingParameterCollection pl =
225 new BindingParameterCollection ();
227 ContractDescription cd = Endpoint.Contract;
229 pl.Add (ChannelProtectionRequirements.CreateFromContract (cd));
231 foreach (IEndpointBehavior behavior in Endpoint.Behaviors)
232 behavior.AddBindingParameters (Endpoint, pl);
238 protected abstract ServiceEndpoint CreateDescription ();
240 void IDisposable.Dispose ()
245 public T GetProperty<T> () where T : class
247 if (OpenedChannelFactory != null)
248 OpenedChannelFactory.GetProperty<T> ();
252 protected void EnsureOpened ()
254 if (State != CommunicationState.Opened)
258 protected void InitializeEndpoint (
259 string endpointConfigurationName,
260 EndpointAddress remoteAddress)
262 InitializeEndpoint (CreateDescription ());
263 if (remoteAddress != null)
264 service_endpoint.Address = remoteAddress;
265 ApplyConfiguration (endpointConfigurationName);
268 protected void InitializeEndpoint (Binding binding,
269 EndpointAddress remoteAddress)
271 InitializeEndpoint (CreateDescription ());
273 service_endpoint.Binding = binding;
274 if (remoteAddress != null)
275 service_endpoint.Address = remoteAddress;
278 protected void InitializeEndpoint (ServiceEndpoint endpoint)
280 if (endpoint == null)
281 throw new ArgumentNullException ("endpoint");
282 service_endpoint = endpoint;
285 protected override void OnAbort ()
287 if (OpenedChannelFactory != null)
288 OpenedChannelFactory.Abort ();
291 Action<TimeSpan> close_delegate;
292 Action<TimeSpan> open_delegate;
295 protected override IAsyncResult OnBeginClose (
296 TimeSpan timeout, AsyncCallback callback, object state)
298 if (close_delegate == null)
299 close_delegate = new Action<TimeSpan> (OnClose);
300 return close_delegate.BeginInvoke (timeout, callback, state);
303 protected override IAsyncResult OnBeginOpen (
304 TimeSpan timeout, AsyncCallback callback, object state)
306 if (open_delegate == null)
307 open_delegate = new Action<TimeSpan> (OnClose);
308 return open_delegate.BeginInvoke (timeout, callback, state);
311 protected override void OnEndClose (IAsyncResult result)
313 if (close_delegate == null)
314 throw new InvalidOperationException ("Async close operation has not started");
315 close_delegate.EndInvoke (result);
318 protected override void OnEndOpen (IAsyncResult result)
320 if (open_delegate == null)
321 throw new InvalidOperationException ("Async close operation has not started");
322 open_delegate.EndInvoke (result);
325 protected override void OnClose (TimeSpan timeout)
327 if (OpenedChannelFactory != null)
328 OpenedChannelFactory.Close (timeout);
331 protected override void OnOpen (TimeSpan timeout)
335 protected override void OnOpening ()
338 OpenedChannelFactory = CreateFactory ();
341 protected override void OnOpened ()
344 OpenedChannelFactory.Open ();
350 interface UninitializedContract
353 void ItShouldReallyGone ();