e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
275 lines
9.5 KiB
C#
275 lines
9.5 KiB
C#
//------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------
|
|
|
|
namespace System.ServiceModel.Channels
|
|
{
|
|
using System;
|
|
using System.Runtime;
|
|
using System.ServiceModel;
|
|
|
|
abstract class ContextRequestChannelBase<TChannel> : LayeredChannel<TChannel> where TChannel : class, IRequestChannel
|
|
{
|
|
ContextProtocol contextProtocol;
|
|
|
|
protected ContextRequestChannelBase(ChannelManagerBase channelManager, TChannel innerChannel,
|
|
ContextExchangeMechanism contextExchangeMechanism, Uri callbackAddress, bool contextManagementEnabled)
|
|
: base(channelManager, innerChannel)
|
|
{
|
|
this.contextProtocol = new ClientContextProtocol(contextExchangeMechanism, innerChannel.Via, this, callbackAddress, contextManagementEnabled);
|
|
}
|
|
|
|
public EndpointAddress RemoteAddress
|
|
{
|
|
get { return this.InnerChannel.RemoteAddress; }
|
|
}
|
|
|
|
public Uri Via
|
|
{
|
|
get { return this.InnerChannel.Via; }
|
|
}
|
|
|
|
public IAsyncResult BeginRequest(Message message, TimeSpan timeout, AsyncCallback callback, object state)
|
|
{
|
|
this.contextProtocol.OnOutgoingMessage(message, null);
|
|
return new RequestAsyncResult(message, this.InnerChannel, timeout, callback, state);
|
|
}
|
|
|
|
public IAsyncResult BeginRequest(Message message, AsyncCallback callback, object state)
|
|
{
|
|
return this.BeginRequest(message, this.DefaultSendTimeout, callback, state);
|
|
}
|
|
|
|
public Message EndRequest(IAsyncResult result)
|
|
{
|
|
Message message = RequestAsyncResult.End(result);
|
|
|
|
if (message != null)
|
|
{
|
|
this.contextProtocol.OnIncomingMessage(message);
|
|
}
|
|
|
|
return message;
|
|
}
|
|
|
|
public override T GetProperty<T>()
|
|
{
|
|
if (typeof(T) == typeof(IContextManager) && this.contextProtocol is IContextManager)
|
|
{
|
|
return (T)(object)this.contextProtocol;
|
|
}
|
|
else
|
|
{
|
|
return base.GetProperty<T>();
|
|
}
|
|
}
|
|
|
|
public Message Request(Message message, TimeSpan timeout)
|
|
{
|
|
CorrelationCallbackMessageProperty callback = null;
|
|
TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
|
|
Message requestMessage = message;
|
|
|
|
this.contextProtocol.OnOutgoingMessage(message, null);
|
|
if (message != null && CorrelationCallbackMessageProperty.TryGet(message, out callback))
|
|
{
|
|
ContextExchangeCorrelationHelper.AddOutgoingCorrelationCallbackData(callback, message, true);
|
|
if (callback.IsFullyDefined)
|
|
{
|
|
requestMessage = callback.FinalizeCorrelation(message, timeoutHelper.RemainingTime());
|
|
}
|
|
}
|
|
|
|
Message response = null;
|
|
try
|
|
{
|
|
response = this.InnerChannel.Request(requestMessage, timeout);
|
|
if (response != null)
|
|
{
|
|
this.contextProtocol.OnIncomingMessage(response);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
if (message != null && !object.ReferenceEquals(message, requestMessage))
|
|
{
|
|
requestMessage.Close();
|
|
}
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
public Message Request(Message message)
|
|
{
|
|
return this.Request(message, this.DefaultSendTimeout);
|
|
}
|
|
|
|
class RequestAsyncResult : AsyncResult
|
|
{
|
|
|
|
static AsyncCallback onFinalizeCorrelation = Fx.ThunkCallback(new AsyncCallback(OnFinalizeCorrelationCompletedCallback));
|
|
static AsyncCallback onRequest = Fx.ThunkCallback(new AsyncCallback(OnRequestCompletedCallback));
|
|
IRequestChannel channel;
|
|
CorrelationCallbackMessageProperty correlationCallback;
|
|
Message message;
|
|
Message replyMessage;
|
|
Message requestMessage;
|
|
TimeoutHelper timeoutHelper;
|
|
|
|
public RequestAsyncResult(Message message, IRequestChannel channel, TimeSpan timeout, AsyncCallback callback, object state)
|
|
: base(callback, state)
|
|
{
|
|
this.channel = channel;
|
|
this.message = this.requestMessage = message;
|
|
this.timeoutHelper = new TimeoutHelper(timeout);
|
|
bool shouldRequest = true;
|
|
|
|
if (message != null)
|
|
{
|
|
if (CorrelationCallbackMessageProperty.TryGet(message, out this.correlationCallback))
|
|
{
|
|
ContextExchangeCorrelationHelper.AddOutgoingCorrelationCallbackData(this.correlationCallback, message, true);
|
|
|
|
if (this.correlationCallback.IsFullyDefined)
|
|
{
|
|
IAsyncResult result = this.correlationCallback.BeginFinalizeCorrelation(this.message, this.timeoutHelper.RemainingTime(), onFinalizeCorrelation, this);
|
|
if (result.CompletedSynchronously)
|
|
{
|
|
if (OnFinalizeCorrelationCompleted(result))
|
|
{
|
|
base.Complete(true);
|
|
}
|
|
}
|
|
|
|
shouldRequest = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (shouldRequest)
|
|
{
|
|
IAsyncResult result = this.channel.BeginRequest(this.message, this.timeoutHelper.RemainingTime(), onRequest, this);
|
|
if (result.CompletedSynchronously)
|
|
{
|
|
OnRequestCompleted(result);
|
|
base.Complete(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static Message End(IAsyncResult result)
|
|
{
|
|
RequestAsyncResult thisPtr = AsyncResult.End<RequestAsyncResult>(result);
|
|
return thisPtr.replyMessage;
|
|
}
|
|
|
|
static void OnFinalizeCorrelationCompletedCallback(IAsyncResult result)
|
|
{
|
|
if (result.CompletedSynchronously)
|
|
{
|
|
return;
|
|
}
|
|
|
|
RequestAsyncResult thisPtr = (RequestAsyncResult)result.AsyncState;
|
|
|
|
Exception completionException = null;
|
|
bool completeSelf;
|
|
try
|
|
{
|
|
completeSelf = thisPtr.OnFinalizeCorrelationCompleted(result);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
if (Fx.IsFatal(e))
|
|
{
|
|
throw;
|
|
}
|
|
|
|
completionException = e;
|
|
completeSelf = true;
|
|
}
|
|
|
|
if (completeSelf)
|
|
{
|
|
thisPtr.Complete(false, completionException);
|
|
}
|
|
}
|
|
|
|
static void OnRequestCompletedCallback(IAsyncResult result)
|
|
{
|
|
if (result.CompletedSynchronously)
|
|
{
|
|
return;
|
|
}
|
|
|
|
RequestAsyncResult thisPtr = (RequestAsyncResult)result.AsyncState;
|
|
|
|
Exception completionException = null;
|
|
try
|
|
{
|
|
thisPtr.OnRequestCompleted(result);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
if (Fx.IsFatal(e))
|
|
{
|
|
throw;
|
|
}
|
|
|
|
completionException = e;
|
|
}
|
|
|
|
thisPtr.Complete(false, completionException);
|
|
}
|
|
|
|
bool OnFinalizeCorrelationCompleted(IAsyncResult result)
|
|
{
|
|
this.requestMessage = this.correlationCallback.EndFinalizeCorrelation(result);
|
|
this.requestMessage.Properties.Remove(CorrelationCallbackMessageProperty.Name);
|
|
|
|
bool throwing = true;
|
|
IAsyncResult requestResult;
|
|
try
|
|
{
|
|
requestResult = this.channel.BeginRequest(this.requestMessage, this.timeoutHelper.RemainingTime(), onRequest, this);
|
|
throwing = false;
|
|
}
|
|
finally
|
|
{
|
|
if (throwing)
|
|
{
|
|
if (this.message != null && !object.ReferenceEquals(this.message, this.requestMessage))
|
|
{
|
|
this.requestMessage.Close();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (requestResult.CompletedSynchronously)
|
|
{
|
|
OnRequestCompleted(requestResult);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void OnRequestCompleted(IAsyncResult result)
|
|
{
|
|
try
|
|
{
|
|
this.replyMessage = this.channel.EndRequest(result);
|
|
}
|
|
finally
|
|
{
|
|
if (this.message != null && !object.ReferenceEquals(this.message, this.requestMessage))
|
|
{
|
|
this.requestMessage.Close();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|