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; }
71 public ClientCredentials Credentials {
72 get { return Endpoint.Behaviors.Find<ClientCredentials> (); }
76 protected internal override TimeSpan DefaultCloseTimeout {
77 get { return Endpoint.Binding.CloseTimeout; }
80 protected internal override TimeSpan DefaultOpenTimeout {
81 get { return Endpoint.Binding.OpenTimeout; }
84 protected virtual void ApplyConfiguration (string endpointConfig)
86 if (endpointConfig == null)
91 // It should automatically use XmlXapResolver
92 var cfg = new SilverlightClientConfigLoader ().Load (XmlReader.Create ("ServiceReferences.ClientConfig"));
94 SilverlightClientConfigLoader.ServiceEndpointConfiguration se = null;
95 if (endpointConfig == "*")
96 se = cfg.GetServiceEndpointConfiguration (Endpoint.Contract.Name);
98 se = cfg.GetServiceEndpointConfiguration (endpointConfig);
100 if (se.Binding != null && Endpoint.Binding == null)
101 Endpoint.Binding = se.Binding;
103 Console.WriteLine ("WARNING: Configured binding not found in configuration {0}", endpointConfig);
104 if (se.Address != null && Endpoint.Address == null)
105 Endpoint.Address = se.Address;
107 Console.WriteLine ("WARNING: Configured endpoint address not found in configuration {0}", endpointConfig);
108 } catch (Exception) {
110 Console.WriteLine ("WARNING: failed to load endpoint configuration for {0}", endpointConfig);
114 string contractName = Endpoint.Contract.ConfigurationName;
115 ClientSection client = (ClientSection) ConfigurationManager.GetSection ("system.serviceModel/client");
116 ChannelEndpointElement res = null;
117 foreach (ChannelEndpointElement el in client.Endpoints) {
118 if (el.Contract == contractName && (endpointConfig == el.Name || endpointConfig == "*")) {
120 throw new InvalidOperationException (String.Format ("More then one endpoint matching contract {0} was found.", contractName));
126 throw new InvalidOperationException (String.Format ("Client endpoint configuration '{0}' was not found in {1} endpoints.", endpointConfig, client.Endpoints.Count));
128 if (Endpoint.Binding == null)
129 Endpoint.Binding = ConfigUtil.CreateBinding (res.Binding, res.BindingConfiguration);
130 if (Endpoint.Address == null)
131 Endpoint.Address = new EndpointAddress (res.Address);
133 if (res.BehaviorConfiguration != "")
134 ApplyBehavior (res.BehaviorConfiguration);
139 private void ApplyBehavior (string behaviorConfig)
141 BehaviorsSection behaviorsSection = (BehaviorsSection) ConfigurationManager.GetSection ("system.serviceModel/behaviors");
142 EndpointBehaviorElement behaviorElement = behaviorsSection.EndpointBehaviors [behaviorConfig];
144 foreach (BehaviorExtensionElement el in behaviorElement) {
145 IEndpointBehavior behavior = (IEndpointBehavior) el.CreateBehavior ();
146 Endpoint.Behaviors.Remove (behavior.GetType ());
147 Endpoint.Behaviors.Add (behavior);
152 protected virtual IChannelFactory CreateFactory ()
154 bool isOneWay = true; // check OperationDescription.IsOneWay
155 foreach (var od in Endpoint.Contract.Operations)
161 BindingParameterCollection pl = CreateBindingParameters ();
163 // the assumption on the type of created channel could
164 // be wrong, but would mostly fit the actual
165 // requirements. No books have explained how it is done.
168 switch (Endpoint.Contract.SessionMode) {
169 case SessionMode.Required:
170 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexSessionChannel> (pl))
171 return Endpoint.Binding.BuildChannelFactory<IDuplexSessionChannel> (pl);
173 case SessionMode.Allowed:
174 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
175 return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
176 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexSessionChannel> (pl))
177 return Endpoint.Binding.BuildChannelFactory<IDuplexSessionChannel> (pl);
180 if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
181 return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
185 if (Endpoint.Contract.CallbackContractType != null)
186 throw new InvalidOperationException ("The binding does not support duplex channel types that the contract requies for CallbackContractType.");
189 switch (Endpoint.Contract.SessionMode) {
190 case SessionMode.Required:
191 if (Endpoint.Binding.CanBuildChannelFactory<IOutputSessionChannel> (pl))
192 return Endpoint.Binding.BuildChannelFactory<IOutputSessionChannel> (pl);
194 case SessionMode.Allowed:
195 if (Endpoint.Binding.CanBuildChannelFactory<IOutputChannel> (pl))
196 return Endpoint.Binding.BuildChannelFactory<IOutputChannel> (pl);
197 goto case SessionMode.Required;
199 if (Endpoint.Binding.CanBuildChannelFactory<IOutputChannel> (pl))
200 return Endpoint.Binding.BuildChannelFactory<IOutputChannel> (pl);
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 ("The binding does not support any of the channel types that the contract allows.");
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 (State != CommunicationState.Opened)
260 protected void InitializeEndpoint (
261 string endpointConfigurationName,
262 EndpointAddress remoteAddress)
264 InitializeEndpoint (CreateDescription ());
265 if (remoteAddress != null)
266 service_endpoint.Address = remoteAddress;
267 ApplyConfiguration (endpointConfigurationName);
270 protected void InitializeEndpoint (Binding binding,
271 EndpointAddress remoteAddress)
273 InitializeEndpoint (CreateDescription ());
275 service_endpoint.Binding = binding;
276 if (remoteAddress != null)
277 service_endpoint.Address = remoteAddress;
280 protected void InitializeEndpoint (ServiceEndpoint endpoint)
282 if (endpoint == null)
283 throw new ArgumentNullException ("endpoint");
284 service_endpoint = endpoint;
287 protected override void OnAbort ()
289 if (OpenedChannelFactory != null)
290 OpenedChannelFactory.Abort ();
293 Action<TimeSpan> close_delegate;
294 Action<TimeSpan> open_delegate;
297 protected override IAsyncResult OnBeginClose (
298 TimeSpan timeout, AsyncCallback callback, object state)
300 if (close_delegate == null)
301 close_delegate = new Action<TimeSpan> (OnClose);
302 return close_delegate.BeginInvoke (timeout, callback, state);
305 protected override IAsyncResult OnBeginOpen (
306 TimeSpan timeout, AsyncCallback callback, object state)
308 if (open_delegate == null)
309 open_delegate = new Action<TimeSpan> (OnClose);
310 return open_delegate.BeginInvoke (timeout, callback, state);
313 protected override void OnEndClose (IAsyncResult result)
315 if (close_delegate == null)
316 throw new InvalidOperationException ("Async close operation has not started");
317 close_delegate.EndInvoke (result);
320 protected override void OnEndOpen (IAsyncResult result)
322 if (open_delegate == null)
323 throw new InvalidOperationException ("Async close operation has not started");
324 open_delegate.EndInvoke (result);
327 protected override void OnClose (TimeSpan timeout)
329 if (OpenedChannelFactory != null)
330 OpenedChannelFactory.Close (timeout);
333 protected override void OnOpen (TimeSpan timeout)
337 protected override void OnOpening ()
339 OpenedChannelFactory = CreateFactory ();
340 OpenedChannelFactory.Open ();
343 protected override void OnOpened ()
350 interface UninitializedContract
353 void ItShouldReallyGone ();