e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
1545 lines
56 KiB
C#
1545 lines
56 KiB
C#
//------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------
|
|
|
|
namespace System.ServiceModel
|
|
{
|
|
using System.ComponentModel;
|
|
using System.Diagnostics;
|
|
using System.Runtime;
|
|
using System.ServiceModel.Channels;
|
|
using System.ServiceModel.Description;
|
|
using System.ServiceModel.Diagnostics;
|
|
using System.Threading;
|
|
using System.ServiceModel.Diagnostics.Application;
|
|
using System.Runtime.Remoting.Messaging;
|
|
using System.ServiceModel.Dispatcher;
|
|
using System.Security;
|
|
|
|
public abstract class ClientBase<TChannel> : ICommunicationObject, IDisposable
|
|
where TChannel : class
|
|
{
|
|
TChannel channel;
|
|
ChannelFactoryRef<TChannel> channelFactoryRef;
|
|
EndpointTrait<TChannel> endpointTrait;
|
|
|
|
// Determine whether the proxy can share factory with others. It is false only if the public getters
|
|
// are invoked.
|
|
bool canShareFactory = true;
|
|
|
|
// Determine whether the proxy is currently holding a cached factory
|
|
bool useCachedFactory;
|
|
|
|
// Determine whether we have locked down sharing for this proxy. This is turned on only when the channel
|
|
// is created.
|
|
bool sharingFinalized;
|
|
|
|
// Determine whether the ChannelFactoryRef has been released. We should release it only once per proxy
|
|
bool channelFactoryRefReleased;
|
|
|
|
// Determine whether we have released the last ref count of the ChannelFactory so that we could abort it when it was closing.
|
|
bool releasedLastRef;
|
|
|
|
object syncRoot = new object();
|
|
|
|
object finalizeLock = new object();
|
|
|
|
// Cache at most 32 ChannelFactories
|
|
const int maxNumChannelFactories = 32;
|
|
static ChannelFactoryRefCache<TChannel> factoryRefCache = new ChannelFactoryRefCache<TChannel>(maxNumChannelFactories);
|
|
static object staticLock = new object();
|
|
|
|
static object cacheLock = new object();
|
|
static CacheSetting cacheSetting = CacheSetting.Default;
|
|
static bool isCacheSettingReadOnly;
|
|
|
|
static AsyncCallback onAsyncCallCompleted = Fx.ThunkCallback(new AsyncCallback(OnAsyncCallCompleted));
|
|
|
|
// IMPORTANT: any changes to the set of protected .ctors of this class need to be reflected
|
|
// in ServiceContractGenerator.cs as well.
|
|
|
|
protected ClientBase()
|
|
{
|
|
MakeCacheSettingReadOnly();
|
|
|
|
if (cacheSetting == CacheSetting.AlwaysOff)
|
|
{
|
|
this.channelFactoryRef = new ChannelFactoryRef<TChannel>(new ChannelFactory<TChannel>("*"));
|
|
this.channelFactoryRef.ChannelFactory.TraceOpenAndClose = false;
|
|
TryDisableSharing();
|
|
}
|
|
else
|
|
{
|
|
this.endpointTrait = new ConfigurationEndpointTrait<TChannel>("*", null, null);
|
|
InitializeChannelFactoryRef();
|
|
}
|
|
}
|
|
|
|
protected ClientBase(string endpointConfigurationName)
|
|
{
|
|
if (endpointConfigurationName == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpointConfigurationName");
|
|
|
|
MakeCacheSettingReadOnly();
|
|
|
|
if (cacheSetting == CacheSetting.AlwaysOff)
|
|
{
|
|
this.channelFactoryRef = new ChannelFactoryRef<TChannel>(new ChannelFactory<TChannel>(endpointConfigurationName));
|
|
this.channelFactoryRef.ChannelFactory.TraceOpenAndClose = false;
|
|
TryDisableSharing();
|
|
}
|
|
else
|
|
{
|
|
this.endpointTrait = new ConfigurationEndpointTrait<TChannel>(endpointConfigurationName, null, null);
|
|
InitializeChannelFactoryRef();
|
|
}
|
|
}
|
|
|
|
protected ClientBase(string endpointConfigurationName, string remoteAddress)
|
|
{
|
|
if (endpointConfigurationName == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpointConfigurationName");
|
|
if (remoteAddress == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("remoteAddress");
|
|
|
|
MakeCacheSettingReadOnly();
|
|
EndpointAddress endpointAddress = new EndpointAddress(remoteAddress);
|
|
|
|
if (cacheSetting == CacheSetting.AlwaysOff)
|
|
{
|
|
this.channelFactoryRef = new ChannelFactoryRef<TChannel>(new ChannelFactory<TChannel>(endpointConfigurationName, endpointAddress));
|
|
this.channelFactoryRef.ChannelFactory.TraceOpenAndClose = false;
|
|
TryDisableSharing();
|
|
}
|
|
else
|
|
{
|
|
this.endpointTrait = new ConfigurationEndpointTrait<TChannel>(endpointConfigurationName, endpointAddress, null);
|
|
InitializeChannelFactoryRef();
|
|
}
|
|
}
|
|
|
|
protected ClientBase(string endpointConfigurationName, EndpointAddress remoteAddress)
|
|
{
|
|
if (endpointConfigurationName == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpointConfigurationName");
|
|
if (remoteAddress == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("remoteAddress");
|
|
|
|
MakeCacheSettingReadOnly();
|
|
|
|
if (cacheSetting == CacheSetting.AlwaysOff)
|
|
{
|
|
this.channelFactoryRef = new ChannelFactoryRef<TChannel>(new ChannelFactory<TChannel>(endpointConfigurationName, remoteAddress));
|
|
this.channelFactoryRef.ChannelFactory.TraceOpenAndClose = false;
|
|
TryDisableSharing();
|
|
}
|
|
else
|
|
{
|
|
this.endpointTrait = new ConfigurationEndpointTrait<TChannel>(endpointConfigurationName, remoteAddress, null);
|
|
InitializeChannelFactoryRef();
|
|
}
|
|
|
|
}
|
|
|
|
protected ClientBase(Binding binding, EndpointAddress remoteAddress)
|
|
{
|
|
if (binding == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("binding");
|
|
if (remoteAddress == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("remoteAddress");
|
|
|
|
MakeCacheSettingReadOnly();
|
|
|
|
if (cacheSetting == CacheSetting.AlwaysOn)
|
|
{
|
|
this.endpointTrait = new ProgrammaticEndpointTrait<TChannel>(binding, remoteAddress, null);
|
|
InitializeChannelFactoryRef();
|
|
}
|
|
else
|
|
{
|
|
this.channelFactoryRef = new ChannelFactoryRef<TChannel>(new ChannelFactory<TChannel>(binding, remoteAddress));
|
|
this.channelFactoryRef.ChannelFactory.TraceOpenAndClose = false;
|
|
TryDisableSharing();
|
|
}
|
|
}
|
|
|
|
protected ClientBase(ServiceEndpoint endpoint)
|
|
{
|
|
if (endpoint == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpoint");
|
|
|
|
MakeCacheSettingReadOnly();
|
|
|
|
if (cacheSetting == CacheSetting.AlwaysOn)
|
|
{
|
|
this.endpointTrait = new ServiceEndpointTrait<TChannel>(endpoint, null);
|
|
this.InitializeChannelFactoryRef();
|
|
}
|
|
else
|
|
{
|
|
channelFactoryRef = new ChannelFactoryRef<TChannel>(new ChannelFactory<TChannel>(endpoint));
|
|
channelFactoryRef.ChannelFactory.TraceOpenAndClose = false;
|
|
TryDisableSharing();
|
|
}
|
|
}
|
|
|
|
protected ClientBase(InstanceContext callbackInstance)
|
|
{
|
|
if (callbackInstance == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("callbackInstance");
|
|
|
|
MakeCacheSettingReadOnly();
|
|
|
|
if (cacheSetting == CacheSetting.AlwaysOff)
|
|
{
|
|
this.channelFactoryRef = new ChannelFactoryRef<TChannel>(
|
|
new DuplexChannelFactory<TChannel>(callbackInstance, "*"));
|
|
this.channelFactoryRef.ChannelFactory.TraceOpenAndClose = false;
|
|
TryDisableSharing();
|
|
}
|
|
else
|
|
{
|
|
this.endpointTrait = new ConfigurationEndpointTrait<TChannel>("*", null, callbackInstance);
|
|
InitializeChannelFactoryRef();
|
|
}
|
|
}
|
|
|
|
protected ClientBase(InstanceContext callbackInstance, string endpointConfigurationName)
|
|
{
|
|
if (callbackInstance == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("callbackInstance");
|
|
if (endpointConfigurationName == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpointConfigurationName");
|
|
|
|
MakeCacheSettingReadOnly();
|
|
|
|
if (cacheSetting == CacheSetting.AlwaysOff)
|
|
{
|
|
this.channelFactoryRef = new ChannelFactoryRef<TChannel>(
|
|
new DuplexChannelFactory<TChannel>(callbackInstance, endpointConfigurationName));
|
|
this.channelFactoryRef.ChannelFactory.TraceOpenAndClose = false;
|
|
TryDisableSharing();
|
|
}
|
|
else
|
|
{
|
|
this.endpointTrait = new ConfigurationEndpointTrait<TChannel>(endpointConfigurationName, null, callbackInstance);
|
|
InitializeChannelFactoryRef();
|
|
}
|
|
}
|
|
|
|
protected ClientBase(InstanceContext callbackInstance, string endpointConfigurationName, string remoteAddress)
|
|
{
|
|
if (callbackInstance == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("callbackInstance");
|
|
if (endpointConfigurationName == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpointConfigurationName");
|
|
if (remoteAddress == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("remoteAddress");
|
|
|
|
MakeCacheSettingReadOnly();
|
|
EndpointAddress endpointAddress = new EndpointAddress(remoteAddress);
|
|
|
|
if (cacheSetting == CacheSetting.AlwaysOff)
|
|
{
|
|
this.channelFactoryRef = new ChannelFactoryRef<TChannel>(
|
|
new DuplexChannelFactory<TChannel>(callbackInstance, endpointConfigurationName, endpointAddress));
|
|
this.channelFactoryRef.ChannelFactory.TraceOpenAndClose = false;
|
|
TryDisableSharing();
|
|
}
|
|
else
|
|
{
|
|
this.endpointTrait = new ConfigurationEndpointTrait<TChannel>(endpointConfigurationName, endpointAddress, callbackInstance);
|
|
InitializeChannelFactoryRef();
|
|
}
|
|
}
|
|
|
|
protected ClientBase(InstanceContext callbackInstance, string endpointConfigurationName, EndpointAddress remoteAddress)
|
|
{
|
|
if (callbackInstance == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("callbackInstance");
|
|
if (endpointConfigurationName == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpointConfigurationName");
|
|
if (remoteAddress == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("remoteAddress");
|
|
|
|
MakeCacheSettingReadOnly();
|
|
|
|
if (cacheSetting == CacheSetting.AlwaysOff)
|
|
{
|
|
this.channelFactoryRef = new ChannelFactoryRef<TChannel>(
|
|
new DuplexChannelFactory<TChannel>(callbackInstance, endpointConfigurationName, remoteAddress));
|
|
this.channelFactoryRef.ChannelFactory.TraceOpenAndClose = false;
|
|
TryDisableSharing();
|
|
}
|
|
else
|
|
{
|
|
this.endpointTrait = new ConfigurationEndpointTrait<TChannel>(endpointConfigurationName, remoteAddress, callbackInstance);
|
|
InitializeChannelFactoryRef();
|
|
}
|
|
}
|
|
|
|
protected ClientBase(InstanceContext callbackInstance, Binding binding, EndpointAddress remoteAddress)
|
|
{
|
|
if (callbackInstance == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("callbackInstance");
|
|
if (binding == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("binding");
|
|
if (remoteAddress == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("remoteAddress");
|
|
|
|
MakeCacheSettingReadOnly();
|
|
|
|
if (cacheSetting == CacheSetting.AlwaysOn)
|
|
{
|
|
this.endpointTrait = new ProgrammaticEndpointTrait<TChannel>(binding, remoteAddress, callbackInstance);
|
|
InitializeChannelFactoryRef();
|
|
}
|
|
else
|
|
{
|
|
this.channelFactoryRef = new ChannelFactoryRef<TChannel>(
|
|
new DuplexChannelFactory<TChannel>(callbackInstance, binding, remoteAddress));
|
|
this.channelFactoryRef.ChannelFactory.TraceOpenAndClose = false;
|
|
TryDisableSharing();
|
|
}
|
|
}
|
|
|
|
protected ClientBase(InstanceContext callbackInstance, ServiceEndpoint endpoint)
|
|
{
|
|
if (callbackInstance == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("callbackInstance");
|
|
if (endpoint == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpoint");
|
|
|
|
MakeCacheSettingReadOnly();
|
|
|
|
if (cacheSetting == CacheSetting.AlwaysOn)
|
|
{
|
|
this.endpointTrait = new ServiceEndpointTrait<TChannel>(endpoint, callbackInstance);
|
|
InitializeChannelFactoryRef();
|
|
}
|
|
else
|
|
{
|
|
this.channelFactoryRef = new ChannelFactoryRef<TChannel>(
|
|
new DuplexChannelFactory<TChannel>(callbackInstance, endpoint));
|
|
this.channelFactoryRef.ChannelFactory.TraceOpenAndClose = false;
|
|
TryDisableSharing();
|
|
}
|
|
}
|
|
|
|
protected T GetDefaultValueForInitialization<T>()
|
|
{
|
|
return default(T);
|
|
}
|
|
|
|
object ThisLock
|
|
{
|
|
get
|
|
{
|
|
return syncRoot;
|
|
}
|
|
}
|
|
|
|
protected TChannel Channel
|
|
{
|
|
get
|
|
{
|
|
// created on demand, so that Mort can modify .Endpoint before calling methods on the client
|
|
if (this.channel == null)
|
|
{
|
|
lock (ThisLock)
|
|
{
|
|
if (this.channel == null)
|
|
{
|
|
using (ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.CreateBoundedActivity() : null)
|
|
{
|
|
if (DiagnosticUtility.ShouldUseActivity)
|
|
{
|
|
ServiceModelActivity.Start(activity, SR.GetString(SR.ActivityOpenClientBase, typeof(TChannel).FullName), ActivityType.OpenClient);
|
|
}
|
|
|
|
if (this.useCachedFactory)
|
|
{
|
|
try
|
|
{
|
|
CreateChannelInternal();
|
|
}
|
|
#pragma warning suppress 56500 // covered by FxCOP
|
|
catch (Exception ex)
|
|
{
|
|
if (this.useCachedFactory &&
|
|
(ex is CommunicationException ||
|
|
ex is ObjectDisposedException ||
|
|
ex is TimeoutException))
|
|
{
|
|
DiagnosticUtility.TraceHandledException(ex, TraceEventType.Warning);
|
|
InvalidateCacheAndCreateChannel();
|
|
}
|
|
else
|
|
{
|
|
#pragma warning suppress 56503 // [....], We throw only for unknown exceptions.
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CreateChannelInternal();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return channel;
|
|
}
|
|
}
|
|
|
|
public static CacheSetting CacheSetting
|
|
{
|
|
get
|
|
{
|
|
return cacheSetting;
|
|
}
|
|
set
|
|
{
|
|
lock (cacheLock)
|
|
{
|
|
if (isCacheSettingReadOnly && cacheSetting != value)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxImmutableClientBaseCacheSetting, typeof(TChannel).ToString())));
|
|
}
|
|
else
|
|
{
|
|
cacheSetting = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public ChannelFactory<TChannel> ChannelFactory
|
|
{
|
|
get
|
|
{
|
|
if (cacheSetting == CacheSetting.Default)
|
|
{
|
|
TryDisableSharing();
|
|
}
|
|
return GetChannelFactory();
|
|
}
|
|
}
|
|
|
|
public ClientCredentials ClientCredentials
|
|
{
|
|
get
|
|
{
|
|
if (cacheSetting == CacheSetting.Default)
|
|
{
|
|
TryDisableSharing();
|
|
}
|
|
return this.ChannelFactory.Credentials;
|
|
}
|
|
}
|
|
|
|
public CommunicationState State
|
|
{
|
|
get
|
|
{
|
|
IChannel channel = (IChannel)this.channel;
|
|
if (channel != null)
|
|
{
|
|
return channel.State;
|
|
}
|
|
else
|
|
{
|
|
// we may have failed to create the channel under open, in which case we our factory wouldn't be open
|
|
if (!this.useCachedFactory)
|
|
{
|
|
return GetChannelFactory().State;
|
|
}
|
|
else
|
|
{
|
|
return CommunicationState.Created;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public IClientChannel InnerChannel
|
|
{
|
|
get
|
|
{
|
|
return (IClientChannel)Channel;
|
|
}
|
|
}
|
|
|
|
public ServiceEndpoint Endpoint
|
|
{
|
|
get
|
|
{
|
|
if (cacheSetting == CacheSetting.Default)
|
|
{
|
|
TryDisableSharing();
|
|
}
|
|
return GetChannelFactory().Endpoint;
|
|
}
|
|
}
|
|
|
|
public void Open()
|
|
{
|
|
((ICommunicationObject)this).Open(GetChannelFactory().InternalOpenTimeout);
|
|
}
|
|
|
|
public void Abort()
|
|
{
|
|
IChannel channel = (IChannel)this.channel;
|
|
if (channel != null)
|
|
{
|
|
channel.Abort();
|
|
}
|
|
|
|
if (!channelFactoryRefReleased)
|
|
{
|
|
lock (staticLock)
|
|
{
|
|
if (!channelFactoryRefReleased)
|
|
{
|
|
if (this.channelFactoryRef.Release())
|
|
{
|
|
this.releasedLastRef = true;
|
|
}
|
|
|
|
channelFactoryRefReleased = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Abort the ChannelFactory if we released the last one. We should be able to abort it when another thread is closing it.
|
|
if (this.releasedLastRef)
|
|
{
|
|
this.channelFactoryRef.Abort();
|
|
}
|
|
}
|
|
|
|
public void Close()
|
|
{
|
|
((ICommunicationObject)this).Close(GetChannelFactory().InternalCloseTimeout);
|
|
}
|
|
|
|
public void DisplayInitializationUI()
|
|
{
|
|
((IClientChannel)this.InnerChannel).DisplayInitializationUI();
|
|
}
|
|
|
|
// This ensures that the cachesetting (on, off or default) cannot be modified by
|
|
// another ClientBase instance of matching TChannel after the first instance is created.
|
|
void MakeCacheSettingReadOnly()
|
|
{
|
|
if (isCacheSettingReadOnly)
|
|
return;
|
|
|
|
lock (cacheLock)
|
|
{
|
|
isCacheSettingReadOnly = true;
|
|
}
|
|
}
|
|
|
|
void CreateChannelInternal()
|
|
{
|
|
try
|
|
{
|
|
this.channel = this.CreateChannel();
|
|
if (this.sharingFinalized)
|
|
{
|
|
if (this.canShareFactory && !this.useCachedFactory)
|
|
{
|
|
// It is OK to add ChannelFactory to the cache now.
|
|
TryAddChannelFactoryToCache();
|
|
}
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
if (!this.sharingFinalized && cacheSetting == CacheSetting.Default)
|
|
{
|
|
// this.CreateChannel() is not called. For safety, we disable sharing.
|
|
TryDisableSharing();
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual TChannel CreateChannel()
|
|
{
|
|
if (this.sharingFinalized)
|
|
return GetChannelFactory().CreateChannel();
|
|
|
|
lock (this.finalizeLock)
|
|
{
|
|
this.sharingFinalized = true;
|
|
return GetChannelFactory().CreateChannel();
|
|
}
|
|
}
|
|
|
|
void IDisposable.Dispose()
|
|
{
|
|
this.Close();
|
|
}
|
|
|
|
void ICommunicationObject.Open(TimeSpan timeout)
|
|
{
|
|
TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
|
|
if (!this.useCachedFactory)
|
|
{
|
|
GetChannelFactory().Open(timeoutHelper.RemainingTime());
|
|
}
|
|
|
|
this.InnerChannel.Open(timeoutHelper.RemainingTime());
|
|
}
|
|
|
|
void ICommunicationObject.Close(TimeSpan timeout)
|
|
{
|
|
using (ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.CreateBoundedActivity() : null)
|
|
{
|
|
if (DiagnosticUtility.ShouldUseActivity)
|
|
{
|
|
ServiceModelActivity.Start(activity, SR.GetString(SR.ActivityCloseClientBase, typeof(TChannel).FullName), ActivityType.Close);
|
|
}
|
|
TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
|
|
|
|
if (this.channel != null)
|
|
{
|
|
InnerChannel.Close(timeoutHelper.RemainingTime());
|
|
}
|
|
|
|
if (!channelFactoryRefReleased)
|
|
{
|
|
lock (staticLock)
|
|
{
|
|
if (!channelFactoryRefReleased)
|
|
{
|
|
if (this.channelFactoryRef.Release())
|
|
{
|
|
this.releasedLastRef = true;
|
|
}
|
|
|
|
this.channelFactoryRefReleased = true;
|
|
}
|
|
}
|
|
|
|
// Close the factory outside of the lock so that we can abort from a different thread.
|
|
if (this.releasedLastRef)
|
|
{
|
|
if (this.useCachedFactory)
|
|
{
|
|
this.channelFactoryRef.Abort();
|
|
}
|
|
else
|
|
{
|
|
this.channelFactoryRef.Close(timeoutHelper.RemainingTime());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
event EventHandler ICommunicationObject.Closed
|
|
{
|
|
add
|
|
{
|
|
this.InnerChannel.Closed += value;
|
|
}
|
|
remove
|
|
{
|
|
this.InnerChannel.Closed -= value;
|
|
}
|
|
}
|
|
|
|
event EventHandler ICommunicationObject.Closing
|
|
{
|
|
add
|
|
{
|
|
this.InnerChannel.Closing += value;
|
|
}
|
|
remove
|
|
{
|
|
this.InnerChannel.Closing -= value;
|
|
}
|
|
}
|
|
|
|
event EventHandler ICommunicationObject.Faulted
|
|
{
|
|
add
|
|
{
|
|
this.InnerChannel.Faulted += value;
|
|
}
|
|
remove
|
|
{
|
|
this.InnerChannel.Faulted -= value;
|
|
}
|
|
}
|
|
|
|
event EventHandler ICommunicationObject.Opened
|
|
{
|
|
add
|
|
{
|
|
this.InnerChannel.Opened += value;
|
|
}
|
|
remove
|
|
{
|
|
this.InnerChannel.Opened -= value;
|
|
}
|
|
}
|
|
|
|
event EventHandler ICommunicationObject.Opening
|
|
{
|
|
add
|
|
{
|
|
this.InnerChannel.Opening += value;
|
|
}
|
|
remove
|
|
{
|
|
this.InnerChannel.Opening -= value;
|
|
}
|
|
}
|
|
|
|
IAsyncResult ICommunicationObject.BeginClose(AsyncCallback callback, object state)
|
|
{
|
|
return ((ICommunicationObject)this).BeginClose(GetChannelFactory().InternalCloseTimeout, callback, state);
|
|
}
|
|
|
|
IAsyncResult ICommunicationObject.BeginClose(TimeSpan timeout, AsyncCallback callback, object state)
|
|
{
|
|
return new ChainedAsyncResult(timeout, callback, state, BeginChannelClose, EndChannelClose, BeginFactoryClose, EndFactoryClose);
|
|
}
|
|
|
|
void ICommunicationObject.EndClose(IAsyncResult result)
|
|
{
|
|
ChainedAsyncResult.End(result);
|
|
}
|
|
|
|
IAsyncResult ICommunicationObject.BeginOpen(AsyncCallback callback, object state)
|
|
{
|
|
return ((ICommunicationObject)this).BeginOpen(GetChannelFactory().InternalOpenTimeout, callback, state);
|
|
}
|
|
|
|
IAsyncResult ICommunicationObject.BeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
|
|
{
|
|
return new ChainedAsyncResult(timeout, callback, state, BeginFactoryOpen, EndFactoryOpen, BeginChannelOpen, EndChannelOpen);
|
|
}
|
|
|
|
void ICommunicationObject.EndOpen(IAsyncResult result)
|
|
{
|
|
ChainedAsyncResult.End(result);
|
|
}
|
|
|
|
//ChainedAsyncResult methods for opening and closing ChannelFactory<T>
|
|
|
|
internal IAsyncResult BeginFactoryOpen(TimeSpan timeout, AsyncCallback callback, object state)
|
|
{
|
|
if (this.useCachedFactory)
|
|
{
|
|
return new CompletedAsyncResult(callback, state);
|
|
}
|
|
else
|
|
{
|
|
return GetChannelFactory().BeginOpen(timeout, callback, state);
|
|
}
|
|
}
|
|
|
|
internal void EndFactoryOpen(IAsyncResult result)
|
|
{
|
|
if (this.useCachedFactory)
|
|
{
|
|
CompletedAsyncResult.End(result);
|
|
}
|
|
else
|
|
{
|
|
GetChannelFactory().EndOpen(result);
|
|
}
|
|
}
|
|
|
|
internal IAsyncResult BeginChannelOpen(TimeSpan timeout, AsyncCallback callback, object state)
|
|
{
|
|
return this.InnerChannel.BeginOpen(timeout, callback, state);
|
|
}
|
|
|
|
internal void EndChannelOpen(IAsyncResult result)
|
|
{
|
|
this.InnerChannel.EndOpen(result);
|
|
}
|
|
|
|
internal IAsyncResult BeginFactoryClose(TimeSpan timeout, AsyncCallback callback, object state)
|
|
{
|
|
if (this.useCachedFactory)
|
|
{
|
|
return new CompletedAsyncResult(callback, state);
|
|
}
|
|
else
|
|
{
|
|
return GetChannelFactory().BeginClose(timeout, callback, state);
|
|
}
|
|
}
|
|
|
|
internal void EndFactoryClose(IAsyncResult result)
|
|
{
|
|
if (typeof(CompletedAsyncResult).IsAssignableFrom(result.GetType()))
|
|
{
|
|
CompletedAsyncResult.End(result);
|
|
}
|
|
else
|
|
{
|
|
GetChannelFactory().EndClose(result);
|
|
}
|
|
}
|
|
|
|
internal IAsyncResult BeginChannelClose(TimeSpan timeout, AsyncCallback callback, object state)
|
|
{
|
|
if (this.channel != null)
|
|
{
|
|
return this.InnerChannel.BeginClose(timeout, callback, state);
|
|
}
|
|
else
|
|
{
|
|
return new CompletedAsyncResult(callback, state);
|
|
}
|
|
}
|
|
|
|
internal void EndChannelClose(IAsyncResult result)
|
|
{
|
|
if (typeof(CompletedAsyncResult).IsAssignableFrom(result.GetType()))
|
|
{
|
|
CompletedAsyncResult.End(result);
|
|
}
|
|
else
|
|
{
|
|
this.InnerChannel.EndClose(result);
|
|
}
|
|
}
|
|
|
|
ChannelFactory<TChannel> GetChannelFactory()
|
|
{
|
|
return this.channelFactoryRef.ChannelFactory;
|
|
}
|
|
|
|
void InitializeChannelFactoryRef()
|
|
{
|
|
Fx.Assert(this.channelFactoryRef == null, "The channelFactory should have never been assigned");
|
|
Fx.Assert(this.canShareFactory, "GetChannelFactoryFromCache can be called only when canShareFactory is true");
|
|
lock (staticLock)
|
|
{
|
|
ChannelFactoryRef<TChannel> factoryRef;
|
|
if (factoryRefCache.TryGetValue(this.endpointTrait, out factoryRef))
|
|
{
|
|
if (factoryRef.ChannelFactory.State != CommunicationState.Opened)
|
|
{
|
|
// Remove the bad ChannelFactory.
|
|
factoryRefCache.Remove(this.endpointTrait);
|
|
}
|
|
else
|
|
{
|
|
this.channelFactoryRef = factoryRef;
|
|
this.channelFactoryRef.AddRef();
|
|
useCachedFactory = true;
|
|
if (TD.ClientBaseChannelFactoryCacheHitIsEnabled())
|
|
{
|
|
TD.ClientBaseChannelFactoryCacheHit(this);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (this.channelFactoryRef == null)
|
|
{
|
|
// Creating the ChannelFactory at initial time to catch configuration exception earlier.
|
|
this.channelFactoryRef = CreateChannelFactoryRef(this.endpointTrait);
|
|
}
|
|
}
|
|
|
|
static ChannelFactoryRef<TChannel> CreateChannelFactoryRef(EndpointTrait<TChannel> endpointTrait)
|
|
{
|
|
Fx.Assert(endpointTrait != null, "The endpointTrait should not be null when the factory can be shared.");
|
|
|
|
ChannelFactory<TChannel> channelFactory = endpointTrait.CreateChannelFactory();
|
|
channelFactory.TraceOpenAndClose = false;
|
|
return new ChannelFactoryRef<TChannel>(channelFactory);
|
|
}
|
|
|
|
// Once the channel is created, we can't disable caching.
|
|
// This method can be called safely multiple times.
|
|
// this.sharingFinalized is set the first time the method is called.
|
|
// Subsequent calls are essentially no-ops.
|
|
void TryDisableSharing()
|
|
{
|
|
if (this.sharingFinalized)
|
|
return;
|
|
|
|
lock (this.finalizeLock)
|
|
{
|
|
if (this.sharingFinalized)
|
|
return;
|
|
|
|
this.canShareFactory = false;
|
|
this.sharingFinalized = true;
|
|
|
|
if (this.useCachedFactory)
|
|
{
|
|
ChannelFactoryRef<TChannel> pendingFactoryRef = this.channelFactoryRef;
|
|
this.channelFactoryRef = CreateChannelFactoryRef(this.endpointTrait);
|
|
this.useCachedFactory = false;
|
|
|
|
lock (staticLock)
|
|
{
|
|
if (!pendingFactoryRef.Release())
|
|
{
|
|
pendingFactoryRef = null;
|
|
}
|
|
}
|
|
|
|
if (pendingFactoryRef != null)
|
|
pendingFactoryRef.Abort();
|
|
}
|
|
}
|
|
|
|
// can be done outside the lock since the lines below do not access shared data.
|
|
// also the use of this.sharingFinalized in the lines above ensures that tracing
|
|
// happens only once and only when needed.
|
|
if (TD.ClientBaseUsingLocalChannelFactoryIsEnabled())
|
|
{
|
|
TD.ClientBaseUsingLocalChannelFactory(this);
|
|
}
|
|
}
|
|
|
|
void TryAddChannelFactoryToCache()
|
|
{
|
|
Fx.Assert(this.canShareFactory, "This should be called only when this proxy can share ChannelFactory.");
|
|
Fx.Assert(this.channelFactoryRef.ChannelFactory.State == CommunicationState.Opened,
|
|
"The ChannelFactory must be in Opened state for caching.");
|
|
|
|
// Lock the cache and add the item to synchronize with lookup.
|
|
lock (staticLock)
|
|
{
|
|
ChannelFactoryRef<TChannel> cfRef;
|
|
if (!factoryRefCache.TryGetValue(this.endpointTrait, out cfRef))
|
|
{
|
|
// Increment the ref count before adding to the cache.
|
|
this.channelFactoryRef.AddRef();
|
|
factoryRefCache.Add(this.endpointTrait, this.channelFactoryRef);
|
|
this.useCachedFactory = true;
|
|
if (TD.ClientBaseCachedChannelFactoryCountIsEnabled())
|
|
{
|
|
TD.ClientBaseCachedChannelFactoryCount(factoryRefCache.Count, maxNumChannelFactories, this);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// NOTE: This should be called inside ThisLock
|
|
void InvalidateCacheAndCreateChannel()
|
|
{
|
|
RemoveFactoryFromCache();
|
|
TryDisableSharing();
|
|
CreateChannelInternal();
|
|
}
|
|
|
|
void RemoveFactoryFromCache()
|
|
{
|
|
lock (staticLock)
|
|
{
|
|
ChannelFactoryRef<TChannel> factoryRef;
|
|
if (factoryRefCache.TryGetValue(this.endpointTrait, out factoryRef))
|
|
{
|
|
if (object.ReferenceEquals(this.channelFactoryRef, factoryRef))
|
|
{
|
|
factoryRefCache.Remove(this.endpointTrait);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// WARNING: changes in the signature/name of the following delegates must be applied to the
|
|
// ClientClassGenerator.cs as well, otherwise the ClientClassGenerator would generate wrong code.
|
|
protected delegate IAsyncResult BeginOperationDelegate(object[] inValues, AsyncCallback asyncCallback, object state);
|
|
protected delegate object[] EndOperationDelegate(IAsyncResult result);
|
|
|
|
// WARNING: Any changes in the signature/name of the following type and its ctor must be applied to the
|
|
// ClientClassGenerator.cs as well, otherwise the ClientClassGenerator would generate wrong code.
|
|
protected class InvokeAsyncCompletedEventArgs : AsyncCompletedEventArgs
|
|
{
|
|
object[] results;
|
|
|
|
internal InvokeAsyncCompletedEventArgs(object[] results, Exception error, bool cancelled, object userState)
|
|
: base(error, cancelled, userState)
|
|
{
|
|
this.results = results;
|
|
}
|
|
|
|
public object[] Results
|
|
{
|
|
get
|
|
{
|
|
return this.results;
|
|
}
|
|
}
|
|
}
|
|
|
|
// WARNING: Any changes in the signature/name of the following method ctor must be applied to the
|
|
// ClientClassGenerator.cs as well, otherwise the ClientClassGenerator would generate wrong code.
|
|
protected void InvokeAsync(BeginOperationDelegate beginOperationDelegate, object[] inValues,
|
|
EndOperationDelegate endOperationDelegate, SendOrPostCallback operationCompletedCallback, object userState)
|
|
{
|
|
if (beginOperationDelegate == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("beginOperationDelegate");
|
|
}
|
|
if (endOperationDelegate == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endOperationDelegate");
|
|
}
|
|
|
|
AsyncOperation asyncOperation = AsyncOperationManager.CreateOperation(userState);
|
|
AsyncOperationContext context = new AsyncOperationContext(asyncOperation, endOperationDelegate, operationCompletedCallback);
|
|
|
|
Exception error = null;
|
|
object[] results = null;
|
|
IAsyncResult result = null;
|
|
try
|
|
{
|
|
result = beginOperationDelegate(inValues, onAsyncCallCompleted, context);
|
|
if (result.CompletedSynchronously)
|
|
{
|
|
results = endOperationDelegate(result);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
if (Fx.IsFatal(e))
|
|
{
|
|
throw;
|
|
}
|
|
error = e;
|
|
}
|
|
|
|
if (error != null || result.CompletedSynchronously) /* result cannot be null if error == null */
|
|
{
|
|
CompleteAsyncCall(context, results, error);
|
|
}
|
|
}
|
|
|
|
static void OnAsyncCallCompleted(IAsyncResult result)
|
|
{
|
|
if (result.CompletedSynchronously)
|
|
{
|
|
return;
|
|
}
|
|
|
|
AsyncOperationContext context = (AsyncOperationContext)result.AsyncState;
|
|
Exception error = null;
|
|
object[] results = null;
|
|
try
|
|
{
|
|
results = context.EndDelegate(result);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
if (Fx.IsFatal(e))
|
|
{
|
|
throw;
|
|
}
|
|
|
|
error = e;
|
|
}
|
|
|
|
CompleteAsyncCall(context, results, error);
|
|
}
|
|
|
|
static void CompleteAsyncCall(AsyncOperationContext context, object[] results, Exception error)
|
|
{
|
|
if (context.CompletionCallback != null)
|
|
{
|
|
InvokeAsyncCompletedEventArgs e = new InvokeAsyncCompletedEventArgs(results, error, false, context.AsyncOperation.UserSuppliedState);
|
|
context.AsyncOperation.PostOperationCompleted(context.CompletionCallback, e);
|
|
}
|
|
else
|
|
{
|
|
context.AsyncOperation.OperationCompleted();
|
|
}
|
|
}
|
|
|
|
class AsyncOperationContext
|
|
{
|
|
AsyncOperation asyncOperation;
|
|
EndOperationDelegate endDelegate;
|
|
SendOrPostCallback completionCallback;
|
|
|
|
internal AsyncOperationContext(AsyncOperation asyncOperation, EndOperationDelegate endDelegate, SendOrPostCallback completionCallback)
|
|
{
|
|
this.asyncOperation = asyncOperation;
|
|
this.endDelegate = endDelegate;
|
|
this.completionCallback = completionCallback;
|
|
}
|
|
|
|
internal AsyncOperation AsyncOperation
|
|
{
|
|
get
|
|
{
|
|
return this.asyncOperation;
|
|
}
|
|
}
|
|
|
|
internal EndOperationDelegate EndDelegate
|
|
{
|
|
get
|
|
{
|
|
return this.endDelegate;
|
|
}
|
|
}
|
|
|
|
internal SendOrPostCallback CompletionCallback
|
|
{
|
|
get
|
|
{
|
|
return this.completionCallback;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected class ChannelBase<T> : IClientChannel, IOutputChannel, IRequestChannel, IChannelBaseProxy
|
|
where T : class
|
|
{
|
|
ServiceChannel channel;
|
|
System.ServiceModel.Dispatcher.ImmutableClientRuntime runtime;
|
|
|
|
protected ChannelBase(ClientBase<T> client)
|
|
{
|
|
if (client.Endpoint.Address == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxChannelFactoryEndpointAddressUri)));
|
|
}
|
|
|
|
ChannelFactory<T> cf = client.ChannelFactory;
|
|
cf.EnsureOpened(); // to prevent the NullReferenceException that is thrown if the ChannelFactory is not open when cf.ServiceChannelFactory is accessed.
|
|
this.channel = cf.ServiceChannelFactory.CreateServiceChannel(client.Endpoint.Address, client.Endpoint.Address.Uri);
|
|
this.channel.InstanceContext = cf.CallbackInstance;
|
|
this.runtime = this.channel.ClientRuntime.GetRuntime();
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Accesses the critical IMethodCallMessage interface.",
|
|
Safe = "The implementation of IMethodCallMessage is local and is created locally as weell; i.e. not passed in from Remoting.")]
|
|
[SecuritySafeCritical]
|
|
protected IAsyncResult BeginInvoke(string methodName, object[] args, AsyncCallback callback, object state)
|
|
{
|
|
object[] inArgs = new object[args.Length + 2];
|
|
Array.Copy(args, inArgs, args.Length);
|
|
inArgs[inArgs.Length - 2] = callback;
|
|
inArgs[inArgs.Length - 1] = state;
|
|
|
|
IMethodCallMessage methodCall = new MethodCallMessage(inArgs);
|
|
ProxyOperationRuntime op = GetOperationByName(methodName);
|
|
object[] ins = op.MapAsyncBeginInputs(methodCall, out callback, out state);
|
|
return this.channel.BeginCall(op.Action, op.IsOneWay, op, ins, callback, state);
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Accesses the critical IMethodCallMessage interface.",
|
|
Safe = "The implementation of IMethodCallMessage is local and is created locally as weell; i.e. not passed in from Remoting.")]
|
|
[SecuritySafeCritical]
|
|
protected object EndInvoke(string methodName, object[] args, IAsyncResult result)
|
|
{
|
|
object[] inArgs = new object[args.Length + 1];
|
|
Array.Copy(args, inArgs, args.Length);
|
|
inArgs[inArgs.Length - 1] = result;
|
|
|
|
IMethodCallMessage methodCall = new MethodCallMessage(inArgs);
|
|
ProxyOperationRuntime op = GetOperationByName(methodName);
|
|
object[] outs;
|
|
op.MapAsyncEndInputs(methodCall, out result, out outs);
|
|
object ret = this.channel.EndCall(op.Action, outs, result);
|
|
object[] retArgs = op.MapAsyncOutputs(methodCall, outs, ref ret);
|
|
if (retArgs != null)
|
|
{
|
|
Fx.Assert(retArgs.Length == inArgs.Length, "retArgs.Length should be equal to inArgs.Length");
|
|
Array.Copy(retArgs, args, args.Length);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
System.ServiceModel.Dispatcher.ProxyOperationRuntime GetOperationByName(string methodName)
|
|
{
|
|
ProxyOperationRuntime op = this.runtime.GetOperationByName(methodName);
|
|
if (op == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SFxMethodNotSupported1, methodName)));
|
|
}
|
|
return op;
|
|
}
|
|
|
|
bool IClientChannel.AllowInitializationUI
|
|
{
|
|
get { return ((IClientChannel)this.channel).AllowInitializationUI; }
|
|
set { ((IClientChannel)this.channel).AllowInitializationUI = value; }
|
|
}
|
|
|
|
bool IClientChannel.DidInteractiveInitialization
|
|
{
|
|
get { return ((IClientChannel)this.channel).DidInteractiveInitialization; }
|
|
}
|
|
|
|
Uri IClientChannel.Via
|
|
{
|
|
get { return ((IClientChannel)this.channel).Via; }
|
|
}
|
|
|
|
event EventHandler<UnknownMessageReceivedEventArgs> IClientChannel.UnknownMessageReceived
|
|
{
|
|
add { ((IClientChannel)this.channel).UnknownMessageReceived += value; }
|
|
remove { ((IClientChannel)this.channel).UnknownMessageReceived -= value; }
|
|
}
|
|
|
|
void IClientChannel.DisplayInitializationUI()
|
|
{
|
|
((IClientChannel)this.channel).DisplayInitializationUI();
|
|
}
|
|
|
|
IAsyncResult IClientChannel.BeginDisplayInitializationUI(AsyncCallback callback, object state)
|
|
{
|
|
return ((IClientChannel)this.channel).BeginDisplayInitializationUI(callback, state);
|
|
}
|
|
|
|
void IClientChannel.EndDisplayInitializationUI(IAsyncResult result)
|
|
{
|
|
((IClientChannel)this.channel).EndDisplayInitializationUI(result);
|
|
}
|
|
|
|
bool IContextChannel.AllowOutputBatching
|
|
{
|
|
get { return ((IContextChannel)this.channel).AllowOutputBatching; }
|
|
set { ((IContextChannel)this.channel).AllowOutputBatching = value; }
|
|
}
|
|
|
|
IInputSession IContextChannel.InputSession
|
|
{
|
|
get { return ((IContextChannel)this.channel).InputSession; }
|
|
}
|
|
|
|
EndpointAddress IContextChannel.LocalAddress
|
|
{
|
|
get { return ((IContextChannel)this.channel).LocalAddress; }
|
|
}
|
|
|
|
TimeSpan IContextChannel.OperationTimeout
|
|
{
|
|
get { return ((IContextChannel)this.channel).OperationTimeout; }
|
|
set { ((IContextChannel)this.channel).OperationTimeout = value; }
|
|
}
|
|
|
|
IOutputSession IContextChannel.OutputSession
|
|
{
|
|
get { return ((IContextChannel)this.channel).OutputSession; }
|
|
}
|
|
|
|
EndpointAddress IContextChannel.RemoteAddress
|
|
{
|
|
get { return ((IContextChannel)this.channel).RemoteAddress; }
|
|
}
|
|
|
|
string IContextChannel.SessionId
|
|
{
|
|
get { return ((IContextChannel)this.channel).SessionId; }
|
|
}
|
|
|
|
TProperty IChannel.GetProperty<TProperty>()
|
|
{
|
|
return ((IChannel)this.channel).GetProperty<TProperty>();
|
|
}
|
|
|
|
CommunicationState ICommunicationObject.State
|
|
{
|
|
get { return ((ICommunicationObject)this.channel).State; }
|
|
}
|
|
|
|
event EventHandler ICommunicationObject.Closed
|
|
{
|
|
add { ((ICommunicationObject)this.channel).Closed += value; }
|
|
remove { ((ICommunicationObject)this.channel).Closed -= value; }
|
|
}
|
|
|
|
event EventHandler ICommunicationObject.Closing
|
|
{
|
|
add { ((ICommunicationObject)this.channel).Closing += value; }
|
|
remove { ((ICommunicationObject)this.channel).Closing -= value; }
|
|
}
|
|
|
|
event EventHandler ICommunicationObject.Faulted
|
|
{
|
|
add { ((ICommunicationObject)this.channel).Faulted += value; }
|
|
remove { ((ICommunicationObject)this.channel).Faulted -= value; }
|
|
}
|
|
|
|
event EventHandler ICommunicationObject.Opened
|
|
{
|
|
add { ((ICommunicationObject)this.channel).Opened += value; }
|
|
remove { ((ICommunicationObject)this.channel).Opened -= value; }
|
|
}
|
|
|
|
event EventHandler ICommunicationObject.Opening
|
|
{
|
|
add { ((ICommunicationObject)this.channel).Opening += value; }
|
|
remove { ((ICommunicationObject)this.channel).Opening -= value; }
|
|
}
|
|
|
|
void ICommunicationObject.Abort()
|
|
{
|
|
((ICommunicationObject)this.channel).Abort();
|
|
}
|
|
|
|
void ICommunicationObject.Close()
|
|
{
|
|
((ICommunicationObject)this.channel).Close();
|
|
}
|
|
|
|
void ICommunicationObject.Close(TimeSpan timeout)
|
|
{
|
|
((ICommunicationObject)this.channel).Close(timeout);
|
|
}
|
|
|
|
IAsyncResult ICommunicationObject.BeginClose(AsyncCallback callback, object state)
|
|
{
|
|
return ((ICommunicationObject)this.channel).BeginClose(callback, state);
|
|
}
|
|
|
|
IAsyncResult ICommunicationObject.BeginClose(TimeSpan timeout, AsyncCallback callback, object state)
|
|
{
|
|
return ((ICommunicationObject)this.channel).BeginClose(timeout, callback, state);
|
|
}
|
|
|
|
void ICommunicationObject.EndClose(IAsyncResult result)
|
|
{
|
|
((ICommunicationObject)this.channel).EndClose(result);
|
|
}
|
|
|
|
void ICommunicationObject.Open()
|
|
{
|
|
((ICommunicationObject)this.channel).Open();
|
|
}
|
|
|
|
void ICommunicationObject.Open(TimeSpan timeout)
|
|
{
|
|
((ICommunicationObject)this.channel).Open(timeout);
|
|
}
|
|
|
|
IAsyncResult ICommunicationObject.BeginOpen(AsyncCallback callback, object state)
|
|
{
|
|
return ((ICommunicationObject)this.channel).BeginOpen(callback, state);
|
|
}
|
|
|
|
IAsyncResult ICommunicationObject.BeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
|
|
{
|
|
return ((ICommunicationObject)this.channel).BeginOpen(timeout, callback, state);
|
|
}
|
|
|
|
void ICommunicationObject.EndOpen(IAsyncResult result)
|
|
{
|
|
((ICommunicationObject)this.channel).EndOpen(result);
|
|
}
|
|
|
|
IExtensionCollection<IContextChannel> IExtensibleObject<IContextChannel>.Extensions
|
|
{
|
|
get { return ((IExtensibleObject<IContextChannel>)this.channel).Extensions; }
|
|
}
|
|
|
|
void IDisposable.Dispose()
|
|
{
|
|
((IDisposable)this.channel).Dispose();
|
|
}
|
|
|
|
Uri IOutputChannel.Via
|
|
{
|
|
get { return ((IOutputChannel)this.channel).Via; }
|
|
}
|
|
|
|
EndpointAddress IOutputChannel.RemoteAddress
|
|
{
|
|
get { return ((IOutputChannel)this.channel).RemoteAddress; }
|
|
}
|
|
|
|
void IOutputChannel.Send(Message message)
|
|
{
|
|
((IOutputChannel)this.channel).Send(message);
|
|
}
|
|
|
|
void IOutputChannel.Send(Message message, TimeSpan timeout)
|
|
{
|
|
((IOutputChannel)this.channel).Send(message, timeout);
|
|
}
|
|
|
|
IAsyncResult IOutputChannel.BeginSend(Message message, AsyncCallback callback, object state)
|
|
{
|
|
return ((IOutputChannel)this.channel).BeginSend(message, callback, state);
|
|
}
|
|
|
|
IAsyncResult IOutputChannel.BeginSend(Message message, TimeSpan timeout, AsyncCallback callback, object state)
|
|
{
|
|
return ((IOutputChannel)this.channel).BeginSend(message, timeout, callback, state);
|
|
}
|
|
|
|
void IOutputChannel.EndSend(IAsyncResult result)
|
|
{
|
|
((IOutputChannel)this.channel).EndSend(result);
|
|
}
|
|
|
|
Uri IRequestChannel.Via
|
|
{
|
|
get { return ((IRequestChannel)this.channel).Via; }
|
|
}
|
|
|
|
EndpointAddress IRequestChannel.RemoteAddress
|
|
{
|
|
get { return ((IRequestChannel)this.channel).RemoteAddress; }
|
|
}
|
|
|
|
Message IRequestChannel.Request(Message message)
|
|
{
|
|
return ((IRequestChannel)this.channel).Request(message);
|
|
}
|
|
|
|
Message IRequestChannel.Request(Message message, TimeSpan timeout)
|
|
{
|
|
return ((IRequestChannel)this.channel).Request(message, timeout);
|
|
}
|
|
|
|
IAsyncResult IRequestChannel.BeginRequest(Message message, AsyncCallback callback, object state)
|
|
{
|
|
return ((IRequestChannel)this.channel).BeginRequest(message, callback, state);
|
|
}
|
|
|
|
IAsyncResult IRequestChannel.BeginRequest(Message message, TimeSpan timeout, AsyncCallback callback, object state)
|
|
{
|
|
return ((IRequestChannel)this.channel).BeginRequest(message, timeout, callback, state);
|
|
}
|
|
|
|
Message IRequestChannel.EndRequest(IAsyncResult result)
|
|
{
|
|
return ((IRequestChannel)this.channel).EndRequest(result);
|
|
}
|
|
|
|
ServiceChannel IChannelBaseProxy.GetServiceChannel()
|
|
{
|
|
return this.channel;
|
|
}
|
|
|
|
class MethodCallMessage : IMethodCallMessage
|
|
{
|
|
readonly object[] args;
|
|
|
|
public MethodCallMessage(object[] args)
|
|
{
|
|
this.args = args;
|
|
}
|
|
|
|
public object[] Args
|
|
{
|
|
get { return this.args; }
|
|
}
|
|
|
|
public int ArgCount
|
|
{
|
|
get { return this.args.Length; }
|
|
}
|
|
|
|
public LogicalCallContext LogicalCallContext
|
|
{
|
|
get { return null; }
|
|
}
|
|
|
|
public object GetInArg(int argNum)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
|
|
}
|
|
|
|
public string GetInArgName(int index)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
|
|
}
|
|
|
|
public int InArgCount
|
|
{
|
|
get
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
|
|
}
|
|
}
|
|
|
|
public object[] InArgs
|
|
{
|
|
get { return this.args; }
|
|
}
|
|
|
|
|
|
public object GetArg(int argNum)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
|
|
}
|
|
|
|
public string GetArgName(int index)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
|
|
}
|
|
|
|
public bool HasVarArgs
|
|
{
|
|
get
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
|
|
}
|
|
}
|
|
|
|
public Reflection.MethodBase MethodBase
|
|
{
|
|
get
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
|
|
}
|
|
}
|
|
|
|
public string MethodName
|
|
{
|
|
get
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
|
|
}
|
|
}
|
|
|
|
public object MethodSignature
|
|
{
|
|
get
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
|
|
}
|
|
}
|
|
|
|
public string TypeName
|
|
{
|
|
get
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
|
|
}
|
|
}
|
|
|
|
public string Uri
|
|
{
|
|
get
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
|
|
}
|
|
}
|
|
|
|
public Collections.IDictionary Properties
|
|
{
|
|
get
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|