Skip to content

Commit e46883d

Browse files
committed
Address request context review feedback
1 parent 8b2c333 commit e46883d

4 files changed

Lines changed: 50 additions & 21 deletions

File tree

src/PostHog.AspNetCore/Tracing/PostHogRequestContextMiddlewareExtensions.cs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using Microsoft.AspNetCore.Builder;
2+
using Microsoft.AspNetCore.Http;
3+
using Microsoft.AspNetCore.Http.Features;
24

35
namespace PostHog;
46

@@ -19,11 +21,34 @@ public static IApplicationBuilder UsePostHogRequestContext(
1921
{
2022
if (app is null)
2123
{
22-
return app!;
24+
return new NoOpApplicationBuilder();
2325
}
2426

2527
var options = new PostHogRequestContextOptions();
2628
configure?.Invoke(options);
2729
return app.UseMiddleware<PostHogRequestContextMiddleware>(options);
2830
}
31+
32+
sealed class NoOpApplicationBuilder : IApplicationBuilder
33+
{
34+
readonly IFeatureCollection _serverFeatures = new FeatureCollection();
35+
readonly IDictionary<string, object?> _properties = new Dictionary<string, object?>();
36+
37+
public IServiceProvider ApplicationServices { get; set; } = new NoOpServiceProvider();
38+
39+
public IFeatureCollection ServerFeatures => _serverFeatures;
40+
41+
public IDictionary<string, object?> Properties => _properties;
42+
43+
public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware) => this;
44+
45+
public IApplicationBuilder New() => new NoOpApplicationBuilder();
46+
47+
public RequestDelegate Build() => _ => Task.CompletedTask;
48+
}
49+
50+
sealed class NoOpServiceProvider : IServiceProvider
51+
{
52+
public object? GetService(Type serviceType) => null;
53+
}
2954
}

src/PostHog.AspNetCore/Tracing/PostHogTracingHeaders.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,7 @@ public static PostHogRequestContextData Extract(HttpContext? httpContext, PostHo
7474
return null;
7575
}
7676

77-
var value = values.Count > 0 ? values[0] : values.ToString();
78-
return SanitizeValue(value);
77+
return SanitizeValue(values[0]);
7978
}
8079

8180
internal static string? SanitizeValue(string? value)
@@ -117,7 +116,8 @@ static void AddIfPresent(Dictionary<string, object> properties, string key, stri
117116
"://",
118117
request.Host.ToUriComponent(),
119118
request.PathBase.ToUriComponent(),
120-
request.Path.ToUriComponent());
119+
request.Path.ToUriComponent(),
120+
request.QueryString.ToUriComponent());
121121
}
122122

123123
static string? GetRequestPath(HttpRequest request)

tests/UnitTests.AspNetCore/PostHogRequestContextMiddlewareTests.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ public async Task NullHttpContextDoesNotThrow()
2020
await middleware.InvokeAsync(null);
2121
}
2222

23+
[Fact]
24+
public async Task NullApplicationBuilderReturnsNoOpBuilder()
25+
{
26+
var app = PostHogRequestContextMiddlewareExtensions.UsePostHogRequestContext(null!);
27+
28+
Assert.NotNull(app);
29+
await app.Build()(new DefaultHttpContext());
30+
}
31+
2332
[Fact]
2433
public void NullTracingExtractionInputsReturnEmptyContext()
2534
{
@@ -60,7 +69,7 @@ public async Task AppliesRequestContextHeadersAndRequestMetadataToDownstreamCapt
6069
Assert.Equal("frontend-user", batchItem.GetProperty("distinct_id").GetString());
6170
var properties = batchItem.GetProperty("properties");
6271
Assert.Equal("frontend-session", properties.GetProperty("$session_id").GetString());
63-
Assert.Equal("https://example.com/api/test", properties.GetProperty("$current_url").GetString());
72+
Assert.Equal("https://example.com/api/test?filter=1", properties.GetProperty("$current_url").GetString());
6473
Assert.Equal("POST", properties.GetProperty("$request_method").GetString());
6574
Assert.Equal("/api/test", properties.GetProperty("$request_path").GetString());
6675
Assert.Equal("TestAgent/1.0", properties.GetProperty("$user_agent").GetString());
@@ -255,7 +264,7 @@ public async Task CapturesUnhandledExceptionsWithRequestContextAndRethrows()
255264
Assert.Equal("exception-user", batchItem.GetProperty("distinct_id").GetString());
256265
var properties = batchItem.GetProperty("properties");
257266
Assert.Equal("exception-session", properties.GetProperty("$session_id").GetString());
258-
Assert.Equal("https://example.com/api/test", properties.GetProperty("$current_url").GetString());
267+
Assert.Equal("https://example.com/api/test?filter=1", properties.GetProperty("$current_url").GetString());
259268
Assert.Equal("ExceptionAgent/1.0", properties.GetProperty("$user_agent").GetString());
260269
Assert.Equal("10.0.0.2", properties.GetProperty("$ip").GetString());
261270
Assert.Equal(StatusCodes.Status503ServiceUnavailable, properties.GetProperty("$response_status_code").GetInt32());

tests/UnitTests/PostHogContextTests.cs

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -100,26 +100,21 @@ public async Task ExplicitCaptureValuesOverrideContext()
100100
Assert.Equal("context-only-value", properties.GetProperty("context-only").GetString());
101101
}
102102

103-
[Fact]
104-
public void MissingDistinctIdCreatesPersonlessContext()
103+
[Theory]
104+
[InlineData(null, false)]
105+
[InlineData(true, true)]
106+
public void PersonlessContextSetsProcessPersonProfile(bool? explicitOverride, bool expectedValue)
105107
{
106-
var context = PostHogContextHelper.ResolveCaptureContext(distinctId: null, properties: null);
108+
var properties = explicitOverride.HasValue
109+
? new Dictionary<string, object> { ["$process_person_profile"] = explicitOverride.Value }
110+
: null;
111+
112+
var context = PostHogContextHelper.ResolveCaptureContext(distinctId: null, properties: properties);
107113

108114
Assert.True(Guid.TryParse(context.DistinctId, out _));
109115
Assert.True(context.IsPersonless);
110116
Assert.NotNull(context.Properties);
111-
Assert.False((bool)context.Properties["$process_person_profile"]);
112-
}
113-
114-
[Fact]
115-
public void ExplicitProcessPersonProfileOverridesPersonlessDefault()
116-
{
117-
var context = PostHogContextHelper.ResolveCaptureContext(
118-
distinctId: null,
119-
properties: new Dictionary<string, object> { ["$process_person_profile"] = true });
120-
121-
Assert.NotNull(context.Properties);
122-
Assert.True((bool)context.Properties["$process_person_profile"]);
117+
Assert.Equal(expectedValue, (bool)context.Properties["$process_person_profile"]);
123118
}
124119

125120
[Fact]

0 commit comments

Comments
 (0)