Skip to content

Adding Request-Id header breaks distributed tracing on .NET Full Framework #87827

@Mpdreamz

Description

@Mpdreamz

Description

Manually adding Request-Id header to HttpRequest will prevent System.Net.Http.Desktop.HttpRequestOut.Start from firing.

This is due to HttpHandlerDiagnosticListener assuming it already instrumented the request:

e.g:

using (var activity = activitySource.StartActivity("first request", ActivityKind.Client))
{
    //Request with Request-Id header
    var request = new HttpRequestMessage(HttpMethod.Get, "/"); 
    request.Headers.Add("Request-Id", "Hello");
    var response = httpClient.SendAsync(request).Result;
    response.EnsureSuccessStatusCode();
    var res = response.Content.ReadAsStringAsync().Result;
    Console.WriteLine(res);
}

Will only fire System.Net.Http.Desktop.HttpRequestOut.Stop and the server will only see the following request headers:

Connection: keep-alive
Host: localhost:5000
Request-Id: Hello

However the following code:

using (var activity2 = activitySource.StartActivity("second request", ActivityKind.Client))
{
    //Request without Request-Id header
    var request = new HttpRequestMessage(HttpMethod.Get, "/"); 
    var response = httpClient.SendAsync(request).Result;
    response.EnsureSuccessStatusCode();
    var res = response.Content.ReadAsStringAsync().Result;
    Console.WriteLine(res);
}

Will successfully fire both

  • System.Net.Http.Desktop.HttpRequestOut.Start
  • System.Net.Http.Desktop.HttpRequestOut.Stop

And attach a traceparent header to the outgoing request.

Host: localhost:5000
traceparent: 00-2a1efd927b6a7c41a68d46b1d001a497-da1ea5a70f00654a-00

Reproduction Steps

https://github.com/Mpdreamz/desktop-http-reproduction

Has a minimal reproduction. Simply start the Server project then run the Client project.

The client project will echo back the request headers the server recieved and echo the Diagnostics events

only works on windows, on mono HttpHandlerDiagnosticListener fails hard trying to reflect over HttpClient. Unrelated to this issue though.

System.Net.Http.InitializationFailed
{ Exception = System.InvalidOperationException: Unable to initialize all required reflection objects
  at System.Diagnostics.HttpHandlerDiagnosticListener.PrepareReflectionObjects () [0x0017d] in <1205d6ca21924e09ba81bcedb8730167>:0 
  at System.Diagnostics.HttpHandlerDiagnosticListener.Initialize () [0x0001b] in <1205d6ca21924e09ba81bcedb8730167>:0  }

Expected behavior

System.Net.Http.Desktop.HttpRequestOut.Start should always fire and traceparent should always be added if there is a diagnostics listener.

Actual behavior

Regression?

Only happens on .NET FullFramework.

Known Workarounds

None

Configuration

No response

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions