public async Task Invoke(HttpContext httpContext) { if (httpContext == null) { throw new ArgumentNullException(nameof(httpContext)); } OverwriteTrackingContextHeader(httpContext, m_HeaderKeys, m_HeaderValueGenerator); // In order to add http headers to the message response, reprocess the Tracking Context // in a callback function. This is necessary because response headers cannot be set after // the response body has been written. httpContext.Response.OnStarting(state => { var ctx = (HttpContext)state; OverwriteTrackingContextHeader(httpContext, m_HeaderKeys, m_HeaderValueGenerator); // Take the current Tracking Context (if it exists) and add it to the http response headers. TrackingContextHelper.ProcessHttpHeaders(ctx?.Response?.Headers); return(Task.FromResult(0)); }, httpContext); await m_Next.Invoke(httpContext).ConfigureAwait(false); }
private static void MergeTrackingContextHeader(HttpContext httpContext) { if (httpContext == null) { throw new ArgumentNullException(nameof(httpContext)); } TrackingContext previousTrackingContext = TrackingContext.Current; // Take the Tracking Context (if it exists) from the http request headers and make it current. TrackingContextHelper.ProcessHttpHeaders(httpContext.Request?.Headers); // Check to see how the new current Tracking Context compares to the previous one. if (previousTrackingContext != null) { TrackingContext currentTrackingContext = TrackingContext.Current; Debug.Assert(currentTrackingContext != null); // Prepare the inputs for the new Tracking Context. Guid callChainId = currentTrackingContext.CallChainId; DateTime originatorUtcTimestamp = currentTrackingContext.OriginatorUtcTimestamp; IDictionary <string, string> extraHeaders = currentTrackingContext .ExtraHeaders .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); // Extract the extra headers that were in the previous Tracking Context, but // are not in the inputs for the new Tracking Context. IList <string> nowMissingHeaderNames = previousTrackingContext .ExtraHeaders.Keys .Except(extraHeaders.Keys) .ToList(); // Add the missing extra headers back to the inputs for the new Tracking Context. foreach (string headerName in nowMissingHeaderNames) { extraHeaders.Add(headerName, previousTrackingContext.ExtraHeaders[headerName]); } // Extract the extra headers that were in the previous Tracking Context, and // also in inputs for the new Tracking Context, but whose values are not empty. IList <string> sharedHeaderNames = extraHeaders .Keys .Except(nowMissingHeaderNames) .ToList(); // Add the missing extra header values back to the inputs for the new Tracking Context. foreach (string headerName in sharedHeaderNames) { if (string.IsNullOrWhiteSpace(extraHeaders[headerName])) { extraHeaders[headerName] = previousTrackingContext.ExtraHeaders[headerName]; } } // Now recreate the current Tracking Context with the refilled extra headers. var newTrackingContext = new TrackingContext( callChainId, originatorUtcTimestamp, extraHeaders); newTrackingContext.SetAsCurrent(); } }