Skip to content

Commit c975ecc

Browse files
authored
Fixing #1402 (#1898)
Fixing #1402 Enabling session tests Exposing OperationContext.GetCallbackChannel in the contract Addressing feedback about wrapping timer callback
1 parent f8bea43 commit c975ecc

File tree

17 files changed

+217
-5
lines changed

17 files changed

+217
-5
lines changed

src/System.Private.ServiceModel/src/Internals/System/Runtime/Fx.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,11 @@ public static AsyncCallback ThunkCallback(AsyncCallback callback)
288288
return (new AsyncThunk(callback)).ThunkFrame;
289289
}
290290

291+
public static Action<T1> ThunkCallback<T1>(Action<T1> callback)
292+
{
293+
return (new ActionThunk<T1>(callback)).ThunkFrame;
294+
}
295+
291296
[SuppressMessage(FxCop.Category.ReliabilityBasic, FxCop.Rule.UseNewGuidHelperRule,
292297
Justification = "These are the core methods that should be used for all other Guid(string) calls.")]
293298
public static Guid CreateGuid(string guidString)

src/System.Private.ServiceModel/src/Resources/Strings.resx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1950,4 +1950,10 @@
19501950
<data name="SFxInvalidSoapAttribute" xml:space="preserve">
19511951
<value>XmlSerializer attribute {0} is not valid in {1}. Only SoapElement attribute is supported.</value>
19521952
</data>
1953+
<data name="SFxTerminatingOperationAlreadyCalled1" xml:space="preserve">
1954+
<value>This channel cannot send any more messages because IsTerminating operation '{0}' has already been called. </value>
1955+
</data>
1956+
<data name="SFxChannelTerminated0" xml:space="preserve">
1957+
<value>An operation marked as IsTerminating has already been invoked on this channel, causing the channel's connection to terminate. No more operations may be invoked on this channel. Please re-create the channel to continue communication.</value>
1958+
</data>
19531959
</root>

src/System.Private.ServiceModel/src/System/ServiceModel/Channels/ServiceChannel.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ internal sealed class ServiceChannel : CommunicationObject, IChannel, IClientCha
4747
private readonly bool _openBinder = false;
4848
private TimeSpan _operationTimeout;
4949
private object _proxy;
50+
private string _terminatingOperationName;
5051
private bool _hasChannelStartedAutoClosing;
5152
private bool _hasCleanedUpChannelCollections;
5253
private EventTraceActivity _eventActivity;
@@ -566,6 +567,11 @@ private void PrepareCall(ProxyOperationRuntime operation, bool oneway, ref Proxy
566567
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.SFxNonInitiatingOperation1, operation.Name)));
567568
}
568569

570+
if (_terminatingOperationName != null)
571+
{
572+
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.SFxTerminatingOperationAlreadyCalled1, _terminatingOperationName)));
573+
}
574+
569575
if (_hasChannelStartedAutoClosing)
570576
{
571577
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(SR.SFxClientOutputSessionAutoClosed));
@@ -934,6 +940,7 @@ private void HandleReply(ProxyOperationRuntime operation, ref ProxyRpc rpc)
934940
operation.Name,
935941
rpc.Reply.Headers.Action,
936942
operation.ReplyAction));
943+
TerminateIfNecessary(ref rpc);
937944
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(error);
938945
}
939946
}
@@ -947,6 +954,7 @@ private void HandleReply(ProxyOperationRuntime operation, ref ProxyRpc rpc)
947954
}
948955
ThrowIfFaultUnderstood(rpc.Reply, fault, action, rpc.Reply.Version, rpc.Channel.GetProperty<FaultConverter>());
949956
FaultException fe = rpc.Operation.FaultFormatter.Deserialize(fault, action);
957+
TerminateIfNecessary(ref rpc);
950958
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(fe);
951959
}
952960

@@ -982,6 +990,7 @@ private void HandleReply(ProxyOperationRuntime operation, ref ProxyRpc rpc)
982990
}
983991
}
984992
}
993+
TerminateIfNecessary(ref rpc);
985994

986995
if (WcfEventSource.Instance.ServiceChannelCallStopIsEnabled())
987996
{
@@ -996,6 +1005,15 @@ private void HandleReply(ProxyOperationRuntime operation, ref ProxyRpc rpc)
9961005
}
9971006
}
9981007

