Skip to content

Commit 539861c

Browse files
committed
fix(request-info): restore stream position and update to .NET 10
Restores the request body stream position after accessing form data in AspNetCore and Web platforms. This commit also updates the test project to target .NET 10 and migrates the copyright notice to use a dynamic year.
1 parent 5f1c840 commit 539861c

6 files changed

Lines changed: 45 additions & 7 deletions

File tree

build/common.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<MinVerTagPrefix>v</MinVerTagPrefix>
99
<EnableWindowsTargeting>true</EnableWindowsTargeting>
1010

11-
<Copyright>Copyright (c) 2025 Exceptionless. All rights reserved.</Copyright>
11+
<Copyright>Copyright © $([System.DateTime]::Now.ToString(yyyy)) Exceptionless. All rights reserved.</Copyright>
1212
<Authors>Exceptionless</Authors>
1313
<NoWarn>$(NoWarn);CS1591;NU1701</NoWarn>
1414
<WarningsAsErrors>true</WarningsAsErrors>

src/Platforms/Exceptionless.AspNetCore/RequestInfoCollector.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ private static object GetPostData(HttpContext context, ExceptionlessConfiguratio
6262
var log = config.Resolver.GetLog();
6363

6464
long contentLength = context.Request.ContentLength.GetValueOrDefault();
65-
if(contentLength == 0) {
65+
if (contentLength == 0) {
6666
string message = "Content-length was zero, empty post.";
6767
log.Debug(message);
6868
return message;
@@ -95,8 +95,11 @@ private static object GetPostData(HttpContext context, ExceptionlessConfiguratio
9595
return message;
9696
}
9797

98+
// Form check must come after seekability and position checks above: accessing
99+
// Request.Form triggers reading the request body stream.
98100
if (context.Request.HasFormContentType && context.Request.Form.Count > 0) {
99101
log.Debug("Reading POST data from Request.Form");
102+
context.Request.Body.Position = originalPosition;
100103
return context.Request.Form.ToDictionary(exclusionList);
101104
}
102105

src/Platforms/Exceptionless.Web/RequestInfoCollector.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,11 @@ private static object GetPostData(HttpContextBase context, ExceptionlessConfigur
108108
return message;
109109
}
110110

111+
// Form check must come after seekability and position checks above: accessing
112+
// Request.Form triggers reading the request body stream.
111113
if (context.Request.Form.Count > 0) {
112114
log.Debug("Reading POST data from Request.Form");
113-
115+
context.Request.InputStream.Position = originalPosition;
114116
return context.Request.Form.ToDictionary(exclusionList);
115117
}
116118

src/Platforms/Exceptionless.WebApi/RequestInfoCollector.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public static RequestInfo Collect(HttpActionContext context, ExceptionlessConfig
5151
// POST data collection is not implemented for WebApi due to async complexities and
5252
// the difficulty of reading the request body without interfering with model binding.
5353
// Other platforms (AspNetCore, Web) now only collect POST data for unhandled errors.
54-
// TODO: support getting post data asyncly.
54+
// TODO: support getting post data asynchronously.
5555
//if (config.IncludePostData && isUnhandledError && context.Request.Method != HttpMethod.Get)
5656
// info.PostData = GetPostData(context, config, exclusionList);
5757

test/Exceptionless.Tests/Exceptionless.Tests.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
<Import Project="..\..\build\common.props" />
33

44
<PropertyGroup Condition=" '$(OS)' != 'Windows_NT' ">
5-
<TargetFramework>net8.0</TargetFramework>
5+
<TargetFramework>net10.0</TargetFramework>
66
</PropertyGroup>
77
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">
8-
<TargetFrameworks>net8.0;net462</TargetFrameworks>
8+
<TargetFrameworks>net10.0;net462</TargetFrameworks>
99
</PropertyGroup>
1010

1111
<PropertyGroup>
@@ -19,7 +19,7 @@
1919
<None Include="app.config" />
2020
</ItemGroup>
2121

22-
<PropertyGroup Condition=" '$(TargetFramework)' == 'net8.0' " Label="Build">
22+
<PropertyGroup Condition=" '$(TargetFramework)' == 'net10.0' " Label="Build">
2323
<DefineConstants>$(DefineConstants);NETSTANDARD;NETSTANDARD2_0</DefineConstants>
2424
</PropertyGroup>
2525

test/Exceptionless.Tests/Platforms/AspNetCoreRequestInfoTests.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,62 @@
1+
using System.Collections.Generic;
12
using System.IO;
23
using System.Text;
34
using Exceptionless;
45
using Exceptionless.Dependency;
56
using Microsoft.AspNetCore.Http;
7+
using Microsoft.Extensions.Primitives;
68
using Xunit;
79

810
namespace Exceptionless.Tests.Platforms {
911
public class AspNetCoreRequestInfoTests {
1012
[Fact]
1113
public void GetRequestInfo_DoesNotReadPostData_ForHandledErrors() {
14+
// Arrange
1215
var context = CreateHttpContext("hello=world");
1316
var config = new ExceptionlessConfiguration(DependencyResolver.CreateDefault());
1417

18+
// Act
1519
var requestInfo = context.GetRequestInfo(config);
1620

21+
// Assert
1722
Assert.NotNull(requestInfo);
1823
Assert.Null(requestInfo.PostData);
1924
Assert.Equal(0L, context.Request.Body.Position);
2025
}
2126

2227
[Fact]
2328
public void GetRequestInfo_ReadsAndRestoresPostData_ForUnhandledErrors() {
29+
// Arrange
2430
const string body = "{\"hello\":\"world\"}";
2531
var context = CreateHttpContext(body);
2632
var config = new ExceptionlessConfiguration(DependencyResolver.CreateDefault());
2733

2834
context.Request.Body.Position = 5;
2935

36+
// Act
3037
var requestInfo = context.GetRequestInfo(config, isUnhandledError: true);
3138

39+
// Assert
3240
Assert.NotNull(requestInfo);
3341
Assert.Equal(body, Assert.IsType<string>(requestInfo.PostData));
3442
Assert.Equal(5L, context.Request.Body.Position);
3543
}
3644

45+
[Fact]
46+
public void GetRequestInfo_ReadsFormData_ForUnhandledErrors() {
47+
// Arrange
48+
var context = CreateFormHttpContext();
49+
var config = new ExceptionlessConfiguration(DependencyResolver.CreateDefault());
50+
51+
// Act
52+
var requestInfo = context.GetRequestInfo(config, isUnhandledError: true);
53+
54+
// Assert
55+
Assert.NotNull(requestInfo);
56+
var postData = Assert.IsType<Dictionary<string, string>>(requestInfo.PostData);
57+
Assert.Equal("world", postData["name"]);
58+
}
59+
3760
private static DefaultHttpContext CreateHttpContext(string body) {
3861
var bodyBytes = Encoding.UTF8.GetBytes(body);
3962
var context = new DefaultHttpContext();
@@ -43,5 +66,15 @@ private static DefaultHttpContext CreateHttpContext(string body) {
4366
context.Request.ContentLength = bodyBytes.Length;
4467
return context;
4568
}
69+
70+
private static DefaultHttpContext CreateFormHttpContext() {
71+
var context = new DefaultHttpContext();
72+
context.Request.Method = HttpMethods.Post;
73+
context.Request.ContentType = "application/x-www-form-urlencoded";
74+
context.Request.Form = new FormCollection(new Dictionary<string, StringValues> {
75+
["name"] = "world"
76+
});
77+
return context;
78+
}
4679
}
4780
}

0 commit comments

Comments
 (0)