diff --git a/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/TelemetryDispatchMessageInspectorForOneWayOperationsTests.netfx.cs b/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/TelemetryDispatchMessageInspectorForOneWayOperationsTests.netfx.cs
new file mode 100644
index 0000000000..868a5e86f7
--- /dev/null
+++ b/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/TelemetryDispatchMessageInspectorForOneWayOperationsTests.netfx.cs
@@ -0,0 +1,147 @@
+//
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#if NETFRAMEWORK
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.ServiceModel;
+using System.Threading;
+using OpenTelemetry.Contrib.Instrumentation.Wcf.Tests.Tools;
+using OpenTelemetry.Trace;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace OpenTelemetry.Contrib.Instrumentation.Wcf.Tests
+{
+ [Collection("WCF")]
+ public class TelemetryDispatchMessageInspectorForOneWayOperationsTests : IDisposable
+ {
+ private readonly ITestOutputHelper output;
+ private readonly Uri serviceBaseUri;
+ private readonly ServiceHost serviceHost;
+
+ private readonly EventWaitHandle thrownExceptionsHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
+ private readonly List thrownExceptions = new List();
+
+ public TelemetryDispatchMessageInspectorForOneWayOperationsTests(ITestOutputHelper outputHelper)
+ {
+ this.output = outputHelper;
+
+ Random random = new Random();
+ var retryCount = 5;
+ while (retryCount > 0)
+ {
+ try
+ {
+ this.serviceBaseUri = new Uri($"net.tcp://localhost:{random.Next(2000, 5000)}/");
+ this.serviceHost = new ServiceHost(new Service(), this.serviceBaseUri);
+
+ var endpoint = this.serviceHost.AddServiceEndpoint(
+ typeof(IServiceContract),
+ new NetTcpBinding(),
+ "/Service");
+ endpoint.Behaviors.Add(new TelemetryEndpointBehavior());
+
+ this.serviceHost.Description.Behaviors.Add(
+ new ErrorHandlerServiceBehavior(this.thrownExceptionsHandle, ex => this.thrownExceptions.Add(ex)));
+
+ this.serviceHost.Open();
+
+ break;
+ }
+ catch (Exception ex)
+ {
+ this.output.WriteLine(ex.ToString());
+ if (this.serviceHost.State == CommunicationState.Faulted)
+ {
+ this.serviceHost.Abort();
+ }
+ else
+ {
+ this.serviceHost.Close();
+ }
+
+ this.serviceHost = null;
+ retryCount--;
+ }
+ }
+
+ if (this.serviceHost == null)
+ {
+ throw new InvalidOperationException("ServiceHost could not be started.");
+ }
+ }
+
+ public void Dispose()
+ {
+ this.serviceHost?.Close();
+ this.thrownExceptionsHandle?.Dispose();
+ }
+
+ [Fact]
+ public void IncomingRequestOneWayOperationInstrumentationTest()
+ {
+ List stoppedActivities = new List();
+
+ using ActivityListener activityListener = new ActivityListener
+ {
+ ShouldListenTo = activitySource => true,
+ ActivityStopped = activity => stoppedActivities.Add(activity),
+ };
+
+ ActivitySource.AddActivityListener(activityListener);
+ TracerProvider tracerProvider = Sdk.CreateTracerProviderBuilder()
+ .AddWcfInstrumentation()
+ .Build();
+
+ ServiceClient client = new ServiceClient(
+ new NetTcpBinding(),
+ new EndpointAddress(new Uri(this.serviceBaseUri, "/Service")));
+
+ try
+ {
+ client.ExecuteWithOneWay(new ServiceRequest());
+ this.thrownExceptionsHandle.WaitOne(3000);
+ }
+ finally
+ {
+ if (client.State == CommunicationState.Faulted)
+ {
+ client.Abort();
+ }
+ else
+ {
+ client.Close();
+ }
+
+ tracerProvider?.Shutdown();
+ tracerProvider?.Dispose();
+
+ WcfInstrumentationActivitySource.Options = null;
+ }
+
+ // Assert
+ Assert.Empty(this.thrownExceptions);
+
+ Activity activity = stoppedActivities[0];
+ Assert.Equal("http://opentelemetry.io/Service/ExecuteWithOneWay", activity.DisplayName);
+ Assert.Equal("ExecuteWithOneWay", activity.TagObjects.FirstOrDefault(t => t.Key == WcfInstrumentationConstants.RpcMethodTag).Value);
+ Assert.DoesNotContain(activity.TagObjects, t => t.Key == WcfInstrumentationConstants.SoapReplyActionTag);
+ }
+ }
+}
+#endif
diff --git a/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/Tools/ErrorHandler.netfx.cs b/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/Tools/ErrorHandler.netfx.cs
new file mode 100644
index 0000000000..3e2a69e21e
--- /dev/null
+++ b/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/Tools/ErrorHandler.netfx.cs
@@ -0,0 +1,48 @@
+//
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#if NETFRAMEWORK
+using System;
+using System.ServiceModel.Channels;
+using System.ServiceModel.Dispatcher;
+using System.Threading;
+
+namespace OpenTelemetry.Contrib.Instrumentation.Wcf.Tests.Tools
+{
+ internal class ErrorHandler : IErrorHandler
+ {
+ private readonly EventWaitHandle handler;
+ private readonly Action log;
+
+ public ErrorHandler(EventWaitHandle handler, Action log)
+ {
+ this.handler = handler;
+ this.log = log;
+ }
+
+ public bool HandleError(Exception error)
+ {
+ this.log(error);
+ this.handler.Set();
+
+ return true;
+ }
+
+ public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
+ {
+ }
+ }
+}
+#endif
diff --git a/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/Tools/ErrorHandlerServiceBehavior.netfx.cs b/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/Tools/ErrorHandlerServiceBehavior.netfx.cs
new file mode 100644
index 0000000000..b32cc2b0e3
--- /dev/null
+++ b/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/Tools/ErrorHandlerServiceBehavior.netfx.cs
@@ -0,0 +1,55 @@
+//
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#if NETFRAMEWORK
+using System;
+using System.Collections.ObjectModel;
+using System.ServiceModel;
+using System.ServiceModel.Channels;
+using System.ServiceModel.Description;
+using System.ServiceModel.Dispatcher;
+using System.Threading;
+
+namespace OpenTelemetry.Contrib.Instrumentation.Wcf.Tests.Tools
+{
+ internal class ErrorHandlerServiceBehavior : IServiceBehavior
+ {
+ private readonly EventWaitHandle handler;
+ private readonly Action action;
+
+ public ErrorHandlerServiceBehavior(EventWaitHandle handler, Action action)
+ {
+ this.handler = handler;
+ this.action = action;
+ }
+
+ public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection endpoints, BindingParameterCollection bindingParameters)
+ {
+ }
+
+ public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
+ {
+ foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
+ {
+ dispatcher.ErrorHandlers.Add(new ErrorHandler(this.handler, this.action));
+ }
+ }
+
+ public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
+ {
+ }
+ }
+}
+#endif
diff --git a/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/WCF/IServiceContract.cs b/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/WCF/IServiceContract.cs
index d4358f2b6d..49746d2178 100644
--- a/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/WCF/IServiceContract.cs
+++ b/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/WCF/IServiceContract.cs
@@ -27,5 +27,8 @@ public interface IServiceContract
[OperationContract(Action = "")]
Task ExecuteWithEmptyActionNameAsync(ServiceRequest request);
+
+ [OperationContract(IsOneWay = true)]
+ void ExecuteWithOneWay(ServiceRequest request);
}
}
diff --git a/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/WCF/Service.netfx.cs b/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/WCF/Service.netfx.cs
index aa75e5e8bf..0f8aa6c9f5 100644
--- a/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/WCF/Service.netfx.cs
+++ b/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/WCF/Service.netfx.cs
@@ -44,6 +44,10 @@ public Task ExecuteWithEmptyActionNameAsync(ServiceRequest requ
Payload = $"RSP: {request.Payload}",
});
}
+
+ public void ExecuteWithOneWay(ServiceRequest request)
+ {
+ }
}
}
#endif
diff --git a/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/WCF/ServiceClient.cs b/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/WCF/ServiceClient.cs
index 98792bb3c1..a3af914511 100644
--- a/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/WCF/ServiceClient.cs
+++ b/test/OpenTelemetry.Contrib.Instrumentation.Wcf.Tests/WCF/ServiceClient.cs
@@ -32,5 +32,8 @@ public Task ExecuteAsync(ServiceRequest request)
public Task ExecuteWithEmptyActionNameAsync(ServiceRequest request)
=> this.Channel.ExecuteWithEmptyActionNameAsync(request);
+
+ public void ExecuteWithOneWay(ServiceRequest request)
+ => this.Channel.ExecuteWithOneWay(request);
}
}