Skip to content

Commit bdcf91a

Browse files
authored
Reduce per-request allocations in middleware hot path (#345)
1 parent b6d7689 commit bdcf91a

File tree

540 files changed

+2174
-2187
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

540 files changed

+2174
-2187
lines changed

readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ internal static string BuildEtag(string timeStamp, string? suffix)
136136
return $"\"{AssemblyWriteTime}-{timeStamp}-{suffix}\"";
137137
}
138138
```
139-
<sup><a href='/src/Delta/DeltaExtensions_Shared.cs#L183-L195' title='Snippet source file'>snippet source</a> | <a href='#snippet-BuildEtag' title='Start of snippet'>anchor</a></sup>
139+
<sup><a href='/src/Delta/DeltaExtensions_Shared.cs#L182-L194' title='Snippet source file'>snippet source</a> | <a href='#snippet-BuildEtag' title='Start of snippet'>anchor</a></sup>
140140
<!-- endSnippet -->
141141

142142

src/Delta.EF/DeltaExtensions_EFMiddleware.cs

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@ public static IApplicationBuilder UseDelta<TDbContext>(this IApplicationBuilder
66
where TDbContext : DbContext
77
{
88
var logger = builder.ApplicationServices.GetLogger();
9+
10+
static Task<string> GetTimeStamp(HttpContext context) =>
11+
context.RequestServices.GetRequiredService<TDbContext>().GetLastTimeStamp();
12+
913
return builder.Use(
1014
async (context, next) =>
1115
{
12-
if (await HandleRequest<TDbContext>(context, logger, suffix, shouldExecute, logLevel, allowAnonymous))
16+
if (await HandleRequest(context, logger, suffix, GetTimeStamp, shouldExecute, logLevel, allowAnonymous))
1317
{
1418
return;
1519
}
@@ -24,9 +28,13 @@ static TBuilder UseDelta<TBuilder, TDbContext>(this TBuilder builder, Func<HttpC
2428
builder.AddEndpointFilterFactory((filterContext, next) =>
2529
{
2630
var logger = filterContext.ApplicationServices.GetLogger();
31+
32+
static Task<string> GetTimeStamp(HttpContext context) =>
33+
context.RequestServices.GetRequiredService<TDbContext>().GetLastTimeStamp();
34+
2735
return async invocationContext =>
2836
{
29-
if (await HandleRequest<TDbContext>(invocationContext.HttpContext, logger, suffix, shouldExecute, logLevel, allowAnonymous))
37+
if (await HandleRequest(invocationContext.HttpContext, logger, suffix, GetTimeStamp, shouldExecute, logLevel, allowAnonymous))
3038
{
3139
return Results.Empty;
3240
}
@@ -35,19 +43,6 @@ static TBuilder UseDelta<TBuilder, TDbContext>(this TBuilder builder, Func<HttpC
3543
};
3644
});
3745

38-
static Task<bool> HandleRequest<T>(HttpContext context, ILogger logger, Func<HttpContext, string?>? suffix, Func<HttpContext, bool>? shouldExecute, LogLevel logLevel, bool allowAnonymous = false)
39-
where T : DbContext =>
40-
HandleRequest(
41-
context,
42-
logger,
43-
suffix,
44-
_ => _.RequestServices
45-
.GetRequiredService<T>()
46-
.GetLastTimeStamp(),
47-
shouldExecute,
48-
logLevel,
49-
allowAnonymous);
50-
5146
public static Task<string> GetLastTimeStamp(this DbContext context, Cancel cancel = default)
5247
{
5348
var database = context.Database;

src/Delta/DeltaExtensions_Middleware.cs

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,17 @@ public static IApplicationBuilder UseDelta(this IApplicationBuilder builder, Get
66
{
77
getConnection ??= DiscoverConnection;
88
var logger = builder.ApplicationServices.GetLogger();
9+
10+
Task<string> GetTimeStamp(HttpContext context)
11+
{
12+
var (connection, transaction) = getConnection(context);
13+
return connection.GetLastTimeStamp(transaction);
14+
}
15+
916
return builder.Use(
1017
async (context, next) =>
1118
{
12-
if (await HandleRequest(context, getConnection, logger, suffix, shouldExecute, logLevel, allowAnonymous))
19+
if (await HandleRequest(context, logger, suffix, GetTimeStamp, shouldExecute, logLevel, allowAnonymous))
1320
{
1421
return;
1522
}
@@ -26,9 +33,16 @@ static TBuilder UseDelta<TBuilder>(this TBuilder builder, GetConnection? getConn
2633
return builder.AddEndpointFilterFactory((filterContext, next) =>
2734
{
2835
var logger = filterContext.ApplicationServices.GetLogger();
36+
37+
Task<string> GetTimeStamp(HttpContext context)
38+
{
39+
var (connection, transaction) = getConnection(context);
40+
return connection.GetLastTimeStamp(transaction);
41+
}
42+
2943
return async invocationContext =>
3044
{
31-
if (await HandleRequest(invocationContext.HttpContext, getConnection, logger, suffix, shouldExecute, logLevel, allowAnonymous))
45+
if (await HandleRequest(invocationContext.HttpContext, logger, suffix, GetTimeStamp, shouldExecute, logLevel, allowAnonymous))
3246
{
3347
return Results.Empty;
3448
}
@@ -38,27 +52,6 @@ static TBuilder UseDelta<TBuilder>(this TBuilder builder, GetConnection? getConn
3852
});
3953
}
4054

41-
static Task<bool> HandleRequest(
42-
HttpContext context,
43-
GetConnection getConnection,
44-
ILogger logger,
45-
Func<HttpContext, string?>? suffix,
46-
Func<HttpContext, bool>? shouldExecute,
47-
LogLevel logLevel,
48-
bool allowAnonymous = false) =>
49-
HandleRequest(
50-
context,
51-
logger,
52-
suffix,
53-
_ =>
54-
{
55-
var (connection, transaction) = getConnection(_);
56-
return connection.GetLastTimeStamp(transaction);
57-
},
58-
shouldExecute,
59-
logLevel,
60-
allowAnonymous);
61-
6255
public static ComponentEndpointConventionBuilder UseDelta(
6356
this ComponentEndpointConventionBuilder builder,
6457
GetConnection? getConnection = null,

src/Delta/DeltaExtensions_Shared.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,9 @@ internal static async Task<bool> HandleRequest(HttpContext context, ILogger logg
6060
var path = request.Path;
6161

6262
var logEnabled = logger.IsEnabled(level);
63-
var method = request.Method;
64-
if (method != "GET")
63+
if (!HttpMethods.IsGet(request.Method))
6564
{
66-
WriteNo304Header(response, $"Request Method={method}", level, logger, path, logEnabled);
65+
WriteNo304Header(response, "Request method is not GET", level, logger, path, logEnabled);
6766
return false;
6867
}
6968

@@ -123,7 +122,7 @@ Ensure authentication middleware runs before UseDelta so that User claims are av
123122
}
124123
else
125124
{
126-
reason = $"Request has no If-None-Match. Request also has Cache-Control header ({cacheControl}) which can interfere with caching";
125+
reason = "Request has no If-None-Match. Request Cache-Control header may interfere with caching";
127126
}
128127

129128
WriteNo304Header(response, reason, level, logger, path, logEnabled);

src/DeltaTests/MiddlewareTests.Combinations_suffixFunc=False_nullSuffixFunc=False_get=False_ifNoneMatch=False_sameIfNoneMatch=False_etag=False_executeFunc=False_trueExecuteFunc=False_immutable=False_requestCacheControl=False.verified.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
{
1+
{
22
target: {
33
notModified: false,
44
context: {
55
Request: {},
66
Response: {
77
StatusCode: OK,
88
Headers: {
9-
Delta-No304: Request Method=POST
9+
Delta-No304: Request method is not GET
1010
}
1111
}
1212
}
1313
},
1414
log: {
15-
Information: Delta /path: No 304. Request Method=POST,
15+
Information: Delta /path: No 304. Request method is not GET,
1616
State: [
1717
{
1818
path: /path
1919
},
2020
{
21-
reason: Request Method=POST
21+
reason: Request method is not GET
2222
},
2323
{
2424
{OriginalFormat}: Delta {path}: No 304. {reason}

src/DeltaTests/MiddlewareTests.Combinations_suffixFunc=False_nullSuffixFunc=False_get=False_ifNoneMatch=False_sameIfNoneMatch=False_etag=False_executeFunc=False_trueExecuteFunc=False_immutable=False_requestCacheControl=True.verified.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{
1+
{
22
target: {
33
notModified: false,
44
context: {
@@ -10,19 +10,19 @@
1010
Response: {
1111
StatusCode: OK,
1212
Headers: {
13-
Delta-No304: Request Method=POST
13+
Delta-No304: Request method is not GET
1414
}
1515
}
1616
}
1717
},
1818
log: {
19-
Information: Delta /path: No 304. Request Method=POST,
19+
Information: Delta /path: No 304. Request method is not GET,
2020
State: [
2121
{
2222
path: /path
2323
},
2424
{
25-
reason: Request Method=POST
25+
reason: Request method is not GET
2626
},
2727
{
2828
{OriginalFormat}: Delta {path}: No 304. {reason}

src/DeltaTests/MiddlewareTests.Combinations_suffixFunc=False_nullSuffixFunc=False_get=False_ifNoneMatch=False_sameIfNoneMatch=False_etag=False_executeFunc=False_trueExecuteFunc=False_immutable=True_requestCacheControl=False.verified.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{
1+
{
22
target: {
33
notModified: false,
44
context: {
@@ -7,19 +7,19 @@
77
StatusCode: OK,
88
Headers: {
99
Cache-Control: public, max-age=31536000, immutable,
10-
Delta-No304: Request Method=POST
10+
Delta-No304: Request method is not GET
1111
}
1212
}
1313
}
1414
},
1515
log: {
16-
Information: Delta /path: No 304. Request Method=POST,
16+
Information: Delta /path: No 304. Request method is not GET,
1717
State: [
1818
{
1919
path: /path
2020
},
2121
{
22-
reason: Request Method=POST
22+
reason: Request method is not GET
2323
},
2424
{
2525
{OriginalFormat}: Delta {path}: No 304. {reason}

src/DeltaTests/MiddlewareTests.Combinations_suffixFunc=False_nullSuffixFunc=False_get=False_ifNoneMatch=False_sameIfNoneMatch=False_etag=False_executeFunc=False_trueExecuteFunc=False_immutable=True_requestCacheControl=True.verified.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{
1+
{
22
target: {
33
notModified: false,
44
context: {
@@ -11,19 +11,19 @@
1111
StatusCode: OK,
1212
Headers: {
1313
Cache-Control: public, max-age=31536000, immutable,
14-
Delta-No304: Request Method=POST
14+
Delta-No304: Request method is not GET
1515
}
1616
}
1717
}
1818
},
1919
log: {
20-
Information: Delta /path: No 304. Request Method=POST,
20+
Information: Delta /path: No 304. Request method is not GET,
2121
State: [
2222
{
2323
path: /path
2424
},
2525
{
26-
reason: Request Method=POST
26+
reason: Request method is not GET
2727
},
2828
{
2929
{OriginalFormat}: Delta {path}: No 304. {reason}

src/DeltaTests/MiddlewareTests.Combinations_suffixFunc=False_nullSuffixFunc=False_get=False_ifNoneMatch=False_sameIfNoneMatch=False_etag=False_executeFunc=False_trueExecuteFunc=True_immutable=False_requestCacheControl=False.verified.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
{
1+
{
22
target: {
33
notModified: false,
44
context: {
55
Request: {},
66
Response: {
77
StatusCode: OK,
88
Headers: {
9-
Delta-No304: Request Method=POST
9+
Delta-No304: Request method is not GET
1010
}
1111
}
1212
}
1313
},
1414
log: {
15-
Information: Delta /path: No 304. Request Method=POST,
15+
Information: Delta /path: No 304. Request method is not GET,
1616
State: [
1717
{
1818
path: /path
1919
},
2020
{
21-
reason: Request Method=POST
21+
reason: Request method is not GET
2222
},
2323
{
2424
{OriginalFormat}: Delta {path}: No 304. {reason}

src/DeltaTests/MiddlewareTests.Combinations_suffixFunc=False_nullSuffixFunc=False_get=False_ifNoneMatch=False_sameIfNoneMatch=False_etag=False_executeFunc=False_trueExecuteFunc=True_immutable=False_requestCacheControl=True.verified.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{
1+
{
22
target: {
33
notModified: false,
44
context: {
@@ -10,19 +10,19 @@
1010
Response: {
1111
StatusCode: OK,
1212
Headers: {
13-
Delta-No304: Request Method=POST
13+
Delta-No304: Request method is not GET
1414
}
1515
}
1616
}
1717
},
1818
log: {
19-
Information: Delta /path: No 304. Request Method=POST,
19+
Information: Delta /path: No 304. Request method is not GET,
2020
State: [
2121
{
2222
path: /path
2323
},
2424
{
25-
reason: Request Method=POST
25+
reason: Request method is not GET
2626
},
2727
{
2828
{OriginalFormat}: Delta {path}: No 304. {reason}

0 commit comments

Comments
 (0)