Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / ReliableMessagingHelpers.cs / 1 / ReliableMessagingHelpers.cs
//---------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //--------------------------------------------------------------------------- namespace System.ServiceModel.Channels { using System.Collections.Generic; using System.Diagnostics; using System.ServiceModel; using System.ServiceModel.Diagnostics; using System.ServiceModel.Dispatcher; using System.Collections.ObjectModel; using System.Globalization; using System.ServiceModel.Security; using System.Threading; using System.Xml; internal delegate void OperationEndCallback(IAsyncResult result); internal delegate IAsyncResult OperationWithTimeoutBeginCallback(TimeSpan timeout, AsyncCallback asyncCallback, object asyncState); internal delegate void OperationWithTimeoutCallback(TimeSpan timeout); static class OperationWithTimeoutComposer { public static IAsyncResult BeginComposeAsyncOperations( TimeSpan timeout, OperationWithTimeoutBeginCallback[] beginOperations, OperationEndCallback[] endOperations, AsyncCallback callback, object state) { return new ComposedAsyncResult(timeout, beginOperations, endOperations, callback, state); } public static void EndComposeAsyncOperations(IAsyncResult result) { ComposedAsyncResult.End(result); } public static TimeSpan RemainingTime(IAsyncResult result) { return ((ComposedAsyncResult)result).RemainingTime(); } class ComposedAsyncResult : AsyncResult { OperationWithTimeoutBeginCallback[] beginOperations; bool completedSynchronously = true; int currentOperation = 0; OperationEndCallback[] endOperations; TimeoutHelper timeoutHelper; static AsyncCallback onOperationCompleted = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnOperationCompletedStatic)); internal ComposedAsyncResult( TimeSpan timeout, OperationWithTimeoutBeginCallback[] beginOperations, OperationEndCallback[] endOperations, AsyncCallback callback, object state) : base(callback, state) { this.timeoutHelper = new TimeoutHelper(timeout); this.beginOperations = beginOperations; this.endOperations = endOperations; this.SkipToNextOperation(); if (this.currentOperation < this.beginOperations.Length) { this.beginOperations[this.currentOperation](this.RemainingTime(), onOperationCompleted, this); } else { Complete(this.completedSynchronously); } } public TimeSpan RemainingTime() { return this.timeoutHelper.RemainingTime(); } internal static void End(IAsyncResult result) { AsyncResult.End(result); } void OnOperationCompleted(IAsyncResult result) { this.completedSynchronously = this.completedSynchronously && result.CompletedSynchronously; Exception exception = null; try { this.endOperations[this.currentOperation](result); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) throw; exception = e; } if (exception != null) { Complete(this.completedSynchronously, exception); return; } this.currentOperation++; this.SkipToNextOperation(); if (this.currentOperation < this.beginOperations.Length) { try { this.beginOperations[this.currentOperation](this.RemainingTime(), onOperationCompleted, this); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) throw; exception = e; } if (exception != null) { Complete(this.completedSynchronously, exception); return; } } else { Complete(this.completedSynchronously); } } static void OnOperationCompletedStatic(IAsyncResult result) { ((ComposedAsyncResult)(result.AsyncState)).OnOperationCompleted(result); } void SkipToNextOperation() { while (this.currentOperation < this.beginOperations.Length) { if (this.beginOperations[this.currentOperation] != default(OperationWithTimeoutBeginCallback)) { return; } this.currentOperation++; } } } } sealed class Guard { ManualResetEvent closeEvent; int currentCount = 0; int maxCount; bool closed; object thisLock = new object(); event WaitAsyncResult.SignaledHandler Signaled; public Guard() : this(1) { } public Guard(int maxCount) { this.maxCount = maxCount; } public void Abort() { this.closed = true; } public IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state) { bool complete = false; WaitAsyncResult result = null; lock (this.thisLock) { if (this.closed || this.currentCount == 0) { complete = true; } else { result = new WaitAsyncResult(timeout, true, callback, state); this.Signaled += result.OnSignaled; } this.closed = true; } if (complete) { return new CompletedAsyncResult(callback, state); } else { result.Begin(); return result; } } public void Close(TimeSpan timeout) { lock (this.thisLock) { if (this.closed) return; this.closed = true; if (this.currentCount > 0) this.closeEvent = new ManualResetEvent(false); } if (this.closeEvent != null) { try { if (!TimeoutHelper.WaitOne(this.closeEvent, timeout, false)) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(SR.GetString(SR.TimeoutOnOperation, timeout))); } finally { lock (this.thisLock) { this.closeEvent.Close(); this.closeEvent = null; } } } } public void EndClose(IAsyncResult result) { if (result is CompletedAsyncResult) CompletedAsyncResult.End(result); else WaitAsyncResult.End(result); } public bool Enter() { lock (this.thisLock) { if (this.closed) return false; if (this.currentCount == this.maxCount) return false; this.currentCount++; return true; } } public void Exit() { WaitAsyncResult.SignaledHandler handler = null; lock (this.thisLock) { this.currentCount--; if (this.currentCount < 0) { DiagnosticUtility.DebugAssert("Exit can only be called after Enter."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } if (this.currentCount == 0) { if (this.closeEvent != null) this.closeEvent.Set(); handler = this.Signaled; } } if (handler != null) handler(); } } class InterruptibleTimer { WaitCallback callback; bool aborted = false; TimeSpan defaultInterval; static WaitCallback onTimerElapsed = new WaitCallback(OnTimerElapsed); bool set = false; object state; object thisLock = new object(); IOThreadTimer timer; public InterruptibleTimer(TimeSpan defaultInterval, WaitCallback callback, object state) { if (callback == null) { DiagnosticUtility.DebugAssert("Argument callback cannot be null."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } this.defaultInterval = defaultInterval; this.callback = callback; this.state = state; } object ThisLock { get { return this.thisLock; } } public void Abort() { lock (this.ThisLock) { this.aborted = true; if (this.set) { this.timer.Cancel(); this.set = false; } } } public bool Cancel() { lock (this.ThisLock) { if (this.aborted) { return false; } if (this.set) { this.timer.Cancel(); this.set = false; return true; } else { return false; } } } void OnTimerElapsed() { lock (this.ThisLock) { if (this.aborted) return; this.set = false; } callback(state); } static void OnTimerElapsed(object state) { InterruptibleTimer interruptibleTimer = (InterruptibleTimer)state; interruptibleTimer.OnTimerElapsed(); } public void Set() { this.Set(this.defaultInterval); } public void Set(TimeSpan interval) { this.InternalSet(interval, false); } public void SetIfNotSet() { this.InternalSet(this.defaultInterval, true); } void InternalSet(TimeSpan interval, bool ifNotSet) { lock (this.ThisLock) { if (this.aborted || (ifNotSet && this.set)) return; if (this.timer == null) this.timer = new IOThreadTimer(onTimerElapsed, this, true); this.timer.Set(interval); this.set = true; } } } class InterruptibleWaitObject { bool aborted = false; CommunicationObject communicationObject; ManualResetEvent handle; bool set; int syncWaiters; object thisLock = new object(); bool throwTimeoutByDefault = true; public InterruptibleWaitObject(bool signaled): this(signaled, true) { } public InterruptibleWaitObject(bool signaled, bool throwTimeoutByDefault) { this.set = signaled; this.throwTimeoutByDefault = throwTimeoutByDefault; } event WaitAsyncResult.AbortHandler Aborted; event WaitAsyncResult.AbortHandler Faulted; event WaitAsyncResult.SignaledHandler Signaled; public void Abort(CommunicationObject communicationObject) { if (communicationObject == null) { DiagnosticUtility.DebugAssert("Argument communicationObject cannot be null."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } lock (this.thisLock) { if (this.aborted) return; this.communicationObject = communicationObject; this.aborted = true; InternalSet(); } WaitAsyncResult.AbortHandler handler = this.Aborted; if (handler != null) handler(communicationObject); } public void Fault(CommunicationObject communicationObject) { if (communicationObject == null) { DiagnosticUtility.DebugAssert("Argument communicationObject cannot be null."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } lock (this.thisLock) { if (this.aborted) return; this.communicationObject = communicationObject; this.aborted = false; InternalSet(); } WaitAsyncResult.AbortHandler handler = this.Faulted; if (handler != null) handler(communicationObject); } public IAsyncResult BeginWait(TimeSpan timeout, AsyncCallback callback, object state) { return this.BeginWait(timeout, this.throwTimeoutByDefault, callback, state); } public IAsyncResult BeginWait(TimeSpan timeout, bool throwTimeoutException, AsyncCallback callback, object state) { Exception e = null; lock (this.thisLock) { if (!this.set) { WaitAsyncResult result = new WaitAsyncResult(timeout, throwTimeoutException, callback, state); this.Aborted += result.OnAborted; this.Faulted += result.OnFaulted; this.Signaled += result.OnSignaled; result.Begin(); return result; } else if (this.communicationObject != null) { e = this.GetException(); } } if (e != null) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, System.Diagnostics.TraceEventType.Error); } return new CompletedAsyncResult(e, callback, state); } public IAsyncResult BeginTryWait(TimeSpan timeout, AsyncCallback callback, object state) { return this.BeginWait(timeout, false, callback, state); } public void EndWait(IAsyncResult result) { this.EndTryWait(result); } public bool EndTryWait(IAsyncResult result) { if (result is CompletedAsyncResult) { CompletedAsyncResult.End(result); return true; } else { return WaitAsyncResult.End(result); } } Exception GetException() { if (this.communicationObject == null) { DiagnosticUtility.DebugAssert("Caller is attempting to retrieve an exception from a null communicationObject."); } return this.aborted ? this.communicationObject.CreateAbortedException() : this.communicationObject.GetTerminalException(); } void InternalSet() { lock (this.thisLock) { set = true; if (this.handle != null) this.handle.Set(); } } public void Reset() { lock (this.thisLock) { communicationObject = null; aborted = false; set = false; if (this.handle != null) this.handle.Reset(); } } public void Set() { InternalSet(); WaitAsyncResult.SignaledHandler handler = this.Signaled; if (handler != null) handler(); } public bool Wait(TimeSpan timeout) { return this.Wait(timeout, this.throwTimeoutByDefault); } public bool Wait(TimeSpan timeout, bool throwTimeoutException) { lock (this.thisLock) { if (set) { if (this.communicationObject != null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(this.GetException()); return true; } if (this.handle == null) this.handle = new ManualResetEvent(false); this.syncWaiters++; } try { if (!TimeoutHelper.WaitOne(this.handle, timeout, false)) { if (throwTimeoutException) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(SR.GetString(SR.TimeoutOnOperation, timeout))); else return false; } } finally { lock (this.thisLock) { // Last one out turns off the light. this.syncWaiters--; if (this.syncWaiters == 0) { this.handle.Close(); this.handle = null; } } } if (this.communicationObject != null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(this.GetException()); return true; } } abstract class FaultHelper { object thisLock = new object(); protected FaultHelper() { } protected object ThisLock { get { return this.thisLock; } } public abstract void Abort(); public static bool AddressReply(Message message, Message faultMessage) { try { RequestReplyCorrelator.PrepareReply(faultMessage, message); } catch (MessageHeaderException exception) { // ignore it - we don't need to correlate the reply if the MessageId header is bad if (DiagnosticUtility.ShouldTraceInformation) DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Information); } bool sendFault = true; try { sendFault = RequestReplyCorrelator.AddressReply(faultMessage, message); } catch (MessageHeaderException exception) { // ignore it - we don't need to address the reply if the addressing headers are bad if (DiagnosticUtility.ShouldTraceInformation) DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Information); } return sendFault; } public abstract IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state); public abstract void Close(TimeSpan timeout); public abstract void EndClose(IAsyncResult result); public abstract void SendFaultAsync(IReliableChannelBinder binder, RequestContext requestContext, Message faultMessage); } abstract class TypedFaultHelper : FaultHelper { InterruptibleWaitObject closeHandle; TimeSpan defaultCloseTimeout; TimeSpan defaultSendTimeout; Dictionary faultList = new Dictionary (); AsyncCallback onBinderCloseComplete; AsyncCallback onSendFaultComplete; WaitCallback sendFaultCallback; protected TypedFaultHelper(TimeSpan defaultSendTimeout, TimeSpan defaultCloseTimeout) { this.defaultSendTimeout = defaultSendTimeout; this.defaultCloseTimeout = defaultCloseTimeout; } public override void Abort() { Dictionary tempFaultList; InterruptibleWaitObject tempCloseHandle; lock (this.ThisLock) { tempFaultList = this.faultList; this.faultList = null; tempCloseHandle = this.closeHandle; } if ((tempFaultList == null) || (tempFaultList.Count == 0)) { if (tempCloseHandle != null) tempCloseHandle.Set(); return; } foreach (KeyValuePair pair in tempFaultList) { this.AbortState(pair.Value); pair.Key.Abort(); } if (tempCloseHandle != null) tempCloseHandle.Set(); } void AbortBinder(IReliableChannelBinder binder) { try { binder.Abort(); } finally { this.RemoveBinder(binder); } } void AsyncCloseBinder(IReliableChannelBinder binder) { if (this.onBinderCloseComplete == null) this.onBinderCloseComplete = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(this.OnBinderCloseComplete)); IAsyncResult result = binder.BeginClose(this.defaultCloseTimeout, this.onBinderCloseComplete, binder); if (result.CompletedSynchronously) this.CompleteBinderClose(binder, result); } protected abstract void AbortState(TState state); void AfterClose() { this.Abort(); } bool BeforeClose() { lock (this.ThisLock) { if ((this.faultList == null) || (this.faultList.Count == 0)) return true; this.closeHandle = new InterruptibleWaitObject(false, false); } return false; } public override IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state) { if (this.BeforeClose()) return new AlreadyClosedAsyncResult(callback, state); else return this.closeHandle.BeginWait(timeout, callback, state); } protected abstract IAsyncResult BeginSendFault(IReliableChannelBinder binder, TState state, TimeSpan timeout, AsyncCallback callback, object asyncState); public override void Close(TimeSpan timeout) { if (this.BeforeClose()) return; this.closeHandle.Wait(timeout); this.AfterClose(); } void CompleteBinderClose(IReliableChannelBinder binder, IAsyncResult result) { try { binder.EndClose(result); } finally { this.RemoveBinder(binder); } } void CompleteSendFault(IReliableChannelBinder binder, TState state, IAsyncResult result) { bool throwing = true; try { this.EndSendFault(binder, state, result); throwing = false; } finally { if (throwing) { this.AbortState(state); this.AbortBinder(binder); } } this.AsyncCloseBinder(binder); } public override void EndClose(IAsyncResult result) { if (result is AlreadyClosedAsyncResult) AlreadyClosedAsyncResult.End(result); else this.closeHandle.EndWait(result); this.AfterClose(); } protected abstract void EndSendFault(IReliableChannelBinder binder, TState state, IAsyncResult result); protected abstract TState GetState(RequestContext requestContext, Message faultMessage); void OnBinderCloseComplete(IAsyncResult result) { if (result.CompletedSynchronously) { return; } IReliableChannelBinder binder = (IReliableChannelBinder)result.AsyncState; try { this.CompleteBinderClose(binder, result); } catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) { throw; } binder.HandleException(e); } } void OnSendFaultComplete(IAsyncResult result) { if (result.CompletedSynchronously) { return; } IReliableChannelBinder binder; TState state; lock (this.ThisLock) { if (this.faultList == null) return; binder = (IReliableChannelBinder)result.AsyncState; state = this.faultList[binder]; } try { this.CompleteSendFault(binder, state, result); } catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) { throw; } binder.HandleException(e); } } protected void RemoveBinder(IReliableChannelBinder binder) { InterruptibleWaitObject tempCloseHandle; lock (this.ThisLock) { if (this.faultList == null) return; this.faultList.Remove(binder); if ((this.closeHandle == null) || (this.faultList.Count > 0)) return; // Close has been called. this.faultList = null; tempCloseHandle = this.closeHandle; } tempCloseHandle.Set(); } protected void SendFault(IReliableChannelBinder binder, TState state) { IAsyncResult result; bool throwing = true; try { result = this.BeginSendFault(binder, state, this.defaultSendTimeout, this.onSendFaultComplete, binder); throwing = false; } finally { if (throwing) { this.AbortState(state); this.AbortBinder(binder); } } if (result.CompletedSynchronously) this.CompleteSendFault(binder, state, result); } public override void SendFaultAsync(IReliableChannelBinder binder, RequestContext requestContext, Message faultMessage) { try { bool abort = true; TState state = this.GetState(requestContext, faultMessage); lock (this.ThisLock) { if (this.faultList != null) { abort = false; this.faultList.Add(binder, state); if (this.onSendFaultComplete == null) this.onSendFaultComplete = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(this.OnSendFaultComplete)); } } if (abort) { this.AbortState(state); binder.Abort(); } else if (Thread.CurrentThread.IsThreadPoolThread) { this.SendFault(binder, state); } else { if (this.sendFaultCallback == null) this.sendFaultCallback = new WaitCallback(this.SendFaultCallback); IOThreadScheduler.ScheduleCallback(this.sendFaultCallback, binder); } } catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) { throw; } binder.HandleException(e); } } void SendFaultCallback(object callbackState) { IReliableChannelBinder binder; TState state; lock (this.ThisLock) { if (this.faultList == null) return; binder = (IReliableChannelBinder)callbackState; state = this.faultList[binder]; } try { this.SendFault(binder, state); } catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) { throw; } binder.HandleException(e); } } class AlreadyClosedAsyncResult : CompletedAsyncResult { public AlreadyClosedAsyncResult(AsyncCallback callback, object state) : base(callback, state) { } } } struct FaultState { Message faultMessage; RequestContext requestContext; public FaultState(RequestContext requestContext, Message faultMessage) { this.requestContext = requestContext; this.faultMessage = faultMessage; } public Message FaultMessage { get { return this.faultMessage; } } public RequestContext RequestContext { get { return this.requestContext; } } } class ReplyFaultHelper : TypedFaultHelper { public ReplyFaultHelper(TimeSpan defaultSendTimeout, TimeSpan defaultCloseTimeout) : base(defaultSendTimeout, defaultCloseTimeout) { } protected override void AbortState(FaultState faultState) { faultState.FaultMessage.Close(); faultState.RequestContext.Abort(); } protected override IAsyncResult BeginSendFault(IReliableChannelBinder binder, FaultState faultState, TimeSpan timeout, AsyncCallback callback, object state) { return faultState.RequestContext.BeginReply(faultState.FaultMessage, timeout, callback, state); } protected override void EndSendFault(IReliableChannelBinder binder, FaultState faultState, IAsyncResult result) { faultState.RequestContext.EndReply(result); faultState.FaultMessage.Close(); } protected override FaultState GetState(RequestContext requestContext, Message faultMessage) { return new FaultState(requestContext, faultMessage); } } class SendFaultHelper : TypedFaultHelper { public SendFaultHelper(TimeSpan defaultSendTimeout, TimeSpan defaultCloseTimeout) : base(defaultSendTimeout, defaultCloseTimeout) { } protected override void AbortState(Message message) { message.Close(); } protected override IAsyncResult BeginSendFault(IReliableChannelBinder binder, Message message, TimeSpan timeout, AsyncCallback callback, object state) { return binder.BeginSend(message, timeout, callback, state); } protected override void EndSendFault(IReliableChannelBinder binder, Message message, IAsyncResult result) { binder.EndSend(result); message.Close(); } protected override Message GetState(RequestContext requestContext, Message faultMessage) { return faultMessage; } } class ReliableChannelCloseAsyncResult : AsyncResult { IReliableChannelBinder binder; static AsyncCallback onBinderCloseComplete = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnBinderCloseComplete)); static AsyncCallback onComposeAsyncOperationsComplete = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnComposeAsyncOperationsComplete)); TimeoutHelper timeoutHelper; public ReliableChannelCloseAsyncResult(OperationWithTimeoutBeginCallback[] beginCallbacks, OperationEndCallback[] endCallbacks, IReliableChannelBinder binder, TimeSpan timeout, AsyncCallback callback, object state) : base (callback, state) { this.binder = binder; this.timeoutHelper = new TimeoutHelper(timeout); IAsyncResult result = OperationWithTimeoutComposer.BeginComposeAsyncOperations(timeoutHelper.RemainingTime(), beginCallbacks, endCallbacks, onComposeAsyncOperationsComplete, this); if (result.CompletedSynchronously) { if (this.CompleteComposeAsyncOperations(result)) { this.Complete(true); } } } bool CompleteComposeAsyncOperations(IAsyncResult result) { OperationWithTimeoutComposer.EndComposeAsyncOperations(result); result = this.binder.BeginClose(this.timeoutHelper.RemainingTime(), MaskingMode.Handled, onBinderCloseComplete, this); if (result.CompletedSynchronously) { this.binder.EndClose(result); return true; } return false; } public static void End(IAsyncResult result) { AsyncResult.End (result); } static void OnBinderCloseComplete(IAsyncResult result) { if (!result.CompletedSynchronously) { ReliableChannelCloseAsyncResult closeResult = (ReliableChannelCloseAsyncResult)result.AsyncState; Exception completeException = null; try { closeResult.binder.EndClose(result); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) throw; completeException = e; } closeResult.Complete(false, completeException); } } static void OnComposeAsyncOperationsComplete(IAsyncResult result) { if (!result.CompletedSynchronously) { ReliableChannelCloseAsyncResult closeResult = (ReliableChannelCloseAsyncResult)result.AsyncState; bool complete = false; Exception completeException = null; try { complete = closeResult.CompleteComposeAsyncOperations(result); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) throw; completeException = e; } if (complete || completeException != null) { closeResult.Complete(false, completeException); } } } } class ReliableChannelOpenAsyncResult : AsyncResult { IReliableChannelBinder binder; static AsyncCallback onBinderOpenComplete = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnBinderOpenComplete)); static AsyncCallback onSessionOpenComplete = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnSessionOpenComplete)); ChannelReliableSession session; TimeoutHelper timeoutHelper; public ReliableChannelOpenAsyncResult(IReliableChannelBinder binder, ChannelReliableSession session, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state) { this.binder = binder; this.session = session; this.timeoutHelper = new TimeoutHelper(timeout); bool complete = false; bool throwing = true; Exception completeException = null; try { IAsyncResult result = this.binder.BeginOpen(timeoutHelper.RemainingTime(), onBinderOpenComplete, this); throwing = false; if (result.CompletedSynchronously) { complete = this.CompleteBinderOpen(true, result); } } catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) throw; if (throwing || this.CloseBinder(completeException)) throw; } finally { if (throwing) this.binder.Abort(); } if (complete) this.Complete(true); } bool CloseBinder(Exception e) { IAsyncResult result = this.binder.BeginClose(this.timeoutHelper.RemainingTime(), DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(this.OnBinderCloseComplete)), e); if (result.CompletedSynchronously) { this.binder.EndClose(result); return true; } else { return false; } } void CloseBinderAndComplete(Exception e) { bool complete = true; try { complete = this.CloseBinder(e); } catch (Exception ex) { if (DiagnosticUtility.IsFatal(ex)) throw; if (DiagnosticUtility.ShouldTraceInformation) DiagnosticUtility.ExceptionUtility.TraceHandledException(ex, TraceEventType.Information); } if (complete) this.Complete(false, e); } bool CompleteBinderOpen(bool synchronous, IAsyncResult result) { this.binder.EndOpen(result); result = this.session.BeginOpen(this.timeoutHelper.RemainingTime(), onSessionOpenComplete, this); if (result.CompletedSynchronously) { this.session.EndOpen(result); return true; } return false; } public static void End(IAsyncResult result) { AsyncResult.End (result); } void OnBinderCloseComplete(IAsyncResult result) { if (!result.CompletedSynchronously) { Exception completeException = (Exception)result.AsyncState; try { this.binder.EndClose(result); } catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) throw; if (DiagnosticUtility.ShouldTraceInformation) DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); } this.Complete(false, completeException); } } static void OnBinderOpenComplete(IAsyncResult result) { if (!result.CompletedSynchronously) { ReliableChannelOpenAsyncResult openResult = (ReliableChannelOpenAsyncResult)result.AsyncState; bool complete = false; Exception completeException = null; try { complete = openResult.CompleteBinderOpen(false, result); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) throw; completeException = e; } if (complete) openResult.Complete(false, completeException); else if (completeException != null) openResult.CloseBinderAndComplete(completeException); } } static void OnSessionOpenComplete(IAsyncResult result) { if (!result.CompletedSynchronously) { ReliableChannelOpenAsyncResult openResult = (ReliableChannelOpenAsyncResult)result.AsyncState; Exception completeException = null; try { openResult.session.EndOpen(result); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) throw; completeException = e; } if (completeException != null) openResult.CloseBinderAndComplete(completeException); else openResult.Complete(false); } } } static class ReliableMessagingConstants { static public TimeSpan UnknownInitiationTime = TimeSpan.FromSeconds(2); static public TimeSpan RequestorIterationTime = TimeSpan.FromSeconds(10); static public TimeSpan RequestorReceiveTime = TimeSpan.FromSeconds(10); static public int MaxSequenceRanges = 128; } // This class and its derivates attempt to unify 3 similar request reply patterns. // 1. Straightforward R/R pattern // 2. R/R pattern with binder and exception semantics on Open (CreateSequence) // 3. TerminateSequence request - TerminateSequence response for R(Request|Reply)SC abstract class ReliableRequestor { InterruptibleWaitObject abortHandle = new InterruptibleWaitObject(false, false); IReliableChannelBinder binder; bool isCreateSequence; ActionHeader messageAction; BodyWriter messageBody; WsrmMessageHeader messageHeader; UniqueId messageId; MessageVersion messageVersion; TimeSpan originalTimeout; string timeoutString1Index; public IReliableChannelBinder Binder { protected get { return this.binder; } set { this.binder = value; } } public bool IsCreateSequence { protected get { return this.isCreateSequence; } set { this.isCreateSequence = value; } } public ActionHeader MessageAction { set { this.messageAction = value; } } public BodyWriter MessageBody { set { this.messageBody = value; } } public UniqueId MessageId { get { return this.messageId; } } public WsrmMessageHeader MessageHeader { get { return this.messageHeader; } set { this.messageHeader = value; } } public MessageVersion MessageVersion { set { this.messageVersion = value; } } public string TimeoutString1Index { set { this.timeoutString1Index = value; } } public void Abort(CommunicationObject communicationObject) { this.abortHandle.Abort(communicationObject); } Message CreateRequestMessage() { Message request = Message.CreateMessage(this.messageVersion, this.messageAction, this.messageBody); request.Properties.AllowOutputBatching = false; if (this.messageHeader != null) { request.Headers.Insert(0, this.messageHeader); } if (this.messageId != null) { request.Headers.MessageId = this.messageId; RequestReplyCorrelator.PrepareRequest(request); EndpointAddress address = this.binder.LocalAddress; if (address == null) { request.Headers.ReplyTo = null; } else if (this.messageVersion.Addressing == AddressingVersion.WSAddressingAugust2004) { request.Headers.ReplyTo = address; } else if (this.messageVersion.Addressing == AddressingVersion.WSAddressing10) { request.Headers.ReplyTo = address.IsAnonymous ? null : address; } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ProtocolException(SR.GetString(SR.AddressingVersionNotSupported, this.messageVersion.Addressing))); } } return request; } bool EnsureChannel() { if (this.IsCreateSequence) { IClientReliableChannelBinder clientBinder = (IClientReliableChannelBinder)this.binder; return clientBinder.EnsureChannelForRequest(); } else { return true; } } public virtual void Fault(CommunicationObject communicationObject) { this.abortHandle.Fault(communicationObject); } public abstract WsrmMessageInfo GetInfo(); TimeSpan GetNextRequestTimeout(TimeSpan remainingTimeout, out TimeoutHelper iterationTimeout, out bool lastIteration) { iterationTimeout = new TimeoutHelper(ReliableMessagingConstants.RequestorIterationTime); lastIteration = remainingTimeout <= ReliableMessagingConstants.RequestorIterationTime; iterationTimeout.SetDeadline(); return remainingTimeout; } bool HandleException(Exception exception, bool lastIteration) { if (this.IsCreateSequence) { if (exception is QuotaExceededException) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new CommunicationException(exception.Message, exception)); } if (!this.binder.IsHandleable(exception) || (this.binder.State != CommunicationState.Opened) || lastIteration) { return false; } return true; } else { return this.binder.IsHandleable(exception); } } void ThrowTimeoutException() { if (this.timeoutString1Index != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new TimeoutException(SR.GetString(this.timeoutString1Index, this.originalTimeout))); } } protected abstract Message OnRequest(Message request, TimeSpan timeout, bool last); protected abstract IAsyncResult OnBeginRequest(Message request, TimeSpan timeout, AsyncCallback callback, object state); protected abstract Message OnEndRequest(bool last, IAsyncResult result); public Message Request(TimeSpan timeout) { this.originalTimeout = timeout; TimeoutHelper timeoutHelper = new TimeoutHelper(this.originalTimeout); TimeoutHelper iterationTimeoutHelper; bool lastIteration; while (true) { Message request = null; Message reply = null; bool requestCompleted = false; TimeSpan requestTimeout = this.GetNextRequestTimeout(timeoutHelper.RemainingTime(), out iterationTimeoutHelper, out lastIteration); try { if (this.EnsureChannel()) { request = this.CreateRequestMessage(); reply = this.OnRequest(request, requestTimeout, lastIteration); requestCompleted = true; } } catch (Exception e) { if (DiagnosticUtility.IsFatal(e) || !this.HandleException(e, lastIteration)) { throw; } if (DiagnosticUtility.ShouldTraceInformation) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); } } finally { if (request != null) { request.Close(); } } if (requestCompleted) { if (this.ValidateReply(reply)) { return reply; } } if (lastIteration) break; this.abortHandle.Wait(iterationTimeoutHelper.RemainingTime()); } this.ThrowTimeoutException(); return null; } public IAsyncResult BeginRequest(TimeSpan timeout, AsyncCallback callback, object state) { return new RequestAsyncResult(this, timeout, callback, state); } public Message EndRequest(IAsyncResult result) { return RequestAsyncResult.End(result); } public abstract void SetInfo(WsrmMessageInfo info); public void SetRequestResponsePattern() { if (this.messageId != null) { DiagnosticUtility.DebugAssert("Initialize messageId only once."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } this.messageId = new UniqueId(); } bool ValidateReply(Message response) { if (this.messageId != null) { // r/r pattern requires a response return response != null; } else { return true; } } class RequestAsyncResult : AsyncResult { static AsyncCallback requestCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(RequestCallback)); static AsyncCallback waitCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(RequestAsyncResult.WaitCallback)); TimeoutHelper iterationTimeoutHelper; bool lastIteration = false; Message request; ReliableRequestor requestor; Message response; TimeoutHelper timeoutHelper; public RequestAsyncResult(ReliableRequestor requestor, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state) { this.requestor = requestor; this.requestor.originalTimeout = timeout; this.timeoutHelper = new TimeoutHelper(this.requestor.originalTimeout); if (this.Request(null)) { this.Complete(true); } } public static Message End(IAsyncResult result) { RequestAsyncResult requestResult = AsyncResult.End (result); return requestResult.response; } bool Request(IAsyncResult requestResult) { while (true) { bool requestCompleted = false; bool disposeRequest = true; TimeSpan requestTimeout = (requestResult == null) ? this.requestor.GetNextRequestTimeout(this.timeoutHelper.RemainingTime(), out this.iterationTimeoutHelper, out this.lastIteration) : TimeSpan.Zero; try { if (requestResult == null) { if (this.requestor.EnsureChannel()) { this.request = this.requestor.CreateRequestMessage(); requestResult = this.requestor.OnBeginRequest(this.request, requestTimeout, requestCallback, this); if (!requestResult.CompletedSynchronously) { disposeRequest = false; return false; } } } if (requestResult != null) { this.response = this.requestor.OnEndRequest(this.lastIteration, requestResult); requestCompleted = true; } } catch (Exception e) { if (DiagnosticUtility.IsFatal(e) || !this.requestor.HandleException(e, lastIteration)) { throw; } if (DiagnosticUtility.ShouldTraceInformation) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); } } finally { if (disposeRequest && this.request != null) { this.request.Close(); this.request = null; } requestResult = null; } if (requestCompleted) { if (this.requestor.ValidateReply(this.response)) { return true; } } if (this.lastIteration) { break; } IAsyncResult waitResult = this.requestor.abortHandle.BeginWait( iterationTimeoutHelper.RemainingTime(), waitCallback, this); if (!waitResult.CompletedSynchronously) { return false; } else { this.requestor.abortHandle.EndWait(waitResult); } } this.requestor.ThrowTimeoutException(); return true; } static void RequestCallback(IAsyncResult result) { if (!result.CompletedSynchronously) { RequestAsyncResult requestResult = (RequestAsyncResult)result.AsyncState; bool complete; Exception completeException; try { complete = requestResult.Request(result); completeException = null; } catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) { throw; } complete = true; completeException = e; } if (complete) { requestResult.Complete(false, completeException); } } } bool EndWait(IAsyncResult result) { this.requestor.abortHandle.EndWait(result); return this.Request(null); } static void WaitCallback(IAsyncResult result) { if (!result.CompletedSynchronously) { RequestAsyncResult requestResult = (RequestAsyncResult)result.AsyncState; bool complete; Exception completeException; try { complete = requestResult.EndWait(result); completeException = null; } catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) { throw; } complete = true; completeException = e; } if (complete) { requestResult.Complete(false, completeException); } } } } } sealed class RequestReliableRequestor : ReliableRequestor { bool replied = false; WsrmMessageInfo replyInfo; object thisLock = new object(); IClientReliableChannelBinder ClientBinder { get { return (IClientReliableChannelBinder)this.Binder; } } object ThisLock { get { return this.thisLock; } } public override WsrmMessageInfo GetInfo() { return this.replyInfo; } Message GetReply(Message reply, bool last) { lock (this.ThisLock) { if (reply != null && this.replyInfo != null) { this.replyInfo = null; } else if (reply == null && this.replyInfo != null) { reply = this.replyInfo.Message; } if (reply != null || last) { this.replied = true; } } return reply; } protected override Message OnRequest(Message request, TimeSpan timeout, bool last) { return this.GetReply(this.ClientBinder.Request(request, timeout, MaskingMode.None), last); } protected override IAsyncResult OnBeginRequest(Message request, TimeSpan timeout, AsyncCallback callback, object state) { return this.ClientBinder.BeginRequest(request, timeout, MaskingMode.None, callback, state); } protected override Message OnEndRequest(bool last, IAsyncResult result) { return this.GetReply(this.ClientBinder.EndRequest(result), last); } public override void SetInfo(WsrmMessageInfo info) { lock (this.ThisLock) { if (!this.replied && this.replyInfo == null) { this.replyInfo = info; } } } } sealed class SendReceiveReliableRequestor : ReliableRequestor { bool timeoutIsSafe; public bool TimeoutIsSafe { set { this.timeoutIsSafe = value; } } public override WsrmMessageInfo GetInfo() { DiagnosticUtility.DebugAssert("Not Supported."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } TimeSpan GetReceiveTimeout(TimeSpan timeoutRemaining) { if ((timeoutRemaining < ReliableMessagingConstants.RequestorReceiveTime) || !this.timeoutIsSafe) { return timeoutRemaining; } else { return ReliableMessagingConstants.RequestorReceiveTime; } } protected override Message OnRequest(Message request, TimeSpan timeout, bool last) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); this.Binder.Send(request, timeoutHelper.RemainingTime(), MaskingMode.None); TimeSpan receiveTimeout = this.GetReceiveTimeout(timeoutHelper.RemainingTime()); RequestContext requestContext; this.Binder.TryReceive(receiveTimeout, out requestContext, MaskingMode.None); return (requestContext != null) ? requestContext.RequestMessage : null; } protected override IAsyncResult OnBeginRequest(Message request, TimeSpan timeout, AsyncCallback callback, object state) { return new SendReceiveAsyncResult(this, request, timeout, callback, state); } protected override Message OnEndRequest(bool last, IAsyncResult result) { return SendReceiveAsyncResult.End(result); } public override void SetInfo(WsrmMessageInfo info) { DiagnosticUtility.DebugAssert("Not Supported."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } class SendReceiveAsyncResult : AsyncResult { static AsyncCallback sendCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(SendCallback)); static AsyncCallback tryReceiveCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(TryReceiveCallback)); Message request; SendReceiveReliableRequestor requestor; Message response; TimeoutHelper timeoutHelper; internal SendReceiveAsyncResult(SendReceiveReliableRequestor requestor, Message request, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state) { this.requestor = requestor; this.request = request; this.timeoutHelper = new TimeoutHelper(timeout); if (this.BeginSend()) { this.Complete(true); } } bool BeginSend() { IAsyncResult sendResult = this.requestor.Binder.BeginSend(this.request, this.timeoutHelper.RemainingTime(), MaskingMode.None, sendCallback, this); if (sendResult.CompletedSynchronously) { return this.EndSend(sendResult); } else { return false; } } public static Message End(IAsyncResult result) { SendReceiveAsyncResult sendReceiveResult = AsyncResult.End (result); return sendReceiveResult.response; } bool EndSend(IAsyncResult result) { this.requestor.Binder.EndSend(result); TimeSpan receiveTimeout = this.requestor.GetReceiveTimeout(this.timeoutHelper.RemainingTime()); IAsyncResult tryReceiveResult = this.requestor.Binder.BeginTryReceive(receiveTimeout, MaskingMode.None, tryReceiveCallback, this); if (tryReceiveResult.CompletedSynchronously) { return this.EndTryReceive(tryReceiveResult); } else { return false; } } bool EndTryReceive(IAsyncResult result) { RequestContext requestContext; this.requestor.Binder.EndTryReceive(result, out requestContext); this.response = (requestContext != null) ? requestContext.RequestMessage : null; return true; } static void SendCallback(IAsyncResult result) { if (!result.CompletedSynchronously) { SendReceiveAsyncResult sendReceiveResult = (SendReceiveAsyncResult)result.AsyncState; Exception completeException; bool complete = false; try { complete = sendReceiveResult.EndSend(result); completeException = null; } catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) { throw; } complete = true; completeException = e; } if (complete) { sendReceiveResult.Complete(false, completeException); } } } static void TryReceiveCallback(IAsyncResult result) { if (!result.CompletedSynchronously) { SendReceiveAsyncResult sendReceiveResult = (SendReceiveAsyncResult)result.AsyncState; Exception completeException; bool complete = false; try { complete = sendReceiveResult.EndTryReceive(result); completeException = null; } catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) { throw; } complete = true; completeException = e; } if (complete) { sendReceiveResult.Complete(false, completeException); } } } } } sealed class SendWaitReliableRequestor : ReliableRequestor { bool replied = false; InterruptibleWaitObject replyHandle = new InterruptibleWaitObject(false, true); WsrmMessageInfo replyInfo; Message request; object thisLock = new object(); object ThisLock { get { return this.thisLock; } } public override void Fault(CommunicationObject communicationObject) { this.replied = true; this.replyHandle.Fault(communicationObject); base.Fault(communicationObject); } public override WsrmMessageInfo GetInfo() { return this.replyInfo; } Message GetReply(bool last) { lock (this.ThisLock) { if (this.replyInfo != null) { this.replied = true; return this.replyInfo.Message; } else if (last) { this.replied = true; } } return null; } TimeSpan GetWaitTimeout(TimeSpan timeoutRemaining) { if ((timeoutRemaining < ReliableMessagingConstants.RequestorReceiveTime)) { return timeoutRemaining; } else { return ReliableMessagingConstants.RequestorReceiveTime; } } protected override Message OnRequest(Message request, TimeSpan timeout, bool last) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); this.Binder.Send(request, timeoutHelper.RemainingTime(), MaskingMode.None); TimeSpan waitTimeout = this.GetWaitTimeout(timeoutHelper.RemainingTime()); this.replyHandle.Wait(waitTimeout); return this.GetReply(last); } protected override IAsyncResult OnBeginRequest(Message request, TimeSpan timeout, AsyncCallback callback, object state) { this.request = request; return OperationWithTimeoutComposer.BeginComposeAsyncOperations(timeout, new OperationWithTimeoutBeginCallback[] { new OperationWithTimeoutBeginCallback(BeginSend), new OperationWithTimeoutBeginCallback(BeginWait) }, new OperationEndCallback[] { new OperationEndCallback(EndSend), new OperationEndCallback(EndWait) }, callback, state); } protected override Message OnEndRequest(bool last, IAsyncResult result) { OperationWithTimeoutComposer.EndComposeAsyncOperations(result); return this.GetReply(last); } IAsyncResult BeginSend(TimeSpan timeout, AsyncCallback callback, object state) { try { return this.Binder.BeginSend(this.request, timeout, MaskingMode.None, callback, state); } finally { this.request = null; } } void EndSend(IAsyncResult result) { this.Binder.EndSend(result); } public override void SetInfo(WsrmMessageInfo info) { lock (this.ThisLock) { if (this.replied || this.replyInfo != null) { return; } this.replyInfo = info; } this.replyHandle.Set(); } IAsyncResult BeginWait(TimeSpan timeout, AsyncCallback callback, object state) { TimeSpan waitTimeout = this.GetWaitTimeout(timeout); return this.replyHandle.BeginWait(waitTimeout, callback, state); } void EndWait(IAsyncResult result) { this.replyHandle.EndWait(result); } } abstract class ReliableOutputAsyncResult : AsyncResult { IReliableChannelBinder binder; Exception handledException; MaskingMode maskingMode; MessageAttemptInfo messageAttemptInfo; static AsyncCallback operationCallback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OperationCallback)); bool saveHandledException; protected ReliableOutputAsyncResult(AsyncCallback callback, object state) : base(callback, state) { } public IReliableChannelBinder Binder { protected get { return this.binder; } set { this.binder = value; } } protected Exception HandledException { get { return this.handledException; } } public MaskingMode MaskingMode { get { return this.maskingMode; } set { this.maskingMode = value; } } public MessageAttemptInfo MessageAttemptInfo { get { return this.messageAttemptInfo; } set { this.messageAttemptInfo = value; } } public Message Message { protected get { return this.messageAttemptInfo.Message; } set { this.messageAttemptInfo = new MessageAttemptInfo(value, 0, 0, null); } } public bool SaveHandledException { set { this.saveHandledException = value; } } public void Begin(TimeSpan timeout) { bool complete; if (this.saveHandledException) { complete = this.BeginInternal(timeout); } else { try { complete = this.BeginInternal(timeout); } catch (Exception e) { if (DiagnosticUtility.IsFatal(e) || !this.HandleException(e)) { throw; } complete = true; } } if (complete) { this.Complete(true); } } bool BeginInternal(TimeSpan timeout) { bool closeMessage = true; try { IAsyncResult operationResult = this.BeginOperation(timeout, operationCallback, this); if (operationResult.CompletedSynchronously) { this.EndOperation(operationResult); return true; } else { closeMessage = false; return false; } } finally { if (closeMessage) { this.Message.Close(); } } } protected abstract IAsyncResult BeginOperation(TimeSpan timeout, AsyncCallback callback, object state); protected abstract void EndOperation(IAsyncResult result); static void OperationCallback(IAsyncResult result) { if (!result.CompletedSynchronously) { ReliableOutputAsyncResult outputResult = (ReliableOutputAsyncResult)result.AsyncState; Exception completeException = null; try { outputResult.EndOperation(result); } catch (Exception e) { if (DiagnosticUtility.IsFatal(e)) { throw; } if (!outputResult.HandleException(e)) { completeException = e; } } finally { outputResult.Message.Close(); } outputResult.Complete(false, completeException); } } bool HandleException(Exception e) { if (this.saveHandledException && this.Binder.IsHandleable(e)) { this.handledException = e; return true; } else { return false; } } } class ReliableBinderSendAsyncResult : ReliableOutputAsyncResult { public ReliableBinderSendAsyncResult(AsyncCallback callback, object state) : base(callback, state) { } public static void End(IAsyncResult result) { Exception handledException; End(result, out handledException); } public static void End(IAsyncResult result, out Exception handledException) { ReliableBinderSendAsyncResult sendResult = AsyncResult.End (result); handledException = sendResult.HandledException; } protected override IAsyncResult BeginOperation(TimeSpan timeout, AsyncCallback callback, object state) { return this.Binder.BeginSend(this.Message, timeout, this.MaskingMode, callback, state); } protected override void EndOperation(IAsyncResult result) { this.Binder.EndSend(result); } } class ReliableBinderRequestAsyncResult : ReliableOutputAsyncResult { Message reply; public ReliableBinderRequestAsyncResult(AsyncCallback callback, object state) : base(callback, state) { } protected IClientReliableChannelBinder ClientBinder { get { return (IClientReliableChannelBinder)this.Binder; } } protected Message Reply { get { return this.reply; } } public static Message End(IAsyncResult result) { Exception handledException; return End(result, out handledException); } public static Message End(IAsyncResult result, out Exception handledException) { ReliableBinderRequestAsyncResult requestResult = AsyncResult.End (result); handledException = requestResult.HandledException; return requestResult.reply; } protected override IAsyncResult BeginOperation(TimeSpan timeout, AsyncCallback callback, object state) { return this.ClientBinder.BeginRequest(this.Message, timeout, this.MaskingMode, callback, state); } protected override void EndOperation(IAsyncResult result) { this.reply = this.ClientBinder.EndRequest(result); } } class WaitAsyncResult : AsyncResult { bool completed; bool throwTimeoutException; bool timedOut; TimeSpan timeout; IOThreadTimer timer; object thisLock = new object(); public delegate void AbortHandler(CommunicationObject communicationObject); public delegate void SignaledHandler(); public WaitAsyncResult(TimeSpan timeout, bool throwTimeoutException, AsyncCallback callback, object state) : base(callback, state) { this.timeout = timeout; this.throwTimeoutException = throwTimeoutException; } public void Begin() { lock (this.thisLock) { if (this.completed) return; if (this.timeout != TimeSpan.MaxValue) { this.timer = new IOThreadTimer(OnTimerElapsed, null, true); this.timer.Set(this.timeout); } } } public static bool End(IAsyncResult result) { return !AsyncResult.End (result).timedOut; } protected virtual string GetTimeoutString(TimeSpan timeout) { return SR.GetString(SR.TimeoutOnOperation, timeout); } public void OnAborted(CommunicationObject communicationObject) { if (this.ShouldComplete(false)) Complete(false, communicationObject.CreateClosedException()); } public void OnFaulted(CommunicationObject communicationObject) { if (this.ShouldComplete(false)) Complete(false, communicationObject.GetTerminalException()); } public void OnSignaled() { if (this.ShouldComplete(false)) Complete(false); } protected virtual void OnTimerElapsed(object state) { if (this.ShouldComplete(true)) { if (this.throwTimeoutException) Complete(false, new TimeoutException(this.GetTimeoutString(this.timeout))); else Complete(false); } } bool ShouldComplete(bool timedOut) { lock (this.thisLock) { if (!this.completed) { this.completed = true; this.timedOut = timedOut; if (!timedOut && (this.timer != null)) { this.timer.Cancel(); } return true; } } return false; } } abstract class WsrmIndex { static WsrmFeb2005Index wsAddressingAug2004WSReliableMessagingFeb2005; static WsrmFeb2005Index wsAddressing10WSReliableMessagingFeb2005; static Wsrm11Index wsAddressingAug2004WSReliableMessaging11; static Wsrm11Index wsAddressing10WSReliableMessaging11; internal static ActionHeader GetAckRequestedActionHeader(AddressingVersion addressingVersion, ReliableMessagingVersion reliableMessagingVersion) { return GetActionHeader(addressingVersion, reliableMessagingVersion, WsrmFeb2005Strings.AckRequested); } protected abstract ActionHeader GetActionHeader(string element); static ActionHeader GetActionHeader(AddressingVersion addressingVersion, ReliableMessagingVersion reliableMessagingVersion, string element) { WsrmIndex cache = null; if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005) { if (addressingVersion == AddressingVersion.WSAddressingAugust2004) { if (wsAddressingAug2004WSReliableMessagingFeb2005 == null) { wsAddressingAug2004WSReliableMessagingFeb2005 = new WsrmFeb2005Index(addressingVersion); } cache = wsAddressingAug2004WSReliableMessagingFeb2005; } else if (addressingVersion == AddressingVersion.WSAddressing10) { if (wsAddressing10WSReliableMessagingFeb2005 == null) { wsAddressing10WSReliableMessagingFeb2005 = new WsrmFeb2005Index(addressingVersion); } cache = wsAddressing10WSReliableMessagingFeb2005; } } else if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11) { if (addressingVersion == AddressingVersion.WSAddressingAugust2004) { if (wsAddressingAug2004WSReliableMessaging11 == null) { wsAddressingAug2004WSReliableMessaging11 = new Wsrm11Index(addressingVersion); } cache = wsAddressingAug2004WSReliableMessaging11; } else if (addressingVersion == AddressingVersion.WSAddressing10) { if (wsAddressing10WSReliableMessaging11 == null) { wsAddressing10WSReliableMessaging11 = new Wsrm11Index(addressingVersion); } cache = wsAddressing10WSReliableMessaging11; } } else { DiagnosticUtility.DebugAssert("Reliable messaging version not supported."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } if (cache == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ProtocolException(SR.GetString(SR.AddressingVersionNotSupported, addressingVersion))); } return cache.GetActionHeader(element); } internal static ActionHeader GetCloseSequenceActionHeader(AddressingVersion addressingVersion) { return GetActionHeader(addressingVersion, ReliableMessagingVersion.WSReliableMessaging11, Wsrm11Strings.CloseSequence); } internal static ActionHeader GetCloseSequenceResponseActionHeader(AddressingVersion addressingVersion) { return GetActionHeader(addressingVersion, ReliableMessagingVersion.WSReliableMessaging11, Wsrm11Strings.CloseSequenceResponse); } internal static ActionHeader GetCreateSequenceActionHeader(AddressingVersion addressingVersion, ReliableMessagingVersion reliableMessagingVersion) { return GetActionHeader(addressingVersion, reliableMessagingVersion, WsrmFeb2005Strings.CreateSequence); } internal static string GetCreateSequenceActionString(ReliableMessagingVersion reliableMessagingVersion) { if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005) { return WsrmFeb2005Strings.CreateSequenceAction; } else if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11) { return Wsrm11Strings.CreateSequenceAction; } else { DiagnosticUtility.DebugAssert("Reliable messaging version not supported."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } internal static XmlDictionaryString GetCreateSequenceResponseAction(ReliableMessagingVersion reliableMessagingVersion) { if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005) { return XD.WsrmFeb2005Dictionary.CreateSequenceResponseAction; } else if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11) { return DXD.Wsrm11Dictionary.CreateSequenceResponseAction; } else { DiagnosticUtility.DebugAssert("Reliable messaging version not supported."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } internal static string GetCreateSequenceResponseActionString(ReliableMessagingVersion reliableMessagingVersion) { if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005) { return WsrmFeb2005Strings.CreateSequenceResponseAction; } else if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11) { return Wsrm11Strings.CreateSequenceResponseAction; } else { DiagnosticUtility.DebugAssert("Reliable messaging version not supported."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } internal static string GetFaultActionString(AddressingVersion addressingVersion, ReliableMessagingVersion reliableMessagingVersion) { if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005) { return addressingVersion.DefaultFaultAction; } else if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11) { return Wsrm11Strings.FaultAction; } else { DiagnosticUtility.DebugAssert("Reliable messaging version not supported."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } internal static XmlDictionaryString GetNamespace(ReliableMessagingVersion reliableMessagingVersion) { if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005) { return XD.WsrmFeb2005Dictionary.Namespace; } else if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11) { return DXD.Wsrm11Dictionary.Namespace; } else { DiagnosticUtility.DebugAssert("Reliable messaging version not supported."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } internal static string GetNamespaceString(ReliableMessagingVersion reliableMessagingVersion) { if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005) { return WsrmFeb2005Strings.Namespace; } else if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11) { return Wsrm11Strings.Namespace; } else { DiagnosticUtility.DebugAssert("Reliable messaging version not supported."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } internal static ActionHeader GetSequenceAcknowledgementActionHeader(AddressingVersion addressingVersion, ReliableMessagingVersion reliableMessagingVersion) { return GetActionHeader(addressingVersion, reliableMessagingVersion, WsrmFeb2005Strings.SequenceAcknowledgement); } internal static string GetSequenceAcknowledgementActionString(ReliableMessagingVersion reliableMessagingVersion) { if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005) { return WsrmFeb2005Strings.SequenceAcknowledgementAction; } else if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11) { return Wsrm11Strings.SequenceAcknowledgementAction; } else { DiagnosticUtility.DebugAssert("Reliable messaging version not supported."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } internal static MessagePartSpecification GetSignedReliabilityMessageParts( ReliableMessagingVersion reliableMessagingVersion) { if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005) { return WsrmFeb2005Index.SignedReliabilityMessageParts; } else if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11) { return Wsrm11Index.SignedReliabilityMessageParts; } else { DiagnosticUtility.DebugAssert("Reliable messaging version not supported."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } internal static ActionHeader GetTerminateSequenceActionHeader(AddressingVersion addressingVersion, ReliableMessagingVersion reliableMessagingVersion) { return GetActionHeader(addressingVersion, reliableMessagingVersion, WsrmFeb2005Strings.TerminateSequence); } internal static string GetTerminateSequenceActionString(ReliableMessagingVersion reliableMessagingVersion) { if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005) { return WsrmFeb2005Strings.TerminateSequenceAction; } else if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11) { return Wsrm11Strings.TerminateSequenceAction; } else { DiagnosticUtility.DebugAssert("Reliable messaging version not supported."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } internal static string GetTerminateSequenceResponseActionString(ReliableMessagingVersion reliableMessagingVersion) { if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11) { return Wsrm11Strings.TerminateSequenceResponseAction; } else { DiagnosticUtility.DebugAssert("Reliable messaging version not supported."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } internal static ActionHeader GetTerminateSequenceResponseActionHeader(AddressingVersion addressingVersion) { return GetActionHeader(addressingVersion, ReliableMessagingVersion.WSReliableMessaging11, Wsrm11Strings.TerminateSequenceResponse); } } class Wsrm11Index : WsrmIndex { static MessagePartSpecification signedReliabilityMessageParts; ActionHeader ackRequestedActionHeader; AddressingVersion addressingVersion; ActionHeader closeSequenceActionHeader; ActionHeader closeSequenceResponseActionHeader; ActionHeader createSequenceActionHeader; ActionHeader sequenceAcknowledgementActionHeader; ActionHeader terminateSequenceActionHeader; ActionHeader terminateSequenceResponseActionHeader; internal Wsrm11Index(AddressingVersion addressingVersion) { this.addressingVersion = addressingVersion; } internal static MessagePartSpecification SignedReliabilityMessageParts { get { if (signedReliabilityMessageParts == null) { XmlQualifiedName[] wsrmMessageHeaders = new XmlQualifiedName[] { new XmlQualifiedName(WsrmFeb2005Strings.Sequence, Wsrm11Strings.Namespace), new XmlQualifiedName(WsrmFeb2005Strings.SequenceAcknowledgement, Wsrm11Strings.Namespace), new XmlQualifiedName(WsrmFeb2005Strings.AckRequested, Wsrm11Strings.Namespace), new XmlQualifiedName(Wsrm11Strings.UsesSequenceSTR, Wsrm11Strings.Namespace), }; MessagePartSpecification s = new MessagePartSpecification(wsrmMessageHeaders); s.MakeReadOnly(); signedReliabilityMessageParts = s; } return signedReliabilityMessageParts; } } protected override ActionHeader GetActionHeader(string element) { Wsrm11Dictionary wsrm11Dictionary = DXD.Wsrm11Dictionary; if (element == WsrmFeb2005Strings.AckRequested) { if (ackRequestedActionHeader == null) { ackRequestedActionHeader = ActionHeader.Create(wsrm11Dictionary.AckRequestedAction, this.addressingVersion); } return ackRequestedActionHeader; } else if (element == WsrmFeb2005Strings.CreateSequence) { if (createSequenceActionHeader == null) { createSequenceActionHeader = ActionHeader.Create(wsrm11Dictionary.CreateSequenceAction, this.addressingVersion); } return createSequenceActionHeader; } else if (element == WsrmFeb2005Strings.SequenceAcknowledgement) { if (sequenceAcknowledgementActionHeader == null) { sequenceAcknowledgementActionHeader = ActionHeader.Create(wsrm11Dictionary.SequenceAcknowledgementAction, this.addressingVersion); } return sequenceAcknowledgementActionHeader; } else if (element == WsrmFeb2005Strings.TerminateSequence) { if (terminateSequenceActionHeader == null) { terminateSequenceActionHeader = ActionHeader.Create(wsrm11Dictionary.TerminateSequenceAction, this.addressingVersion); } return terminateSequenceActionHeader; } else if (element == Wsrm11Strings.TerminateSequenceResponse) { if (terminateSequenceResponseActionHeader == null) { terminateSequenceResponseActionHeader = ActionHeader.Create(wsrm11Dictionary.TerminateSequenceResponseAction, this.addressingVersion); } return terminateSequenceResponseActionHeader; } else if (element == Wsrm11Strings.CloseSequence) { if (closeSequenceActionHeader == null) { closeSequenceActionHeader = ActionHeader.Create(wsrm11Dictionary.CloseSequenceAction, this.addressingVersion); } return closeSequenceActionHeader; } else if (element == Wsrm11Strings.CloseSequenceResponse) { if (closeSequenceResponseActionHeader == null) { closeSequenceResponseActionHeader = ActionHeader.Create(wsrm11Dictionary.CloseSequenceResponseAction, this.addressingVersion); } return closeSequenceResponseActionHeader; } else { DiagnosticUtility.DebugAssert("Element not supported."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } } class WsrmFeb2005Index : WsrmIndex { static MessagePartSpecification signedReliabilityMessageParts; ActionHeader ackRequestedActionHeader; AddressingVersion addressingVersion; ActionHeader createSequenceActionHeader; ActionHeader sequenceAcknowledgementActionHeader; ActionHeader terminateSequenceActionHeader; internal WsrmFeb2005Index(AddressingVersion addressingVersion) { this.addressingVersion = addressingVersion; } internal static MessagePartSpecification SignedReliabilityMessageParts { get { if (signedReliabilityMessageParts == null) { XmlQualifiedName[] wsrmMessageHeaders = new XmlQualifiedName[] { new XmlQualifiedName(WsrmFeb2005Strings.Sequence, WsrmFeb2005Strings.Namespace), new XmlQualifiedName(WsrmFeb2005Strings.SequenceAcknowledgement, WsrmFeb2005Strings.Namespace), new XmlQualifiedName(WsrmFeb2005Strings.AckRequested, WsrmFeb2005Strings.Namespace), }; MessagePartSpecification s = new MessagePartSpecification(wsrmMessageHeaders); s.MakeReadOnly(); signedReliabilityMessageParts = s; } return signedReliabilityMessageParts; } } protected override ActionHeader GetActionHeader(string element) { WsrmFeb2005Dictionary wsrmFeb2005Dictionary = XD.WsrmFeb2005Dictionary; if (element == WsrmFeb2005Strings.AckRequested) { if (ackRequestedActionHeader == null) { ackRequestedActionHeader = ActionHeader.Create(wsrmFeb2005Dictionary.AckRequestedAction, this.addressingVersion); } return ackRequestedActionHeader; } else if (element == WsrmFeb2005Strings.CreateSequence) { if (createSequenceActionHeader == null) { createSequenceActionHeader = ActionHeader.Create(wsrmFeb2005Dictionary.CreateSequenceAction, this.addressingVersion); } return createSequenceActionHeader; } else if (element == WsrmFeb2005Strings.SequenceAcknowledgement) { if (sequenceAcknowledgementActionHeader == null) { sequenceAcknowledgementActionHeader = ActionHeader.Create(wsrmFeb2005Dictionary.SequenceAcknowledgementAction, this.addressingVersion); } return sequenceAcknowledgementActionHeader; } else if (element == WsrmFeb2005Strings.TerminateSequence) { if (terminateSequenceActionHeader == null) { terminateSequenceActionHeader = ActionHeader.Create(wsrmFeb2005Dictionary.TerminateSequenceAction, this.addressingVersion); } return terminateSequenceActionHeader; } else { DiagnosticUtility.DebugAssert("Element not supported."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } } static class WsrmUtilities { public static TimeSpan CalculateKeepAliveInterval(TimeSpan inactivityTimeout, int maxRetryCount) { return Ticks.ToTimeSpan(Ticks.FromTimeSpan(inactivityTimeout) / 2 / maxRetryCount); } internal static UniqueId NextSequenceId() { return new UniqueId(); } internal static void AddAcknowledgementHeader(ReliableMessagingVersion reliableMessagingVersion, Message message, UniqueId id, SequenceRangeCollection ranges, bool final) { WsrmUtilities.AddAcknowledgementHeader(reliableMessagingVersion, message, id, ranges, final, -1); } internal static void AddAcknowledgementHeader(ReliableMessagingVersion reliableMessagingVersion, Message message, UniqueId id, SequenceRangeCollection ranges, bool final, int bufferRemaining) { message.Headers.Insert(0, new WsrmAcknowledgmentHeader(reliableMessagingVersion, id, ranges, final, bufferRemaining)); } internal static void AddAckRequestedHeader(ReliableMessagingVersion reliableMessagingVersion, Message message, UniqueId id) { message.Headers.Insert(0, new WsrmAckRequestedHeader(reliableMessagingVersion, id)); } internal static void AddSequenceHeader(ReliableMessagingVersion reliableMessagingVersion, Message message, UniqueId id, Int64 sequenceNumber, bool isLast) { message.Headers.Insert(0, new WsrmSequencedMessageHeader(reliableMessagingVersion, id, sequenceNumber, isLast)); } internal static void AssertWsrm11(ReliableMessagingVersion reliableMessagingVersion) { if (reliableMessagingVersion != ReliableMessagingVersion.WSReliableMessaging11) { DiagnosticUtility.DebugAssert("WS-ReliableMessaging 1.1 required."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } } internal static Message CreateAcknowledgmentMessage(MessageVersion version, ReliableMessagingVersion reliableMessagingVersion, UniqueId id, SequenceRangeCollection ranges, bool final, int bufferRemaining) { Message message = Message.CreateMessage(version, WsrmIndex.GetSequenceAcknowledgementActionHeader(version.Addressing, reliableMessagingVersion)); WsrmUtilities.AddAcknowledgementHeader(reliableMessagingVersion, message, id, ranges, final, bufferRemaining); message.Properties.AllowOutputBatching = false; return message; } internal static Message CreateAckRequestedMessage(MessageVersion messageVersion, ReliableMessagingVersion reliableMessagingVersion, UniqueId id) { Message message = Message.CreateMessage(messageVersion, WsrmIndex.GetAckRequestedActionHeader(messageVersion.Addressing, reliableMessagingVersion)); WsrmUtilities.AddAckRequestedHeader(reliableMessagingVersion, message, id); message.Properties.AllowOutputBatching = false; return message; } internal static Message CreateCloseSequenceResponse(MessageVersion messageVersion, UniqueId messageId, UniqueId inputId) { CloseSequenceResponse response = new CloseSequenceResponse(inputId); Message message = Message.CreateMessage(messageVersion, WsrmIndex.GetCloseSequenceResponseActionHeader(messageVersion.Addressing), response); message.Headers.RelatesTo = messageId; return message; } internal static Message CreateCreateSequenceResponse(MessageVersion messageVersion, ReliableMessagingVersion reliableMessagingVersion, bool duplex, CreateSequenceInfo createSequenceInfo, bool ordered, UniqueId inputId, EndpointAddress acceptAcksTo) { CreateSequenceResponse response = new CreateSequenceResponse(messageVersion.Addressing, reliableMessagingVersion); response.Identifier = inputId; response.Expires = createSequenceInfo.Expires; response.Ordered = ordered; if (duplex) response.AcceptAcksTo = acceptAcksTo; Message responseMessage = Message.CreateMessage(messageVersion, ActionHeader.Create( WsrmIndex.GetCreateSequenceResponseAction(reliableMessagingVersion), messageVersion.Addressing), response); return responseMessage; } internal static Message CreateCSRefusedCommunicationFault(MessageVersion messageVersion, ReliableMessagingVersion reliableMessagingVersion, string reason) { return CreateCSRefusedFault(messageVersion, reliableMessagingVersion, false, null, reason); } internal static Message CreateCSRefusedProtocolFault(MessageVersion messageVersion, ReliableMessagingVersion reliableMessagingVersion, string reason) { return CreateCSRefusedFault(messageVersion, reliableMessagingVersion, true, null, reason); } internal static Message CreateCSRefusedServerTooBusyFault(MessageVersion messageVersion, ReliableMessagingVersion reliableMessagingVersion, string reason) { FaultCode subCode = new FaultCode(WsrmFeb2005Strings.ConnectionLimitReached, WsrmFeb2005Strings.NETNamespace); subCode = new FaultCode(WsrmFeb2005Strings.CreateSequenceRefused, WsrmIndex.GetNamespaceString(reliableMessagingVersion), subCode); return CreateCSRefusedFault(messageVersion, reliableMessagingVersion, false, subCode, reason); } static Message CreateCSRefusedFault(MessageVersion messageVersion, ReliableMessagingVersion reliableMessagingVersion, bool isSenderFault, FaultCode subCode, string reason) { FaultCode code; if (messageVersion.Envelope == EnvelopeVersion.Soap11) { code = new FaultCode(WsrmFeb2005Strings.CreateSequenceRefused, WsrmIndex.GetNamespaceString(reliableMessagingVersion)); } else if (messageVersion.Envelope == EnvelopeVersion.Soap12) { if (subCode == null) subCode = new FaultCode(WsrmFeb2005Strings.CreateSequenceRefused, WsrmIndex.GetNamespaceString(reliableMessagingVersion), subCode); if (isSenderFault) code = FaultCode.CreateSenderFaultCode(subCode); else code = FaultCode.CreateReceiverFaultCode(subCode); } else { DiagnosticUtility.DebugAssert("Unsupported version."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } FaultReason faultReason = new FaultReason(SR.GetString(SR.CSRefused, reason), CultureInfo.CurrentCulture); MessageFault fault = MessageFault.CreateFault(code, faultReason); string action = WsrmIndex.GetFaultActionString(messageVersion.Addressing, reliableMessagingVersion); return Message.CreateMessage(messageVersion, fault, action); } public static Exception CreateCSFaultException(MessageVersion version, ReliableMessagingVersion reliableMessagingVersion, Message message, IChannel innerChannel) { MessageFault fault = MessageFault.CreateFault(message, TransportDefaults.MaxRMFaultSize); FaultCode code = fault.Code; FaultCode subCode; if (version.Envelope == EnvelopeVersion.Soap11) { subCode = code; } else if (version.Envelope == EnvelopeVersion.Soap12) { subCode = code.SubCode; } else { DiagnosticUtility.DebugAssert("Unsupported version."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } if (subCode != null) { // CreateSequenceRefused if ((subCode.Namespace == WsrmIndex.GetNamespaceString(reliableMessagingVersion)) && (subCode.Name == WsrmFeb2005Strings.CreateSequenceRefused)) { string reason = FaultException.GetSafeReasonText(fault); if (version.Envelope == EnvelopeVersion.Soap12) { FaultCode subSubCode = subCode.SubCode; if ((subSubCode != null) && (subSubCode.Namespace == WsrmFeb2005Strings.NETNamespace) && (subSubCode.Name == WsrmFeb2005Strings.ConnectionLimitReached)) { return new ServerTooBusyException(reason); } if (code.IsSenderFault) { return new ProtocolException(reason); } } return new CommunicationException(reason); } else if ((subCode.Namespace == version.Addressing.Namespace) && (subCode.Name == AddressingStrings.EndpointUnavailable)) { return new EndpointNotFoundException(FaultException.GetSafeReasonText(fault)); } } FaultConverter faultConverter = innerChannel.GetProperty (); if (faultConverter == null) faultConverter = FaultConverter.GetDefaultFaultConverter(version); Exception exception; if (faultConverter.TryCreateException(message, fault, out exception)) { return exception; } else { return new ProtocolException(SR.GetString(SR.UnrecognizedFaultReceivedOnOpen, fault.Code.Namespace, fault.Code.Name, FaultException.GetSafeReasonText(fault))); } } internal static Message CreateEndpointNotFoundFault(MessageVersion version, string reason) { FaultCode subCode = new FaultCode(AddressingStrings.EndpointUnavailable, version.Addressing.Namespace); FaultCode code; if (version.Envelope == EnvelopeVersion.Soap11) { code = subCode; } else if (version.Envelope == EnvelopeVersion.Soap12) { code = FaultCode.CreateSenderFaultCode(subCode); } else { DiagnosticUtility.DebugAssert("Unsupported version."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } FaultReason faultReason = new FaultReason(reason, CultureInfo.CurrentCulture); MessageFault fault = MessageFault.CreateFault(code, faultReason); return Message.CreateMessage(version, fault, version.Addressing.DefaultFaultAction); } internal static Message CreateTerminateMessage(MessageVersion version, ReliableMessagingVersion reliableMessagingVersion, UniqueId id) { return CreateTerminateMessage(version, reliableMessagingVersion, id, -1); } internal static Message CreateTerminateMessage(MessageVersion version, ReliableMessagingVersion reliableMessagingVersion, UniqueId id, Int64 last) { Message message = Message.CreateMessage(version, WsrmIndex.GetTerminateSequenceActionHeader(version.Addressing, reliableMessagingVersion), new TerminateSequence(reliableMessagingVersion, id, last)); message.Properties.AllowOutputBatching = false; return message; } internal static Message CreateTerminateResponseMessage(MessageVersion version, UniqueId messageId, UniqueId sequenceId) { Message message = Message.CreateMessage(version, WsrmIndex.GetTerminateSequenceResponseActionHeader(version.Addressing), new TerminateSequenceResponse(sequenceId)); message.Properties.AllowOutputBatching = false; message.Headers.RelatesTo = messageId; return message; } internal static UniqueId GetInputId(WsrmMessageInfo info) { if (info.TerminateSequenceInfo != null) { return info.TerminateSequenceInfo.Identifier; } if (info.SequencedMessageInfo != null) { return info.SequencedMessageInfo.SequenceID; } if (info.AckRequestedInfo != null) { return info.AckRequestedInfo.SequenceID; } if (info.WsrmHeaderFault != null && info.WsrmHeaderFault.FaultsInput) { return info.WsrmHeaderFault.SequenceID; } if (info.CloseSequenceInfo != null) { return info.CloseSequenceInfo.Identifier; } return null; } internal static UniqueId GetOutputId(ReliableMessagingVersion reliableMessagingVersion, WsrmMessageInfo info) { if (info.AcknowledgementInfo != null) { return info.AcknowledgementInfo.SequenceID; } if (info.WsrmHeaderFault != null && info.WsrmHeaderFault.FaultsOutput) { return info.WsrmHeaderFault.SequenceID; } if (info.TerminateSequenceResponseInfo != null) { return info.TerminateSequenceResponseInfo.Identifier; } if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11) { if (info.CloseSequenceInfo != null) { return info.CloseSequenceInfo.Identifier; } if (info.CloseSequenceResponseInfo != null) { return info.CloseSequenceResponseInfo.Identifier; } if (info.TerminateSequenceResponseInfo != null) { return info.TerminateSequenceResponseInfo.Identifier; } } return null; } internal static bool IsWsrmAction(ReliableMessagingVersion reliableMessagingVersion, string action) { if (action == null) return false; return (action.StartsWith(WsrmIndex.GetNamespaceString(reliableMessagingVersion), StringComparison.Ordinal)); } public static void ReadEmptyElement(XmlDictionaryReader reader) { if (reader.IsEmptyElement) { reader.Read(); } else { reader.Read(); reader.ReadEndElement(); } } public static UniqueId ReadIdentifier(XmlDictionaryReader reader, ReliableMessagingVersion reliableMessagingVersion) { reader.ReadStartElement(XD.WsrmFeb2005Dictionary.Identifier, WsrmIndex.GetNamespace(reliableMessagingVersion)); UniqueId sequenceID = reader.ReadContentAsUniqueId(); reader.ReadEndElement(); return sequenceID; } public static Int64 ReadSequenceNumber(XmlDictionaryReader reader) { return WsrmUtilities.ReadSequenceNumber(reader, false); } public static Int64 ReadSequenceNumber(XmlDictionaryReader reader, bool allowZero) { Int64 sequenceNumber = reader.ReadContentAsLong(); if (sequenceNumber < 0 || (sequenceNumber == 0 && !allowZero)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException( SR.GetString(SR.InvalidSequenceNumber, sequenceNumber))); } return sequenceNumber; } // Caller owns message. public static WsrmFault ValidateCloseSequenceResponse(ChannelReliableSession session, UniqueId messageId, WsrmMessageInfo info, Int64 last) { string exceptionString = null; string faultString = null; if (info.CloseSequenceResponseInfo == null) { exceptionString = SR.GetString(SR.InvalidWsrmResponseSessionFaultedExceptionString, Wsrm11Strings.CloseSequence, info.Action, Wsrm11Strings.CloseSequenceResponseAction); faultString = SR.GetString(SR.InvalidWsrmResponseSessionFaultedFaultString, Wsrm11Strings.CloseSequence, info.Action, Wsrm11Strings.CloseSequenceResponseAction); } else if (!object.Equals(messageId, info.CloseSequenceResponseInfo.RelatesTo)) { exceptionString = SR.GetString(SR.WsrmMessageWithWrongRelatesToExceptionString, Wsrm11Strings.CloseSequence); faultString = SR.GetString(SR.WsrmMessageWithWrongRelatesToFaultString, Wsrm11Strings.CloseSequence); } else if (info.AcknowledgementInfo == null || !info.AcknowledgementInfo.Final) { exceptionString = SR.GetString(SR.MissingFinalAckExceptionString); faultString = SR.GetString(SR.SequenceTerminatedMissingFinalAck); } else { return ValidateFinalAck(session, info, last); } UniqueId sequenceId = session.OutputID; return SequenceTerminatedFault.CreateProtocolFault(sequenceId, faultString, exceptionString); } public static bool ValidateCreateSequence (WsrmMessageInfo info, ReliableChannelListenerBase listener, IChannel channel, out EndpointAddress acksTo) where TChannel : class, IChannel { acksTo = null; string reason = null; if (info.CreateSequenceInfo.OfferIdentifier == null) { if (typeof(TChannel) == typeof(IDuplexSessionChannel)) reason = SR.GetString(SR.CSRefusedDuplexNoOffer, listener.Uri); else if (typeof(TChannel) == typeof(IReplySessionChannel)) reason = SR.GetString(SR.CSRefusedReplyNoOffer, listener.Uri); } else if (listener.ReliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005) { if (typeof(TChannel) == typeof(IInputSessionChannel)) reason = SR.GetString(SR.CSRefusedInputOffer, listener.Uri); } if (reason != null) { info.FaultReply = WsrmUtilities.CreateCSRefusedProtocolFault(listener.MessageVersion, listener.ReliableMessagingVersion, reason); info.FaultException = new ProtocolException(SR.GetString(SR.ConflictingOffer)); return false; } if (listener.LocalAddresses != null) { Collection addresses = new Collection (); try { listener.LocalAddresses.GetMatchingValues(info.Message, addresses); } catch (CommunicationException e) { FaultConverter converter = channel.GetProperty (); if (converter == null) converter = FaultConverter.GetDefaultFaultConverter(listener.MessageVersion); Message faultReply; if (converter.TryCreateFaultMessage(e, out faultReply)) { info.FaultReply = faultReply; info.FaultException = new ProtocolException(SR.GetString(SR.MessageExceptionOccurred), e); return false; } throw; } if (addresses.Count > 0) { EndpointAddress match = addresses[0]; acksTo = new EndpointAddress(info.CreateSequenceInfo.To, match.Identity, match.Headers); return true; } else { info.FaultReply = CreateEndpointNotFoundFault(listener.MessageVersion, SR.GetString(SR.EndpointNotFound, info.CreateSequenceInfo.To)); info.FaultException = new ProtocolException(SR.GetString(SR.ConflictingAddress)); return false; } } else { acksTo = new EndpointAddress(info.CreateSequenceInfo.To); return true; } } public static WsrmFault ValidateFinalAck(ChannelReliableSession session, WsrmMessageInfo info, Int64 last) { WsrmAcknowledgmentInfo ackInfo = info.AcknowledgementInfo; WsrmFault fault = ValidateFinalAckExists(session, ackInfo); if (fault != null) { return fault; } SequenceRangeCollection finalRanges = ackInfo.Ranges; if (last == 0) { if (finalRanges.Count == 0) { return null; } } else { if ((finalRanges.Count == 1) && (finalRanges[0].Lower == 1) && (finalRanges[0].Upper == last)) { return null; } } return new InvalidAcknowledgementFault(session.OutputID, ackInfo.Ranges); } public static WsrmFault ValidateFinalAckExists(ChannelReliableSession session, WsrmAcknowledgmentInfo ackInfo) { if (ackInfo == null || !ackInfo.Final) { string exceptionString = SR.GetString(SR.MissingFinalAckExceptionString); string faultString = SR.GetString(SR.SequenceTerminatedMissingFinalAck); return SequenceTerminatedFault.CreateProtocolFault(session.OutputID, faultString, exceptionString); } return null; } // Caller owns message. public static WsrmFault ValidateTerminateSequenceResponse(ChannelReliableSession session, UniqueId messageId, WsrmMessageInfo info, Int64 last) { string exceptionString = null; string faultString = null; if (info.WsrmHeaderFault is UnknownSequenceFault) { return null; } else if (info.TerminateSequenceResponseInfo == null) { exceptionString = SR.GetString(SR.InvalidWsrmResponseSessionFaultedExceptionString, WsrmFeb2005Strings.TerminateSequence, info.Action, Wsrm11Strings.TerminateSequenceResponseAction); faultString = SR.GetString(SR.InvalidWsrmResponseSessionFaultedFaultString, WsrmFeb2005Strings.TerminateSequence, info.Action, Wsrm11Strings.TerminateSequenceResponseAction); } else if (!object.Equals(messageId, info.TerminateSequenceResponseInfo.RelatesTo)) { exceptionString = SR.GetString(SR.WsrmMessageWithWrongRelatesToExceptionString, WsrmFeb2005Strings.TerminateSequence); faultString = SR.GetString(SR.WsrmMessageWithWrongRelatesToFaultString, WsrmFeb2005Strings.TerminateSequence); } else { return ValidateFinalAck(session, info, last); } UniqueId sequenceId = session.OutputID; return SequenceTerminatedFault.CreateProtocolFault(sequenceId, faultString, exceptionString); } // Checks that ReplyTo and RemoteAddress are equivalent. Will fault the session with SequenceTerminatedFault. // Meant to be used for CloseSequence and TerminateSequence in Wsrm 1.1. public static bool ValidateWsrmRequest(ChannelReliableSession session, WsrmRequestInfo info, IReliableChannelBinder binder, RequestContext context) { if (!(info is CloseSequenceInfo) && !(info is TerminateSequenceInfo)) { DiagnosticUtility.DebugAssert("Method is meant for CloseSequence or TerminateSequence only."); throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); } if (info.ReplyTo.Uri != binder.RemoteAddress.Uri) { string faultString = SR.GetString(SR.WsrmRequestIncorrectReplyToFaultString, info.RequestName); string exceptionString = SR.GetString(SR.WsrmRequestIncorrectReplyToExceptionString, info.RequestName); WsrmFault fault = SequenceTerminatedFault.CreateProtocolFault(session.InputID, faultString, exceptionString); session.OnLocalFault(fault.CreateException(), fault, context); return false; } else { return true; } } public static void WriteIdentifier(XmlDictionaryWriter writer, ReliableMessagingVersion reliableMessagingVersion, UniqueId sequenceId) { writer.WriteStartElement(WsrmFeb2005Strings.Prefix, XD.WsrmFeb2005Dictionary.Identifier, WsrmIndex.GetNamespace(reliableMessagingVersion)); writer.WriteValue(sequenceId); writer.WriteEndElement(); } // These are strings that are not actually used anywhere. // This method and resources strings can be deleted whenever the resource file can be changed. public static string UseStrings() { string s = SR.SupportedAddressingModeNotSupported; s = SR.SequenceTerminatedUnexpectedCloseSequence; s = SR.UnexpectedCloseSequence; s = SR.SequenceTerminatedUnsupportedTerminateSequence; return s; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- XPathNodePointer.cs
- VirtualPathData.cs
- WebBrowserContainer.cs
- ValueType.cs
- NavigationExpr.cs
- AstTree.cs
- ResizingMessageFilter.cs
- SchemaAttDef.cs
- SingleTagSectionHandler.cs
- NewExpression.cs
- ListViewItem.cs
- Schema.cs
- NullReferenceException.cs
- PaginationProgressEventArgs.cs
- FontFamilyValueSerializer.cs
- DefaultShape.cs
- HtmlAnchor.cs
- DataGridViewLinkColumn.cs
- ScriptDescriptor.cs
- MruCache.cs
- StorageScalarPropertyMapping.cs
- PropertyGeneratedEventArgs.cs
- DomainUpDown.cs
- InfiniteIntConverter.cs
- QueueProcessor.cs
- URLIdentityPermission.cs
- ViewStateModeByIdAttribute.cs
- TextRange.cs
- MenuDesigner.cs
- InfoCardProofToken.cs
- DependencyPropertyKey.cs
- CapabilitiesSection.cs
- ComplexType.cs
- DataColumnMappingCollection.cs
- precedingquery.cs
- Scene3D.cs
- QilLiteral.cs
- SerializationException.cs
- CmsInterop.cs
- ListViewPagedDataSource.cs
- PageWrapper.cs
- SemanticResultKey.cs
- DescendentsWalker.cs
- MissingMemberException.cs
- CmsUtils.cs
- _FtpDataStream.cs
- WSSecurityPolicy12.cs
- Overlapped.cs
- HMACSHA512.cs
- GridViewCancelEditEventArgs.cs
- QuaternionAnimation.cs
- OciLobLocator.cs
- RemotingException.cs
- StyleSheetRefUrlEditor.cs
- AttributeCollection.cs
- ExtractedStateEntry.cs
- MsmqIntegrationValidationBehavior.cs
- Point3DCollectionValueSerializer.cs
- GiveFeedbackEvent.cs
- CodeGroup.cs
- SafeViewOfFileHandle.cs
- Inflater.cs
- InputProcessorProfilesLoader.cs
- TryExpression.cs
- BamlTreeUpdater.cs
- DataException.cs
- FtpRequestCacheValidator.cs
- QueueProcessor.cs
- FileLogRecord.cs
- DayRenderEvent.cs
- MissingFieldException.cs
- RewritingProcessor.cs
- StorageMappingItemCollection.cs
- EventWaitHandleSecurity.cs
- IncrementalHitTester.cs
- arabicshape.cs
- WebEvents.cs
- VarRemapper.cs
- _LocalDataStore.cs
- AutomationPropertyInfo.cs
- Point3D.cs
- FormatSettings.cs
- NavigationHelper.cs
- StaticFileHandler.cs
- DocumentOrderComparer.cs
- ServicesUtilities.cs
- FormattedTextSymbols.cs
- VBIdentifierName.cs
- AssemblyBuilder.cs
- SafeIUnknown.cs
- WebColorConverter.cs
- OleDbStruct.cs
- StorageComplexPropertyMapping.cs
- FormsAuthenticationTicket.cs
- RuntimeWrappedException.cs
- RowUpdatingEventArgs.cs
- EntityStoreSchemaFilterEntry.cs
- InheritedPropertyDescriptor.cs
- DockPattern.cs
- _HeaderInfo.cs