diff --git a/src/System.Private.ServiceModel/src/Internals/WcfEventSource.cs b/src/System.Private.ServiceModel/src/Internals/WcfEventSource.cs index c87ff2c83bc0..842ff2fac6aa 100644 --- a/src/System.Private.ServiceModel/src/Internals/WcfEventSource.cs +++ b/src/System.Private.ServiceModel/src/Internals/WcfEventSource.cs @@ -221,6 +221,46 @@ public void FaultProviderInvoked(string TypeName, string ExceptionTypeName) FaultProviderInvoked(TypeName, ExceptionTypeName, "", ""); } + public bool MessageInspectorAfterReceiveInvokedIsEnabled() + { + return base.IsEnabled(EventLevel.Informational, Keywords.Troubleshooting | Keywords.ServiceModel, EventChannel.Analytic); + } + + [Event(EventIds.MessageInspectorAfterReceiveInvoked, Level = EventLevel.Informational, Channel = EventChannel.Analytic, Opcode = Opcodes.DispatchMessageDispathMessageInspectorAfterReceiveInvoked, Task = Tasks.DispatchMessage, + Keywords = Keywords.Troubleshooting | Keywords.ServiceModel, + Message = "The Dispatcher invoked 'AfterReceiveReply' on a MessageInspector of type '{0}'.")] + public void MessageInspectorAfterReceiveInvoked(string TypeName, string HostReference, string AppDomain) + { + WriteEvent(EventIds.MessageInspectorAfterReceiveInvoked, TypeName, HostReference, AppDomain); + } + + [NonEvent] + public void MessageInspectorAfterReceiveInvoked(EventTraceActivity eventTraceActivity, string TypeName) + { + SetActivityId(eventTraceActivity); + MessageInspectorAfterReceiveInvoked(TypeName, "", ""); + } + + public bool MessageInspectorBeforeSendInvokedIsEnabled() + { + return base.IsEnabled(EventLevel.Informational, Keywords.Troubleshooting | Keywords.ServiceModel, EventChannel.Analytic); + } + + [Event(EventIds.MessageInspectorBeforeSendInvoked, Level = EventLevel.Informational, Channel = EventChannel.Analytic, Opcode = Opcodes.DispatchMessageDispathMessageInspectorBeforeSendInvoked, Task = Tasks.DispatchMessage, + Keywords = Keywords.Troubleshooting | Keywords.ServiceModel, + Message = "The Dispatcher invoked 'BeforeSendRequest' on a MessageInspector of type '{0}'.")] + public void MessageInspectorBeforeSendInvoked(string TypeName, string HostReference, string AppDomain) + { + WriteEvent(EventIds.MessageInspectorBeforeSendInvoked, TypeName, HostReference, AppDomain); + } + + [NonEvent] + public void MessageInspectorBeforeSendInvoked(EventTraceActivity eventTraceActivity, string TypeName) + { + SetActivityId(eventTraceActivity); + MessageInspectorBeforeSendInvoked(TypeName, "", ""); + } + public bool ParameterInspectorAfterCallInvokedIsEnabled() { return base.IsEnabled(EventLevel.Informational, Keywords.Troubleshooting | Keywords.ServiceModel, EventChannel.Analytic); diff --git a/src/System.Private.ServiceModel/src/Resources/Strings.resx b/src/System.Private.ServiceModel/src/Resources/Strings.resx index 108bab2b6add..646e389147be 100644 --- a/src/System.Private.ServiceModel/src/Resources/Strings.resx +++ b/src/System.Private.ServiceModel/src/Resources/Strings.resx @@ -2994,4 +2994,7 @@ This value cannot be changed after the first ClientBase of type '{0}' has been created. + + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + \ No newline at end of file diff --git a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.cs.xlf b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.cs.xlf index e87d7dfb64a9..292daa10d362 100644 --- a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.cs.xlf +++ b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.cs.xlf @@ -3217,6 +3217,11 @@ Hodnota NONE elementu WS-Addressing není platná pro verzi elementu WS-Addressing ze srpna 2004. + + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + + Formatter {0} returned a null reply message for call to operation '{1}'. Formátovací modul {0} vrátil zprávu odpovědi s hodnotou NULL pro volání do operace {1}. diff --git a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.de.xlf b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.de.xlf index b064aef18e29..90f24b70be89 100644 --- a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.de.xlf +++ b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.de.xlf @@ -3217,6 +3217,11 @@ Der Wert "none" der WS-Adressierung ist für die August 2004-Version der WS-Adressierung nicht gültig. + + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + + Formatter {0} returned a null reply message for call to operation '{1}'. Der Formatierer {0} hat eine leere Antwortnachricht für einen Aufruf des Vorgangs "{1}" zurückgegeben. diff --git a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.es.xlf b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.es.xlf index 1efdaf4fd127..ec9430ef6575 100644 --- a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.es.xlf +++ b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.es.xlf @@ -3217,6 +3217,11 @@ El valor "none" de WS-Addressing no es válido para la versión de agosto de 2004 de WS-Addressing. + + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + + Formatter {0} returned a null reply message for call to operation '{1}'. El formateador {0} devolvió un mensaje de respuesta nulo para la llamada a la operación "{1}". diff --git a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.fr.xlf b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.fr.xlf index 56f37bd2f053..21fea85b8138 100644 --- a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.fr.xlf +++ b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.fr.xlf @@ -3217,6 +3217,11 @@ La valeur 'none' de WS-Addressing n'est pas valide pour la version d'août 2004 de WS-Addressing. + + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + + Formatter {0} returned a null reply message for call to operation '{1}'. Le formateur {0} a retourné un message de réponse avec une valeur null pour l'appel à l'opération '{1}'. diff --git a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.it.xlf b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.it.xlf index 36baaf49e1b5..b27c769e0528 100644 --- a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.it.xlf +++ b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.it.xlf @@ -3217,6 +3217,11 @@ Valore WS-Addressing "none" non valido per la versione di agosto 2004 di WS-Addressing. + + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + + Formatter {0} returned a null reply message for call to operation '{1}'. Il formattatore {0} ha restituito un messaggio di risposta Null per la chiamata all'operazione '{1}'. diff --git a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.ja.xlf b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.ja.xlf index 044c2def3c1f..80a5263ceea3 100644 --- a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.ja.xlf +++ b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.ja.xlf @@ -3217,6 +3217,11 @@ WS-Addressing の値を "なし" にすることは、2004 年 8 月版の WS-Addressing では無効です。 + + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + + Formatter {0} returned a null reply message for call to operation '{1}'. フォーマッタ {0} が、操作 '{1}' への呼び出しに対して null の応答メッセージを返しました。 diff --git a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.ko.xlf b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.ko.xlf index 8537123e9be0..080c99788bd1 100644 --- a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.ko.xlf +++ b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.ko.xlf @@ -3217,6 +3217,11 @@ WS-Addressing "none" 값이 2004년 8월 버전의 WS-Addressing에 올바르지 않습니다. + + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + + Formatter {0} returned a null reply message for call to operation '{1}'. {0} 포맷터가 '{1}' 작업의 호출에 대해 null 회신 메시지를 반환했습니다. diff --git a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.pl.xlf b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.pl.xlf index 8817280ce9c9..bfb061309a37 100644 --- a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.pl.xlf +++ b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.pl.xlf @@ -3217,6 +3217,11 @@ Wartość WS-Addressing „none” jest nieprawidłowa dla wersji WS-Addressing z sierpnia 2004. + + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + + Formatter {0} returned a null reply message for call to operation '{1}'. Program formatujący {0} zwrócił komunikat odpowiedzi o wartości null dla wywołania operacji „{1}”. diff --git a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.pt-BR.xlf b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.pt-BR.xlf index 5b3d3d2dab33..663c529feb28 100644 --- a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.pt-BR.xlf +++ b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.pt-BR.xlf @@ -3217,6 +3217,11 @@ O valor "none" do WS-Addressing não é válido para a versão de agosto de 2004 do WS-Addressing. + + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + + Formatter {0} returned a null reply message for call to operation '{1}'. O formatador {0} retornou uma mensagem de resposta nula da chamada para a operação '{1}'. diff --git a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.ru.xlf b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.ru.xlf index 44b87072e7b6..9d498275b9db 100644 --- a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.ru.xlf +++ b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.ru.xlf @@ -3217,6 +3217,11 @@ Значение WS-Addressing "none" недопустимо для версии WS-Addressing августа 2004 г. + + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + + Formatter {0} returned a null reply message for call to operation '{1}'. Модуль форматирования {0} вернул нулевое ответное сообщение для вызова операции "{1}". diff --git a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.tr.xlf b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.tr.xlf index 0298a2d8728e..0b6fc4b19abb 100644 --- a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.tr.xlf +++ b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.tr.xlf @@ -3217,6 +3217,11 @@ WS-Addressing "none" değeri, WS-Addressing Ağustos 2004 sürümü için geçerli değil. + + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + + Formatter {0} returned a null reply message for call to operation '{1}'. {0} biçimlendiricisi '{1}' işlemi çağrısı için bir null yanıt iletisi döndürdü. diff --git a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.zh-Hans.xlf b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.zh-Hans.xlf index 0f23a9cf96b8..890fdf9f1d2d 100644 --- a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.zh-Hans.xlf @@ -3217,6 +3217,11 @@ WS-Addressing "none" 值对 2004 年 8 月版本的 WS-Addressing 无效。 + + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + + Formatter {0} returned a null reply message for call to operation '{1}'. 格式化程序 {0} 对操作“{1}”的调用返回了空回复消息。 diff --git a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.zh-Hant.xlf b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.zh-Hant.xlf index 35f2eab732bc..b2c72a6ba359 100644 --- a/src/System.Private.ServiceModel/src/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/System.Private.ServiceModel/src/Resources/xlf/Strings.zh-Hant.xlf @@ -3217,6 +3217,11 @@ WS-Addressing "none" 值對於 WS-Addressing August 2004 版本無效。 + + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + Extension {0} prevented call to operation '{1}' from replying by setting the reply to null. + + Formatter {0} returned a null reply message for call to operation '{1}'. 格式器 {0} 對作業 '{1}' 的呼叫,傳回了 null 的回覆訊息。 diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/DispatchRuntime.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/DispatchRuntime.cs index 5c121935e910..e744ee22967e 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/DispatchRuntime.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/DispatchRuntime.cs @@ -20,13 +20,13 @@ public sealed class DispatchRuntime private ChannelDispatcher _channelDispatcher; private IInstanceProvider _instanceProvider; private IInstanceContextProvider _instanceContextProvider; + private SynchronizedCollection _messageInspectors; private OperationCollection _operations; private ImmutableDispatchRuntime _runtime; private SynchronizationContext _synchronizationContext; private Type _type; private DispatchOperation _unhandled; private SharedRuntimeState _shared; - private SynchronizedCollection _messageInspectors; internal DispatchRuntime(ClientRuntime proxyRuntime, SharedRuntimeState shared) : this(shared) @@ -159,6 +159,11 @@ public IInstanceProvider InstanceProvider } } + public SynchronizedCollection MessageInspectors + { + get { return _messageInspectors; } + } + public SynchronizedKeyedCollection Operations { get { return _operations; } @@ -190,11 +195,6 @@ public Type Type } } - public SynchronizedCollection MessageInspectors - { - get { return _messageInspectors; } - } - public DispatchOperation UnhandledDispatchOperation { get { return _unhandled; } diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/ErrorBehavior.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/ErrorBehavior.cs index cd2ee3265d46..f2023e3127a0 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/ErrorBehavior.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/ErrorBehavior.cs @@ -223,6 +223,11 @@ internal bool HandleError(Exception error, ref ErrorHandlerFaultInfo faultInfo) return HandleErrorCommon(error, ref faultInfo); } + internal static bool ShouldRethrowExceptionAsIs(Exception e) + { + return true; + } + internal static bool ShouldRethrowClientSideExceptionAsIs(Exception e) { return true; diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/ImmutableDispatchRuntime.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/ImmutableDispatchRuntime.cs index 52b9f5fa7883..262988e0b6f1 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/ImmutableDispatchRuntime.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/ImmutableDispatchRuntime.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. - using System.Collections.Specialized; using System.Runtime; using System.Runtime.Diagnostics; @@ -13,10 +12,11 @@ namespace System.ServiceModel.Dispatcher { internal class ImmutableDispatchRuntime { - readonly private ConcurrencyBehavior _concurrency; - readonly private IDemuxer _demuxer; - readonly private ErrorBehavior _error; + private readonly ConcurrencyBehavior _concurrency; + private readonly IDemuxer _demuxer; + private readonly ErrorBehavior _error; private InstanceBehavior _instance; + private readonly IDispatchMessageInspector[] _messageInspectors; private readonly TerminatingOperationBehavior _terminate; private readonly ThreadBehavior _thread; private readonly bool _sendAsynchronously; @@ -45,6 +45,7 @@ internal ImmutableDispatchRuntime(DispatchRuntime dispatch) EnableFaults = dispatch.EnableFaults; _instance = new InstanceBehavior(dispatch, this); ManualAddressing = dispatch.ManualAddressing; + _messageInspectors = EmptyArray.ToArray(dispatch.MessageInspectors); _terminate = TerminatingOperationBehavior.CreateIfNecessary(dispatch); _thread = new ThreadBehavior(dispatch); _sendAsynchronously = dispatch.ChannelDispatcher.SendAsynchronously; @@ -87,9 +88,93 @@ internal ImmutableDispatchRuntime(DispatchRuntime dispatch) internal bool ValidateMustUnderstand { get; } + internal int MessageInspectorCorrelationOffset => 0; + internal void AfterReceiveRequest(ref MessageRpc rpc) { - // IDispatchMessageInspector would normally be called here. That interface isn't in contract. + if (_messageInspectors.Length > 0) + { + AfterReceiveRequestCore(ref rpc); + } + } + + internal void AfterReceiveRequestCore(ref MessageRpc rpc) + { + int offset = MessageInspectorCorrelationOffset; + try + { + for (int i = 0; i < _messageInspectors.Length; i++) + { + rpc.Correlation[offset + i] = _messageInspectors[i].AfterReceiveRequest(ref rpc.Request, (IClientChannel)rpc.Channel.Proxy, rpc.InstanceContext); + if (WcfEventSource.Instance.MessageInspectorAfterReceiveInvokedIsEnabled()) + { + WcfEventSource.Instance.MessageInspectorAfterReceiveInvoked(rpc.EventTraceActivity, _messageInspectors[i].GetType().FullName); + } + } + } + catch (Exception e) + { + if (Fx.IsFatal(e)) + { + throw; + } + if (ErrorBehavior.ShouldRethrowExceptionAsIs(e)) + { + throw; + } + throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e); + } + } + + void BeforeSendReply(ref MessageRpc rpc, ref Exception exception, ref bool thereIsAnUnhandledException) + { + if (_messageInspectors.Length > 0) + { + BeforeSendReplyCore(ref rpc, ref exception, ref thereIsAnUnhandledException); + } + } + + internal void BeforeSendReplyCore(ref MessageRpc rpc, ref Exception exception, ref bool thereIsAnUnhandledException) + { + int offset = MessageInspectorCorrelationOffset; + for (int i = 0; i < _messageInspectors.Length; i++) + { + try + { + Message originalReply = rpc.Reply; + Message reply = originalReply; + + _messageInspectors[i].BeforeSendReply(ref reply, rpc.Correlation[offset + i]); + if (WcfEventSource.Instance.MessageInspectorBeforeSendInvokedIsEnabled()) + { + WcfEventSource.Instance.MessageInspectorBeforeSendInvoked(rpc.EventTraceActivity, _messageInspectors[i].GetType().FullName); + } + + if ((reply == null) && (originalReply != null)) + { + string message = SR.Format(SR.SFxNullReplyFromExtension2, _messageInspectors[i].GetType().ToString(), (rpc.Operation.Name ?? "")); + ErrorBehavior.ThrowAndCatch(new InvalidOperationException(message)); + } + rpc.Reply = reply; + } + catch (Exception e) + { + if (Fx.IsFatal(e)) + { + throw; + } + if (!ErrorBehavior.ShouldRethrowExceptionAsIs(e)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e); + } + + if (exception == null) + { + exception = e; + } + thereIsAnUnhandledException = (!_error.HandleError(e)) || thereIsAnUnhandledException; + } + } } private void Reply(ref MessageRpc rpc) @@ -304,6 +389,8 @@ private void PrepareReply(ref MessageRpc rpc) } } + BeforeSendReply(ref rpc, ref exception, ref thereIsAnUnhandledException); + if (rpc.Operation.IsOneWay) { rpc.CanSendReply = false; diff --git a/src/System.ServiceModel.Duplex/ref/System.ServiceModel.Duplex.cs b/src/System.ServiceModel.Duplex/ref/System.ServiceModel.Duplex.cs index 513f8cc507e7..9fa20aff671e 100644 --- a/src/System.ServiceModel.Duplex/ref/System.ServiceModel.Duplex.cs +++ b/src/System.ServiceModel.Duplex/ref/System.ServiceModel.Duplex.cs @@ -5,6 +5,7 @@ // ------------------------------------------------------------------------------ +[assembly: TypeForwardedToAttribute(typeof(System.ServiceModel.InstanceContext))] namespace System.ServiceModel { [System.AttributeUsageAttribute((System.AttributeTargets)(4))]