Blog Post

Microsoft Mission Critical Blog
4 MIN READ

Demystifying SessionTrackingId and Request Correlation in D365 CE Integrations

PravinT's avatar
PravinT
Icon for Microsoft rankMicrosoft
Sep 29, 2025

By Praveen Thonda, Cloud Solution Architect, Microsoft

Introduction 

As a Cloud Solution Architect working with Dynamics 365 Customer Engagement (D365 CE) customers, I often see organizations building high-volume integrations using the ServiceClient SDK for .NET Core (or CrmServiceClient for classic .NET Framework). While these SDKs make it easy to connect and interact with Dataverse, tracking and diagnosing issues—especially in production—can be challenging. 

One of the least-known but most powerful features for support and diagnostics is the SessionTrackingId property on ServiceClient. In this post, I’ll explain what it is, how to use it, and why it’s invaluable for working with Microsoft support and troubleshooting performance issues. 

 

The Problem: Diagnosing Integration Performance 

Many customers log the time before and after each Dataverse call, and if they see high latency, they often suspect the Dataverse service itself. However, in large-scale, high-volume integrations, the real culprit is frequently client-side resource contention or SNAT port exhaustion. This can lead to slow connection establishment, WCF binding timeouts, and misleadingly high client-side timings—even when the server-side execution is fast. 

 

The Solution: SessionTrackingId and Request Correlation 

With ServiceClient, you cannot manually set HTTP headers. You rely on the SessionTrackingId property, which internally maps to the x-ms-client-session-id header. Microsoft support can use this ID to trace your request end-to-end, from your client to the Dataverse backend. When using HttpClient, you can achieve similar tracking by utilizing the User-Agent HTTP header to append a GUID, which helps Microsoft support correlate requests in telemetry for diagnostics and troubleshooting.  

 

Sample: Using SessionTrackingId and Logging Request Timing 

using Microsoft.PowerPlatform.Dataverse.Client;
using Microsoft.Extensions.Configuration;
using System;
using System.IO;
using System.Diagnostics;
using Microsoft.Crm.Sdk.Messages;

namespace D365UserAgentDemo
{
        class Program
        {
                static void Main(string[] args)
                {
                        var config = new ConfigurationBuilder()
                                .SetBasePath(Directory.GetCurrentDirectory())
                                .AddJsonFile("appsettings.json", optional: false)
                                .Build();

                        var d365Section = config.GetSection("D365");
                        string appId = d365Section["AppId"];
                        string clientSecret = d365Section["ClientSecret"];
                        string orgUrl = d365Section["OrgUrl"];
                        string tenantId = d365Section["TenantId"];

                        string connectionString = $"AuthType=ClientSecret;Url={orgUrl};ClientId={appId};ClientSecret={clientSecret};TenantId={tenantId};";

                        // 1. Call with ServiceClient
                        var sessionTrackingId1 = Guid.NewGuid();
                        Console.WriteLine($"\n[ServiceClient] Using SessionTrackingId: {sessionTrackingId1}");
                        string? accessToken = null;

                        using (var svc = new ServiceClient(connectionString))
                        {
                                svc.SessionTrackingId = sessionTrackingId1;
                                try
                                {
                                        var sw = Stopwatch.StartNew();
                                        var response = svc.Execute(new WhoAmIRequest());
                                        sw.Stop();

                                        var userId = ((WhoAmIResponse)response).UserId;
                                        Console.WriteLine($"[ServiceClient] WhoAmI UserId: {userId}");
                                        Console.WriteLine($"[ServiceClient] Time taken: {sw.ElapsedMilliseconds} ms");
                                        Console.WriteLine($"[ServiceClient] TrackingId: {sessionTrackingId1}");
                                        accessToken = svc.CurrentAccessToken;
                                }
                                catch (Exception ex)
                                {
                                        Console.WriteLine($"[ServiceClient] Error: {ex.Message}");
                                }
                        }

                        // 2. Call with HttpClient
                        var trackingId2 = Guid.NewGuid();
                        Console.WriteLine($"\n[HttpClient] Using User-Agent with embedded tracking ID: {trackingId2}");
                        if (!string.IsNullOrWhiteSpace(accessToken))
                        {
                                using (var httpClient = new System.Net.Http.HttpClient())
                                {
                                        httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
                                        httpClient.DefaultRequestHeaders.UserAgent.Clear();
                                        httpClient.DefaultRequestHeaders.UserAgent.ParseAdd($"D365UserAgentDemo/{trackingId2}");
                                        httpClient.DefaultRequestHeaders.Remove("x-ms-client-request-id");
                                        httpClient.DefaultRequestHeaders.Add("x-ms-client-request-id", trackingId2.ToString());

                                        var apiBase = orgUrl.TrimEnd('/');
                                        var apiUrl = $"{apiBase}/api/data/v9.2/WhoAmI";

                                        try
                                        {
                                                var sw = Stopwatch.StartNew();
                                                var httpResponse = httpClient.GetAsync(apiUrl).GetAwaiter().GetResult();
                                                sw.Stop();

                                                var content = httpResponse.Content.ReadAsStringAsync().GetAwaiter().GetResult();
                                                Console.WriteLine($"[HttpClient] WhoAmI response: {content}");
                                                Console.WriteLine($"[HttpClient] Time taken: {sw.ElapsedMilliseconds} ms");
                                                Console.WriteLine($"[HttpClient] TrackingId (User-Agent): {trackingId2}");
                                        }
                                        catch (Exception ex)
                                        {
                                                Console.WriteLine($"[HttpClient] Error: {ex.Message}");
                                        }
                                }
                        }
                        else
                        {
                                Console.WriteLine("No access token available from ServiceClient for HttpClient call.");
                        }
                }
        }
}

 

 Why This Matters 

  • Supportability: When you open a support ticket, provide the SessionTrackingId (for SDK). Microsoft support can trace your request through the entire stack. 
  • Root Cause Analysis: If you see high client-side latency, but Microsoft support shows fast server-side execution for your tracking ID, the issue is likely on the client (resource contention, SNAT exhaustion, etc.). 

 

 Bonus: Classic .NET Framework 

If you’re using classic .NET Framework, use CrmServiceClient instead. The pattern is similar, and the property is also called SessionTrackingId. 

 

Conclusion 

The SessionTrackingId and embedded tracking IDs in User-Agent headers are powerful but underutilized features for D365 CE integrations. They enable precise request tracking, better support experiences, and faster root cause analysis. 

Although SessionTrackingId is documented as a session-level identifier, in practice it is best used to track individual requests—especially when diagnosing performance issues. Since ServiceClient does not expose a separate property for request-level correlation, assigning a unique SessionTrackingId per request is the most effective approach. 

Takeaway 

When client-side telemetry shows significantly higher latency than Power Platform telemetry, it’s a strong indicator that your integration needs horizontal scaling. Logging request-level timing with a unique tracking ID helps pinpoint these bottlenecks and guides you toward the right architectural decisions. 

Updated Sep 29, 2025
Version 1.0
No CommentsBe the first to comment