Xamarin Public Jenkins (auto-signing) 94b2861243 Imported Upstream version 4.8.0.309
Former-commit-id: 5f9c6ae75f295e057a7d2971f3a6df4656fa8850
2016-11-10 13:04:39 +00:00

402 lines
14 KiB
C#

//
// ChannelFactory.cs
//
// Author:
// Atsushi Enomoto <atsushi@ximian.com>
//
// Copyright (C) 2005 Novell, Inc. http://www.novell.com
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Security;
using System.Configuration;
using System.ServiceModel.Configuration;
using System.Xml;
namespace System.ServiceModel
{
public abstract class ChannelFactory : CommunicationObject,
IChannelFactory, ICommunicationObject, IDisposable
{
// instance members
ServiceEndpoint service_endpoint;
IChannelFactory factory;
List<IClientChannel> opened_channels = new List<IClientChannel> ();
protected ChannelFactory ()
{
}
internal IChannelFactory OpenedChannelFactory {
get {
if (factory == null) {
factory = CreateFactory ();
factory.Open ();
}
return factory;
}
private set {
factory = value;
}
}
internal List<IClientChannel> OpenedChannels {
get { return opened_channels; }
}
public ServiceEndpoint Endpoint {
get { return service_endpoint; }
}
public ClientCredentials Credentials {
get { return Endpoint.Behaviors.Find<ClientCredentials> (); }
}
protected internal override TimeSpan DefaultCloseTimeout {
get { return Endpoint.Binding.CloseTimeout; }
}
protected internal override TimeSpan DefaultOpenTimeout {
get { return Endpoint.Binding.OpenTimeout; }
}
protected virtual void ApplyConfiguration (string configurationName)
{
if (configurationName == null)
return;
#if MOBILE || XAMMAC_4_5
try {
// It should automatically use XmlXapResolver
var cfg = new SilverlightClientConfigLoader ().Load (XmlReader.Create ("ServiceReferences.ClientConfig"));
SilverlightClientConfigLoader.ServiceEndpointConfiguration se = null;
if (configurationName == "*")
se = cfg.GetServiceEndpointConfiguration (Endpoint.Contract.Name);
if (se == null)
se = cfg.GetServiceEndpointConfiguration (configurationName);
if (se.Binding != null && Endpoint.Binding == null)
Endpoint.Binding = se.Binding;
else // ignore it
Console.WriteLine ("WARNING: Configured binding not found in configuration {0}", configurationName);
if (se.Address != null && Endpoint.Address == null)
Endpoint.Address = se.Address;
else // ignore it
Console.WriteLine ("WARNING: Configured endpoint address not found in configuration {0}", configurationName);
} catch (Exception) {
// ignore it.
Console.WriteLine ("WARNING: failed to load endpoint configuration for {0}", configurationName);
}
#else
string contractName = Endpoint.Contract.ConfigurationName;
ClientSection client = ConfigUtil.ClientSection;
ChannelEndpointElement endpoint = null;
foreach (ChannelEndpointElement el in client.Endpoints) {
if (el.Contract == contractName && (configurationName == el.Name || configurationName == "*")) {
if (endpoint != null)
throw new InvalidOperationException (String.Format ("More then one endpoint matching contract {0} was found.", contractName));
endpoint = el;
}
}
if (endpoint == null)
throw new InvalidOperationException (String.Format ("Client endpoint configuration '{0}' was not found in {1} endpoints.", configurationName, client.Endpoints.Count));
var binding = String.IsNullOrEmpty (endpoint.Binding) ? null : ConfigUtil.CreateBinding (endpoint.Binding, endpoint.BindingConfiguration);
var contractType = ConfigUtil.GetTypeFromConfigString (endpoint.Contract, NamedConfigCategory.Contract);
if (contractType == null)
throw new ArgumentException (String.Format ("Contract '{0}' was not found", endpoint.Contract));
var contract = String.IsNullOrEmpty (endpoint.Contract) ? Endpoint.Contract : ContractDescription.GetContract (contractType);
if (!String.IsNullOrEmpty (endpoint.Kind)) {
var se = ConfigUtil.ConfigureStandardEndpoint (contract, endpoint);
if (se.Binding == null)
se.Binding = binding;
if (se.Address == null && se.Binding != null) // standard endpoint might have empty address
se.Address = new EndpointAddress (endpoint.Address);
if (se.Binding == null && se.Address != null) // look for protocol mapping
se.Binding = ConfigUtil.GetBindingByProtocolMapping (se.Address.Uri);
service_endpoint = se;
} else {
if (binding == null && endpoint.Address != null) // look for protocol mapping
Endpoint.Binding = ConfigUtil.GetBindingByProtocolMapping (endpoint.Address);
}
if (Endpoint.Binding == null)
Endpoint.Binding = ConfigUtil.CreateBinding (endpoint.Binding, endpoint.BindingConfiguration);
if (Endpoint.Address == null)
Endpoint.Address = new EndpointAddress (endpoint.Address);
if (endpoint.BehaviorConfiguration != "")
ApplyBehavior (endpoint.BehaviorConfiguration);
#endif
}
#if !MOBILE && !XAMMAC_4_5
private void ApplyBehavior (string behaviorConfig)
{
BehaviorsSection behaviorsSection = ConfigUtil.BehaviorsSection;
EndpointBehaviorElement behaviorElement = behaviorsSection.EndpointBehaviors [behaviorConfig];
int i = 0;
foreach (BehaviorExtensionElement el in behaviorElement) {
IEndpointBehavior behavior = (IEndpointBehavior) el.CreateBehavior ();
Endpoint.Behaviors.Remove (behavior.GetType ());
Endpoint.Behaviors.Add (behavior);
}
}
#endif
protected virtual IChannelFactory CreateFactory ()
{
bool isOneWay = true; // check OperationDescription.IsOneWay
foreach (var od in Endpoint.Contract.Operations)
if (!od.IsOneWay) {
isOneWay = false;
break;
}
BindingParameterCollection pl = CreateBindingParameters ();
// the assumption on the type of created channel could
// be wrong, but would mostly fit the actual
// requirements. No books have explained how it is done.
// try duplex
switch (Endpoint.Contract.SessionMode) {
case SessionMode.Required:
if (Endpoint.Binding.CanBuildChannelFactory<IDuplexSessionChannel> (pl))
return Endpoint.Binding.BuildChannelFactory<IDuplexSessionChannel> (pl);
break;
case SessionMode.Allowed:
if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
if (Endpoint.Binding.CanBuildChannelFactory<IDuplexSessionChannel> (pl))
return Endpoint.Binding.BuildChannelFactory<IDuplexSessionChannel> (pl);
break;
default:
if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
break;
}
if (Endpoint.Contract.CallbackContractType != null)
throw new InvalidOperationException ("The binding does not support duplex channel types that the contract requies for CallbackContractType.");
if (isOneWay) {
switch (Endpoint.Contract.SessionMode) {
case SessionMode.Required:
if (Endpoint.Binding.CanBuildChannelFactory<IOutputSessionChannel> (pl))
return Endpoint.Binding.BuildChannelFactory<IOutputSessionChannel> (pl);
if (Endpoint.Binding.CanBuildChannelFactory<IDuplexSessionChannel> (pl))
return Endpoint.Binding.BuildChannelFactory<IDuplexSessionChannel> (pl);
break;
case SessionMode.Allowed:
if (Endpoint.Binding.CanBuildChannelFactory<IOutputChannel> (pl))
return Endpoint.Binding.BuildChannelFactory<IOutputChannel> (pl);
if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
goto case SessionMode.Required;
default:
if (Endpoint.Binding.CanBuildChannelFactory<IOutputChannel> (pl))
return Endpoint.Binding.BuildChannelFactory<IOutputChannel> (pl);
if (Endpoint.Binding.CanBuildChannelFactory<IDuplexChannel> (pl))
return Endpoint.Binding.BuildChannelFactory<IDuplexChannel> (pl);
break;
}
}
// both OneWay and non-OneWay contracts fall into here.
{
switch (Endpoint.Contract.SessionMode) {
case SessionMode.Required:
if (Endpoint.Binding.CanBuildChannelFactory<IRequestSessionChannel> (pl))
return Endpoint.Binding.BuildChannelFactory<IRequestSessionChannel> (pl);
break;
case SessionMode.Allowed:
if (Endpoint.Binding.CanBuildChannelFactory<IRequestChannel> (pl))
return Endpoint.Binding.BuildChannelFactory<IRequestChannel> (pl);
if (Endpoint.Binding.CanBuildChannelFactory<IRequestSessionChannel> (pl))
return Endpoint.Binding.BuildChannelFactory<IRequestSessionChannel> (pl);
break;
default:
if (Endpoint.Binding.CanBuildChannelFactory<IRequestChannel> (pl))
return Endpoint.Binding.BuildChannelFactory<IRequestChannel> (pl);
break;
}
}
throw new InvalidOperationException (String.Format ("The binding does not support any of the channel types that the contract '{0}' allows.", Endpoint.Contract.Name));
}
BindingParameterCollection CreateBindingParameters ()
{
BindingParameterCollection pl =
new BindingParameterCollection ();
ContractDescription cd = Endpoint.Contract;
#if !MOBILE
pl.Add (ChannelProtectionRequirements.CreateFromContract (cd));
#endif
foreach (IEndpointBehavior behavior in Endpoint.Behaviors)
behavior.AddBindingParameters (Endpoint, pl);
return pl;
}
protected abstract ServiceEndpoint CreateDescription ();
void IDisposable.Dispose ()
{
Close ();
}
public T GetProperty<T> () where T : class
{
if (OpenedChannelFactory != null)
return OpenedChannelFactory.GetProperty<T> ();
return null;
}
protected void EnsureOpened ()
{
if (Endpoint == null)
throw new InvalidOperationException ("A service endpoint must be configured for this channel factory");
if (Endpoint.Contract == null)
throw new InvalidOperationException ("A service Contract must be configured for this channel factory");
if (Endpoint.Binding == null)
throw new InvalidOperationException ("A Binding must be configured for this channel factory");
if (State != CommunicationState.Opened)
Open ();
}
protected void InitializeEndpoint (
string configurationName,
EndpointAddress remoteAddress)
{
InitializeEndpoint (CreateDescription ());
if (remoteAddress != null)
service_endpoint.Address = remoteAddress;
ApplyConfiguration (configurationName);
}
protected void InitializeEndpoint (Binding binding,
EndpointAddress address)
{
InitializeEndpoint (CreateDescription ());
if (binding != null)
service_endpoint.Binding = binding;
if (address != null)
service_endpoint.Address = address;
}
protected void InitializeEndpoint (ServiceEndpoint endpoint)
{
if (endpoint == null)
throw new ArgumentNullException ("endpoint");
service_endpoint = endpoint;
}
protected override void OnAbort ()
{
if (OpenedChannelFactory != null)
OpenedChannelFactory.Abort ();
}
Action<TimeSpan> close_delegate;
Action<TimeSpan> open_delegate;
protected override IAsyncResult OnBeginClose (
TimeSpan timeout, AsyncCallback callback, object state)
{
if (close_delegate == null)
close_delegate = new Action<TimeSpan> (OnClose);
return close_delegate.BeginInvoke (timeout, callback, state);
}
protected override IAsyncResult OnBeginOpen (
TimeSpan timeout, AsyncCallback callback, object state)
{
if (open_delegate == null)
open_delegate = new Action<TimeSpan> (OnClose);
return open_delegate.BeginInvoke (timeout, callback, state);
}
protected override void OnEndClose (IAsyncResult result)
{
if (close_delegate == null)
throw new InvalidOperationException ("Async close operation has not started");
close_delegate.EndInvoke (result);
}
protected override void OnEndOpen (IAsyncResult result)
{
if (open_delegate == null)
throw new InvalidOperationException ("Async close operation has not started");
open_delegate.EndInvoke (result);
}
protected override void OnClose (TimeSpan timeout)
{
DateTime start = DateTime.Now;
foreach (var ch in opened_channels.ToArray ())
ch.Close (timeout - (DateTime.Now - start));
if (OpenedChannelFactory != null)
OpenedChannelFactory.Close (timeout - (DateTime.Now - start));
}
protected override void OnOpen (TimeSpan timeout)
{
}
protected override void OnOpening ()
{
base.OnOpening ();
OpenedChannelFactory = CreateFactory ();
}
protected override void OnOpened ()
{
base.OnOpened ();
OpenedChannelFactory.Open ();
}
}
#if obsolete
[ServiceContract]
interface UninitializedContract
{
[OperationContract]
void ItShouldReallyGone ();
}
#endif
}