Skip to content

Exception SFxCallbackRequestReplyInOrder1 in System.ServiceModel.Channels.ServiceChannel when using ConcurrencyMode.Multiple #5861

@fedotovrr

Description

@fedotovrr

My service using ConcurrencyMode.Multiple and my Framework code is identical to NET code.
NET code sometimes throws SFxCallbackRequestReplyInOrder1 exceptions in System.ServiceModel.Channels.ServiceChannel on client side.
While debugging my Framework code, I see that OperationContext.Current is always null and anyway ConcurrencyMode.Single, in NET code OperationContext.Current is not null and this results in an exception.

private void PrepareCall(ProxyOperationRuntime operation, bool oneway, ref ProxyRpc rpc)
{
OperationContext context = OperationContext.Current;
// Doing a request reply callback when dispatching in-order deadlocks.
// We never receive the reply until we finish processing the current message.
if (!oneway)
{
DispatchRuntime dispatchBehavior = ClientRuntime.DispatchRuntime;
if ((dispatchBehavior != null) && (dispatchBehavior.ConcurrencyMode == ConcurrencyMode.Single))
{
if ((context != null) && (!context.IsUserContext) && (context.InternalServiceChannel == this))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRP.Format(SRP.SFxCallbackRequestReplyInOrder1, typeof(CallbackBehaviorAttribute).Name)));
}
}
}

This led me to this section of code where the OperationContext.Current value is assigned.

internal bool Process(bool isOperationContextSet)
{
using (ServiceModelActivity.BoundOperation(Activity))
{
bool completed = true;
if (NextProcessor != null)
{
MessageRpcProcessor processor = NextProcessor;
NextProcessor = null;
OperationContext originalContext;
if (!isOperationContextSet)
{
originalContext = OperationContext.Current;
}
else
{
originalContext = null;
}
IncrementBusyCount();
try
{
if (!isOperationContextSet)
{
OperationContext.Current = OperationContext;
}
processor(ref this);
if (!IsPaused)
{
OperationContext.SetClientReply(null, false);
}
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
if (!ProcessError(e) && FaultInfo.Fault == null)
{
Abort();
}
}
finally
{
try
{
DecrementBusyCount();
if (!isOperationContextSet)
{
OperationContext.Current = originalContext;
}
completed = !IsPaused;
if (completed)
{
channelHandler.DispatchDone();
OperationContext.ClearClientReplyNoThrow();
}
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(e.Message, e);
}
}
}
return completed;
}
}

I noticed that the Framework code uses OperationContext.Holder instead of OperationContext.Current

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions