Skip to content

Commit 7db7dcd

Browse files
Update HttpLoggingAttribute API (#48214)
1 parent 0c3121d commit 7db7dcd

7 files changed

+104
-22
lines changed

src/Middleware/HttpLogging/src/HttpLoggingAttribute.cs

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,73 @@ public sealed class HttpLoggingAttribute : Attribute
1313
/// Initializes an instance of the <see cref="HttpLoggingAttribute"/> class.
1414
/// </summary>
1515
/// <param name="loggingFields">Specifies what fields to log for the endpoint.</param>
16-
/// <param name="requestBodyLogLimit">Specifies the maximum number of bytes to be logged for the request body. A value of <c>-1</c> means use the default setting in <see cref="HttpLoggingOptions.RequestBodyLogLimit"/>.</param>
17-
/// <param name="responseBodyLogLimit">Specifies the maximum number of bytes to be logged for the response body. A value of <c>-1</c> means use the default setting in <see cref="HttpLoggingOptions.ResponseBodyLogLimit"/>.</param>
18-
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="requestBodyLogLimit"/> or <paramref name="responseBodyLogLimit"/> is less than <c>-1</c>.</exception>
19-
public HttpLoggingAttribute(HttpLoggingFields loggingFields, int requestBodyLogLimit = -1, int responseBodyLogLimit = -1)
16+
public HttpLoggingAttribute(HttpLoggingFields loggingFields)
2017
{
2118
LoggingFields = loggingFields;
22-
23-
ArgumentOutOfRangeException.ThrowIfLessThan(requestBodyLogLimit, -1);
24-
ArgumentOutOfRangeException.ThrowIfLessThan(responseBodyLogLimit, -1);
25-
26-
RequestBodyLogLimit = requestBodyLogLimit;
27-
ResponseBodyLogLimit = responseBodyLogLimit;
2819
}
2920

21+
private int _responseBodyLogLimit;
22+
private int _requestBodyLogLimit;
23+
3024
/// <summary>
3125
/// Specifies what fields to log.
3226
/// </summary>
3327
public HttpLoggingFields LoggingFields { get; }
3428

29+
/// <summary>
30+
/// Indicates whether <see cref="RequestBodyLogLimit"/> has been set.
31+
/// </summary>
32+
public bool IsRequestBodyLogLimitSet { get; private set; }
33+
3534
/// <summary>
3635
/// Specifies the maximum number of bytes to be logged for the request body.
3736
/// </summary>
38-
public int RequestBodyLogLimit { get; }
37+
/// <exception cref="ArgumentOutOfRangeException">Thrown when <see cref="RequestBodyLogLimit"/> set to a value less than <c>0</c>.</exception>
38+
/// <exception cref="InvalidOperationException">Thrown when getting <see cref="RequestBodyLogLimit"/> if it hasn't been set to a value. Check <see cref="IsRequestBodyLogLimitSet"/> first.</exception>
39+
public int RequestBodyLogLimit
40+
{
41+
get
42+
{
43+
if (IsRequestBodyLogLimitSet)
44+
{
45+
return _requestBodyLogLimit;
46+
}
47+
48+
throw new InvalidOperationException($"{nameof(RequestBodyLogLimit)} was not set. Check {nameof(IsRequestBodyLogLimitSet)} before accessing this property.");
49+
}
50+
set
51+
{
52+
ArgumentOutOfRangeException.ThrowIfLessThan(value, 0, nameof(RequestBodyLogLimit));
53+
_requestBodyLogLimit = value;
54+
IsRequestBodyLogLimitSet = true;
55+
}
56+
}
57+
58+
/// <summary>
59+
/// Indicates whether <see cref="ResponseBodyLogLimit"/> has been set.
60+
/// </summary>
61+
public bool IsResponseBodyLogLimitSet { get; private set; }
3962

4063
/// <summary>
4164
/// Specifies the maximum number of bytes to be logged for the response body.
4265
/// </summary>
43-
public int ResponseBodyLogLimit { get; }
66+
/// <exception cref="ArgumentOutOfRangeException">Thrown when <see cref="ResponseBodyLogLimit"/> set to a value less than <c>0</c>.</exception>
67+
/// <exception cref="InvalidOperationException">Thrown when getting <see cref="ResponseBodyLogLimit"/> if it hasn't been set to a value. Check <see cref="IsResponseBodyLogLimitSet"/> first.</exception>
68+
public int ResponseBodyLogLimit
69+
{
70+
get
71+
{
72+
if (IsResponseBodyLogLimitSet)
73+
{
74+
return _responseBodyLogLimit;
75+
}
76+
throw new InvalidOperationException($"{nameof(ResponseBodyLogLimit)} was not set. Check {nameof(IsResponseBodyLogLimitSet)} before accessing this property.");
77+
}
78+
set
79+
{
80+
ArgumentOutOfRangeException.ThrowIfLessThan(value, 0, nameof(ResponseBodyLogLimit));
81+
_responseBodyLogLimit = value;
82+
IsResponseBodyLogLimitSet = true;
83+
}
84+
}
4485
}

src/Middleware/HttpLogging/src/HttpLoggingEndpointConventionBuilderExtensions.cs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,22 @@ public static class HttpLoggingEndpointConventionBuilderExtensions
1919
/// <param name="requestBodyLogLimit">Sets the <see cref="HttpLoggingOptions.RequestBodyLogLimit"/> for this endpoint. A value of <c>-1</c> means use the default setting in <see cref="HttpLoggingOptions.RequestBodyLogLimit"/>.</param>
2020
/// <param name="responseBodyLogLimit">Sets the <see cref="HttpLoggingOptions.ResponseBodyLogLimit"/> for this endpoint. A value of <c>-1</c> means use the default setting in <see cref="HttpLoggingOptions.ResponseBodyLogLimit"/>.</param>
2121
/// <returns>The original convention builder parameter.</returns>
22-
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="requestBodyLogLimit"/> or <paramref name="responseBodyLogLimit"/> is less than <c>-1</c>.</exception>
23-
public static TBuilder WithHttpLogging<TBuilder>(this TBuilder builder, HttpLoggingFields loggingFields, int requestBodyLogLimit = -1, int responseBodyLogLimit = -1) where TBuilder : IEndpointConventionBuilder
22+
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="requestBodyLogLimit"/> or <paramref name="responseBodyLogLimit"/> is less than <c>0</c>.</exception>
23+
public static TBuilder WithHttpLogging<TBuilder>(this TBuilder builder, HttpLoggingFields loggingFields, int? requestBodyLogLimit = null, int? responseBodyLogLimit = null) where TBuilder : IEndpointConventionBuilder
2424
{
2525
// Construct outside build.Add lambda to allow exceptions to be thrown immediately
26-
var metadata = new HttpLoggingAttribute(loggingFields, requestBodyLogLimit, responseBodyLogLimit);
26+
var metadata = new HttpLoggingAttribute(loggingFields);
27+
28+
if (requestBodyLogLimit is not null)
29+
{
30+
ArgumentOutOfRangeException.ThrowIfLessThan(requestBodyLogLimit.Value, 0, nameof(requestBodyLogLimit));
31+
metadata.RequestBodyLogLimit = requestBodyLogLimit.Value;
32+
}
33+
if (responseBodyLogLimit is not null)
34+
{
35+
ArgumentOutOfRangeException.ThrowIfLessThan(responseBodyLogLimit.Value, 0, nameof(responseBodyLogLimit));
36+
metadata.ResponseBodyLogLimit = responseBodyLogLimit.Value;
37+
}
2738

2839
builder.Add(endpointBuilder =>
2940
{

src/Middleware/HttpLogging/src/HttpLoggingMiddleware.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ private async Task InvokeInternal(HttpContext context)
110110
out var encoding))
111111
{
112112
var requestBodyLogLimit = options.RequestBodyLogLimit;
113-
if (loggingAttribute?.RequestBodyLogLimit is int)
113+
if (loggingAttribute?.IsRequestBodyLogLimitSet is true)
114114
{
115115
requestBodyLogLimit = loggingAttribute.RequestBodyLogLimit;
116116
}
@@ -161,7 +161,7 @@ private async Task InvokeInternal(HttpContext context)
161161
originalBodyFeature = context.Features.Get<IHttpResponseBodyFeature>()!;
162162

163163
var responseBodyLogLimit = options.ResponseBodyLogLimit;
164-
if (loggingAttribute?.ResponseBodyLogLimit is int)
164+
if (loggingAttribute?.IsRequestBodyLogLimitSet is true)
165165
{
166166
responseBodyLogLimit = loggingAttribute.ResponseBodyLogLimit;
167167
}
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
#nullable enable
22
Microsoft.AspNetCore.Builder.HttpLoggingEndpointConventionBuilderExtensions
33
Microsoft.AspNetCore.HttpLogging.HttpLoggingAttribute
4-
Microsoft.AspNetCore.HttpLogging.HttpLoggingAttribute.HttpLoggingAttribute(Microsoft.AspNetCore.HttpLogging.HttpLoggingFields loggingFields, int requestBodyLogLimit = -1, int responseBodyLogLimit = -1) -> void
4+
Microsoft.AspNetCore.HttpLogging.HttpLoggingAttribute.HttpLoggingAttribute(Microsoft.AspNetCore.HttpLogging.HttpLoggingFields loggingFields) -> void
5+
Microsoft.AspNetCore.HttpLogging.HttpLoggingAttribute.IsRequestBodyLogLimitSet.get -> bool
6+
Microsoft.AspNetCore.HttpLogging.HttpLoggingAttribute.IsResponseBodyLogLimitSet.get -> bool
57
Microsoft.AspNetCore.HttpLogging.HttpLoggingAttribute.LoggingFields.get -> Microsoft.AspNetCore.HttpLogging.HttpLoggingFields
68
Microsoft.AspNetCore.HttpLogging.HttpLoggingAttribute.RequestBodyLogLimit.get -> int
9+
Microsoft.AspNetCore.HttpLogging.HttpLoggingAttribute.RequestBodyLogLimit.set -> void
710
Microsoft.AspNetCore.HttpLogging.HttpLoggingAttribute.ResponseBodyLogLimit.get -> int
8-
static Microsoft.AspNetCore.Builder.HttpLoggingEndpointConventionBuilderExtensions.WithHttpLogging<TBuilder>(this TBuilder builder, Microsoft.AspNetCore.HttpLogging.HttpLoggingFields loggingFields, int requestBodyLogLimit = -1, int responseBodyLogLimit = -1) -> TBuilder
11+
Microsoft.AspNetCore.HttpLogging.HttpLoggingAttribute.ResponseBodyLogLimit.set -> void
12+
static Microsoft.AspNetCore.Builder.HttpLoggingEndpointConventionBuilderExtensions.WithHttpLogging<TBuilder>(this TBuilder builder, Microsoft.AspNetCore.HttpLogging.HttpLoggingFields loggingFields, int? requestBodyLogLimit = null, int? responseBodyLogLimit = null) -> TBuilder
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.AspNetCore.HttpLogging.Tests;
5+
6+
public class HttpLoggingAttributeTests
7+
{
8+
[Fact]
9+
public void ThrowsForInvalidOptions()
10+
{
11+
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => new HttpLoggingAttribute(HttpLoggingFields.None) { RequestBodyLogLimit = -1 });
12+
Assert.Equal(nameof(HttpLoggingAttribute.RequestBodyLogLimit), ex.ParamName);
13+
14+
ex = Assert.Throws<ArgumentOutOfRangeException>(() => new HttpLoggingAttribute(HttpLoggingFields.None) { ResponseBodyLogLimit = -1 });
15+
Assert.Equal(nameof(HttpLoggingAttribute.ResponseBodyLogLimit), ex.ParamName);
16+
}
17+
18+
[Fact]
19+
public void ThrowsWhenAccessingFieldsThatAreNotSet()
20+
{
21+
var attribute = new HttpLoggingAttribute(HttpLoggingFields.None);
22+
23+
Assert.Throws<InvalidOperationException>(() => attribute.RequestBodyLogLimit);
24+
Assert.Throws<InvalidOperationException>(() => attribute.ResponseBodyLogLimit);
25+
}
26+
}

src/Middleware/HttpLogging/test/HttpLoggingEndpointConventionBuilderTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ public void WithHttpLogging_ThrowsForInvalidLimits()
4242

4343
// Act & Assert
4444
var ex = Assert.Throws<ArgumentOutOfRangeException>(() =>
45-
testConventionBuilder.WithHttpLogging(HttpLoggingFields.None, requestBodyLogLimit: -2));
45+
testConventionBuilder.WithHttpLogging(HttpLoggingFields.None, requestBodyLogLimit: -1));
4646
Assert.Equal("requestBodyLogLimit", ex.ParamName);
4747

4848
ex = Assert.Throws<ArgumentOutOfRangeException>(() =>
49-
testConventionBuilder.WithHttpLogging(HttpLoggingFields.None, responseBodyLogLimit: -2));
49+
testConventionBuilder.WithHttpLogging(HttpLoggingFields.None, responseBodyLogLimit: -1));
5050
Assert.Equal("responseBodyLogLimit", ex.ParamName);
5151
}
5252
}

src/Middleware/HttpLogging/test/HttpLoggingMiddlewareTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1337,7 +1337,7 @@ private IHost CreateApp(HttpLoggingFields defaultFields = HttpLoggingFields.All)
13371337
return "testing";
13381338
}).WithHttpLogging((HttpLoggingFields.Request & ~HttpLoggingFields.RequestScheme) | (HttpLoggingFields.Response & ~HttpLoggingFields.ResponseStatusCode));
13391339

1340-
endpoint.MapGet("/attr_restrictedsize", [HttpLogging(HttpLoggingFields.Request | HttpLoggingFields.Response, requestBodyLogLimit: 3, responseBodyLogLimit: 6)] async (HttpContext c) =>
1340+
endpoint.MapGet("/attr_restrictedsize", [HttpLogging(HttpLoggingFields.Request | HttpLoggingFields.Response, RequestBodyLogLimit = 3, ResponseBodyLogLimit = 6)] async (HttpContext c) =>
13411341
{
13421342
await c.Request.Body.ReadAsync(new byte[100]);
13431343
return "testing";

0 commit comments

Comments
 (0)