@@ -161,6 +161,147 @@ public void
161161 Assert . Equal ( requestCorrelationId , evt . Properties [ LogPropertyName ] . LiteralValue ( ) . ToString ( ) ) ;
162162 }
163163
164+ [ Fact ]
165+ public void GetCorrelationId_WhenHttpRequestContainCorrelationHeader_ShouldReturnCorrelationIdFromHttpContext ( )
166+ {
167+ // Arrange
168+ string correlationId = Guid . NewGuid ( ) . ToString ( ) ;
169+ _contextAccessor . HttpContext ! . Request ! . Headers [ HeaderKey ] = correlationId ;
170+ CorrelationIdEnricher correlationIdEnricher = new ( HeaderKey , false , _contextAccessor ) ;
171+
172+ LogEvent evt = null ;
173+ Logger log = new LoggerConfiguration ( )
174+ . Enrich . With ( correlationIdEnricher )
175+ . WriteTo . Sink ( new DelegatingSink ( e => evt = e ) )
176+ . CreateLogger ( ) ;
177+
178+ // Act
179+ log . Information ( "Has a correlation id." ) ;
180+ string retrievedCorrelationId = _contextAccessor . HttpContext ! . GetCorrelationId ( ) ;
181+
182+ // Assert
183+ Assert . NotNull ( evt ) ;
184+ Assert . Equal ( correlationId , retrievedCorrelationId ) ;
185+ }
186+
187+ [ Fact ]
188+ public void
189+ GetCorrelationId_WhenHttpRequestNotContainCorrelationHeaderAndAddDefaultValueIsTrue_ShouldReturnGeneratedCorrelationIdFromHttpContext ( )
190+ {
191+ // Arrange
192+ CorrelationIdEnricher correlationIdEnricher = new ( HeaderKey , true , _contextAccessor ) ;
193+
194+ LogEvent evt = null ;
195+ Logger log = new LoggerConfiguration ( )
196+ . Enrich . With ( correlationIdEnricher )
197+ . WriteTo . Sink ( new DelegatingSink ( e => evt = e ) )
198+ . CreateLogger ( ) ;
199+
200+ // Act
201+ log . Information ( "Has a correlation id." ) ;
202+ string retrievedCorrelationId = _contextAccessor . HttpContext ! . GetCorrelationId ( ) ;
203+
204+ // Assert
205+ Assert . NotNull ( evt ) ;
206+ Assert . NotNull ( retrievedCorrelationId ) ;
207+ Assert . NotEmpty ( retrievedCorrelationId ) ;
208+ // Verify it's a valid GUID format
209+ Assert . True ( Guid . TryParse ( retrievedCorrelationId , out _ ) ) ;
210+ }
211+
212+ [ Fact ]
213+ public void
214+ GetCorrelationId_WhenHttpRequestNotContainCorrelationHeaderAndAddDefaultValueIsFalse_ShouldReturnNullFromHttpContext ( )
215+ {
216+ // Arrange
217+ CorrelationIdEnricher correlationIdEnricher = new ( HeaderKey , false , _contextAccessor ) ;
218+
219+ LogEvent evt = null ;
220+ Logger log = new LoggerConfiguration ( )
221+ . Enrich . With ( correlationIdEnricher )
222+ . WriteTo . Sink ( new DelegatingSink ( e => evt = e ) )
223+ . CreateLogger ( ) ;
224+
225+ // Act
226+ log . Information ( "Has a correlation id." ) ;
227+ string retrievedCorrelationId = _contextAccessor . HttpContext ! . GetCorrelationId ( ) ;
228+
229+ // Assert
230+ Assert . NotNull ( evt ) ;
231+ Assert . Null ( retrievedCorrelationId ) ;
232+ }
233+
234+ [ Fact ]
235+ public void GetCorrelationId_WhenCalledMultipleTimes_ShouldReturnSameCorrelationId ( )
236+ {
237+ // Arrange
238+ string correlationId = Guid . NewGuid ( ) . ToString ( ) ;
239+ _contextAccessor . HttpContext ! . Request ! . Headers [ HeaderKey ] = correlationId ;
240+ CorrelationIdEnricher correlationIdEnricher = new ( HeaderKey , false , _contextAccessor ) ;
241+
242+ Logger log = new LoggerConfiguration ( )
243+ . Enrich . With ( correlationIdEnricher )
244+ . WriteTo . Sink ( new DelegatingSink ( _ => { } ) )
245+ . CreateLogger ( ) ;
246+
247+ // Act
248+ log . Information ( "First log message." ) ;
249+ string firstRetrieval = _contextAccessor . HttpContext ! . GetCorrelationId ( ) ;
250+
251+ log . Information ( "Second log message." ) ;
252+ string secondRetrieval = _contextAccessor . HttpContext ! . GetCorrelationId ( ) ;
253+
254+ // Assert
255+ Assert . Equal ( correlationId , firstRetrieval ) ;
256+ Assert . Equal ( correlationId , secondRetrieval ) ;
257+ Assert . Equal ( firstRetrieval , secondRetrieval ) ;
258+ }
259+
260+ [ Fact ]
261+ public void GetCorrelationId_WhenHttpContextIsNull_ShouldReturnNull ( )
262+ {
263+ // Arrange & Act
264+ string result = HttpContextExtensions . GetCorrelationId ( null ) ;
265+
266+ // Assert
267+ Assert . Null ( result ) ;
268+ }
269+
270+ [ Fact ]
271+ public void EnrichLogWithCorrelationId_BackwardCompatibility_OldRetrievalMethodShouldStillWork ( )
272+ {
273+ // Arrange
274+ string correlationId = Guid . NewGuid ( ) . ToString ( ) ;
275+ _contextAccessor . HttpContext ! . Request ! . Headers [ HeaderKey ] = correlationId ;
276+ CorrelationIdEnricher correlationIdEnricher = new ( HeaderKey , false , _contextAccessor ) ;
277+
278+ LogEvent evt = null ;
279+ Logger log = new LoggerConfiguration ( )
280+ . Enrich . With ( correlationIdEnricher )
281+ . WriteTo . Sink ( new DelegatingSink ( e => evt = e ) )
282+ . CreateLogger ( ) ;
283+
284+ // Act
285+ log . Information ( "Has a correlation id." ) ;
286+
287+ // Test that the old way (hacky way) still works
288+ HttpContext httpContext = _contextAccessor . HttpContext ! ;
289+ string retrievedCorrelationIdOldWay = null ;
290+
291+ if ( httpContext . Items . TryGetValue ( "Serilog_CorrelationId" , out object correlationIdItem ) &&
292+ correlationIdItem is LogEventProperty { Name : "CorrelationId" } correlationIdProperty )
293+ retrievedCorrelationIdOldWay = ( ( ScalarValue ) correlationIdProperty . Value ) . Value as string ;
294+
295+ // Test that the new way also works
296+ string retrievedCorrelationIdNewWay = httpContext . GetCorrelationId ( ) ;
297+
298+ // Assert
299+ Assert . NotNull ( evt ) ;
300+ Assert . Equal ( correlationId , retrievedCorrelationIdOldWay ) ;
301+ Assert . Equal ( correlationId , retrievedCorrelationIdNewWay ) ;
302+ Assert . Equal ( retrievedCorrelationIdOldWay , retrievedCorrelationIdNewWay ) ;
303+ }
304+
164305 [ Fact ]
165306 public void WithClientIp_ThenLoggerIsCalled_ShouldNotThrowException ( )
166307 {
0 commit comments