/// </summary>
internal sealed class DiagnosticsHandler : DelegatingHandler
{
- private const string Namespace = "System.Net.Http";
- private const string RequestWriteNameDeprecated = Namespace + ".Request";
- private const string ResponseWriteNameDeprecated = Namespace + ".Response";
- private const string ExceptionEventName = Namespace + ".Exception";
- private const string ActivityName = Namespace + ".HttpRequestOut";
- private const string ActivityStartName = ActivityName + ".Start";
- private const string ActivityStopName = ActivityName + ".Stop";
-
- private static readonly DiagnosticListener s_diagnosticListener = new("HttpHandlerDiagnosticListener");
- private static readonly ActivitySource s_activitySource = new(Namespace);
-
- public static bool IsGloballyEnabled { get; } = GetEnableActivityPropagationValue();
-
- private static bool GetEnableActivityPropagationValue()
+ /// <summary>
+ /// DiagnosticHandler constructor
+ /// </summary>
+ /// <param name="innerHandler">Inner handler: Windows or Unix implementation of HttpMessageHandler.
+ /// Note that DiagnosticHandler is the latest in the pipeline </param>
+ public DiagnosticsHandler(HttpMessageHandler innerHandler) : base(innerHandler)
{
- // First check for the AppContext switch, giving it priority over the environment variable.
- if (AppContext.TryGetSwitch(Namespace + ".EnableActivityPropagation", out bool enableActivityPropagation))
- {
- return enableActivityPropagation;
- }
-
- // AppContext switch wasn't used. Check the environment variable to determine which handler should be used.
- string? envVar = Environment.GetEnvironmentVariable("DOTNET_SYSTEM_NET_HTTP_ENABLEACTIVITYPROPAGATION");
- if (envVar != null && (envVar.Equals("false", StringComparison.OrdinalIgnoreCase) || envVar.Equals("0")))
- {
- // Suppress Activity propagation.
- return false;
- }
+ }
- // Defaults to enabling Activity propagation.
- return true;
+ internal static bool IsEnabled()
+ {
+ // check if there is a parent Activity (and propagation is not suppressed)
+ // or if someone listens to HttpHandlerDiagnosticListener
+ return IsGloballyEnabled() && (Activity.Current != null || Settings.s_diagnosticListener.IsEnabled());
}
- public DiagnosticsHandler(HttpMessageHandler innerHandler) : base(innerHandler)
+ internal static bool IsGloballyEnabled()
{
- Debug.Assert(IsGloballyEnabled);
+ return Settings.s_activityPropagationEnabled;
}
- private static bool ShouldLogDiagnostics(HttpRequestMessage request, out Activity? activity)
+ // SendAsyncCore returns already completed ValueTask for when async: false is passed.
+ // Internally, it calls the synchronous Send method of the base class.
+ protected internal override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken) =>
+ SendAsyncCore(request, async: false, cancellationToken).AsTask().GetAwaiter().GetResult();
+
+ protected internal override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) =>
+ SendAsyncCore(request, async: true, cancellationToken).AsTask();
+
+ private async ValueTask<HttpResponseMessage> SendAsyncCore(HttpRequestMessage request, bool async,
+ CancellationToken cancellationToken)
{
- if (request is null)
+ // HttpClientHandler is responsible to call static DiagnosticsHandler.IsEnabled() before forwarding request here.
+ // It will check if propagation is on (because parent Activity exists or there is a listener) or off (forcibly disabled)
+ // This code won't be called unless consumer unsubscribes from DiagnosticListener right after the check.
+ // So some requests happening right after subscription starts might not be instrumented. Similarly,
+ // when consumer unsubscribes, extra requests might be instrumented
+
+ if (request == null)
{
throw new ArgumentNullException(nameof(request), SR.net_http_handler_norequest);
}
- activity = null;
-
- if (s_activitySource.HasListeners())
- {
- activity = s_activitySource.CreateActivity(ActivityName, ActivityKind.Client);
- }
+ Activity? activity = null;
+ DiagnosticListener diagnosticListener = Settings.s_diagnosticListener;
- if (activity is null)
+ // if there is no listener, but propagation is enabled (with previous IsEnabled() check)
+ // do not write any events just start/stop Activity and propagate Ids
+ if (!diagnosticListener.IsEnabled())
{
- bool diagnosticListenerEnabled = s_diagnosticListener.IsEnabled();
+ activity = new Activity(DiagnosticsHandlerLoggingStrings.ActivityName);
+ activity.Start();
+ InjectHeaders(activity, request);
- if (Activity.Current is not null || (diagnosticListenerEnabled && s_diagnosticListener.IsEnabled(ActivityName, request)))
+ try
{
- // If a diagnostics listener is enabled for the Activity, always create one
- activity = new Activity(ActivityName);
+ return async ?
+ await base.SendAsync(request, cancellationToken).ConfigureAwait(false) :
+ base.Send(request, cancellationToken);
}
- else
+ finally
{
- // There is no Activity, but we may still want to use the instrumented SendAsyncCore if diagnostic listeners are interested in other events
- return diagnosticListenerEnabled;
+ activity.Stop();
}
}
- activity.Start();
+ Guid loggingRequestId = Guid.Empty;
- if (s_diagnosticListener.IsEnabled(ActivityStartName))
+ // There is a listener. Check if listener wants to be notified about HttpClient Activities
+ if (diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.ActivityName, request))
{
- Write(ActivityStartName, new ActivityStartData(request));
- }
+ activity = new Activity(DiagnosticsHandlerLoggingStrings.ActivityName);
- InjectHeaders(activity, request);
-
- return true;
- }
-
- protected internal override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)
- {
- if (ShouldLogDiagnostics(request, out Activity? activity))
- {
- ValueTask<HttpResponseMessage> sendTask = SendAsyncCore(request, activity, async: false, cancellationToken);
- return sendTask.IsCompleted ?
- sendTask.Result :
- sendTask.AsTask().GetAwaiter().GetResult();
+ // Only send start event to users who subscribed for it, but start activity anyway
+ if (diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.ActivityStartName))
+ {
+ StartActivity(diagnosticListener, activity, new ActivityStartData(request));
+ }
+ else
+ {
+ activity.Start();
+ }
}
- else
+ // try to write System.Net.Http.Request event (deprecated)
+ if (diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.RequestWriteNameDeprecated))
{
- return base.Send(request, cancellationToken);
+ long timestamp = Stopwatch.GetTimestamp();
+ loggingRequestId = Guid.NewGuid();
+ Write(diagnosticListener, DiagnosticsHandlerLoggingStrings.RequestWriteNameDeprecated,
+ new RequestData(request, loggingRequestId, timestamp));
}
- }
- protected internal override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
- {
- if (ShouldLogDiagnostics(request, out Activity? activity))
- {
- return SendAsyncCore(request, activity, async: true, cancellationToken).AsTask();
- }
- else
+ // If we are on at all, we propagate current activity information
+ Activity? currentActivity = Activity.Current;
+ if (currentActivity != null)
{
- return base.SendAsync(request, cancellationToken);
- }
- }
-
- private async ValueTask<HttpResponseMessage> SendAsyncCore(HttpRequestMessage request, Activity? activity, bool async, CancellationToken cancellationToken)
- {
- Guid loggingRequestId = default;
-
- if (s_diagnosticListener.IsEnabled(RequestWriteNameDeprecated))
- {
- loggingRequestId = Guid.NewGuid();
- Write(RequestWriteNameDeprecated, new RequestData(request, loggingRequestId, Stopwatch.GetTimestamp()));
+ InjectHeaders(currentActivity, request);
}
HttpResponseMessage? response = null;
catch (OperationCanceledException)
{
taskStatus = TaskStatus.Canceled;
+
+ // we'll report task status in HttpRequestOut.Stop
throw;
}
catch (Exception ex)
{
- if (s_diagnosticListener.IsEnabled(ExceptionEventName))
+ taskStatus = TaskStatus.Faulted;
+
+ if (diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.ExceptionEventName))
{
- Write(ExceptionEventName, new ExceptionData(ex, request));
+ // If request was initially instrumented, Activity.Current has all necessary context for logging
+ // Request is passed to provide some context if instrumentation was disabled and to avoid
+ // extensive Activity.Tags usage to tunnel request properties
+ Write(diagnosticListener, DiagnosticsHandlerLoggingStrings.ExceptionEventName, new ExceptionData(ex, request));
}
-
- taskStatus = TaskStatus.Faulted;
throw;
}
finally
{
- if (activity is not null)
+ // always stop activity if it was started
+ if (activity != null)
{
- activity.SetEndTime(DateTime.UtcNow);
-
- if (s_diagnosticListener.IsEnabled(ActivityStopName))
- {
- Write(ActivityStopName, new ActivityStopData(response, request, taskStatus));
- }
-
- activity.Stop();
+ StopActivity(diagnosticListener, activity, new ActivityStopData(
+ response,
+ // If request is failed or cancelled, there is no response, therefore no information about request;
+ // pass the request in the payload, so consumers can have it in Stop for failed/canceled requests
+ // and not retain all requests in Start
+ request,
+ taskStatus));
}
-
- if (s_diagnosticListener.IsEnabled(ResponseWriteNameDeprecated))
+ // Try to write System.Net.Http.Response event (deprecated)
+ if (diagnosticListener.IsEnabled(DiagnosticsHandlerLoggingStrings.ResponseWriteNameDeprecated))
{
- Write(ResponseWriteNameDeprecated, new ResponseData(response, loggingRequestId, Stopwatch.GetTimestamp(), taskStatus));
+ long timestamp = Stopwatch.GetTimestamp();
+ Write(diagnosticListener, DiagnosticsHandlerLoggingStrings.ResponseWriteNameDeprecated,
+ new ResponseData(
+ response,
+ loggingRequestId,
+ timestamp,
+ taskStatus));
}
}
}
+ #region private
+
private sealed class ActivityStartData
{
// matches the properties selected in https://github.com/dotnet/diagnostics/blob/ffd0254da3bcc47847b1183fa5453c0877020abd/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/HttpRequestSourceConfiguration.cs#L36-L40
public override string ToString() => $"{{ {nameof(Response)} = {Response}, {nameof(LoggingRequestId)} = {LoggingRequestId}, {nameof(Timestamp)} = {Timestamp}, {nameof(RequestTaskStatus)} = {RequestTaskStatus} }}";
}
- private static void InjectHeaders(Activity currentActivity, HttpRequestMessage request)
+ private static class Settings
{
- const string TraceParentHeaderName = "traceparent";
- const string TraceStateHeaderName = "tracestate";
- const string RequestIdHeaderName = "Request-Id";
- const string CorrelationContextHeaderName = "Correlation-Context";
+ private const string EnableActivityPropagationEnvironmentVariableSettingName = "DOTNET_SYSTEM_NET_HTTP_ENABLEACTIVITYPROPAGATION";
+ private const string EnableActivityPropagationAppCtxSettingName = "System.Net.Http.EnableActivityPropagation";
+
+ public static readonly bool s_activityPropagationEnabled = GetEnableActivityPropagationValue();
+
+ private static bool GetEnableActivityPropagationValue()
+ {
+ // First check for the AppContext switch, giving it priority over the environment variable.
+ if (AppContext.TryGetSwitch(EnableActivityPropagationAppCtxSettingName, out bool enableActivityPropagation))
+ {
+ return enableActivityPropagation;
+ }
+
+ // AppContext switch wasn't used. Check the environment variable to determine which handler should be used.
+ string? envVar = Environment.GetEnvironmentVariable(EnableActivityPropagationEnvironmentVariableSettingName);
+ if (envVar != null && (envVar.Equals("false", StringComparison.OrdinalIgnoreCase) || envVar.Equals("0")))
+ {
+ // Suppress Activity propagation.
+ return false;
+ }
+ // Defaults to enabling Activity propagation.
+ return true;
+ }
+
+ public static readonly DiagnosticListener s_diagnosticListener =
+ new DiagnosticListener(DiagnosticsHandlerLoggingStrings.DiagnosticListenerName);
+ }
+
+ private static void InjectHeaders(Activity currentActivity, HttpRequestMessage request)
+ {
if (currentActivity.IdFormat == ActivityIdFormat.W3C)
{
- if (!request.Headers.Contains(TraceParentHeaderName))
+ if (!request.Headers.Contains(DiagnosticsHandlerLoggingStrings.TraceParentHeaderName))
{
- request.Headers.TryAddWithoutValidation(TraceParentHeaderName, currentActivity.Id);
+ request.Headers.TryAddWithoutValidation(DiagnosticsHandlerLoggingStrings.TraceParentHeaderName, currentActivity.Id);
if (currentActivity.TraceStateString != null)
{
- request.Headers.TryAddWithoutValidation(TraceStateHeaderName, currentActivity.TraceStateString);
+ request.Headers.TryAddWithoutValidation(DiagnosticsHandlerLoggingStrings.TraceStateHeaderName, currentActivity.TraceStateString);
}
}
}
else
{
- if (!request.Headers.Contains(RequestIdHeaderName))
+ if (!request.Headers.Contains(DiagnosticsHandlerLoggingStrings.RequestIdHeaderName))
{
- request.Headers.TryAddWithoutValidation(RequestIdHeaderName, currentActivity.Id);
+ request.Headers.TryAddWithoutValidation(DiagnosticsHandlerLoggingStrings.RequestIdHeaderName, currentActivity.Id);
}
}
baggage.Add(new NameValueHeaderValue(WebUtility.UrlEncode(item.Key), WebUtility.UrlEncode(item.Value)).ToString());
}
while (e.MoveNext());
- request.Headers.TryAddWithoutValidation(CorrelationContextHeaderName, baggage);
+ request.Headers.TryAddWithoutValidation(DiagnosticsHandlerLoggingStrings.CorrelationContextHeaderName, baggage);
}
}
}
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern",
Justification = "The values being passed into Write have the commonly used properties being preserved with DynamicDependency.")]
- private static void Write<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(string name, T value)
+ private static void Write<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(
+ DiagnosticSource diagnosticSource,
+ string name,
+ T value)
+ {
+ diagnosticSource.Write(name, value);
+ }
+
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern",
+ Justification = "The args being passed into StartActivity have the commonly used properties being preserved with DynamicDependency.")]
+ private static Activity StartActivity<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(
+ DiagnosticSource diagnosticSource,
+ Activity activity,
+ T? args)
{
- s_diagnosticListener.Write(name, value);
+ return diagnosticSource.StartActivity(activity, args);
}
+
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:UnrecognizedReflectionPattern",
+ Justification = "The args being passed into StopActivity have the commonly used properties being preserved with DynamicDependency.")]
+ private static void StopActivity<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(
+ DiagnosticSource diagnosticSource,
+ Activity activity,
+ T? args)
+ {
+ diagnosticSource.StopActivity(activity, args);
+ }
+
+ #endregion
}
}
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Tracing;
-using System.IO;
using System.Linq;
using System.Net.Http.Headers;
using System.Net.Test.Common;
GetProperty<HttpRequestMessage>(kvp.Value, "Request");
TaskStatus status = GetProperty<TaskStatus>(kvp.Value, "RequestTaskStatus");
Assert.Equal(TaskStatus.Canceled, status);
- activityStopTcs.SetResult();
+ activityStopTcs.SetResult();;
}
});
activityStopResponseLogged = GetProperty<HttpResponseMessage>(kvp.Value, "Response");
TaskStatus requestStatus = GetProperty<TaskStatus>(kvp.Value, "RequestTaskStatus");
Assert.Equal(TaskStatus.RanToCompletion, requestStatus);
- activityStopTcs.SetResult();
+ activityStopTcs.SetResult();;
}
});
Assert.Contains("goodkey=bad%2Fvalue", correlationContext);
TaskStatus requestStatus = GetProperty<TaskStatus>(kvp.Value, "RequestTaskStatus");
Assert.Equal(TaskStatus.RanToCompletion, requestStatus);
- activityStopTcs.SetResult();
+ activityStopTcs.SetResult();;
}
else if (kvp.Key.Equals("System.Net.Http.Exception"))
{
Assert.False(request.Headers.TryGetValues("traceparent", out var _));
Assert.False(request.Headers.TryGetValues("tracestate", out var _));
- activityStopTcs.SetResult();
+ activityStopTcs.SetResult();;
}
});
}
else if (kvp.Key.Equals("System.Net.Http.HttpRequestOut.Stop"))
{
- activityStopTcs.SetResult();
+ activityStopTcs.SetResult();;
}
});
GetProperty<HttpRequestMessage>(kvp.Value, "Request");
TaskStatus requestStatus = GetProperty<TaskStatus>(kvp.Value, "RequestTaskStatus");
Assert.Equal(TaskStatus.Faulted, requestStatus);
- activityStopTcs.SetResult();
+ activityStopTcs.SetResult();;
}
else if (kvp.Key.Equals("System.Net.Http.Exception"))
{
GetProperty<HttpRequestMessage>(kvp.Value, "Request");
TaskStatus requestStatus = GetProperty<TaskStatus>(kvp.Value, "RequestTaskStatus");
Assert.Equal(TaskStatus.Faulted, requestStatus);
- activityStopTcs.SetResult();
+ activityStopTcs.SetResult();;
}
else if (kvp.Key.Equals("System.Net.Http.Exception"))
{
}, UseVersion.ToString(), TestAsync.ToString()).Dispose();
}
+ [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+ public void SendAsync_ExpectedActivityPropagationWithoutListener()
+ {
+ RemoteExecutor.Invoke(async (useVersion, testAsync) =>
+ {
+ Activity parent = new Activity("parent").Start();
+
+ await GetFactoryForVersion(useVersion).CreateClientAndServerAsync(
+ async uri =>
+ {
+ await GetAsync(useVersion, testAsync, uri);
+ },
+ async server =>
+ {
+ HttpRequestData requestData = await server.AcceptConnectionSendResponseAndCloseAsync();
+ AssertHeadersAreInjected(requestData, parent);
+ });
+ }, UseVersion.ToString(), TestAsync.ToString()).Dispose();
+ }
+
+ [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+ public void SendAsync_ExpectedActivityPropagationWithoutListenerOrParentActivity()
+ {
+ RemoteExecutor.Invoke(async (useVersion, testAsync) =>
+ {
+ await GetFactoryForVersion(useVersion).CreateClientAndServerAsync(
+ async uri =>
+ {
+ await GetAsync(useVersion, testAsync, uri);
+ },
+ async server =>
+ {
+ HttpRequestData requestData = await server.AcceptConnectionSendResponseAndCloseAsync();
+ AssertNoHeadersAreInjected(requestData);
+ });
+ }, UseVersion.ToString(), TestAsync.ToString()).Dispose();
+ }
+
[ConditionalTheory(nameof(EnableActivityPropagationEnvironmentVariableIsNotSetAndRemoteExecutorSupported))]
[InlineData("true")]
[InlineData("1")]
}, UseVersion.ToString(), TestAsync.ToString(), switchValue.ToString()).Dispose();
}
- [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
- [InlineData(true, true, true)] // Activity was set and ActivitySource created an Activity
- [InlineData(true, false, true)] // Activity was set and ActivitySource created an Activity
- [InlineData(true, null, true)] // Activity was set and ActivitySource created an Activity
- [InlineData(true, true, false)] // Activity was set, ActivitySource chose not to create an Activity, so one was manually created
- [InlineData(true, false, false)] // Activity was set, ActivitySource chose not to create an Activity, so one was manually created
- [InlineData(true, null, false)] // Activity was set, ActivitySource chose not to create an Activity, so one was manually created
- [InlineData(true, true, null)] // Activity was set, ActivitySource had no listeners, so an Activity was manually created
- [InlineData(true, false, null)] // Activity was set, ActivitySource had no listeners, so an Activity was manually created
- [InlineData(true, null, null)] // Activity was set, ActivitySource had no listeners, so an Activity was manually created
- [InlineData(false, true, true)] // DiagnosticListener requested an Activity and ActivitySource created an Activity
- [InlineData(false, true, false)] // DiagnosticListener requested an Activity, ActivitySource chose not to create an Activity, so one was manually created
- [InlineData(false, true, null)] // DiagnosticListener requested an Activity, ActivitySource had no listeners, so an Activity was manually created
- [InlineData(false, false, true)] // No Activity is set, DiagnosticListener does not want one, but ActivitySource created an Activity
- [InlineData(false, false, false)] // No Activity is set, DiagnosticListener does not want one and ActivitySource chose not to create an Activity
- [InlineData(false, false, null)] // No Activity is set, DiagnosticListener does not want one and ActivitySource has no listeners
- [InlineData(false, null, true)] // No Activity is set, there is no DiagnosticListener, but ActivitySource created an Activity
- [InlineData(false, null, false)] // No Activity is set, there is no DiagnosticListener and ActivitySource chose not to create an Activity
- [InlineData(false, null, null)] // No Activity is set, there is no DiagnosticListener and ActivitySource has no listeners
- public void SendAsync_ActivityIsCreatedIfRequested(bool currentActivitySet, bool? diagnosticListenerActivityEnabled, bool? activitySourceCreatesActivity)
- {
- string parameters = $"{currentActivitySet},{diagnosticListenerActivityEnabled},{activitySourceCreatesActivity}";
-
- RemoteExecutor.Invoke(async (useVersion, testAsync, parametersString) =>
- {
- bool?[] parameters = parametersString.Split(',').Select(p => p.Length == 0 ? (bool?)null : bool.Parse(p)).ToArray();
- bool currentActivitySet = parameters[0].Value;
- bool? diagnosticListenerActivityEnabled = parameters[1];
- bool? activitySourceCreatesActivity = parameters[2];
-
- bool madeASamplingDecision = false;
- if (activitySourceCreatesActivity.HasValue)
- {
- ActivitySource.AddActivityListener(new ActivityListener
- {
- ShouldListenTo = _ => true,
- Sample = (ref ActivityCreationOptions<ActivityContext> _) =>
- {
- madeASamplingDecision = true;
- return activitySourceCreatesActivity.Value ? ActivitySamplingResult.AllData : ActivitySamplingResult.None;
- }
- });
- }
-
- bool listenerCallbackWasCalled = false;
- IDisposable listenerSubscription = new MemoryStream(); // Dummy disposable
- if (diagnosticListenerActivityEnabled.HasValue)
- {
- var diagnosticListenerObserver = new FakeDiagnosticListenerObserver(_ => listenerCallbackWasCalled = true);
-
- diagnosticListenerObserver.Enable(name => !name.Contains("HttpRequestOut") || diagnosticListenerActivityEnabled.Value);
-
- listenerSubscription = DiagnosticListener.AllListeners.Subscribe(diagnosticListenerObserver);
- }
-
- Activity activity = currentActivitySet ? new Activity("parent").Start() : null;
-
- if (!currentActivitySet)
- {
- // Listen to new activity creations if an Activity was created without a parent
- // (when a DiagnosticListener forced one to be created)
- ActivitySource.AddActivityListener(new ActivityListener
- {
- ShouldListenTo = _ => true,
- ActivityStarted = created =>
- {
- Assert.Null(activity);
- activity = created;
- }
- });
- }
-
- using (listenerSubscription)
- {
- await GetFactoryForVersion(useVersion).CreateClientAndServerAsync(
- async uri =>
- {
- await GetAsync(useVersion, testAsync, uri);
- },
- async server =>
- {
- HttpRequestData requestData = await server.AcceptConnectionSendResponseAndCloseAsync();
-
- if (currentActivitySet || diagnosticListenerActivityEnabled == true || activitySourceCreatesActivity == true)
- {
- Assert.NotNull(activity);
- AssertHeadersAreInjected(requestData, activity);
- }
- else
- {
- AssertNoHeadersAreInjected(requestData);
-
- if (!currentActivitySet)
- {
- Assert.Null(activity);
- }
- }
- });
- }
-
- Assert.Equal(activitySourceCreatesActivity.HasValue, madeASamplingDecision);
- Assert.Equal(diagnosticListenerActivityEnabled.HasValue, listenerCallbackWasCalled);
- }, UseVersion.ToString(), TestAsync.ToString(), parameters).Dispose();
- }
-
private static T GetProperty<T>(object obj, string propertyName)
{
Type t = obj.GetType();