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.
+
+
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.
+
+
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.
+
+
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.
+
+
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.
+
+
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.
+
+
フォーマッタ {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.
+
+
{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.
+
+
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.
+
+
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.
+
+
Модуль форматирования {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.
+
+
{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.
+
+
格式化程序 {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.
+
+
格式器 {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))]