1008+
private void TerminateIfNecessary(ref ProxyRpc rpc)
1009+
{
1010+
if (rpc.Operation.IsTerminating)
1011+
{
1012+
_terminatingOperationName = rpc.Operation.Name;
1013+
TerminatingOperationBehavior.AfterReply(ref rpc);
1014+
}
1015+
}
1016+
9991017
private void ThrowIfFaultUnderstood(Message reply, MessageFault fault, string action, MessageVersion version, FaultConverter faultConverter)
10001018
{
10011019
Exception exception;

src/System.Private.ServiceModel/src/System/ServiceModel/Description/ContractDescription.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ internal void EnsureInvariants()
228228
operationDescription.EnsureInvariants();
229229
if (operationDescription.IsInitiating)
230230
thereIsAtLeastOneInitiatingOperation = true;
231-
if ((!operationDescription.IsInitiating)
231+
if ((!operationDescription.IsInitiating || operationDescription.IsTerminating)
232232
&& (this.SessionMode != SessionMode.Required))
233233
{
234234
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(

src/System.Private.ServiceModel/src/System/ServiceModel/Description/DispatcherBuilder.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ private static void BuildProxyOperation(OperationDescription operation, ClientRu
134134
child.EndMethod = operation.EndMethod;
135135
child.IsOneWay = operation.IsOneWay;
136136
child.IsInitiating = operation.IsInitiating;
137+
child.IsTerminating = operation.IsTerminating;
137138
child.IsSessionOpenNotificationEnabled = operation.IsSessionOpenNotificationEnabled;
138139
for (int i = 0; i < operation.Faults.Count; i++)
139140
{
@@ -160,6 +161,7 @@ private static void BuildDispatchOperation(OperationDescription operation, Dispa
160161

161162
child.HasNoDisposableParameters = operation.HasNoDisposableParameters;
162163

164+
child.IsTerminating = operation.IsTerminating;
163165
child.IsSessionOpenNotificationEnabled = operation.IsSessionOpenNotificationEnabled;
164166
for (int i = 0; i < operation.Faults.Count; i++)
165167
{

src/System.Private.ServiceModel/src/System/ServiceModel/Description/OperationDescription.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@
1111

1212
namespace System.ServiceModel.Description
1313
{
14-
[DebuggerDisplay("Name={_name}, IsInitiating={_isInitiating}")]
14+
[DebuggerDisplay("Name={_name}, IsInitiating={_isInitiating}, IsTerminating={_isTerminating}")]
1515
public class OperationDescription
1616
{
1717
internal const string SessionOpenedAction = Channels.WebSocketTransportSettings.ConnectionOpenedAction;
1818

1919
private XmlName _name;
2020
private bool _isInitiating;
21+
private bool _isTerminating;
2122
private bool _isSessionOpenNotificationEnabled;
2223
private ContractDescription _declaringContract;
2324
private FaultDescriptionCollection _faults;
@@ -49,6 +50,7 @@ public OperationDescription(string name, ContractDescription declaringContract)
4950
}
5051
_declaringContract = declaringContract;
5152
_isInitiating = true;
53+
_isTerminating = false;
5254
_faults = new FaultDescriptionCollection();
5355
_messages = new MessageDescriptionCollection();
5456
_behaviors = new KeyedByTypeCollection<IOperationBehavior>();
@@ -164,6 +166,12 @@ internal bool IsServerInitiated()
164166
return Messages[0].Direction == MessageDirection.Output;
165167
}
166168

169+
public bool IsTerminating
170+
{
171+
get { return _isTerminating; }
172+
set { _isTerminating = value; }
173+
}
174+
167175
public Collection<Type> KnownTypes
168176
{
169177
get { return _knownTypes; }

src/System.Private.ServiceModel/src/System/ServiceModel/Description/TypeLoader.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,8 @@ private OperationDescription CreateOperationDescription(ContractDescription cont
954954

955955
OperationDescription operationDescription = new OperationDescription(operationName.EncodedName, declaringContract);
956956
operationDescription.IsInitiating = opAttr.IsInitiating;
957+
operationDescription.IsTerminating = opAttr.IsTerminating;
958+
957959
operationDescription.IsSessionOpenNotificationEnabled = opAttr.IsSessionOpenNotificationEnabled;
958960

959961
operationDescription.HasNoDisposableParameters = ServiceReflector.HasNoDisposableParameters(methodInfo);

src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/ChannelHandler.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ internal class ChannelHandler
4242
private bool _hasRegisterBeenCalled;
4343
private bool _hasSession;
4444
private int _isPumpAcquired;
45+
private bool _isChannelTerminated;
4546
private bool _isConcurrent;
4647
private bool _isManualAddressing;
4748
private MessageVersion _messageVersion;
@@ -279,6 +280,11 @@ private bool DispatchAndReleasePump(RequestContext request, bool cleanThread, Op
279280
MessageLogger.LogMessage(ref message, (operation.IsOneWay ? MessageLoggingSource.ServiceLevelReceiveDatagram : MessageLoggingSource.ServiceLevelReceiveRequest) | MessageLoggingSource.LastChance);
280281
}
281282

283+
if (operation.IsTerminating && _hasSession)
284+
{
285+
_isChannelTerminated = true;
286+
}
287+
282288
bool hasOperationContextBeenSet;
283289
if (currentOperationContext != null)
284290
{
@@ -694,6 +700,14 @@ private bool HandleRequest(RequestContext request, OperationContext currentOpera
694700
this.ReleasePump();
695701
return true;
696702
}
703+
704+
if (_isChannelTerminated)
705+
{
706+
ReleasePump();
707+
ReplyChannelTerminated(request);
708+
return true;
709+
}
710+
697711
if (_requestInfo.RequestContext != null)
698712
{
699713
Fx.Assert("ChannelHandler.HandleRequest: this.requestInfo.RequestContext != null");
@@ -851,6 +865,16 @@ private void ReplyContractFilterDidNotMatch(RequestContext request)
851865
}
852866
}
853867

868+
private void ReplyChannelTerminated(RequestContext request)
869+
{
870+
FaultCode code = FaultCode.CreateSenderFaultCode(FaultCodeConstants.Codes.SessionTerminated,
871+
FaultCodeConstants.Namespaces.NetDispatch);
872+
string reason = SR.Format(SR.SFxChannelTerminated0);
873+
string action = FaultCodeConstants.Actions.NetDispatcher;
874+
Message fault = Message.CreateMessage(_messageVersion, code, reason, action);
875+
ReplyFailure(request, fault, action, reason, code);
876+
}
877+
854878
private void ReplyFailure(RequestContext request, FaultCode code, string reason)
855879
{
856880
string action = _messageVersion.Addressing.DefaultFaultAction;

src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/ClientOperation.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public sealed class ClientOperation : ClientOperationCompatBase
3737
private IClientFaultFormatter _faultFormatter;
3838
private bool _isInitiating = true;
3939
private bool _isOneWay;
40+
private bool _isTerminating;
4041
private bool _isSessionOpenNotificationEnabled;
4142
private string _name;
4243

@@ -194,6 +195,19 @@ public bool IsOneWay
194195
}
195196
}
196197

198+
public bool IsTerminating
199+
{
200+
get { return _isTerminating; }
201+
set
202+
{
203+
lock (_parent.ThisLock)
204+
{
205+
_parent.InvalidateRuntime();
206+
_isTerminating = value;
207+
}
208+
}
209+
}
210+
197211
public string Name
198212
{
199213
get { return _name; }

src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/DispatchOperation.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public sealed class DispatchOperation
1414
private IDispatchMessageFormatter _formatter;
1515
private IDispatchFaultFormatter _faultFormatter;
1616
private IOperationInvoker _invoker;
17+
private bool _isTerminating;
1718
private bool _isSessionOpenNotificationEnabled;
1819
private readonly string _name;
1920
private readonly SynchronizedCollection<IParameterInspector> _parameterInspectors;
@@ -148,6 +149,19 @@ public IOperationInvoker Invoker
148149
}
149150
}
150151

152+
public bool IsTerminating
153+
{
154+
get { return _isTerminating; }
155+
set
156+
{
157+
lock (_parent.ThisLock)
158+
{
159+
_parent.InvalidateRuntime();
160+
_isTerminating = value;
161+
}
162+
}
163+
}
164+
151165
internal bool IsSessionOpenNotificationEnabled
152166
{
153167
get { return _isSessionOpenNotificationEnabled; }

0 commit comments

Comments
 (0)