<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/distributed-tracing-across-net-services-with-opentelemetry-w3c-trace-context-and-baggage-u8610tjrt" -->

---
title: Distributed Tracing Across .NET Services with...
description: A comprehensive guide to distributed tracing in .NET using OpenTelemetry. Covers the W3C Trace Context standard (traceparent and tracestate headers), automatic...
canonical: https://daily.dev/posts/distributed-tracing-across-net-services-with-opentelemetry-w3c-trace-context-and-baggage-u8610tjrt
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Distributed Tracing Across .NET Services with OpenTelemetry: W3C Trace Context and Baggage | daily.dev
og:description: A comprehensive guide to distributed tracing in .NET using OpenTelemetry. Covers the W3C Trace Context standard (traceparent and tracestate headers), automatic...
og:url: https://daily.dev/posts/distributed-tracing-across-net-services-with-opentelemetry-w3c-trace-context-and-baggage-u8610tjrt
og:image: https://api.daily.dev/og/posts/u8610tjrt.png
og:image:alt: Distributed Tracing Across .NET Services with OpenTelemetry: W3C Trace Context and Baggage
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Distributed Tracing Across .NET Services with OpenTelemetry: W3C Trace Context and Baggage

**[We Are .NET](https://daily.dev/sources/wearedotnet)** · 20 min read · 1 upvotes · 0 comments

## Summary

A comprehensive guide to distributed tracing in .NET using OpenTelemetry. Covers the W3C Trace Context standard (traceparent and tracestate headers), automatic propagation via HttpClient and ASP.NET Core instrumentation, Baggage for business metadata, manual propagation for message queues using DefaultTextMapPropagator, and why ParentBasedSampler is critical for consistent sampling across services. Also addresses common pitfalls like using new HttpClient() directly, losing Activity context across async boundaries, and putting sensitive data in Baggage. Includes C# code examples and testing strategies using MockDelegatingHandler and WebApplicationFactory.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.devleader.ca/2026/08/01/distributed-tracing-across-net-services-with-opentelemetry-w3c-trace-context-and-baggage>

## Questions this post answers

### What are the four fields in the W3C traceparent header used by OpenTelemetry?

The traceparent header has four hyphen-separated fields: version (always 00), trace ID (a 128-bit, 32 hex character identifier for the entire distributed trace), parent span ID (a 64-bit, 16 hex character identifier of the calling span), and trace flags (a single byte where 01 means sampled and 00 means not sampled).

_Developers wiring up cross-service tracing can dig deeper into traceparent mechanics on daily.dev._

### Why does my distributed trace break when I create HttpClient manually instead of using IHttpClientFactory in .NET?

Manually creating a new HttpClient() bypasses the DelegatingHandler pipeline that OpenTelemetry registers through IHttpClientFactory, so the outbound request never carries the traceparent header. The receiving service then starts a disconnected trace instead of linking to the caller's trace, and this fails silently with no errors, only missing context propagation.

_Debugging silent trace gaps in .NET services is easier when you keep tracing pitfalls like this bookmarked on daily.dev._

### Why should distributed services use ParentBasedSampler instead of TraceIdRatioBasedSampler alone?

TraceIdRatioBasedSampler makes an independent sampling decision per service, so different services can mathematically disagree on whether to sample the same trace, producing incomplete partial traces. ParentBasedSampler instead reads the trace-flags field from the incoming traceparent header and inherits the upstream sampling decision, ensuring all downstream services record complete, consistent traces for the sampled percentage.

_Getting sampling consistent across services is a recurring pain point worth tracking on daily.dev when choosing observability strategies._

## Similar posts on daily.dev

- [Distributed tracing for agentic workflows with OpenTelemetry](https://daily.dev/posts/distributed-tracing-for-agentic-workflows-with-opentelemetry-3suufjdue) · Red Hat Developer · 0 upvotes · 0 comments
- [OpenTelemetry ASP.NET Core: Setup, Auto-Instrumentation, and Configuration](https://daily.dev/posts/opentelemetry-asp-net-core-setup-auto-instrumentation-and-configuration-tiydmwrgx) · We Are .NET · 1 upvotes · 0 comments
- [Logging, Metrics, and Distributed Tracing in .NET with OpenTelemetry and ClickStack](https://daily.dev/posts/logging-metrics-and-distributed-tracing-in-net-with-opentelemetry-and-clickstack-ohkhm2db1) · ClickHouse · 4 upvotes · 0 comments
- [Implement Distributed Tracing with Spring Boot 3](https://daily.dev/posts/implement-distributed-tracing-with-spring-boot-3-vwpklksid) · Last9 · 2 upvotes · 0 comments

---

Tags: [#devops](https://daily.dev/tags/devops), [#.net](https://daily.dev/tags/.net), [#opentelemetry](https://daily.dev/tags/opentelemetry)

[View this post on daily.dev](https://daily.dev/posts/distributed-tracing-across-net-services-with-opentelemetry-w3c-trace-context-and-baggage-u8610tjrt)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Distributed Tracing Across .NET Services with OpenTelemetry: W3C Trace Context and Baggage","url":"https://daily.dev/posts/distributed-tracing-across-net-services-with-opentelemetry-w3c-trace-context-and-baggage-u8610tjrt","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/distributed-tracing-across-net-services-with-opentelemetry-w3c-trace-context-and-baggage-u8610tjrt"},"datePublished":"2026-08-01T21:56:57.068Z","dateModified":"2026-09-14T08:55:29.670Z","description":"A comprehensive guide to distributed tracing in .NET using OpenTelemetry. Covers the W3C Trace Context standard (traceparent and tracestate headers), automatic...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/7a22f2549b4b604a14d0e7024b6dcfe3?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/7a22f2549b4b604a14d0e7024b6dcfe3?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"We Are .NET","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"We Are .NET","logo":"https://media.daily.dev/image/upload/s--BsnVOa3i--/f_auto/v1718347410/logos/wearedotnet","url":"https://daily.dev/sources/wearedotnet"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/distributed-tracing-across-net-services-with-opentelemetry-w3c-trace-context-and-baggage-u8610tjrt","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":1},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"devops,.net,opentelemetry","timeRequired":"PT20M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"We Are .NET","item":"https://daily.dev/sources/wearedotnet"},{"@type":"ListItem","position":3,"name":"Distributed Tracing Across .NET Services with OpenTelemetry: W3C Trace Context and Baggage"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/distributed-tracing-across-net-services-with-opentelemetry-w3c-trace-context-and-baggage-u8610tjrt#faq","mainEntity":[{"@type":"Question","name":"What are the four fields in the W3C traceparent header used by OpenTelemetry?","acceptedAnswer":{"@type":"Answer","text":"The traceparent header has four hyphen-separated fields: version (always 00), trace ID (a 128-bit, 32 hex character identifier for the entire distributed trace), parent span ID (a 64-bit, 16 hex character identifier of the calling span), and trace flags (a single byte where 01 means sampled and 00 means not sampled). Developers wiring up cross-service tracing can dig deeper into traceparent mechanics on daily.dev."}},{"@type":"Question","name":"Why does my distributed trace break when I create HttpClient manually instead of using IHttpClientFactory in .NET?","acceptedAnswer":{"@type":"Answer","text":"Manually creating a new HttpClient() bypasses the DelegatingHandler pipeline that OpenTelemetry registers through IHttpClientFactory, so the outbound request never carries the traceparent header. The receiving service then starts a disconnected trace instead of linking to the caller's trace, and this fails silently with no errors, only missing context propagation. Debugging silent trace gaps in .NET services is easier when you keep tracing pitfalls like this bookmarked on daily.dev."}},{"@type":"Question","name":"Why should distributed services use ParentBasedSampler instead of TraceIdRatioBasedSampler alone?","acceptedAnswer":{"@type":"Answer","text":"TraceIdRatioBasedSampler makes an independent sampling decision per service, so different services can mathematically disagree on whether to sample the same trace, producing incomplete partial traces. ParentBasedSampler instead reads the trace-flags field from the incoming traceparent header and inherits the upstream sampling decision, ensuring all downstream services record complete, consistent traces for the sampled percentage. Getting sampling consistent across services is a recurring pain point worth tracking on daily.dev when choosing observability strategies."}}]}
```

