|
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.ServiceModel.Channels
{
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime;
using System.ServiceModel;
using System.ServiceModel.Diagnostics;
using System.ServiceModel.Diagnostics.Application;
public abstract class CommunicationObject : ICommunicationObject
{
bool aborted;
bool closeCalled;
#if DEBUG
StackTrace closeStack;
StackTrace faultedStack;
#endif
ExceptionQueue exceptionQueue;
object mutex;
bool onClosingCalled;
bool onClosedCalled;
bool onOpeningCalled;
bool onOpenedCalled;
bool raisedClosed;
bool raisedClosing;
bool raisedFaulted;
bool traceOpenAndClose;
object eventSender;
CommunicationState state;
protected CommunicationObject()
: this(new object())
{
}
protected CommunicationObject(object mutex)
{
this.mutex = mutex;
this.eventSender = this;
this.state = CommunicationState.Created;
}
internal CommunicationObject(object mutex, object eventSender)
{
this.mutex = mutex;
this.eventSender = eventSender;
this.state = CommunicationState.Created;
}
internal bool Aborted
{
get { return this.aborted; }
}
internal object EventSender
{
get { return this.eventSender; }
set { eventSender = value; }
}
protected bool IsDisposed
{
get { return this.state == CommunicationState.Closed; }
}
public CommunicationState State
{
get { return this.state; }
}
protected object ThisLock
{
get { return this.mutex; }
}
protected abstract TimeSpan DefaultCloseTimeout { get; }
protected abstract TimeSpan DefaultOpenTimeout { get; }
internal TimeSpan InternalCloseTimeout
{
get { return this.DefaultCloseTimeout; }
}
internal TimeSpan InternalOpenTimeout
{
get { return this.DefaultOpenTimeout; }
}
public event EventHandler Closed;
public event EventHandler Closing;
public event EventHandler Faulted;
public event EventHandler Opened;
public event EventHandler Opening;
public void Abort()
{
lock (ThisLock)
{
if (this.aborted || this.state == CommunicationState.Closed)
return;
this.aborted = true;
#if DEBUG
if (closeStack == null)
closeStack = new StackTrace();
#endif
this.state = CommunicationState.Closing;
}
if (DiagnosticUtility.ShouldTraceInformation)
{
TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.CommunicationObjectAborted, SR.GetString(SR.TraceCodeCommunicationObjectAborted, TraceUtility.CreateSourceString(this)), this);
}
bool throwing = true;
try
{
OnClosing();
if (!this.onClosingCalled)
throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnClosing"), Guid.Empty, this);
OnAbort();
OnClosed();
if (!this.onClosedCalled)
throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnClosed"), Guid.Empty, this);
throwing = false;
}
finally
{
if (throwing)
{
if (DiagnosticUtility.ShouldTraceWarning)
TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.CommunicationObjectAbortFailed, SR.GetString(SR.TraceCodeCommunicationObjectAbortFailed, this.GetCommunicationObjectType().ToString()), this);
}
}
}
public IAsyncResult BeginClose(AsyncCallback callback, object state)
{
return this.BeginClose(this.DefaultCloseTimeout, callback, state);
}
public IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state)
{
if (timeout < TimeSpan.Zero)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new ArgumentOutOfRangeException("timeout", SR.GetString(SR.SFxTimeoutOutOfRange0)));
using (DiagnosticUtility.ShouldUseActivity && this.TraceOpenAndClose ? this.CreateCloseActivity() : null)
{
CommunicationState originalState;
lock (ThisLock)
{
originalState = this.state;
#if DEBUG
if (closeStack == null)
closeStack = new StackTrace();
#endif
if (originalState != CommunicationState.Closed)
this.state = CommunicationState.Closing;
this.closeCalled = true;
}
switch (originalState)
{
case CommunicationState.Created:
case CommunicationState.Opening:
case CommunicationState.Faulted:
this.Abort();
if (originalState == CommunicationState.Faulted)
{
throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this);
}
return new AlreadyClosedAsyncResult(callback, state);
case CommunicationState.Opened:
{
bool throwing = true;
try
{
OnClosing();
if (!this.onClosingCalled)
throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnClosing"), Guid.Empty, this);
IAsyncResult result = new CloseAsyncResult(this, timeout, callback, state);
throwing = false;
return result;
}
finally
{
if (throwing)
{
if (DiagnosticUtility.ShouldTraceWarning)
{
TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.CommunicationObjectCloseFailed, SR.GetString(SR.TraceCodeCommunicationObjectCloseFailed, this.GetCommunicationObjectType().ToString()), this);
}
Abort();
}
}
}
case CommunicationState.Closing:
case CommunicationState.Closed:
return new AlreadyClosedAsyncResult(callback, state);
default:
throw Fx.AssertAndThrow("CommunicationObject.BeginClose: Unknown CommunicationState");
}
}
}
public IAsyncResult BeginOpen(AsyncCallback callback, object state)
{
return this.BeginOpen(this.DefaultOpenTimeout, callback, state);
}
public IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
{
if (timeout < TimeSpan.Zero)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new ArgumentOutOfRangeException("timeout", SR.GetString(SR.SFxTimeoutOutOfRange0)));
lock (ThisLock)
{
ThrowIfDisposedOrImmutable();
this.state = CommunicationState.Opening;
}
bool throwing = true;
try
{
OnOpening();
if (!this.onOpeningCalled)
throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnOpening"), Guid.Empty, this);
IAsyncResult result = new OpenAsyncResult(this, timeout, callback, state);
throwing = false;
return result;
}
finally
{
if (throwing)
{
if (DiagnosticUtility.ShouldTraceWarning)
{
TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.CommunicationObjectOpenFailed, SR.GetString(SR.TraceCodeCommunicationObjectOpenFailed, this.GetCommunicationObjectType().ToString()), this);
}
Fault();
}
}
}
public void Close()
{
this.Close(this.DefaultCloseTimeout);
}
public void Close(TimeSpan timeout)
{
if (timeout < TimeSpan.Zero)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new ArgumentOutOfRangeException("timeout", SR.GetString(SR.SFxTimeoutOutOfRange0)));
using (DiagnosticUtility.ShouldUseActivity && this.TraceOpenAndClose ? this.CreateCloseActivity() : null)
{
CommunicationState originalState;
lock (ThisLock)
{
originalState = this.state;
#if DEBUG
if (closeStack == null)
closeStack = new StackTrace();
#endif
if (originalState != CommunicationState.Closed)
this.state = CommunicationState.Closing;
this.closeCalled = true;
}
switch (originalState)
{
case CommunicationState.Created:
case CommunicationState.Opening:
case CommunicationState.Faulted:
this.Abort();
if (originalState == CommunicationState.Faulted)
{
throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this);
}
break;
case CommunicationState.Opened:
{
bool throwing = true;
try
{
TimeoutHelper actualTimeout = new TimeoutHelper(timeout);
OnClosing();
if (!this.onClosingCalled)
throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnClosing"), Guid.Empty, this);
OnClose(actualTimeout.RemainingTime());
OnClosed();
if (!this.onClosedCalled)
throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnClosed"), Guid.Empty, this);
throwing = false;
}
finally
{
if (throwing)
{
if (DiagnosticUtility.ShouldTraceWarning)
{
TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.CommunicationObjectCloseFailed, SR.GetString(SR.TraceCodeCommunicationObjectCloseFailed, this.GetCommunicationObjectType().ToString()), this);
}
Abort();
}
}
break;
}
case CommunicationState.Closing:
case CommunicationState.Closed:
break;
default:
throw Fx.AssertAndThrow("CommunicationObject.BeginClose: Unknown CommunicationState");
}
}
}
Exception CreateNotOpenException()
{
return new InvalidOperationException(SR.GetString(SR.CommunicationObjectCannotBeUsed, this.GetCommunicationObjectType().ToString(), this.state.ToString()));
}
Exception CreateImmutableException()
{
return new InvalidOperationException(SR.GetString(SR.CommunicationObjectCannotBeModifiedInState, this.GetCommunicationObjectType().ToString(), this.state.ToString()));
}
Exception CreateBaseClassMethodNotCalledException(string method)
{
return new InvalidOperationException(SR.GetString(SR.CommunicationObjectBaseClassMethodNotCalled, this.GetCommunicationObjectType().ToString(), method));
}
internal Exception CreateClosedException()
{
if (!this.closeCalled)
{
return CreateAbortedException();
}
else
{
#if DEBUG
string originalStack = closeStack.ToString().Replace("\r\n", "\r\n ");
return new ObjectDisposedException(this.GetCommunicationObjectType().ToString() + ", Object already closed:\r\n " + originalStack);
#else
return new ObjectDisposedException(this.GetCommunicationObjectType().ToString());
#endif
}
}
internal Exception CreateFaultedException()
{
#if DEBUG
string originalStack = faultedStack.ToString().Replace("\r\n", "\r\n ");
string message = SR.GetString(SR.CommunicationObjectFaultedStack2, this.GetCommunicationObjectType().ToString(), originalStack);
#else
string message = SR.GetString(SR.CommunicationObjectFaulted1, this.GetCommunicationObjectType().ToString());
#endif
return new CommunicationObjectFaultedException(message);
}
internal Exception CreateAbortedException()
{
#if DEBUG
string originalStack = closeStack.ToString().Replace("\r\n", "\r\n ");
return new CommunicationObjectAbortedException(SR.GetString(SR.CommunicationObjectAbortedStack2, this.GetCommunicationObjectType().ToString(), originalStack));
#else
return new CommunicationObjectAbortedException(SR.GetString(SR.CommunicationObjectAborted1, this.GetCommunicationObjectType().ToString()));
#endif
}
internal virtual string CloseActivityName
{
get { return SR.GetString(SR.ActivityClose, this.GetType().FullName); }
}
internal virtual string OpenActivityName
{
get { return SR.GetString(SR.ActivityOpen, this.GetType().FullName); }
}
internal virtual ActivityType OpenActivityType
{
get { return ActivityType.Open; }
}
ServiceModelActivity CreateCloseActivity()
{
ServiceModelActivity retval = null;
retval = ServiceModelActivity.CreateBoundedActivity();
if (DiagnosticUtility.ShouldUseActivity)
{
ServiceModelActivity.Start(retval, this.CloseActivityName, ActivityType.Close);
}
return retval;
}
internal bool DoneReceivingInCurrentState()
{
this.ThrowPending();
switch (this.state)
{
case CommunicationState.Created:
throw TraceUtility.ThrowHelperError(this.CreateNotOpenException(), Guid.Empty, this);
case CommunicationState.Opening:
throw TraceUtility.ThrowHelperError(this.CreateNotOpenException(), Guid.Empty, this);
case CommunicationState.Opened:
return false;
case CommunicationState.Closing:
return true;
case CommunicationState.Closed:
return true;
case CommunicationState.Faulted:
return true;
default:
throw Fx.AssertAndThrow("DoneReceivingInCurrentState: Unknown CommunicationObject.state");
}
}
public void EndClose(IAsyncResult result)
{
if (result is AlreadyClosedAsyncResult)
AlreadyClosedAsyncResult.End(result);
else
CloseAsyncResult.End(result);
}
public void EndOpen(IAsyncResult result)
{
OpenAsyncResult.End(result);
}
protected void Fault()
{
lock (ThisLock)
{
if (this.state == CommunicationState.Closed || this.state == CommunicationState.Closing)
return;
if (this.state == CommunicationState.Faulted)
return;
#if DEBUG
if (faultedStack == null)
faultedStack = new StackTrace();
#endif
this.state = CommunicationState.Faulted;
}
OnFaulted();
}
internal void Fault(Exception exception)
{
lock (this.ThisLock)
{
if (this.exceptionQueue == null)
this.exceptionQueue = new ExceptionQueue(this.ThisLock);
}
if (exception != null && DiagnosticUtility.ShouldTraceInformation)
{
TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.CommunicationObjectFaultReason,
SR.GetString(SR.TraceCodeCommunicationObjectFaultReason), exception, null);
}
this.exceptionQueue.AddException(exception);
this.Fault();
}
internal void AddPendingException(Exception exception)
{
lock (this.ThisLock)
{
if (this.exceptionQueue == null)
this.exceptionQueue = new ExceptionQueue(this.ThisLock);
}
this.exceptionQueue.AddException(exception);
}
internal Exception GetPendingException()
{
CommunicationState currentState = this.state;
Fx.Assert(currentState == CommunicationState.Closing || currentState == CommunicationState.Closed || currentState == CommunicationState.Faulted,
"CommunicationObject.GetPendingException(currentState == CommunicationState.Closing || currentState == CommunicationState.Closed || currentState == CommunicationState.Faulted)");
ExceptionQueue queue = this.exceptionQueue;
if (queue != null)
{
return queue.GetException();
}
else
{
return null;
}
}
// Terminal is loosely defined as an interruption to close or a fault.
internal Exception GetTerminalException()
{
Exception exception = this.GetPendingException();
if (exception != null)
{
return exception;
}
switch (this.state)
{
case CommunicationState.Closing:
case CommunicationState.Closed:
return new CommunicationException(SR.GetString(SR.CommunicationObjectCloseInterrupted1, this.GetCommunicationObjectType().ToString()));
case CommunicationState.Faulted:
return this.CreateFaultedException();
default:
throw Fx.AssertAndThrow("GetTerminalException: Invalid CommunicationObject.state");
}
}
public void Open()
{
this.Open(this.DefaultOpenTimeout);
}
public void Open(TimeSpan timeout)
{
if (timeout < TimeSpan.Zero)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new ArgumentOutOfRangeException("timeout", SR.GetString(SR.SFxTimeoutOutOfRange0)));
using (ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity && this.TraceOpenAndClose ? ServiceModelActivity.CreateBoundedActivity() : null)
{
if (DiagnosticUtility.ShouldUseActivity)
{
ServiceModelActivity.Start(activity, this.OpenActivityName, this.OpenActivityType);
}
lock (ThisLock)
{
ThrowIfDisposedOrImmutable();
this.state = CommunicationState.Opening;
}
bool throwing = true;
try
{
TimeoutHelper actualTimeout = new TimeoutHelper(timeout);
OnOpening();
if (!this.onOpeningCalled)
throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnOpening"), Guid.Empty, this);
OnOpen(actualTimeout.RemainingTime());
OnOpened();
if (!this.onOpenedCalled)
throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnOpened"), Guid.Empty, this);
throwing = false;
}
finally
{
if (throwing)
{
if (DiagnosticUtility.ShouldTraceWarning)
{
TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.CommunicationObjectOpenFailed, SR.GetString(SR.TraceCodeCommunicationObjectOpenFailed, this.GetCommunicationObjectType().ToString()), this);
}
Fault();
}
}
}
}
protected virtual void OnClosed()
{
this.onClosedCalled = true;
lock (ThisLock)
{
if (this.raisedClosed)
return;
this.raisedClosed = true;
this.state = CommunicationState.Closed;
}
if (DiagnosticUtility.ShouldTraceVerbose)
{
TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.CommunicationObjectClosed, SR.GetString(SR.TraceCodeCommunicationObjectClosed, TraceUtility.CreateSourceString(this)), this);
}
EventHandler handler = Closed;
if (handler != null)
{
try
{
handler(eventSender, EventArgs.Empty);
}
catch (Exception exception)
{
if (Fx.IsFatal(exception))
throw;
throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(exception);
}
}
}
protected virtual void OnClosing()
{
this.onClosingCalled = true;
lock (ThisLock)
{
if (this.raisedClosing)
return;
this.raisedClosing = true;
}
if (DiagnosticUtility.ShouldTraceVerbose)
{
TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.CommunicationObjectClosing, SR.GetString(SR.TraceCodeCommunicationObjectClosing, TraceUtility.CreateSourceString(this)), this);
}
EventHandler handler = Closing;
if (handler != null)
{
try
{
handler(eventSender, EventArgs.Empty);
}
catch (Exception exception)
{
if (Fx.IsFatal(exception))
throw;
throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(exception);
}
}
}
protected virtual void OnFaulted()
{
lock (ThisLock)
{
if (this.raisedFaulted)
return;
this.raisedFaulted = true;
}
if (DiagnosticUtility.ShouldTraceWarning)
{
TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.CommunicationObjectFaulted, SR.GetString(SR.TraceCodeCommunicationObjectFaulted, this.GetCommunicationObjectType().ToString()), this);
}
EventHandler handler = Faulted;
if (handler != null)
{
try
{
handler(eventSender, EventArgs.Empty);
}
catch (Exception exception)
{
if (Fx.IsFatal(exception))
throw;
throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(exception);
}
}
}
protected virtual void OnOpened()
{
this.onOpenedCalled = true;
lock (ThisLock)
{
if (this.aborted || this.state != CommunicationState.Opening)
return;
this.state = CommunicationState.Opened;
}
if (DiagnosticUtility.ShouldTraceVerbose)
TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.CommunicationObjectOpened, SR.GetString(SR.TraceCodeCommunicationObjectOpened, TraceUtility.CreateSourceString(this)), this);
EventHandler handler = Opened;
if (handler != null)
{
try
{
handler(eventSender, EventArgs.Empty);
}
catch (Exception exception)
{
if (Fx.IsFatal(exception))
throw;
throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(exception);
}
}
}
protected virtual void OnOpening()
{
this.onOpeningCalled = true;
if (DiagnosticUtility.ShouldTraceVerbose)
{
TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.CommunicationObjectOpening, SR.GetString(SR.TraceCodeCommunicationObjectOpening, TraceUtility.CreateSourceString(this)), this);
}
EventHandler handler = Opening;
if (handler != null)
{
try
{
handler(eventSender, EventArgs.Empty);
}
catch (Exception exception)
{
if (Fx.IsFatal(exception))
throw;
throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(exception);
}
}
}
internal void ThrowIfFaulted()
{
this.ThrowPending();
switch (this.state)
{
case CommunicationState.Created:
break;
case CommunicationState.Opening:
break;
case CommunicationState.Opened:
break;
case CommunicationState.Closing:
break;
case CommunicationState.Closed:
break;
case CommunicationState.Faulted:
throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this);
default:
throw Fx.AssertAndThrow("ThrowIfFaulted: Unknown CommunicationObject.state");
}
}
internal void ThrowIfAborted()
{
if (this.aborted && !this.closeCalled)
{
throw TraceUtility.ThrowHelperError(CreateAbortedException(), Guid.Empty, this);
}
}
internal bool TraceOpenAndClose
{
get
{
return this.traceOpenAndClose;
}
set
{
this.traceOpenAndClose = value && DiagnosticUtility.ShouldUseActivity;
}
}
internal void ThrowIfClosed()
{
ThrowPending();
switch (this.state)
{
case CommunicationState.Created:
break;
case CommunicationState.Opening:
break;
case CommunicationState.Opened:
break;
case CommunicationState.Closing:
break;
case CommunicationState.Closed:
throw TraceUtility.ThrowHelperError(this.CreateClosedException(), Guid.Empty, this);
case CommunicationState.Faulted:
throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this);
default:
throw Fx.AssertAndThrow("ThrowIfClosed: Unknown CommunicationObject.state");
}
}
protected virtual Type GetCommunicationObjectType()
{
return this.GetType();
}
protected internal void ThrowIfDisposed()
{
ThrowPending();
switch (this.state)
{
case CommunicationState.Created:
break;
case CommunicationState.Opening:
break;
case CommunicationState.Opened:
break;
case CommunicationState.Closing:
throw TraceUtility.ThrowHelperError(this.CreateClosedException(), Guid.Empty, this);
case CommunicationState.Closed:
throw TraceUtility.ThrowHelperError(this.CreateClosedException(), Guid.Empty, this);
case CommunicationState.Faulted:
throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this);
default:
throw Fx.AssertAndThrow("ThrowIfDisposed: Unknown CommunicationObject.state");
}
}
internal void ThrowIfClosedOrOpened()
{
ThrowPending();
switch (this.state)
{
case CommunicationState.Created:
break;
case CommunicationState.Opening:
break;
case CommunicationState.Opened:
throw TraceUtility.ThrowHelperError(this.CreateImmutableException(), Guid.Empty, this);
case CommunicationState.Closing:
throw TraceUtility.ThrowHelperError(this.CreateImmutableException(), Guid.Empty, this);
case CommunicationState.Closed:
throw TraceUtility.ThrowHelperError(this.CreateClosedException(), Guid.Empty, this);
case CommunicationState.Faulted:
throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this);
default:
throw Fx.AssertAndThrow("ThrowIfClosedOrOpened: Unknown CommunicationObject.state");
}
}
protected internal void ThrowIfDisposedOrImmutable()
{
ThrowPending();
switch (this.state)
{
case CommunicationState.Created:
break;
case CommunicationState.Opening:
throw TraceUtility.ThrowHelperError(this.CreateImmutableException(), Guid.Empty, this);
case CommunicationState.Opened:
throw TraceUtility.ThrowHelperError(this.CreateImmutableException(), Guid.Empty, this);
case CommunicationState.Closing:
throw TraceUtility.ThrowHelperError(this.CreateClosedException(), Guid.Empty, this);
case CommunicationState.Closed:
throw TraceUtility.ThrowHelperError(this.CreateClosedException(), Guid.Empty, this);
case CommunicationState.Faulted:
throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this);
default:
throw Fx.AssertAndThrow("ThrowIfDisposedOrImmutable: Unknown CommunicationObject.state");
}
}
protected internal void ThrowIfDisposedOrNotOpen()
{
ThrowPending();
switch (this.state)
{
case CommunicationState.Created:
throw TraceUtility.ThrowHelperError(this.CreateNotOpenException(), Guid.Empty, this);
case CommunicationState.Opening:
throw TraceUtility.ThrowHelperError(this.CreateNotOpenException(), Guid.Empty, this);
case CommunicationState.Opened:
break;
case CommunicationState.Closing:
throw TraceUtility.ThrowHelperError(this.CreateClosedException(), Guid.Empty, this);
case CommunicationState.Closed:
throw TraceUtility.ThrowHelperError(this.CreateClosedException(), Guid.Empty, this);
case CommunicationState.Faulted:
throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this);
default:
throw Fx.AssertAndThrow("ThrowIfDisposedOrNotOpen: Unknown CommunicationObject.state");
}
}
internal void ThrowIfNotOpened()
{
if (this.state == CommunicationState.Created || this.state == CommunicationState.Opening)
throw TraceUtility.ThrowHelperError(this.CreateNotOpenException(), Guid.Empty, this);
}
internal void ThrowIfClosedOrNotOpen()
{
ThrowPending();
switch (this.state)
{
case CommunicationState.Created:
throw TraceUtility.ThrowHelperError(this.CreateNotOpenException(), Guid.Empty, this);
case CommunicationState.Opening:
throw TraceUtility.ThrowHelperError(this.CreateNotOpenException(), Guid.Empty, this);
case CommunicationState.Opened:
break;
case CommunicationState.Closing:
break;
case CommunicationState.Closed:
throw TraceUtility.ThrowHelperError(this.CreateClosedException(), Guid.Empty, this);
case CommunicationState.Faulted:
throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this);
default:
throw Fx.AssertAndThrow("ThrowIfClosedOrNotOpen: Unknown CommunicationObject.state");
}
}
internal void ThrowPending()
{
ExceptionQueue queue = this.exceptionQueue;
if (queue != null)
{
Exception exception = queue.GetException();
if (exception != null)
{
throw TraceUtility.ThrowHelperError(exception, Guid.Empty, this);
}
}
}
//
// State callbacks
//
protected abstract void OnAbort();
protected abstract void OnClose(TimeSpan timeout);
protected abstract void OnEndClose(IAsyncResult result);
protected abstract IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state);
protected abstract void OnOpen(TimeSpan timeout);
protected abstract IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state);
protected abstract void OnEndOpen(IAsyncResult result);
class AlreadyClosedAsyncResult : CompletedAsyncResult
{
public AlreadyClosedAsyncResult(AsyncCallback callback, object state)
: base(callback, state)
{
}
}
class ExceptionQueue
{
Queue<Exception> exceptions = new Queue<Exception>();
object thisLock;
internal ExceptionQueue(object thisLock)
{
this.thisLock = thisLock;
}
object ThisLock
{
get { return this.thisLock; }
}
public void AddException(Exception exception)
{
if (exception == null)
{
return;
}
lock (this.ThisLock)
{
this.exceptions.Enqueue(exception);
}
}
public Exception GetException()
{
lock (this.ThisLock)
{
if (this.exceptions.Count > 0)
{
return this.exceptions.Dequeue();
}
}
return null;
}
}
class OpenAsyncResult : AsyncResult
{
static AsyncCompletion onOpenCompletion = new AsyncCompletion(OnOpenCompletion);
CommunicationObject communicationObject;
TimeoutHelper timeout;
public OpenAsyncResult(CommunicationObject communicationObject, TimeSpan timeout, AsyncCallback callback, object state)
: base(callback, state)
{
this.communicationObject = communicationObject;
this.timeout = new TimeoutHelper(timeout);
base.OnCompleting = new Action<AsyncResult, Exception>(OnOpenCompleted);
if (InvokeOpen())
{
this.Complete(true);
}
}
bool InvokeOpen()
{
IAsyncResult result = this.communicationObject.OnBeginOpen(this.timeout.RemainingTime(),
base.PrepareAsyncCompletion(onOpenCompletion), this);
if (result.CompletedSynchronously)
{
return OnOpenCompletion(result);
}
else
{
return false;
}
}
void NotifyOpened()
{
this.communicationObject.OnOpened();
if (!this.communicationObject.onOpenedCalled)
{
throw TraceUtility.ThrowHelperError(
this.communicationObject.CreateBaseClassMethodNotCalledException("OnOpened"),
Guid.Empty, this.communicationObject);
}
}
void OnOpenCompleted(AsyncResult result, Exception exception)
{
if (exception != null)
{
if (DiagnosticUtility.ShouldTraceWarning)
{
TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.CommunicationObjectOpenFailed,
SR.GetString(SR.TraceCodeCommunicationObjectOpenFailed, this.communicationObject.GetCommunicationObjectType().ToString()),
this, exception);
}
this.communicationObject.Fault();
}
}
static bool OnOpenCompletion(IAsyncResult result)
{
OpenAsyncResult thisPtr = (OpenAsyncResult)result.AsyncState;
thisPtr.communicationObject.OnEndOpen(result);
thisPtr.NotifyOpened();
return true;
}
public static void End(IAsyncResult result)
{
AsyncResult.End<OpenAsyncResult>(result);
}
}
class CloseAsyncResult : TraceAsyncResult
{
static AsyncCompletion onCloseCompletion = new AsyncCompletion(OnCloseCompletion);
CommunicationObject communicationObject;
TimeoutHelper timeout;
public CloseAsyncResult(CommunicationObject communicationObject, TimeSpan timeout, AsyncCallback callback, object state)
: base(callback, state)
{
this.communicationObject = communicationObject;
this.timeout = new TimeoutHelper(timeout);
base.OnCompleting = new Action<AsyncResult, Exception>(OnCloseCompleted);
if (InvokeClose())
{
this.Complete(true);
}
}
bool InvokeClose()
{
IAsyncResult result = this.communicationObject.OnBeginClose(this.timeout.RemainingTime(),
base.PrepareAsyncCompletion(onCloseCompletion), this);
if (result.CompletedSynchronously)
{
return OnCloseCompletion(result);
}
else
{
return false;
}
}
void NotifyClosed()
{
this.communicationObject.OnClosed();
if (!this.communicationObject.onClosedCalled)
{
throw TraceUtility.ThrowHelperError(
this.communicationObject.CreateBaseClassMethodNotCalledException("OnClosed"),
Guid.Empty, this.communicationObject);
}
}
void OnCloseCompleted(AsyncResult result, Exception exception)
{
if (exception != null)
{
if (DiagnosticUtility.ShouldTraceWarning)
{
TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.CommunicationObjectCloseFailed,
SR.GetString(SR.TraceCodeCommunicationObjectCloseFailed, this.communicationObject.GetCommunicationObjectType().ToString()),
this, exception);
}
this.communicationObject.Abort();
}
}
static bool OnCloseCompletion(IAsyncResult result)
{
CloseAsyncResult thisPtr = (CloseAsyncResult)result.AsyncState;
thisPtr.communicationObject.OnEndClose(result);
thisPtr.NotifyClosed();
return true;
}
public static void End(IAsyncResult result)
{
AsyncResult.End<CloseAsyncResult>(result);
}
}
}
}
|